zz-meridian 0.35.0 → 0.37.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 (641) hide show
  1. package/README.md +29 -7
  2. package/dist/adopt.js +68 -40
  3. package/dist/cli.js +32 -33
  4. package/dist/command-flags.js +32 -0
  5. package/dist/context.js +2 -2
  6. package/dist/create.js +12 -6
  7. package/dist/files.js +36 -10
  8. package/dist/migrations.js +314 -53
  9. package/dist/ownership.js +8 -7
  10. package/dist/rebrand.js +6 -6
  11. package/dist/reconcile.js +35 -7
  12. package/dist/session.js +18 -52
  13. package/dist/update-session.js +11 -4
  14. package/dist/update.js +4 -5
  15. package/package.json +1 -1
  16. package/payload/.env.example +3 -2
  17. package/payload/CHANGELOG.md +317 -97
  18. package/payload/CONTRIBUTING.md +3 -3
  19. package/payload/LICENSE +21 -0
  20. package/payload/README.md +1 -1
  21. package/payload/app/(dashboard)/(home)/README.md +3 -1
  22. package/payload/app/(dashboard)/(home)/loading.tsx +6 -34
  23. package/payload/app/(dashboard)/(home)/page.tsx +1 -1
  24. package/payload/app/(dashboard)/business/README.md +1 -1
  25. package/payload/app/(dashboard)/business/loading.tsx +6 -32
  26. package/payload/app/(dashboard)/business/page.tsx +1 -1
  27. package/payload/app/(dashboard)/customers/README.md +1 -1
  28. package/payload/app/(dashboard)/customers/[id]/README.md +3 -3
  29. package/payload/app/(dashboard)/engineering/README.md +2 -2
  30. package/payload/app/(dashboard)/engineering/loading.tsx +6 -23
  31. package/payload/app/(dashboard)/engineering/page.tsx +1 -1
  32. package/payload/app/(dashboard)/error.tsx +7 -4
  33. package/payload/app/(dashboard)/keys/README.md +1 -1
  34. package/payload/app/(dashboard)/keys/actions.ts +33 -18
  35. package/payload/app/(dashboard)/layout.tsx +4 -4
  36. package/payload/app/(dashboard)/members/README.md +2 -2
  37. package/payload/app/(dashboard)/members/actions.ts +7 -7
  38. package/payload/app/(dashboard)/members/page.tsx +7 -5
  39. package/payload/app/(dashboard)/operations-tickets/README.md +1 -0
  40. package/payload/app/(dashboard)/operations-tickets/actions.ts +4 -4
  41. package/payload/app/(dashboard)/operations-tickets/page.tsx +12 -9
  42. package/payload/app/(dashboard)/requests/README.md +2 -2
  43. package/payload/app/(dashboard)/requests/[id]/README.md +12 -4
  44. package/payload/app/(dashboard)/requests/[id]/actions.ts +11 -4
  45. package/payload/app/(dashboard)/requests/[id]/page.tsx +4 -3
  46. package/payload/app/(dashboard)/services/README.md +2 -2
  47. package/payload/app/(dashboard)/services/loading.tsx +2 -9
  48. package/payload/app/(dashboard)/settings/README.md +4 -2
  49. package/payload/app/(dashboard)/settings/actions.ts +4 -4
  50. package/payload/app/(dashboard)/usage/README.md +2 -2
  51. package/payload/app/(dashboard)/usage/loading.tsx +2 -9
  52. package/payload/app/(dashboard)/usage/page.tsx +1 -1
  53. package/payload/app/api/assistant/route.ts +34 -13
  54. package/payload/app/api/export/requests/route.ts +9 -4
  55. package/payload/app/embed/error.tsx +2 -2
  56. package/payload/app/embed/now/README.md +1 -0
  57. package/payload/app/embed/now/view.tsx +3 -2
  58. package/payload/app/embed/proposal/README.md +1 -1
  59. package/payload/app/embed/proposal/view.tsx +3 -1
  60. package/payload/app/embed/requests/README.md +2 -2
  61. package/payload/app/embed/requests/view.tsx +4 -3
  62. package/payload/app/layout.tsx +5 -1
  63. package/payload/app/sign-in/README.md +7 -2
  64. package/payload/app/sign-in/actions.ts +13 -8
  65. package/payload/app/sign-in/panel.tsx +21 -5
  66. package/payload/app/system/(atlas)/[section]/[id]/page.tsx +8 -2
  67. package/payload/app/system/(atlas)/_article.tsx +28 -3
  68. package/payload/app/system/(atlas)/page.tsx +6 -6
  69. package/payload/app/system/preview/[section]/[card]/page.tsx +2 -1
  70. package/payload/app/system/preview/[section]/[card]/stage.tsx +3 -2
  71. package/payload/app/system/states/error/page.tsx +4 -6
  72. package/payload/app/system/states/error/view.tsx +9 -0
  73. package/payload/docs/agents.md +14 -8
  74. package/payload/docs/assistant.md +31 -7
  75. package/payload/docs/atlas-scenario-coverage.md +12 -12
  76. package/payload/docs/benchmark.md +1 -1
  77. package/payload/docs/data-layers.md +35 -16
  78. package/payload/docs/distribution.md +24 -10
  79. package/payload/docs/product-workspaces.md +3 -3
  80. package/payload/docs/skill-evals.md +1 -1
  81. package/payload/docs/start-a-dashboard.md +5 -2
  82. package/payload/docs/surfaces.md +8 -3
  83. package/payload/docs/testing.md +37 -2
  84. package/payload/docs/voice.md +1 -1
  85. package/payload/journeys/workspaces.ts +41 -30
  86. package/payload/next.config.ts +3 -11
  87. package/payload/package.json +1 -1
  88. package/payload/proxy.ts +12 -5
  89. package/payload/scripts/ask.ts +16 -5
  90. package/payload/scripts/assistant.ts +2 -0
  91. package/payload/scripts/audit.ts +30 -40
  92. package/payload/scripts/brand.ts +28 -18
  93. package/payload/scripts/check.ts +19 -24
  94. package/payload/scripts/contrast.ts +1 -1
  95. package/payload/scripts/fake-llm.ts +9 -12
  96. package/payload/scripts/interactions.ts +21 -15
  97. package/payload/scripts/keyboard.ts +21 -35
  98. package/payload/scripts/lib/answered.ts +1 -3
  99. package/payload/scripts/lib/args.ts +17 -0
  100. package/payload/scripts/lib/bin.ts +29 -0
  101. package/payload/scripts/lib/chrome.ts +27 -14
  102. package/payload/scripts/lib/context-check.ts +6 -2
  103. package/payload/scripts/lib/coverage.ts +20 -2
  104. package/payload/scripts/lib/data-url.ts +67 -43
  105. package/payload/scripts/lib/deep.ts +46 -4
  106. package/payload/scripts/lib/effective-manifest.ts +19 -0
  107. package/payload/scripts/lib/journey.ts +47 -18
  108. package/payload/scripts/lib/layer-rules.ts +24 -11
  109. package/payload/scripts/lib/nav-under.ts +25 -8
  110. package/payload/scripts/lib/routes.ts +16 -9
  111. package/payload/scripts/lib/sample.ts +9 -4
  112. package/payload/scripts/lib/sizes.ts +3 -2
  113. package/payload/scripts/lib/team-config.ts +25 -0
  114. package/payload/scripts/lib/update-session.ts +9 -4
  115. package/payload/scripts/live.ts +39 -36
  116. package/payload/scripts/navigate.ts +6 -23
  117. package/payload/scripts/perf.ts +5 -4
  118. package/payload/scripts/rail.ts +10 -12
  119. package/payload/scripts/registry.ts +12 -12
  120. package/payload/scripts/shot.ts +5 -8
  121. package/payload/scripts/sizes.ts +3 -3
  122. package/payload/scripts/tokens.ts +23 -8
  123. package/payload/scripts/verify.baseline.json +29 -29
  124. package/payload/scripts/verify.config.ts +14 -5
  125. package/payload/scripts/verify.ts +17 -20
  126. package/payload/scripts/vitals.ts +4 -1
  127. package/payload/skills/zz-meridian/SKILL.md +2 -2
  128. package/payload/skills/zz-meridian/references/agents.md +14 -8
  129. package/payload/skills/zz-meridian/references/cache.md +34 -22
  130. package/payload/skills/zz-meridian/references/customize.md +51 -26
  131. package/payload/skills/zz-meridian/references/data-layers.md +35 -16
  132. package/payload/skills/zz-meridian/references/existing-project.md +5 -3
  133. package/payload/skills/zz-meridian/references/live.md +18 -27
  134. package/payload/skills/zz-meridian/references/ownership.md +4 -3
  135. package/payload/skills/zz-meridian/references/update.md +14 -4
  136. package/payload/skills/zz-meridian/references/validation.md +14 -2
  137. package/payload/skills/zz-meridian/references/voice.md +1 -1
  138. package/payload/src/components/base/motion/README.md +1 -1
  139. package/payload/src/components/base/motion/preview.tsx +2 -2
  140. package/payload/src/components/base/providers.tsx +24 -7
  141. package/payload/src/components/base/shell/README.md +5 -1
  142. package/payload/src/components/base/shell/index.tsx +10 -5
  143. package/payload/src/components/base/shell/leave-question.tsx +1 -1
  144. package/payload/src/components/base/shell/preview.tsx +5 -3
  145. package/payload/src/components/base/surface/index.tsx +14 -5
  146. package/payload/src/components/base/text-roles/README.md +1 -1
  147. package/payload/src/components/base/text-roles/preview.tsx +2 -2
  148. package/payload/src/components/charts/bar-list/index.tsx +6 -4
  149. package/payload/src/components/charts/bar-list/preview.tsx +1 -1
  150. package/payload/src/components/charts/column-chart/README.md +1 -1
  151. package/payload/src/components/charts/column-chart/grouped.tsx +25 -17
  152. package/payload/src/components/charts/column-chart/index.tsx +30 -18
  153. package/payload/src/components/charts/column-chart/shared.tsx +0 -1
  154. package/payload/src/components/charts/composition-bar/README.md +1 -1
  155. package/payload/src/components/charts/composition-bar/index.tsx +13 -10
  156. package/payload/src/components/charts/diverging-bars/index.tsx +2 -1
  157. package/payload/src/components/charts/heatmap/README.md +1 -1
  158. package/payload/src/components/charts/heatmap/index.tsx +17 -10
  159. package/payload/src/components/charts/meridian/README.md +3 -2
  160. package/payload/src/components/charts/meridian/index.tsx +15 -3
  161. package/payload/src/components/charts/sparkline/README.md +1 -1
  162. package/payload/src/components/charts/sparkline/index.tsx +12 -2
  163. package/payload/src/components/charts/sparkline/preview.tsx +7 -18
  164. package/payload/src/components/charts/trend-chart/README.md +2 -2
  165. package/payload/src/components/charts/trend-chart/index.tsx +17 -7
  166. package/payload/src/components/charts/uptime-bars/README.md +5 -2
  167. package/payload/src/components/charts/uptime-bars/index.tsx +22 -10
  168. package/payload/src/components/charts/uptime-bars/preview.tsx +22 -3
  169. package/payload/src/components/patterns/activity-feed/README.md +3 -3
  170. package/payload/src/components/patterns/activity-feed/index.tsx +2 -1
  171. package/payload/src/components/patterns/activity-feed/preview.tsx +11 -1
  172. package/payload/src/components/patterns/appearance-menu/README.md +6 -6
  173. package/payload/src/components/patterns/appearance-menu/index.tsx +7 -17
  174. package/payload/src/components/patterns/appearance-menu/preview.tsx +12 -11
  175. package/payload/src/components/patterns/ask-about/index.tsx +5 -4
  176. package/payload/src/components/patterns/assistant/README.md +4 -4
  177. package/payload/src/components/patterns/assistant/index.tsx +49 -23
  178. package/payload/src/components/patterns/assistant/preview.tsx +9 -4
  179. package/payload/src/components/patterns/command-palette/README.md +12 -5
  180. package/payload/src/components/patterns/command-palette/index.tsx +9 -10
  181. package/payload/src/components/patterns/command-palette/open.ts +36 -0
  182. package/payload/src/components/patterns/data-table/README.md +4 -3
  183. package/payload/src/components/patterns/data-table/index.tsx +20 -13
  184. package/payload/src/components/patterns/data-table/preview.tsx +8 -2
  185. package/payload/src/components/patterns/detail-head/README.md +1 -1
  186. package/payload/src/components/patterns/detail-head/index.tsx +1 -1
  187. package/payload/src/components/patterns/embed-frame/README.md +1 -1
  188. package/payload/src/components/patterns/embed-frame/index.tsx +12 -18
  189. package/payload/src/components/patterns/embed-frame/preview.tsx +8 -2
  190. package/payload/src/components/patterns/export-button/README.md +7 -5
  191. package/payload/src/components/patterns/export-button/index.tsx +10 -5
  192. package/payload/src/components/patterns/export-button/preview.tsx +4 -3
  193. package/payload/src/components/patterns/filter-bar/README.md +4 -4
  194. package/payload/src/components/patterns/filter-bar/index.tsx +6 -3
  195. package/payload/src/components/patterns/form-section/README.md +4 -4
  196. package/payload/src/components/patterns/form-section/index.tsx +9 -10
  197. package/payload/src/components/patterns/form-section/preview.tsx +5 -0
  198. package/payload/src/components/patterns/metric-tile/index.tsx +2 -2
  199. package/payload/src/components/patterns/metric-tile/preview.tsx +7 -19
  200. package/payload/src/components/patterns/page-loading/README.md +1 -1
  201. package/payload/src/components/patterns/page-loading/index.tsx +40 -0
  202. package/payload/src/components/patterns/page-loading/preview.tsx +7 -2
  203. package/payload/src/components/patterns/proposal/README.md +8 -7
  204. package/payload/src/components/patterns/proposal/index.tsx +10 -8
  205. package/payload/src/components/patterns/proposal/preview.tsx +4 -1
  206. package/payload/src/components/patterns/prose/preview.tsx +2 -2
  207. package/payload/src/components/patterns/rail/README.md +7 -5
  208. package/payload/src/components/patterns/rail/index.tsx +6 -8
  209. package/payload/src/components/patterns/rail/trail.ts +18 -4
  210. package/payload/src/components/patterns/shell-tools/README.md +3 -3
  211. package/payload/src/components/patterns/shell-tools/index.tsx +20 -5
  212. package/payload/src/components/patterns/status-list/README.md +1 -1
  213. package/payload/src/components/patterns/status-list/index.tsx +2 -3
  214. package/payload/src/components/patterns/status-list/preview.tsx +1 -1
  215. package/payload/src/components/ui/avatar/README.md +6 -4
  216. package/payload/src/components/ui/avatar/index.tsx +14 -3
  217. package/payload/src/components/ui/avatar/preview.tsx +3 -0
  218. package/payload/src/components/ui/badge/index.tsx +3 -2
  219. package/payload/src/components/ui/banner/README.md +3 -3
  220. package/payload/src/components/ui/banner/index.tsx +4 -3
  221. package/payload/src/components/ui/banner/preview.tsx +5 -3
  222. package/payload/src/components/ui/breadcrumb/README.md +3 -3
  223. package/payload/src/components/ui/breadcrumb/index.tsx +9 -3
  224. package/payload/src/components/ui/breadcrumb/preview.tsx +5 -0
  225. package/payload/src/components/ui/button/README.md +3 -0
  226. package/payload/src/components/ui/button/index.tsx +31 -15
  227. package/payload/src/components/ui/button/preview.tsx +12 -0
  228. package/payload/src/components/ui/card/README.md +4 -4
  229. package/payload/src/components/ui/card/preview.tsx +5 -5
  230. package/payload/src/components/ui/checkbox/README.md +2 -2
  231. package/payload/src/components/ui/checkbox/index.tsx +4 -2
  232. package/payload/src/components/ui/copy-field/README.md +5 -2
  233. package/payload/src/components/ui/copy-field/index.tsx +50 -21
  234. package/payload/src/components/ui/copy-field/preview.tsx +2 -0
  235. package/payload/src/components/ui/delta/README.md +2 -2
  236. package/payload/src/components/ui/delta/index.tsx +5 -2
  237. package/payload/src/components/ui/dialog/README.md +1 -1
  238. package/payload/src/components/ui/dialog/index.tsx +14 -4
  239. package/payload/src/components/ui/dialog/preview.tsx +4 -4
  240. package/payload/src/components/ui/disclosure/README.md +1 -1
  241. package/payload/src/components/ui/empty-state/README.md +1 -1
  242. package/payload/src/components/ui/empty-state/index.tsx +2 -2
  243. package/payload/src/components/ui/field/README.md +2 -2
  244. package/payload/src/components/ui/icon-button/preview.tsx +2 -1
  245. package/payload/src/components/ui/input/index.tsx +4 -2
  246. package/payload/src/components/ui/input/preview.tsx +1 -1
  247. package/payload/src/components/ui/key-value/README.md +4 -4
  248. package/payload/src/components/ui/key-value/index.tsx +23 -19
  249. package/payload/src/components/ui/key-value/preview.tsx +1 -1
  250. package/payload/src/components/ui/menu/README.md +1 -0
  251. package/payload/src/components/ui/menu/index.tsx +1 -1
  252. package/payload/src/components/ui/pagination/README.md +3 -3
  253. package/payload/src/components/ui/pagination/index.tsx +3 -2
  254. package/payload/src/components/ui/pagination/preview.tsx +10 -4
  255. package/payload/src/components/ui/popover/README.md +3 -3
  256. package/payload/src/components/ui/popover/index.tsx +4 -1
  257. package/payload/src/components/ui/popover/preview.tsx +17 -11
  258. package/payload/src/components/ui/progress/README.md +4 -1
  259. package/payload/src/components/ui/progress/index.tsx +18 -13
  260. package/payload/src/components/ui/progress/preview.tsx +6 -2
  261. package/payload/src/components/ui/radio-group/README.md +7 -1
  262. package/payload/src/components/ui/radio-group/index.tsx +6 -4
  263. package/payload/src/components/ui/radio-group/preview.tsx +11 -1
  264. package/payload/src/components/ui/search-input/README.md +2 -0
  265. package/payload/src/components/ui/search-input/index.tsx +3 -2
  266. package/payload/src/components/ui/search-input/preview.tsx +8 -2
  267. package/payload/src/components/ui/segmented/README.md +1 -1
  268. package/payload/src/components/ui/segmented/index.tsx +1 -1
  269. package/payload/src/components/ui/segmented/preview.tsx +18 -2
  270. package/payload/src/components/ui/select/index.tsx +1 -1
  271. package/payload/src/components/ui/select/preview.tsx +1 -2
  272. package/payload/src/components/ui/sheet/README.md +1 -1
  273. package/payload/src/components/ui/sheet/index.tsx +1 -1
  274. package/payload/src/components/ui/sheet/preview.tsx +2 -2
  275. package/payload/src/components/ui/status-dot/README.md +5 -5
  276. package/payload/src/components/ui/status-dot/index.tsx +2 -1
  277. package/payload/src/components/ui/status-dot/preview.tsx +4 -1
  278. package/payload/src/components/ui/switch/README.md +1 -1
  279. package/payload/src/components/ui/switch/index.tsx +4 -2
  280. package/payload/src/components/ui/table/README.md +3 -3
  281. package/payload/src/components/ui/table/preview.tsx +4 -2
  282. package/payload/src/components/ui/tabs/README.md +3 -3
  283. package/payload/src/components/ui/tabs/index.tsx +2 -0
  284. package/payload/src/components/ui/textarea/README.md +1 -1
  285. package/payload/src/components/ui/textarea/index.tsx +2 -2
  286. package/payload/src/components/ui/toast/README.md +3 -2
  287. package/payload/src/components/ui/toast/index.tsx +58 -7
  288. package/payload/src/data/README.md +5 -3
  289. package/payload/src/data/access.ts +14 -9
  290. package/payload/src/data/collections.ts +20 -17
  291. package/payload/src/data/derived.ts +15 -13
  292. package/payload/src/data/live-stream.ts +9 -20
  293. package/payload/src/data/member-mutations.ts +36 -30
  294. package/payload/src/data/metrics.ts +7 -18
  295. package/payload/src/data/read.ts +10 -7
  296. package/payload/src/data/requests.ts +6 -9
  297. package/payload/src/data/sample.ts +3 -3
  298. package/payload/src/data/ticket-mutations.ts +3 -3
  299. package/payload/src/data/uptime.ts +2 -2
  300. package/payload/src/data/view-as.ts +4 -4
  301. package/payload/src/lib/assistant/prompt.ts +10 -7
  302. package/payload/src/lib/assistant/scoped.ts +2 -2
  303. package/payload/src/lib/assistant/tools.ts +35 -19
  304. package/payload/src/lib/collection.ts +17 -2
  305. package/payload/src/lib/csv.ts +8 -2
  306. package/payload/src/lib/demo-gate.ts +5 -0
  307. package/payload/src/lib/explore.ts +15 -12
  308. package/payload/src/lib/facts.ts +12 -7
  309. package/payload/src/lib/format-date.ts +23 -16
  310. package/payload/src/lib/format.ts +17 -0
  311. package/payload/src/lib/live.ts +2 -1
  312. package/payload/src/lib/sort.ts +11 -0
  313. package/payload/src/lib/totals.ts +24 -0
  314. package/payload/src/logic/alerts.ts +6 -3
  315. package/payload/src/logic/customer-context.ts +6 -5
  316. package/payload/src/logic/customers-context.ts +16 -7
  317. package/payload/src/logic/derivations.ts +2 -2
  318. package/payload/src/logic/fact-insight.ts +9 -3
  319. package/payload/src/logic/home-context.ts +15 -13
  320. package/payload/src/logic/home-parts.ts +26 -25
  321. package/payload/src/logic/keys-context.ts +1 -1
  322. package/payload/src/logic/members-context.ts +4 -2
  323. package/payload/src/logic/now-context.ts +1 -3
  324. package/payload/src/logic/now-parts.ts +9 -9
  325. package/payload/src/logic/releases-context.ts +2 -1
  326. package/payload/src/logic/request-context.ts +18 -10
  327. package/payload/src/logic/requests-context.ts +2 -1
  328. package/payload/src/logic/requests-explore.ts +2 -3
  329. package/payload/src/logic/revenue-context.ts +13 -9
  330. package/payload/src/logic/revenue-parts.ts +16 -16
  331. package/payload/src/logic/services-context.ts +2 -2
  332. package/payload/src/logic/tests-context.ts +2 -2
  333. package/payload/src/logic/tools.ts +2 -2
  334. package/payload/src/logic/usage-context.ts +6 -5
  335. package/payload/src/logic/usage-parts.ts +4 -5
  336. package/payload/src/styles/base.css +21 -5
  337. package/payload/src/styles/fonts/Geist-Variable.woff2 +0 -0
  338. package/payload/src/styles/fonts/GeistMono-Variable.woff2 +0 -0
  339. package/payload/src/styles/tokens.css +35 -5
  340. package/payload/src/system/atlas-shell.tsx +4 -3
  341. package/payload/src/system/card-stage.tsx +12 -3
  342. package/payload/src/system/content.ts +8 -2
  343. package/payload/src/system/fixtures/company.ts +9 -12
  344. package/payload/src/system/fixtures/sample-records.ts +11 -7
  345. package/payload/src/system/fixtures/sample.ts +0 -1
  346. package/payload/src/system/hero.tsx +9 -6
  347. package/payload/src/system/page-stage.tsx +2 -2
  348. package/payload/src/system/preview-loading.tsx +7 -0
  349. package/payload/src/system/sample-cells.tsx +14 -5
  350. package/payload/src/system/token-view.tsx +9 -9
  351. package/payload/src/views/console-chrome.tsx +6 -1
  352. package/payload/src/views/console-live.tsx +4 -3
  353. package/payload/src/views/customer.tsx +12 -8
  354. package/payload/src/views/customers.tsx +1 -3
  355. package/payload/src/views/home.tsx +9 -11
  356. package/payload/src/views/keys.tsx +16 -8
  357. package/payload/src/views/members.tsx +42 -34
  358. package/payload/src/views/no-access.tsx +5 -4
  359. package/payload/src/views/not-found-address.tsx +1 -1
  360. package/payload/src/views/not-found.tsx +2 -4
  361. package/payload/src/views/now.tsx +7 -9
  362. package/payload/src/views/period-actions.tsx +4 -4
  363. package/payload/src/views/refusal.tsx +1 -1
  364. package/payload/src/views/releases.tsx +3 -3
  365. package/payload/src/views/request.tsx +38 -22
  366. package/payload/src/views/requests.tsx +2 -3
  367. package/payload/src/views/revenue.tsx +11 -14
  368. package/payload/src/views/roles-matrix.tsx +5 -3
  369. package/payload/src/views/sample-footer.tsx +12 -8
  370. package/payload/src/views/settings.tsx +18 -10
  371. package/payload/src/views/tests.tsx +8 -9
  372. package/payload/src/views/tickets.tsx +32 -17
  373. package/payload/src/views/unread.tsx +2 -1
  374. package/payload/src/views/usage.tsx +3 -6
  375. package/payload/src/views/workspaces.ts +4 -11
  376. package/payload/tests/action-needs.test.tsx +1 -1
  377. package/payload/tests/activity-feed-link.test.tsx +1 -2
  378. package/payload/tests/agent-page-spec.test.ts +2 -3
  379. package/payload/tests/agents.test.tsx +0 -11
  380. package/payload/tests/alerts-read.test.tsx +33 -0
  381. package/payload/tests/appearance-menu-keyboard.test.tsx +29 -0
  382. package/payload/tests/assistant-access.test.ts +8 -22
  383. package/payload/tests/assistant-column-draft.test.tsx +57 -0
  384. package/payload/tests/assistant-explore-tool.test.ts +3 -19
  385. package/payload/tests/assistant-guard.test.ts +114 -3
  386. package/payload/tests/assistant-ime.test.tsx +18 -0
  387. package/payload/tests/assistant-page-text.test.tsx +6 -4
  388. package/payload/tests/assistant-panel.test.tsx +4 -5
  389. package/payload/tests/assistant-prompt-truth.test.ts +5 -12
  390. package/payload/tests/assistant-prompt-writes.test.ts +1 -4
  391. package/payload/tests/assistant-proposal.test.tsx +40 -5
  392. package/payload/tests/assistant-questions.test.tsx +0 -4
  393. package/payload/tests/assistant-route.test.ts +10 -0
  394. package/payload/tests/assistant-safety.test.ts +80 -2
  395. package/payload/tests/assistant-settings.test.tsx +9 -7
  396. package/payload/tests/assistant-stale-scope.test.tsx +0 -4
  397. package/payload/tests/assistant-thread-scope.test.tsx +1 -5
  398. package/payload/tests/assistant-thread.test.tsx +0 -1
  399. package/payload/tests/assistant-tools.test.ts +2 -4
  400. package/payload/tests/assistant-withheld.test.ts +4 -13
  401. package/payload/tests/atlas-layers.test.ts +18 -39
  402. package/payload/tests/atlas-product-slice.test.tsx +1 -29
  403. package/payload/tests/atlas-shell-early-press.test.tsx +24 -0
  404. package/payload/tests/atlas-template-contracts.test.tsx +2 -69
  405. package/payload/tests/avatar-initials.test.tsx +34 -0
  406. package/payload/tests/banner-preview.test.tsx +18 -0
  407. package/payload/tests/bar-list-forms.test.tsx +30 -13
  408. package/payload/tests/bar-list-links.test.tsx +1 -1
  409. package/payload/tests/brand-config.test.tsx +1 -4
  410. package/payload/tests/breadcrumb-fold.test.tsx +20 -0
  411. package/payload/tests/button-busy.test.tsx +45 -0
  412. package/payload/tests/card-header-title.test.tsx +0 -14
  413. package/payload/tests/card-stage-hydration.test.tsx +2 -12
  414. package/payload/tests/card-stage-loading.test.tsx +40 -0
  415. package/payload/tests/chart-count-default.test.tsx +20 -0
  416. package/payload/tests/chart-scale-held.test.ts +1 -1
  417. package/payload/tests/chart-semantics.test.tsx +3 -3
  418. package/payload/tests/chart-table-memo.test.tsx +51 -0
  419. package/payload/tests/check-nav-under.test.ts +27 -7
  420. package/payload/tests/choice-description.test.tsx +33 -0
  421. package/payload/tests/chrome-navigation.test.tsx +7 -8
  422. package/payload/tests/client-imports.test.ts +0 -8
  423. package/payload/tests/collection-aggregate.test.ts +8 -9
  424. package/payload/tests/column-chart-crowded.test.tsx +0 -7
  425. package/payload/tests/column-chart-grouped.test.tsx +5 -21
  426. package/payload/tests/column-chart-labels.test.tsx +4 -42
  427. package/payload/tests/column-chart-no-data.test.tsx +0 -4
  428. package/payload/tests/column-chart-readout.test.tsx +0 -3
  429. package/payload/tests/column-chart-running.test.tsx +0 -21
  430. package/payload/tests/column-chart-signed.test.tsx +1 -4
  431. package/payload/tests/column-chart.test.tsx +2 -8
  432. package/payload/tests/composition-bar.test.tsx +22 -9
  433. package/payload/tests/console-chrome.test.tsx +12 -12
  434. package/payload/tests/console-live.test.tsx +4 -0
  435. package/payload/tests/context-check.test.ts +3 -0
  436. package/payload/tests/contexts-timezone.test.ts +45 -0
  437. package/payload/tests/copy-field.test.tsx +197 -1
  438. package/payload/tests/counts-and-lists.test.tsx +3 -15
  439. package/payload/tests/csv-bom.test.ts +27 -0
  440. package/payload/tests/customer-empty-period.test.ts +25 -0
  441. package/payload/tests/customer-figures.test.ts +28 -12
  442. package/payload/tests/customers-masthead.test.tsx +0 -1
  443. package/payload/tests/customers-payload.test.tsx +3 -6
  444. package/payload/tests/data-model.test.ts +0 -1
  445. package/payload/tests/data-read.test.ts +3 -4
  446. package/payload/tests/data-table-manual-size.test.tsx +21 -0
  447. package/payload/tests/data-table.test.tsx +26 -10
  448. package/payload/tests/day-in-progress.test.ts +0 -2
  449. package/payload/tests/delta-flat.test.tsx +26 -0
  450. package/payload/tests/demo-gate.test.ts +14 -1
  451. package/payload/tests/demo-policy.test.ts +0 -1
  452. package/payload/tests/derivations.test.ts +5 -24
  453. package/payload/tests/derived-answer.test.ts +178 -19
  454. package/payload/tests/dialog-focus.test.tsx +33 -0
  455. package/payload/tests/disclosure.test.tsx +4 -5
  456. package/payload/tests/diverging-bars.test.tsx +2 -7
  457. package/payload/tests/effective-manifest.test.ts +56 -0
  458. package/payload/tests/embed-context-lifetime.test.tsx +79 -0
  459. package/payload/tests/embed-page-failure.test.tsx +1 -8
  460. package/payload/tests/embed-proposal.test.tsx +43 -0
  461. package/payload/tests/embed-requests-provenance.test.tsx +46 -1
  462. package/payload/tests/embed-theme.test.tsx +62 -0
  463. package/payload/tests/engineering-records.test.ts +1 -19
  464. package/payload/tests/engineering-workflows.test.ts +4 -57
  465. package/payload/tests/explore-answer-length.test.ts +4 -26
  466. package/payload/tests/explore-contract.test.ts +2 -5
  467. package/payload/tests/explore-group-change.test.ts +5 -12
  468. package/payload/tests/explore-io.ts +16 -0
  469. package/payload/tests/explore-money.test.ts +6 -12
  470. package/payload/tests/explore-narrowed-measure.test.ts +6 -11
  471. package/payload/tests/explore-none.test.ts +4 -8
  472. package/payload/tests/explore-percent.test.ts +5 -12
  473. package/payload/tests/explore-refers.test.ts +7 -6
  474. package/payload/tests/explore-runner.test.ts +3 -5
  475. package/payload/tests/export-button.test.tsx +45 -0
  476. package/payload/tests/facts-config.test.ts +0 -6
  477. package/payload/tests/facts-engineering.test.ts +1 -12
  478. package/payload/tests/facts.test.ts +1 -18
  479. package/payload/tests/failed-request.test.ts +20 -0
  480. package/payload/tests/fake-llm.test.ts +1 -1
  481. package/payload/tests/feature-access.test.ts +2 -9
  482. package/payload/tests/feature-definitions.test.ts +1 -21
  483. package/payload/tests/featured-metric.test.tsx +1 -24
  484. package/payload/tests/feel-column-chart.test.tsx +1 -1
  485. package/payload/tests/feel-sparkline.test.tsx +13 -1
  486. package/payload/tests/filter-bar-search.test.tsx +10 -15
  487. package/payload/tests/form-section-actions.test.tsx +0 -3
  488. package/payload/tests/form-section-readonly.test.tsx +14 -0
  489. package/payload/tests/format-currency.test.ts +1 -1
  490. package/payload/tests/format-date-calendar.test.ts +23 -0
  491. package/payload/tests/format-semantics.test.ts +1 -3
  492. package/payload/tests/format.test.ts +31 -23
  493. package/payload/tests/heatmap-states.test.tsx +1 -37
  494. package/payload/tests/honest-controls.test.tsx +8 -28
  495. package/payload/tests/incident-card-hyphens.test.tsx +3 -18
  496. package/payload/tests/incident-card.test.tsx +1 -1
  497. package/payload/tests/input-states.test.tsx +12 -0
  498. package/payload/tests/key-value.test.tsx +11 -32
  499. package/payload/tests/keys-actions.test.ts +8 -7
  500. package/payload/tests/keys-gate.test.tsx +8 -31
  501. package/payload/tests/keys-scopes-view.test.tsx +1 -2
  502. package/payload/tests/keys-secret-view.test.tsx +2 -3
  503. package/payload/tests/linked-records.test.ts +12 -38
  504. package/payload/tests/live-client.test.tsx +66 -1
  505. package/payload/tests/live-resume.test.ts +0 -2
  506. package/payload/tests/live-route.test.ts +3 -3
  507. package/payload/tests/loading-routes.test.tsx +1 -10
  508. package/payload/tests/logo.test.ts +13 -0
  509. package/payload/tests/member-duplicate.test.ts +12 -1
  510. package/payload/tests/member-mutations.test.ts +30 -28
  511. package/payload/tests/member-roles.test.ts +0 -11
  512. package/payload/tests/member-roster-boundary.test.ts +3 -9
  513. package/payload/tests/members-optimistic.test.tsx +61 -60
  514. package/payload/tests/meridian.test.tsx +25 -2
  515. package/payload/tests/metric-tile-compact.test.tsx +0 -38
  516. package/payload/tests/metric-tile-delta-format.test.tsx +1 -2
  517. package/payload/tests/metric-tile-note.test.tsx +1 -15
  518. package/payload/tests/metric-tile-pointed-empty.test.tsx +1 -1
  519. package/payload/tests/metric-tile-title.test.tsx +0 -1
  520. package/payload/tests/metric-tile.test.tsx +2 -17
  521. package/payload/tests/next-start.test.ts +21 -0
  522. package/payload/tests/no-access.test.tsx +18 -10
  523. package/payload/tests/not-found.test.ts +7 -4
  524. package/payload/tests/page-frame-title.test.tsx +7 -99
  525. package/payload/tests/page-gates.test.tsx +2 -2
  526. package/payload/tests/page-loading.test.tsx +66 -45
  527. package/payload/tests/page-server-module.test.ts +32 -0
  528. package/payload/tests/pages-read-every-row.test.tsx +17 -31
  529. package/payload/tests/pagination-sizes.test.tsx +16 -0
  530. package/payload/tests/palette-hint.test.tsx +2 -6
  531. package/payload/tests/palette-ime.test.tsx +46 -0
  532. package/payload/tests/palette-open.test.ts +24 -0
  533. package/payload/tests/period-whole-previous.test.ts +25 -0
  534. package/payload/tests/plural.test.ts +11 -1
  535. package/payload/tests/popover-name.test.tsx +15 -0
  536. package/payload/tests/popover-preview.test.tsx +14 -0
  537. package/payload/tests/preview-live-controls.test.tsx +37 -0
  538. package/payload/tests/progress-values.test.tsx +40 -0
  539. package/payload/tests/proposal-approval.test.tsx +31 -0
  540. package/payload/tests/prose-cell-labels.test.tsx +0 -8
  541. package/payload/tests/providers-stored.test.tsx +28 -0
  542. package/payload/tests/rail-branch-feel.test.tsx +3 -71
  543. package/payload/tests/rail-branch.test.tsx +17 -23
  544. package/payload/tests/rail-name-title.test.tsx +0 -4
  545. package/payload/tests/rail-trail.test.ts +16 -1
  546. package/payload/tests/read-all-query.test.ts +56 -8
  547. package/payload/tests/read-every-row.test.ts +6 -16
  548. package/payload/tests/records-consumers.test.tsx +9 -76
  549. package/payload/tests/refusal-descriptor.test.ts +1 -12
  550. package/payload/tests/release-phone-cell.test.ts +0 -3
  551. package/payload/tests/release-wording.test.ts +2 -7
  552. package/payload/tests/request-curl.test.ts +108 -0
  553. package/payload/tests/request-keys-link.test.tsx +24 -0
  554. package/payload/tests/request-replay.test.ts +19 -1
  555. package/payload/tests/request-usage.test.tsx +40 -0
  556. package/payload/tests/request-view-replay.test.tsx +36 -28
  557. package/payload/tests/requests-export.test.ts +15 -1
  558. package/payload/tests/requests-p95-one-rule.test.ts +24 -0
  559. package/payload/tests/requests-query.test.ts +6 -3
  560. package/payload/tests/requests-summary-newest.test.ts +0 -1
  561. package/payload/tests/review-held-scales.test.tsx +1 -31
  562. package/payload/tests/roles-context.test.ts +0 -1
  563. package/payload/tests/roles-matrix-redraw.test.tsx +22 -0
  564. package/payload/tests/roles-matrix.test.tsx +0 -2
  565. package/payload/tests/routes-discover-shapes.test.ts +45 -0
  566. package/payload/tests/script-args.test.ts +86 -0
  567. package/payload/tests/search-input.test.tsx +54 -0
  568. package/payload/tests/segmented-measure.test.tsx +23 -0
  569. package/payload/tests/served.tsx +34 -0
  570. package/payload/tests/settings-access.test.tsx +11 -11
  571. package/payload/tests/settings-agents.test.tsx +0 -25
  572. package/payload/tests/settings-save.test.tsx +15 -11
  573. package/payload/tests/setup.ts +4 -0
  574. package/payload/tests/shared-context.test.tsx +132 -105
  575. package/payload/tests/shell-alerts.test.ts +11 -13
  576. package/payload/tests/shell-drawer-open.test.tsx +3 -2
  577. package/payload/tests/shell-first-arrival.test.tsx +0 -6
  578. package/payload/tests/shell-promise.test.tsx +2 -12
  579. package/payload/tests/shell-search-name.test.tsx +14 -10
  580. package/payload/tests/sign-in-answer.test.tsx +37 -0
  581. package/payload/tests/sign-in-honest.test.tsx +20 -12
  582. package/payload/tests/sign-in-persona.test.ts +28 -6
  583. package/payload/tests/sparkline-forms.test.tsx +5 -5
  584. package/payload/tests/specimen-still.test.tsx +1 -1
  585. package/payload/tests/status-list.test.tsx +8 -0
  586. package/payload/tests/table-cut-cell.test.tsx +14 -42
  587. package/payload/tests/table-grid.test.tsx +3 -59
  588. package/payload/tests/template-consumers.test.tsx +0 -4
  589. package/payload/tests/ticket-mutations.test.ts +0 -1
  590. package/payload/tests/ticket-owner.test.ts +0 -10
  591. package/payload/tests/tickets-view.test.tsx +61 -9
  592. package/payload/tests/tile-row.test.tsx +29 -0
  593. package/payload/tests/toast-timing.test.tsx +53 -0
  594. package/payload/tests/trend-chart-band.test.tsx +1 -3
  595. package/payload/tests/trend-chart-curve.test.tsx +6 -6
  596. package/payload/tests/trend-chart-forms.test.tsx +6 -7
  597. package/payload/tests/trend-chart-whole.test.tsx +2 -0
  598. package/payload/tests/trend-chart.test.tsx +28 -0
  599. package/payload/tests/truncation-keeps-text.test.tsx +4 -5
  600. package/payload/tests/update-session.test.ts +19 -13
  601. package/payload/tests/uptime-bars-end.test.tsx +2 -4
  602. package/payload/tests/uptime-edges.test.tsx +38 -0
  603. package/payload/tests/uptime-no-data.test.tsx +1 -3
  604. package/payload/tests/uptime-svg.test.tsx +1 -3
  605. package/payload/tests/uptime-tap.test.tsx +15 -0
  606. package/payload/tests/usage-figures.test.ts +0 -12
  607. package/payload/tests/usage-summary.test.tsx +0 -1
  608. package/payload/tests/use-size-late.test.tsx +1 -1
  609. package/payload/tests/verify-coverage.test.ts +10 -0
  610. package/payload/tests/verify-data-url.test.ts +88 -15
  611. package/payload/tests/verify-explore-surfaces.test.ts +10 -7
  612. package/payload/tests/verify-loopback.test.ts +10 -10
  613. package/payload/tests/verify-personas.test.ts +3 -22
  614. package/payload/tests/verify-sample-surfaces.test.ts +34 -11
  615. package/payload/tests/verify-sizes.test.ts +1 -5
  616. package/payload/tests/verify-suite-outcome.test.ts +14 -3
  617. package/payload/tests/verify-timing.test.ts +1 -2
  618. package/payload/tests/view-as.test.ts +1 -7
  619. package/payload/tests/view-tool-modules.test.ts +1 -2
  620. package/payload/tests/view-tool-needs.test.ts +0 -12
  621. package/payload/tests/workspace-access.test.ts +20 -4
  622. package/payload/tests/workspace-chrome.test.tsx +1 -13
  623. package/payload/tests/workspace-data-paths.test.ts +0 -13
  624. package/payload/tests/workspace-figures.test.ts +0 -1
  625. package/payload/tests/workspace-home.test.tsx +0 -10
  626. package/payload/tests/workspaces.test.ts +1 -27
  627. package/payload/tests/bar-list-axis-words.test.tsx +0 -42
  628. package/payload/tests/bypasses.test.ts +0 -72
  629. package/payload/tests/dialog-xl.test.tsx +0 -25
  630. package/payload/tests/feel-bar-list.test.tsx +0 -22
  631. package/payload/tests/forced-colors-states.test.ts +0 -62
  632. package/payload/tests/hatch.test.ts +0 -45
  633. package/payload/tests/heatmap-names-column.test.tsx +0 -30
  634. package/payload/tests/logic-alerts.test.ts +0 -50
  635. package/payload/tests/logic-layer.test.ts +0 -58
  636. package/payload/tests/moved-paths-documented.test.ts +0 -51
  637. package/payload/tests/sample-company.test.ts +0 -227
  638. package/payload/tests/sample.test.ts +0 -158
  639. package/payload/tests/segmented-fit.test.tsx +0 -22
  640. package/payload/tests/table-cut-align.test.tsx +0 -30
  641. package/payload/tests/table-hide-below-pad.test.tsx +0 -18
package/README.md CHANGED
@@ -34,20 +34,29 @@ npx zz-meridian@<version> brand [brand flags] # rebrand this project, with t
34
34
  npx zz-meridian@latest skill [--global] # install only the agent skill
35
35
  ```
36
36
 
37
- Brand flags: `--name "Acme Ops"`, `--hex '#2E6BE4'` (or `--accent indigo|cobalt|jade|graphite`), `--theme dark|light`,
37
+ Brand flags: `--name "Acme Ops"`, `--hex '#2E6BE4'` (or `--hue 250 --chroma 0.14`, or `--accent indigo|cobalt|jade|graphite`), `--theme dark|light`,
38
38
  `--workspace`, `--timezone`, `--currency`, `--user`, `--role`. `--workspace` sets `app.workspace`, the environment named
39
39
  in a page's kicker ("Production"); it does not touch the navigation workspaces.
40
+ `--timezone` must be accepted by `Intl.DateTimeFormat`, for example `UTC` or `Europe/London`; an unsupported zone is refused rather than saved.
41
+ Quoted brand strings remain literal values across repeated rebranding; changing a role does not rewrite the person's existing name.
42
+ Every valued flag needs its own value, including with the standalone `pnpm brand`: missing values and a following flag used as a value are refused before any configuration changes.
43
+ Commands reject extra positional arguments before changing files: only `create` takes a folder argument.
40
44
 
41
45
  **adopt** copies Meridian's tokens, styles, components, gates and scripts into `src/`, `tokens/` and `scripts/`;
42
46
  merges the dependencies and scripts it needs into your `package.json`; adds the `@meridian/*` alias to your
43
47
  `tsconfig.json` (yours is kept as `tsconfig.before.json` when it carries comments or trailing commas, which JSON
44
48
  cannot hold); replaces your global stylesheet (yours is kept
45
- beside it as `*.before.css`); brands it; adds Meridian's managed block to your `AGENTS.md` between two markers, keeping your own text there byte
49
+ beside it as `*.before.css`); preserves string keys and values in your TypeScript configuration, including punctuation;
50
+ brands it; adds Meridian's managed block to your `AGENTS.md` between two markers, keeping your own text there byte
46
51
  for byte; writes an empty `docs/brief.md` (your product, users, data, decisions and glossary) if you have none; installs the skill into
47
52
  `.agents/skills/` (Codex) and `.claude/skills/` (Claude Code); records every Meridian file it copied in `.meridian/manifest.json`;
48
- installs and type checks. Your routes, your data layer and your own components are not touched. Meridian's files
49
- import each other by relative path, so a `components/ui/button` of your own is never confused with Meridian's; your
50
- code imports Meridian as `@meridian/…`.
53
+ installs and reports route-generation and TypeScript diagnostics. An installation failure exits nonzero; diagnostic
54
+ failures are reported as `types: fails` but adoption still exits zero, because your existing routes may need repairs.
55
+ This is not a clean-typecheck guarantee: fix those diagnostics before running the gate. Your routes, your data layer
56
+ and your own components are not touched. Meridian's files import each other by relative path, so a
57
+ `components/ui/button` of your own is never confused with Meridian's; your code imports Meridian as `@meridian/…`.
58
+ Supported dependency specifications below Meridian's required floor are raised, including within the same major;
59
+ newer versions are kept. Custom specifications are kept with a note to confirm compatibility.
51
60
 
52
61
  It refuses, and writes nothing, when the git tree has uncommitted changes (so its change is one reviewable diff), when
53
62
  the project is not Next.js with the App Router, or when a file it would copy already exists with other content.
@@ -68,10 +77,12 @@ writes nothing; run it first.
68
77
  - It reports a migration for each interface the release changed where one of your own files still has the old shape,
69
78
  such as `cache-components-config` or `nav-needs`. `cli/src/migrations.ts` holds every one; resolve them as the skill's
70
79
  `references/update.md` says.
80
+ - Team-owned sample files are checked again on every forward upgrade, even after their migration's introduction, so newer managed tests do not silently outrun the sample they exercise. They remain team-owned: the migration asks for review and never overwrites them.
71
81
  - Everything it did and everything left to do is in `.meridian/update/<version>/MERGE.md`. Resolve the items, then run
72
82
  the pinned `npx zz-meridian@<version> update --finalize`; `--resume` continues an interrupted run and `--abort` restores
73
83
  what it changed. Only finalize records the new version. `--finalize --verify` validates with the project's default
74
84
  `verify` instead of the gate and the build, and reports its coverage line.
85
+ - Failure and coverage metadata is recorded literally in the report, including `$` sequences; it is not interpreted as report-template syntax.
75
86
  - It refuses, writing nothing, on a dirty git tree (unless `--allow-dirty`) or while another update is open. `--verbose`
76
87
  lists every file.
77
88
 
@@ -80,8 +91,11 @@ styles) and `src/app.config.ts` for the new flags and records them in the manife
80
91
  refuses when one of those outputs was edited, while an update is open, or on a dirty tree (unless `--allow-dirty`). Run
81
92
  it with the version the manifest records. The project's own `pnpm brand` still works, but its changes count as your edits.
82
93
 
94
+ **skill** checks both `.agents/skills/zz-meridian` and `.claude/skills/zz-meridian` before writing either. Identical files are retained; different content or symlinks are refused. Move a customized copy aside, install the shipped skill, then reconcile the customization manually rather than losing it to an overwrite.
95
+ An incomplete package without its `SKILL.md` is refused before either destination is written.
96
+
83
97
  The standard a project on Meridian is built to is
84
- [data-layers.md](https://github.com/zhixuan312/zz-meridian/blob/main/docs/data-layers.md): the four layers between a
98
+ [data-layers.md](https://github.com/zhixuan312/zz-meridian/blob/master/docs/data-layers.md): the four layers between a
85
99
  database and the screen, the contract a backend answers, and the six rules a project switches on in its own
86
100
  `scripts/check.local.ts`.
87
101
 
@@ -102,6 +116,14 @@ telemetry. It talks to npm only, when `npx` fetches it and when `update` reads r
102
116
  public, so leave out anything that identifies you, your organisation or your product, and describe the problem with
103
117
  Meridian's own template or sample data.
104
118
 
119
+ ## Maintaining this package
120
+
121
+ From the repository root, run `node cli/scripts/build-payload.ts` before `pnpm exec tsc -p cli/tsconfig.json` and packing. The producer reads committed `HEAD` by default; use `--worktree` to try uncommitted tracked changes. It also generates `cli/src/update-session.ts` from the canonical standalone `scripts/lib/update-session.ts`, using the same source provenance as the payload. Edit only the canonical module, never its generated CLI companion.
122
+ The payload excludes `.env` and its variants at every directory depth, even when tracked; deliberate `.env.example`
123
+ files remain available as public configuration templates. Never put credentials in an example file.
124
+
125
+ The template's copied-command regression runs real cURL on loopback and needs a POSIX shell and `curl`, with no external endpoint or credentials.
126
+
105
127
  ## License
106
128
 
107
- MIT
129
+ MIT: the text is `payload/LICENSE` in the package and `LICENSE` in a project `create` makes.
package/dist/adopt.js CHANGED
@@ -3,20 +3,50 @@
3
3
  * its data layer. Everything here is the settled part of the skill's Route A; rebuilding each page on Meridian's
4
4
  * components is the agent's work, and the printed next step hands it over.
5
5
  *
6
- * Nothing is written until every check has passed: a dirty tree, a project that is not Next.js with the App Router,
7
- * or a file of the same name with other content stops it before the first write.
6
+ * Nothing is written until every check has passed: a project already on Meridian (its manifest: update is the command),
7
+ * a dirty tree, a project that is not Next.js with the App Router, or a file of the same name with other content stops
8
+ * it before the first write.
8
9
  */
9
10
  import fs from 'node:fs';
10
11
  import path from 'node:path';
11
12
  import { VERSION, brandArgs, effectiveBrand, inside, installArgs, installSkill, jsoncExtras, packageManager, payloadBytes, payloadFiles, readJsonc, readPayload, relativeImports, skillPaths, run, runTool, sha256, writeIn, writeManifest, } from './files.js';
12
13
  import { BRIEF_TEMPLATE, managedBlock, upsertManagedBlock } from './context.js';
13
- import { FIXED, adoptSetOf, managedPaths } from './ownership.js';
14
- /** The template's dependencies a dashboard built from these files needs. */
15
- const DEPS = ['next', 'react', 'react-dom', 'radix-ui', 'lucide-react', 'clsx', 'tailwind-merge', 'react-markdown', 'remark-gfm', 'ai', '@ai-sdk/react', 'zod'];
16
- const DEV_DEPS = ['typescript', '@types/node', '@types/react', '@types/react-dom', 'tailwindcss', '@tailwindcss/postcss', 'eslint', 'eslint-config-next', 'vitest', '@vitejs/plugin-react', 'jsdom', '@testing-library/react', '@testing-library/dom', '@testing-library/jest-dom'];
17
- const SCRIPTS = ['typecheck', 'test', 'tokens', 'check', 'contrast', 'gate', 'audit', 'verify', 'brand', 'shot', 'interactions', 'keyboard', 'vitals'];
18
- const major = (spec) => Number(/(\d+)/.exec(spec)?.[1] ?? NaN);
14
+ import { FIXED, adoptSetOf, managedPaths, parseManifest } from './ownership.js';
15
+ import { MERIDIAN_SCRIPTS, TOOLCHAIN, compareMinimum, needOf } from './reconcile.js';
19
16
  const TS = /\.(ts|tsx)$/;
17
+ /** Raise known dependency floors in place; custom specifications stay the team's decision. */
18
+ export function adoptDependencies(pkg, tpl, field, names) {
19
+ const notes = [];
20
+ pkg[field] ??= {};
21
+ for (const n of names) {
22
+ const want = tpl.dependencies?.[n] ?? tpl.devDependencies?.[n];
23
+ if (!want)
24
+ continue;
25
+ const have = pkg.dependencies?.[n] ?? pkg.devDependencies?.[n];
26
+ if (!have) {
27
+ pkg[field][n] = want;
28
+ continue;
29
+ }
30
+ const order = compareMinimum(have, want);
31
+ if (order === null) {
32
+ notes.push(`kept ${n} ${have}, which Meridian cannot compare: confirm it meets ${want} before running the gate`);
33
+ }
34
+ else if (order < 0) {
35
+ const at = pkg.dependencies?.[n] ? 'dependencies' : 'devDependencies';
36
+ pkg[at][n] = want;
37
+ notes.push(`raised ${n} from ${have} to ${want} (Meridian needs this floor; read its upgrade guide)`);
38
+ }
39
+ }
40
+ return notes;
41
+ }
42
+ /** Adoption is installed even when a team's existing routes need type repairs; report both diagnostic stages. */
43
+ function adoptionTypes(root) {
44
+ const route = runTool(root, 'next/dist/bin/next', ['typegen']);
45
+ const tsc = runTool(root, 'typescript/bin/tsc', ['--noEmit']);
46
+ const failures = [['next typegen', route], ['tsc', tsc]];
47
+ const failed = failures.filter(([, result]) => result.status !== 0);
48
+ return failed.length ? `fails:\n${failed.map(([name, result]) => `${name}:\n${(result.stdout + result.stderr).trim().split('\n').slice(0, 30).join('\n')}`).join('\n')}` : 'passes';
49
+ }
20
50
  /** A specifier inside a copied file, pinned to the exact module so a team file of a similar name can never win. */
21
51
  function exactImports(rel, source, known) {
22
52
  const pin = (spec) => {
@@ -93,13 +123,14 @@ export function projectConfig(template, pages) {
93
123
  .replace(/export const nav: NavGroup\[\] = \[[\s\S]*?\n\];/, `/** Written by zz-meridian adopt from the project's pages: give each its own icon and group them. */\nexport const nav: NavGroup[] = [\n {\n items: [\n${items}\n ],\n },\n];`);
94
124
  }
95
125
  /**
96
- * `scripts/verify.config.ts` as a project gets it. The sample's persona rows are what used `EVERY_ROUTE`, so replacing the
97
- * config object leaves the constant declared and never read — which the gate's own lint fails, in the project adopt just
98
- * wrote, 0.7 s after the other steps passed. Exported so a test can hold the rewrite to that.
126
+ * `scripts/verify.config.ts` as a project gets it. The sample's persona rows are what used `EVERY_ROUTE` and `ROLE_ROUTES`,
127
+ * so replacing the config object leaves them declared and never read — which the gate's own lint fails, in the project
128
+ * adopt just wrote, 0.7 s after the other steps passed — and names the sample's routes in the team's file. Each goes
129
+ * with its doc line. Exported so a test can hold the rewrite to that.
99
130
  */
100
131
  export function verifyConfig() {
101
132
  return readPayload('scripts/verify.config.ts')
102
- .replace(/^const EVERY_ROUTE = \[[^\n]*\n/m, '')
133
+ .replace(/^\/\*\*[^\n]*\*\/\nconst (?:EVERY_ROUTE|ROLE_ROUTES) = \[[^\n]*\n\n?/gm, '')
103
134
  .replace(/const config: VerifyConfig = \{[\s\S]*?\n\};/, `const config: VerifyConfig = {
104
135
  // One detail page per state worth seeing (a normal record, a failed one, a missing one), with ids from your data.
105
136
  detailRoutes: [],
@@ -182,6 +213,17 @@ export function adopt(o) {
182
213
  // ── Checks: nothing is written until all of them pass ─────────────────────────────────────────────────
183
214
  if (!fs.existsSync(pkgPath))
184
215
  return fail(`no package.json in ${root}: run adopt in the project's folder`);
216
+ // A project adopt or create already set up holds Meridian's files as its manifest records them, and whatever the team
217
+ // changed since; adopted again, every edited one would be listed as a conflict. Moving it to this release is update's.
218
+ const manifestPath = path.join(root, '.meridian/manifest.json');
219
+ if (fs.existsSync(manifestPath)) {
220
+ let at = '';
221
+ try {
222
+ at = ` ${parseManifest(fs.readFileSync(manifestPath, 'utf8')).version}`;
223
+ }
224
+ catch { /* the version is only named */ }
225
+ return fail(`this project is already on Meridian${at} (.meridian/manifest.json): run npx zz-meridian@latest update to move it to this release`);
226
+ }
185
227
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
186
228
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
187
229
  const dir = appDir(root);
@@ -257,28 +299,13 @@ Rename or move them, then run adopt again.`);
257
299
  }
258
300
  // ── Merged files: the project's own, changed only where Meridian needs it ────────────────────────────
259
301
  const tpl = JSON.parse(readPayload('package.json'));
260
- const merge = (field, names) => {
261
- pkg[field] ??= {};
262
- for (const n of names) {
263
- const want = tpl.dependencies?.[n] ?? tpl.devDependencies?.[n];
264
- if (!want)
265
- continue;
266
- const have = pkg.dependencies?.[n] ?? pkg.devDependencies?.[n];
267
- if (!have) {
268
- pkg[field][n] = want;
269
- continue;
270
- }
271
- if (major(have) < major(want)) {
272
- const at = pkg.dependencies?.[n] ? 'dependencies' : 'devDependencies';
273
- pkg[at][n] = want;
274
- notes.push(`raised ${n} from ${have} to ${want} (Meridian needs the newer major; read its upgrade guide)`);
275
- }
276
- }
277
- };
278
- merge('dependencies', DEPS);
279
- merge('devDependencies', DEV_DEPS);
302
+ // The packages the adopted modules import, and the framework: the rule `update` applies to a created project.
303
+ const sources = new Map(set.filter((rel) => TS.test(rel)).map((rel) => [rel, payloadBytes(rel).toString('utf8')]));
304
+ sources.set('src/app.config.ts', config);
305
+ notes.push(...adoptDependencies(pkg, tpl, 'dependencies', needOf(tpl, sources).runtime));
306
+ notes.push(...adoptDependencies(pkg, tpl, 'devDependencies', TOOLCHAIN));
280
307
  pkg.scripts ??= {};
281
- for (const s of SCRIPTS) {
308
+ for (const s of MERIDIAN_SCRIPTS) {
282
309
  const want = tpl.scripts[s];
283
310
  if (!pkg.scripts[s])
284
311
  pkg.scripts[s] = want;
@@ -364,8 +391,11 @@ Rename or move them, then run adopt again.`);
364
391
  const brandDirs = () => ['tokens', 'src/styles'].flatMap((d) => listFiles(root, d));
365
392
  const existed = new Set(brandDirs());
366
393
  const b = run(process.execPath, ['scripts/brand.ts', ...brandArgs(brand), '--existing'], root);
367
- if (b.status !== 0)
368
- return fail('scripts/brand.ts failed (above); the files are copied, so fix the cause and run it again with the same flags');
394
+ if (b.status !== 0) {
395
+ // From a clean tree, git takes back exactly what adopt wrote; with --allow-dirty it would take the team's changes too.
396
+ const back = o.allowDirty ? 'remove what adopt wrote (git status shows it beside your own changes)' : 'put the tree back (git restore . && git clean -fd removes only what adopt wrote, since it started clean)';
397
+ return fail(`scripts/brand.ts failed (above) after the files were copied, and the manifest and agent files are not written. Fix the cause, ${back}, and run zz-meridian adopt again with the same flags`);
398
+ }
369
399
  // The project's own AGENTS.md keeps every byte and gains the managed block; the brief is the team's, written only when absent.
370
400
  // Neither is a Meridian file, so neither is recorded in the manifest.
371
401
  const pm = packageManager(root);
@@ -390,16 +420,14 @@ Rename or move them, then run adopt again.`);
390
420
  files[rel] = sha256(fs.readFileSync(inside(root, rel)));
391
421
  installSkill(root, files);
392
422
  writeManifest(root, { version: VERSION, route: 'adopt', brand, files });
393
- // ── Install and prove it compiles ─────────────────────────────────────────────────────────────────────
423
+ // ── Install and report type diagnostics (existing team code may still need repairs) ──────────────────
394
424
  let typed = 'not run (--no-install)';
395
425
  if (o.install) {
396
426
  say(`\nInstalling with ${pm}…`);
397
427
  if (run(pm, installArgs(pm), root).status !== 0)
398
428
  return fail(`${pm} install failed (above). Fix it, then run ${pm} install and ${pm} run typecheck.`);
399
- // Route types first (LayoutProps, PageProps), as the gate does.
400
- runTool(root, 'next/dist/bin/next', ['typegen']);
401
- const tsc = runTool(root, 'typescript/bin/tsc', ['--noEmit']);
402
- typed = tsc.status === 0 ? 'passes' : `fails:\n${(tsc.stdout + tsc.stderr).trim().split('\n').slice(0, 30).join('\n')}`;
429
+ // Route types first (LayoutProps, PageProps), as the gate does; neither failure may be reported as passing.
430
+ typed = adoptionTypes(root);
403
431
  }
404
432
  say(`
405
433
  Meridian ${VERSION} is in ${root}.
package/dist/cli.js CHANGED
@@ -5,9 +5,8 @@
5
5
  */
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
- import { parseArgs } from 'node:util';
9
8
  import { adopt } from './adopt.js';
10
- import { misapplied } from './command-flags.js';
9
+ import { misapplied, readFlags } from './command-flags.js';
11
10
  import { create } from './create.js';
12
11
  import { BRAND_FLAGS, VERSION, installSkill } from './files.js';
13
12
  import { brandCommand } from './rebrand.js';
@@ -38,31 +37,20 @@ const HELP = `zz-meridian ${VERSION}
38
37
 
39
38
  Brand flags: --name "Acme Ops" --workspace Production --timezone Europe/London --currency EUR
40
39
  --user "Ada Park" --role Admin --accent indigo|cobalt|jade|graphite | --hex '#2E6BE4' | --hue 250 --chroma 0.14
40
+ --theme dark|light
41
41
 
42
42
  Then give your coding agent the skill: .agents/skills/zz-meridian/SKILL.md.`;
43
- const { values, positionals } = parseArgs({
44
- allowPositionals: true,
45
- options: {
46
- ...Object.fromEntries(BRAND_FLAGS.map((f) => [f, { type: 'string' }])),
47
- 'allow-dirty': { type: 'boolean' },
48
- 'no-install': { type: 'boolean' },
49
- 'dry-run': { type: 'boolean' },
50
- resume: { type: 'boolean' },
51
- finalize: { type: 'boolean' },
52
- abort: { type: 'boolean' },
53
- verify: { type: 'boolean' },
54
- verbose: { type: 'boolean' },
55
- global: { type: 'boolean' },
56
- help: { type: 'boolean', short: 'h' },
57
- version: { type: 'boolean', short: 'v' },
58
- },
59
- });
60
- const flags = values;
43
+ const read = readFlags(process.argv.slice(2));
44
+ if ('error' in read) {
45
+ console.error(`zz-meridian: ${read.error}. zz-meridian --help lists the commands and their flags.`);
46
+ process.exit(1);
47
+ }
48
+ const { values: flags, positionals } = read;
61
49
  const brand = Object.fromEntries(BRAND_FLAGS.flatMap((f) => (typeof flags[f] === 'string' ? [[f, flags[f]]] : [])));
62
- const install = !values['no-install'];
50
+ const install = !flags['no-install'];
63
51
  const [command, arg] = positionals;
64
52
  function main() {
65
- if (values.version) {
53
+ if (flags.version) {
66
54
  console.log(VERSION);
67
55
  return 0;
68
56
  }
@@ -72,9 +60,9 @@ function main() {
72
60
  console.error(`zz-meridian: --${unsafe[0]} may not contain a backslash or a line break`);
73
61
  return 1;
74
62
  }
75
- if (values.help || !command) {
63
+ if (flags.help || !command) {
76
64
  console.log(HELP);
77
- return command || values.help ? 0 : 1;
65
+ return command || flags.help ? 0 : 1;
78
66
  }
79
67
  // A flag a command does not read is refused, never ignored: `adopt --dry-run` wrote the project rather than previewing it.
80
68
  const wrong = misapplied(command, flags);
@@ -82,8 +70,13 @@ function main() {
82
70
  console.error(`zz-meridian ${command}: --${wrong.flag} belongs to ${wrong.belongsTo}`);
83
71
  return 1;
84
72
  }
73
+ const extra = positionals[command === 'create' ? 2 : 1];
74
+ if (extra !== undefined) {
75
+ console.error(`zz-meridian ${command}: unexpected argument ${JSON.stringify(extra)}`);
76
+ return 1;
77
+ }
85
78
  if (command === 'adopt')
86
- return adopt({ root: process.cwd(), brand, allowDirty: Boolean(values['allow-dirty']), install });
79
+ return adopt({ root: process.cwd(), brand, allowDirty: Boolean(flags['allow-dirty']), install });
87
80
  if (command === 'create') {
88
81
  if (!arg) {
89
82
  console.error('zz-meridian create: name the folder for the new dashboard');
@@ -92,26 +85,32 @@ function main() {
92
85
  return create({ dir: arg, brand, install });
93
86
  }
94
87
  if (command === 'update') {
95
- const modes = ['dry-run', 'resume', 'finalize', 'abort'].filter((m) => values[m]);
88
+ const modes = ['dry-run', 'resume', 'finalize', 'abort'].filter((m) => flags[m]);
96
89
  if (modes.length > 1) {
97
90
  console.error(`zz-meridian update: ${modes.map((m) => `--${m}`).join(' and ')} cannot be combined`);
98
91
  return 1;
99
92
  }
100
- if (values.verify && !values.finalize) {
93
+ if (flags.verify && !flags.finalize) {
101
94
  console.error('zz-meridian update: --verify belongs to --finalize');
102
95
  return 1;
103
96
  }
104
97
  const mode = modes[0] ?? 'update';
105
- return update({ root: process.cwd(), mode, flags: { verbose: Boolean(values.verbose), allowDirty: Boolean(values['allow-dirty']), install, verify: Boolean(values.verify) } });
98
+ return update({ root: process.cwd(), mode, flags: { verbose: Boolean(flags.verbose), allowDirty: Boolean(flags['allow-dirty']), install, verify: Boolean(flags.verify) } });
106
99
  }
107
100
  if (command === 'brand')
108
- return brandCommand({ root: process.cwd(), flags: brand, allowDirty: Boolean(values['allow-dirty']) });
101
+ return brandCommand({ root: process.cwd(), flags: brand, allowDirty: Boolean(flags['allow-dirty']) });
109
102
  if (command === 'skill') {
110
- const roots = values.global ? [os.homedir()] : [process.cwd()];
111
- for (const r of roots)
112
- installSkill(r);
103
+ const roots = flags.global ? [os.homedir()] : [process.cwd()];
104
+ try {
105
+ for (const r of roots)
106
+ installSkill(r);
107
+ }
108
+ catch (error) {
109
+ console.error(`zz-meridian skill: ${error instanceof Error ? error.message : String(error)}`);
110
+ return 1;
111
+ }
113
112
  const skill = path.join(roots[0], '.claude/skills/zz-meridian/SKILL.md');
114
- console.log(`The zz-meridian skill is in ${values.global ? path.join(os.homedir(), '.agents/skills') + ' and ' + path.join(os.homedir(), '.claude/skills') : '.agents/skills and .claude/skills'}. Codex may need a restart to list it.`);
113
+ console.log(`The zz-meridian skill is in ${flags.global ? path.join(os.homedir(), '.agents/skills') + ' and ' + path.join(os.homedir(), '.claude/skills') : '.agents/skills and .claude/skills'}. Codex may need a restart to list it.`);
115
114
  console.log(`To follow it now, read ${skill} and the references beside it: it says how to build what was asked and when it is done.`);
116
115
  return 0;
117
116
  }
@@ -3,7 +3,39 @@
3
3
  * else it is refused by name rather than accepted and ignored, so `adopt --dry-run` never modifies a project while the
4
4
  * person waits for a preview.
5
5
  */
6
+ import { parseArgs } from 'node:util';
6
7
  import { BRAND_FLAGS } from './files.js';
8
+ /**
9
+ * The command line, read: its flags and positionals, or the reason it cannot be read (an unknown flag, a value-less one),
10
+ * as one line for the person rather than a stack trace.
11
+ */
12
+ export function readFlags(args) {
13
+ try {
14
+ const { values, positionals } = parseArgs({
15
+ args,
16
+ allowPositionals: true,
17
+ options: {
18
+ ...Object.fromEntries(BRAND_FLAGS.map((f) => [f, { type: 'string' }])),
19
+ 'allow-dirty': { type: 'boolean' },
20
+ 'no-install': { type: 'boolean' },
21
+ 'dry-run': { type: 'boolean' },
22
+ resume: { type: 'boolean' },
23
+ finalize: { type: 'boolean' },
24
+ abort: { type: 'boolean' },
25
+ verify: { type: 'boolean' },
26
+ verbose: { type: 'boolean' },
27
+ global: { type: 'boolean' },
28
+ help: { type: 'boolean', short: 'h' },
29
+ version: { type: 'boolean', short: 'v' },
30
+ },
31
+ });
32
+ return { values: { ...values }, positionals };
33
+ }
34
+ catch (e) {
35
+ // Node's first sentence names the flag; the rest is about positionals that start with a dash.
36
+ return { error: e.message.split('. ')[0] };
37
+ }
38
+ }
7
39
  /** Every command reads these. */
8
40
  const EVERYWHERE = ['help', 'version'];
9
41
  /** The brand flags, read by the commands that write a brand. */
package/dist/context.js CHANGED
@@ -41,8 +41,8 @@ Brand, layout and behaviour choices already made, one line each with its reason,
41
41
  ## Glossary
42
42
  The team's own words for things, one per line: term and what it means here.
43
43
  `;
44
- /** One `pnpm <script> [flags]` command, spelled for the package manager; npm needs `--` before flags. */
45
- function command(pm, script, flags) {
44
+ /** A package script with flags, as the package manager runs it: npm passes flags on only after `--`. */
45
+ export function command(pm, script, flags) {
46
46
  if (pm === 'pnpm')
47
47
  return `pnpm ${script}${flags}`;
48
48
  if (pm === 'npm')
package/dist/create.js CHANGED
@@ -6,10 +6,12 @@
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
8
  import { managedPaths } from './ownership.js';
9
- import { BRIEF_TEMPLATE, managedBlock, upsertManagedBlock } from './context.js';
9
+ import { BRIEF_TEMPLATE, command, managedBlock, upsertManagedBlock } from './context.js';
10
10
  import { VERSION, brandArgs, effectiveBrand, hasCommand, inside, installSkill, payloadBytes, payloadFiles, run, sha256, writeIn, writeManifest } from './files.js';
11
11
  export function create(o) {
12
12
  const root = path.resolve(o.dir);
13
+ if (fs.existsSync(root) && !fs.statSync(root).isDirectory())
14
+ return fail(`${root} is a file: name a new folder`);
13
15
  if (fs.existsSync(root) && fs.readdirSync(root).length)
14
16
  return fail(`${root} exists and is not empty: name a new folder`);
15
17
  let brand;
@@ -27,7 +29,7 @@ export function create(o) {
27
29
  const name = brand.name ?? path.basename(root).replace(/[-_]+/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
28
30
  brand = effectiveBrand({ ...brand, name });
29
31
  if (run(process.execPath, ['scripts/brand.ts', ...brandArgs(brand), '--product'], root).status !== 0) {
30
- return fail('scripts/brand.ts failed (above); the template is copied, so fix the cause and run it again with the same flags');
32
+ return fail(`scripts/brand.ts failed (above). ${root} holds the unbranded template and nothing else: fix the cause, delete the folder and run zz-meridian create again with the same flags`);
31
33
  }
32
34
  // pnpm installs from the template's lockfile, with install scripts off (pnpm-workspace.yaml). Without pnpm, corepack
33
35
  // (bundled with Node 22) runs it; only without both does npm install, from the version ranges, with scripts off too.
@@ -71,16 +73,20 @@ export function create(o) {
71
73
  if (hasCommand('git'))
72
74
  run('git', ['init', '-q'], root);
73
75
  if (o.install && run(install[0], install[1], root).status !== 0)
74
- return fail(`${install.join(' ')} failed (above); run it again in ${root}`);
76
+ return fail(`${install[0]} ${install[1].join(' ')} failed (above); run it again in ${root}`);
75
77
  console.log(`
76
78
  ${name} is a new Meridian ${VERSION} dashboard in ${root}.
77
79
  skill: .agents/skills/zz-meridian (Codex) and .claude/skills/zz-meridian (Claude Code)
78
80
 
79
- Next: follow .agents/skills/zz-meridian/SKILL.md from step 3's brief (the template is fetched and branded): the brief,
80
- step 4's colour check, then data and the pages, then the loop in references/standard.md until ${pm} run verify --full --timed ends with "the project meets the
81
- Meridian standard" and no view on the scoreboard is Weak.`);
81
+ ${nextStep(pm)}`);
82
82
  return 0;
83
83
  }
84
+ /** What the person does next, with the full verify written so their package manager passes its flags on. */
85
+ export function nextStep(pm) {
86
+ return `Next: follow .agents/skills/zz-meridian/SKILL.md from step 3's brief (the template is fetched and branded): the brief,
87
+ step 4's colour check, then data and the pages, then the loop in references/standard.md until ${command(pm, 'verify', ' --full --timed')} ends with "the project meets the
88
+ Meridian standard" and no view on the scoreboard is Weak.`;
89
+ }
84
90
  function fail(msg) {
85
91
  console.error(`zz-meridian create: ${msg}`);
86
92
  return 1;
package/dist/files.js CHANGED
@@ -7,7 +7,7 @@ import { spawnSync } from 'node:child_process';
7
7
  import fs from 'node:fs';
8
8
  import path from 'node:path';
9
9
  import { fileURLToPath } from 'node:url';
10
- /** The template snapshot this package carries, built from `git ls-files` at the release commit. */
10
+ /** The template snapshot this package carries, extracted from the release commit by `git archive` (cli/scripts/build-payload.ts). */
11
11
  export const PAYLOAD = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'payload');
12
12
  export const VERSION = JSON.parse(fs.readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8')).version;
13
13
  /**
@@ -73,6 +73,8 @@ export function writeIn(root, rel, content) {
73
73
  fs.writeFileSync(abs, content);
74
74
  }
75
75
  export const sha256 = (content) => `sha256-${createHash('sha256').update(content).digest('hex')}`;
76
+ /** What a quiet command may print and still be read whole: past Node's 1 MiB default the child is killed, and a long gate reads as exit 1. */
77
+ const OUTPUT = 256 * 1024 * 1024;
76
78
  /**
77
79
  * A command with its arguments, without a shell, so nothing in a name or a path is ever interpreted. The one exception
78
80
  * is a Windows .cmd shim (npm, pnpm, tsc), which Node runs only through a shell: those calls pass fixed arguments
@@ -80,7 +82,7 @@ export const sha256 = (content) => `sha256-${createHash('sha256').update(content
80
82
  */
81
83
  export function run(cmd, args, cwd, quiet = false) {
82
84
  const shim = process.platform === 'win32' && cmd !== process.execPath;
83
- return spawnSync(shim && cmd.includes(' ') ? `"${cmd}"` : cmd, args, { cwd, encoding: 'utf8', stdio: quiet ? 'pipe' : 'inherit', shell: shim });
85
+ return spawnSync(shim && cmd.includes(' ') ? `"${cmd}"` : cmd, args, { cwd, encoding: 'utf8', stdio: quiet ? 'pipe' : 'inherit', shell: shim, maxBuffer: OUTPUT });
84
86
  }
85
87
  /** The package manager a project already uses, from its lockfile; npm when it has none. */
86
88
  export function packageManager(root) {
@@ -99,7 +101,7 @@ export function packageManager(root) {
99
101
  export const installArgs = (pm) => (pm === 'pnpm' ? ['install', '--no-frozen-lockfile'] : ['install']);
100
102
  /** A tool in the project's node_modules, run as `node <its script>`: no shell and no .cmd shim on any platform. */
101
103
  export function runTool(root, entry, args, quiet = true) {
102
- return spawnSync(process.execPath, [path.join(root, 'node_modules', entry), ...args], { cwd: root, encoding: 'utf8', stdio: quiet ? 'pipe' : 'inherit' });
104
+ return spawnSync(process.execPath, [path.join(root, 'node_modules', entry), ...args], { cwd: root, encoding: 'utf8', stdio: quiet ? 'pipe' : 'inherit', maxBuffer: OUTPUT });
103
105
  }
104
106
  export const hasCommand = (cmd) => spawnSync(cmd, ['--version'], { stdio: 'ignore', shell: process.platform === 'win32' }).status === 0;
105
107
  /** A JSONC document's text with the comments dropped, and whether anything had to be dropped to read it. */
@@ -138,7 +140,8 @@ function strippedJsonc(text) {
138
140
  }
139
141
  out += c;
140
142
  }
141
- const json = out.replace(/,(\s*[}\]])/g, '$1');
143
+ // Consume strings whole before removing trailing commas: their keys and values may themselves contain ",]" or ",}".
144
+ const json = out.replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (match, end) => end ?? match);
142
145
  return { json, dropped: dropped || json.length !== out.length };
143
146
  }
144
147
  /** JSON with the comments and trailing commas a tsconfig may carry. */
@@ -164,9 +167,16 @@ export function relativeImports(rel, source) {
164
167
  return `${lead}${q}${to}${q}`;
165
168
  });
166
169
  }
170
+ /**
171
+ * The manifest file as every writer writes it: paths sorted by code unit (never the machine's collation), two-space
172
+ * indent, a final newline. Finalize tells an interrupted rename by comparing the file with this, byte for byte.
173
+ */
174
+ export function manifestText(m) {
175
+ const files = Object.fromEntries(Object.entries(m.files).sort(([a], [b]) => (a < b ? -1 : 1)));
176
+ return `${JSON.stringify({ ...m, files }, null, 2)}\n`;
177
+ }
167
178
  export function writeManifest(root, m) {
168
- const sorted = Object.fromEntries(Object.entries(m.files).sort(([a], [b]) => a.localeCompare(b)));
169
- writeIn(root, '.meridian/manifest.json', JSON.stringify({ ...m, files: sorted }, null, 2) + '\n');
179
+ writeIn(root, '.meridian/manifest.json', manifestText(m));
170
180
  }
171
181
  /**
172
182
  * Where the skill goes: the folders each agent reads in a repository, Codex (`.agents`) and Claude Code (`.claude`), and
@@ -175,13 +185,29 @@ export function writeManifest(root, m) {
175
185
  */
176
186
  export function skillPaths() {
177
187
  const files = payloadFiles('skills/zz-meridian');
188
+ if (!files.includes('skills/zz-meridian/SKILL.md'))
189
+ throw new Error('skills/zz-meridian/SKILL.md is not in cli/payload/: rebuild the payload or reinstall a complete package before installing the skill.');
178
190
  return ['.agents/skills/zz-meridian', '.claude/skills/zz-meridian'].flatMap((base) => files.map((f) => ({ rel: `${base}/${f.slice('skills/zz-meridian/'.length)}`, payload: f })));
179
191
  }
180
- /** The agent skill, into the folders each agent reads in a repository. */
192
+ /** Refuse a different existing skill before writing either agent's copy. Identical copies need no write. */
181
193
  export function installSkill(root, record) {
182
- for (const { rel, payload } of skillPaths()) {
183
- const content = payloadBytes(payload);
184
- writeIn(root, rel, content);
194
+ const contents = new Map();
195
+ const plan = skillPaths().map(({ rel, payload }) => {
196
+ const abs = inside(root, rel);
197
+ let content = contents.get(payload);
198
+ if (!content) {
199
+ content = payloadBytes(payload);
200
+ contents.set(payload, content);
201
+ }
202
+ const existing = fs.lstatSync(abs, { throwIfNoEntry: false });
203
+ if (existing && (!existing.isFile() || !fs.readFileSync(abs).equals(content))) {
204
+ throw new Error(`refusing to overwrite ${rel}: it differs from the packaged skill. Move your copy aside before installing again; no skill files were written.`);
205
+ }
206
+ return { rel, content, exists: Boolean(existing) };
207
+ });
208
+ for (const { rel, content, exists } of plan) {
209
+ if (!exists)
210
+ writeIn(root, rel, content);
185
211
  if (record)
186
212
  record[rel] = sha256(content);
187
213
  }