zz-meridian 0.14.1 → 0.16.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 (546) hide show
  1. package/README.md +9 -7
  2. package/dist/adopt.js +24 -6
  3. package/dist/migrations.js +283 -1
  4. package/dist/ownership.js +2 -2
  5. package/dist/session.js +25 -0
  6. package/package.json +1 -1
  7. package/payload/CHANGELOG.md +351 -0
  8. package/payload/CONTRIBUTING.md +19 -8
  9. package/payload/README.md +6 -3
  10. package/payload/app/(dashboard)/(home)/README.md +129 -0
  11. package/payload/app/(dashboard)/(home)/loading.tsx +75 -0
  12. package/payload/app/(dashboard)/(home)/page.tsx +94 -0
  13. package/payload/app/(dashboard)/business/README.md +124 -0
  14. package/payload/app/(dashboard)/business/loading.tsx +81 -0
  15. package/payload/app/(dashboard)/business/page.tsx +86 -0
  16. package/payload/app/(dashboard)/customers/README.md +34 -12
  17. package/payload/app/(dashboard)/customers/[id]/README.md +98 -0
  18. package/payload/app/(dashboard)/customers/[id]/loading.tsx +34 -0
  19. package/payload/app/(dashboard)/customers/[id]/page.tsx +43 -0
  20. package/payload/app/(dashboard)/customers/loading.tsx +5 -4
  21. package/payload/app/(dashboard)/customers/page.tsx +15 -11
  22. package/payload/app/(dashboard)/engineering/README.md +136 -0
  23. package/payload/app/(dashboard)/engineering/loading.tsx +63 -0
  24. package/payload/app/(dashboard)/engineering/page.tsx +64 -0
  25. package/payload/app/(dashboard)/error.tsx +5 -5
  26. package/payload/app/(dashboard)/keys/README.md +22 -7
  27. package/payload/app/(dashboard)/keys/loading.tsx +5 -3
  28. package/payload/app/(dashboard)/keys/page.tsx +9 -8
  29. package/payload/app/(dashboard)/layout.tsx +15 -7
  30. package/payload/app/(dashboard)/members/README.md +26 -11
  31. package/payload/app/(dashboard)/members/loading.tsx +5 -3
  32. package/payload/app/(dashboard)/members/page.tsx +21 -4
  33. package/payload/app/(dashboard)/not-found.tsx +2 -1
  34. package/payload/app/(dashboard)/operations-tickets/README.md +73 -0
  35. package/payload/app/(dashboard)/operations-tickets/actions.ts +35 -0
  36. package/payload/app/(dashboard)/operations-tickets/loading.tsx +12 -0
  37. package/payload/app/(dashboard)/operations-tickets/page.tsx +44 -0
  38. package/payload/app/(dashboard)/releases/README.md +69 -0
  39. package/payload/app/(dashboard)/releases/loading.tsx +12 -0
  40. package/payload/app/(dashboard)/releases/page.tsx +45 -0
  41. package/payload/app/(dashboard)/requests/README.md +23 -8
  42. package/payload/app/(dashboard)/requests/[id]/README.md +19 -5
  43. package/payload/app/(dashboard)/requests/[id]/actions.ts +4 -2
  44. package/payload/app/(dashboard)/requests/[id]/loading.tsx +3 -2
  45. package/payload/app/(dashboard)/requests/[id]/page.tsx +25 -12
  46. package/payload/app/(dashboard)/requests/loading.tsx +5 -4
  47. package/payload/app/(dashboard)/requests/page.tsx +10 -8
  48. package/payload/app/(dashboard)/services/README.md +113 -0
  49. package/payload/app/(dashboard)/services/loading.tsx +44 -0
  50. package/payload/app/(dashboard)/services/page.tsx +54 -0
  51. package/payload/app/(dashboard)/settings/README.md +10 -13
  52. package/payload/app/(dashboard)/settings/actions.ts +4 -7
  53. package/payload/app/(dashboard)/settings/loading.tsx +4 -3
  54. package/payload/app/(dashboard)/settings/page.tsx +8 -9
  55. package/payload/app/(dashboard)/tests/README.md +69 -0
  56. package/payload/app/(dashboard)/tests/loading.tsx +12 -0
  57. package/payload/app/(dashboard)/tests/page.tsx +45 -0
  58. package/payload/app/(dashboard)/usage/README.md +131 -0
  59. package/payload/app/(dashboard)/usage/loading.tsx +52 -0
  60. package/payload/app/(dashboard)/usage/page.tsx +94 -0
  61. package/payload/app/api/assistant/route.ts +123 -11
  62. package/payload/app/embed/home/README.md +35 -0
  63. package/payload/app/embed/home/page.tsx +27 -0
  64. package/payload/app/embed/home/view.tsx +40 -0
  65. package/payload/app/embed/now/README.md +44 -0
  66. package/payload/app/embed/now/page.tsx +23 -0
  67. package/payload/app/embed/now/view.tsx +49 -0
  68. package/payload/app/embed/proposal/README.md +2 -2
  69. package/payload/app/embed/requests/README.md +1 -1
  70. package/payload/app/embed/requests/view.tsx +4 -4
  71. package/payload/app/layout.tsx +1 -1
  72. package/payload/app/not-found/README.md +4 -3
  73. package/payload/app/not-found.tsx +10 -4
  74. package/payload/app/sign-in/README.md +11 -16
  75. package/payload/app/sign-in/gated-panel.tsx +5 -10
  76. package/payload/app/sign-in/page.tsx +3 -3
  77. package/payload/app/sign-in/panel.tsx +11 -68
  78. package/payload/app/system/(atlas)/[section]/[id]/page.tsx +5 -5
  79. package/payload/app/system/(atlas)/_article.tsx +12 -4
  80. package/payload/app/system/(atlas)/layout.tsx +1 -1
  81. package/payload/app/system/(atlas)/page.tsx +5 -5
  82. package/payload/app/system/(atlas)/products/[id]/page.tsx +9 -0
  83. package/payload/app/system/preview/[section]/[card]/keys.ts +2 -0
  84. package/payload/app/system/preview/[section]/[card]/page.tsx +7 -1
  85. package/payload/app/system/states/loading/page.tsx +2 -2
  86. package/payload/decisions/0011-one-context-two-agents.md +1 -1
  87. package/payload/decisions/0012-roles-and-feature-access.md +2 -2
  88. package/payload/decisions/0014-the-atlas-is-held-to-the-floors.md +52 -0
  89. package/payload/docs/agents.md +70 -8
  90. package/payload/docs/assistant.md +26 -12
  91. package/payload/docs/atlas-scenario-coverage.md +350 -0
  92. package/payload/docs/benchmark.md +45 -25
  93. package/payload/docs/data-display.md +96 -10
  94. package/payload/docs/distribution.md +21 -18
  95. package/payload/docs/product-workspaces.md +116 -0
  96. package/payload/docs/start-a-dashboard.md +15 -10
  97. package/payload/docs/surfaces.md +49 -27
  98. package/payload/docs/voice.md +5 -4
  99. package/payload/journeys/workspaces.ts +634 -0
  100. package/payload/package.json +2 -2
  101. package/payload/scripts/ask.ts +397 -0
  102. package/payload/scripts/assistant.ts +179 -55
  103. package/payload/scripts/audit.ts +137 -25
  104. package/payload/scripts/brand.ts +7 -3
  105. package/payload/scripts/check.ts +29 -5
  106. package/payload/scripts/contrast.ts +18 -7
  107. package/payload/scripts/fake-llm.ts +81 -19
  108. package/payload/scripts/interactions.ts +3 -1
  109. package/payload/scripts/keyboard.ts +18 -28
  110. package/payload/scripts/lib/atlas.ts +44 -0
  111. package/payload/scripts/lib/chrome.ts +56 -15
  112. package/payload/scripts/lib/contrast-pairs.ts +10 -0
  113. package/payload/scripts/lib/routes.ts +164 -0
  114. package/payload/scripts/lib/sample.ts +28 -5
  115. package/payload/scripts/lib/settle.ts +39 -0
  116. package/payload/scripts/live.ts +2 -2
  117. package/payload/scripts/navigate.ts +158 -44
  118. package/payload/scripts/perf.ts +25 -10
  119. package/payload/scripts/rail.ts +29 -11
  120. package/payload/scripts/registry.ts +10 -6
  121. package/payload/scripts/route-policy.ts +25 -3
  122. package/payload/scripts/shot.ts +11 -1
  123. package/payload/scripts/tokens.ts +3 -1
  124. package/payload/scripts/verify.baseline.json +29 -22
  125. package/payload/scripts/verify.config.ts +48 -19
  126. package/payload/scripts/verify.ts +14 -7
  127. package/payload/scripts/vitals.ts +24 -8
  128. package/payload/skills/zz-meridian/SKILL.md +14 -7
  129. package/payload/skills/zz-meridian/references/agents.md +57 -6
  130. package/payload/skills/zz-meridian/references/cache.md +123 -27
  131. package/payload/skills/zz-meridian/references/customize.md +412 -42
  132. package/payload/skills/zz-meridian/references/existing-project.md +54 -13
  133. package/payload/skills/zz-meridian/references/live.md +14 -4
  134. package/payload/skills/zz-meridian/references/ownership.md +1 -1
  135. package/payload/skills/zz-meridian/references/update.md +19 -9
  136. package/payload/skills/zz-meridian/references/validation.md +53 -9
  137. package/payload/skills/zz-meridian/references/voice.md +5 -4
  138. package/payload/src/app.config.ts +61 -16
  139. package/payload/src/components/base/icons/preview.tsx +2 -2
  140. package/payload/src/components/base/providers.tsx +8 -3
  141. package/payload/src/components/base/shell/README.md +65 -9
  142. package/payload/src/components/base/shell/index.tsx +273 -55
  143. package/payload/src/components/base/shell/leave-question.tsx +27 -0
  144. package/payload/src/components/base/shell/preview.tsx +51 -4
  145. package/payload/src/components/base/surface/README.md +2 -2
  146. package/payload/src/components/base/surface/preview.tsx +4 -3
  147. package/payload/src/components/base/text-roles/README.md +2 -2
  148. package/payload/src/components/base/text-roles/index.tsx +1 -1
  149. package/payload/src/components/base/text-roles/preview.tsx +2 -2
  150. package/payload/src/components/charts/bar-list/README.md +11 -4
  151. package/payload/src/components/charts/bar-list/index.tsx +13 -1
  152. package/payload/src/components/charts/bar-list/preview.tsx +23 -5
  153. package/payload/src/components/charts/column-chart/README.md +127 -17
  154. package/payload/src/components/charts/column-chart/index.tsx +299 -59
  155. package/payload/src/components/charts/column-chart/preview.tsx +185 -23
  156. package/payload/src/components/charts/composition-bar/README.md +3 -2
  157. package/payload/src/components/charts/composition-bar/index.tsx +13 -7
  158. package/payload/src/components/charts/composition-bar/preview.tsx +6 -1
  159. package/payload/src/components/charts/heatmap/README.md +70 -21
  160. package/payload/src/components/charts/heatmap/index.tsx +334 -70
  161. package/payload/src/components/charts/heatmap/preview.tsx +123 -3
  162. package/payload/src/components/charts/meridian/README.md +12 -9
  163. package/payload/src/components/charts/meridian/index.tsx +8 -2
  164. package/payload/src/components/charts/meridian/preview.tsx +3 -3
  165. package/payload/src/components/charts/readout.tsx +48 -0
  166. package/payload/src/components/charts/scale.ts +18 -4
  167. package/payload/src/components/charts/sparkline/README.md +18 -7
  168. package/payload/src/components/charts/sparkline/index.tsx +24 -12
  169. package/payload/src/components/charts/sparkline/preview.tsx +16 -5
  170. package/payload/src/components/charts/trend-chart/README.md +25 -12
  171. package/payload/src/components/charts/trend-chart/index.tsx +106 -51
  172. package/payload/src/components/charts/trend-chart/preview.tsx +33 -5
  173. package/payload/src/components/charts/uptime-bars/README.md +7 -7
  174. package/payload/src/components/charts/uptime-bars/index.tsx +17 -6
  175. package/payload/src/components/charts/uptime-bars/preview.tsx +8 -0
  176. package/payload/src/components/patterns/ask-about/README.md +6 -2
  177. package/payload/src/components/patterns/ask-about/index.tsx +2 -3
  178. package/payload/src/components/patterns/assistant/README.md +5 -3
  179. package/payload/src/components/patterns/assistant/index.tsx +44 -22
  180. package/payload/src/components/patterns/assistant/page-text.ts +21 -0
  181. package/payload/src/components/patterns/assistant/preview.tsx +1 -1
  182. package/payload/src/components/patterns/assistant/scope.tsx +28 -0
  183. package/payload/src/components/patterns/assistant/thread.ts +65 -13
  184. package/payload/src/components/patterns/command-palette/README.md +2 -2
  185. package/payload/src/components/patterns/command-palette/index.tsx +4 -2
  186. package/payload/src/components/patterns/data-table/README.md +3 -3
  187. package/payload/src/components/patterns/data-table/index.tsx +8 -5
  188. package/payload/src/components/patterns/data-table/use-query-state.ts +4 -2
  189. package/payload/src/components/patterns/data-table/use-search-draft.ts +28 -0
  190. package/payload/src/components/patterns/embed-frame/README.md +2 -2
  191. package/payload/src/components/patterns/embed-frame/preview.tsx +5 -4
  192. package/payload/src/components/patterns/export-button/README.md +2 -2
  193. package/payload/src/components/patterns/export-button/preview.tsx +6 -5
  194. package/payload/src/components/patterns/featured-metric/README.md +137 -20
  195. package/payload/src/components/patterns/featured-metric/index.tsx +138 -46
  196. package/payload/src/components/patterns/featured-metric/preview.tsx +196 -32
  197. package/payload/src/components/patterns/form-section/README.md +15 -11
  198. package/payload/src/components/patterns/form-section/index.tsx +20 -8
  199. package/payload/src/components/patterns/form-section/preview.tsx +11 -2
  200. package/payload/src/components/patterns/incident-card/README.md +31 -14
  201. package/payload/src/components/patterns/incident-card/index.tsx +29 -7
  202. package/payload/src/components/patterns/incident-card/preview.tsx +25 -7
  203. package/payload/src/components/patterns/metric-tile/README.md +78 -13
  204. package/payload/src/components/patterns/metric-tile/index.tsx +101 -24
  205. package/payload/src/components/patterns/metric-tile/preview.tsx +124 -18
  206. package/payload/src/components/patterns/page-loading/README.md +102 -0
  207. package/payload/src/components/patterns/page-loading/index.tsx +142 -0
  208. package/payload/src/components/patterns/page-loading/preview.tsx +36 -0
  209. package/payload/src/components/patterns/period-select/README.md +2 -2
  210. package/payload/src/components/patterns/proposal/README.md +1 -1
  211. package/payload/src/components/patterns/proposal/index.tsx +2 -2
  212. package/payload/src/components/patterns/prose/README.md +3 -0
  213. package/payload/src/components/patterns/prose/index.tsx +3 -2
  214. package/payload/src/components/patterns/rail/README.md +9 -6
  215. package/payload/src/components/patterns/rail/index.tsx +34 -7
  216. package/payload/src/components/patterns/rail/preview.tsx +26 -64
  217. package/payload/src/components/patterns/shell-tools/README.md +2 -2
  218. package/payload/src/components/patterns/shell-tools/preview.tsx +1 -1
  219. package/payload/src/components/patterns/status-list/README.md +36 -14
  220. package/payload/src/components/patterns/status-list/index.tsx +29 -2
  221. package/payload/src/components/patterns/status-list/preview.tsx +15 -3
  222. package/payload/src/components/templates/records/README.md +57 -0
  223. package/payload/src/components/templates/records/index.tsx +33 -0
  224. package/payload/src/components/templates/records/preview.tsx +73 -0
  225. package/payload/src/components/ui/banner/index.tsx +1 -1
  226. package/payload/src/components/ui/breadcrumb/README.md +1 -1
  227. package/payload/src/components/ui/breadcrumb/index.tsx +5 -4
  228. package/payload/src/components/ui/card/README.md +7 -2
  229. package/payload/src/components/ui/card/index.tsx +4 -1
  230. package/payload/src/components/ui/card/preview.tsx +12 -0
  231. package/payload/src/components/ui/copy-field/README.md +1 -1
  232. package/payload/src/components/ui/copy-field/index.tsx +2 -1
  233. package/payload/src/components/ui/dialog/preview.tsx +1 -1
  234. package/payload/src/components/ui/icon-button/preview.tsx +1 -1
  235. package/payload/src/components/ui/key-value/README.md +2 -2
  236. package/payload/src/components/ui/key-value/index.tsx +21 -9
  237. package/payload/src/components/ui/key-value/preview.tsx +3 -2
  238. package/payload/src/components/ui/search-input/README.md +1 -1
  239. package/payload/src/components/ui/segmented/README.md +3 -3
  240. package/payload/src/components/ui/segmented/index.tsx +2 -2
  241. package/payload/src/components/ui/table/index.tsx +1 -1
  242. package/payload/src/components/ui/tabs/preview.tsx +2 -2
  243. package/payload/src/components/ui/toast/index.tsx +5 -2
  244. package/payload/src/data/README.md +34 -7
  245. package/payload/src/data/access.ts +66 -13
  246. package/payload/src/data/alerts.ts +110 -0
  247. package/payload/src/data/collections.ts +215 -43
  248. package/payload/src/data/engineering.ts +36 -0
  249. package/payload/src/data/features.ts +27 -19
  250. package/payload/src/data/main.ts +8 -0
  251. package/payload/src/data/member-mutations.ts +14 -33
  252. package/payload/src/data/metrics.ts +60 -21
  253. package/payload/src/data/read.ts +41 -5
  254. package/payload/src/data/refusal.ts +20 -0
  255. package/payload/src/data/requests.ts +48 -20
  256. package/payload/src/data/roles.ts +5 -5
  257. package/payload/src/data/sample.ts +10 -6
  258. package/payload/src/data/sign-in.ts +11 -0
  259. package/payload/src/data/ticket-mutations.ts +155 -0
  260. package/payload/src/data/tickets.ts +33 -0
  261. package/payload/src/data/usage.ts +31 -0
  262. package/payload/src/data/verification.ts +58 -0
  263. package/payload/src/data/write-boundary.ts +38 -0
  264. package/payload/src/lib/agent-guidance.ts +4 -3
  265. package/payload/src/lib/assistant/prompt.ts +66 -6
  266. package/payload/src/lib/assistant/respond.ts +23 -7
  267. package/payload/src/lib/assistant/scoped.ts +15 -32
  268. package/payload/src/lib/assistant/tools.ts +50 -14
  269. package/payload/src/lib/collection.ts +211 -43
  270. package/payload/src/lib/explore.ts +456 -0
  271. package/payload/src/lib/facts.ts +172 -0
  272. package/payload/src/lib/format-date.ts +26 -0
  273. package/payload/src/lib/format.ts +49 -22
  274. package/payload/src/lib/insight.ts +0 -56
  275. package/payload/src/lib/live.ts +11 -1
  276. package/payload/src/lib/period.ts +3 -2
  277. package/payload/src/lib/shared-context.ts +22 -7
  278. package/payload/src/styles/motion.css +2 -2
  279. package/payload/src/styles/tokens.css +5 -3
  280. package/payload/src/system/atlas-shell.tsx +54 -26
  281. package/payload/src/system/card-stage.tsx +11 -5
  282. package/payload/src/system/content.ts +44 -20
  283. package/payload/src/system/fixtures/company.ts +410 -0
  284. package/payload/src/system/fixtures/sample-engineering.ts +146 -0
  285. package/payload/src/system/fixtures/sample-ops.ts +13 -32
  286. package/payload/src/system/fixtures/sample-records.ts +11 -21
  287. package/payload/src/system/fixtures/sample.ts +110 -128
  288. package/payload/src/system/hero.tsx +1 -1
  289. package/payload/src/system/page-stage.tsx +2 -2
  290. package/payload/src/system/preview-loaders.ts +2 -0
  291. package/payload/src/system/registry.ts +2 -0
  292. package/payload/src/system/sample-cells.tsx +13 -5
  293. package/payload/src/system/specimen.tsx +10 -2
  294. package/payload/src/system/strata.tsx +13 -5
  295. package/payload/src/system/token-view.tsx +3 -3
  296. package/payload/src/views/ask-period.tsx +15 -0
  297. package/payload/src/views/console-chrome.tsx +37 -19
  298. package/payload/src/views/customer-context.ts +144 -0
  299. package/payload/src/views/customer-explore.ts +48 -0
  300. package/payload/src/views/customer.tsx +217 -0
  301. package/payload/src/views/customers-context.ts +80 -27
  302. package/payload/src/views/customers-explore.ts +42 -0
  303. package/payload/src/views/customers.tsx +63 -103
  304. package/payload/src/views/fact-insight.ts +56 -0
  305. package/payload/src/views/home-context.ts +250 -0
  306. package/payload/src/views/home-explore.ts +77 -0
  307. package/payload/src/views/home-parts.ts +336 -0
  308. package/payload/src/views/home.tsx +366 -0
  309. package/payload/src/views/keys-context.ts +6 -3
  310. package/payload/src/views/keys-explore.ts +27 -0
  311. package/payload/src/views/keys.tsx +28 -20
  312. package/payload/src/views/main-summary.ts +16 -0
  313. package/payload/src/views/members-context.ts +13 -6
  314. package/payload/src/views/members-explore.ts +31 -0
  315. package/payload/src/views/members.tsx +28 -39
  316. package/payload/src/views/missing-page.tsx +8 -4
  317. package/payload/src/views/no-access.tsx +23 -10
  318. package/payload/src/views/not-found-address.tsx +6 -5
  319. package/payload/src/views/not-found.tsx +9 -4
  320. package/payload/src/views/now-context.ts +291 -0
  321. package/payload/src/views/now-explore.ts +92 -0
  322. package/payload/src/views/now-parts.ts +238 -0
  323. package/payload/src/views/now.tsx +427 -0
  324. package/payload/src/views/period-actions.tsx +29 -0
  325. package/payload/src/views/releases-context.ts +100 -0
  326. package/payload/src/views/releases-explore.ts +57 -0
  327. package/payload/src/views/releases.tsx +116 -0
  328. package/payload/src/views/request-context.ts +8 -5
  329. package/payload/src/views/request-explore.ts +30 -0
  330. package/payload/src/views/request.tsx +46 -36
  331. package/payload/src/views/requests-context.ts +2 -3
  332. package/payload/src/views/requests-explore.ts +50 -0
  333. package/payload/src/views/requests.tsx +48 -60
  334. package/payload/src/views/revenue-context.ts +242 -0
  335. package/payload/src/views/revenue-explore.ts +48 -0
  336. package/payload/src/views/revenue-parts.ts +219 -0
  337. package/payload/src/views/revenue.tsx +351 -0
  338. package/payload/src/views/sample-footer.tsx +2 -2
  339. package/payload/src/views/services-context.ts +179 -0
  340. package/payload/src/views/services-explore.ts +44 -0
  341. package/payload/src/views/services.tsx +129 -0
  342. package/payload/src/views/settings.tsx +22 -127
  343. package/payload/src/views/shell-alerts.tsx +27 -0
  344. package/payload/src/views/tests-context.ts +79 -0
  345. package/payload/src/views/tests-explore.ts +46 -0
  346. package/payload/src/views/tests.tsx +121 -0
  347. package/payload/src/views/tickets-context.ts +87 -0
  348. package/payload/src/views/tickets-explore.ts +61 -0
  349. package/payload/src/views/tickets.tsx +243 -0
  350. package/payload/src/views/tools.ts +246 -49
  351. package/payload/src/views/unread.tsx +25 -0
  352. package/payload/src/views/usage-context.ts +163 -0
  353. package/payload/src/views/usage-explore.ts +66 -0
  354. package/payload/src/views/usage-parts.ts +126 -0
  355. package/payload/src/views/usage.tsx +220 -0
  356. package/payload/src/views/workspace-chrome.tsx +80 -0
  357. package/payload/src/views/workspaces.ts +27 -0
  358. package/payload/tests/action-needs.test.tsx +12 -11
  359. package/payload/tests/agent-page-spec.test.ts +21 -0
  360. package/payload/tests/assistant-access.test.ts +22 -14
  361. package/payload/tests/assistant-brief.test.ts +1 -1
  362. package/payload/tests/assistant-errors.test.ts +1 -1
  363. package/payload/tests/assistant-explore-tool.test.ts +121 -0
  364. package/payload/tests/assistant-limits.test.ts +46 -0
  365. package/payload/tests/assistant-page-text.test.tsx +73 -0
  366. package/payload/tests/assistant-panel.test.tsx +1 -1
  367. package/payload/tests/assistant-prompt-truth.test.ts +89 -0
  368. package/payload/tests/assistant-proposal.test.tsx +2 -2
  369. package/payload/tests/assistant-respond.test.ts +3 -3
  370. package/payload/tests/assistant-route.test.ts +9 -0
  371. package/payload/tests/assistant-safety.test.ts +2 -2
  372. package/payload/tests/assistant-settings.test.tsx +4 -4
  373. package/payload/tests/assistant-stale-scope.test.tsx +93 -0
  374. package/payload/tests/assistant-thread-scope.test.tsx +121 -0
  375. package/payload/tests/assistant-thread.test.tsx +12 -10
  376. package/payload/tests/assistant-tools.test.ts +62 -21
  377. package/payload/tests/assistant-withheld.test.ts +73 -0
  378. package/payload/tests/atlas-layers.test.ts +88 -0
  379. package/payload/tests/atlas-product-slice.test.tsx +40 -0
  380. package/payload/tests/atlas-shell-early-press.test.tsx +55 -0
  381. package/payload/tests/atlas-template-contracts.test.tsx +148 -0
  382. package/payload/tests/bar-list-links.test.tsx +38 -0
  383. package/payload/tests/bypasses.test.ts +9 -8
  384. package/payload/tests/card-header-title.test.tsx +24 -0
  385. package/payload/tests/card-stage-hydration.test.tsx +84 -0
  386. package/payload/tests/chrome-navigation.test.tsx +100 -0
  387. package/payload/tests/client-imports.test.ts +85 -0
  388. package/payload/tests/collection-aggregate.test.ts +107 -0
  389. package/payload/tests/collection-null-group.test.ts +37 -0
  390. package/payload/tests/collection.test.ts +4 -13
  391. package/payload/tests/column-chart-crowded.test.tsx +93 -0
  392. package/payload/tests/column-chart-labels.test.tsx +77 -0
  393. package/payload/tests/column-chart-no-data.test.tsx +107 -0
  394. package/payload/tests/column-chart-readout.test.tsx +52 -0
  395. package/payload/tests/column-chart-running.test.tsx +49 -0
  396. package/payload/tests/column-chart-stacked.test.tsx +151 -0
  397. package/payload/tests/column-chart.test.tsx +153 -0
  398. package/payload/tests/composition-bar.test.tsx +33 -0
  399. package/payload/tests/console-chrome.test.tsx +2 -2
  400. package/payload/tests/counts-and-lists.test.tsx +203 -0
  401. package/payload/tests/customer-figures.test.ts +55 -0
  402. package/payload/tests/customers-payload.test.tsx +30 -0
  403. package/payload/tests/data-model.test.ts +88 -0
  404. package/payload/tests/day-in-progress.test.ts +85 -0
  405. package/payload/tests/empty-views.test.tsx +20 -12
  406. package/payload/tests/engineering-records.test.ts +223 -0
  407. package/payload/tests/engineering-workflows.test.ts +114 -0
  408. package/payload/tests/explore-contract.test.ts +43 -0
  409. package/payload/tests/explore-group-change.test.ts +65 -0
  410. package/payload/tests/explore-labels.test.ts +33 -0
  411. package/payload/tests/explore-money.test.ts +72 -0
  412. package/payload/tests/explore-narrowed-measure.test.ts +54 -0
  413. package/payload/tests/explore-none.test.ts +60 -0
  414. package/payload/tests/explore-percent.test.ts +62 -0
  415. package/payload/tests/explore-refers.test.ts +86 -0
  416. package/payload/tests/explore-runner.test.ts +224 -0
  417. package/payload/tests/fact-periods.test.ts +29 -0
  418. package/payload/tests/facts-config.test.ts +40 -0
  419. package/payload/tests/facts-engineering.test.ts +84 -0
  420. package/payload/tests/facts.test.ts +146 -0
  421. package/payload/tests/fake-llm.test.ts +98 -1
  422. package/payload/tests/feature-access.test.ts +19 -10
  423. package/payload/tests/featured-metric.test.tsx +178 -0
  424. package/payload/tests/form-section-actions.test.tsx +30 -0
  425. package/payload/tests/format-compact-boundary.test.ts +31 -0
  426. package/payload/tests/format-cost-axis.test.ts +39 -0
  427. package/payload/tests/format.test.ts +24 -7
  428. package/payload/tests/heatmap-calendar-timezone.test.tsx +29 -0
  429. package/payload/tests/heatmap-calendar.test.tsx +214 -0
  430. package/payload/tests/heatmap-hours-timezone.test.tsx +30 -0
  431. package/payload/tests/heatmap-names-column.test.tsx +30 -0
  432. package/payload/tests/heatmap-scale.test.tsx +91 -0
  433. package/payload/tests/heatmap-states.test.tsx +191 -0
  434. package/payload/tests/honest-controls.test.tsx +76 -0
  435. package/payload/tests/incident-card-hyphens.test.tsx +56 -0
  436. package/payload/tests/incident-card.test.tsx +54 -0
  437. package/payload/tests/key-value.test.tsx +47 -0
  438. package/payload/tests/leave-then-unload.test.tsx +62 -0
  439. package/payload/tests/linked-records.test.ts +126 -0
  440. package/payload/tests/live-client.test.tsx +41 -0
  441. package/payload/tests/loading-routes.test.tsx +31 -5
  442. package/payload/tests/member-duplicate.test.ts +32 -0
  443. package/payload/tests/member-mutations.test.ts +2 -1
  444. package/payload/tests/member-row-access.test.tsx +5 -3
  445. package/payload/tests/members-optimistic.test.tsx +27 -2
  446. package/payload/tests/metric-tile-compact.test.tsx +107 -0
  447. package/payload/tests/metric-tile-note.test.tsx +28 -0
  448. package/payload/tests/metric-tile.test.tsx +100 -0
  449. package/payload/tests/navigate-menu-start.test.ts +35 -0
  450. package/payload/tests/navigate-start.test.ts +39 -0
  451. package/payload/tests/no-access.test.tsx +23 -1
  452. package/payload/tests/not-found.test.ts +2 -2
  453. package/payload/tests/page-fallbacks.test.tsx +4 -4
  454. package/payload/tests/page-frame-title.test.tsx +168 -0
  455. package/payload/tests/page-gates.test.tsx +6 -6
  456. package/payload/tests/page-loading.test.tsx +149 -0
  457. package/payload/tests/prose-memo.test.tsx +10 -0
  458. package/payload/tests/providers-hydration.test.tsx +75 -0
  459. package/payload/tests/query-rows.test.ts +30 -0
  460. package/payload/tests/query-state-address.test.tsx +32 -0
  461. package/payload/tests/rail-marker.test.tsx +46 -0
  462. package/payload/tests/rail-menu-prefetch.test.tsx +46 -0
  463. package/payload/tests/rail-sign-out-thread.test.tsx +44 -0
  464. package/payload/tests/records-consumers.test.tsx +101 -0
  465. package/payload/tests/records-template.test.tsx +38 -0
  466. package/payload/tests/release-phone-cell.test.ts +30 -0
  467. package/payload/tests/release-wording.test.ts +24 -0
  468. package/payload/tests/requests-summary-newest.test.ts +23 -0
  469. package/payload/tests/roles-context.test.ts +2 -2
  470. package/payload/tests/roles.test.ts +9 -4
  471. package/payload/tests/route-policy.test.ts +7 -2
  472. package/payload/tests/sample-company.test.ts +227 -0
  473. package/payload/tests/sample.test.ts +114 -5
  474. package/payload/tests/search-draft.test.tsx +37 -0
  475. package/payload/tests/segmented-fit.test.tsx +22 -0
  476. package/payload/tests/settings-access.test.tsx +11 -11
  477. package/payload/tests/settings-agents.test.tsx +58 -0
  478. package/payload/tests/settings-save.test.tsx +79 -0
  479. package/payload/tests/setup.ts +5 -0
  480. package/payload/tests/shared-context.test.tsx +484 -60
  481. package/payload/tests/shell-address.test.tsx +59 -0
  482. package/payload/tests/shell-alerts.test.ts +104 -0
  483. package/payload/tests/shell-drawer-back.test.tsx +51 -0
  484. package/payload/tests/shell-early-press.test.tsx +58 -0
  485. package/payload/tests/shell-first-arrival.test.tsx +51 -0
  486. package/payload/tests/shell-promise.test.tsx +1 -1
  487. package/payload/tests/sign-in-honest.test.tsx +36 -0
  488. package/payload/tests/sparkline-gaps.test.tsx +51 -0
  489. package/payload/tests/sparkline.test.tsx +20 -0
  490. package/payload/tests/status-list.test.tsx +56 -0
  491. package/payload/tests/template-consumers.test.tsx +94 -0
  492. package/payload/tests/ticket-mutations.test.ts +135 -0
  493. package/payload/tests/ticket-owner.test.ts +35 -0
  494. package/payload/tests/tickets-view.test.tsx +96 -0
  495. package/payload/tests/titles-engineering.test.ts +40 -0
  496. package/payload/tests/titles.test.ts +94 -0
  497. package/payload/tests/toast-announce.test.tsx +15 -0
  498. package/payload/tests/trend-chart-baseline.test.tsx +147 -0
  499. package/payload/tests/trend-chart-running.test.tsx +77 -0
  500. package/payload/tests/trend-chart.test.tsx +8 -4
  501. package/payload/tests/truncate.test.tsx +40 -0
  502. package/payload/tests/unsaved-leave.test.tsx +160 -0
  503. package/payload/tests/uptime-bars-end.test.tsx +20 -0
  504. package/payload/tests/uptime-no-data.test.tsx +34 -0
  505. package/payload/tests/usage-figures.test.ts +75 -0
  506. package/payload/tests/usage-summary.test.tsx +107 -0
  507. package/payload/tests/verify-coverage.test.ts +4 -4
  508. package/payload/tests/verify-explore-surfaces.test.ts +28 -0
  509. package/payload/tests/verify-personas.test.ts +3 -3
  510. package/payload/tests/verify-sample-surfaces.test.ts +23 -4
  511. package/payload/tests/verify-sizes.test.ts +1 -1
  512. package/payload/tests/view-tool-needs.test.ts +8 -3
  513. package/payload/tests/workspace-access.test.ts +72 -0
  514. package/payload/tests/workspace-chrome.test.tsx +134 -0
  515. package/payload/tests/workspace-data-paths.test.ts +140 -0
  516. package/payload/tests/workspace-figures.test.ts +111 -0
  517. package/payload/tests/workspace-home.test.tsx +119 -0
  518. package/payload/tests/workspace-menu-access.test.tsx +90 -0
  519. package/payload/tests/workspaces.test.ts +91 -0
  520. package/payload/tokens/theme.light.tokens.json +1 -1
  521. package/payload/vitest.config.ts +5 -1
  522. package/payload/app/(dashboard)/(overview)/README.md +0 -65
  523. package/payload/app/(dashboard)/(overview)/loading.tsx +0 -52
  524. package/payload/app/(dashboard)/(overview)/page.tsx +0 -62
  525. package/payload/app/(dashboard)/_loading.tsx +0 -74
  526. package/payload/app/(dashboard)/analytics/README.md +0 -64
  527. package/payload/app/(dashboard)/analytics/loading.tsx +0 -23
  528. package/payload/app/(dashboard)/analytics/page.tsx +0 -61
  529. package/payload/app/(dashboard)/health/README.md +0 -67
  530. package/payload/app/(dashboard)/health/loading.tsx +0 -33
  531. package/payload/app/(dashboard)/health/page.tsx +0 -27
  532. package/payload/app/embed/health/README.md +0 -41
  533. package/payload/app/embed/health/page.tsx +0 -22
  534. package/payload/app/embed/health/view.tsx +0 -44
  535. package/payload/app/embed/overview/README.md +0 -31
  536. package/payload/app/embed/overview/page.tsx +0 -27
  537. package/payload/app/embed/overview/view.tsx +0 -59
  538. package/payload/src/data/analytics.ts +0 -26
  539. package/payload/src/views/analytics-context.ts +0 -79
  540. package/payload/src/views/analytics.tsx +0 -153
  541. package/payload/src/views/health-context.ts +0 -53
  542. package/payload/src/views/health.tsx +0 -112
  543. package/payload/src/views/overview-context.ts +0 -179
  544. package/payload/src/views/overview.tsx +0 -182
  545. package/payload/tests/chrome-cleanup.test.ts +0 -35
  546. package/payload/tests/settings-disconnect-undo.test.tsx +0 -28
package/README.md CHANGED
@@ -35,13 +35,14 @@ npx zz-meridian@latest skill [--global] # install only the agent skill
35
35
  ```
36
36
 
37
37
  Brand flags: `--name "Acme Ops"`, `--hex '#2E6BE4'` (or `--accent indigo|cobalt|jade|graphite`), `--theme dark|light`,
38
- `--workspace`, `--timezone`, `--currency`, `--user`, `--role`.
38
+ `--workspace`, `--timezone`, `--currency`, `--user`, `--role`. `--workspace` sets `app.workspace`, the environment named
39
+ in a page's kicker ("Production"); it does not touch the navigation workspaces.
39
40
 
40
41
  **adopt** copies Meridian's tokens, styles, components, gates and scripts into `src/`, `tokens/` and `scripts/`;
41
42
  merges the dependencies and scripts it needs into your `package.json`; replaces your global stylesheet (yours is kept
42
43
  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
43
44
  for byte; writes an empty `docs/brief.md` (your product, users, data, decisions and glossary) if you have none; installs the skill into
44
- `.agents/skills/` (Codex) and `.claude/skills/` (Claude Code); records every copied file in `.meridian/manifest.json`;
45
+ `.agents/skills/` (Codex) and `.claude/skills/` (Claude Code); records every Meridian file it copied in `.meridian/manifest.json`;
45
46
  installs and type checks. Your routes, your data layer and your own components are not touched. Meridian's files
46
47
  import each other by relative path, so a `components/ui/button` of your own is never confused with Meridian's; your
47
48
  code imports Meridian as `@meridian/…`.
@@ -60,10 +61,11 @@ writes nothing; run it first.
60
61
  deleted or kept (`.meridian/keep.json`) is never overwritten: an edited or deleted one is staged as base/ours/new copies
61
62
  for you to merge.
62
63
  - It adds the dependencies and scripts this release needs to `package.json` and updates Meridian's managed block in
63
- `AGENTS.md`; a version or script you chose yourself becomes a migration to resolve, never a silent change.
64
- - It reports a migration for each interface the release changed where one of your own files still has the old shape;
65
- moving to 0.5.0 can report ten, such as `cache-components-config`. Resolve them as the skill's
66
- `references/update.md` says; `docs/distribution.md` lists them.
64
+ `AGENTS.md`; an older version of the same major is raised, and a newer version, an older major or a script you
65
+ chose yourself becomes a migration to resolve, never a silent change.
66
+ - It reports a migration for each interface the release changed where one of your own files still has the old shape,
67
+ such as `cache-components-config` or `nav-needs`. `cli/src/migrations.ts` holds every one; resolve them as the skill's
68
+ `references/update.md` says.
67
69
  - Everything it did and everything left to do is in `.meridian/update/<version>/MERGE.md`. Resolve the items, then run
68
70
  the pinned `npx zz-meridian@<version> update --finalize`; `--resume` continues an interrupted run and `--abort` restores
69
71
  what it changed. Only finalize records the new version. `--finalize --verify` validates with the project's default
@@ -82,7 +84,7 @@ Requires Node 22.18 or newer. The default `pnpm verify` runs without Google Chro
82
84
 
83
85
  It has no dependencies and no install scripts: running it executes only its own code, and only when you call it. It
84
86
  sends nothing anywhere; the only network access is your package manager's install, which you can skip with
85
- `--no-install`. Every release is built and published by GitHub Actions with npm provenance, so the registry shows the
87
+ `--no-install`, and `update` reading releases from npm. Every release is built and published by GitHub Actions with npm provenance, so the registry shows the
86
88
  commit and workflow each version came from.
87
89
 
88
90
  ## Privacy and feedback
package/dist/adopt.js CHANGED
@@ -72,21 +72,32 @@ function routes(root, dir) {
72
72
  return [...new Set(out)].filter((r) => /^\/[\w/.-]*$/.test(r)).sort((a, b) => (a === '/' ? -1 : b === '/' ? 1 : a.localeCompare(b)));
73
73
  }
74
74
  const label = (route) => (route === '/' ? 'Home' : route.split('/').pop().replace(/[-_]+/g, ' ').replace(/^./, (c) => c.toUpperCase()));
75
- function appConfig(pages) {
76
- const template = readPayload('src/app.config.ts');
75
+ /**
76
+ * The configuration `adopt` writes: the template's own file with the project's pages as its navigation. Everything that
77
+ * belongs to the sample is left out, because the project does not have it: the feature table (so every item is `public`,
78
+ * the honest default, until the fourth step of "Decide who may do what" in the Start guide points each at a feature of its own), every icon but the one the
79
+ * items use, and the sample's workspaces with the field that names one. It throws when the template has no navigation
80
+ * block to replace, since a configuration that still listed the sample's pages would be wrong without saying so.
81
+ */
82
+ export function projectConfig(template, pages) {
83
+ if (!/export const nav: NavGroup\[\] = \[[\s\S]*?\n\];/.test(template))
84
+ throw new Error('the template\'s src/app.config.ts has no `export const nav: NavGroup[] = [ … ];` block to replace');
77
85
  const items = pages.map((r) => ` { href: ${JSON.stringify(r)}, label: ${JSON.stringify(label(r))}, icon: LayoutGrid, needs: 'public' },`).join('\n');
78
86
  return template
79
87
  .replace(/^import \{[\s\S]*?\} from 'lucide-react';/m, "import { LayoutGrid, type LucideIcon } from 'lucide-react';")
80
- // The project's pages have no feature entry yet, so every item is `public` — the honest default — and step 4 of the
81
- // Start guide points each at its own feature once it has one. The template's own `FEATURES` import would name a file
82
- // this project's `src/data/` need not have, and a nav item without a `needs` is a type error since 0.13.0.
88
+ // The template's own `FEATURES` import would name a file this project's `src/data/` need not have, and a nav item
89
+ // without a `needs` is a type error since 0.13.0.
83
90
  .replace(/^import \{ FEATURES \} from '\.\/data\/features\.ts';\n/m, '')
91
+ .replace(/\/\*\*(?:(?!\*\/)[\s\S])*\*\/\nexport const workspaces = \{[\s\S]*?\n\} as const;\nexport type WorkspaceId = [^\n]*\n\n/, '')
92
+ .replace(' workspace?: WorkspaceId;', '')
84
93
  .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];`);
85
94
  }
86
95
  function verifyConfig() {
87
96
  return readPayload('scripts/verify.config.ts').replace(/const config: VerifyConfig = \{[\s\S]*?\n\};/, `const config: VerifyConfig = {
88
97
  // One detail page per state worth seeing (a normal record, a failed one, a missing one), with ids from your data.
89
98
  detailRoutes: [],
99
+ // What a route a persona may not open draws: the product's choice in src/app.config.ts.
100
+ refusal,
90
101
  };`);
91
102
  }
92
103
  /** The template's stylesheet, with its paths made relative to where the project keeps its own. */
@@ -168,7 +179,14 @@ https://github.com/zhixuan312/zz-meridian/blob/master/skills/zz-meridian/referen
168
179
  const raw = payloadBytes(rel);
169
180
  own(rel, TS.test(rel) ? exactImports(rel, raw.toString('utf8'), known) : raw);
170
181
  }
171
- own('src/app.config.ts', exactImports('src/app.config.ts', appConfig(routes(root, dir)), known));
182
+ let config;
183
+ try {
184
+ config = projectConfig(readPayload('src/app.config.ts'), routes(root, dir));
185
+ }
186
+ catch (e) {
187
+ return fail(e.message);
188
+ }
189
+ own('src/app.config.ts', exactImports('src/app.config.ts', config, known));
172
190
  own('scripts/verify.config.ts', verifyConfig());
173
191
  // Meridian's scripts are ES modules; a project whose package.json is not "type": "module" gets that for scripts/ only.
174
192
  if (pkg.type !== 'module')
@@ -100,6 +100,134 @@ function callArity(src, fn) {
100
100
  }
101
101
  return out;
102
102
  }
103
+ /** Where an import of the team's file `rel` points, as a project path with no extension; null for a package. */
104
+ const resolvedImport = (rel, spec) => {
105
+ const bare = spec.replace(/\.[mc]?[jt]sx?$/, '');
106
+ if (bare.startsWith('@/'))
107
+ return `src/${bare.slice(2)}`;
108
+ return bare.startsWith('.') ? path.posix.join(path.posix.dirname(rel), bare) : null;
109
+ };
110
+ /** Each import of a file of the team's: the module it resolves to, the names it takes and its namespace, if it has one. */
111
+ function importsOf(rel, src) {
112
+ const out = [];
113
+ for (const m of src.matchAll(/^\s*import\s+(?:type\s+)?([^'"]*?)\s+from\s+(['"])([^'"]+)\2/gm)) {
114
+ const from = resolvedImport(rel, m[3]);
115
+ if (from === null)
116
+ continue;
117
+ const names = (/\{([^}]*)\}/.exec(m[1])?.[1] ?? '').split(',').map((s) => s.trim().replace(/^type\s+/, '').split(/\s+as\s+/)[0]).filter(Boolean);
118
+ out.push({ from, names, namespace: /\*\s*as\s+([\w$]+)/.exec(m[1])?.[1] ?? null });
119
+ }
120
+ return out;
121
+ }
122
+ /**
123
+ * The index just past the string, template or comment that starts at `i`, or `i` when none does. A regular expression is
124
+ * not told from a division here: a view tool's object holds none whose brackets or quotes do not balance.
125
+ */
126
+ function skipLiteral(src, i) {
127
+ const c = src[i], next = src[i + 1];
128
+ if (c === '/' && next === '/') {
129
+ const e = src.indexOf('\n', i);
130
+ return e < 0 ? src.length : e;
131
+ }
132
+ if (c === '/' && next === '*') {
133
+ const e = src.indexOf('*/', i + 2);
134
+ return e < 0 ? src.length : e + 2;
135
+ }
136
+ if (c === "'" || c === '"') {
137
+ let j = i + 1;
138
+ while (j < src.length && src[j] !== c && src[j] !== '\n')
139
+ j += src[j] === '\\' ? 2 : 1;
140
+ return j + 1;
141
+ }
142
+ if (c === '`') {
143
+ let j = i + 1;
144
+ while (j < src.length && src[j] !== '`') {
145
+ if (src[j] === '\\')
146
+ j += 2;
147
+ else if (src[j] === '$' && src[j + 1] === '{')
148
+ j = closeOf(src, j + 1) + 1;
149
+ else
150
+ j++;
151
+ }
152
+ return j + 1;
153
+ }
154
+ return i;
155
+ }
156
+ /** The index of the bracket that closes the `{`, `(` or `[` at `open`, passing over strings and comments. */
157
+ function closeOf(src, open) {
158
+ let depth = 0;
159
+ for (let i = open; i < src.length;) {
160
+ const past = skipLiteral(src, i);
161
+ if (past !== i) {
162
+ i = past;
163
+ continue;
164
+ }
165
+ const c = src[i];
166
+ if ('{(['.includes(c))
167
+ depth++;
168
+ else if ('})]'.includes(c) && --depth === 0)
169
+ return i;
170
+ i++;
171
+ }
172
+ return src.length;
173
+ }
174
+ /**
175
+ * Each `defineViewTool({ … })` call of a file, as the keys of its object's own level, each with its value when that is a
176
+ * string and null otherwise; a key inside a nested object, call or function body, such as an input's `page`, is not
177
+ * the tool's. An object that spreads another has the key `...`, since what it spreads cannot be read here.
178
+ */
179
+ function viewToolCalls(src) {
180
+ const out = [];
181
+ const call = /defineViewTool\s*(?:<[^>]*>)?\s*\(\s*\{/y;
182
+ const key = /(?:async\s+)?([A-Za-z_$][\w$]*)(?:\s*:\s*(['"])((?:\\.|(?!\2)[^\\\n])*)\2)?/y;
183
+ for (let i = 0; i < src.length;) {
184
+ const past = skipLiteral(src, i);
185
+ if (past !== i) {
186
+ i = past;
187
+ continue;
188
+ }
189
+ call.lastIndex = i;
190
+ const m = call.exec(src);
191
+ if (!m || /[\w$.]/.test(src[i - 1] ?? '')) {
192
+ i++;
193
+ continue;
194
+ }
195
+ const open = i + m[0].length - 1;
196
+ const close = closeOf(src, open);
197
+ const keys = new Map();
198
+ let prev = '{';
199
+ for (let k = open + 1; k < close;) {
200
+ const lit = skipLiteral(src, k);
201
+ if (lit !== k) {
202
+ k = lit;
203
+ continue;
204
+ }
205
+ const c = src[k];
206
+ if (/\s/.test(c)) {
207
+ k++;
208
+ continue;
209
+ }
210
+ if (prev === '{' || prev === ',') {
211
+ if (src.startsWith('...', k))
212
+ keys.set('...', null);
213
+ key.lastIndex = k;
214
+ const found = key.exec(src);
215
+ if (found && !keys.has(found[1]))
216
+ keys.set(found[1], found[3] ?? null);
217
+ }
218
+ if ('{(['.includes(c)) {
219
+ k = closeOf(src, k) + 1;
220
+ prev = '}';
221
+ continue;
222
+ }
223
+ prev = c;
224
+ k++;
225
+ }
226
+ out.push(keys);
227
+ i = close + 1;
228
+ }
229
+ return out;
230
+ }
103
231
  // ── The registry ─────────────────────────────────────────────────────────────────────────────────────
104
232
  const GATE_AND_BUILD = ['gate', 'build'];
105
233
  export const RELEASE_MIGRATIONS = [
@@ -243,10 +371,146 @@ export const RELEASE_MIGRATIONS = [
243
371
  since: '0.13.0',
244
372
  applies: navItemsWithoutNeeds,
245
373
  summary: 'Every item in the project\'s `nav` carries a `needs`, so the rail shows only the destinations a person may reach.',
246
- instructions: 'Read "Roles and access" in the Start guide (docs/start-a-dashboard.md). For each item in `src/app.config.ts`\'s `nav`, add `needs: \'public\'` when everyone may open that page, or point it at its feature (`needs: FEATURES.<id>.needs`); step 4 of that guide has the four steps, and `scripts/check.ts` fails the project\'s gate, naming the href, on an item without one. `adopt` writes `needs: \'public\'` for a project it sets up from now on.',
374
+ instructions: 'Read "5. Decide who may do what" in the Start guide (docs/start-a-dashboard.md). For each item in `src/app.config.ts`\'s `nav`, add `needs: \'public\'` when everyone may open that page, or point it at its feature (`needs: FEATURES.<id>.needs`); the fourth of its four steps covers it, and `scripts/check.ts` fails the project\'s gate, naming the href, on an item without one. `adopt` writes `needs: \'public\'` for a project it sets up from now on.',
247
375
  checks: ['gate'],
248
376
  },
377
+ {
378
+ id: 'agent-reads-own-group',
379
+ since: '0.15.0',
380
+ applies: ownGroupPagesWithoutAgentReads,
381
+ summary: 'A page under the route group the project keeps its console in says what the agent reads.',
382
+ instructions: 'The gate asked this of pages under `app/(dashboard)/` only; from 0.15.0 it asks it under whatever route group sits at the top of the app folder. Read "A page spec" in references/customize.md. Under `## Agents` in each page\'s README.md listed here, add `### What the agent reads`: what the page\'s shared context tells each agent, with a real line of it, and what the MCP App and the console assistant do with it. A copy of the rule kept in `scripts/check.local.ts` for the project\'s own group can be deleted.',
383
+ checks: ['gate'],
384
+ },
385
+ {
386
+ id: 'refusal-declared',
387
+ since: '0.16.0',
388
+ applies: refusalUndeclared,
389
+ summary: 'The product says what an address a person may not open draws: `refusal` in `src/app.config.ts`.',
390
+ instructions: 'Read "Navigation: `src/app.config.ts`" in references/customize.md. Add `export const refusal: \'explain\' | \'absent\' = \'explain\';` to `src/app.config.ts`, beside `facts`: `explain` keeps the no-access page a refused page draws today, and `absent` answers as an address that names nothing. A project that keeps the sample\'s access seam brings `src/data/access.ts` and `src/data/refusal.ts` over from the release (`gate` reads `refusal`, with `gatedMetadata` and `withheldEntries` beside it, and `gatedLoading` reads it alone), titles each gated page with `export function generateMetadata() { return gatedMetadata(\'<feature>\', { title: \'<its title>\' }); }` in place of a static `metadata`, passes its loading state\'s `name` and `title` through `gatedLoading`, and adds `refusal,` to the config object of `scripts/verify.config.ts`, imported from `../src/app.config.ts`, so `verify --as` expects the page the product chose.',
391
+ checks: GATE_AND_BUILD,
392
+ },
393
+ {
394
+ id: 'managed-exports-removed',
395
+ since: '0.16.0',
396
+ applies: removedExportReaders,
397
+ summary: 'A file of the team\'s imports an export the release removed from a managed module: `deviations`, `largest`, `runs` or `weekendRatio` from `src/lib/insight.ts`, or `queryInput` from `src/lib/collection.ts`.',
398
+ instructions: 'The update brought `src/lib/insight.ts` and `src/lib/collection.ts` without them, so each file listed here fails the type check. A file of the sample\'s comes over from the release: the Overview context is Home\'s, `src/views/home-context.ts` (see `sample-pages-renamed`); the assistant reads through `view_<name>` and `explore_<view>` and has no `query_<name>` tools, so bring `src/lib/assistant/tools.ts` and `src/lib/assistant/respond.ts` over and pass `readable`, every collection the person may read, from the assistant route to `respond` beside `collections` (read "Prepared queries" in references/agents.md); and a shipped test that imports one, such as `tests/shared-context.test.tsx` or `tests/collection.test.ts`, comes over as the release has it. A file of your own that still needs one of the functions writes it in that file, from its 0.15.0 source.',
399
+ checks: GATE_AND_BUILD,
400
+ },
401
+ {
402
+ id: 'view-tool-page-explore',
403
+ since: '0.16.0',
404
+ applies: (root) => matching(root, (_, src) => viewToolCalls(src).some((k) => !k.has('...') && !(k.has('page') && k.has('explore')))),
405
+ summary: 'Every view tool names the page it renders and its prepared query: `page` and `explore` on `defineViewTool`.',
406
+ instructions: 'Read "Prepared queries" in references/agents.md. Add to each `defineViewTool` call in the files listed here `page`, the console route of the page the view renders (a rail destination\'s `href` in `nav`, or a detail page\'s route with its segment, such as `/customers/[id]`), and `explore`, its prepared query (`PreparedQuery` in `src/lib/explore.ts`), declared beside the view as the sample\'s are in `src/views/<view>-explore.ts`. `ViewTool` in `src/lib/shared-context.ts` requires both, so a tool without them fails the type check. A project that kept the sample\'s view tools brings `src/views/tools.ts` and the `src/views/*-explore.ts` files over from the release. Once a tool names its page, the gate asks that page\'s specification what the agent does there (`agent-does-here-section`).',
407
+ checks: GATE_AND_BUILD,
408
+ },
409
+ {
410
+ id: 'agent-does-here-section',
411
+ since: '0.16.0',
412
+ applies: viewToolPagesWithoutAgentDoes,
413
+ summary: 'The specification of a page a view tool renders says what the agent does there.',
414
+ instructions: 'Read "Prepared queries" in references/agents.md. Under `## Agents` in the README.md of each page a view tool\'s `page` names, add `### What the agent does here`: a line `Protagonist: <the card\'s name>.`, then at least three questions a person on the page asks that its context does not answer alone, each `- "<question>" — <what the prepared query is asked>`, and mark that card on the page with `data-protagonist="<name>"`. `scripts/check.ts` fails the gate on such a page without the part. While a view tool in `src/views/tools.ts` names no page yet (`view-tool-page-explore`), every console page specification without the part is listed: one that no tool comes to name needs nothing.',
415
+ checks: ['gate'],
416
+ },
417
+ {
418
+ id: 'sample-pages-renamed',
419
+ since: '0.16.0',
420
+ applies: renamedSampleFiles,
421
+ summary: 'The project holds the sample\'s pages and views under their 0.15.0 names: Overview is Home, Analytics is Usage at `/usage` and Operations is Services at `/services`.',
422
+ instructions: 'The release renamed them with no redirect, and an update writes none of the team\'s pages, views or tests. Each file listed is one of them or names one: a page or a view, the view tools, `src/app.config.ts`\'s nav and the feature ids it names, the routes of `scripts/verify.config.ts`, or a shipped test that expects them. A project that kept the sample\'s pages as they were brings the release\'s over: `app/(dashboard)/` and `app/embed/`, `src/views/`, `src/data/`, `src/lib/assistant/` beside `prompt.ts`, `src/app.config.ts` with its own `app` kept, and each shipped test as the release has it; a file listed here that the release no longer has is deleted. A project that made the pages its own keeps its own names, makes the changes this release\'s other migrations list in them, and reads "not applicable" for the assistant walk-through\'s steps on Home and Now (`scripts/lib/sample.ts`).',
423
+ checks: GATE_AND_BUILD,
424
+ },
249
425
  ];
426
+ /** The team's files that import an export 0.16.0 removed from a managed module, by name or through a namespace. */
427
+ function removedExportReaders(root) {
428
+ const removed = { 'src/lib/insight': ['deviations', 'largest', 'runs', 'weekendRatio'], 'src/lib/collection': ['queryInput'] };
429
+ return matching(root, (rel, src) => importsOf(rel, src).some(({ from, names, namespace }) => {
430
+ const gone = removed[from] ?? [];
431
+ return names.some((n) => gone.includes(n)) || (namespace !== null && gone.some((g) => new RegExp(`(?<![\\w$.])${namespace.replace(/\$/g, '\\$')}\\.${g}\\b`).test(src)));
432
+ }));
433
+ }
434
+ /**
435
+ * The specifications of the pages the view tools of `src/views/tools.ts` render, as the gate reads them from 0.16.0,
436
+ * that lack "What the agent does here". While a tool names no page, the gate cannot tell its page, and neither can this:
437
+ * every console page specification without the part is listed then.
438
+ */
439
+ function viewToolPagesWithoutAgentDoes(root) {
440
+ const tools = text(root, 'src/views/tools.ts');
441
+ if (tools === null)
442
+ return null;
443
+ const calls = viewToolCalls(tools).filter((k) => !k.has('...'));
444
+ if (calls.length === 0)
445
+ return null;
446
+ const pages = new Set(calls.map((k) => k.get('page')).filter((p) => typeof p === 'string'));
447
+ const unnamed = calls.some((k) => !k.has('page'));
448
+ const app = fs.existsSync(path.join(root, 'app')) ? 'app' : 'src/app';
449
+ const specs = [];
450
+ walk(root, app, specs, /^README\.md$/);
451
+ const hits = specs.filter((rel) => {
452
+ const rest = rel.slice(app.length + 1);
453
+ if (!/^\([^/)]+\)\//.test(rest))
454
+ return false;
455
+ const route = `/${path.posix.dirname(rest).split('/').filter((s) => !/^\(.*\)$/.test(s)).join('/')}`;
456
+ return (unnamed || pages.has(route)) && !/^## Agents$(?:\n(?!## ).*)*\n### What the agent does here$/m.test(text(root, rel) ?? '');
457
+ });
458
+ return hits.length > 0 ? hits : null;
459
+ }
460
+ /**
461
+ * The sample's pages and views under the names 0.16.0 replaced, and every file of the team's that names one: an import
462
+ * of one of their modules, a feature id or view tool of theirs, the walk-through's surfaces as they were, and the
463
+ * verify config's routes for them. Only a project that still holds one of the sample's old files is read, so a page of
464
+ * a product's own at the same address, or a feature of its own of the same name, is never taken for the sample's. The
465
+ * names are put together from their parts: the repository holds them out of everything but its history.
466
+ */
467
+ function renamedSampleFiles(root) {
468
+ const old = ['overview', 'analytics', 'health'];
469
+ const modules = new Set([...old.flatMap((n) => [`src/views/${n}`, `src/views/${n}-context`]), `src/data/${old[1]}`]);
470
+ const group = `(${old[0]})`;
471
+ const named = new RegExp(`\\b(?:FEATURES\\.|view_)(?:${old.join('|')})\\b`);
472
+ const isOld = (rel) => modules.has(rel.replace(/\.[mc]?[jt]sx?$/, '')) || (/^(?:src\/)?app\//.test(rel) && rel.split('/').includes(group));
473
+ const sources = teamSources(root);
474
+ if (!sources.some((f) => isOld(f.rel)))
475
+ return null;
476
+ const seeds = sources.filter(({ rel, src }) => isOld(rel)
477
+ || importsOf(rel, src).some((i) => modules.has(i.from))
478
+ || named.test(src)
479
+ || (/\bsampleSurfaces\b/.test(src) && new RegExp(`\\b${old[0]}\\s*:|\\.${old[0]}\\b`).test(src))).map((f) => f.rel);
480
+ // A page or an embed view of the sample's goes with its folder: its loading state and its specification name nothing
481
+ // of the old, and are as much the sample's. A file that imports one of the old files, such as a test that renders the
482
+ // page, names it too; a file that only names one, such as the configuration, is not itself the old.
483
+ const oldFiles = new Set(sources.map((f) => f.rel).filter(isOld));
484
+ const pages = sources.filter(({ rel, src }) => /^(?:src\/)?app\//.test(rel) && /^(?:page|view)\.tsx?$/.test(base(rel)) && (isOld(rel) || importsOf(rel, src).some((i) => modules.has(i.from))));
485
+ for (const { rel } of pages) {
486
+ const dir = path.posix.dirname(rel);
487
+ try {
488
+ for (const e of fs.readdirSync(path.join(root, dir), { withFileTypes: true }))
489
+ if (e.isFile())
490
+ oldFiles.add(`${dir}/${e.name}`);
491
+ }
492
+ catch { /* gone since it was read */ }
493
+ }
494
+ const oldPaths = new Set([...oldFiles].map((r) => r.replace(/\.[mc]?[jt]sx?$/, '')));
495
+ const found = new Set([...seeds, ...oldFiles]);
496
+ for (const { rel, src } of sources)
497
+ if (importsOf(rel, src).some((i) => oldPaths.has(i.from)))
498
+ found.add(rel);
499
+ const hits = [...found].sort();
500
+ const verifyConfig = 'scripts/verify.config.ts';
501
+ const routes = new RegExp(`'/(?:${old[1]}|${old[2]})'|title:\\s*'(?:Overview|Analytics|Operations)'`);
502
+ if (routes.test(text(root, verifyConfig) ?? ''))
503
+ hits.push(verifyConfig);
504
+ return hits;
505
+ }
506
+ /** The project's configuration, when it does not yet say what an address a person may not open draws (0.16.0). */
507
+ function refusalUndeclared(root) {
508
+ const rel = 'src/app.config.ts';
509
+ const body = text(root, rel);
510
+ if (body === null)
511
+ return null;
512
+ return /^export const refusal\b/m.test(body) ? null : [rel];
513
+ }
250
514
  /** The project's own nav, with any item still missing the `needs` that 0.13.0 requires of it. */
251
515
  function navItemsWithoutNeeds(root) {
252
516
  const rel = 'src/app.config.ts';
@@ -267,6 +531,24 @@ function navItemsWithoutNeeds(root) {
267
531
  const typeHasNeeds = /export type NavItem[^;]*\bneeds\s*:/.test(body);
268
532
  return items.some((l) => !/\bneeds\s*:/.test(l)) || (declaredType && !typeHasNeeds) ? [rel] : null;
269
533
  }
534
+ /**
535
+ * The page specifications under a route group of the project's own, at the top of its app folder, that lack the part the
536
+ * gate asks for there from 0.15.0. The template's `(dashboard)` is left out: the rule has covered it since 0.9.0.
537
+ */
538
+ function ownGroupPagesWithoutAgentReads(root) {
539
+ const files = [];
540
+ for (const app of ['app', 'src/app']) {
541
+ let groups = [];
542
+ try {
543
+ groups = fs.readdirSync(path.join(root, app), { withFileTypes: true }).filter((e) => e.isDirectory() && /^\(.+\)$/.test(e.name) && e.name !== '(dashboard)').map((e) => e.name);
544
+ }
545
+ catch { /* no such folder */ }
546
+ for (const g of groups)
547
+ walk(root, `${app}/${g}`, files, /^README\.md$/);
548
+ }
549
+ const hits = files.filter((rel) => !/^## Agents\n[\s\S]*?^### What the agent reads$/m.test(text(root, rel) ?? ''));
550
+ return hits.length > 0 ? hits : null;
551
+ }
270
552
  /** The page specifications under the console and embed folders that lack the part the 0.9.0 check requires. */
271
553
  function pagesWithoutAgentReads(root) {
272
554
  const files = [];
package/dist/ownership.js CHANGED
@@ -1,14 +1,14 @@
1
1
  const HASH = /^sha256-[0-9a-f]{64}$/;
2
2
  const SEMVER = /^\d+\.\d+\.\d+$/;
3
3
  /** The library modules Meridian's components and gates import; the rest of src/lib belongs to the template's pages. */
4
- export const LIB = ['cn', 'format', 'format-date', 'period', 'color', 'host', 'preferences', 'csv', 'safe-markdown', 'logo', 'collection', 'live', 'shared-context', 'agent-guidance', 'insight'].map((n) => `src/lib/${n}.ts`);
4
+ export const LIB = ['cn', 'format', 'format-date', 'period', 'color', 'host', 'preferences', 'csv', 'safe-markdown', 'logo', 'collection', 'explore', 'live', 'shared-context', 'agent-guidance', 'insight', 'facts'].map((n) => `src/lib/${n}.ts`);
5
5
  /** The single files adopt copies besides the folders and the library: all of them must be in a payload that is whole. */
6
6
  export const FIXED = [...LIB, 'src/lib/assistant/prompt.ts', 'src/views/console-chrome.tsx', 'tests/setup.ts'];
7
7
  /** The one rule, a plain-English line per clause. `references/ownership.md` renders it, so the guidance cannot drift. */
8
8
  export const OWNERSHIP = [
9
9
  'Managed: the payload files under `tokens/`, `src/styles/` and `src/components/`, except each component\'s `README.md` and `preview.tsx`.',
10
10
  'Managed: the distributed scripts under `scripts/`, except `scripts/verify.config.ts`, the first-load baseline `optional:scripts/verify.baseline.json` and a team-local `optional:scripts/check.local.ts`.',
11
- 'Managed: the library helpers `src/lib/cn.ts`, `src/lib/format.ts`, `src/lib/format-date.ts`, `src/lib/period.ts`, `src/lib/color.ts`, `src/lib/host.ts`, `src/lib/preferences.ts`, `src/lib/csv.ts`, `src/lib/safe-markdown.ts`, `src/lib/logo.ts`, `src/lib/collection.ts`, `src/lib/live.ts`, `src/lib/shared-context.ts`, `src/lib/agent-guidance.ts` and `src/lib/insight.ts`, and the assistant prompt `src/lib/assistant/prompt.ts`.',
11
+ 'Managed: the library helpers `src/lib/cn.ts`, `src/lib/format.ts`, `src/lib/format-date.ts`, `src/lib/period.ts`, `src/lib/color.ts`, `src/lib/host.ts`, `src/lib/preferences.ts`, `src/lib/csv.ts`, `src/lib/safe-markdown.ts`, `src/lib/logo.ts`, `src/lib/collection.ts`, `src/lib/explore.ts`, `src/lib/live.ts`, `src/lib/shared-context.ts`, `src/lib/agent-guidance.ts`, `src/lib/insight.ts` and `src/lib/facts.ts`, and the assistant prompt `src/lib/assistant/prompt.ts`.',
12
12
  'Managed: `src/views/console-chrome.tsx` and `tests/setup.ts`.',
13
13
  'Managed: `optional:scripts/package.json`, only when the adopt or create that set the project up generated it for this project shape.',
14
14
  'Managed: both installed skill trees, `optional:.agents/skills/zz-meridian/` and `optional:.claude/skills/zz-meridian/`, taken from the release\'s skill payload.',
package/dist/session.js CHANGED
@@ -289,6 +289,29 @@ function install(ctx, session, j, pm) {
289
289
  return { ms, failure: r.status === 0 ? null : `${pm} install exited with ${r.status}; see evidence/0-install.log` };
290
290
  }
291
291
  const isInstall = (v) => v.command.endsWith(' install');
292
+ /**
293
+ * The managed files that are not the release's bytes and that no keep entry explains, as lines to print; none when
294
+ * there are none. Nothing else reports them between releases, and the next update would meet each as an edit nobody
295
+ * recorded a reason for. A keep register that cannot be read explains nothing, and the gate already says why.
296
+ */
297
+ function unrecordedEdits(root, manifest) {
298
+ let kept = new Set();
299
+ try {
300
+ kept = new Set(parseKeep(fs.readFileSync(path.join(root, '.meridian', 'keep.json'), 'utf8')).map((k) => k.path));
301
+ }
302
+ catch { /* no register, or one the gate reports */ }
303
+ const edited = Object.entries(manifest.files)
304
+ .filter(([p, hash]) => !kept.has(p) && (!fs.existsSync(path.join(root, p)) || sha256(fs.readFileSync(path.join(root, p))) !== hash))
305
+ .map(([p]) => p)
306
+ .sort();
307
+ if (edited.length === 0)
308
+ return [];
309
+ return [
310
+ `${edited.length} managed ${edited.length === 1 ? 'file differs' : 'files differ'} from the release and ${edited.length === 1 ? 'is' : 'are'} not in .meridian/keep.json:`,
311
+ ...edited.map((p) => ` ${p}${fs.existsSync(path.join(root, p)) ? '' : ' (missing)'}`),
312
+ 'The next update will ask about each. Restore a file to the release, or name it in .meridian/keep.json with the reason it differs.',
313
+ ];
314
+ }
292
315
  export function start(ctx, o) {
293
316
  const { root, log } = ctx;
294
317
  const refuse = (cause) => { log(`zz-meridian update: ${cause}`); return 1; };
@@ -310,6 +333,8 @@ export function start(ctx, o) {
310
333
  // Already current is not a refusal: there is nothing to do, and the run that asked has its answer.
311
334
  if (manifest.version === ctx.version) {
312
335
  log(`zz-meridian update: already at ${ctx.version}; nothing to update`);
336
+ for (const line of unrecordedEdits(root, manifest))
337
+ log(line);
313
338
  return 0;
314
339
  }
315
340
  if (!isNewer(ctx.version, manifest.version))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zz-meridian",
3
- "version": "0.14.1",
3
+ "version": "0.16.0",
4
4
  "description": "Bring ZZ Meridian, a dashboard design system, into a Next.js project, or start a new dashboard on it. Copies the files in; nothing depends on this package at runtime.",
5
5
  "license": "MIT",
6
6
  "type": "module",