@mesh-tech/mesh-cli 0.1.0 → 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 +4 -0
  134. package/dist/src/commands/secrets/set.d.ts.map +1 -1
  135. package/dist/src/commands/secrets/set.js +243 -64
  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 +35 -21
  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,739 @@
1
+ /**
2
+ * Assembly: turn the discovered doc roots into a plain content tree plus a
3
+ * navigation manifest, ready for a docs renderer (Zudoku today) to build.
4
+ *
5
+ * The seam of the whole design is here: assembly's output is a directory of
6
+ * markdown files, a generated `zudoku.config.ts`, and a publish manifest.
7
+ * Nothing downstream knows about Mesh; nothing upstream knows about Zudoku.
8
+ *
9
+ * What assembly does, per page:
10
+ * - derives the title (front-matter `title:` → first `#` heading → filename)
11
+ * and writes it into the assembled front-matter, so nav labels and page
12
+ * titles can never drift apart
13
+ * - rewrites links: a relative link between two published files is correct
14
+ * *on disk* but meaningless at a route, so published targets become
15
+ * routes, unpublished-but-real files become repo blob links (reported as
16
+ * `external`), and links that resolve to nothing are reported `broken`
17
+ * - footers the page with the exact repo file it came from, so a reader who
18
+ * spots a mistake knows where to fix it
19
+ *
20
+ * It also emits the publish manifest — every source path that made it into
21
+ * the site — which the CI gate uploads and diffs so growing the public
22
+ * surface is a thing a reviewer sees.
23
+ */
24
+ import { execFileSync } from "node:child_process";
25
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
26
+ import path from "node:path";
27
+ import { parse as parseYaml } from "yaml";
28
+ import { pathKind } from "./discover.js";
29
+ import { hasReservedSegment } from "./schema.js";
30
+ const DEFAULT_REPO_URL = "https://github.com/mesh-tech/mesh-platform";
31
+ const DEFAULT_IGNORE_LINK_PREFIXES = ["node_modules/"];
32
+ /**
33
+ * Split a markdown document into front-matter and body. Only a `---` fence on
34
+ * the very first line counts — a horizontal rule later in the prose is not
35
+ * front-matter. A YAML parse failure is not fatal: the document is treated as
36
+ * having no front-matter (the heading/filename title fallbacks still apply),
37
+ * because one bad page must not take the whole site down at assemble time.
38
+ */
39
+ export function splitFrontMatter(markdown) {
40
+ const normalized = markdown.replace(/^\uFEFF/, "");
41
+ if (!normalized.startsWith("---\n") && !normalized.startsWith("---\r\n")) {
42
+ return { data: {}, body: markdown, hasFrontMatter: false };
43
+ }
44
+ const end = normalized.indexOf("\n---", 4);
45
+ if (end === -1)
46
+ return { data: {}, body: markdown, hasFrontMatter: false };
47
+ const rawBlock = normalized.slice(4, end);
48
+ const bodyStart = normalized.indexOf("\n", end + 1);
49
+ const body = (bodyStart === -1 ? "" : normalized.slice(bodyStart + 1)).replace(/^\r?\n/, "");
50
+ try {
51
+ const data = parseYaml(rawBlock);
52
+ if (data && typeof data === "object" && !Array.isArray(data)) {
53
+ return {
54
+ data: data,
55
+ body,
56
+ hasFrontMatter: true,
57
+ };
58
+ }
59
+ }
60
+ catch {
61
+ // fall through to the no-front-matter shape
62
+ }
63
+ return { data: {}, body, hasFrontMatter: true };
64
+ }
65
+ /** Serialize front-matter data + body back into a markdown document. */
66
+ function joinFrontMatter(data, body) {
67
+ const lines = Object.entries(data).map(([key, value]) => {
68
+ if (typeof value === "number" || typeof value === "boolean")
69
+ return `${key}: ${value}`;
70
+ const text = String(value);
71
+ // Quote only when YAML would misread the bare form.
72
+ return /^[\w .,'’()/-]+$/.test(text)
73
+ ? `${key}: ${text}`
74
+ : `${key}: ${JSON.stringify(text)}`;
75
+ });
76
+ return `---\n${lines.join("\n")}\n---\n\n${body.replace(/^\s*\n/, "")}`;
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // Title derivation
80
+ // ---------------------------------------------------------------------------
81
+ /** First `#` heading text, or undefined. Headings inside code fences don't count. */
82
+ function firstHeading(body) {
83
+ let inFence = false;
84
+ for (const line of body.split("\n")) {
85
+ if (/^\s*(```|~~~)/.test(line)) {
86
+ inFence = !inFence;
87
+ continue;
88
+ }
89
+ if (inFence)
90
+ continue;
91
+ const match = /^#\s+(.+?)\s*#*\s*$/.exec(line);
92
+ if (match)
93
+ return match[1].trim();
94
+ }
95
+ return undefined;
96
+ }
97
+ /** Titleize a filename stem for the filename-fallback case: `hub-dev-local` → "Hub dev local". */
98
+ function titleizeStem(stem) {
99
+ const words = stem.replace(/[-_]+/g, " ").trim();
100
+ return words.charAt(0).toUpperCase() + words.slice(1);
101
+ }
102
+ /**
103
+ * The title derivation order, fixed by the design: front-matter `title:` →
104
+ * first `#` heading → filename. `sidebar_label` wins for the nav when present
105
+ * (Zudoku honours it), but the document still gets its real title.
106
+ */
107
+ export function deriveTitle(frontMatter, body, source) {
108
+ const fmTitle = frontMatter.title;
109
+ if (typeof fmTitle === "string" && fmTitle.trim())
110
+ return fmTitle.trim();
111
+ const heading = firstHeading(body);
112
+ if (heading)
113
+ return heading;
114
+ const stem = path.posix.basename(source).replace(/\.md$/i, "");
115
+ return titleizeStem(stem);
116
+ }
117
+ function scanLinks(markdown) {
118
+ const hits = [];
119
+ const lines = markdown.split("\n");
120
+ let offset = 0;
121
+ let inFence = null;
122
+ for (const line of lines) {
123
+ const fenceMatch = /^(\s{0,3})(`{3,}|~{3,})/.exec(line);
124
+ if (fenceMatch) {
125
+ if (!inFence) {
126
+ inFence = { marker: fenceMatch[2][0] };
127
+ }
128
+ else if (fenceMatch[2].startsWith(inFence.marker)) {
129
+ inFence = null;
130
+ }
131
+ offset += line.length + 1;
132
+ continue;
133
+ }
134
+ if (inFence) {
135
+ offset += line.length + 1;
136
+ continue;
137
+ }
138
+ // Reference definitions: [id]: href — the href runs to end of line
139
+ // (optionally followed by a title). Rewrite in place.
140
+ const refDef = /^ {0,3}\[[^\]]+\]:\s*(\S+)/.exec(line);
141
+ if (refDef) {
142
+ const href = refDef[1];
143
+ const start = offset + line.indexOf(href);
144
+ hits.push({ start, end: start + href.length, href });
145
+ offset += line.length + 1;
146
+ continue;
147
+ }
148
+ // Inline links/images, skipping inline code spans.
149
+ let i = 0;
150
+ while (i < line.length) {
151
+ const ch = line[i];
152
+ if (ch === "`") {
153
+ const run = /^`+/.exec(line.slice(i))[0];
154
+ const close = line.indexOf(run, i + run.length);
155
+ i = close === -1 ? line.length : close + run.length;
156
+ continue;
157
+ }
158
+ if (ch === "<") {
159
+ const close = line.indexOf(">", i);
160
+ i = close === -1 ? line.length : close + 1;
161
+ continue;
162
+ }
163
+ if (ch === "!" && line[i + 1] === "[") {
164
+ i = scanBracketLink(line, i + 1, offset, hits);
165
+ continue;
166
+ }
167
+ if (ch === "[") {
168
+ i = scanBracketLink(line, i, offset, hits);
169
+ continue;
170
+ }
171
+ i++;
172
+ }
173
+ offset += line.length + 1;
174
+ }
175
+ return hits;
176
+ }
177
+ /**
178
+ * At `line[i] === "["`, try to read `[...](href …)` or `[...][id]`. Only the
179
+ * `(...)` form carries an inline href we can rewrite; reference uses are
180
+ * covered by rewriting their definitions.
181
+ */
182
+ function scanBracketLink(line, open, lineOffset, hits) {
183
+ const closeBracket = line.indexOf("]", open);
184
+ if (closeBracket === -1)
185
+ return line.length;
186
+ if (line[closeBracket + 1] !== "(")
187
+ return closeBracket + 1;
188
+ let j = closeBracket + 2;
189
+ while (j < line.length && /\s/.test(line[j]))
190
+ j++;
191
+ if (line[j] === "<") {
192
+ const end = line.indexOf(">", j);
193
+ if (end === -1)
194
+ return line.length;
195
+ hits.push({
196
+ start: lineOffset + j + 1,
197
+ end: lineOffset + end,
198
+ href: line.slice(j + 1, end),
199
+ });
200
+ return end + 1;
201
+ }
202
+ const closeParen = line.indexOf(")", j);
203
+ if (closeParen === -1)
204
+ return line.length;
205
+ const inner = line.slice(j, closeParen).trim();
206
+ // href may be followed by a "title" — split on the first space.
207
+ const space = inner.search(/\s/);
208
+ const href = space === -1 ? inner : inner.slice(0, space);
209
+ if (href) {
210
+ const start = lineOffset + line.indexOf(href, j);
211
+ hits.push({ start, end: start + href.length, href });
212
+ }
213
+ return closeParen + 1;
214
+ }
215
+ /**
216
+ * Remove HTML comments (`<!-- … -->`, single- or multi-line) from a page body.
217
+ * They are invisible in any rendered output by definition — the source file
218
+ * keeps them — and multi-line comments currently crash Zudoku's MDX plugin
219
+ * (`chunks[startIndex].slice is not a function`), which turns one authored
220
+ * comment into a failed site build. Fenced code blocks are left alone: a doc
221
+ * *teaching* HTML comments shows them as code, and that code must survive.
222
+ */
223
+ export function stripHtmlComments(body) {
224
+ const lines = body.split("\n");
225
+ const out = [];
226
+ let inFence = false;
227
+ let inComment = false;
228
+ for (const line of lines) {
229
+ if (/^\s*(```|~~~)/.test(line)) {
230
+ if (!inComment)
231
+ inFence = !inFence;
232
+ if (!inComment)
233
+ out.push(line);
234
+ continue;
235
+ }
236
+ if (inFence) {
237
+ out.push(line);
238
+ continue;
239
+ }
240
+ let rest = line;
241
+ let rebuilt = "";
242
+ while (rest.length > 0) {
243
+ if (inComment) {
244
+ const end = rest.indexOf("-->");
245
+ if (end === -1) {
246
+ rest = "";
247
+ break;
248
+ }
249
+ inComment = false;
250
+ rest = rest.slice(end + 3);
251
+ continue;
252
+ }
253
+ const start = rest.indexOf("<!--");
254
+ if (start === -1) {
255
+ rebuilt += rest;
256
+ break;
257
+ }
258
+ rebuilt += rest.slice(0, start);
259
+ inComment = true;
260
+ rest = rest.slice(start + 4);
261
+ }
262
+ // A line that held only a comment collapses to nothing; a line with prose
263
+ // around a comment keeps its prose.
264
+ if (rebuilt.trim() !== "" || !inComment)
265
+ out.push(rebuilt.replace(/\s+$/, ""));
266
+ }
267
+ return out.join("\n").replace(/\n{3,}/g, "\n\n");
268
+ }
269
+ function isAbsoluteHref(href) {
270
+ return /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href);
271
+ }
272
+ function normalizeRepoPath(value) {
273
+ return path.posix
274
+ .normalize(value.replace(/\\/g, "/"))
275
+ .replace(/^\.\//, "")
276
+ .replace(/\/+$/, "");
277
+ }
278
+ function splitHash(href) {
279
+ const index = href.indexOf("#");
280
+ return index === -1
281
+ ? [href, ""]
282
+ : [href.slice(0, index), href.slice(index + 1)];
283
+ }
284
+ /**
285
+ * Resolve one link, exactly the #3503 semantics with routes instead of slugs:
286
+ *
287
+ * - anchors, absolute URLs, mailto: → untouched
288
+ * - an `ignoreLinkPrefixes` match → untouched (declared deliberately
289
+ * unresolvable — the app-kit README's `node_modules/…` guidance exists in
290
+ * a tenant's install, never in this repo)
291
+ * - a file the portal publishes → that page's route
292
+ * - a directory whose index/README the portal publishes → that route
293
+ * - a real repo file the portal does not publish → a repo blob link
294
+ * (reported `external`)
295
+ * - nothing → reported `broken`
296
+ * - a site-rooted path (`/guides/x`) → validated against the route set, so a
297
+ * typo'd route fails the gate instead of shipping as a 404
298
+ */
299
+ export function resolveLink(args) {
300
+ const { href, pageRoute, sourceDir, sourceIndex, routes, repoUrl } = args;
301
+ if (href.startsWith("#") || isAbsoluteHref(href))
302
+ return { href };
303
+ if (args.ignoreLinkPrefixes.some((prefix) => href.startsWith(prefix)))
304
+ return { href };
305
+ const [rawTarget, rawHash] = splitHash(href);
306
+ const hash = rawHash ? `#${rawHash}` : "";
307
+ if (rawTarget === "")
308
+ return { href };
309
+ // Site-rooted route reference.
310
+ if (rawTarget.startsWith("/")) {
311
+ const route = rawTarget.replace(/\/$/, "") || "/";
312
+ return routes.has(route)
313
+ ? { href: `${route}${hash}` }
314
+ : { href, issue: { kind: "broken", page: pageRoute, href } };
315
+ }
316
+ const repoPath = normalizeRepoPath(path.posix.join(sourceDir, rawTarget));
317
+ const page = sourceIndex.get(repoPath);
318
+ if (page)
319
+ return { href: `${page.route}${hash}` };
320
+ // A link to a directory conventionally means its index page.
321
+ for (const candidate of [`${repoPath}/index.md`]) {
322
+ const indexPage = sourceIndex.get(normalizeRepoPath(candidate));
323
+ if (indexPage)
324
+ return { href: `${indexPage.route}${hash}` };
325
+ }
326
+ const kind = args.pathKind(repoPath);
327
+ if (kind !== null) {
328
+ const base = repoUrl.replace(/\/$/, "").replace(/\/(blob|tree)$/, "");
329
+ return {
330
+ href: `${base}/${kind === "dir" ? "tree" : "blob"}/main/${repoPath}${hash}`,
331
+ issue: { kind: "external", page: pageRoute, href },
332
+ };
333
+ }
334
+ return { href, issue: { kind: "broken", page: pageRoute, href } };
335
+ }
336
+ /** Rewrite every link in a page body, collecting issues. */
337
+ export function rewriteLinks(args) {
338
+ const issues = [];
339
+ const hits = scanLinks(args.body);
340
+ if (hits.length === 0)
341
+ return { body: args.body, issues };
342
+ const sourceDir = path.posix.dirname(args.page.source);
343
+ let out = "";
344
+ let cursor = 0;
345
+ for (const hit of hits) {
346
+ const resolution = resolveLink({
347
+ href: hit.href,
348
+ pageRoute: args.page.route,
349
+ sourceDir,
350
+ sourceIndex: args.sourceIndex,
351
+ routes: args.routes,
352
+ ignoreLinkPrefixes: args.ignoreLinkPrefixes,
353
+ pathKind: args.pathKind,
354
+ repoUrl: args.repoUrl,
355
+ });
356
+ out += args.body.slice(cursor, hit.start) + resolution.href;
357
+ cursor = hit.end;
358
+ if (resolution.issue)
359
+ issues.push(resolution.issue);
360
+ }
361
+ out += args.body.slice(cursor);
362
+ return { body: out, issues };
363
+ }
364
+ /** A page's full route: section slug + route path. "/" for the site home. */
365
+ export function pageRoute(page) {
366
+ const joined = [page.root.slug, page.routePath].filter(Boolean).join("/");
367
+ return `/${joined}`.replace(/\/$/, "") || "/";
368
+ }
369
+ /** The assembled file path (no leading slash, with extension). */
370
+ export function pageFilePath(route) {
371
+ return route === "/" ? "index.md" : `${route.slice(1)}.md`;
372
+ }
373
+ /**
374
+ * Assemble the discovered pages into `outDir`. Pure function of the repo tree
375
+ * — the same inputs always produce the same tree, manifest, and navigation.
376
+ */
377
+ export function assemblePortal(options) {
378
+ const { repoRoot, discovery, outDir } = options;
379
+ const repoUrl = options.repoUrl ?? DEFAULT_REPO_URL;
380
+ const ignoreLinkPrefixes = options.ignoreLinkPrefixes ?? DEFAULT_IGNORE_LINK_PREFIXES;
381
+ // Build the page model first: routes must all exist before any link can be
382
+ // rewritten against them.
383
+ const pages = discovery.pages.map((page) => {
384
+ const route = pageRoute(page);
385
+ return {
386
+ source: page.source,
387
+ route,
388
+ filePath: pageFilePath(route),
389
+ title: "",
390
+ sectionTitle: page.root.config.title,
391
+ sectionOrder: page.root.config.order,
392
+ sectionSlug: page.root.slug,
393
+ };
394
+ });
395
+ const sourceIndex = new Map(pages.map((p) => [normalizeRepoPath(p.source), p]));
396
+ const routes = new Set(pages.map((p) => p.route));
397
+ const brokenLinks = [];
398
+ const externalLinks = [];
399
+ rmSync(outDir, { recursive: true, force: true });
400
+ mkdirSync(outDir, { recursive: true });
401
+ for (const page of pages) {
402
+ const raw = readFileSync(path.join(repoRoot, page.source), "utf-8");
403
+ const frontMatter = splitFrontMatter(raw);
404
+ const title = deriveTitle(frontMatter.data, frontMatter.body, page.source);
405
+ page.title = title;
406
+ const order = frontMatter.data.order;
407
+ if (typeof order === "number" && Number.isFinite(order))
408
+ page.order = order;
409
+ const rewritten = rewriteLinks({
410
+ body: stripHtmlComments(frontMatter.body),
411
+ page,
412
+ sourceIndex,
413
+ routes,
414
+ ignoreLinkPrefixes,
415
+ pathKind: (rel) => pathKind(path.join(repoRoot, rel)),
416
+ repoUrl,
417
+ });
418
+ for (const issue of rewritten.issues) {
419
+ (issue.kind === "broken" ? brokenLinks : externalLinks).push(issue);
420
+ }
421
+ // Front-matter: keep the author's, guarantee `title`. `showLastModified`
422
+ // is off — the assembled tree is rebuilt every run, so git-mtime-derived
423
+ // dates would say "today" on every page.
424
+ const outData = { ...frontMatter.data, title };
425
+ const blobBase = repoUrl.replace(/\/$/, "").replace(/\/(blob|tree)$/, "");
426
+ const sourceNote = `\n\n---\n\n<sub>Source: [\`${page.source}\`](${blobBase}/blob/main/${page.source}) — edit that file, not this page.</sub>\n`;
427
+ const outFile = path.join(outDir, page.filePath);
428
+ mkdirSync(path.dirname(outFile), { recursive: true });
429
+ writeFileSync(outFile, joinFrontMatter(outData, rewritten.body.trimEnd() + sourceNote));
430
+ }
431
+ const navigation = buildNavigation(pages);
432
+ // Fail-closed: no assembled output path may contain a reserved segment. The
433
+ // walk already skips reserved directories, so a violation here means the
434
+ // exclusion itself broke — exactly what the gate exists to catch.
435
+ const reservedViolations = pages
436
+ .map((p) => p.filePath)
437
+ .filter((filePath) => hasReservedSegment(filePath));
438
+ const publishManifest = {
439
+ version: 1,
440
+ count: pages.length,
441
+ sources: pages.map((p) => p.source).sort(),
442
+ };
443
+ return {
444
+ outDir,
445
+ pages,
446
+ navigation,
447
+ brokenLinks,
448
+ externalLinks,
449
+ publishManifest,
450
+ reservedViolations,
451
+ };
452
+ }
453
+ function titleizeDir(name) {
454
+ return titleizeStem(name);
455
+ }
456
+ /**
457
+ * Build the Zudoku navigation array from the assembled pages.
458
+ *
459
+ * Shape: one root category ("Documentation", clicking it lands on the home
460
+ * page) whose items are one non-collapsible category per doc root — the
461
+ * sidebar's section headers — each holding the section's tree: pages as doc
462
+ * items, directories as nested categories. A directory with an index page
463
+ * becomes a clickable category (its link); the section's own index page
464
+ * becomes the section category's link. Order is front-matter `order:` first,
465
+ * then filename — never declared anywhere but the files themselves.
466
+ */
467
+ export function buildNavigation(pages) {
468
+ const sections = new Map();
469
+ for (const page of pages) {
470
+ const key = page.sectionSlug;
471
+ if (!sections.has(key)) {
472
+ sections.set(key, {
473
+ title: page.sectionTitle,
474
+ order: page.sectionOrder,
475
+ slug: page.sectionSlug,
476
+ pages: [],
477
+ });
478
+ }
479
+ sections.get(key).pages.push(page);
480
+ }
481
+ const sortedSections = [...sections.values()].sort((a, b) => a.order - b.order || a.title.localeCompare(b.title));
482
+ const sortPages = (list) => [...list].sort((a, b) => (a.order ?? Number.MAX_SAFE_INTEGER) -
483
+ (b.order ?? Number.MAX_SAFE_INTEGER) ||
484
+ a.filePath.localeCompare(b.filePath));
485
+ // A nav doc reference (item or category link — same shape in both places).
486
+ // A `path` is a CUSTOM path in Zudoku: when it equals the file-derived
487
+ // route, the build moves the file's entry onto itself and deletes it
488
+ // (resolveCustomNavigationPaths compares `path === file` without the
489
+ // leading slash). The assembler already names files so the file route IS
490
+ // the desired route — so `path` is only emitted for the one genuinely
491
+ // custom mapping: the home page (file "index" → "/").
492
+ const docRef = (page) => {
493
+ const file = page.filePath.replace(/\.md$/, "");
494
+ return page.route === `/${file}`
495
+ ? file
496
+ : { type: "doc", file, path: page.route };
497
+ };
498
+ const items = [];
499
+ for (const section of sortedSections) {
500
+ const indexPage = section.pages.find((p) => p.route === `/${section.slug}` ||
501
+ (section.slug === "" && p.route === "/"));
502
+ const rest = section.pages.filter((p) => p !== indexPage);
503
+ // Group remaining pages by their section-relative directory.
504
+ const rootPages = [];
505
+ const dirs = new Map();
506
+ for (const page of rest) {
507
+ const rel = page.route.replace(/^\//, "");
508
+ const sectionPrefix = section.slug ? `${section.slug}/` : "";
509
+ const relParts = (sectionPrefix && rel.startsWith(sectionPrefix)
510
+ ? rel.slice(sectionPrefix.length)
511
+ : rel)
512
+ .split("/")
513
+ .filter(Boolean);
514
+ if (relParts.length <= 1) {
515
+ rootPages.push(page);
516
+ continue;
517
+ }
518
+ const dirKey = relParts.slice(0, -1).join("/");
519
+ if (!dirs.has(dirKey)) {
520
+ dirs.set(dirKey, {
521
+ label: titleizeDir(relParts[relParts.length - 2]),
522
+ routePath: relParts.slice(0, -1).join("/"),
523
+ pages: [],
524
+ dirs: new Map(),
525
+ });
526
+ }
527
+ dirs.get(dirKey).pages.push(page);
528
+ }
529
+ const byRoute = new Map(section.pages.map((p) => [p.route, p]));
530
+ const childItems = sortPages(rootPages).map(docRef);
531
+ for (const dir of [...dirs.values()].sort((a, b) => a.routePath.localeCompare(b.routePath))) {
532
+ const dirRoute = `/${[section.slug, dir.routePath].filter(Boolean).join("/")}`.replace(/\/$/, "") || "/";
533
+ const dirIndex = byRoute.get(dirRoute);
534
+ const grandchildren = sortPages(dir.pages.filter((p) => p !== dirIndex)).map(docRef);
535
+ if (grandchildren.length === 0 && dirIndex) {
536
+ childItems.push(docRef(dirIndex));
537
+ continue;
538
+ }
539
+ childItems.push({
540
+ type: "category",
541
+ label: dir.label,
542
+ ...(dirIndex ? { link: docRef(dirIndex) } : {}),
543
+ items: grandchildren,
544
+ });
545
+ }
546
+ items.push({
547
+ type: "category",
548
+ label: section.title,
549
+ collapsible: false,
550
+ ...(indexPage ? { link: docRef(indexPage) } : {}),
551
+ items: childItems,
552
+ });
553
+ }
554
+ return [
555
+ {
556
+ type: "category",
557
+ label: "Documentation",
558
+ link: { type: "doc", file: "index", path: "/" },
559
+ items,
560
+ },
561
+ ];
562
+ }
563
+ // ---------------------------------------------------------------------------
564
+ // Generated config + manifests
565
+ // ---------------------------------------------------------------------------
566
+ /**
567
+ * Render the generated `zudoku.config.ts`. It is regenerated on every
568
+ * assemble and gitignored — the navigation manifest is derived state, and
569
+ * committed derived state is how the old manifest rotted.
570
+ */
571
+ export function renderZudokuConfig(args) {
572
+ const versionLine = args.baseline
573
+ ? `Documents @mesh-tech/* ${args.baseline} · built from ${args.commit ?? "unknown"}`
574
+ : `Local build · ${args.commit ?? "unknown"}`;
575
+ const config = {
576
+ metadata: {
577
+ title: args.title,
578
+ description: args.description,
579
+ },
580
+ site: {
581
+ title: args.title,
582
+ logoUrl: "/",
583
+ footer: {
584
+ copyright: `${versionLine} · /version.json`,
585
+ },
586
+ },
587
+ theme: "THEME_IMPORT",
588
+ navigation: args.navigation,
589
+ docs: {
590
+ files: ["/content/**/*.{md,mdx}"],
591
+ defaultOptions: {
592
+ toc: true,
593
+ showLastModified: false,
594
+ },
595
+ },
596
+ redirects: [],
597
+ // Search is Zudoku's built-in Pagefind index — no config needed.
598
+ };
599
+ const json = JSON.stringify(config, null, 2).replace(`"THEME_IMPORT"`, "portalTheme");
600
+ return `/**
601
+ * GENERATED by \`mesh docs portal\` — do not edit.
602
+ *
603
+ * The navigation array is derived from the repo's docs.json roots and the
604
+ * markdown tree beneath them. To change what the site publishes, change the
605
+ * tree; to change section labels or order, change the root's docs.json.
606
+ * Regenerate: pnpm exec mesh docs portal --assemble-only
607
+ */
608
+ import type { ZudokuConfig } from "zudoku";
609
+ import { portalTheme } from "./theme.js";
610
+
611
+ const config: ZudokuConfig = ${json};
612
+
613
+ export default config;
614
+ `;
615
+ }
616
+ /** version.json — the version-parity contract the parity monitor asserts. */
617
+ export function renderVersionJson(args) {
618
+ return `${JSON.stringify({
619
+ meshBaseline: args.baseline ?? null,
620
+ commit: args.commit,
621
+ builtAt: args.builtAt,
622
+ }, null, 2)}\n`;
623
+ }
624
+ /** Best-effort short commit of the repo being assembled. */
625
+ export function currentCommit(repoRoot) {
626
+ try {
627
+ return execFileSync("git", ["rev-parse", "--short", "HEAD"], {
628
+ cwd: repoRoot,
629
+ encoding: "utf-8",
630
+ }).trim();
631
+ }
632
+ catch {
633
+ return "unknown";
634
+ }
635
+ }
636
+ /** The fixed lockstep group's version, read from app-kit's package.json. */
637
+ export function currentBaseline(repoRoot) {
638
+ try {
639
+ const pkg = JSON.parse(readFileSync(path.join(repoRoot, "libs/app-kit/package.json"), "utf-8"));
640
+ return pkg.version;
641
+ }
642
+ catch {
643
+ return undefined;
644
+ }
645
+ }
646
+ /**
647
+ * Compute the publish set of another git ref WITHOUT checking it out — the
648
+ * docs.json files and tree listing are read via `git show`/`git ls-tree`, and
649
+ * the same discovery rules (reserved segments, README exclusion, include[])
650
+ * are applied to that listing. Lets a PR diff its publish set against its
651
+ * merge base in a CI job that has no second worktree and no installed deps
652
+ * for the base.
653
+ *
654
+ * APPROXIMATION, base side only: this reimplementation skips schema
655
+ * validation (an invalid docs.json publishes nothing in real discovery but
656
+ * is walked here), nested-root rejection, and route-collision detection, so
657
+ * it can OVER-report the base's publish set (a spurious "removed" row in the
658
+ * summary) — never under-report the head's. The head side is always real
659
+ * discovery; the gate's assertions never read this function.
660
+ */
661
+ export function publishSetAtRef(repoRoot, ref) {
662
+ const git = (gitArgs) => execFileSync("git", gitArgs, {
663
+ cwd: repoRoot,
664
+ encoding: "utf-8",
665
+ maxBuffer: 64 * 1024 * 1024,
666
+ });
667
+ const allFiles = git(["ls-tree", "-r", "--name-only", ref])
668
+ .split("\n")
669
+ .filter(Boolean);
670
+ const docsJsonPaths = allFiles.filter((file) => file === "docs.json" || file.endsWith("/docs.json"));
671
+ const published = new Set();
672
+ for (const docsJsonPath of docsJsonPaths) {
673
+ const rootDir = docsJsonPath === "docs.json"
674
+ ? ""
675
+ : docsJsonPath.slice(0, -"/docs.json".length);
676
+ if (rootDir && hasReservedSegment(rootDir))
677
+ continue;
678
+ let config;
679
+ try {
680
+ config = JSON.parse(git(["show", `${ref}:${docsJsonPath}`]));
681
+ }
682
+ catch {
683
+ continue;
684
+ }
685
+ const prefix = rootDir ? `${rootDir}/` : "";
686
+ for (const file of allFiles) {
687
+ if (!file.startsWith(prefix) || !file.toLowerCase().endsWith(".md"))
688
+ continue;
689
+ const rel = file.slice(prefix.length);
690
+ if (hasReservedSegment(rel))
691
+ continue;
692
+ if (path.posix.basename(file).toLowerCase() === "readme.md")
693
+ continue;
694
+ published.add(file);
695
+ }
696
+ for (const include of config.include ?? []) {
697
+ const normalized = include.replace(/\\/g, "/").replace(/^\.\//, "");
698
+ if (hasReservedSegment(normalized))
699
+ continue;
700
+ if (allFiles.includes(normalized))
701
+ published.add(normalized);
702
+ }
703
+ }
704
+ return [...published].sort();
705
+ }
706
+ export function diffPublishSets(base, head) {
707
+ const baseSet = new Set(base);
708
+ const headSet = new Set(head);
709
+ return {
710
+ added: head.filter((source) => !baseSet.has(source)),
711
+ removed: base.filter((source) => !headSet.has(source)),
712
+ };
713
+ }
714
+ /** Render the publish-set diff as a GitHub job-summary markdown block. */
715
+ export function renderPublishSetSummary(manifest, diff) {
716
+ const lines = [
717
+ `## Docs portal publish set`,
718
+ ``,
719
+ `**${manifest.count} pages publish** from this tree.`,
720
+ ``,
721
+ ];
722
+ if (diff && (diff.added.length > 0 || diff.removed.length > 0)) {
723
+ lines.push(`### Changes vs the merge base`, ``);
724
+ for (const source of diff.added)
725
+ lines.push(`- ➕ \`${source}\``);
726
+ for (const source of diff.removed)
727
+ lines.push(`- ➖ \`${source}\``);
728
+ lines.push(``, `Growing the public surface is a deliberate act — a reviewer should see this list.`);
729
+ }
730
+ else if (diff) {
731
+ lines.push(`No change vs the merge base.`);
732
+ }
733
+ lines.push(``, `<details><summary>Full publish set</summary>`, ``);
734
+ for (const source of manifest.sources)
735
+ lines.push(`- \`${source}\``);
736
+ lines.push(``, `</details>`);
737
+ return `${lines.join("\n")}\n`;
738
+ }
739
+ //# sourceMappingURL=assemble.js.map