@qijenchen/design-system 0.1.0-beta.13 → 0.1.0-beta.130

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 (1751) hide show
  1. package/AGENTS.md +8 -0
  2. package/CLAUDE.md +3 -199
  3. package/README.md +6 -4
  4. package/cli-init.mjs +30 -2
  5. package/dist/components/Accordion/accordion.d.ts +3 -3
  6. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  7. package/dist/components/Accordion/accordion.js +6 -3
  8. package/dist/components/Accordion/accordion.js.map +1 -1
  9. package/dist/components/Accordion/index.d.ts +2 -0
  10. package/dist/components/Accordion/index.d.ts.map +1 -0
  11. package/dist/components/Accordion/index.js +9 -0
  12. package/dist/components/Accordion/index.js.map +1 -0
  13. package/dist/components/AccountMenu/account-menu.d.ts +93 -0
  14. package/dist/components/AccountMenu/account-menu.d.ts.map +1 -0
  15. package/dist/components/AccountMenu/account-menu.js +73 -0
  16. package/dist/components/AccountMenu/account-menu.js.map +1 -0
  17. package/dist/components/AccountMenu/index.d.ts +2 -0
  18. package/dist/components/AccountMenu/index.d.ts.map +1 -0
  19. package/dist/components/AccountMenu/index.js +6 -0
  20. package/dist/components/AccountMenu/index.js.map +1 -0
  21. package/dist/components/AgentPanel/agent-fab.d.ts +24 -0
  22. package/dist/components/AgentPanel/agent-fab.d.ts.map +1 -0
  23. package/dist/components/AgentPanel/agent-logo.d.ts +40 -0
  24. package/dist/components/AgentPanel/agent-logo.d.ts.map +1 -0
  25. package/dist/components/AgentPanel/agent-logo.js +344 -0
  26. package/dist/components/AgentPanel/agent-logo.js.map +1 -0
  27. package/dist/components/AgentPanel/agent-panel.d.ts +148 -0
  28. package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -0
  29. package/dist/components/AgentPanel/agent-panel.js +670 -0
  30. package/dist/components/AgentPanel/agent-panel.js.map +1 -0
  31. package/dist/components/AgentPanel/index.d.ts +2 -0
  32. package/dist/components/AgentPanel/index.d.ts.map +1 -0
  33. package/dist/components/AgentPanel/index.js +13 -0
  34. package/dist/components/AgentPanel/index.js.map +1 -0
  35. package/dist/components/Alert/alert.d.ts +7 -2
  36. package/dist/components/Alert/alert.d.ts.map +1 -1
  37. package/dist/components/Alert/alert.js +12 -8
  38. package/dist/components/Alert/alert.js.map +1 -1
  39. package/dist/components/Alert/index.d.ts +2 -0
  40. package/dist/components/Alert/index.d.ts.map +1 -0
  41. package/dist/components/Alert/index.js +7 -0
  42. package/dist/components/Alert/index.js.map +1 -0
  43. package/dist/components/AppShell/_demo-helpers.d.ts +3 -1
  44. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
  45. package/dist/components/AppShell/app-shell.d.ts +19 -4
  46. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  47. package/dist/components/AppShell/app-shell.js +48 -11
  48. package/dist/components/AppShell/app-shell.js.map +1 -1
  49. package/dist/components/AppShell/index.d.ts +2 -0
  50. package/dist/components/AppShell/index.d.ts.map +1 -0
  51. package/dist/components/AppShell/index.js +8 -0
  52. package/dist/components/AppShell/index.js.map +1 -0
  53. package/dist/components/AspectRatio/aspect-ratio.d.ts +3 -2
  54. package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -1
  55. package/dist/components/AspectRatio/aspect-ratio.js +4 -2
  56. package/dist/components/AspectRatio/aspect-ratio.js.map +1 -1
  57. package/dist/components/AspectRatio/index.d.ts +2 -0
  58. package/dist/components/AspectRatio/index.d.ts.map +1 -0
  59. package/dist/components/AspectRatio/index.js +6 -0
  60. package/dist/components/AspectRatio/index.js.map +1 -0
  61. package/dist/components/Avatar/avatar.d.ts +14 -7
  62. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  63. package/dist/components/Avatar/avatar.js +24 -30
  64. package/dist/components/Avatar/avatar.js.map +1 -1
  65. package/dist/components/Avatar/index.d.ts +2 -0
  66. package/dist/components/Avatar/index.d.ts.map +1 -0
  67. package/dist/components/Avatar/index.js +6 -0
  68. package/dist/components/Avatar/index.js.map +1 -0
  69. package/dist/components/Badge/badge.d.ts +21 -9
  70. package/dist/components/Badge/badge.d.ts.map +1 -1
  71. package/dist/components/Badge/badge.js +9 -6
  72. package/dist/components/Badge/badge.js.map +1 -1
  73. package/dist/components/Badge/index.d.ts +2 -0
  74. package/dist/components/Badge/index.d.ts.map +1 -0
  75. package/dist/components/Badge/index.js +7 -0
  76. package/dist/components/Badge/index.js.map +1 -0
  77. package/dist/components/Breadcrumb/breadcrumb.d.ts +16 -3
  78. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  79. package/dist/components/Breadcrumb/breadcrumb.js +21 -53
  80. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  81. package/dist/components/Breadcrumb/index.d.ts +2 -0
  82. package/dist/components/Breadcrumb/index.d.ts.map +1 -0
  83. package/dist/components/Breadcrumb/index.js +12 -0
  84. package/dist/components/Breadcrumb/index.js.map +1 -0
  85. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +7 -4
  86. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  87. package/dist/components/BulkActionBar/bulk-action-bar.js +8 -8
  88. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  89. package/dist/components/BulkActionBar/index.d.ts +2 -0
  90. package/dist/components/BulkActionBar/index.d.ts.map +1 -0
  91. package/dist/components/BulkActionBar/index.js +7 -0
  92. package/dist/components/BulkActionBar/index.js.map +1 -0
  93. package/dist/components/Button/button-group.d.ts +31 -5
  94. package/dist/components/Button/button-group.d.ts.map +1 -1
  95. package/dist/components/Button/button-group.js +31 -14
  96. package/dist/components/Button/button-group.js.map +1 -1
  97. package/dist/components/Button/button.d.ts +15 -14
  98. package/dist/components/Button/button.d.ts.map +1 -1
  99. package/dist/components/Button/button.js +94 -52
  100. package/dist/components/Button/button.js.map +1 -1
  101. package/dist/components/Button/index.d.ts +3 -0
  102. package/dist/components/Button/index.d.ts.map +1 -0
  103. package/dist/components/Button/index.js +11 -0
  104. package/dist/components/Button/index.js.map +1 -0
  105. package/dist/components/Calendar/calendar.d.ts +22 -19
  106. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  107. package/dist/components/Calendar/calendar.js +180 -135
  108. package/dist/components/Calendar/calendar.js.map +1 -1
  109. package/dist/components/Calendar/index.d.ts +2 -0
  110. package/dist/components/Calendar/index.d.ts.map +1 -0
  111. package/dist/components/Calendar/index.js +6 -0
  112. package/dist/components/Calendar/index.js.map +1 -0
  113. package/dist/components/Carousel/carousel.d.ts +15 -9
  114. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  115. package/dist/components/Carousel/carousel.js +91 -50
  116. package/dist/components/Carousel/carousel.js.map +1 -1
  117. package/dist/components/Carousel/index.d.ts +2 -0
  118. package/dist/components/Carousel/index.d.ts.map +1 -0
  119. package/dist/components/Carousel/index.js +11 -0
  120. package/dist/components/Carousel/index.js.map +1 -0
  121. package/dist/components/Chart/chart.d.ts +2 -2
  122. package/dist/components/Chart/chart.d.ts.map +1 -1
  123. package/dist/components/Chart/chart.js +5 -2
  124. package/dist/components/Chart/chart.js.map +1 -1
  125. package/dist/components/Chart/index.d.ts +2 -0
  126. package/dist/components/Chart/index.d.ts.map +1 -0
  127. package/dist/components/Chart/index.js +11 -0
  128. package/dist/components/Chart/index.js.map +1 -0
  129. package/dist/components/Checkbox/checkbox-group.d.ts +2 -1
  130. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  131. package/dist/components/Checkbox/checkbox-group.js +21 -14
  132. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  133. package/dist/components/Checkbox/checkbox.d.ts +20 -11
  134. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  135. package/dist/components/Checkbox/checkbox.js +117 -18
  136. package/dist/components/Checkbox/checkbox.js.map +1 -1
  137. package/dist/components/Checkbox/index.d.ts +3 -0
  138. package/dist/components/Checkbox/index.d.ts.map +1 -0
  139. package/dist/components/Checkbox/index.js +10 -0
  140. package/dist/components/Checkbox/index.js.map +1 -0
  141. package/dist/components/Chip/chip.d.ts +30 -11
  142. package/dist/components/Chip/chip.d.ts.map +1 -1
  143. package/dist/components/Chip/chip.js +83 -33
  144. package/dist/components/Chip/chip.js.map +1 -1
  145. package/dist/components/Chip/index.d.ts +2 -0
  146. package/dist/components/Chip/index.d.ts.map +1 -0
  147. package/dist/components/Chip/index.js +8 -0
  148. package/dist/components/Chip/index.js.map +1 -0
  149. package/dist/components/CircularProgress/circular-progress.d.ts +2 -3
  150. package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -1
  151. package/dist/components/CircularProgress/circular-progress.js +5 -4
  152. package/dist/components/CircularProgress/circular-progress.js.map +1 -1
  153. package/dist/components/CircularProgress/index.d.ts +2 -0
  154. package/dist/components/CircularProgress/index.d.ts.map +1 -0
  155. package/dist/components/CircularProgress/index.js +6 -0
  156. package/dist/components/CircularProgress/index.js.map +1 -0
  157. package/dist/components/Coachmark/coachmark-story-helpers.d.ts +22 -0
  158. package/dist/components/Coachmark/coachmark-story-helpers.d.ts.map +1 -0
  159. package/dist/components/Coachmark/coachmark.d.ts +15 -6
  160. package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
  161. package/dist/components/Coachmark/coachmark.js +12 -4
  162. package/dist/components/Coachmark/coachmark.js.map +1 -1
  163. package/dist/components/Coachmark/index.d.ts +2 -0
  164. package/dist/components/Coachmark/index.d.ts.map +1 -0
  165. package/dist/components/Coachmark/index.js +6 -0
  166. package/dist/components/Coachmark/index.js.map +1 -0
  167. package/dist/components/Combobox/combobox.d.ts +39 -15
  168. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  169. package/dist/components/Combobox/combobox.js +169 -65
  170. package/dist/components/Combobox/combobox.js.map +1 -1
  171. package/dist/components/Combobox/index.d.ts +2 -0
  172. package/dist/components/Combobox/index.d.ts.map +1 -0
  173. package/dist/components/Combobox/index.js +6 -0
  174. package/dist/components/Combobox/index.js.map +1 -0
  175. package/dist/components/Command/command.d.ts +7 -3
  176. package/dist/components/Command/command.d.ts.map +1 -1
  177. package/dist/components/Command/command.js +23 -10
  178. package/dist/components/Command/command.js.map +1 -1
  179. package/dist/components/Command/index.d.ts +2 -0
  180. package/dist/components/Command/index.d.ts.map +1 -0
  181. package/dist/components/Command/index.js +14 -0
  182. package/dist/components/Command/index.js.map +1 -0
  183. package/dist/components/DataTable/active-editor-controller.d.ts +4 -3
  184. package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -1
  185. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  186. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  187. package/dist/components/DataTable/cell-registry.js +89 -95
  188. package/dist/components/DataTable/cell-registry.js.map +1 -1
  189. package/dist/components/DataTable/column-types.d.ts +11 -21
  190. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  191. package/dist/components/DataTable/column-types.js.map +1 -1
  192. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +4 -3
  193. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  194. package/dist/components/DataTable/data-table-column-visibility-panel.js +193 -0
  195. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
  196. package/dist/components/DataTable/data-table-filter-group.d.ts +51 -0
  197. package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
  198. package/dist/components/DataTable/data-table-filter-group.js +159 -0
  199. package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
  200. package/dist/components/DataTable/data-table-filter-labels.d.ts +44 -0
  201. package/dist/components/DataTable/data-table-filter-labels.d.ts.map +1 -0
  202. package/dist/components/DataTable/data-table-filter-labels.js +55 -0
  203. package/dist/components/DataTable/data-table-filter-labels.js.map +1 -0
  204. package/dist/components/DataTable/data-table-filter-panel.d.ts +12 -3
  205. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  206. package/dist/components/DataTable/data-table-filter-panel.js +316 -0
  207. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  208. package/dist/components/DataTable/data-table-filter-value-picker.d.ts +32 -0
  209. package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
  210. package/dist/components/DataTable/data-table-filter-value-picker.js +205 -0
  211. package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
  212. package/dist/components/DataTable/data-table-interaction-layer.d.ts +17 -20
  213. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  214. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  215. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  216. package/dist/components/DataTable/data-table-sort-manager.d.ts +5 -5
  217. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
  218. package/dist/components/DataTable/data-table-sort-manager.js +150 -0
  219. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  220. package/dist/components/DataTable/data-table.d.ts +66 -15
  221. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  222. package/dist/components/DataTable/data-table.js +367 -185
  223. package/dist/components/DataTable/data-table.js.map +1 -1
  224. package/dist/components/DataTable/filter-operators.d.ts +1 -1
  225. package/dist/components/DataTable/filter-operators.js +140 -0
  226. package/dist/components/DataTable/filter-operators.js.map +1 -0
  227. package/dist/components/DataTable/filter-tree.d.ts +6 -1
  228. package/dist/components/DataTable/filter-tree.d.ts.map +1 -1
  229. package/dist/components/DataTable/filter-tree.js +318 -0
  230. package/dist/components/DataTable/filter-tree.js.map +1 -0
  231. package/dist/components/DataTable/index.d.ts +5 -0
  232. package/dist/components/DataTable/index.d.ts.map +1 -0
  233. package/dist/components/DataTable/index.js +21 -0
  234. package/dist/components/DataTable/index.js.map +1 -0
  235. package/dist/components/DataTable/lib/column-meta.js +25 -0
  236. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  237. package/dist/components/DateGrid/date-grid.d.ts +23 -19
  238. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  239. package/dist/components/DateGrid/date-grid.js +60 -12
  240. package/dist/components/DateGrid/date-grid.js.map +1 -1
  241. package/dist/components/DateGrid/index.d.ts +2 -0
  242. package/dist/components/DateGrid/index.d.ts.map +1 -0
  243. package/dist/components/DateGrid/index.js +6 -0
  244. package/dist/components/DateGrid/index.js.map +1 -0
  245. package/dist/components/DatePicker/date-picker.d.ts +12 -12
  246. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  247. package/dist/components/DatePicker/date-picker.js +418 -309
  248. package/dist/components/DatePicker/date-picker.js.map +1 -1
  249. package/dist/components/DatePicker/index.d.ts +2 -0
  250. package/dist/components/DatePicker/index.d.ts.map +1 -0
  251. package/dist/components/DatePicker/index.js +8 -0
  252. package/dist/components/DatePicker/index.js.map +1 -0
  253. package/dist/components/DescriptionList/description-list.d.ts +6 -6
  254. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  255. package/dist/components/DescriptionList/description-list.js +11 -10
  256. package/dist/components/DescriptionList/description-list.js.map +1 -1
  257. package/dist/components/DescriptionList/index.d.ts +2 -0
  258. package/dist/components/DescriptionList/index.d.ts.map +1 -0
  259. package/dist/components/DescriptionList/index.js +7 -0
  260. package/dist/components/DescriptionList/index.js.map +1 -0
  261. package/dist/components/Dialog/dialog.d.ts +22 -5
  262. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  263. package/dist/components/Dialog/dialog.js +44 -23
  264. package/dist/components/Dialog/dialog.js.map +1 -1
  265. package/dist/components/Dialog/index.d.ts +2 -0
  266. package/dist/components/Dialog/index.d.ts.map +1 -0
  267. package/dist/components/Dialog/index.js +16 -0
  268. package/dist/components/Dialog/index.js.map +1 -0
  269. package/dist/components/DropdownMenu/dropdown-menu.d.ts +19 -10
  270. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  271. package/dist/components/DropdownMenu/dropdown-menu.js +79 -28
  272. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  273. package/dist/components/DropdownMenu/index.d.ts +2 -0
  274. package/dist/components/DropdownMenu/index.d.ts.map +1 -0
  275. package/dist/components/DropdownMenu/index.js +21 -0
  276. package/dist/components/DropdownMenu/index.js.map +1 -0
  277. package/dist/components/Empty/empty.d.ts +14 -6
  278. package/dist/components/Empty/empty.d.ts.map +1 -1
  279. package/dist/components/Empty/empty.js +7 -7
  280. package/dist/components/Empty/empty.js.map +1 -1
  281. package/dist/components/Empty/index.d.ts +2 -0
  282. package/dist/components/Empty/index.d.ts.map +1 -0
  283. package/dist/components/Empty/index.js +6 -0
  284. package/dist/components/Empty/index.js.map +1 -0
  285. package/dist/components/Field/field-context.d.ts +111 -4
  286. package/dist/components/Field/field-context.d.ts.map +1 -1
  287. package/dist/components/Field/field-context.js +70 -0
  288. package/dist/components/Field/field-context.js.map +1 -1
  289. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  290. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  291. package/dist/components/Field/field-edit-keys.js +19 -0
  292. package/dist/components/Field/field-edit-keys.js.map +1 -0
  293. package/dist/components/Field/field-types.d.ts +22 -3
  294. package/dist/components/Field/field-types.d.ts.map +1 -1
  295. package/dist/components/Field/field-types.js.map +1 -1
  296. package/dist/components/Field/field-wrapper.d.ts +24 -6
  297. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  298. package/dist/components/Field/field-wrapper.js +98 -74
  299. package/dist/components/Field/field-wrapper.js.map +1 -1
  300. package/dist/components/Field/field.d.ts +7 -4
  301. package/dist/components/Field/field.d.ts.map +1 -1
  302. package/dist/components/Field/field.js +39 -6
  303. package/dist/components/Field/field.js.map +1 -1
  304. package/dist/components/Field/index.d.ts +3 -0
  305. package/dist/components/Field/index.d.ts.map +1 -0
  306. package/dist/components/Field/index.js +14 -0
  307. package/dist/components/Field/index.js.map +1 -0
  308. package/dist/components/Field/use-form-validation.d.ts +92 -0
  309. package/dist/components/Field/use-form-validation.d.ts.map +1 -0
  310. package/dist/components/Field/use-form-validation.js +137 -0
  311. package/dist/components/Field/use-form-validation.js.map +1 -0
  312. package/dist/components/FieldControlGroup/field-control-group.d.ts +8 -11
  313. package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -1
  314. package/dist/components/FieldControlGroup/field-control-group.js +2 -2
  315. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  316. package/dist/components/FieldControlGroup/index.d.ts +2 -0
  317. package/dist/components/FieldControlGroup/index.d.ts.map +1 -0
  318. package/dist/components/FieldControlGroup/index.js +6 -0
  319. package/dist/components/FieldControlGroup/index.js.map +1 -0
  320. package/dist/components/FileItem/file-item.d.ts +14 -2
  321. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  322. package/dist/components/FileItem/file-item.js +45 -16
  323. package/dist/components/FileItem/file-item.js.map +1 -1
  324. package/dist/components/FileItem/index.d.ts +2 -0
  325. package/dist/components/FileItem/index.d.ts.map +1 -0
  326. package/dist/components/FileItem/index.js +6 -0
  327. package/dist/components/FileItem/index.js.map +1 -0
  328. package/dist/components/FileUpload/file-upload.d.ts +39 -19
  329. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  330. package/dist/components/FileUpload/file-upload.js +102 -32
  331. package/dist/components/FileUpload/file-upload.js.map +1 -1
  332. package/dist/components/FileUpload/index.d.ts +2 -0
  333. package/dist/components/FileUpload/index.d.ts.map +1 -0
  334. package/dist/components/FileUpload/index.js +6 -0
  335. package/dist/components/FileUpload/index.js.map +1 -0
  336. package/dist/components/FileViewer/can-render-image.d.ts +6 -0
  337. package/dist/components/FileViewer/can-render-image.d.ts.map +1 -0
  338. package/dist/components/FileViewer/can-render-image.js +11 -0
  339. package/dist/components/FileViewer/can-render-image.js.map +1 -0
  340. package/dist/components/FileViewer/file-viewer.d.ts +4 -4
  341. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  342. package/dist/components/FileViewer/file-viewer.js +88 -50
  343. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  344. package/dist/components/FileViewer/image-renderer.d.ts +0 -5
  345. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  346. package/dist/components/FileViewer/image-renderer.js +23 -10
  347. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  348. package/dist/components/FileViewer/index.d.ts +2 -0
  349. package/dist/components/FileViewer/index.d.ts.map +1 -0
  350. package/dist/components/FileViewer/index.js +7 -0
  351. package/dist/components/FileViewer/index.js.map +1 -0
  352. package/dist/components/HoverCard/hover-card.d.ts +9 -5
  353. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  354. package/dist/components/HoverCard/hover-card.js +12 -5
  355. package/dist/components/HoverCard/hover-card.js.map +1 -1
  356. package/dist/components/HoverCard/index.d.ts +2 -0
  357. package/dist/components/HoverCard/index.d.ts.map +1 -0
  358. package/dist/components/HoverCard/index.js +8 -0
  359. package/dist/components/HoverCard/index.js.map +1 -0
  360. package/dist/components/InlineEdit/index.d.ts +2 -0
  361. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  362. package/dist/components/InlineEdit/index.js +6 -0
  363. package/dist/components/InlineEdit/index.js.map +1 -0
  364. package/dist/components/InlineEdit/inline-edit.d.ts +86 -0
  365. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  366. package/dist/components/InlineEdit/inline-edit.js +254 -0
  367. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  368. package/dist/components/Input/index.d.ts +2 -0
  369. package/dist/components/Input/index.d.ts.map +1 -0
  370. package/dist/components/Input/index.js +6 -0
  371. package/dist/components/Input/index.js.map +1 -0
  372. package/dist/components/Input/input.d.ts +31 -10
  373. package/dist/components/Input/input.d.ts.map +1 -1
  374. package/dist/components/Input/input.js +67 -30
  375. package/dist/components/Input/input.js.map +1 -1
  376. package/dist/components/LinkInput/index.d.ts +2 -0
  377. package/dist/components/LinkInput/index.d.ts.map +1 -0
  378. package/dist/components/LinkInput/index.js +6 -0
  379. package/dist/components/LinkInput/index.js.map +1 -0
  380. package/dist/components/LinkInput/link-input.d.ts +9 -9
  381. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  382. package/dist/components/LinkInput/link-input.js +40 -37
  383. package/dist/components/LinkInput/link-input.js.map +1 -1
  384. package/dist/components/Menu/index.d.ts +2 -0
  385. package/dist/components/Menu/index.d.ts.map +1 -0
  386. package/dist/components/Menu/index.js +9 -0
  387. package/dist/components/Menu/index.js.map +1 -0
  388. package/dist/components/Menu/menu-item.d.ts +20 -4
  389. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  390. package/dist/components/Menu/menu-item.js +37 -9
  391. package/dist/components/Menu/menu-item.js.map +1 -1
  392. package/dist/components/Notice/index.d.ts +2 -0
  393. package/dist/components/Notice/index.d.ts.map +1 -0
  394. package/dist/components/Notice/index.js +8 -0
  395. package/dist/components/Notice/index.js.map +1 -0
  396. package/dist/components/Notice/notice.d.ts +35 -7
  397. package/dist/components/Notice/notice.d.ts.map +1 -1
  398. package/dist/components/Notice/notice.js +34 -10
  399. package/dist/components/Notice/notice.js.map +1 -1
  400. package/dist/components/NumberInput/index.d.ts +2 -0
  401. package/dist/components/NumberInput/index.d.ts.map +1 -0
  402. package/dist/components/NumberInput/index.js +7 -0
  403. package/dist/components/NumberInput/index.js.map +1 -0
  404. package/dist/components/NumberInput/number-input.d.ts +5 -5
  405. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  406. package/dist/components/NumberInput/number-input.js +40 -18
  407. package/dist/components/NumberInput/number-input.js.map +1 -1
  408. package/dist/components/OverflowIndicator/index.d.ts +2 -0
  409. package/dist/components/OverflowIndicator/index.d.ts.map +1 -0
  410. package/dist/components/OverflowIndicator/index.js +6 -0
  411. package/dist/components/OverflowIndicator/index.js.map +1 -0
  412. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +6 -2
  413. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  414. package/dist/components/OverflowIndicator/overflow-indicator.js +11 -7
  415. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  416. package/dist/components/Pagination/index.d.ts +2 -0
  417. package/dist/components/Pagination/index.d.ts.map +1 -0
  418. package/dist/components/Pagination/index.js +6 -0
  419. package/dist/components/Pagination/index.js.map +1 -0
  420. package/dist/components/Pagination/pagination.d.ts +49 -0
  421. package/dist/components/Pagination/pagination.d.ts.map +1 -0
  422. package/dist/components/Pagination/pagination.js +182 -0
  423. package/dist/components/Pagination/pagination.js.map +1 -0
  424. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  425. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  426. package/dist/components/PeoplePicker/index.d.ts +2 -0
  427. package/dist/components/PeoplePicker/index.d.ts.map +1 -0
  428. package/dist/components/PeoplePicker/index.js +15 -0
  429. package/dist/components/PeoplePicker/index.js.map +1 -0
  430. package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -1
  431. package/dist/components/PeoplePicker/people-picker-helpers.js +2 -2
  432. package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -1
  433. package/dist/components/PeoplePicker/people-picker.d.ts +26 -10
  434. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  435. package/dist/components/PeoplePicker/people-picker.js +97 -65
  436. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  437. package/dist/components/PeoplePicker/person-display.d.ts +19 -11
  438. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  439. package/dist/components/PeoplePicker/person-display.js +39 -23
  440. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  441. package/dist/components/Popover/index.d.ts +2 -0
  442. package/dist/components/Popover/index.d.ts.map +1 -0
  443. package/dist/components/Popover/index.js +14 -0
  444. package/dist/components/Popover/index.js.map +1 -0
  445. package/dist/components/Popover/popover.d.ts +2 -2
  446. package/dist/components/Popover/popover.d.ts.map +1 -1
  447. package/dist/components/Popover/popover.js +72 -42
  448. package/dist/components/Popover/popover.js.map +1 -1
  449. package/dist/components/ProfileCard/index.d.ts +2 -0
  450. package/dist/components/ProfileCard/index.d.ts.map +1 -0
  451. package/dist/components/ProfileCard/index.js +8 -0
  452. package/dist/components/ProfileCard/index.js.map +1 -0
  453. package/dist/components/{NameCard/name-card.d.ts → ProfileCard/profile-card.d.ts} +34 -20
  454. package/dist/components/ProfileCard/profile-card.d.ts.map +1 -0
  455. package/dist/components/{NameCard/name-card.js → ProfileCard/profile-card.js} +27 -16
  456. package/dist/components/ProfileCard/profile-card.js.map +1 -0
  457. package/dist/components/ProgressBar/index.d.ts +2 -0
  458. package/dist/components/ProgressBar/index.d.ts.map +1 -0
  459. package/dist/components/ProgressBar/index.js +6 -0
  460. package/dist/components/ProgressBar/index.js.map +1 -0
  461. package/dist/components/ProgressBar/progress-bar.d.ts +2 -14
  462. package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -1
  463. package/dist/components/ProgressBar/progress-bar.js +5 -9
  464. package/dist/components/ProgressBar/progress-bar.js.map +1 -1
  465. package/dist/components/RadioGroup/index.d.ts +2 -0
  466. package/dist/components/RadioGroup/index.d.ts.map +1 -0
  467. package/dist/components/RadioGroup/index.js +8 -0
  468. package/dist/components/RadioGroup/index.js.map +1 -0
  469. package/dist/components/RadioGroup/radio-group.d.ts +18 -12
  470. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  471. package/dist/components/RadioGroup/radio-group.js +131 -40
  472. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  473. package/dist/components/Rating/index.d.ts +2 -0
  474. package/dist/components/Rating/index.d.ts.map +1 -0
  475. package/dist/components/Rating/index.js +6 -0
  476. package/dist/components/Rating/index.js.map +1 -0
  477. package/dist/components/Rating/rating.d.ts +6 -2
  478. package/dist/components/Rating/rating.d.ts.map +1 -1
  479. package/dist/components/Rating/rating.js +17 -10
  480. package/dist/components/Rating/rating.js.map +1 -1
  481. package/dist/components/ScrollArea/index.d.ts +2 -0
  482. package/dist/components/ScrollArea/index.d.ts.map +1 -0
  483. package/dist/components/ScrollArea/index.js +7 -0
  484. package/dist/components/ScrollArea/index.js.map +1 -0
  485. package/dist/components/ScrollArea/scroll-area.d.ts +16 -4
  486. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  487. package/dist/components/ScrollArea/scroll-area.js +9 -6
  488. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  489. package/dist/components/SegmentedControl/index.d.ts +2 -0
  490. package/dist/components/SegmentedControl/index.d.ts.map +1 -0
  491. package/dist/components/SegmentedControl/index.js +9 -0
  492. package/dist/components/SegmentedControl/index.js.map +1 -0
  493. package/dist/components/SegmentedControl/segmented-control.d.ts +8 -7
  494. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  495. package/dist/components/SegmentedControl/segmented-control.js +31 -20
  496. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  497. package/dist/components/Select/index.d.ts +2 -0
  498. package/dist/components/Select/index.d.ts.map +1 -0
  499. package/dist/components/Select/index.js +6 -0
  500. package/dist/components/Select/index.js.map +1 -0
  501. package/dist/components/Select/select.d.ts +70 -13
  502. package/dist/components/Select/select.d.ts.map +1 -1
  503. package/dist/components/Select/select.js +271 -83
  504. package/dist/components/Select/select.js.map +1 -1
  505. package/dist/components/SelectMenu/index.d.ts +2 -0
  506. package/dist/components/SelectMenu/index.d.ts.map +1 -0
  507. package/dist/components/SelectMenu/index.js +8 -0
  508. package/dist/components/SelectMenu/index.js.map +1 -0
  509. package/dist/components/SelectMenu/select-menu.d.ts +61 -10
  510. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  511. package/dist/components/SelectMenu/select-menu.js +216 -93
  512. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  513. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  514. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  515. package/dist/components/SelectionControl/boolean-value.js +23 -0
  516. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  517. package/dist/components/SelectionControl/index.d.ts +3 -0
  518. package/dist/components/SelectionControl/index.d.ts.map +1 -0
  519. package/dist/components/SelectionControl/index.js +9 -0
  520. package/dist/components/SelectionControl/index.js.map +1 -0
  521. package/dist/components/SelectionControl/selection-item.d.ts +5 -1
  522. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
  523. package/dist/components/SelectionControl/selection-item.js +3 -1
  524. package/dist/components/SelectionControl/selection-item.js.map +1 -1
  525. package/dist/components/Separator/index.d.ts +2 -0
  526. package/dist/components/Separator/index.d.ts.map +1 -0
  527. package/dist/components/Separator/index.js +6 -0
  528. package/dist/components/Separator/index.js.map +1 -0
  529. package/dist/components/Separator/separator.d.ts +2 -2
  530. package/dist/components/Separator/separator.js +4 -3
  531. package/dist/components/Separator/separator.js.map +1 -1
  532. package/dist/components/Sheet/index.d.ts +2 -0
  533. package/dist/components/Sheet/index.d.ts.map +1 -0
  534. package/dist/components/Sheet/index.js +18 -0
  535. package/dist/components/Sheet/index.js.map +1 -0
  536. package/dist/components/Sheet/sheet.d.ts +15 -8
  537. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  538. package/dist/components/Sheet/sheet.js +9 -5
  539. package/dist/components/Sheet/sheet.js.map +1 -1
  540. package/dist/components/Sidebar/index.d.ts +2 -0
  541. package/dist/components/Sidebar/index.d.ts.map +1 -0
  542. package/dist/components/Sidebar/index.js +24 -0
  543. package/dist/components/Sidebar/index.js.map +1 -0
  544. package/dist/components/Sidebar/sidebar.d.ts +17 -11
  545. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  546. package/dist/components/Sidebar/sidebar.js +78 -35
  547. package/dist/components/Sidebar/sidebar.js.map +1 -1
  548. package/dist/components/Skeleton/index.d.ts +2 -0
  549. package/dist/components/Skeleton/index.d.ts.map +1 -0
  550. package/dist/components/Skeleton/index.js +6 -0
  551. package/dist/components/Skeleton/index.js.map +1 -0
  552. package/dist/components/Skeleton/skeleton.d.ts +2 -2
  553. package/dist/components/Skeleton/skeleton.js +4 -3
  554. package/dist/components/Skeleton/skeleton.js.map +1 -1
  555. package/dist/components/Slider/index.d.ts +2 -0
  556. package/dist/components/Slider/index.d.ts.map +1 -0
  557. package/dist/components/Slider/index.js +7 -0
  558. package/dist/components/Slider/index.js.map +1 -0
  559. package/dist/components/Slider/slider.d.ts +7 -7
  560. package/dist/components/Slider/slider.d.ts.map +1 -1
  561. package/dist/components/Slider/slider.js +39 -17
  562. package/dist/components/Slider/slider.js.map +1 -1
  563. package/dist/components/Steps/index.d.ts +2 -0
  564. package/dist/components/Steps/index.d.ts.map +1 -0
  565. package/dist/components/Steps/index.js +12 -0
  566. package/dist/components/Steps/index.js.map +1 -0
  567. package/dist/components/Steps/steps.d.ts +8 -6
  568. package/dist/components/Steps/steps.d.ts.map +1 -1
  569. package/dist/components/Steps/steps.js +74 -32
  570. package/dist/components/Steps/steps.js.map +1 -1
  571. package/dist/components/Switch/index.d.ts +2 -0
  572. package/dist/components/Switch/index.d.ts.map +1 -0
  573. package/dist/components/Switch/index.js +7 -0
  574. package/dist/components/Switch/index.js.map +1 -0
  575. package/dist/components/Switch/switch.d.ts +20 -18
  576. package/dist/components/Switch/switch.d.ts.map +1 -1
  577. package/dist/components/Switch/switch.js +133 -26
  578. package/dist/components/Switch/switch.js.map +1 -1
  579. package/dist/components/Tabs/index.d.ts +2 -0
  580. package/dist/components/Tabs/index.d.ts.map +1 -0
  581. package/dist/components/Tabs/index.js +10 -0
  582. package/dist/components/Tabs/index.js.map +1 -0
  583. package/dist/components/Tabs/tabs-inline-action-geometry.d.ts +31 -0
  584. package/dist/components/Tabs/tabs-inline-action-geometry.d.ts.map +1 -0
  585. package/dist/components/Tabs/tabs-inline-action-geometry.js +43 -0
  586. package/dist/components/Tabs/tabs-inline-action-geometry.js.map +1 -0
  587. package/dist/components/Tabs/tabs.d.ts +14 -11
  588. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  589. package/dist/components/Tabs/tabs.js +184 -69
  590. package/dist/components/Tabs/tabs.js.map +1 -1
  591. package/dist/components/Tag/index.d.ts +2 -0
  592. package/dist/components/Tag/index.d.ts.map +1 -0
  593. package/dist/components/Tag/index.js +7 -0
  594. package/dist/components/Tag/index.js.map +1 -0
  595. package/dist/components/Tag/tag.d.ts +39 -23
  596. package/dist/components/Tag/tag.d.ts.map +1 -1
  597. package/dist/components/Tag/tag.js +71 -63
  598. package/dist/components/Tag/tag.js.map +1 -1
  599. package/dist/components/Textarea/index.d.ts +2 -0
  600. package/dist/components/Textarea/index.d.ts.map +1 -0
  601. package/dist/components/Textarea/index.js +7 -0
  602. package/dist/components/Textarea/index.js.map +1 -0
  603. package/dist/components/Textarea/textarea.d.ts +24 -17
  604. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  605. package/dist/components/Textarea/textarea.js +110 -72
  606. package/dist/components/Textarea/textarea.js.map +1 -1
  607. package/dist/components/TimePicker/index.d.ts +2 -0
  608. package/dist/components/TimePicker/index.d.ts.map +1 -0
  609. package/dist/components/TimePicker/index.js +6 -0
  610. package/dist/components/TimePicker/index.js.map +1 -0
  611. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  612. package/dist/components/TimePicker/time-columns.js +44 -36
  613. package/dist/components/TimePicker/time-columns.js.map +1 -1
  614. package/dist/components/TimePicker/time-picker.d.ts +8 -7
  615. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  616. package/dist/components/TimePicker/time-picker.js +71 -53
  617. package/dist/components/TimePicker/time-picker.js.map +1 -1
  618. package/dist/components/Toast/index.d.ts +2 -0
  619. package/dist/components/Toast/index.d.ts.map +1 -0
  620. package/dist/components/Toast/index.js +7 -0
  621. package/dist/components/Toast/index.js.map +1 -0
  622. package/dist/components/Toast/toast.d.ts +2 -2
  623. package/dist/components/Toast/toast.d.ts.map +1 -1
  624. package/dist/components/Toast/toast.js +82 -20
  625. package/dist/components/Toast/toast.js.map +1 -1
  626. package/dist/components/Tooltip/index.d.ts +2 -0
  627. package/dist/components/Tooltip/index.d.ts.map +1 -0
  628. package/dist/components/Tooltip/index.js +9 -0
  629. package/dist/components/Tooltip/index.js.map +1 -0
  630. package/dist/components/Tooltip/tooltip.d.ts +2 -2
  631. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  632. package/dist/components/Tooltip/tooltip.js +57 -25
  633. package/dist/components/Tooltip/tooltip.js.map +1 -1
  634. package/dist/components/TreeView/index.d.ts +2 -0
  635. package/dist/components/TreeView/index.d.ts.map +1 -0
  636. package/dist/components/TreeView/index.js +8 -0
  637. package/dist/components/TreeView/index.js.map +1 -0
  638. package/dist/components/TreeView/tree-view.d.ts +71 -14
  639. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  640. package/dist/components/TreeView/tree-view.js +313 -34
  641. package/dist/components/TreeView/tree-view.js.map +1 -1
  642. package/dist/hooks/use-controllable.d.ts.map +1 -1
  643. package/dist/hooks/use-controllable.js +4 -2
  644. package/dist/hooks/use-controllable.js.map +1 -1
  645. package/dist/hooks/use-is-touch-device.d.ts.map +1 -1
  646. package/dist/hooks/use-is-touch-device.js +3 -1
  647. package/dist/hooks/use-is-touch-device.js.map +1 -1
  648. package/dist/hooks/use-overflow-items.d.ts +10 -6
  649. package/dist/hooks/use-overflow-items.d.ts.map +1 -1
  650. package/dist/hooks/use-overflow-items.js.map +1 -1
  651. package/dist/hooks/use-truncated.d.ts +27 -0
  652. package/dist/hooks/use-truncated.d.ts.map +1 -0
  653. package/dist/hooks/use-truncated.js +57 -0
  654. package/dist/hooks/use-truncated.js.map +1 -0
  655. package/dist/{react-day-picker.css → index.css} +43 -0
  656. package/dist/index.d.ts +121 -67
  657. package/dist/index.d.ts.map +1 -1
  658. package/dist/index.js +140 -160
  659. package/dist/index.js.map +1 -1
  660. package/dist/lib/drag-visual.d.ts +2 -2
  661. package/dist/lib/drag-visual.js.map +1 -1
  662. package/dist/lib/utils.d.ts +1 -0
  663. package/dist/lib/utils.d.ts.map +1 -1
  664. package/dist/lib/utils.js +24 -2
  665. package/dist/lib/utils.js.map +1 -1
  666. package/dist/patterns/element-anatomy/index.d.ts +3 -0
  667. package/dist/patterns/element-anatomy/index.d.ts.map +1 -0
  668. package/dist/patterns/element-anatomy/index.js +22 -0
  669. package/dist/patterns/element-anatomy/index.js.map +1 -0
  670. package/dist/patterns/element-anatomy/item-anatomy.d.ts +32 -16
  671. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  672. package/dist/patterns/element-anatomy/item-anatomy.js +83 -35
  673. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  674. package/dist/patterns/element-anatomy/truncated-text.d.ts +27 -0
  675. package/dist/patterns/element-anatomy/truncated-text.d.ts.map +1 -0
  676. package/dist/patterns/element-anatomy/truncated-text.js +16 -0
  677. package/dist/patterns/element-anatomy/truncated-text.js.map +1 -0
  678. package/dist/patterns/header-canonical/chrome-header.d.ts +20 -4
  679. package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -1
  680. package/dist/patterns/header-canonical/chrome-header.js +4 -2
  681. package/dist/patterns/header-canonical/chrome-header.js.map +1 -1
  682. package/dist/patterns/header-canonical/index.d.ts +2 -0
  683. package/dist/patterns/header-canonical/index.d.ts.map +1 -0
  684. package/dist/patterns/header-canonical/index.js +6 -0
  685. package/dist/patterns/header-canonical/index.js.map +1 -0
  686. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +1 -1
  687. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
  688. package/dist/patterns/horizontal-overflow/index.d.ts +2 -0
  689. package/dist/patterns/horizontal-overflow/index.d.ts.map +1 -0
  690. package/dist/patterns/horizontal-overflow/index.js +14 -0
  691. package/dist/patterns/horizontal-overflow/index.js.map +1 -0
  692. package/dist/patterns/overlay-surface/index.d.ts +2 -0
  693. package/dist/patterns/overlay-surface/index.d.ts.map +1 -0
  694. package/dist/patterns/overlay-surface/index.js +8 -0
  695. package/dist/patterns/overlay-surface/index.js.map +1 -0
  696. package/dist/patterns/overlay-surface/overlay-surface.d.ts +12 -2
  697. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
  698. package/dist/patterns/overlay-surface/overlay-surface.js +6 -2
  699. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
  700. package/dist/patterns/resize-handle/index.d.ts +2 -0
  701. package/dist/patterns/resize-handle/index.d.ts.map +1 -0
  702. package/dist/patterns/resize-handle/index.js +5 -0
  703. package/dist/patterns/resize-handle/index.js.map +1 -0
  704. package/dist/patterns/resize-handle/resize-handle.d.ts +9 -11
  705. package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -1
  706. package/dist/patterns/resize-handle/resize-handle.js +3 -6
  707. package/dist/patterns/resize-handle/resize-handle.js.map +1 -1
  708. package/dist/story-governance/category-matrix.d.ts +35 -0
  709. package/dist/story-governance/category-matrix.d.ts.map +1 -0
  710. package/dist/tokens/categorical-color.d.ts +60 -0
  711. package/dist/tokens/categorical-color.d.ts.map +1 -0
  712. package/dist/tokens/categorical-color.js +125 -0
  713. package/dist/tokens/categorical-color.js.map +1 -0
  714. package/dist/tokens/motion/motion.d.ts +8 -7
  715. package/dist/tokens/motion/motion.d.ts.map +1 -1
  716. package/dist/tokens/motion/motion.js +6 -6
  717. package/dist/tokens/motion/motion.js.map +1 -1
  718. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  719. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  720. package/dist/tokens/motion/overlay-motion.js +9 -0
  721. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  722. package/dist/tokens/uiSize/icon-size.d.ts +3 -4
  723. package/dist/tokens/uiSize/icon-size.d.ts.map +1 -1
  724. package/dist/tokens/uiSize/icon-size.js +5 -0
  725. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  726. package/ds-canonical/adapters/claude/agents/README.md +58 -0
  727. package/ds-canonical/adapters/claude/agents/canonical-reviewer.md +14 -0
  728. package/ds-canonical/adapters/claude-root-instructions.md +24 -0
  729. package/ds-canonical/adapters/claude-settings-base.json +169 -0
  730. package/ds-canonical/commands/README.md +9 -14
  731. package/ds-canonical/fork/AGENTS.md +110 -0
  732. package/ds-canonical/fork/CLAUDE.md +54 -0
  733. package/ds-canonical/fork/codex/agents/skills/bug-fix-rhythm/SKILL.md +207 -0
  734. package/ds-canonical/fork/codex/agents/skills/code-quality-audit/SKILL.md +71 -0
  735. package/ds-canonical/fork/codex/agents/skills/delivery-handoff/SKILL.md +244 -0
  736. package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/flow-diagram.md +180 -0
  737. package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/handoff-template.md +177 -0
  738. package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  739. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +43 -0
  740. package/ds-canonical/fork/codex/agents/skills/independent-review/agents/openai.yaml +4 -0
  741. package/ds-canonical/fork/codex/agents/skills/independent-review/references/evidence-contract.md +23 -0
  742. package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +114 -0
  743. package/ds-canonical/fork/codex/agents/skills/product-ui-audit/SKILL.md +252 -0
  744. package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/audit-checks.md +250 -0
  745. package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/common-misuses.md +329 -0
  746. package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/report-template.md +163 -0
  747. package/ds-canonical/fork/codex/agents/skills/propose-options/SKILL.md +190 -0
  748. package/ds-canonical/fork/codex/agents/skills/prototype/SKILL.md +246 -0
  749. package/ds-canonical/fork/codex/agents/skills/prototype/references/audit-checks.md +39 -0
  750. package/ds-canonical/fork/codex/agents/skills/prototype/references/benchmark-sources.md +94 -0
  751. package/ds-canonical/fork/codex/agents/skills/prototype/references/checkpoints.md +200 -0
  752. package/ds-canonical/fork/codex/agents/skills/prototype/references/evaluation-matrix.md +142 -0
  753. package/ds-canonical/fork/codex/agents/skills/prototype/references/ooux-template.md +198 -0
  754. package/ds-canonical/fork/codex/agents/skills/prototype/references/proposal-template.md +230 -0
  755. package/ds-canonical/fork/codex/agents/skills/scan-similar-bugs/SKILL.md +203 -0
  756. package/ds-canonical/fork/codex/agents/skills/ux-audit/SKILL.md +135 -0
  757. package/ds-canonical/fork/codex/agents/skills/visual-audit/SKILL.md +258 -0
  758. package/ds-canonical/fork/codex/agents/skills/visual-audit/output/.gitkeep +0 -0
  759. package/ds-canonical/fork/codex/agents/skills/visual-audit/references/audit-architecture.md +101 -0
  760. package/ds-canonical/fork/codex/agents/skills/visual-audit/references/visual-checklist.md +297 -0
  761. package/ds-canonical/fork/codex/agents/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  762. package/ds-canonical/fork/codex/hooks.json +57 -0
  763. package/ds-canonical/fork/common/closed-tool-execution.mjs +1005 -0
  764. package/ds-canonical/fork/common/instruction.md +110 -0
  765. package/ds-canonical/fork/consumer/governance-check.mjs +3163 -0
  766. package/ds-canonical/fork/consumer/lib/closed-tool-execution.mjs +1005 -0
  767. package/ds-canonical/fork/consumer/lock.json +189 -0
  768. package/ds-canonical/fork/consumer/lock.schema.json +338 -0
  769. package/ds-canonical/fork/consumer/managed-files/0235cf6b3fd402a3717881dc205b5bf77aed7632e7d7d6f1811a40e3033bd816.blob +145 -0
  770. package/ds-canonical/fork/consumer/managed-files/145aab4b4fc470fc9ba7679b4a1d87d4f6a6d604940bd40f8d675c8af696498f.blob +53 -0
  771. package/ds-canonical/fork/consumer/managed-files/189e551431181e4a88783c02130d2787b801ef731c86e35bcde89a7313aa020e.blob +149 -0
  772. package/ds-canonical/fork/consumer/managed-files/24ad71c8613ddcf6fd23818cb3bb477a1fb6d83af4550b0bad43099813088686.blob +28 -0
  773. package/ds-canonical/fork/consumer/managed-files/2d1ef5617a5ce3c39ad9aae1c42af7d199f9270c0a0ccb490b63d62dbc6913db.blob +1005 -0
  774. package/ds-canonical/fork/consumer/managed-files/3625e02235cf166a50649a4d704cfb68fead69d0e168c481df013ebae9f6be25.blob +1412 -0
  775. package/ds-canonical/fork/consumer/managed-files/3ddedc67b464bdfe3dde9803a2d917920c96d633678b802eee638a44cd47366a.blob +8 -0
  776. package/ds-canonical/fork/consumer/managed-files/423729840acdd43c812f17c245b871716c6b60f76e4d3e94864d0e34a815bf8d.blob +348 -0
  777. package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +549 -0
  778. package/ds-canonical/fork/consumer/managed-files/475fba657eaeb8abd88f60635f3eadab27a9d0d3114ba4fffc65f43a2a0fe6e2.blob +124 -0
  779. package/ds-canonical/fork/consumer/managed-files/5aeda1df235815f40dd755951f2b868d4e02035653d4536a8dde209cdc75b493.blob +268 -0
  780. package/ds-canonical/fork/consumer/managed-files/61c6aca6d7f04bedbf556eaa9d3043681fe48cbe0e93a8ccb1d69a7c5e23fdcf.blob +113 -0
  781. package/ds-canonical/fork/consumer/managed-files/63061e05969667005020166ea2ae7df3c96663f7a928e7dd3eebc1471022df56.blob +2454 -0
  782. package/ds-canonical/fork/consumer/managed-files/65410b66e8799a560e07b71779c186fed2a0ef50575ac44745df7a0938a9c2b4.blob +321 -0
  783. package/ds-canonical/fork/consumer/managed-files/6b746628ac11fcccbe277ef6fea94cc2a7b90ea2822e83536eae80d5ee4b3fa5.blob +167 -0
  784. package/ds-canonical/fork/consumer/managed-files/76d485470d30ff014afacf7ce643763de9f4f956d9fc8128dbc1814774cf2e63.blob +671 -0
  785. package/ds-canonical/fork/consumer/managed-files/7937321877e5c34c27dae36c0d507d21cd42fa3f46a8f11a284b8b4a52b6faa4.blob +84 -0
  786. package/ds-canonical/fork/consumer/managed-files/794bb911ba8ebef58ab0d44a55b9968a19d2c62bcfb310b1ee3a84166f087f21.blob +924 -0
  787. package/ds-canonical/fork/consumer/managed-files/7ab15a8aeca39485d7b9b57234bbc4a69e0b9e70b4a851dfe10f6447127cee78.blob +51 -0
  788. package/ds-canonical/fork/consumer/managed-files/7b17835d0ceb17cdcdcaf930540a3e5d0943a34a747ac43c12ca8cd485c11581.blob +44 -0
  789. package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +900 -0
  790. package/ds-canonical/fork/consumer/managed-files/81037efa5b3b9f4a875704005fb268acdc9233bb901f44902e4e37e1da92b8e3.blob +46 -0
  791. package/ds-canonical/fork/consumer/managed-files/884721550b56308812b20917adac7a12f36fdb4ecda6b02460a7f5a219c0c966.blob +82 -0
  792. package/ds-canonical/fork/consumer/managed-files/91f414b9462ddc1e4be1d4c6ca4ac7a7340a6eec9e98ee109cbc049d3b354b6a.blob +36 -0
  793. package/ds-canonical/fork/consumer/managed-files/92e4828cdcb96ff0d01daa16f6885f24045a8e72820665650f2a1890dc3a446c.blob +121 -0
  794. package/ds-canonical/fork/consumer/managed-files/93a89f16f6717d1e4e4e27ec20ef916e3355c7aa890ca74cd9b12db30d8a899f.blob +36 -0
  795. package/ds-canonical/fork/consumer/managed-files/974521d6b8fe796ea4c58b3c78b0c2b8a1be262b97100d77aaf4cc9c7724bcab.blob +45 -0
  796. package/ds-canonical/fork/consumer/managed-files/9791c85388d2e2e2bd564e2550fadc3351c4c960a47ce838098afcba7544eb90.blob +973 -0
  797. package/ds-canonical/fork/consumer/managed-files/a448d2222133335c30e6fda5116e26a40db3283a19d62ccc0663c30d272262a7.blob +174 -0
  798. package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +2639 -0
  799. package/ds-canonical/fork/consumer/managed-files/bc44cabad181f766611dab6a8f52d81100afadd50ac59799015e8ba7bf46d9eb.blob +620 -0
  800. package/ds-canonical/fork/consumer/managed-files/c4aa767f11714467de0038a2149cf78074baddc17fc6a9e074b6aed7544c6f3c.blob +80 -0
  801. package/ds-canonical/fork/consumer/managed-files/c893e9b734b162f4c631fef871128c16a9ab565f796a0e76d7f320f821f220f5.blob +41 -0
  802. package/ds-canonical/fork/consumer/managed-files/cd9c61f8ff24fb9bcc3663e346e2cfa419cfb84e02aae18d3dc66dd192681696.blob +9 -0
  803. package/ds-canonical/fork/consumer/managed-files/da2ad2737315d25a5300905ddefd62f1695056a8a1af155c5b34170ad9923bce.blob +38 -0
  804. package/ds-canonical/fork/consumer/managed-files/e26057408661597aac4a57cdf7e30e2f9d0afb1b9a2dbbb692c3805cd9028ca5.blob +250 -0
  805. package/ds-canonical/fork/consumer/managed-files/e68ae1915965d8e17d4b2441c00c2b97fe062ea308ae8535c9eebb2fc16fa245.blob +20 -0
  806. package/ds-canonical/fork/consumer/managed-files/e71c65f45c6af7ce12b6b3c0d8028f185da5b719e2050c9b2a6b243d41ae4878.blob +182 -0
  807. package/ds-canonical/fork/consumer/managed-files/e813096d69c49812e40e00be9ac8fa14d77f0ec1f97ab4c45cb096b3bedd35de.blob +3 -0
  808. package/ds-canonical/fork/consumer/managed-files/e930ebca6fd8eeb30802aac0930efae7bcc44cc0996f24de07c11ca6a081fedf.blob +277 -0
  809. package/ds-canonical/fork/consumer/managed-files/ea94e914d5c8acb84ad7660e5bda0f01b6ccc8cf96b0f6b1ce048f8938d0f5b5.blob +47 -0
  810. package/ds-canonical/fork/consumer/managed-files/f4db6e616d5229aa7e700c6a3ace022cb9d90baae74e38ca65fce617f18e0d9b.blob +110 -0
  811. package/ds-canonical/fork/consumer/managed-files/faa128c26102415dc5345e68698efbbd28a395c35ee278dceae044cf430692b2.blob +11 -0
  812. package/ds-canonical/fork/governance.lock +1696 -0
  813. package/ds-canonical/fork/hooks/_log-fire.sh +143 -0
  814. package/ds-canonical/fork/hooks/block_prototype_imports.py +241 -0
  815. package/ds-canonical/fork/hooks/check_chrome_header_avatar_canonical.sh +106 -0
  816. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +731 -0
  817. package/ds-canonical/fork/hooks/check_consumer_code_quality.sh +173 -0
  818. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +219 -0
  819. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +57 -0
  820. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +213 -0
  821. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +376 -0
  822. package/ds-canonical/fork/hooks/check_fork_product_quality.sh +38 -0
  823. package/ds-canonical/fork/hooks/check_item_list_gap.sh +56 -0
  824. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +160 -0
  825. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +319 -0
  826. package/ds-canonical/fork/hooks/check_pattern_invariants.sh +339 -0
  827. package/ds-canonical/fork/hooks/check_sidebar_menu_button_implicit_wrap.sh +99 -0
  828. package/ds-canonical/fork/hooks/check_story_determinism.sh +39 -0
  829. package/ds-canonical/fork/hooks/check_story_invariants.sh +400 -0
  830. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +241 -0
  831. package/ds-canonical/fork/hooks/check_tailwind_wildcard_in_docs.sh +86 -0
  832. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +333 -0
  833. package/ds-canonical/fork/hooks/lib/_hook_integrity.sh +158 -0
  834. package/ds-canonical/fork/hooks/lib/_micro_geometry.sh +291 -0
  835. package/ds-canonical/fork/hooks/lib/_provider_paths.sh +162 -0
  836. package/ds-canonical/fork/launchers/approval-evidence.mjs +1286 -0
  837. package/ds-canonical/fork/launchers/authority-decision-evidence.mjs +413 -0
  838. package/ds-canonical/fork/launchers/canonical-order.mjs +8 -0
  839. package/ds-canonical/fork/launchers/fork-governance-dispatcher.sh +154 -0
  840. package/ds-canonical/fork/launchers/format-provider-hook-output.mjs +25 -0
  841. package/ds-canonical/fork/launchers/independent-review.mjs +490 -0
  842. package/ds-canonical/fork/launchers/inject_fork_governance_preamble.sh +99 -0
  843. package/ds-canonical/fork/launchers/normalize-provider-event.mjs +355 -0
  844. package/ds-canonical/fork/launchers/product-hook-dispatch-runtime.mjs +1067 -0
  845. package/ds-canonical/fork/launchers/provider-hook-normalization.mjs +1640 -0
  846. package/ds-canonical/fork/launchers/provider-hook-output-transport.mjs +540 -0
  847. package/ds-canonical/fork/launchers/settings-hooks.json +35 -0
  848. package/ds-canonical/fork/manifest.json +1984 -0
  849. package/ds-canonical/fork/providers/claude/hook-config.json +327 -0
  850. package/ds-canonical/fork/providers/claude/instruction.md +54 -0
  851. package/ds-canonical/fork/providers/claude/skills/bug-fix-rhythm/SKILL.md +207 -0
  852. package/ds-canonical/fork/providers/claude/skills/code-quality-audit/SKILL.md +71 -0
  853. package/ds-canonical/fork/providers/claude/skills/delivery-handoff/SKILL.md +244 -0
  854. package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/flow-diagram.md +180 -0
  855. package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/handoff-template.md +177 -0
  856. package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  857. package/ds-canonical/fork/providers/claude/skills/independent-review/SKILL.md +43 -0
  858. package/ds-canonical/fork/providers/claude/skills/independent-review/agents/openai.yaml +4 -0
  859. package/ds-canonical/fork/providers/claude/skills/independent-review/references/evidence-contract.md +23 -0
  860. package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +114 -0
  861. package/ds-canonical/fork/providers/claude/skills/product-ui-audit/SKILL.md +252 -0
  862. package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/audit-checks.md +250 -0
  863. package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/common-misuses.md +329 -0
  864. package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/report-template.md +163 -0
  865. package/ds-canonical/fork/providers/claude/skills/propose-options/SKILL.md +190 -0
  866. package/ds-canonical/fork/providers/claude/skills/prototype/SKILL.md +246 -0
  867. package/ds-canonical/fork/providers/claude/skills/prototype/references/audit-checks.md +39 -0
  868. package/ds-canonical/fork/providers/claude/skills/prototype/references/benchmark-sources.md +94 -0
  869. package/ds-canonical/fork/providers/claude/skills/prototype/references/checkpoints.md +200 -0
  870. package/ds-canonical/fork/providers/claude/skills/prototype/references/evaluation-matrix.md +142 -0
  871. package/ds-canonical/fork/providers/claude/skills/prototype/references/ooux-template.md +198 -0
  872. package/ds-canonical/fork/providers/claude/skills/prototype/references/proposal-template.md +230 -0
  873. package/ds-canonical/fork/providers/claude/skills/scan-similar-bugs/SKILL.md +203 -0
  874. package/ds-canonical/fork/providers/claude/skills/ux-audit/SKILL.md +135 -0
  875. package/ds-canonical/fork/providers/claude/skills/visual-audit/SKILL.md +258 -0
  876. package/ds-canonical/fork/providers/claude/skills/visual-audit/output/.gitkeep +0 -0
  877. package/ds-canonical/fork/providers/claude/skills/visual-audit/references/audit-architecture.md +101 -0
  878. package/ds-canonical/fork/providers/claude/skills/visual-audit/references/visual-checklist.md +297 -0
  879. package/ds-canonical/fork/providers/claude/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  880. package/ds-canonical/fork/providers/codex/hook-config.json +57 -0
  881. package/ds-canonical/fork/providers/codex/skills/bug-fix-rhythm/SKILL.md +207 -0
  882. package/ds-canonical/fork/providers/codex/skills/code-quality-audit/SKILL.md +71 -0
  883. package/ds-canonical/fork/providers/codex/skills/delivery-handoff/SKILL.md +244 -0
  884. package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/flow-diagram.md +180 -0
  885. package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/handoff-template.md +177 -0
  886. package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  887. package/ds-canonical/fork/providers/codex/skills/independent-review/SKILL.md +43 -0
  888. package/ds-canonical/fork/providers/codex/skills/independent-review/agents/openai.yaml +4 -0
  889. package/ds-canonical/fork/providers/codex/skills/independent-review/references/evidence-contract.md +23 -0
  890. package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +114 -0
  891. package/ds-canonical/fork/providers/codex/skills/product-ui-audit/SKILL.md +252 -0
  892. package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/audit-checks.md +250 -0
  893. package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/common-misuses.md +329 -0
  894. package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/report-template.md +163 -0
  895. package/ds-canonical/fork/providers/codex/skills/propose-options/SKILL.md +190 -0
  896. package/ds-canonical/fork/providers/codex/skills/prototype/SKILL.md +246 -0
  897. package/ds-canonical/fork/providers/codex/skills/prototype/references/audit-checks.md +39 -0
  898. package/ds-canonical/fork/providers/codex/skills/prototype/references/benchmark-sources.md +94 -0
  899. package/ds-canonical/fork/providers/codex/skills/prototype/references/checkpoints.md +200 -0
  900. package/ds-canonical/fork/providers/codex/skills/prototype/references/evaluation-matrix.md +142 -0
  901. package/ds-canonical/fork/providers/codex/skills/prototype/references/ooux-template.md +198 -0
  902. package/ds-canonical/fork/providers/codex/skills/prototype/references/proposal-template.md +230 -0
  903. package/ds-canonical/fork/providers/codex/skills/scan-similar-bugs/SKILL.md +203 -0
  904. package/ds-canonical/fork/providers/codex/skills/ux-audit/SKILL.md +135 -0
  905. package/ds-canonical/fork/providers/codex/skills/visual-audit/SKILL.md +258 -0
  906. package/ds-canonical/fork/providers/codex/skills/visual-audit/output/.gitkeep +0 -0
  907. package/ds-canonical/fork/providers/codex/skills/visual-audit/references/audit-architecture.md +101 -0
  908. package/ds-canonical/fork/providers/codex/skills/visual-audit/references/visual-checklist.md +297 -0
  909. package/ds-canonical/fork/providers/codex/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  910. package/ds-canonical/fork/references/story-baseline-registry.json +123 -0
  911. package/ds-canonical/fork/references/story-baseline-registry.schema.json +145 -0
  912. package/ds-canonical/fork/references/utility-registry.json +426 -0
  913. package/ds-canonical/fork/references/utility-registry.schema.json +409 -0
  914. package/ds-canonical/fork/review/canonical-order.mjs +8 -0
  915. package/ds-canonical/fork/review/provider-review-binding.mjs +2377 -0
  916. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +196 -0
  917. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +69 -0
  918. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +242 -0
  919. package/ds-canonical/fork/skills/delivery-handoff/references/flow-diagram.md +180 -0
  920. package/ds-canonical/fork/skills/delivery-handoff/references/handoff-template.md +177 -0
  921. package/ds-canonical/fork/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  922. package/ds-canonical/fork/skills/independent-review/SKILL.md +37 -0
  923. package/ds-canonical/fork/skills/independent-review/agents/openai.yaml +4 -0
  924. package/ds-canonical/fork/skills/independent-review/references/evidence-contract.md +23 -0
  925. package/ds-canonical/fork/skills/performance-audit/SKILL.md +112 -0
  926. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +250 -0
  927. package/ds-canonical/fork/skills/product-ui-audit/references/audit-checks.md +250 -0
  928. package/ds-canonical/fork/skills/product-ui-audit/references/common-misuses.md +329 -0
  929. package/ds-canonical/fork/skills/product-ui-audit/references/report-template.md +163 -0
  930. package/ds-canonical/fork/skills/propose-options/SKILL.md +179 -0
  931. package/ds-canonical/fork/skills/prototype/SKILL.md +244 -0
  932. package/ds-canonical/fork/skills/prototype/references/audit-checks.md +39 -0
  933. package/ds-canonical/fork/skills/prototype/references/benchmark-sources.md +94 -0
  934. package/ds-canonical/fork/skills/prototype/references/checkpoints.md +200 -0
  935. package/ds-canonical/fork/skills/prototype/references/evaluation-matrix.md +142 -0
  936. package/ds-canonical/fork/skills/prototype/references/ooux-template.md +198 -0
  937. package/ds-canonical/fork/skills/prototype/references/proposal-template.md +230 -0
  938. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +201 -0
  939. package/ds-canonical/fork/skills/ux-audit/SKILL.md +133 -0
  940. package/ds-canonical/fork/skills/visual-audit/SKILL.md +248 -0
  941. package/ds-canonical/fork/skills/visual-audit/output/.gitkeep +0 -0
  942. package/ds-canonical/fork/skills/visual-audit/references/audit-architecture.md +101 -0
  943. package/ds-canonical/fork/skills/visual-audit/references/visual-checklist.md +297 -0
  944. package/ds-canonical/fork/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  945. package/ds-canonical/hooks/README.md +39 -25
  946. package/ds-canonical/hooks/_log-fire.sh +111 -12
  947. package/ds-canonical/hooks/auto_regen_ds_barrel.sh +90 -0
  948. package/ds-canonical/hooks/block_prototype_imports.py +156 -26
  949. package/ds-canonical/hooks/check_audit_post_report_validator.sh +328 -32
  950. package/ds-canonical/hooks/check_audit_sample_escape.sh +10 -7
  951. package/ds-canonical/hooks/check_benchmark_citation.sh +41 -8
  952. package/ds-canonical/hooks/check_canonical_propagation.sh +85 -24
  953. package/ds-canonical/hooks/check_chrome_header_avatar_canonical.sh +106 -0
  954. package/ds-canonical/hooks/check_codex_brief_invariants.sh +138 -29
  955. package/ds-canonical/hooks/check_codex_collab_5step.sh +31 -25
  956. package/ds-canonical/hooks/check_consumer_app_invariants.sh +731 -0
  957. package/ds-canonical/hooks/check_consumer_code_quality.sh +173 -0
  958. package/ds-canonical/hooks/check_datatable_invariants.sh +173 -29
  959. package/ds-canonical/hooks/check_dim_count_drift.sh +8 -7
  960. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +219 -0
  961. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +57 -0
  962. package/ds-canonical/hooks/check_escape_marker_abuse.sh +213 -0
  963. package/ds-canonical/hooks/check_field_controls_contracts.sh +37 -8
  964. package/ds-canonical/hooks/check_field_family_invariants.sh +195 -24
  965. package/ds-canonical/hooks/check_file_size_budget.sh +32 -14
  966. package/ds-canonical/hooks/check_full_story_visual_interaction_sweep.sh +111 -0
  967. package/ds-canonical/hooks/check_item_list_gap.sh +56 -0
  968. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +160 -0
  969. package/ds-canonical/hooks/check_main_branch_workbench.sh +27 -68
  970. package/ds-canonical/hooks/check_naming_and_abstraction.sh +21 -10
  971. package/ds-canonical/hooks/check_opacity_token_usage.sh +238 -68
  972. package/ds-canonical/hooks/check_orphan_ds_css.sh +96 -0
  973. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +110 -0
  974. package/ds-canonical/hooks/check_pattern_invariants.sh +160 -15
  975. package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +4 -4
  976. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +6 -4
  977. package/ds-canonical/hooks/check_plugin_fork_health.sh +282 -0
  978. package/ds-canonical/hooks/check_propose_discipline.sh +255 -0
  979. package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +6 -4
  980. package/ds-canonical/hooks/check_propose_without_benchmark.sh +71 -0
  981. package/ds-canonical/hooks/check_select_all_canonical.sh +1 -1
  982. package/ds-canonical/hooks/check_sidebar_menu_button_implicit_wrap.sh +99 -0
  983. package/ds-canonical/hooks/check_solo_workflow.sh +62 -168
  984. package/ds-canonical/hooks/check_spec_class_drift.sh +33 -19
  985. package/ds-canonical/hooks/check_ssot_header_declaration.sh +56 -0
  986. package/ds-canonical/hooks/check_story_determinism.sh +39 -0
  987. package/ds-canonical/hooks/check_story_invariants.sh +722 -222
  988. package/ds-canonical/hooks/check_storybook_addon_packaging.sh +201 -0
  989. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +143 -64
  990. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +241 -0
  991. package/ds-canonical/hooks/check_tailwind_wildcard_in_docs.sh +86 -0
  992. package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +15 -12
  993. package/ds-canonical/hooks/chrome_header_dispatcher.sh +105 -0
  994. package/ds-canonical/hooks/enforce_home_charter.sh +31 -10
  995. package/ds-canonical/hooks/governance_control_plane.sh +15 -0
  996. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +333 -0
  997. package/ds-canonical/hooks/inject_pending_self_audit.sh +68 -21
  998. package/ds-canonical/hooks/lib/_app_shell_primary_header_consistency.sh +148 -0
  999. package/ds-canonical/hooks/lib/_chrome_header_handcraft.sh +121 -0
  1000. package/ds-canonical/hooks/lib/_code_quality.sh +9 -9
  1001. package/ds-canonical/hooks/lib/_cva_default_sync.sh +11 -13
  1002. package/ds-canonical/hooks/lib/_governance_coverage_check.sh +48 -21
  1003. package/ds-canonical/hooks/lib/_hardcoded_strings.sh +18 -10
  1004. package/ds-canonical/hooks/lib/_header_with_tabs_border.sh +107 -0
  1005. package/ds-canonical/hooks/lib/_hook_integrity.sh +158 -0
  1006. package/ds-canonical/hooks/lib/_layout_space_canonical.sh +5 -5
  1007. package/ds-canonical/hooks/lib/_micro_geometry.sh +291 -0
  1008. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +42 -23
  1009. package/ds-canonical/hooks/lib/_person_data_richness.sh +5 -5
  1010. package/ds-canonical/hooks/lib/_provider_paths.sh +162 -0
  1011. package/ds-canonical/hooks/lib/_story_compile_drift.sh +5 -5
  1012. package/ds-canonical/hooks/lib/_tab_lg_chrome_header_equal.sh +290 -0
  1013. package/ds-canonical/hooks/lib/_token_hygiene.sh +55 -20
  1014. package/ds-canonical/hooks/lib/approval-evidence.mjs +1286 -0
  1015. package/ds-canonical/hooks/lib/audit-report-validator.mjs +122 -0
  1016. package/ds-canonical/hooks/lib/provider-marker-regex.mjs +23 -0
  1017. package/ds-canonical/hooks/lib/tsx-governance-analysis.mjs +410 -0
  1018. package/ds-canonical/hooks/log_governance_fires.sh +45 -13
  1019. package/ds-canonical/hooks/log_skill_invokes.sh +8 -7
  1020. package/ds-canonical/hooks/post_edit_dispatcher.sh +106 -28
  1021. package/ds-canonical/hooks/registrations.json +488 -0
  1022. package/ds-canonical/hooks/registrations.schema.json +58 -0
  1023. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_addon_subdir_ship.sh +76 -0
  1024. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_app_story_title.sh +81 -0
  1025. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_ds_primitive_misuse.sh +120 -0
  1026. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_no_ds_catalog.sh +101 -0
  1027. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_story_baseline.sh +76 -0
  1028. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_data_table_size_num_to_meta_width.sh +68 -0
  1029. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_fork_user_plugin_install.sh +79 -0
  1030. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_plugin_freshness.sh +68 -0
  1031. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_propose_cite_required.sh +88 -0
  1032. package/ds-canonical/hooks/{check_propose_plain_chinese.sh → retired/2026-06-11-prune-merge/check_propose_plain_chinese.sh} +2 -2
  1033. package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_storybook_addon_preset_cjs.sh +87 -0
  1034. package/ds-canonical/hooks/{lib/_approval_re.sh → retired/_approval_re.sh.retired-2026-08-18} +6 -7
  1035. package/ds-canonical/hooks/retired/check_container_breathing.sh +1 -1
  1036. package/ds-canonical/hooks/retired/check_governance_compliance.sh +1 -1
  1037. package/ds-canonical/hooks/session_start_governance_check.sh +157 -69
  1038. package/ds-canonical/hooks/stop_audit_content_quality.sh +20 -0
  1039. package/ds-canonical/hooks/stop_extract_canonical_rules.sh +20 -0
  1040. package/ds-canonical/hooks/stop_passive_logging.sh +133 -59
  1041. package/ds-canonical/hooks/stop_self_audit.sh +472 -178
  1042. package/ds-canonical/hooks/tests/fixtures/transcripts/claude-transcript-jsonl-v1.jsonl +3 -0
  1043. package/ds-canonical/hooks/tests/fixtures/transcripts/claude-transcript-jsonl-v2.jsonl +3 -0
  1044. package/ds-canonical/hooks/tests/registration-output-contracts.mjs +151 -0
  1045. package/ds-canonical/hooks/tests/run-all.sh +35 -5
  1046. package/ds-canonical/hooks/tests/test_auto_regen_ds_barrel.sh +224 -0
  1047. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +181 -9
  1048. package/ds-canonical/hooks/tests/test_check_addon_subdir_ship.sh +171 -0
  1049. package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +275 -81
  1050. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +292 -14
  1051. package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +0 -0
  1052. package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +41 -9
  1053. package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +56 -5
  1054. package/ds-canonical/hooks/tests/test_check_chrome_header_avatar_canonical.sh +198 -0
  1055. package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +197 -81
  1056. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +375 -0
  1057. package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +49 -5
  1058. package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +140 -0
  1059. package/ds-canonical/hooks/tests/test_check_consumer_app_story_title.sh +164 -0
  1060. package/ds-canonical/hooks/tests/test_check_consumer_code_quality.sh +86 -0
  1061. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +417 -0
  1062. package/ds-canonical/hooks/tests/test_check_consumer_no_ds_catalog.sh +214 -0
  1063. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +209 -0
  1064. package/ds-canonical/hooks/tests/test_check_data_table_size_num_to_meta_width.sh +71 -0
  1065. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +126 -12
  1066. package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +13 -8
  1067. package/ds-canonical/hooks/tests/test_check_ds_anchor_preflight.sh +150 -0
  1068. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  1069. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +278 -0
  1070. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +108 -18
  1071. package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +67 -5
  1072. package/ds-canonical/hooks/tests/test_check_fork_user_plugin_install.sh +151 -0
  1073. package/ds-canonical/hooks/tests/test_check_full_story_visual_interaction_sweep.sh +200 -0
  1074. package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +178 -68
  1075. package/ds-canonical/hooks/tests/test_check_item_list_gap.sh +44 -0
  1076. package/ds-canonical/hooks/tests/test_check_layout_space_magic_numbers.sh +264 -0
  1077. package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +45 -110
  1078. package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +19 -2
  1079. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +151 -6
  1080. package/ds-canonical/hooks/tests/test_check_orphan_ds_css.sh +228 -0
  1081. package/ds-canonical/hooks/tests/test_check_overlay_open_focus_escape_probe.sh +191 -0
  1082. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +103 -7
  1083. package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +132 -0
  1084. package/ds-canonical/hooks/tests/test_check_propose_cite_required.sh +181 -0
  1085. package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +69 -0
  1086. package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +10 -7
  1087. package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +5 -5
  1088. package/ds-canonical/hooks/tests/test_check_propose_without_benchmark.sh +100 -0
  1089. package/ds-canonical/hooks/tests/test_check_sidebar_menu_button_implicit_wrap.sh +224 -0
  1090. package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +86 -105
  1091. package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +35 -7
  1092. package/ds-canonical/hooks/tests/test_check_ssot_header_declaration.sh +72 -0
  1093. package/ds-canonical/hooks/tests/{test_check_story_anatomy.sh.broken → test_check_story_anatomy.sh} +73 -4
  1094. package/ds-canonical/hooks/tests/test_check_story_category.sh +411 -0
  1095. package/ds-canonical/hooks/tests/test_check_story_determinism.sh +39 -0
  1096. package/ds-canonical/hooks/tests/test_check_story_invariants.sh +734 -43
  1097. package/ds-canonical/hooks/tests/{test_check_story_name_jargon.sh.broken → test_check_story_name_jargon.sh} +22 -1
  1098. package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +89 -0
  1099. package/ds-canonical/hooks/tests/test_check_storybook_addon_preset_cjs.sh +200 -0
  1100. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +626 -28
  1101. package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +182 -97
  1102. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  1103. package/ds-canonical/hooks/tests/test_check_tailwind_wildcard_in_docs.sh +182 -0
  1104. package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +63 -15
  1105. package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +12 -6
  1106. package/ds-canonical/hooks/tests/test_chrome_header_dispatcher.sh +125 -0
  1107. package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +58 -4
  1108. package/ds-canonical/hooks/tests/test_governance_control_plane.sh +66 -0
  1109. package/ds-canonical/hooks/tests/test_governance_coverage_check.sh +88 -0
  1110. package/ds-canonical/hooks/tests/test_hook_integrity_classification.sh +217 -0
  1111. package/ds-canonical/hooks/tests/test_inject_deploy_url_after_push.sh +276 -0
  1112. package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +116 -11
  1113. package/ds-canonical/hooks/tests/test_log_governance_fires.sh +117 -1
  1114. package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +74 -5
  1115. package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +234 -77
  1116. package/ds-canonical/hooks/tests/test_provider_peer_symmetry.sh +76 -0
  1117. package/ds-canonical/hooks/tests/test_registration_output_contracts.sh +20 -0
  1118. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +145 -22
  1119. package/ds-canonical/hooks/tests/test_stop_audit_content_quality.sh +75 -0
  1120. package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +101 -23
  1121. package/ds-canonical/hooks/tests/test_stop_extract_canonical_rules.sh +75 -0
  1122. package/ds-canonical/hooks/tests/{test_stop_governance_drift_check.sh.broken → test_stop_governance_drift_check.sh} +22 -12
  1123. package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +102 -1
  1124. package/ds-canonical/hooks/tests/test_stop_repository_command_context.sh +38 -0
  1125. package/ds-canonical/hooks/tests/test_stop_self_audit.sh +427 -13
  1126. package/ds-canonical/references/README.md +19 -11
  1127. package/ds-canonical/references/build-ui-canonicals.md +23 -6
  1128. package/ds-canonical/references/certified-surfaces.md +46 -0
  1129. package/ds-canonical/references/composition-fidelity.md +47 -0
  1130. package/ds-canonical/references/cva-patterns.md +2 -2
  1131. package/ds-canonical/references/drag-canonical.md +67 -311
  1132. package/ds-canonical/references/failure-class-registry.json +160 -0
  1133. package/ds-canonical/references/governance-audit-coverage.md +34 -0
  1134. package/ds-canonical/references/item-anatomy-recipe.md +3 -3
  1135. package/ds-canonical/references/naming-conventions.md +2 -1
  1136. package/ds-canonical/references/principle-dim-map.json +136 -9
  1137. package/ds-canonical/references/props-naming.md +18 -3
  1138. package/ds-canonical/references/repository-hygiene-policy.json +143 -0
  1139. package/ds-canonical/references/repository-hygiene.md +106 -0
  1140. package/ds-canonical/references/runtime-evidence-retention.md +88 -0
  1141. package/ds-canonical/references/scenario-definition.md +146 -0
  1142. package/ds-canonical/references/spec-rules.md +1 -1
  1143. package/ds-canonical/references/ssot-consultation.md +5 -5
  1144. package/ds-canonical/references/ssot-index.md +11 -10
  1145. package/ds-canonical/references/story-baseline-registry.json +55 -11
  1146. package/ds-canonical/references/story-baseline-registry.schema.json +145 -0
  1147. package/ds-canonical/references/structural-token-retention.md +7 -10
  1148. package/ds-canonical/references/tailwind-gotchas.md +4 -4
  1149. package/ds-canonical/references/ui-dev-rules.md +22 -1
  1150. package/ds-canonical/rules/README.md +15 -10
  1151. package/ds-canonical/rules/meta-patterns.md +30 -30
  1152. package/ds-canonical/rules/self-verify.md +22 -12
  1153. package/ds-canonical/rules/spec-rules.md +2 -2
  1154. package/ds-canonical/rules/story-rules.md +36 -9
  1155. package/ds-canonical/rules/ui-development.md +23 -15
  1156. package/ds-canonical/skills/README.md +29 -17
  1157. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +26 -13
  1158. package/ds-canonical/skills/canonical-reviewer/SKILL.md +29 -0
  1159. package/ds-canonical/skills/code-quality-audit/SKILL.md +15 -11
  1160. package/ds-canonical/skills/codex-collab/SKILL.md +22 -235
  1161. package/ds-canonical/skills/codex-collab/references/brief-template.md +37 -43
  1162. package/ds-canonical/skills/codex-collab/references/transport.md +38 -57
  1163. package/ds-canonical/skills/codify-corrections/SKILL.md +37 -36
  1164. package/ds-canonical/skills/codify-principle/SKILL.md +35 -34
  1165. package/ds-canonical/skills/component-quality-gate/SKILL.md +17 -17
  1166. package/ds-canonical/skills/component-quality-gate/references/checklist.md +8 -8
  1167. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +47 -224
  1168. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +36 -102
  1169. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +33 -147
  1170. package/ds-canonical/skills/deep-audit-cross-codex/references/skill-relationships-antipatterns-benchmarks.md +28 -0
  1171. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +15 -80
  1172. package/ds-canonical/skills/deep-audit-cross-codex/references/upstream-directives-r-mapping.md +34 -0
  1173. package/ds-canonical/skills/delivery-handoff/SKILL.md +19 -8
  1174. package/ds-canonical/skills/design-system-audit/SKILL.md +130 -76
  1175. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +207 -105
  1176. package/ds-canonical/skills/design-system-audit/references/checkpoints.md +59 -50
  1177. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +33 -9
  1178. package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +51 -32
  1179. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +57 -53
  1180. package/ds-canonical/skills/ensure-canonical/SKILL.md +37 -35
  1181. package/ds-canonical/skills/governance-health/SKILL.md +31 -25
  1182. package/ds-canonical/skills/governance-status/SKILL.md +30 -0
  1183. package/ds-canonical/skills/independent-review/SKILL.md +37 -0
  1184. package/ds-canonical/skills/independent-review/agents/openai.yaml +4 -0
  1185. package/ds-canonical/skills/independent-review/references/evidence-contract.md +23 -0
  1186. package/ds-canonical/skills/knowledge-prune/SKILL.md +57 -114
  1187. package/ds-canonical/skills/knowledge-prune/references/phase-z-cross-repo-ssot-propagation.md +15 -0
  1188. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +57 -0
  1189. package/ds-canonical/skills/knowledge-prune/references/world-class-prune-alignment.md +7 -0
  1190. package/ds-canonical/skills/new-component/SKILL.md +33 -25
  1191. package/ds-canonical/skills/new-component/references/new-component-checklist.md +12 -11
  1192. package/ds-canonical/skills/performance-audit/SKILL.md +15 -12
  1193. package/ds-canonical/skills/product-ui-audit/SKILL.md +52 -34
  1194. package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +10 -7
  1195. package/ds-canonical/skills/product-ui-audit/references/report-template.md +30 -26
  1196. package/ds-canonical/skills/propose-options/SKILL.md +23 -23
  1197. package/ds-canonical/skills/prototype/SKILL.md +19 -21
  1198. package/ds-canonical/skills/prototype/references/audit-checks.md +6 -5
  1199. package/ds-canonical/skills/prototype/references/checkpoints.md +26 -17
  1200. package/ds-canonical/skills/prototype/references/evaluation-matrix.md +2 -2
  1201. package/ds-canonical/skills/prototype/references/ooux-template.md +1 -1
  1202. package/ds-canonical/skills/prototype/references/proposal-template.md +5 -5
  1203. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +29 -28
  1204. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +26 -25
  1205. package/ds-canonical/skills/story-writing/SKILL.md +25 -14
  1206. package/ds-canonical/skills/story-writing/references/anatomy-standard.md +2 -2
  1207. package/ds-canonical/skills/story-writing/references/category-templates.md +15 -15
  1208. package/ds-canonical/skills/ux-audit/SKILL.md +13 -10
  1209. package/ds-canonical/skills/visual-audit/SKILL.md +47 -46
  1210. package/ds-canonical/skills/visual-audit/references/audit-architecture.md +7 -7
  1211. package/ds-canonical/skills/visual-audit/references/visual-checklist.md +14 -14
  1212. package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +3 -3
  1213. package/ds-canonical/templates/_README.md +22 -0
  1214. package/ds-canonical/templates/consumer-governance.md +82 -0
  1215. package/ds-canonical/templates/dashboard-app.tsx +186 -0
  1216. package/ds-canonical/templates/product-launchers/fork-governance-dispatcher.sh +154 -0
  1217. package/ds-canonical/templates/product-launchers/format-provider-hook-output.mjs +25 -0
  1218. package/ds-canonical/templates/product-launchers/independent-review.mjs +490 -0
  1219. package/ds-canonical/templates/product-launchers/inject_fork_governance_preamble.sh +99 -0
  1220. package/ds-canonical/templates/product-launchers/normalize-provider-event.mjs +355 -0
  1221. package/ds-canonical/templates/product-launchers/product-hook-dispatch-runtime.mjs +1067 -0
  1222. package/ds-canonical/templates/product-provider-wiring.json +82 -0
  1223. package/ds-canonical/templates/product-provider-wiring.schema.json +153 -0
  1224. package/ds-story-manifest.json +1786 -0
  1225. package/llms-full.txt +450 -0
  1226. package/llms.txt +74 -0
  1227. package/package.json +43 -10
  1228. package/src/README.md +1 -1
  1229. package/src/components/Accordion/accordion.anatomy.stories.tsx +496 -0
  1230. package/src/components/Accordion/accordion.principles.stories.tsx +365 -0
  1231. package/src/components/Accordion/accordion.spec.md +31 -5
  1232. package/src/components/Accordion/accordion.stories.tsx +192 -0
  1233. package/src/components/Accordion/accordion.tsx +13 -5
  1234. package/src/components/Accordion/index.ts +5 -0
  1235. package/src/components/AccountMenu/account-menu.anatomy.stories.tsx +117 -0
  1236. package/src/components/AccountMenu/account-menu.principles.stories.tsx +99 -0
  1237. package/src/components/AccountMenu/account-menu.spec.md +127 -0
  1238. package/src/components/AccountMenu/account-menu.stories.tsx +65 -0
  1239. package/src/components/AccountMenu/account-menu.tsx +194 -0
  1240. package/src/components/AccountMenu/index.ts +5 -0
  1241. package/src/components/AgentPanel/agent-fab.tsx +111 -0
  1242. package/src/components/AgentPanel/agent-logo.tsx +417 -0
  1243. package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +124 -0
  1244. package/src/components/AgentPanel/agent-panel.css +43 -0
  1245. package/src/components/AgentPanel/agent-panel.principles.stories.tsx +40 -0
  1246. package/src/components/AgentPanel/agent-panel.spec.md +226 -0
  1247. package/src/components/AgentPanel/agent-panel.stories.tsx +215 -0
  1248. package/src/components/AgentPanel/agent-panel.tsx +0 -0
  1249. package/src/components/AgentPanel/index.ts +5 -0
  1250. package/src/components/Alert/alert.anatomy.stories.tsx +241 -0
  1251. package/src/components/Alert/alert.principles.stories.tsx +214 -0
  1252. package/src/components/Alert/alert.spec.md +28 -26
  1253. package/src/components/Alert/alert.stories.tsx +136 -0
  1254. package/src/components/Alert/alert.tsx +19 -8
  1255. package/src/components/Alert/index.ts +5 -0
  1256. package/src/components/AppShell/_demo-helpers.tsx +107 -28
  1257. package/src/components/AppShell/app-shell.anatomy.stories.tsx +185 -0
  1258. package/src/components/AppShell/app-shell.principles.stories.tsx +140 -0
  1259. package/src/components/AppShell/app-shell.spec.md +84 -48
  1260. package/src/components/AppShell/app-shell.stories.tsx +445 -0
  1261. package/src/components/AppShell/app-shell.tsx +77 -24
  1262. package/src/components/AppShell/index.ts +5 -0
  1263. package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +208 -0
  1264. package/src/components/AspectRatio/aspect-ratio.principles.stories.tsx +303 -0
  1265. package/src/components/AspectRatio/aspect-ratio.spec.md +24 -12
  1266. package/src/components/AspectRatio/aspect-ratio.stories.tsx +91 -0
  1267. package/src/components/AspectRatio/aspect-ratio.tsx +6 -3
  1268. package/src/components/AspectRatio/index.ts +5 -0
  1269. package/src/components/Avatar/avatar.anatomy.stories.tsx +705 -0
  1270. package/src/components/Avatar/avatar.principles.stories.tsx +249 -0
  1271. package/src/components/Avatar/avatar.spec.md +66 -103
  1272. package/src/components/Avatar/avatar.stories.tsx +156 -0
  1273. package/src/components/Avatar/avatar.tsx +85 -64
  1274. package/src/components/Avatar/index.ts +5 -0
  1275. package/src/components/Badge/badge.anatomy.stories.tsx +591 -0
  1276. package/src/components/Badge/badge.principles.stories.tsx +391 -0
  1277. package/src/components/Badge/badge.spec.md +43 -23
  1278. package/src/components/Badge/badge.stories.tsx +82 -0
  1279. package/src/components/Badge/badge.tsx +38 -14
  1280. package/src/components/Badge/index.ts +5 -0
  1281. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +462 -0
  1282. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +353 -0
  1283. package/src/components/Breadcrumb/breadcrumb.spec.md +55 -43
  1284. package/src/components/Breadcrumb/breadcrumb.stories.tsx +381 -0
  1285. package/src/components/Breadcrumb/breadcrumb.tsx +43 -86
  1286. package/src/components/Breadcrumb/index.ts +5 -0
  1287. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +225 -0
  1288. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +255 -0
  1289. package/src/components/BulkActionBar/bulk-action-bar.spec.md +64 -36
  1290. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +124 -0
  1291. package/src/components/BulkActionBar/bulk-action-bar.tsx +26 -18
  1292. package/src/components/BulkActionBar/index.ts +5 -0
  1293. package/src/components/Button/button-group.tsx +64 -21
  1294. package/src/components/Button/button.anatomy.stories.tsx +729 -0
  1295. package/src/components/Button/button.principles.stories.tsx +369 -0
  1296. package/src/components/Button/button.spec.md +42 -39
  1297. package/src/components/Button/button.stories.tsx +368 -0
  1298. package/src/components/Button/button.tsx +109 -55
  1299. package/src/components/Button/index.ts +6 -0
  1300. package/src/components/Calendar/calendar.anatomy.stories.tsx +237 -0
  1301. package/src/components/Calendar/calendar.principles.stories.tsx +152 -0
  1302. package/src/components/Calendar/calendar.spec.md +80 -55
  1303. package/src/components/Calendar/calendar.stories.tsx +108 -0
  1304. package/src/components/Calendar/calendar.tsx +200 -134
  1305. package/src/components/Calendar/index.ts +5 -0
  1306. package/src/components/Carousel/carousel.anatomy.stories.tsx +517 -0
  1307. package/src/components/Carousel/carousel.principles.stories.tsx +334 -0
  1308. package/src/components/Carousel/carousel.spec.md +51 -15
  1309. package/src/components/Carousel/carousel.stories.tsx +125 -0
  1310. package/src/components/Carousel/carousel.tsx +139 -56
  1311. package/src/components/Carousel/index.ts +5 -0
  1312. package/src/components/Chart/chart.anatomy.stories.tsx +310 -0
  1313. package/src/components/Chart/chart.principles.stories.tsx +437 -0
  1314. package/src/components/Chart/chart.spec.md +24 -5
  1315. package/src/components/Chart/chart.stories.tsx +263 -0
  1316. package/src/components/Chart/chart.tsx +10 -3
  1317. package/src/components/Chart/index.ts +5 -0
  1318. package/src/components/Checkbox/checkbox-group.tsx +28 -16
  1319. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +614 -0
  1320. package/src/components/Checkbox/checkbox.principles.stories.tsx +216 -0
  1321. package/src/components/Checkbox/checkbox.spec.md +65 -42
  1322. package/src/components/Checkbox/checkbox.stories.tsx +119 -0
  1323. package/src/components/Checkbox/checkbox.tsx +189 -32
  1324. package/src/components/Checkbox/index.ts +6 -0
  1325. package/src/components/Chip/chip.anatomy.stories.tsx +442 -0
  1326. package/src/components/Chip/chip.principles.stories.tsx +228 -0
  1327. package/src/components/Chip/chip.spec.md +52 -40
  1328. package/src/components/Chip/chip.stories.tsx +111 -0
  1329. package/src/components/Chip/chip.tsx +130 -45
  1330. package/src/components/Chip/index.ts +5 -0
  1331. package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +177 -0
  1332. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +265 -0
  1333. package/src/components/CircularProgress/circular-progress.spec.md +32 -32
  1334. package/src/components/CircularProgress/circular-progress.stories.tsx +149 -0
  1335. package/src/components/CircularProgress/circular-progress.tsx +5 -6
  1336. package/src/components/CircularProgress/index.ts +5 -0
  1337. package/src/components/Coachmark/coachmark-story-helpers.tsx +39 -0
  1338. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +356 -0
  1339. package/src/components/Coachmark/coachmark.principles.stories.tsx +356 -0
  1340. package/src/components/Coachmark/coachmark.spec.md +36 -29
  1341. package/src/components/Coachmark/coachmark.stories.tsx +220 -0
  1342. package/src/components/Coachmark/coachmark.tsx +36 -10
  1343. package/src/components/Coachmark/index.ts +5 -0
  1344. package/src/components/Combobox/combobox.anatomy.stories.tsx +926 -0
  1345. package/src/components/Combobox/combobox.principles.stories.tsx +238 -0
  1346. package/src/components/Combobox/combobox.spec.md +45 -16
  1347. package/src/components/Combobox/combobox.stories.tsx +194 -0
  1348. package/src/components/Combobox/combobox.tsx +278 -97
  1349. package/src/components/Combobox/index.ts +5 -0
  1350. package/src/components/Command/command.anatomy.stories.tsx +107 -0
  1351. package/src/components/Command/command.principles.stories.tsx +86 -0
  1352. package/src/components/Command/command.spec.md +33 -23
  1353. package/src/components/Command/command.stories.tsx +312 -0
  1354. package/src/components/Command/command.tsx +28 -12
  1355. package/src/components/Command/index.ts +5 -0
  1356. package/src/components/DataTable/active-editor-controller.ts +4 -3
  1357. package/src/components/DataTable/cell-registry.tsx +161 -120
  1358. package/src/components/DataTable/column-types.ts +14 -18
  1359. package/src/components/DataTable/data-table-column-visibility-panel.tsx +28 -12
  1360. package/src/components/DataTable/data-table-filter-group.tsx +248 -0
  1361. package/src/components/DataTable/data-table-filter-labels.ts +100 -0
  1362. package/src/components/DataTable/data-table-filter-panel.tsx +85 -448
  1363. package/src/components/DataTable/data-table-filter-value-picker.tsx +254 -0
  1364. package/src/components/DataTable/data-table-interaction-layer.tsx +26 -29
  1365. package/src/components/DataTable/data-table-sort-manager.tsx +19 -11
  1366. package/src/components/DataTable/data-table.anatomy.stories.tsx +522 -0
  1367. package/src/components/DataTable/data-table.css +34 -8
  1368. package/src/components/DataTable/data-table.principles.stories.tsx +270 -0
  1369. package/src/components/DataTable/data-table.spec.md +186 -172
  1370. package/src/components/DataTable/data-table.stories.tsx +2311 -0
  1371. package/src/components/DataTable/data-table.tsx +678 -278
  1372. package/src/components/DataTable/filter-operators.spec.md +269 -0
  1373. package/src/components/DataTable/filter-operators.ts +1 -1
  1374. package/src/components/DataTable/filter-tree.ts +194 -44
  1375. package/src/components/DataTable/index.ts +8 -0
  1376. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +587 -0
  1377. package/src/components/DateGrid/date-grid.principles.stories.tsx +344 -0
  1378. package/src/components/DateGrid/date-grid.spec.md +46 -41
  1379. package/src/components/DateGrid/date-grid.stories.tsx +204 -0
  1380. package/src/components/DateGrid/date-grid.tsx +89 -28
  1381. package/src/components/DateGrid/index.ts +5 -0
  1382. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +946 -0
  1383. package/src/components/DatePicker/date-picker.principles.stories.tsx +205 -0
  1384. package/src/components/DatePicker/date-picker.spec.md +61 -57
  1385. package/src/components/DatePicker/date-picker.stories.tsx +364 -0
  1386. package/src/components/DatePicker/date-picker.tsx +382 -198
  1387. package/src/components/DatePicker/index.ts +5 -0
  1388. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +254 -0
  1389. package/src/components/DescriptionList/description-list.principles.stories.tsx +309 -0
  1390. package/src/components/DescriptionList/description-list.spec.md +35 -30
  1391. package/src/components/DescriptionList/description-list.stories.tsx +113 -0
  1392. package/src/components/DescriptionList/description-list.tsx +16 -14
  1393. package/src/components/DescriptionList/index.ts +5 -0
  1394. package/src/components/Dialog/dialog.anatomy.stories.tsx +485 -0
  1395. package/src/components/Dialog/dialog.principles.stories.tsx +261 -0
  1396. package/src/components/Dialog/dialog.spec.md +58 -32
  1397. package/src/components/Dialog/dialog.stories.tsx +548 -0
  1398. package/src/components/Dialog/dialog.tsx +81 -36
  1399. package/src/components/Dialog/index.ts +5 -0
  1400. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +971 -0
  1401. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +341 -0
  1402. package/src/components/DropdownMenu/dropdown-menu.spec.md +40 -22
  1403. package/src/components/DropdownMenu/dropdown-menu.stories.tsx +276 -0
  1404. package/src/components/DropdownMenu/dropdown-menu.tsx +153 -40
  1405. package/src/components/DropdownMenu/index.ts +5 -0
  1406. package/src/components/Empty/empty.anatomy.stories.tsx +275 -0
  1407. package/src/components/Empty/empty.principles.stories.tsx +314 -0
  1408. package/src/components/Empty/empty.spec.md +42 -42
  1409. package/src/components/Empty/empty.stories.tsx +69 -0
  1410. package/src/components/Empty/empty.tsx +23 -11
  1411. package/src/components/Empty/index.ts +5 -0
  1412. package/src/components/Field/field-context.ts +196 -4
  1413. package/src/components/Field/field-controls.spec.md +161 -54
  1414. package/src/components/Field/field-edit-keys.ts +66 -0
  1415. package/src/components/Field/field-types.ts +71 -20
  1416. package/src/components/Field/field-wrapper.tsx +139 -89
  1417. package/src/components/Field/field.anatomy.stories.tsx +547 -0
  1418. package/src/components/Field/field.principles.stories.tsx +255 -0
  1419. package/src/components/Field/field.spec.md +76 -34
  1420. package/src/components/Field/field.stories.tsx +751 -0
  1421. package/src/components/Field/field.tsx +65 -12
  1422. package/src/components/Field/form-validation.spec.md +60 -34
  1423. package/src/components/Field/index.ts +6 -0
  1424. package/src/components/Field/use-form-validation.ts +270 -0
  1425. package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +119 -0
  1426. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +121 -0
  1427. package/src/components/FieldControlGroup/field-control-group.spec.md +41 -19
  1428. package/src/components/FieldControlGroup/field-control-group.stories.tsx +162 -0
  1429. package/src/components/FieldControlGroup/field-control-group.tsx +13 -15
  1430. package/src/components/FieldControlGroup/index.ts +5 -0
  1431. package/src/components/FileItem/file-item.anatomy.stories.tsx +346 -0
  1432. package/src/components/FileItem/file-item.principles.stories.tsx +245 -0
  1433. package/src/components/FileItem/file-item.spec.md +133 -104
  1434. package/src/components/FileItem/file-item.stories.tsx +289 -0
  1435. package/src/components/FileItem/file-item.tsx +85 -39
  1436. package/src/components/FileItem/index.ts +5 -0
  1437. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +446 -0
  1438. package/src/components/FileUpload/file-upload.principles.stories.tsx +312 -0
  1439. package/src/components/FileUpload/file-upload.spec.md +66 -24
  1440. package/src/components/FileUpload/file-upload.stories.tsx +219 -0
  1441. package/src/components/FileUpload/file-upload.tsx +138 -43
  1442. package/src/components/FileUpload/index.ts +5 -0
  1443. package/src/components/FileViewer/can-render-image.ts +15 -0
  1444. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1130 -0
  1445. package/src/components/FileViewer/file-viewer.principles.stories.tsx +636 -0
  1446. package/src/components/FileViewer/file-viewer.spec.md +70 -58
  1447. package/src/components/FileViewer/file-viewer.stories.tsx +417 -0
  1448. package/src/components/FileViewer/file-viewer.tsx +157 -72
  1449. package/src/components/FileViewer/image-renderer.tsx +38 -15
  1450. package/src/components/FileViewer/index.ts +5 -0
  1451. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +151 -0
  1452. package/src/components/HoverCard/hover-card.principles.stories.tsx +211 -0
  1453. package/src/components/HoverCard/hover-card.spec.md +38 -28
  1454. package/src/components/HoverCard/hover-card.stories.tsx +304 -0
  1455. package/src/components/HoverCard/hover-card.tsx +23 -6
  1456. package/src/components/HoverCard/index.ts +5 -0
  1457. package/src/components/InlineEdit/index.ts +5 -0
  1458. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +250 -0
  1459. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  1460. package/src/components/InlineEdit/inline-edit.spec.md +186 -0
  1461. package/src/components/InlineEdit/inline-edit.stories.tsx +261 -0
  1462. package/src/components/InlineEdit/inline-edit.tsx +455 -0
  1463. package/src/components/Input/index.ts +5 -0
  1464. package/src/components/Input/input.anatomy.stories.tsx +780 -0
  1465. package/src/components/Input/input.principles.stories.tsx +260 -0
  1466. package/src/components/Input/input.spec.md +34 -26
  1467. package/src/components/Input/input.stories.tsx +150 -0
  1468. package/src/components/Input/input.tsx +102 -45
  1469. package/src/components/LinkInput/index.ts +5 -0
  1470. package/src/components/LinkInput/link-input.anatomy.stories.tsx +748 -0
  1471. package/src/components/LinkInput/link-input.principles.stories.tsx +182 -0
  1472. package/src/components/LinkInput/link-input.spec.md +25 -7
  1473. package/src/components/LinkInput/link-input.stories.tsx +133 -0
  1474. package/src/components/LinkInput/link-input.tsx +89 -66
  1475. package/src/components/Menu/index.ts +5 -0
  1476. package/src/components/Menu/menu-item.anatomy.stories.tsx +780 -0
  1477. package/src/components/Menu/menu-item.principles.stories.tsx +81 -0
  1478. package/src/components/Menu/menu-item.spec.md +55 -32
  1479. package/src/components/Menu/menu-item.stories.tsx +242 -0
  1480. package/src/components/Menu/menu-item.tsx +71 -12
  1481. package/src/components/Notice/index.ts +5 -0
  1482. package/src/components/Notice/notice.anatomy.stories.tsx +614 -0
  1483. package/src/components/Notice/notice.principles.stories.tsx +102 -0
  1484. package/src/components/Notice/notice.spec.md +39 -18
  1485. package/src/components/Notice/notice.stories.tsx +257 -0
  1486. package/src/components/Notice/notice.tsx +62 -16
  1487. package/src/components/NumberInput/index.ts +5 -0
  1488. package/src/components/NumberInput/number-input.anatomy.stories.tsx +822 -0
  1489. package/src/components/NumberInput/number-input.principles.stories.tsx +206 -0
  1490. package/src/components/NumberInput/number-input.spec.md +35 -16
  1491. package/src/components/NumberInput/number-input.stories.tsx +167 -0
  1492. package/src/components/NumberInput/number-input.tsx +65 -31
  1493. package/src/components/OverflowIndicator/index.ts +5 -0
  1494. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +550 -0
  1495. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +76 -0
  1496. package/src/components/OverflowIndicator/overflow-indicator.spec.md +36 -26
  1497. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +222 -0
  1498. package/src/components/OverflowIndicator/overflow-indicator.tsx +22 -7
  1499. package/src/components/Pagination/index.ts +5 -0
  1500. package/src/components/Pagination/pagination.anatomy.stories.tsx +144 -0
  1501. package/src/components/Pagination/pagination.principles.stories.tsx +81 -0
  1502. package/src/components/Pagination/pagination.spec.md +150 -0
  1503. package/src/components/Pagination/pagination.stories.tsx +97 -0
  1504. package/src/components/Pagination/pagination.tsx +263 -0
  1505. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  1506. package/src/components/PeoplePicker/index.ts +5 -0
  1507. package/src/components/PeoplePicker/people-picker-helpers.ts +5 -5
  1508. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +437 -0
  1509. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +196 -0
  1510. package/src/components/PeoplePicker/people-picker.spec.md +97 -40
  1511. package/src/components/PeoplePicker/people-picker.stories.tsx +245 -0
  1512. package/src/components/PeoplePicker/people-picker.tsx +225 -108
  1513. package/src/components/PeoplePicker/person-display.tsx +83 -47
  1514. package/src/components/Popover/index.ts +5 -0
  1515. package/src/components/Popover/popover.anatomy.stories.tsx +282 -0
  1516. package/src/components/Popover/popover.principles.stories.tsx +316 -0
  1517. package/src/components/Popover/popover.spec.md +41 -31
  1518. package/src/components/Popover/popover.stories.tsx +120 -0
  1519. package/src/components/Popover/popover.tsx +106 -47
  1520. package/src/components/ProfileCard/index.ts +5 -0
  1521. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +493 -0
  1522. package/src/components/ProfileCard/profile-card.principles.stories.tsx +225 -0
  1523. package/src/components/ProfileCard/profile-card.spec.md +189 -0
  1524. package/src/components/ProfileCard/profile-card.stories.tsx +57 -0
  1525. package/src/components/{NameCard/name-card.tsx → ProfileCard/profile-card.tsx} +66 -39
  1526. package/src/components/ProgressBar/index.ts +5 -0
  1527. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +441 -0
  1528. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +326 -0
  1529. package/src/components/ProgressBar/progress-bar.spec.md +25 -21
  1530. package/src/components/ProgressBar/progress-bar.stories.tsx +133 -0
  1531. package/src/components/ProgressBar/progress-bar.tsx +6 -23
  1532. package/src/components/README.md +5 -4
  1533. package/src/components/RadioGroup/index.ts +5 -0
  1534. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +672 -0
  1535. package/src/components/RadioGroup/radio-group.principles.stories.tsx +163 -0
  1536. package/src/components/RadioGroup/radio-group.spec.md +15 -9
  1537. package/src/components/RadioGroup/radio-group.stories.tsx +204 -0
  1538. package/src/components/RadioGroup/radio-group.tsx +219 -67
  1539. package/src/components/Rating/index.ts +5 -0
  1540. package/src/components/Rating/rating.anatomy.stories.tsx +498 -0
  1541. package/src/components/Rating/rating.principles.stories.tsx +296 -0
  1542. package/src/components/Rating/rating.spec.md +41 -29
  1543. package/src/components/Rating/rating.stories.tsx +119 -0
  1544. package/src/components/Rating/rating.tsx +37 -18
  1545. package/src/components/ScrollArea/index.ts +5 -0
  1546. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +451 -0
  1547. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +331 -0
  1548. package/src/components/ScrollArea/scroll-area.spec.md +24 -22
  1549. package/src/components/ScrollArea/scroll-area.stories.tsx +247 -0
  1550. package/src/components/ScrollArea/scroll-area.tsx +24 -7
  1551. package/src/components/SegmentedControl/index.ts +5 -0
  1552. package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +295 -0
  1553. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +284 -0
  1554. package/src/components/SegmentedControl/segmented-control.spec.md +38 -39
  1555. package/src/components/SegmentedControl/segmented-control.stories.tsx +37 -0
  1556. package/src/components/SegmentedControl/segmented-control.tsx +44 -24
  1557. package/src/components/Select/index.ts +5 -0
  1558. package/src/components/Select/select.anatomy.stories.tsx +834 -0
  1559. package/src/components/Select/select.principles.stories.tsx +312 -0
  1560. package/src/components/Select/select.spec.md +99 -39
  1561. package/src/components/Select/select.stories.tsx +273 -0
  1562. package/src/components/Select/select.tsx +389 -97
  1563. package/src/components/SelectMenu/index.ts +5 -0
  1564. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +830 -0
  1565. package/src/components/SelectMenu/select-menu.principles.stories.tsx +106 -0
  1566. package/src/components/SelectMenu/select-menu.spec.md +51 -32
  1567. package/src/components/SelectMenu/select-menu.stories.tsx +143 -0
  1568. package/src/components/SelectMenu/select-menu.tsx +276 -33
  1569. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  1570. package/src/components/SelectionControl/index.ts +6 -0
  1571. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +580 -0
  1572. package/src/components/SelectionControl/selection-item.principles.stories.tsx +77 -0
  1573. package/src/components/SelectionControl/selection-item.spec.md +30 -16
  1574. package/src/components/SelectionControl/selection-item.stories.tsx +137 -0
  1575. package/src/components/SelectionControl/selection-item.tsx +8 -2
  1576. package/src/components/Separator/index.ts +5 -0
  1577. package/src/components/Separator/separator.anatomy.stories.tsx +125 -0
  1578. package/src/components/Separator/separator.principles.stories.tsx +141 -0
  1579. package/src/components/Separator/separator.spec.md +15 -9
  1580. package/src/components/Separator/separator.stories.tsx +106 -0
  1581. package/src/components/Separator/separator.tsx +2 -2
  1582. package/src/components/Sheet/index.ts +5 -0
  1583. package/src/components/Sheet/sheet.anatomy.stories.tsx +269 -0
  1584. package/src/components/Sheet/sheet.principles.stories.tsx +353 -0
  1585. package/src/components/Sheet/sheet.spec.md +16 -17
  1586. package/src/components/Sheet/sheet.stories.tsx +172 -0
  1587. package/src/components/Sheet/sheet.tsx +24 -14
  1588. package/src/components/Sidebar/index.ts +5 -0
  1589. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +776 -0
  1590. package/src/components/Sidebar/sidebar.principles.stories.tsx +507 -0
  1591. package/src/components/Sidebar/sidebar.spec.md +65 -62
  1592. package/src/components/Sidebar/sidebar.stories.tsx +535 -0
  1593. package/src/components/Sidebar/sidebar.tsx +134 -57
  1594. package/src/components/Skeleton/index.ts +5 -0
  1595. package/src/components/Skeleton/skeleton.anatomy.stories.tsx +145 -0
  1596. package/src/components/Skeleton/skeleton.principles.stories.tsx +234 -0
  1597. package/src/components/Skeleton/skeleton.spec.md +15 -14
  1598. package/src/components/Skeleton/skeleton.stories.tsx +134 -0
  1599. package/src/components/Skeleton/skeleton.tsx +2 -2
  1600. package/src/components/Slider/index.ts +5 -0
  1601. package/src/components/Slider/slider.anatomy.stories.tsx +237 -0
  1602. package/src/components/Slider/slider.principles.stories.tsx +250 -0
  1603. package/src/components/Slider/slider.spec.md +66 -118
  1604. package/src/components/Slider/slider.stories.tsx +115 -0
  1605. package/src/components/Slider/slider.tsx +83 -26
  1606. package/src/components/Steps/index.ts +5 -0
  1607. package/src/components/Steps/steps.anatomy.stories.tsx +448 -0
  1608. package/src/components/Steps/steps.principles.stories.tsx +300 -0
  1609. package/src/components/Steps/steps.spec.md +91 -74
  1610. package/src/components/Steps/steps.stories.tsx +306 -0
  1611. package/src/components/Steps/steps.tsx +99 -37
  1612. package/src/components/Switch/index.ts +5 -0
  1613. package/src/components/Switch/switch.anatomy.stories.tsx +227 -0
  1614. package/src/components/Switch/switch.principles.stories.tsx +177 -0
  1615. package/src/components/Switch/switch.spec.md +53 -24
  1616. package/src/components/Switch/switch.stories.tsx +95 -0
  1617. package/src/components/Switch/switch.tsx +176 -43
  1618. package/src/components/Tabs/index.ts +5 -0
  1619. package/src/components/Tabs/tabs-inline-action-geometry.ts +94 -0
  1620. package/src/components/Tabs/tabs.anatomy.stories.tsx +424 -0
  1621. package/src/components/Tabs/tabs.principles.stories.tsx +291 -0
  1622. package/src/components/Tabs/tabs.spec.md +58 -69
  1623. package/src/components/Tabs/tabs.stories.tsx +257 -0
  1624. package/src/components/Tabs/tabs.tsx +262 -82
  1625. package/src/components/Tag/index.ts +5 -0
  1626. package/src/components/Tag/tag.anatomy.stories.tsx +667 -0
  1627. package/src/components/Tag/tag.principles.stories.tsx +270 -0
  1628. package/src/components/Tag/tag.spec.md +112 -100
  1629. package/src/components/Tag/tag.stories.tsx +88 -0
  1630. package/src/components/Tag/tag.tsx +120 -80
  1631. package/src/components/Textarea/index.ts +5 -0
  1632. package/src/components/Textarea/textarea.anatomy.stories.tsx +310 -0
  1633. package/src/components/Textarea/textarea.principles.stories.tsx +192 -0
  1634. package/src/components/Textarea/textarea.spec.md +35 -16
  1635. package/src/components/Textarea/textarea.stories.tsx +57 -0
  1636. package/src/components/Textarea/textarea.tsx +154 -83
  1637. package/src/components/TimePicker/index.ts +5 -0
  1638. package/src/components/TimePicker/time-columns.tsx +15 -3
  1639. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +283 -0
  1640. package/src/components/TimePicker/time-picker.principles.stories.tsx +133 -0
  1641. package/src/components/TimePicker/time-picker.spec.md +58 -52
  1642. package/src/components/TimePicker/time-picker.stories.tsx +193 -0
  1643. package/src/components/TimePicker/time-picker.tsx +119 -60
  1644. package/src/components/Toast/index.ts +5 -0
  1645. package/src/components/Toast/toast.anatomy.stories.tsx +328 -0
  1646. package/src/components/Toast/toast.principles.stories.tsx +216 -0
  1647. package/src/components/Toast/toast.spec.md +26 -16
  1648. package/src/components/Toast/toast.stories.tsx +241 -0
  1649. package/src/components/Toast/toast.tsx +101 -23
  1650. package/src/components/Tooltip/index.ts +5 -0
  1651. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +422 -0
  1652. package/src/components/Tooltip/tooltip.principles.stories.tsx +204 -0
  1653. package/src/components/Tooltip/tooltip.spec.md +37 -23
  1654. package/src/components/Tooltip/tooltip.stories.tsx +82 -0
  1655. package/src/components/Tooltip/tooltip.tsx +58 -12
  1656. package/src/components/TreeView/index.ts +5 -0
  1657. package/src/components/TreeView/tree-view.anatomy.stories.tsx +436 -0
  1658. package/src/components/TreeView/tree-view.principles.stories.tsx +223 -0
  1659. package/src/components/TreeView/tree-view.spec.md +103 -54
  1660. package/src/components/TreeView/tree-view.stories.tsx +365 -0
  1661. package/src/components/TreeView/tree-view.tsx +501 -58
  1662. package/src/hooks/use-controllable.ts +7 -2
  1663. package/src/hooks/use-is-touch-device.ts +8 -1
  1664. package/src/hooks/use-overflow-items.ts +10 -6
  1665. package/src/hooks/use-truncated.ts +111 -0
  1666. package/src/index.ts +648 -71
  1667. package/src/lib/drag-visual.ts +2 -2
  1668. package/src/lib/utils.ts +21 -1
  1669. package/src/patterns/README.md +20 -16
  1670. package/src/patterns/action-bar/action-bar.spec.md +63 -45
  1671. package/src/patterns/action-bar/action-bar.stories.tsx +619 -0
  1672. package/src/patterns/element-anatomy/element-anatomy.spec.md +17 -13
  1673. package/src/patterns/element-anatomy/index.ts +6 -0
  1674. package/src/patterns/element-anatomy/inline-action.spec.md +33 -22
  1675. package/src/patterns/element-anatomy/item-anatomy.spec.md +108 -79
  1676. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +1648 -0
  1677. package/src/patterns/element-anatomy/item-anatomy.tsx +147 -56
  1678. package/src/patterns/element-anatomy/truncated-text.spec.md +68 -0
  1679. package/src/patterns/element-anatomy/truncated-text.tsx +61 -0
  1680. package/src/patterns/header-canonical/chrome-header.tsx +26 -6
  1681. package/src/patterns/header-canonical/header-canonical.css +3 -4
  1682. package/src/patterns/header-canonical/header-canonical.spec.md +96 -42
  1683. package/src/patterns/header-canonical/header-canonical.stories.tsx +257 -0
  1684. package/src/patterns/header-canonical/index.ts +5 -0
  1685. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +36 -15
  1686. package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +139 -0
  1687. package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +1 -1
  1688. package/src/patterns/horizontal-overflow/index.ts +5 -0
  1689. package/src/patterns/overlay-surface/index.ts +5 -0
  1690. package/src/patterns/overlay-surface/overlay-surface.spec.md +94 -58
  1691. package/src/patterns/overlay-surface/overlay-surface.stories.tsx +132 -0
  1692. package/src/patterns/overlay-surface/overlay-surface.tsx +37 -18
  1693. package/src/patterns/resize-handle/index.ts +5 -0
  1694. package/src/patterns/resize-handle/resize-handle.spec.md +22 -13
  1695. package/src/patterns/resize-handle/resize-handle.stories.tsx +73 -0
  1696. package/src/patterns/resize-handle/resize-handle.tsx +13 -18
  1697. package/src/story-governance/category-matrix.json +132 -0
  1698. package/src/story-governance/category-matrix.ts +55 -0
  1699. package/src/styles/base.css +99 -0
  1700. package/src/styles/tokens.css +14 -0
  1701. package/src/tokens/README.md +10 -5
  1702. package/src/tokens/categorical-color.ts +164 -0
  1703. package/src/tokens/color/color.spec.md +95 -72
  1704. package/src/tokens/color/color.stories.tsx +403 -0
  1705. package/src/tokens/color/primitives.css +23 -7
  1706. package/src/tokens/color/semantic.css +75 -21
  1707. package/src/tokens/density/density.spec.md +33 -30
  1708. package/src/tokens/density/density.stories.tsx +254 -0
  1709. package/src/tokens/elevation/elevation.spec.md +11 -14
  1710. package/src/tokens/elevation/elevation.stories.tsx +99 -0
  1711. package/src/tokens/layoutSpace/layoutSpace.css +1 -1
  1712. package/src/tokens/layoutSpace/layoutSpace.spec.md +44 -31
  1713. package/src/tokens/layoutSpace/layoutSpace.stories.tsx +76 -0
  1714. package/src/tokens/motion/motion.css +49 -20
  1715. package/src/tokens/motion/motion.spec.md +45 -21
  1716. package/src/tokens/motion/motion.stories.tsx +196 -0
  1717. package/src/tokens/motion/motion.ts +8 -7
  1718. package/src/tokens/motion/overlay-motion.ts +26 -0
  1719. package/src/tokens/opacity/opacity.spec.md +15 -20
  1720. package/src/tokens/opacity/opacity.stories.tsx +66 -0
  1721. package/src/tokens/orphan-tokens.spec.md +22 -11
  1722. package/src/tokens/radius/radius.spec.md +14 -11
  1723. package/src/tokens/radius/radius.stories.tsx +87 -0
  1724. package/src/tokens/token-system.spec.md +241 -0
  1725. package/src/tokens/typography/typography.css +1 -1
  1726. package/src/tokens/typography/typography.spec.md +12 -8
  1727. package/src/tokens/typography/typography.stories.tsx +134 -0
  1728. package/src/tokens/uiSize/icon-size.ts +3 -4
  1729. package/src/tokens/uiSize/uiSize.css +58 -1
  1730. package/src/tokens/uiSize/uiSize.spec.md +61 -32
  1731. package/src/tokens/uiSize/uiSize.stories.tsx +106 -0
  1732. package/src/tokens/utility-registry.json +426 -0
  1733. package/src/tokens/utility-registry.schema.json +409 -0
  1734. package/tools/README.md +9 -0
  1735. package/tools/codemods/cli.mjs +93 -0
  1736. package/tools/codemods/index.mjs +582 -0
  1737. package/tools/shared/safe-filesystem.mjs +371 -0
  1738. package/tools/visual-baseline/cli.mjs +97 -0
  1739. package/tools/visual-baseline/index.mjs +522 -0
  1740. package/dist/components/NameCard/name-card.d.ts.map +0 -1
  1741. package/dist/components/NameCard/name-card.js.map +0 -1
  1742. package/ds-canonical/commands/gov-status.md +0 -79
  1743. package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +0 -68
  1744. package/ds-canonical/hooks/check_chrome_header_handcraft.sh +0 -70
  1745. package/ds-canonical/hooks/check_header_with_tabs_border.sh +0 -87
  1746. package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +0 -66
  1747. package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +0 -15
  1748. package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +0 -187
  1749. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +0 -74
  1750. package/ds-canonical/skills/design-system-audit/references/spec-template.md +0 -66
  1751. package/src/components/NameCard/name-card.spec.md +0 -171
@@ -0,0 +1,2454 @@
1
+ #!/usr/bin/env node
2
+ // refresh-fork-launchers.mjs — C-prime 接線骨架刷新(sync-all 呼叫 + harness 可測)
3
+ //
4
+ // 既有 fork 的「接線骨架」(provider configs + governance/bin 的 manifest-declared shared launchers)原本
5
+ // 不隨 npm 同步 → DS 改接線層後 user fork 拿不到(2026-06-17 user 抓:完全同步不偏移未達成)。
6
+ // 本模組從 npm-current 的 ds-canonical/fork/launchers/ 把骨架 idempotent 刷新進 fork:
7
+ // 1. copy manifest-declared launcher set → manifest.consumer.launcherDestination(官方控管,唯一共享副本)
8
+ // 2. merge settings-hooks.json 進 .claude/settings.json:
9
+ // - strip 所有 event 裡「引用 canonical launcher set」的舊註冊(去重)
10
+ // - append canonical 啟動器註冊
11
+ // - retire only the exact unsafe allows shipped by older corpus versions
12
+ // - replace policy-owned permissions.ask, retain non-conflicting consumer allow/deny, and enforce safe modes
13
+ // → 不 clobber user 自有「非治理」hook;重跑結果一致(idempotent)
14
+ // 4. provider surfaces:manifest-declared instructions + hooks + skills + closed trees 送達 fork root
15
+ // — AGENTS.md 與 provider wiring 是 immutable governance views,固定 clobber;product 規則只放 governance/overlay.md。
16
+ // 安全:.github/no-governance-sync opt-out → 整段 skip;launchers 未 ship(舊 npm)→ skip 不報錯。
17
+ // §15 契約:deterministic(輸出只依 corpus+dest 內容)/ idempotent(重跑收斂)/ atomic(所有檔案都走
18
+ // same-directory tmp+rename,不沿既有 target inode 覆寫)/ dry-run(opts.dryRun 只算不寫)/ json(CLI --json)。
19
+ //
20
+ // 抽成獨立模組 = sync-all 呼叫 + test-fork-governance.mjs 直接測(不需真跑 npm install)。
21
+
22
+ import { closeSync, existsSync, fchmodSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, cpSync, writeFileSync } from 'node:fs'
23
+ import { createHash, randomUUID } from 'node:crypto'
24
+ import { join, dirname, resolve, sep, isAbsolute, relative } from 'node:path'
25
+ import { fileURLToPath } from 'node:url'
26
+ import {
27
+ compareUtf8Bytes,
28
+ portableRepositoryPathKey,
29
+ repositoryPathsOverlap,
30
+ validateAuthenticatedProviderLifecycle,
31
+ } from './lib/provider-lifecycle.mjs'
32
+ import { assertNoRootNpmShrinkwrap } from './lib/governance-dependency-bootstrap.mjs'
33
+
34
+ // Consumer upgrades run repository-owned code against attacker-editable working trees. Lexical
35
+ // containment alone is insufficient: an in-repo parent symlink can redirect copy/rename/remove to
36
+ // a sibling or arbitrary host path. These helpers are the single path-safety SSOT shared with
37
+ // sync-all.mjs; every managed source/target is validated before the first mutation.
38
+ export function canonicalRepositoryRoot(root) {
39
+ const absolute = resolve(root)
40
+ const info = lstatSync(absolute)
41
+ if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`repository root must be a real directory:${absolute}`)
42
+ return realpathSync(absolute)
43
+ }
44
+
45
+ export function normalizeRepositoryRelative(value, label = 'path', { allowGit = false } = {}) {
46
+ if (typeof value !== 'string' || !value || value.includes('\0') || isAbsolute(value)) throw new Error(`${label} must be a non-empty repository-relative path`)
47
+ const normalized = value.replaceAll('\\', '/').replace(/^\.\//, '').replace(/\/+$/, '')
48
+ const parts = normalized.split('/')
49
+ if (!normalized || parts.some((part) => !part || part === '.' || part === '..')) throw new Error(`${label} escapes its repository root:${value}`)
50
+ if (!allowGit && parts[0] === '.git') throw new Error(`${label} may not address .git:${value}`)
51
+ return normalized
52
+ }
53
+
54
+ export function pathEntryExists(path) {
55
+ try { lstatSync(path); return true }
56
+ catch (error) {
57
+ if (error?.code === 'ENOENT') return false
58
+ throw error
59
+ }
60
+ }
61
+
62
+ // Linux permits entries that alias after the case-folding/Unicode normalization used by default
63
+ // macOS filesystems. Detect those aliases without following symlinks so a newly claimed provider
64
+ // surface cannot create a repository that is uncheckoutable or clobber-prone on another host.
65
+ function existingPortablePathCollision(root, repositoryPath) {
66
+ const canonicalRoot = canonicalRepositoryRoot(root)
67
+ const normalized = normalizeRepositoryRelative(repositoryPath, 'portable collision path')
68
+ let cursor = canonicalRoot
69
+ const segments = normalized.split('/')
70
+ for (const [index, segment] of segments.entries()) {
71
+ const cursorInfo = lstatSync(cursor)
72
+ if (!cursorInfo.isDirectory() || cursorInfo.isSymbolicLink()) return cursor
73
+ const matches = readdirSync(cursor)
74
+ .filter((name) => portableRepositoryPathKey(name) === portableRepositoryPathKey(segment))
75
+ .sort()
76
+ if (!matches.length) return null
77
+ const matched = matches[0]
78
+ const child = join(cursor, matched)
79
+ if (matches.length > 1 || matched !== segment || index === segments.length - 1) return child
80
+ const childInfo = lstatSync(child)
81
+ if (!childInfo.isDirectory() || childInfo.isSymbolicLink()) return child
82
+ cursor = child
83
+ }
84
+ return null
85
+ }
86
+
87
+ export function assertNoSymlinkPath(root, target, label = 'path', { allowMissing = true } = {}) {
88
+ const canonicalRoot = canonicalRepositoryRoot(root)
89
+ const absolute = resolve(target)
90
+ const rel = relative(canonicalRoot, absolute)
91
+ if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) throw new Error(`${label} escapes repository root:${absolute}`)
92
+ let cursor = canonicalRoot
93
+ for (const part of rel.split(sep).filter(Boolean)) {
94
+ cursor = join(cursor, part)
95
+ if (!pathEntryExists(cursor)) {
96
+ if (allowMissing) return absolute
97
+ throw new Error(`${label} is missing:${cursor}`)
98
+ }
99
+ const info = lstatSync(cursor)
100
+ if (info.isSymbolicLink()) throw new Error(`${label} contains symlink component:${cursor}`)
101
+ }
102
+ return absolute
103
+ }
104
+
105
+ export function assertSafeTree(root, target, label = 'tree', { allowMissing = false, allowInternalSymlinks = false } = {}) {
106
+ const absolute = assertNoSymlinkPath(root, target, label, { allowMissing })
107
+ if (!pathEntryExists(absolute)) return absolute
108
+ const visit = (path) => {
109
+ const info = lstatSync(path)
110
+ if (info.isSymbolicLink() && !allowInternalSymlinks) throw new Error(`${label} contains symlink:${path}`)
111
+ if (info.isDirectory()) for (const name of readdirSync(path)) visit(join(path, name))
112
+ else if (info.isFile() && info.nlink !== 1) throw new Error(`${label} contains hard-link alias:${path}`)
113
+ else if (!info.isFile() && !info.isSymbolicLink()) throw new Error(`${label} contains unsupported file type:${path}`)
114
+ }
115
+ visit(absolute)
116
+ return absolute
117
+ }
118
+
119
+ // One same-directory, attempt-unique replacement primitive is the managed-file durability SSOT.
120
+ // Keeping it separately testable lets the concurrency test exercise the exact production writer
121
+ // without launching two whole provider-tree transactions against the same repository.
122
+ export function atomicReplaceRepositoryFile(projectDir, target, content, { mode = 0o600, label = 'atomic repository file' } = {}) {
123
+ projectDir = canonicalRepositoryRoot(projectDir)
124
+ target = resolve(target)
125
+ assertNoSymlinkPath(projectDir, target, label)
126
+ mkdirSync(dirname(target), { recursive: true })
127
+ assertNoSymlinkPath(projectDir, dirname(target), `${label} parent`, { allowMissing: false })
128
+ const tmpPath = `${target}.tmp-${process.pid}-${randomUUID()}`
129
+ assertNoSymlinkPath(projectDir, tmpPath, `${label} temporary path`)
130
+ let descriptor = null
131
+ let parentDescriptor = null
132
+ try {
133
+ descriptor = openSync(tmpPath, 'wx', 0o600)
134
+ writeFileSync(descriptor, content)
135
+ fchmodSync(descriptor, mode & 0o777)
136
+ fsyncSync(descriptor)
137
+ closeSync(descriptor)
138
+ descriptor = null
139
+ assertNoSymlinkPath(projectDir, dirname(target), `${label} parent before replace`, { allowMissing: false })
140
+ const temporaryInfo = lstatSync(tmpPath)
141
+ if (!temporaryInfo.isFile() || temporaryInfo.isSymbolicLink() || temporaryInfo.nlink !== 1) {
142
+ throw new Error(`${label} temporary path is not one regular unaliased file:${tmpPath}`)
143
+ }
144
+ renameSync(tmpPath, target)
145
+ parentDescriptor = openSync(dirname(target), 'r')
146
+ fsyncSync(parentDescriptor)
147
+ closeSync(parentDescriptor)
148
+ parentDescriptor = null
149
+ } finally {
150
+ if (descriptor !== null) closeSync(descriptor)
151
+ if (parentDescriptor !== null) closeSync(parentDescriptor)
152
+ if (pathEntryExists(tmpPath)) rmSync(tmpPath, { force: true })
153
+ }
154
+ }
155
+
156
+ // Required npm commands are part of the immutable consumer BOM, but package.json also contains
157
+ // product-owned commands. Merge only the authenticated names so sync-all can add/upgrade governance
158
+ // entrypoints without replacing unrelated product scripts or teaching an old updater each new name.
159
+ export function mergeRequiredPackageScripts(manifest, requiredScripts) {
160
+ if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) throw new Error('consumer package manifest must be an object')
161
+ if (!requiredScripts || typeof requiredScripts !== 'object' || Array.isArray(requiredScripts)) throw new Error('consumer BOM requiredScripts must be an object')
162
+ if (manifest.scripts !== undefined && (!manifest.scripts || typeof manifest.scripts !== 'object' || Array.isArray(manifest.scripts))) {
163
+ throw new Error('consumer package scripts must be an object')
164
+ }
165
+ const entries = Object.entries(requiredScripts)
166
+ const names = entries.map(([name]) => name)
167
+ if (!entries.length || JSON.stringify(names) !== JSON.stringify([...names].sort())) {
168
+ throw new Error('consumer BOM requiredScripts must be nonempty and sorted')
169
+ }
170
+ for (const [name, command] of entries) {
171
+ if (!/^[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(name) || typeof command !== 'string' || !command.trim() || /[\0\r\n]/.test(command)) {
172
+ throw new Error(`consumer BOM required script is invalid:${name}`)
173
+ }
174
+ }
175
+ return {
176
+ ...manifest,
177
+ scripts: {
178
+ ...(manifest.scripts || {}),
179
+ ...Object.fromEntries(entries),
180
+ },
181
+ }
182
+ }
183
+
184
+ function safeCopyFile({ sourceRoot, source, targetRoot, target, label, mode = null }) {
185
+ assertNoSymlinkPath(sourceRoot, source, `${label} source`, { allowMissing: false })
186
+ const sourceInfo = lstatSync(source)
187
+ if (!sourceInfo.isFile() || sourceInfo.isSymbolicLink() || sourceInfo.nlink !== 1) throw new Error(`${label} source is not one regular unaliased file:${source}`)
188
+ assertNoSymlinkPath(targetRoot, target, `${label} target`)
189
+ atomicReplaceRepositoryFile(targetRoot, target, readFileSync(source), {
190
+ mode: mode === null ? sourceInfo.mode & 0o777 : mode,
191
+ label: `${label} target`,
192
+ })
193
+ }
194
+
195
+ function safeReplaceTree({ sourceRoot, source, targetRoot, target, label }) {
196
+ assertSafeTree(sourceRoot, source, `${label} source`)
197
+ assertNoSymlinkPath(targetRoot, target, `${label} target`)
198
+ if (pathEntryExists(target)) rmSync(target, { recursive: true, force: true })
199
+ mkdirSync(dirname(target), { recursive: true })
200
+ assertNoSymlinkPath(targetRoot, dirname(target), `${label} target parent`, { allowMissing: false })
201
+ cpSync(source, target, { recursive: true })
202
+ }
203
+
204
+ // Claude Code 的 .claude/settings.json 允許 JSONC(// 行註解 / block 註解)→ JSON.parse 會炸。
205
+ // string-aware strip 註解後再 parse(fork user 若註解過 settings,skeleton 刷新才不會默默 no-op)。
206
+ function parseJsonc(text, label) {
207
+ let out = '', inStr = false, inLine = false, inBlock = false
208
+ for (let i = 0; i < text.length; i++) {
209
+ const c = text[i], n = text[i + 1]
210
+ if (inLine) { if (c === '\n') { inLine = false; out += c } continue }
211
+ if (inBlock) { if (c === '*' && n === '/') { inBlock = false; i++ } continue }
212
+ if (inStr) { out += c; if (c === '\\') out += text[++i] ?? ''; else if (c === '"') inStr = false; continue }
213
+ if (c === '"') { inStr = true; out += c; continue }
214
+ if (c === '/' && n === '/') { inLine = true; i++; continue }
215
+ if (c === '/' && n === '*') { inBlock = true; i++; continue }
216
+ out += c
217
+ }
218
+ try { return JSON.parse(out) } catch (e) { throw new Error(`${label} JSONC strip 後仍非法 JSON:${e.message}`) }
219
+ }
220
+
221
+ const LAUNCHERS = ['fork-governance-dispatcher.sh', 'inject_fork_governance_preamble.sh']
222
+ const CLAUDE_PERMISSION_POLICY_SOURCE = 'packages/design-system/ds-canonical/adapters/claude-settings-base.json'
223
+ const escRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
224
+ // path-segment 比對:啟動器必以 `/<name>` 出現且後接邊界(引號/空白/結尾)。
225
+ // 避免 loose substring 誤刪「command 只是『含』啟動器名為子字串」的 user hook(adversarial FINDING 2b)。
226
+ const refsLauncher = (cmd) => LAUNCHERS.some((l) => new RegExp(`/${escRe(l)}(?=["'\\s]|$)`).test(cmd || ''))
227
+ const refsManagedRepositoryPath = (cmd, path) => {
228
+ const variants = [path, `./${path}`, `$CLAUDE_PROJECT_DIR/${path}`, `\${CLAUDE_PROJECT_DIR}/${path}`]
229
+ return variants.some((candidate) => new RegExp(`(?:^|["'\\s])${escRe(candidate)}(?=["'\\s]|$)`).test(cmd || ''))
230
+ }
231
+
232
+ /**
233
+ * Pure materializer for one validated merge-hook-map-into-base-v1 surface. The caller owns file
234
+ * authentication and atomic replacement; this function deliberately selects behavior from the
235
+ * registered materializer/base-template engines, never from a provider id.
236
+ */
237
+ export function mergeProviderHookSettings({ settings, canonicalConfig, policy, label = 'provider hook settings' } = {}) {
238
+ if (!settings || typeof settings !== 'object' || Array.isArray(settings)) throw new Error(`${label} must be an object`)
239
+ if (!canonicalConfig || typeof canonicalConfig !== 'object' || Array.isArray(canonicalConfig)) throw new Error(`${label} canonical config must be an object`)
240
+ if (
241
+ policy?.materializer?.engine !== 'json-hook-map-v1'
242
+ || policy.materializer.mergeStrategy !== 'merge-hook-map-into-base-v1'
243
+ || typeof policy.materializer.hooksField !== 'string'
244
+ || !policy.baseTemplate
245
+ ) throw new Error(`${label} has no supported registered merge materializer`)
246
+ const merged = structuredClone(settings)
247
+ const hooksField = policy.materializer.hooksField
248
+ const priorHooks = merged[hooksField]
249
+ if (priorHooks !== undefined && (!priorHooks || typeof priorHooks !== 'object' || Array.isArray(priorHooks))) {
250
+ throw new Error(`${label} ${hooksField} must be an object`)
251
+ }
252
+ const retiredIds = []
253
+ // F6 fail-closed:canonical hook map 必須存在、非空,且每 event 都是非空合形的 group 陣列。
254
+ // 寬鬆 fallback(`|| {}` / `Array.isArray ? : []`)會把「看不懂的另一世代 artifact 形狀」當
255
+ // 「零 hooks」:下方 strip(canonicalCommands / refsLauncher)照跑、append 卻是空 → 靜默清空
256
+ // 治理 hooks(WM 1f71fec 同型事故)。禁止。
257
+ const canonicalHookMap = canonicalConfig[hooksField]
258
+ if (!canonicalHookMap || typeof canonicalHookMap !== 'object' || Array.isArray(canonicalHookMap) || !Object.keys(canonicalHookMap).length) {
259
+ throw new Error(
260
+ `${label}: canonical hook artifact carries no non-empty ${JSON.stringify(hooksField)} map — the installed corpus uses a schema generation this scripts/refresh-fork-launchers.mjs does not understand; `
261
+ + 'refusing to write (an empty merge would silently strip every governance hook). '
262
+ + 'Migrate the fork scaffold to the matching generation first (npm run sync-all -- --apply --to <exact-version>).'
263
+ )
264
+ }
265
+ const canonicalCommands = new Set()
266
+ for (const [event, groups] of Object.entries(canonicalHookMap)) {
267
+ if (!Array.isArray(groups) || !groups.length) throw new Error(`${label} canonical ${hooksField}.${event} must be a non-empty array`)
268
+ for (const group of groups) {
269
+ if (!group || typeof group !== 'object' || Array.isArray(group) || !Array.isArray(group.hooks) || !group.hooks.length) {
270
+ throw new Error(`${label} canonical ${hooksField}.${event} contains an invalid or empty hook group`)
271
+ }
272
+ for (const handler of group.hooks) {
273
+ if (typeof handler?.command !== 'string' || !handler.command) throw new Error(`${label} canonical ${hooksField}.${event} contains a hook without a command`)
274
+ canonicalCommands.add(handler.command)
275
+ }
276
+ }
277
+ }
278
+ const retainedHooks = {}
279
+ for (const groups of Object.values(priorHooks || {})) for (const group of Array.isArray(groups) ? groups : []) {
280
+ for (const handler of Array.isArray(group?.hooks) ? group.hooks : []) {
281
+ const retired = policy.retiredHookRegistrations.find((record) => refsManagedRepositoryPath(handler?.command, record.path))
282
+ if (retired && !retiredIds.includes(retired.id)) retiredIds.push(retired.id)
283
+ }
284
+ }
285
+
286
+ for (const [event, groups] of Object.entries(priorHooks || {})) {
287
+ if (!Array.isArray(groups)) throw new Error(`${label} ${hooksField}.${event} must be an array`)
288
+ const retainedGroups = []
289
+ for (const group of groups) {
290
+ if (!group || typeof group !== 'object' || Array.isArray(group) || !Array.isArray(group.hooks)) {
291
+ throw new Error(`${label} ${hooksField}.${event} contains an invalid hook group`)
292
+ }
293
+ const hooks = group.hooks.filter((handler) => {
294
+ const command = handler?.command
295
+ if (typeof command !== 'string') return true
296
+ if (canonicalCommands.has(command) || refsLauncher(command)) return false
297
+ return !policy.retiredHookRegistrations.some((record) => refsManagedRepositoryPath(command, record.path))
298
+ })
299
+ if (hooks.length) retainedGroups.push({ ...structuredClone(group), hooks: structuredClone(hooks) })
300
+ }
301
+ if (retainedGroups.length) retainedHooks[event] = retainedGroups
302
+ }
303
+
304
+ // Remove only previously managed/retired registrations, retain consumer-owned hooks, then append
305
+ // the authenticated canonical groups exactly once. This keeps refresh idempotent without turning
306
+ // a provider adapter update into authority over unrelated product automation.
307
+ merged[hooksField] = retainedHooks
308
+ for (const [event, groups] of Object.entries(canonicalHookMap)) {
309
+ merged[hooksField][event] = [...(merged[hooksField][event] || []), ...structuredClone(groups)]
310
+ }
311
+ // Never-empty postcondition(F6 迴歸絆網):merge 結果必含每個 canonical event 的註冊,
312
+ // 否則代表上游 shape 判定失守 → 寧可 throw 也不寫出被清空的 hook surface。
313
+ for (const event of Object.keys(canonicalHookMap)) {
314
+ if (!Array.isArray(merged[hooksField][event]) || !merged[hooksField][event].length) {
315
+ throw new Error(`${label}: merged ${hooksField}.${event} lost its canonical registrations — refusing to write an emptied hook surface`)
316
+ }
317
+ }
318
+ for (const [key, value] of Object.entries(canonicalConfig)) {
319
+ if (key === hooksField || key === 'permissions' || key === 'disableAutoMode') continue
320
+ merged[key] = structuredClone(value)
321
+ }
322
+ if (policy.baseTemplate.engine === 'claude-permission-policy-v1') {
323
+ if (merged.permissions !== undefined && (!merged.permissions || typeof merged.permissions !== 'object' || Array.isArray(merged.permissions))) {
324
+ throw new Error(`${label} permissions must be an object`)
325
+ }
326
+ merged.permissions = merged.permissions || {}
327
+ for (const key of ['allow', 'ask', 'deny']) {
328
+ if (merged.permissions[key] !== undefined && !Array.isArray(merged.permissions[key])) throw new Error(`${label} permissions.${key} must be an array`)
329
+ if ((merged.permissions[key] || []).some((rule) => typeof rule !== 'string')) throw new Error(`${label} permissions.${key} must contain only strings`)
330
+ }
331
+ const canonicalPermissions = canonicalConfig.permissions
332
+ if (!canonicalPermissions || typeof canonicalPermissions !== 'object' || Array.isArray(canonicalPermissions)) {
333
+ throw new Error(`${label} canonical permission base is missing`)
334
+ }
335
+ const retiredAllow = new Set(policy.permissionPolicy.retiredPermissionAllow)
336
+ const nextDeny = Array.from(new Set([...(canonicalPermissions.deny || []), ...(merged.permissions.deny || [])]))
337
+ const nextDenySet = new Set(nextDeny)
338
+ // Human-only ask semantics are policy-owned. Retaining arbitrary historical consumer asks would
339
+ // let an old provider config reintroduce engineering approval milestones after the canonical
340
+ // Standing Authorization delegated them. Consumer-specific safety may remain a stricter deny;
341
+ // ask is always the authenticated canonical set.
342
+ const nextAsk = Array.from(new Set(canonicalPermissions.ask || []))
343
+ .filter((rule) => !nextDenySet.has(rule))
344
+ const nextAskSet = new Set(nextAsk)
345
+ merged.permissions.allow = Array.from(new Set([
346
+ ...(merged.permissions.allow || []).filter((rule) => !retiredAllow.has(rule)),
347
+ ...(canonicalPermissions.allow || []),
348
+ ])).filter((rule) => !nextAskSet.has(rule) && !nextDenySet.has(rule))
349
+ merged.permissions.ask = nextAsk
350
+ merged.permissions.deny = nextDeny
351
+ merged.permissions.defaultMode = canonicalPermissions.defaultMode
352
+ merged.permissions.disableBypassPermissionsMode = canonicalPermissions.disableBypassPermissionsMode
353
+ if (Object.hasOwn(canonicalConfig, 'disableAutoMode')) throw new Error(`${label} canonical permission base carries the retired disableAutoMode flag`)
354
+ delete merged.disableAutoMode
355
+ delete merged.permissions.disableAutoMode
356
+ delete merged.defaultMode
357
+ } else if (policy.baseTemplate.engine === 'static-json-object-v1') {
358
+ if (policy.permissionPolicy !== null) throw new Error(`${label} static base template may not claim a permission policy`)
359
+ for (const [key, value] of Object.entries(canonicalConfig)) if (key !== hooksField) merged[key] = structuredClone(value)
360
+ } else {
361
+ throw new Error(`${label} base-template engine is unsupported:${policy.baseTemplate.engine}`)
362
+ }
363
+ return { settings: merged, retiredIds: retiredIds.sort() }
364
+ }
365
+
366
+ // ── F6 fail-closed schema generation gate(WM commit 1f71fec 教訓)──
367
+ // 舊代 refresh 對新代 settings-hooks.json 用 `canonical.hooks || {}` 寬鬆 fallback,把「看不懂的
368
+ // 另一世代 schema」當「零 hooks」:strip 舊治理註冊照跑、append 卻是空 → 靜默清空
369
+ // .claude/settings.json hooks = Claude 端治理整條斷線。本 gate 是唯一 generation 判定 SSOT:
370
+ // kind + schemaVersion 必須 exact match 本腳本世代,否則丟含遷移指引的錯誤;絕不寫檔。
371
+ export const SETTINGS_HOOKS_KIND = 'provider-hook-merge-policies'
372
+ export const SETTINGS_HOOKS_SCHEMA_VERSION = 1
373
+
374
+ export function assertSupportedSettingsHooksGeneration(value, label = 'installed launchers/settings-hooks.json') {
375
+ const record = value && typeof value === 'object' && !Array.isArray(value) ? value : {}
376
+ if (record.kind === SETTINGS_HOOKS_KIND && record.schemaVersion === SETTINGS_HOOKS_SCHEMA_VERSION) return
377
+ throw new Error(
378
+ `${label} declares kind=${JSON.stringify(record.kind ?? null)} schemaVersion=${JSON.stringify(record.schemaVersion ?? null)}, `
379
+ + `but this scripts/refresh-fork-launchers.mjs generation understands exactly ${SETTINGS_HOOKS_KIND}@${SETTINGS_HOOKS_SCHEMA_VERSION}. `
380
+ + 'Refusing to merge provider hooks; nothing was written. Merging an ununderstood generation is exactly how an older scaffold silently emptied .claude/settings.json hooks. '
381
+ + 'Migrate this fork scaffold to the generation matching the installed corpus first (npm run sync-all -- --apply --to <exact-version>), then re-run.'
382
+ )
383
+ }
384
+
385
+ export function validateCanonicalSettingsWiring(value, manifest) {
386
+ assertSupportedSettingsHooksGeneration(value)
387
+ exactKeys(value, ['_generated', 'kind', 'schemaVersion', 'sourceDigest', 'surfaces'], 'installed provider hook merge policies')
388
+ if (
389
+ value._generated !== 'build-fork-governance.mjs'
390
+ || value.kind !== 'provider-hook-merge-policies'
391
+ || value.schemaVersion !== 1
392
+ || !SHA256.test(value.sourceDigest || '')
393
+ || !value.surfaces
394
+ || typeof value.surfaces !== 'object'
395
+ || Array.isArray(value.surfaces)
396
+ ) throw new Error('installed provider hook merge policy identity is invalid')
397
+ const expectedProviderIds = Object.entries(manifest?.providerSurfaces || {})
398
+ .filter(([, surface]) => surface.generated && surface.hookMaterializerId)
399
+ .filter(([providerId, surface]) => resolveManifestMaterializer(
400
+ manifest,
401
+ 'hookViews',
402
+ surface.hookMaterializerId,
403
+ `${providerId}.hookMaterializerId`,
404
+ ).mergeStrategy === 'merge-hook-map-into-base-v1')
405
+ .map(([providerId]) => providerId)
406
+ .sort()
407
+ if (JSON.stringify(Object.keys(value.surfaces).sort()) !== JSON.stringify(expectedProviderIds)) {
408
+ throw new Error('installed provider hook merge policies do not exactly match merge-capable provider surfaces')
409
+ }
410
+ const surfaces = {}
411
+ for (const providerId of expectedProviderIds) {
412
+ const record = value.surfaces[providerId]
413
+ exactKeys(record, [
414
+ 'baseTemplateContract', 'hookArtifact', 'hookDestination', 'hookMaterializerId', 'mergeStrategy',
415
+ 'permissionPolicy', 'retiredHookRegistrations', 'schemaVersion',
416
+ ], `installed hook merge policy ${providerId}`)
417
+ const surface = manifest.providerSurfaces[providerId]
418
+ const materializer = resolveManifestMaterializer(manifest, 'hookViews', record.hookMaterializerId, `${providerId}.hookMaterializerId`)
419
+ const baseTemplate = resolveManifestMaterializer(manifest, 'hookBaseTemplateContracts', record.baseTemplateContract, `${providerId}.baseTemplateContract`)
420
+ if (
421
+ record.schemaVersion !== 1
422
+ || record.hookArtifact !== surface.hookArtifact
423
+ || record.hookDestination !== surface.hookDestination
424
+ || record.hookMaterializerId !== surface.hookMaterializerId
425
+ || record.mergeStrategy !== 'merge-hook-map-into-base-v1'
426
+ || materializer.mergeStrategy !== record.mergeStrategy
427
+ || materializer.baseTemplateContract !== record.baseTemplateContract
428
+ || materializer.engine !== 'json-hook-map-v1'
429
+ ) throw new Error(`${providerId}:installed hook merge policy differs from its provider materializer`)
430
+ if (!Array.isArray(record.retiredHookRegistrations)) throw new Error(`${providerId}:retired hook registration inventory is invalid`)
431
+ const retirements = record.retiredHookRegistrations.map((retirement, index) => {
432
+ exactKeys(retirement, ['id', 'path', 'provider', 'reasonCode'], `${providerId} retired hook registration[${index}]`)
433
+ const path = normalizeRepositoryRelative(retirement.path, `${providerId} retired hook registration[${index}].path`)
434
+ if (
435
+ retirement.provider !== providerId
436
+ || !/^[a-z][a-z0-9-]*$/.test(retirement.id || '')
437
+ || !/^[A-Z][A-Z0-9_]*$/.test(retirement.reasonCode || '')
438
+ ) throw new Error(`${providerId}:retired hook registration[${index}] is invalid`)
439
+ return { ...retirement, path }
440
+ })
441
+ if (
442
+ JSON.stringify(retirements.map((item) => item.id)) !== JSON.stringify(retirements.map((item) => item.id).sort())
443
+ || new Set(retirements.map((item) => portableRepositoryPathKey(item.path))).size !== retirements.length
444
+ ) throw new Error(`${providerId}:retired hook registrations must be sorted by id and unique by path`)
445
+ if (baseTemplate.engine === 'claude-permission-policy-v1') {
446
+ exactKeys(record.permissionPolicy, ['retiredPermissionAllow', 'sha256', 'source'], `${providerId} permission policy`)
447
+ if (
448
+ record.permissionPolicy.source !== baseTemplate.source
449
+ || !SHA256.test(record.permissionPolicy.sha256 || '')
450
+ || !Array.isArray(record.permissionPolicy.retiredPermissionAllow)
451
+ || record.permissionPolicy.retiredPermissionAllow.length === 0
452
+ || record.permissionPolicy.retiredPermissionAllow.some((rule) => typeof rule !== 'string' || !/^Bash\(.+\)$/.test(rule))
453
+ ) throw new Error(`${providerId}:permission policy binding is invalid`)
454
+ } else if (record.permissionPolicy !== null) throw new Error(`${providerId}:non-permission base template may not claim a permission policy`)
455
+ surfaces[providerId] = { ...record, retiredHookRegistrations: retirements, materializer, baseTemplate }
456
+ }
457
+ return { ...value, surfaces }
458
+ }
459
+
460
+ const safeRelative = (root, value) => {
461
+ try {
462
+ const normalized = normalizeRepositoryRelative(value)
463
+ return resolve(root, normalized).startsWith(resolve(root) + sep)
464
+ } catch { return false }
465
+ }
466
+
467
+ const SHA256 = /^[a-f0-9]{64}$/
468
+ const EXACT_SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\+[0-9A-Za-z.-]+)?$/
469
+ const stableVersionAtLeast = (value, minimum) => {
470
+ const parse = version => typeof version === 'string'
471
+ ? version.match(/^(\d+)\.(\d+)\.(\d+)(?:\+[0-9A-Za-z.-]+)?$/)?.slice(1, 4).map(Number)
472
+ : null
473
+ const observed = parse(value)
474
+ const required = parse(minimum)
475
+ if (!observed || !required) return false
476
+ for (let index = 0; index < 3; index += 1) {
477
+ if (observed[index] !== required[index]) return observed[index] > required[index]
478
+ }
479
+ return true
480
+ }
481
+ const DISCOVERY_KEYS = Object.freeze([
482
+ 'providerRootNames', 'instructionNames', 'instructionOverrideNames', 'configPaths', 'pluginRootNames',
483
+ ])
484
+ const DISCOVERY_PATTERNS = Object.freeze({
485
+ providerRootNames: /^\.(?!git(?:hub)?$)[A-Za-z0-9][A-Za-z0-9_-]*$/,
486
+ instructionNames: /^[A-Za-z0-9][A-Za-z0-9_.@-]*\.md$/,
487
+ instructionOverrideNames: /^[A-Za-z0-9][A-Za-z0-9_.@-]*\.md$/,
488
+ configPaths: /^\.(?:[A-Za-z0-9][A-Za-z0-9_.@-]*|[A-Za-z0-9][A-Za-z0-9_-]*\/[A-Za-z0-9_.@/-]+)$/,
489
+ pluginRootNames: /^\.(?!git(?:hub)?$)[A-Za-z0-9][A-Za-z0-9_-]*$/,
490
+ })
491
+ const PROTECTED_PRODUCT_DOCUMENTS = new Set(['CHANGELOG.md', 'CODE_OF_CONDUCT.md', 'CONTRIBUTING.md', 'LICENSE.md', 'README.md', 'SECURITY.md'].map((path) => portableRepositoryPathKey(path)))
492
+ const sha256 = (content) => createHash('sha256').update(content).digest('hex')
493
+ const fileSha256 = (path) => sha256(readFileSync(path))
494
+ const exactKeys = (value, keys, label) => {
495
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object`)
496
+ if (JSON.stringify(Object.keys(value).sort()) !== JSON.stringify([...keys].sort())) throw new Error(`${label} has an open or incomplete shape`)
497
+ return value
498
+ }
499
+ // Structural/tamper mirror only. Canonical selection and certification semantics remain owned by
500
+ // packages/governance/src/provider-review-binding.mjs after the shipped corpus is authenticated.
501
+ const stableProjectionValue = (value) => {
502
+ if (Array.isArray(value)) return value.map(stableProjectionValue)
503
+ if (value && typeof value === 'object') {
504
+ return Object.fromEntries(
505
+ Object.keys(value).sort(compareUtf8Bytes).map((key) => [key, stableProjectionValue(value[key])]),
506
+ )
507
+ }
508
+ return value
509
+ }
510
+ const validateReviewInvocation = (value, label) => {
511
+ if (value?.strategy === 'main-context') {
512
+ exactKeys(value, ['strategy'], label)
513
+ return value
514
+ }
515
+ exactKeys(value, ['agent', 'context', 'strategy'], label)
516
+ if (
517
+ value.strategy !== 'native-context-fork'
518
+ || value.context !== 'fork'
519
+ || !/^[a-z][a-z0-9-]*$/.test(value.agent || '')
520
+ ) throw new Error(`${label} is invalid`)
521
+ return value
522
+ }
523
+ const validateIndependentReviewProjection = (value) => {
524
+ exactKeys(value, [
525
+ 'bindings', 'certificationContract', 'certifications', 'kind', 'projectionDigest',
526
+ 'providerCompatibility', 'repositoryRole', 'schemaVersion', 'skill',
527
+ ], 'installed independent-review projection')
528
+ if (
529
+ value.schemaVersion !== 2
530
+ || value.kind !== 'provider-neutral-independent-review-projection'
531
+ || value.skill !== 'independent-review'
532
+ || value.repositoryRole !== 'product-consumer'
533
+ || value.certificationContract !== 'exact-provider-runtime-surface-role-target-v1'
534
+ || !SHA256.test(value.projectionDigest || '')
535
+ || !Array.isArray(value.bindings)
536
+ || value.bindings.length === 0
537
+ || !Array.isArray(value.providerCompatibility)
538
+ || value.providerCompatibility.length === 0
539
+ || !Array.isArray(value.certifications)
540
+ ) throw new Error('installed independent-review projection is invalid')
541
+ const bindingIds = []
542
+ for (const [index, binding] of value.bindings.entries()) {
543
+ exactKeys(binding, [
544
+ 'bindingDigest', 'certificationContract', 'invocation', 'requiredAssuranceTier',
545
+ 'requiredComputeTier', 'requiredReasoningTier', 'reviewClass', 'selectionPolicy',
546
+ 'selfProviderId', 'transport',
547
+ ], `installed independent-review binding[${index}]`)
548
+ if (
549
+ !/^[a-z][a-z0-9-]*$/.test(binding.selfProviderId || '')
550
+ || !/^[a-z][a-z0-9-]*-v[1-9][0-9]*$/.test(binding.selectionPolicy || '')
551
+ || binding.reviewClass !== 'tier-0-governance'
552
+ || binding.requiredAssuranceTier !== 'maximum'
553
+ || binding.requiredReasoningTier !== 'maximum'
554
+ || binding.requiredComputeTier !== 'maximum'
555
+ || binding.transport !== 'content-addressed-model-broker-exchange-v1'
556
+ || binding.certificationContract !== 'exact-provider-runtime-surface-role-target-v1'
557
+ || !SHA256.test(binding.bindingDigest || '')
558
+ ) throw new Error(`installed independent-review binding[${index}] is invalid`)
559
+ validateReviewInvocation(binding.invocation, `installed independent-review binding[${index}].invocation`)
560
+ bindingIds.push(binding.selfProviderId)
561
+ }
562
+ const compatibilityProviderIds = []
563
+ const compatibilityRuntimeIds = []
564
+ for (const [index, compatibility] of value.providerCompatibility.entries()) {
565
+ exactKeys(compatibility, ['compatibilityProviderId', 'providerId'], `installed independent-review provider compatibility[${index}]`)
566
+ if (
567
+ !/^[a-z][a-z0-9-]*$/.test(compatibility.providerId || '')
568
+ || !/^[a-z][a-z0-9-]*$/.test(compatibility.compatibilityProviderId || '')
569
+ ) throw new Error(`installed independent-review provider compatibility[${index}] is invalid`)
570
+ compatibilityProviderIds.push(compatibility.providerId)
571
+ compatibilityRuntimeIds.push(compatibility.compatibilityProviderId)
572
+ }
573
+ if (
574
+ JSON.stringify(bindingIds) !== JSON.stringify([...new Set(bindingIds)].sort(compareUtf8Bytes))
575
+ || JSON.stringify(compatibilityProviderIds) !== JSON.stringify([...new Set(compatibilityProviderIds)].sort(compareUtf8Bytes))
576
+ || new Set(compatibilityRuntimeIds).size !== compatibilityRuntimeIds.length
577
+ || bindingIds.some((providerId) => !compatibilityProviderIds.includes(providerId))
578
+ ) throw new Error('installed independent-review provider compatibility is incomplete or ambiguous')
579
+ const expectedDigest = sha256(JSON.stringify(stableProjectionValue({
580
+ skill: value.skill,
581
+ repositoryRole: value.repositoryRole,
582
+ bindings: value.bindings,
583
+ providerCompatibility: value.providerCompatibility,
584
+ certifications: value.certifications,
585
+ })))
586
+ if (value.projectionDigest !== expectedDigest) throw new Error('installed independent-review projection digest is invalid')
587
+ return value
588
+ }
589
+ const regularUnaliasedFile = (root, path, label) => {
590
+ assertNoSymlinkPath(root, path, label, { allowMissing: false })
591
+ const info = lstatSync(path)
592
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) throw new Error(`${label} must be one regular unaliased file`)
593
+ return path
594
+ }
595
+ const validateSurface = (surface, label) => {
596
+ exactKeys(surface, ['kind', 'path'], label)
597
+ if (!['file', 'tree'].includes(surface.kind)) throw new Error(`${label}.kind is invalid`)
598
+ const normalized = normalizeRepositoryRelative(surface.path, `${label}.path`)
599
+ const portable = portableRepositoryPathKey(normalized)
600
+ if (['.git', '.github'].includes(portable.split('/')[0])) throw new Error(`${label}.path addresses a protected Git root`)
601
+ if (PROTECTED_PRODUCT_DOCUMENTS.has(portable)) throw new Error(`${label}.path addresses a protected product document`)
602
+ return { path: normalized, kind: surface.kind }
603
+ }
604
+ const validateRetiredSurface = (surface, label) => {
605
+ exactKeys(surface, ['kind', 'path', 'sha256'], label)
606
+ if (!SHA256.test(surface.sha256 || '')) throw new Error(`${label}.sha256 is invalid`)
607
+ return { ...validateSurface({ path: surface.path, kind: surface.kind }, label), sha256: surface.sha256 }
608
+ }
609
+ export function providerSurfaceDigest(projectDir, surface) {
610
+ projectDir = canonicalRepositoryRoot(projectDir)
611
+ const normalized = validateSurface({ path: surface.path, kind: surface.kind }, 'provider digest surface')
612
+ const target = join(projectDir, normalized.path)
613
+ assertNoSymlinkPath(projectDir, target, `provider digest target ${normalized.path}`, { allowMissing: false })
614
+ const info = lstatSync(target)
615
+ if (normalized.kind === 'file') {
616
+ if (!info.isFile() || info.nlink !== 1) throw new Error(`provider digest file is not regular and unaliased:${normalized.path}`)
617
+ return fileSha256(target)
618
+ }
619
+ if (!info.isDirectory()) throw new Error(`provider digest tree is not a directory:${normalized.path}`)
620
+ const rows = []
621
+ const visit = (absolute) => {
622
+ const entry = lstatSync(absolute)
623
+ const rel = relative(target, absolute).split(sep).join('/') || '.'
624
+ const mode = (entry.mode & 0o777).toString(8).padStart(4, '0')
625
+ if (entry.isDirectory()) {
626
+ rows.push(`dir:${rel}:${mode}`)
627
+ for (const name of readdirSync(absolute).sort()) visit(join(absolute, name))
628
+ } else if (entry.isFile() && entry.nlink === 1) rows.push(`file:${rel}:${mode}:${fileSha256(absolute)}`)
629
+ else throw new Error(`provider digest tree contains unsafe entry:${normalized.path}/${rel}`)
630
+ }
631
+ visit(target)
632
+ return sha256(rows.join('\n') + '\n')
633
+ }
634
+ const sortedUniqueStrings = (values, label) => {
635
+ if (!Array.isArray(values) || values.some((value) => typeof value !== 'string')) throw new Error(`${label} must be a string array`)
636
+ if (JSON.stringify(values) !== JSON.stringify([...new Set(values)].sort())) throw new Error(`${label} must be sorted and unique`)
637
+ return values
638
+ }
639
+ const validateDiscovery = (discovery, label) => {
640
+ exactKeys(discovery, DISCOVERY_KEYS, label)
641
+ for (const key of DISCOVERY_KEYS) validateDiscoveryEntries(discovery[key], key, `${label}.${key}`)
642
+ return discovery
643
+ }
644
+ const validateDiscoveryEntries = (values, key, label) => {
645
+ const entries = sortedUniqueStrings(values, label)
646
+ const portable = new Set()
647
+ for (const [index, entry] of entries.entries()) {
648
+ const normalized = normalizeRepositoryRelative(entry, `${label}[${index}]`)
649
+ if (normalized !== entry || !DISCOVERY_PATTERNS[key].test(entry)) {
650
+ throw new Error(`${label}[${index}] is not a canonical ${key} discovery path`)
651
+ }
652
+ const alias = portableRepositoryPathKey(normalized)
653
+ if (portable.has(alias)) throw new Error(`${label} contains a portable alias:${entry}`)
654
+ portable.add(alias)
655
+ }
656
+ return entries
657
+ }
658
+ const validateDiscoveryPolicy = (policy, label) => {
659
+ exactKeys(policy, ['schemaVersion', ...DISCOVERY_KEYS], label)
660
+ if (policy.schemaVersion !== 1) throw new Error(`${label}.schemaVersion is unsupported`)
661
+ for (const key of DISCOVERY_KEYS) validateDiscoveryEntries(policy[key], key, `${label}.${key}`)
662
+ return policy
663
+ }
664
+ const assertSnapshotDiscoveryWithinPolicy = (snapshot, policy, label) => {
665
+ const records = [
666
+ ...snapshot.providers.map((provider) => ({ ...provider, lifecycleRole: 'provider' })),
667
+ ...snapshot.retiredProviders.map((retirement) => ({ ...retirement, lifecycleRole: 'retirement' })),
668
+ ]
669
+ for (const record of records) for (const key of DISCOVERY_KEYS) {
670
+ const allowed = new Set(policy[key].map(portableRepositoryPathKey))
671
+ for (const entry of record.discovery[key]) if (!allowed.has(portableRepositoryPathKey(entry))) {
672
+ throw new Error(`${label}.${record.lifecycleRole}.${record.id}.discovery.${key} is outside the signed global discovery policy:${entry}`)
673
+ }
674
+ }
675
+ }
676
+ const snapshotActiveSurfaceView = (snapshot) => snapshot.providers.map((provider) => ({
677
+ id: provider.id,
678
+ surfaces: provider.surfaces.map(({ path, kind }) => ({ path, kind })),
679
+ }))
680
+ const discoveryPolicyReservesPath = (policy, path) => {
681
+ const pathKey = portableRepositoryPathKey(normalizeRepositoryRelative(path, 'discovery-reserved path'))
682
+ const treeRoots = [...policy.providerRootNames, ...policy.pluginRootNames].map(portableRepositoryPathKey)
683
+ if (treeRoots.some((root) => pathKey === root || pathKey.startsWith(`${root}/`))) return true
684
+ return [
685
+ ...policy.instructionNames,
686
+ ...policy.instructionOverrideNames,
687
+ ...policy.configPaths,
688
+ ].some((candidate) => portableRepositoryPathKey(candidate) === pathKey)
689
+ }
690
+ const validateProviderMaterializers = (catalog, label = 'provider materializers') => {
691
+ const groups = ['instructionViews', 'hookBaseTemplateContracts', 'hookViews', 'skillViews', 'treeViews']
692
+ exactKeys(catalog, groups, label)
693
+ for (const group of groups) {
694
+ if (!catalog[group] || typeof catalog[group] !== 'object' || Array.isArray(catalog[group]) || !Object.keys(catalog[group]).length) {
695
+ throw new Error(`${label}.${group} must be a non-empty object`)
696
+ }
697
+ }
698
+ const validId = (id, group) => {
699
+ if (!/^[a-z][a-z0-9-]*-v[1-9][0-9]*$/.test(id)) throw new Error(`${label}.${group} has invalid id:${id}`)
700
+ }
701
+ for (const [id, materializer] of Object.entries(catalog.instructionViews)) {
702
+ validId(id, 'instructionViews')
703
+ exactKeys(materializer, ['engine', 'ownershipPolicy', 'supplementPolicy'], `${label}.instructionViews.${id}`)
704
+ if (!['shared-instruction-v1', 'markdown-relative-at-import-v1'].includes(materializer.engine)) throw new Error(`${label}.instructionViews.${id} has unsupported engine`)
705
+ if (!['forbidden', 'optional', 'required'].includes(materializer.supplementPolicy)) throw new Error(`${label}.instructionViews.${id}.supplementPolicy is invalid`)
706
+ if (materializer.engine === 'shared-instruction-v1' && (materializer.supplementPolicy !== 'forbidden' || materializer.ownershipPolicy !== 'common-authority-consumer')) throw new Error(`${label}.instructionViews.${id} shared instruction contract is invalid`)
707
+ if (materializer.engine === 'markdown-relative-at-import-v1' && materializer.ownershipPolicy !== 'provider-generated-projection') throw new Error(`${label}.instructionViews.${id} projection ownership is invalid`)
708
+ }
709
+ const commonInstructionMaterializers = Object.entries(catalog.instructionViews).filter(([, materializer]) => (
710
+ materializer.engine === 'shared-instruction-v1'
711
+ && materializer.ownershipPolicy === 'common-authority-consumer'
712
+ ))
713
+ if (commonInstructionMaterializers.length !== 1) {
714
+ throw new Error(`${label}.instructionViews must declare exactly one common-authority shared instruction materializer`)
715
+ }
716
+ for (const [id, contract] of Object.entries(catalog.hookBaseTemplateContracts)) {
717
+ validId(id, 'hookBaseTemplateContracts')
718
+ if (contract?.engine === 'claude-permission-policy-v1') {
719
+ exactKeys(contract, ['engine', 'schema', 'source'], `${label}.hookBaseTemplateContracts.${id}`)
720
+ if (contract.source !== CLAUDE_PERMISSION_POLICY_SOURCE || typeof contract.schema !== 'string' || !contract.schema) throw new Error(`${label}.hookBaseTemplateContracts.${id} is invalid`)
721
+ } else if (contract?.engine === 'static-json-object-v1') exactKeys(contract, ['engine'], `${label}.hookBaseTemplateContracts.${id}`)
722
+ else throw new Error(`${label}.hookBaseTemplateContracts.${id} has unsupported engine`)
723
+ }
724
+ for (const [id, materializer] of Object.entries(catalog.hookViews)) {
725
+ validId(id, 'hookViews')
726
+ if (materializer?.engine === 'json-hook-map-v1') {
727
+ exactKeys(materializer, ['baseTemplateContract', 'descriptionField', 'engine', 'hooksField', 'mergeStrategy'], `${label}.hookViews.${id}`)
728
+ if (typeof materializer.hooksField !== 'string' || !materializer.hooksField) throw new Error(`${label}.hookViews.${id}.hooksField is invalid`)
729
+ } else if (materializer?.engine === 'json-hook-event-list-v1') {
730
+ exactKeys(materializer, ['baseTemplateContract', 'descriptionField', 'engine', 'eventField', 'eventsField', 'groupsField', 'handlerArgvField', 'handlersField', 'matcherField', 'mergeStrategy'], `${label}.hookViews.${id}`)
731
+ for (const field of ['eventField', 'eventsField', 'groupsField', 'handlerArgvField', 'handlersField', 'matcherField']) {
732
+ if (typeof materializer[field] !== 'string' || !materializer[field]) throw new Error(`${label}.hookViews.${id}.${field} is invalid`)
733
+ }
734
+ } else throw new Error(`${label}.hookViews.${id} has unsupported engine:${materializer?.engine || '<missing>'}`)
735
+ if (
736
+ (materializer.engine === 'json-hook-event-list-v1' && (typeof materializer.descriptionField !== 'string' || !materializer.descriptionField))
737
+ || (materializer.engine === 'json-hook-map-v1' && materializer.descriptionField !== null && (typeof materializer.descriptionField !== 'string' || !materializer.descriptionField))
738
+ ) {
739
+ throw new Error(`${label}.hookViews.${id}.descriptionField is invalid`)
740
+ }
741
+ if (!['merge-hook-map-into-base-v1', 'replace-document-v1'].includes(materializer.mergeStrategy)) throw new Error(`${label}.hookViews.${id}.mergeStrategy is invalid`)
742
+ if (materializer.mergeStrategy === 'merge-hook-map-into-base-v1') {
743
+ if (typeof materializer.baseTemplateContract !== 'string' || !catalog.hookBaseTemplateContracts[materializer.baseTemplateContract]) throw new Error(`${label}.hookViews.${id}.baseTemplateContract is invalid`)
744
+ } else if (materializer.baseTemplateContract !== null) throw new Error(`${label}.hookViews.${id} replace-document must not bind a base template`)
745
+ }
746
+ for (const [id, materializer] of Object.entries(catalog.skillViews)) {
747
+ validId(id, 'skillViews')
748
+ exactKeys(materializer, ['engine', 'entryFile'], `${label}.skillViews.${id}`)
749
+ if (materializer.engine !== 'skill-directory-v1') throw new Error(`${label}.skillViews.${id} has unsupported engine:${materializer.engine}`)
750
+ if (typeof materializer.entryFile !== 'string' || !/^[A-Za-z0-9._-]+\.md$/.test(materializer.entryFile)) {
751
+ throw new Error(`${label}.skillViews.${id}.entryFile is invalid`)
752
+ }
753
+ }
754
+ for (const [id, materializer] of Object.entries(catalog.treeViews)) {
755
+ validId(id, 'treeViews')
756
+ exactKeys(materializer, ['engine', 'transformPolicies'], `${label}.treeViews.${id}`)
757
+ if (materializer.engine !== 'closed-tree-copy-v1' || JSON.stringify(materializer.transformPolicies) !== JSON.stringify(['byte-exact'])) throw new Error(`${label}.treeViews.${id} is unsupported`)
758
+ }
759
+ return catalog
760
+ }
761
+ const resolveManifestMaterializer = (manifest, group, id, label) => {
762
+ const catalog = validateProviderMaterializers(manifest?.materializers, 'installed provider materializers')
763
+ if (typeof id !== 'string' || !Object.hasOwn(catalog[group] || {}, id)) {
764
+ throw new Error(`${label} references unknown ${group} materializer:${id || '<missing>'}`)
765
+ }
766
+ return catalog[group][id]
767
+ }
768
+ const compareVersion = (leftValue, rightValue) => {
769
+ const parse = (value) => {
770
+ const match = String(value || '').match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/)
771
+ return match ? { core: match.slice(1, 4).map(Number), pre: match[4]?.split('.') ?? null } : null
772
+ }
773
+ const left = parse(leftValue)
774
+ const right = parse(rightValue)
775
+ if (!left || !right) throw new Error(`provider transition releases must be exact semver:${leftValue}:${rightValue}`)
776
+ for (let index = 0; index < 3; index += 1) if (left.core[index] !== right.core[index]) return left.core[index] - right.core[index]
777
+ if (left.pre === null || right.pre === null) return left.pre === right.pre ? 0 : left.pre === null ? 1 : -1
778
+ for (let index = 0; index < Math.max(left.pre.length, right.pre.length); index += 1) {
779
+ if (left.pre[index] === undefined || right.pre[index] === undefined) return left.pre[index] === undefined ? -1 : 1
780
+ if (left.pre[index] === right.pre[index]) continue
781
+ const leftNumeric = /^\d+$/.test(left.pre[index])
782
+ const rightNumeric = /^\d+$/.test(right.pre[index])
783
+ if (leftNumeric && rightNumeric) return Number(left.pre[index]) - Number(right.pre[index])
784
+ if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1
785
+ return compareUtf8Bytes(left.pre[index], right.pre[index])
786
+ }
787
+ return 0
788
+ }
789
+
790
+ export function validateForkManifestProviderSurfaces(manifest, label = 'installed manifest') {
791
+ validateProviderMaterializers(manifest?.materializers, `${label}.materializers`)
792
+ const commonInstruction = exactKeys(manifest?.consumer?.commonInstruction, [
793
+ 'artifact', 'destination', 'materializerId', 'schemaVersion',
794
+ ], `${label}.consumer.commonInstruction`)
795
+ const commonMaterializer = resolveManifestMaterializer(
796
+ manifest,
797
+ 'instructionViews',
798
+ commonInstruction.materializerId,
799
+ `${label}.consumer.commonInstruction.materializerId`,
800
+ )
801
+ const commonDestination = normalizeRepositoryRelative(
802
+ commonInstruction.destination,
803
+ `${label}.consumer.commonInstruction.destination`,
804
+ )
805
+ if (
806
+ commonInstruction.schemaVersion !== 1
807
+ || commonInstruction.artifact !== 'common/instruction.md'
808
+ || commonInstruction.destination !== commonDestination
809
+ || commonMaterializer.engine !== 'shared-instruction-v1'
810
+ || commonMaterializer.ownershipPolicy !== 'common-authority-consumer'
811
+ ) throw new Error(`${label}.consumer.commonInstruction is not the closed common authority record`)
812
+ const providers = []
813
+ for (const [providerId, surface] of Object.entries(manifest?.providerSurfaces || {}).sort(([left], [right]) => compareUtf8Bytes(left, right))) {
814
+ const surfaceLabel = `${label}.providerSurfaces.${providerId}`
815
+ exactKeys(surface, [
816
+ 'capabilities', 'environmentMap', 'exclusions', 'generated', 'hookArtifact', 'hookDestination',
817
+ 'hookMaterializerId', 'instructionArtifact', 'instructionDestination', 'instructionMaterializerId', 'managedSurfaces', 'schemaVersion',
818
+ 'skillArtifactRoot', 'skillDestination', 'skillEntryFile', 'skillMaterializerId', 'skills', 'trees', 'nativeHookCoverage',
819
+ ], surfaceLabel)
820
+ if (surface.schemaVersion !== 3 || typeof surface.generated !== 'boolean' || !Array.isArray(surface.skills) || !Array.isArray(surface.trees) || !Array.isArray(surface.managedSurfaces)) {
821
+ throw new Error(`${surfaceLabel} identity is invalid`)
822
+ }
823
+ const managedSurfaces = surface.managedSurfaces.map((record, index) => validateSurface(record, `${surfaceLabel}.managedSurfaces[${index}]`))
824
+ if (JSON.stringify(managedSurfaces) !== JSON.stringify([...managedSurfaces].sort((left, right) => compareUtf8Bytes(left.path, right.path)))) {
825
+ throw new Error(`${surfaceLabel}.managedSurfaces must be sorted by path`)
826
+ }
827
+ if (new Set(managedSurfaces.map((record) => portableRepositoryPathKey(record.path))).size !== managedSurfaces.length) {
828
+ throw new Error(`${surfaceLabel}.managedSurfaces must be unique by path`)
829
+ }
830
+ for (let left = 0; left < managedSurfaces.length; left += 1) for (let right = left + 1; right < managedSurfaces.length; right += 1) {
831
+ if (repositoryPathsOverlap(managedSurfaces[left].path, managedSurfaces[right].path)) {
832
+ throw new Error(`${surfaceLabel}.managedSurfaces contain overlapping portable paths:${managedSurfaces[left].path} <> ${managedSurfaces[right].path}`)
833
+ }
834
+ }
835
+ if (!surface.generated) {
836
+ if (managedSurfaces.length) throw new Error(`${surfaceLabel} disabled provider may not claim managed surfaces`)
837
+ if (surface.trees.length || surface.nativeHookCoverage !== null) throw new Error(`${surfaceLabel} disabled provider may not claim materialized trees or native coverage`)
838
+ if (surface.instructionMaterializerId !== null || surface.hookMaterializerId !== null || surface.skillMaterializerId !== null || surface.skillEntryFile !== null) {
839
+ throw new Error(`${surfaceLabel} disabled provider may not bind materializers`)
840
+ }
841
+ continue
842
+ }
843
+ if (!managedSurfaces.length) throw new Error(`${surfaceLabel} generated provider needs managed surfaces`)
844
+ const instructionMaterializer = resolveManifestMaterializer(manifest, 'instructionViews', surface.instructionMaterializerId, `${surfaceLabel}.instructionMaterializerId`)
845
+ if (surface.hookMaterializerId !== null) {
846
+ resolveManifestMaterializer(manifest, 'hookViews', surface.hookMaterializerId, `${surfaceLabel}.hookMaterializerId`)
847
+ }
848
+ const skillMaterializer = resolveManifestMaterializer(manifest, 'skillViews', surface.skillMaterializerId, `${surfaceLabel}.skillMaterializerId`)
849
+ if (surface.skillEntryFile !== skillMaterializer.entryFile) throw new Error(`${surfaceLabel}.skillEntryFile differs from its registered materializer`)
850
+ const coverage = exactKeys(surface.nativeHookCoverage, [
851
+ 'canonicalEvents', 'excludedEvents', 'projectedEvents', 'projectedNativeEvents', 'schemaVersion',
852
+ ], `${surfaceLabel}.nativeHookCoverage`)
853
+ const canonicalEvents = sortedUniqueStrings(coverage.canonicalEvents, `${surfaceLabel}.nativeHookCoverage.canonicalEvents`)
854
+ const projectedEvents = sortedUniqueStrings(coverage.projectedEvents, `${surfaceLabel}.nativeHookCoverage.projectedEvents`)
855
+ if (coverage.schemaVersion !== 2 || !canonicalEvents.length) throw new Error(`${surfaceLabel}.nativeHookCoverage identity is invalid`)
856
+ if (!Array.isArray(coverage.projectedNativeEvents)) throw new Error(`${surfaceLabel}.nativeHookCoverage.projectedNativeEvents must be an array`)
857
+ const projectedNativeEvents = coverage.projectedNativeEvents.map((record, index) => {
858
+ exactKeys(record, ['canonicalEvent', 'nativeEvent'], `${surfaceLabel}.nativeHookCoverage.projectedNativeEvents[${index}]`)
859
+ if (
860
+ typeof record.canonicalEvent !== 'string'
861
+ || !record.canonicalEvent
862
+ || typeof record.nativeEvent !== 'string'
863
+ || !/^[A-Za-z][A-Za-z0-9_.:@/-]*$/.test(record.nativeEvent)
864
+ ) throw new Error(`${surfaceLabel}.nativeHookCoverage.projectedNativeEvents[${index}] is invalid`)
865
+ return record
866
+ })
867
+ if (JSON.stringify(projectedNativeEvents) !== JSON.stringify([...projectedNativeEvents].sort((left, right) => compareUtf8Bytes(left.canonicalEvent, right.canonicalEvent)))) {
868
+ throw new Error(`${surfaceLabel}.nativeHookCoverage.projectedNativeEvents must be sorted by canonicalEvent`)
869
+ }
870
+ if (!Array.isArray(coverage.excludedEvents)) throw new Error(`${surfaceLabel}.nativeHookCoverage.excludedEvents must be an array`)
871
+ const excludedEvents = coverage.excludedEvents.map((record, index) => {
872
+ exactKeys(record, ['authoritativeFallback', 'event', 'reasonCode'], `${surfaceLabel}.nativeHookCoverage.excludedEvents[${index}]`)
873
+ if (
874
+ typeof record.event !== 'string'
875
+ || !record.event
876
+ || !/^[A-Z][A-Z0-9_]*$/.test(record.reasonCode || '')
877
+ || record.authoritativeFallback !== 'immutable-governance-check-and-protected-ci'
878
+ ) throw new Error(`${surfaceLabel}.nativeHookCoverage.excludedEvents[${index}] is invalid`)
879
+ return record
880
+ })
881
+ if (JSON.stringify(excludedEvents) !== JSON.stringify([...excludedEvents].sort((left, right) => compareUtf8Bytes(left.event, right.event)))) {
882
+ throw new Error(`${surfaceLabel}.nativeHookCoverage.excludedEvents must be sorted by event`)
883
+ }
884
+ const excludedNames = excludedEvents.map((record) => record.event)
885
+ if (
886
+ excludedNames.length !== new Set(excludedNames).size
887
+ || projectedEvents.some((event) => excludedNames.includes(event))
888
+ || JSON.stringify([...projectedEvents, ...excludedNames].sort()) !== JSON.stringify(canonicalEvents)
889
+ || JSON.stringify(projectedNativeEvents.map((record) => record.canonicalEvent)) !== JSON.stringify(projectedEvents)
890
+ || new Set(projectedNativeEvents.map((record) => record.nativeEvent)).size !== projectedNativeEvents.length
891
+ || (!surface.capabilities?.nativeHooks && projectedEvents.length)
892
+ || (!surface.capabilities?.nativeHooks && excludedEvents.some((record) => record.reasonCode !== 'NATIVE_HOOK_API_UNAVAILABLE'))
893
+ || (surface.capabilities?.nativeHooks && excludedEvents.some((record) => record.reasonCode !== 'EVENT_NOT_SUPPORTED'))
894
+ ) throw new Error(`${surfaceLabel}.nativeHookCoverage is not an exact projected/excluded partition`)
895
+ if (surface.capabilities?.nativeHooks) {
896
+ if (!surface.hookArtifact || !surface.hookDestination || !surface.hookMaterializerId) throw new Error(`${surfaceLabel} native hooks lack a materialized hook surface`)
897
+ } else if (surface.hookArtifact !== null || surface.hookDestination !== null || surface.hookMaterializerId !== null) {
898
+ throw new Error(`${surfaceLabel} hookless provider claims a hook surface`)
899
+ }
900
+ if (instructionMaterializer.engine === 'shared-instruction-v1') {
901
+ if (
902
+ surface.instructionArtifact !== commonInstruction.artifact
903
+ || surface.instructionDestination !== commonInstruction.destination
904
+ || surface.instructionMaterializerId !== commonInstruction.materializerId
905
+ || managedSurfaces.some((record) => pathsOverlap(record.path, commonInstruction.destination))
906
+ ) throw new Error(`${surfaceLabel} shared instruction does not reference the common non-provider authority`)
907
+ } else if (!managedSurfaces.some((record) => (
908
+ record.path === normalizeRepositoryRelative(surface.instructionDestination, `${surfaceLabel}.instructionDestination`)
909
+ && record.kind === 'file'
910
+ ))) throw new Error(`${surfaceLabel}.instructionDestination is absent from managedSurfaces`)
911
+ for (const [path, kind, field] of [
912
+ [surface.hookDestination, 'file', 'hookDestination'],
913
+ [surface.skillDestination, 'tree', 'skillDestination'],
914
+ ]) {
915
+ if (!path) continue
916
+ const normalized = normalizeRepositoryRelative(path, `${surfaceLabel}.${field}`)
917
+ if (!managedSurfaces.some((record) => record.path === normalized && record.kind === kind)) {
918
+ throw new Error(`${surfaceLabel}.${field} is absent from managedSurfaces`)
919
+ }
920
+ }
921
+ const trees = surface.trees.map((tree, index) => {
922
+ const treeLabel = `${surfaceLabel}.trees[${index}]`
923
+ exactKeys(tree, ['artifactRoot', 'destination', 'materializerId', 'name', 'schemaVersion', 'transformPolicy'], treeLabel)
924
+ if (tree.schemaVersion !== 1 || !/^[a-z][a-z0-9-]*$/.test(tree.name || '')) throw new Error(`${treeLabel} identity is invalid`)
925
+ const artifactRoot = normalizeRepositoryRelative(tree.artifactRoot, `${treeLabel}.artifactRoot`)
926
+ const destination = normalizeRepositoryRelative(tree.destination, `${treeLabel}.destination`)
927
+ if (artifactRoot !== `providers/${providerId}/trees/${tree.name}`) throw new Error(`${treeLabel}.artifactRoot is not provider/name scoped`)
928
+ const materializer = resolveManifestMaterializer(manifest, 'treeViews', tree.materializerId, `${treeLabel}.materializerId`)
929
+ if (
930
+ materializer.engine !== 'closed-tree-copy-v1'
931
+ || tree.transformPolicy !== 'byte-exact'
932
+ || !materializer.transformPolicies.includes(tree.transformPolicy)
933
+ ) throw new Error(`${treeLabel} has an unsupported tree materializer contract`)
934
+ if (!managedSurfaces.some((record) => record.path === destination && record.kind === 'tree')) {
935
+ throw new Error(`${treeLabel}.destination is absent from managedSurfaces`)
936
+ }
937
+ return { ...tree, artifactRoot, destination }
938
+ })
939
+ if (
940
+ JSON.stringify(trees) !== JSON.stringify([...trees].sort((left, right) => compareUtf8Bytes(left.name, right.name)))
941
+ || new Set(trees.map((tree) => tree.name)).size !== trees.length
942
+ || new Set(trees.map((tree) => portableRepositoryPathKey(tree.destination))).size !== trees.length
943
+ ) throw new Error(`${surfaceLabel}.trees must be sorted and unique by name/destination`)
944
+ const expectedManagedTrees = [
945
+ normalizeRepositoryRelative(surface.skillDestination, `${surfaceLabel}.skillDestination`),
946
+ ...trees.map((tree) => tree.destination),
947
+ ].sort()
948
+ const actualManagedTrees = managedSurfaces.filter((record) => record.kind === 'tree').map((record) => record.path).sort()
949
+ if (JSON.stringify(actualManagedTrees) !== JSON.stringify(expectedManagedTrees)) {
950
+ throw new Error(`${surfaceLabel}.managedSurfaces trees must exactly match skillDestination plus materialized trees`)
951
+ }
952
+ const compatibilityFiles = (manifest?.consumer?.compatibilityCategories || [])
953
+ .filter((category) => category?.providerId === providerId)
954
+ .flatMap((category, categoryIndex) => {
955
+ const destinationRoot = normalizeRepositoryRelative(category.destinationRoot, `${surfaceLabel}.compatibilityCategories[${categoryIndex}].destinationRoot`)
956
+ if (!Array.isArray(category.entries)) throw new Error(`${surfaceLabel}.compatibilityCategories[${categoryIndex}].entries must be an array`)
957
+ return category.entries.map((entry, entryIndex) => normalizeRepositoryRelative(
958
+ `${destinationRoot}/${entry}`,
959
+ `${surfaceLabel}.compatibilityCategories[${categoryIndex}].entries[${entryIndex}]`,
960
+ ))
961
+ })
962
+ const expectedManagedFiles = [
963
+ ...(instructionMaterializer.engine === 'shared-instruction-v1'
964
+ ? []
965
+ : [normalizeRepositoryRelative(surface.instructionDestination, `${surfaceLabel}.instructionDestination`)]),
966
+ ...(surface.hookDestination
967
+ ? [normalizeRepositoryRelative(surface.hookDestination, `${surfaceLabel}.hookDestination`)]
968
+ : []),
969
+ ...compatibilityFiles,
970
+ ].sort()
971
+ const actualManagedFiles = managedSurfaces.filter((record) => record.kind === 'file').map((record) => record.path).sort()
972
+ if (JSON.stringify(actualManagedFiles) !== JSON.stringify(expectedManagedFiles)) {
973
+ throw new Error(`${surfaceLabel}.managedSurfaces files must exactly match non-shared instruction, hook, and compatibility leaves`)
974
+ }
975
+ providers.push({ id: providerId, surfaces: managedSurfaces })
976
+ }
977
+ const claims = providers.flatMap((provider) => provider.surfaces.map((record) => ({
978
+ ...record,
979
+ providerId: provider.id,
980
+ }))).sort((left, right) => (
981
+ compareUtf8Bytes(left.path, right.path) || compareUtf8Bytes(left.providerId, right.providerId)
982
+ ))
983
+ for (let left = 0; left < claims.length; left += 1) for (let right = left + 1; right < claims.length; right += 1) {
984
+ if (
985
+ claims[left].providerId !== claims[right].providerId
986
+ && repositoryPathsOverlap(claims[left].path, claims[right].path)
987
+ ) {
988
+ throw new Error(
989
+ `${label} has cross-provider managed surface overlap:`
990
+ + `${claims[left].providerId}:${claims[left].path} <> ${claims[right].providerId}:${claims[right].path}`,
991
+ )
992
+ }
993
+ }
994
+ const nonProviderClaims = [
995
+ { path: commonDestination, kind: 'file', owner: 'common-instruction' },
996
+ {
997
+ path: normalizeRepositoryRelative(manifest?.consumer?.launcherDestination, `${label}.consumer.launcherDestination`),
998
+ kind: 'tree',
999
+ owner: 'shared-launchers',
1000
+ },
1001
+ ...Object.keys(manifest?.consumer?.managedFiles || {}).map((path) => ({
1002
+ path: normalizeRepositoryRelative(path, `${label}.consumer.managedFiles destination`),
1003
+ kind: 'file',
1004
+ owner: 'consumer-managed-file',
1005
+ })),
1006
+ ...CONSUMER_CONTROL_PLANE_PATHS.map((path) => ({
1007
+ path,
1008
+ kind: 'file',
1009
+ owner: 'consumer-control-plane',
1010
+ })),
1011
+ ]
1012
+ for (const claim of nonProviderClaims.filter((item) => item.owner !== 'consumer-control-plane')) {
1013
+ const controlPlaneAuthority = consumerControlPlaneAuthority(claim.path)
1014
+ if (controlPlaneAuthority) {
1015
+ throw new Error(
1016
+ `${label} non-provider materialization authority overlaps consumer control plane:`
1017
+ + `${claim.owner}:${claim.path} <> ${controlPlaneAuthority}`,
1018
+ )
1019
+ }
1020
+ }
1021
+ for (let left = 0; left < nonProviderClaims.length; left += 1) for (let right = left + 1; right < nonProviderClaims.length; right += 1) {
1022
+ if (repositoryPathsOverlap(nonProviderClaims[left].path, nonProviderClaims[right].path)) {
1023
+ throw new Error(
1024
+ `${label} non-provider materialization authorities overlap:`
1025
+ + `${nonProviderClaims[left].owner}:${nonProviderClaims[left].path}`
1026
+ + ` <> ${nonProviderClaims[right].owner}:${nonProviderClaims[right].path}`,
1027
+ )
1028
+ }
1029
+ }
1030
+ for (const claim of claims) {
1031
+ const controlPlaneAuthority = consumerControlPlaneAuthority(claim.path)
1032
+ if (controlPlaneAuthority) {
1033
+ throw new Error(
1034
+ `${label} provider surface overlaps non-provider authority:`
1035
+ + `${claim.providerId}:${claim.path} <> consumer-control-plane:${controlPlaneAuthority}`,
1036
+ )
1037
+ }
1038
+ }
1039
+ for (const claim of claims) for (const reserved of nonProviderClaims) {
1040
+ if (
1041
+ repositoryPathsOverlap(claim.path, reserved.path)
1042
+ ) {
1043
+ throw new Error(
1044
+ `${label} provider surface overlaps non-provider authority:`
1045
+ + `${claim.providerId}:${claim.path} <> ${reserved.owner}:${reserved.path}`,
1046
+ )
1047
+ }
1048
+ }
1049
+ return providers
1050
+ }
1051
+
1052
+ // The installed consumer BOM is the package trust root, the corpus lock binds every executable
1053
+ // body, and the lock binds the manifest. Refresh must prove that complete chain before its first
1054
+ // write or tombstone removal; a merely well-shaped node_modules/manifest.json is never authority.
1055
+ export function validateInstalledForkCorpus(projectDir) {
1056
+ projectDir = canonicalRepositoryRoot(projectDir)
1057
+ assertNoRootNpmShrinkwrap(projectDir, { errorPrefix: 'GOV-CORPUS-LOCK-001' })
1058
+ const dsRoot = join(projectDir, 'node_modules/@qijenchen/design-system')
1059
+ const forkRoot = join(dsRoot, 'ds-canonical/fork')
1060
+ const projectPackagePath = regularUnaliasedFile(projectDir, join(projectDir, 'package.json'), 'consumer package manifest')
1061
+ const projectLockPath = regularUnaliasedFile(projectDir, join(projectDir, 'package-lock.json'), 'consumer package lock')
1062
+ const dsPackagePath = regularUnaliasedFile(projectDir, join(dsRoot, 'package.json'), 'installed design-system package manifest')
1063
+ const utilityRegistryPath = regularUnaliasedFile(projectDir, join(dsRoot, 'src/tokens/utility-registry.json'), 'installed canonical utility registry')
1064
+ const bomPath = regularUnaliasedFile(projectDir, join(forkRoot, 'consumer/lock.json'), 'installed consumer BOM')
1065
+ const corpusLockPath = regularUnaliasedFile(projectDir, join(forkRoot, 'governance.lock'), 'installed fork corpus lock')
1066
+ const manifestPath = regularUnaliasedFile(projectDir, join(forkRoot, 'manifest.json'), 'installed fork manifest')
1067
+ const projectPackage = JSON.parse(readFileSync(projectPackagePath, 'utf8'))
1068
+ const projectLock = JSON.parse(readFileSync(projectLockPath, 'utf8'))
1069
+ const dsPackage = JSON.parse(readFileSync(dsPackagePath, 'utf8'))
1070
+ const bom = JSON.parse(readFileSync(bomPath, 'utf8'))
1071
+ const corpusLock = JSON.parse(readFileSync(corpusLockPath, 'utf8'))
1072
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
1073
+ exactKeys(bom, ['$schema', 'authority', 'generatedBy', 'payload', 'providers', 'release', 'role', 'schemaVersion', 'upgradeProtocol', 'upgradeTrust'], 'installed consumer BOM')
1074
+ exactKeys(bom.release, ['designSystem', 'storybookConfig'], 'installed consumer BOM release')
1075
+ exactKeys(bom.upgradeProtocol, [
1076
+ 'bootstrapEvidenceContract', 'candidateCodeExecutionAllowed',
1077
+ 'controlPlaneUpdateEvidenceContract', 'controlPlaneUpdateMode', 'controlPlaneUpdatePlanner',
1078
+ 'implementationSha256', 'legacyEntryMode', 'ordinaryUpgradeMode',
1079
+ 'physicalPowerLossDurabilityClaimed', 'protectedBaseVerifier', 'protocolId', 'schemaSha256',
1080
+ 'schemaVersion', 'specificationSha256',
1081
+ ], 'installed consumer upgrade protocol')
1082
+ exactKeys(bom.payload, [
1083
+ 'commonInstructionSha256', 'mergeSurfaceDigests', 'providerArtifactDigests',
1084
+ 'discoveryPolicySha256', 'executionRuntimeSha256', 'forkCorpusLockSha256', 'governanceCheckSha256', 'managedFiles',
1085
+ 'providerInventorySha256', 'providerLifecycleSha256', 'providerMaterializersSha256', 'requiredScripts', 'sharedSkillCount',
1086
+ 'sharedSkillsSha256', 'utilityRegistrySha256',
1087
+ ], 'installed consumer BOM payload')
1088
+ if (bom.$schema !== './lock.schema.json' || bom.schemaVersion !== 1 || bom.role !== 'template-consumer' || !bom.payload.managedFiles || typeof bom.payload.managedFiles !== 'object' || Array.isArray(bom.payload.managedFiles)) {
1089
+ throw new Error('installed consumer BOM identity is invalid')
1090
+ }
1091
+ if (
1092
+ bom.upgradeProtocol.schemaVersion !== 2
1093
+ || bom.upgradeProtocol.protocolId !== 'protected-base-reconstruction-v2'
1094
+ || bom.upgradeProtocol.legacyEntryMode !== 'one-time-reviewed-full-snapshot-pr'
1095
+ || bom.upgradeProtocol.bootstrapEvidenceContract !== 'consumer-governance-bootstrap-readback-v1'
1096
+ || bom.upgradeProtocol.controlPlaneUpdateMode !== 'recurring-reviewed-full-snapshot-pr'
1097
+ || bom.upgradeProtocol.controlPlaneUpdateEvidenceContract !== 'consumer-governance-control-plane-update-readback-v1'
1098
+ || bom.upgradeProtocol.controlPlaneUpdatePlanner !== 'infra/governance/bin/consumerctl.mjs'
1099
+ || bom.upgradeProtocol.ordinaryUpgradeMode !== 'protected-base-disposable-reconstruction'
1100
+ || bom.upgradeProtocol.protectedBaseVerifier !== 'scripts/verify-upgrade-evidence.mjs'
1101
+ || bom.upgradeProtocol.candidateCodeExecutionAllowed !== false
1102
+ || bom.upgradeProtocol.physicalPowerLossDurabilityClaimed !== false
1103
+ || !SHA256.test(bom.upgradeProtocol.specificationSha256 || '')
1104
+ || !SHA256.test(bom.upgradeProtocol.schemaSha256 || '')
1105
+ || !SHA256.test(bom.upgradeProtocol.implementationSha256 || '')
1106
+ ) throw new Error('installed consumer BOM lacks the protected-base reconstruction v2 boundary; use the reviewed full-snapshot bootstrap path')
1107
+ if (!EXACT_SEMVER.test(dsPackage.version || '') || bom?.release?.designSystem !== dsPackage.version) {
1108
+ throw new Error('installed consumer BOM is not bound to the installed design-system release')
1109
+ }
1110
+ if (!SHA256.test(bom?.payload?.forkCorpusLockSha256 || '') || bom.payload.forkCorpusLockSha256 !== fileSha256(corpusLockPath)) {
1111
+ throw new Error('installed consumer BOM does not bind the exact fork corpus lock')
1112
+ }
1113
+ if (!SHA256.test(bom?.payload?.utilityRegistrySha256 || '') || bom.payload.utilityRegistrySha256 !== fileSha256(utilityRegistryPath)) {
1114
+ throw new Error('installed consumer BOM does not bind the exact canonical utility registry')
1115
+ }
1116
+ exactKeys(corpusLock, ['_purpose', 'entries', 'hashAlgorithm', 'kind', 'schemaVersion'], 'installed fork corpus lock')
1117
+ if (corpusLock.schemaVersion !== 1 || corpusLock.kind !== 'fork-governance-corpus-lock' || corpusLock.hashAlgorithm !== 'sha256' || !Array.isArray(corpusLock.entries)) {
1118
+ throw new Error('installed fork corpus lock identity is invalid')
1119
+ }
1120
+ const entryFiles = []
1121
+ const entriesByFile = new Map()
1122
+ for (const [index, entry] of corpusLock.entries.entries()) {
1123
+ exactKeys(entry, ['classification', 'destination', 'file', 'schemaVersion', 'sha256', 'source'], `installed corpus entry[${index}]`)
1124
+ const relativePath = normalizeRepositoryRelative(entry.file, `installed corpus entry[${index}].file`)
1125
+ if (entry.schemaVersion !== 1 || !SHA256.test(entry.sha256 || '') || !safeRelative(forkRoot, relativePath)) throw new Error(`installed corpus entry is invalid:${relativePath}`)
1126
+ const body = regularUnaliasedFile(projectDir, join(forkRoot, relativePath), `installed corpus body ${relativePath}`)
1127
+ if (fileSha256(body) !== entry.sha256) throw new Error(`installed corpus body digest mismatch:${relativePath}`)
1128
+ entryFiles.push(relativePath)
1129
+ entriesByFile.set(relativePath, entry)
1130
+ }
1131
+ if (JSON.stringify(entryFiles) !== JSON.stringify([...new Set(entryFiles)].sort(compareUtf8Bytes))) {
1132
+ throw new Error('installed corpus entries must be sorted and unique')
1133
+ }
1134
+ const manifestEntry = corpusLock.entries.filter((entry) => entry.file === 'manifest.json')
1135
+ if (manifestEntry.length !== 1 || manifestEntry[0].sha256 !== fileSha256(manifestPath)) throw new Error('installed corpus lock does not bind exactly one manifest')
1136
+ const expectedManifestKeys = [
1137
+ '_generated', 'schemaVersion', 'kind', 'providerRegistrySchemaVersion', 'materializers', 'discoveryPolicy',
1138
+ 'providerLifecycle', 'providerAdapters', 'authorityDecision', 'independentReview', 'launchers', 'hooks', 'ciReplay', 'skills', 'commands',
1139
+ 'agents', 'providerSurfaces', 'codex', 'consumer',
1140
+ ]
1141
+ exactKeys(manifest, expectedManifestKeys, 'installed fork manifest')
1142
+ if (manifest.schemaVersion !== 2 || manifest.kind !== 'provider-neutral-fork-manifest' || manifest.providerRegistrySchemaVersion !== 9) {
1143
+ throw new Error('installed fork manifest identity is invalid')
1144
+ }
1145
+ exactKeys(manifest.authorityDecision, [
1146
+ 'schemaVersion', 'policySource', 'classifierSource', 'receiptContractSource', 'runner',
1147
+ 'prepareArgv', 'verifyArgv', 'certificationClaim',
1148
+ ], 'installed fork manifest authorityDecision')
1149
+ if (
1150
+ manifest.authorityDecision.schemaVersion !== 1
1151
+ || manifest.authorityDecision.policySource !== 'AGENTS.md#canonical-decision-authority'
1152
+ || manifest.authorityDecision.classifierSource !== 'launchers/approval-evidence.mjs'
1153
+ || manifest.authorityDecision.receiptContractSource !== 'launchers/authority-decision-evidence.mjs'
1154
+ || manifest.authorityDecision.runner !== 'launchers/product-hook-dispatch-runtime.mjs'
1155
+ || JSON.stringify(manifest.authorityDecision.prepareArgv) !== JSON.stringify(['--authority-decision', 'prepare'])
1156
+ || JSON.stringify(manifest.authorityDecision.verifyArgv) !== JSON.stringify(['--authority-decision', 'verify'])
1157
+ || manifest.authorityDecision.certificationClaim !== 'structural-only-not-runtime-certified'
1158
+ ) throw new Error('installed fork manifest authorityDecision projection is invalid')
1159
+ validateIndependentReviewProjection(manifest.independentReview)
1160
+ validateDiscoveryPolicy(manifest.discoveryPolicy, 'installed fork manifest discoveryPolicy')
1161
+ if (bom.payload.discoveryPolicySha256 !== sha256(JSON.stringify(manifest.discoveryPolicy))) {
1162
+ throw new Error('installed consumer BOM does not bind the discovery policy')
1163
+ }
1164
+ if (manifest.codex !== null) {
1165
+ exactKeys(manifest.codex, [
1166
+ 'agentsMd', 'agentsSkills', 'compatibilityOnly', 'hookArtifact', 'hookDestination', 'hooksJson',
1167
+ 'instructionDestination', 'skillArtifactRoot', 'skillDestination',
1168
+ ], 'installed legacy Codex compatibility record')
1169
+ if (
1170
+ manifest.codex.compatibilityOnly !== true
1171
+ || typeof manifest.codex.agentsMd !== 'string'
1172
+ || typeof manifest.codex.instructionDestination !== 'string'
1173
+ || !Array.isArray(manifest.codex.agentsSkills)
1174
+ || !Array.isArray(manifest.codex.hooksJson)
1175
+ || (manifest.codex.hookArtifact !== null && typeof manifest.codex.hookArtifact !== 'string')
1176
+ || (manifest.codex.hookDestination !== null && typeof manifest.codex.hookDestination !== 'string')
1177
+ || typeof manifest.codex.skillArtifactRoot !== 'string'
1178
+ || typeof manifest.codex.skillDestination !== 'string'
1179
+ ) throw new Error('installed legacy Codex compatibility record is invalid')
1180
+ }
1181
+ exactKeys(manifest.consumer, [
1182
+ 'claudeMd', 'commonInstruction', 'compatibilityCategories', 'executionRuntime', 'governanceCheck', 'governanceLock', 'governanceLockSchema', 'launcherDestination', 'managedFiles', 'materialization',
1183
+ ], 'installed fork manifest consumer')
1184
+ if (manifest.consumer.claudeMd !== null && typeof manifest.consumer.claudeMd !== 'string') {
1185
+ throw new Error('installed fork manifest legacy claudeMd compatibility alias is invalid')
1186
+ }
1187
+ if (!Array.isArray(manifest.consumer.compatibilityCategories)) throw new Error('installed compatibility category inventory must be an array')
1188
+ exactKeys(manifest.consumer.materialization, ['exactPaths', 'pathPrefixes'], 'installed fork manifest consumer materialization')
1189
+ if (!manifest.consumer.managedFiles || typeof manifest.consumer.managedFiles !== 'object' || Array.isArray(manifest.consumer.managedFiles)) {
1190
+ throw new Error('installed fork manifest managed-file map is invalid')
1191
+ }
1192
+ exactKeys(manifest.consumer.executionRuntime, [
1193
+ 'engine', 'exactNpmVersion', 'minimumNodeVersion', 'nativeWindowsPolicy', 'requiredExecutables', 'requiredPathClasses', 'schemaVersion',
1194
+ 'supportedHostPlatforms', 'windowsCompatibilityEnvironments',
1195
+ ], 'installed consumer execution runtime')
1196
+ if (
1197
+ manifest.consumer.executionRuntime.schemaVersion !== 2
1198
+ || manifest.consumer.executionRuntime.engine !== 'node-posix-toolchain-v2'
1199
+ || !/^\d+\.\d+\.\d+$/.test(manifest.consumer.executionRuntime.minimumNodeVersion || '')
1200
+ || !/^\d+\.\d+\.\d+$/.test(manifest.consumer.executionRuntime.exactNpmVersion || '')
1201
+ || manifest.consumer.executionRuntime.nativeWindowsPolicy !== 'unsupported-fail-closed'
1202
+ || JSON.stringify(manifest.consumer.executionRuntime.supportedHostPlatforms) !== JSON.stringify(['darwin', 'linux'])
1203
+ || JSON.stringify(manifest.consumer.executionRuntime.windowsCompatibilityEnvironments) !== JSON.stringify(['devcontainer-linux', 'wsl2-linux'])
1204
+ || JSON.stringify(manifest.consumer.executionRuntime.requiredExecutables) !== JSON.stringify(['bash', 'git', 'jq', 'node', 'perl', 'python3'])
1205
+ || JSON.stringify(manifest.consumer.executionRuntime.requiredPathClasses) !== JSON.stringify(['plain', 'space-containing'])
1206
+ || bom.payload.executionRuntimeSha256 !== sha256(JSON.stringify(manifest.consumer.executionRuntime))
1207
+ ) throw new Error('installed consumer execution runtime contract is invalid or unbound')
1208
+ const requiredNodeRange = `>=${manifest.consumer.executionRuntime.minimumNodeVersion}`
1209
+ const lockedRoot = projectLock?.packages?.['']
1210
+ const lockedNpm = projectLock?.packages?.['node_modules/npm']
1211
+ if (
1212
+ projectPackage?.engines?.node !== requiredNodeRange
1213
+ || projectPackage?.devDependencies?.npm !== manifest.consumer.executionRuntime.exactNpmVersion
1214
+ || projectLock?.lockfileVersion !== 3
1215
+ || lockedRoot?.engines?.node !== requiredNodeRange
1216
+ || lockedRoot?.devDependencies?.npm !== manifest.consumer.executionRuntime.exactNpmVersion
1217
+ || lockedNpm?.version !== manifest.consumer.executionRuntime.exactNpmVersion
1218
+ || lockedNpm?.resolved !== `https://registry.npmjs.org/npm/-/npm-${manifest.consumer.executionRuntime.exactNpmVersion}.tgz`
1219
+ || !/^sha512-[A-Za-z0-9+/]+={0,2}$/.test(lockedNpm?.integrity || '')
1220
+ ) throw new Error('consumer package engines/npm lock differs from the installed execution runtime contract')
1221
+ if (!stableVersionAtLeast(process.versions.node, manifest.consumer.executionRuntime.minimumNodeVersion)) {
1222
+ throw new Error(`consumer refresh requires Node.js ${manifest.consumer.executionRuntime.minimumNodeVersion} or newer`)
1223
+ }
1224
+ const launcherDestination = normalizeRepositoryRelative(manifest.consumer.launcherDestination, 'installed shared launcher destination')
1225
+ if (!Array.isArray(manifest.launchers) || !manifest.launchers.length) throw new Error('installed fork manifest launcher inventory is empty')
1226
+ const launcherNames = manifest.launchers.map((name, index) => {
1227
+ if (typeof name !== 'string' || !/^[A-Za-z0-9._-]+\.(?:sh|mjs|py)$/.test(name)) {
1228
+ throw new Error(`installed fork manifest launcher[${index}] is invalid`)
1229
+ }
1230
+ return name
1231
+ })
1232
+ if (JSON.stringify(launcherNames) !== JSON.stringify([...new Set(launcherNames)].sort())) {
1233
+ throw new Error('installed fork manifest launchers must be sorted and unique')
1234
+ }
1235
+ if (!launcherNames.includes('independent-review.mjs')) throw new Error('installed fork manifest lacks the provider-neutral independent-review launcher')
1236
+ const assertLockedArtifact = (relativePath, label) => {
1237
+ const normalized = normalizeRepositoryRelative(relativePath, label)
1238
+ if (!safeRelative(forkRoot, normalized)) throw new Error(`${label} escapes fork corpus`)
1239
+ const absolute = join(forkRoot, normalized)
1240
+ assertNoSymlinkPath(projectDir, absolute, label, { allowMissing: false })
1241
+ const info = lstatSync(absolute)
1242
+ const files = []
1243
+ const visit = (path, rel) => {
1244
+ const childInfo = lstatSync(path)
1245
+ if (childInfo.isDirectory()) for (const name of readdirSync(path).sort()) visit(join(path, name), `${rel}/${name}`)
1246
+ else if (childInfo.isFile() && childInfo.nlink === 1) files.push(rel)
1247
+ else throw new Error(`${label} contains an unsafe filesystem entry`)
1248
+ }
1249
+ visit(absolute, normalized)
1250
+ if (!info.isFile() && !info.isDirectory()) throw new Error(`${label} is not a file or tree`)
1251
+ for (const file of files) if (!entriesByFile.has(file)) throw new Error(`${label} references unlocked corpus body:${file}`)
1252
+ return { normalized, files }
1253
+ }
1254
+ for (const [relativePath, label] of [
1255
+ [manifest.authorityDecision.classifierSource, 'installed authority decision classifier'],
1256
+ [manifest.authorityDecision.receiptContractSource, 'installed authority decision receipt contract'],
1257
+ [manifest.authorityDecision.runner, 'installed authority decision runner'],
1258
+ ]) {
1259
+ const launcherName = relativePath.slice('launchers/'.length)
1260
+ if (!relativePath.startsWith('launchers/') || !launcherNames.includes(launcherName)) {
1261
+ throw new Error(`${label} is absent from the shared launcher inventory`)
1262
+ }
1263
+ assertLockedArtifact(relativePath, label)
1264
+ }
1265
+ const lifecycle = manifest.providerLifecycle
1266
+ assertLockedArtifact('review/provider-review-binding.mjs', 'installed provider review binding resolver')
1267
+ if (!lifecycle || typeof lifecycle !== 'object' || Array.isArray(lifecycle) || ![3, 4].includes(lifecycle.schemaVersion)) {
1268
+ throw new Error('installed provider lifecycle identity is invalid')
1269
+ }
1270
+ exactKeys(lifecycle, [
1271
+ 'currentProviderInventorySha256', 'currentSnapshotSha256', 'immutableHead', 'ledgerSha256', 'previousSnapshotSha256',
1272
+ 'releaseVersion', 'retiredProviders', 'schemaVersion',
1273
+ ...(lifecycle.schemaVersion === 4 ? ['currentSnapshot', 'immutableHeadSnapshot'] : []),
1274
+ ], 'installed provider lifecycle')
1275
+ if (
1276
+ lifecycle.releaseVersion !== dsPackage.version
1277
+ || !SHA256.test(lifecycle.ledgerSha256 || '')
1278
+ || !SHA256.test(lifecycle.currentSnapshotSha256 || '')
1279
+ || !SHA256.test(lifecycle.currentProviderInventorySha256 || '')
1280
+ || (lifecycle.previousSnapshotSha256 !== null && !SHA256.test(lifecycle.previousSnapshotSha256 || ''))
1281
+ || !Array.isArray(lifecycle.retiredProviders)
1282
+ ) throw new Error('installed provider lifecycle identity is invalid')
1283
+ exactKeys(lifecycle.immutableHead, ['providerInventorySha256', 'releaseVersion', 'snapshotSha256'], 'installed provider lifecycle immutable head')
1284
+ if (!EXACT_SEMVER.test(lifecycle.immutableHead.releaseVersion || '') || !SHA256.test(lifecycle.immutableHead.snapshotSha256 || '') || !SHA256.test(lifecycle.immutableHead.providerInventorySha256 || '')) {
1285
+ throw new Error('installed provider lifecycle immutable head is invalid')
1286
+ }
1287
+ validateAuthenticatedProviderLifecycle(lifecycle, { allowLegacyV3: true })
1288
+ const activeProviders = validateForkManifestProviderSurfaces(manifest)
1289
+ if (lifecycle.schemaVersion === 4) {
1290
+ const currentSnapshot = lifecycle.currentSnapshot
1291
+ const immutableHeadSnapshot = lifecycle.immutableHeadSnapshot
1292
+ assertSnapshotDiscoveryWithinPolicy(currentSnapshot, manifest.discoveryPolicy, 'installed provider lifecycle currentSnapshot')
1293
+ assertSnapshotDiscoveryWithinPolicy(immutableHeadSnapshot, manifest.discoveryPolicy, 'installed provider lifecycle immutableHeadSnapshot')
1294
+ if (JSON.stringify(snapshotActiveSurfaceView(currentSnapshot)) !== JSON.stringify(snapshotActiveSurfaceView({ providers: activeProviders }))) {
1295
+ throw new Error('installed provider lifecycle currentSnapshot provider ids/surfaces do not exactly match active providerSurfaces managedSurfaces')
1296
+ }
1297
+ }
1298
+ const activeProviderById = new Map(activeProviders.map((provider) => [provider.id, provider]))
1299
+ const activeSurfaces = activeProviders.flatMap((provider) => provider.surfaces.map((surface) => ({ ...surface, providerId: provider.id })))
1300
+ const commonInstruction = manifest.consumer.commonInstruction
1301
+ const commonDestination = normalizeRepositoryRelative(commonInstruction.destination, 'installed common instruction destination')
1302
+ const commonArtifact = assertLockedArtifact(commonInstruction.artifact, 'installed common instruction artifact')
1303
+ if (
1304
+ commonArtifact.files.length !== 1
1305
+ || bom.payload.commonInstructionSha256 !== entriesByFile.get(commonArtifact.normalized)?.sha256
1306
+ || activeSurfaces.some((surface) => pathsOverlap(surface.path, commonDestination))
1307
+ ) throw new Error('installed common instruction is unbound or incorrectly owned by a provider')
1308
+ const governanceCheck = assertLockedArtifact(manifest.consumer.governanceCheck, 'installed governance checker artifact')
1309
+ if (
1310
+ governanceCheck.files.length !== 1
1311
+ || entriesByFile.get(governanceCheck.normalized)?.sha256 !== bom.payload.governanceCheckSha256
1312
+ ) throw new Error('installed governance checker is not exactly bound by BOM/corpus lock')
1313
+ if (manifest.codex !== null) {
1314
+ const compatibility = manifest.codex
1315
+ const matchingSurfaces = Object.values(manifest.providerSurfaces).filter((surface) => (
1316
+ surface.generated
1317
+ && surface.instructionArtifact === compatibility.agentsMd
1318
+ && surface.instructionDestination === compatibility.instructionDestination
1319
+ && surface.hookDestination === compatibility.hookDestination
1320
+ && surface.skillDestination === compatibility.skillDestination
1321
+ && JSON.stringify(surface.skills) === JSON.stringify(compatibility.agentsSkills)
1322
+ ))
1323
+ if (matchingSurfaces.length !== 1) throw new Error('legacy Codex compatibility record does not bind exactly one active provider surface')
1324
+ assertLockedArtifact(compatibility.agentsMd, 'legacy Codex instruction alias source')
1325
+ if (compatibility.hookArtifact !== null) assertLockedArtifact(compatibility.hookArtifact, 'legacy Codex hook alias')
1326
+ for (const name of compatibility.agentsSkills) {
1327
+ assertLockedArtifact(`${compatibility.skillArtifactRoot}/${name}`, `legacy Codex skill alias ${name}`)
1328
+ }
1329
+ }
1330
+ const compatibilityCategories = manifest.consumer.compatibilityCategories.map((category, index) => {
1331
+ const categoryLabel = `installed compatibility category[${index}]`
1332
+ exactKeys(category, ['artifactRoot', 'destinationRoot', 'entries', 'name', 'providerId', 'schemaVersion'], categoryLabel)
1333
+ if (
1334
+ category.schemaVersion !== 1
1335
+ || !['agents', 'commands'].includes(category.name)
1336
+ || !/^[a-z][a-z0-9-]*$/.test(category.providerId || '')
1337
+ ) throw new Error(`${categoryLabel} identity is invalid`)
1338
+ const artifactRoot = normalizeRepositoryRelative(category.artifactRoot, `${categoryLabel}.artifactRoot`)
1339
+ const destinationRoot = normalizeRepositoryRelative(category.destinationRoot, `${categoryLabel}.destinationRoot`)
1340
+ const entries = sortedUniqueStrings(category.entries, `${categoryLabel}.entries`)
1341
+ const owner = activeProviderById.get(category.providerId)
1342
+ if (!owner) throw new Error(`${categoryLabel} owner is not an active generated provider`)
1343
+ if (JSON.stringify(manifest[category.name]) !== JSON.stringify(entries)) throw new Error(`${categoryLabel} differs from its legacy manifest alias`)
1344
+ for (const entry of entries) {
1345
+ if (!/^[A-Za-z0-9][A-Za-z0-9_.@-]*\.md$/.test(entry)) throw new Error(`${categoryLabel} entry is unsafe:${entry}`)
1346
+ const destination = `${destinationRoot}/${entry}`
1347
+ if (!owner.surfaces.some((surface) => surface.path === destination && surface.kind === 'file')) {
1348
+ throw new Error(`${categoryLabel} destination is absent from provider lifecycle ownership:${destination}`)
1349
+ }
1350
+ assertLockedArtifact(`${artifactRoot}/${entry}`, `${categoryLabel} artifact ${entry}`)
1351
+ if (!manifest.consumer.materialization.exactPaths.includes(destination)) throw new Error(`${categoryLabel} destination is absent from exact materialization:${destination}`)
1352
+ }
1353
+ return { ...category, artifactRoot, destinationRoot, entries }
1354
+ })
1355
+ if (
1356
+ JSON.stringify(compatibilityCategories.map((category) => category.name))
1357
+ !== JSON.stringify([...new Set(compatibilityCategories.map((category) => category.name))].sort())
1358
+ ) throw new Error('installed compatibility categories must be sorted and unique by name')
1359
+ for (const name of ['agents', 'commands']) {
1360
+ if (!compatibilityCategories.some((category) => category.name === name) && (manifest[name] || []).length) {
1361
+ throw new Error(`legacy ${name} inventory exists without an active compatibility category owner`)
1362
+ }
1363
+ }
1364
+ if (activeSurfaces.some((surface) => pathsOverlap(surface.path, launcherDestination))) {
1365
+ throw new Error(`shared launcher destination is owned by a provider lifecycle surface:${launcherDestination}`)
1366
+ }
1367
+ const retiredIds = []
1368
+ const retiredPaths = []
1369
+ for (const [index, retirement] of lifecycle.retiredProviders.entries()) {
1370
+ exactKeys(retirement, [
1371
+ 'discovery', 'id', 'priorProviderSha256', 'priorReleaseVersion', 'priorSnapshotSha256',
1372
+ 'reasonCode', 'replacementProviderId', 'retiredInVersion', 'surfaces',
1373
+ ...(Object.hasOwn(retirement || {}, 'transfers') ? ['transfers'] : []),
1374
+ ], `installed retirement[${index}]`)
1375
+ const transfers = retirement.transfers || []
1376
+ if (
1377
+ !/^[a-z][a-z0-9-]*$/.test(retirement.id || '')
1378
+ || !EXACT_SEMVER.test(retirement.priorReleaseVersion || '')
1379
+ || !EXACT_SEMVER.test(retirement.retiredInVersion || '')
1380
+ || !SHA256.test(retirement.priorSnapshotSha256 || '')
1381
+ || !SHA256.test(retirement.priorProviderSha256 || '')
1382
+ || !Array.isArray(retirement.surfaces)
1383
+ || (Object.hasOwn(retirement, 'transfers') && (!Array.isArray(transfers) || !transfers.length))
1384
+ || (!retirement.surfaces.length && !transfers.length)
1385
+ ) throw new Error(`installed retirement proof is invalid:${retirement?.id || index}`)
1386
+ validateDiscovery(retirement.discovery, `installed retirement ${retirement.id}.discovery`)
1387
+ const surfaces = retirement.surfaces.map((surface, surfaceIndex) => validateRetiredSurface(surface, `installed retirement ${retirement.id}.surfaces[${surfaceIndex}]`))
1388
+ if (surfaces.some((surface) => pathsOverlap(surface.path, commonDestination))) {
1389
+ throw new Error(`${retirement.id}:provider tombstone may not delete the common instruction authority`)
1390
+ }
1391
+ if (JSON.stringify(surfaces) !== JSON.stringify([...surfaces].sort((left, right) => compareUtf8Bytes(left.path, right.path)))) throw new Error(`${retirement.id}:retired surfaces must be sorted`)
1392
+ const transferred = transfers.map((surface, surfaceIndex) => validateSurface(surface, `installed retirement ${retirement.id}.transfers[${surfaceIndex}]`))
1393
+ if (JSON.stringify(transferred) !== JSON.stringify([...transferred].sort((left, right) => compareUtf8Bytes(left.path, right.path)))) throw new Error(`${retirement.id}:transferred surfaces must be sorted`)
1394
+ const partition = [...surfaces, ...transferred].map(({ path, kind }) => ({ path, kind }))
1395
+ .sort((left, right) => compareUtf8Bytes(left.path, right.path))
1396
+ if (partition.length !== new Set(partition.map((surface) => portableRepositoryPathKey(surface.path))).size) throw new Error(`${retirement.id}:retirement deletion/transfer partition contains duplicate paths`)
1397
+ const priorProvider = {
1398
+ id: retirement.id,
1399
+ discovery: retirement.discovery,
1400
+ surfaces: partition,
1401
+ }
1402
+ if (sha256(JSON.stringify(priorProvider)) !== retirement.priorProviderSha256) throw new Error(`${retirement.id}:retirement does not bind its prior provider inventory`)
1403
+ const replacement = retirement.replacementProviderId === null ? null : activeProviderById.get(retirement.replacementProviderId)
1404
+ if (retirement.replacementProviderId !== null && (!replacement || retirement.replacementProviderId === retirement.id)) {
1405
+ throw new Error(`${retirement.id}:replacementProviderId must name a distinct active current provider`)
1406
+ }
1407
+ if (!replacement && transferred.length) throw new Error(`${retirement.id}:null replacementProviderId cannot transfer surfaces`)
1408
+ for (const surface of surfaces) {
1409
+ if (activeSurfaces.some((candidate) => pathsOverlap(candidate.path, surface.path))) {
1410
+ throw new Error(`${retirement.id}:deletion tombstone remains owned by an active provider:${surface.path}`)
1411
+ }
1412
+ }
1413
+ for (const surface of transferred) {
1414
+ if (!replacement.surfaces.some((candidate) => candidate.path === surface.path && candidate.kind === surface.kind)) {
1415
+ throw new Error(`${retirement.id}:transfer is not exactly owned by replacement ${retirement.replacementProviderId}:${surface.path}`)
1416
+ }
1417
+ if (activeSurfaces.some((candidate) => candidate.providerId !== replacement.id && pathsOverlap(candidate.path, surface.path))) {
1418
+ throw new Error(`${retirement.id}:transfer is also owned by a non-replacement provider:${surface.path}`)
1419
+ }
1420
+ }
1421
+ retiredIds.push(retirement.id)
1422
+ retiredPaths.push(...surfaces.map((surface) => surface.path))
1423
+ }
1424
+ if (JSON.stringify(retiredIds) !== JSON.stringify([...new Set(retiredIds)].sort()) || retiredPaths.length !== new Set(retiredPaths.map(portableRepositoryPathKey)).size) {
1425
+ throw new Error('installed retirement ids and paths must be globally unique and sorted')
1426
+ }
1427
+ if (bom.payload.providerLifecycleSha256 !== sha256(JSON.stringify(lifecycle))) throw new Error('installed consumer BOM does not bind the provider lifecycle')
1428
+ if (bom.payload.providerInventorySha256 !== sha256(JSON.stringify(manifest.providerSurfaces))) throw new Error('installed consumer BOM does not bind provider surfaces')
1429
+ if (bom.payload.providerMaterializersSha256 !== sha256(JSON.stringify(manifest.materializers))) throw new Error('installed consumer BOM does not bind provider materializers')
1430
+ const activeIds = activeProviders.map((provider) => provider.id)
1431
+ if (activeIds.some((id) => retiredIds.includes(id))) throw new Error('installed provider lifecycle reactivates a retired provider')
1432
+ if (JSON.stringify(Object.keys(manifest.consumer.managedFiles).sort()) !== JSON.stringify(Object.keys(bom.payload.managedFiles).sort())) {
1433
+ throw new Error('installed managed-file artifact map differs from the consumer BOM')
1434
+ }
1435
+ for (const [destination, artifact] of Object.entries(manifest.consumer.managedFiles)) {
1436
+ normalizeRepositoryRelative(destination, `managed-file destination ${destination}`)
1437
+ const locked = assertLockedArtifact(artifact, `managed-file artifact ${artifact}`)
1438
+ if (locked.files.length !== 1 || entriesByFile.get(locked.normalized)?.sha256 !== bom.payload.managedFiles[destination]) {
1439
+ throw new Error(`managed-file artifact is not exactly bound by BOM/corpus lock:${destination}`)
1440
+ }
1441
+ }
1442
+ for (const [providerId, surface] of Object.entries(manifest.providerSurfaces)) {
1443
+ if (!surface.generated) continue
1444
+ assertLockedArtifact(surface.instructionArtifact, `${providerId} instruction artifact`)
1445
+ if (surface.hookArtifact) assertLockedArtifact(surface.hookArtifact, `${providerId} hook artifact`)
1446
+ for (const name of surface.skills) assertLockedArtifact(`${surface.skillArtifactRoot}/${name}`, `${providerId} skill artifact ${name}`)
1447
+ for (const tree of surface.trees) {
1448
+ const locked = assertLockedArtifact(tree.artifactRoot, `${providerId} product managed tree ${tree.name}`)
1449
+ if (!locked.files.length) throw new Error(`${providerId} product managed tree is empty or unlocked:${tree.name}`)
1450
+ }
1451
+ }
1452
+ const lockedTreeDigest = (prefix) => sha256(corpusLock.entries
1453
+ .filter((entry) => entry.file.startsWith(`${prefix}/`))
1454
+ .map((entry) => `${entry.file}:${entry.sha256}`)
1455
+ .join('\n') + '\n')
1456
+ const sharedSkillEntries = corpusLock.entries
1457
+ .filter((entry) => entry.file.startsWith('skills/'))
1458
+ .map((entry) => `${entry.file}:${entry.sha256}`)
1459
+ .sort()
1460
+ const lockedSharedSkillNames = [...new Set(corpusLock.entries
1461
+ .filter((entry) => entry.file.startsWith('skills/'))
1462
+ .map((entry) => entry.file.split('/')[1]))]
1463
+ .sort()
1464
+ if (
1465
+ !Array.isArray(manifest.skills)
1466
+ || JSON.stringify(manifest.skills) !== JSON.stringify([...new Set(manifest.skills)].sort())
1467
+ || manifest.skills.some((name) => !/^[a-z][a-z0-9-]*$/.test(name))
1468
+ || JSON.stringify(manifest.skills) !== JSON.stringify(lockedSharedSkillNames)
1469
+ || bom.payload.sharedSkillCount !== manifest.skills.length
1470
+ || bom.payload.sharedSkillsSha256 !== sha256(`${sharedSkillEntries.join('\n')}\n`)
1471
+ ) throw new Error('installed shared skill inventory/digest is invalid')
1472
+ const providerIds = Object.keys(manifest.providerSurfaces).sort()
1473
+ if (JSON.stringify(Object.keys(bom.payload.providerArtifactDigests || {}).sort()) !== JSON.stringify(providerIds)) {
1474
+ throw new Error('installed provider artifact digest map differs from the provider inventory')
1475
+ }
1476
+ for (const [providerId, surface] of Object.entries(manifest.providerSurfaces).sort(([a], [b]) => compareUtf8Bytes(a, b))) {
1477
+ const binding = exactKeys(bom.payload.providerArtifactDigests[providerId], [
1478
+ 'hookSha256', 'instructionSha256', 'skillsSha256', 'treeDigests',
1479
+ ], `installed provider artifact digest ${providerId}`)
1480
+ exactKeys(binding.treeDigests, surface.trees.map((tree) => tree.name), `installed provider tree digest ${providerId}`)
1481
+ const expected = {
1482
+ instructionSha256: surface.instructionArtifact ? fileSha256(join(forkRoot, surface.instructionArtifact)) : null,
1483
+ hookSha256: surface.hookArtifact ? fileSha256(join(forkRoot, surface.hookArtifact)) : null,
1484
+ skillsSha256: surface.skillArtifactRoot ? lockedTreeDigest(surface.skillArtifactRoot) : null,
1485
+ treeDigests: Object.fromEntries(surface.trees.map((tree) => [tree.name, lockedTreeDigest(tree.artifactRoot)])),
1486
+ }
1487
+ if (JSON.stringify(binding) !== JSON.stringify(expected)) throw new Error(`${providerId}:installed provider artifact digest binding is invalid`)
1488
+ }
1489
+ const mergePolicies = validateCanonicalSettingsWiring(
1490
+ JSON.parse(readFileSync(join(forkRoot, 'launchers/settings-hooks.json'), 'utf8')),
1491
+ manifest,
1492
+ )
1493
+ const expectedMergeDigests = Object.fromEntries(Object.entries(mergePolicies.surfaces)
1494
+ .sort(([a], [b]) => compareUtf8Bytes(a, b))
1495
+ .map(([providerId, policy]) => [providerId, fileSha256(join(forkRoot, policy.hookArtifact))]))
1496
+ if (JSON.stringify(bom.payload.mergeSurfaceDigests) !== JSON.stringify(expectedMergeDigests)) {
1497
+ throw new Error('installed merge-surface digest map differs from the locked merge policies')
1498
+ }
1499
+ const exactMaterialization = manifest.consumer.materialization.exactPaths
1500
+ if (!Array.isArray(exactMaterialization)) throw new Error('consumer exact materialization inventory must be an array')
1501
+ const prefixMaterialization = manifest.consumer.materialization.pathPrefixes
1502
+ if (!Array.isArray(prefixMaterialization)) throw new Error('consumer prefix materialization inventory must be an array')
1503
+ const generatedSurfaces = Object.entries(manifest.providerSurfaces)
1504
+ .filter(([, surface]) => surface.generated)
1505
+ .sort(([left], [right]) => compareUtf8Bytes(left, right))
1506
+ const exactMaterializationClaims = [
1507
+ ...Object.keys(manifest.consumer.managedFiles).map((destination) => ({
1508
+ owner: `consumer-managed-file:${destination}`,
1509
+ path: normalizeRepositoryRelative(destination, `managed-file materialization destination ${destination}`),
1510
+ })),
1511
+ ...CONSUMER_CONTROL_PLANE_PATHS.map((path) => ({ owner: `consumer-control-plane:${path}`, path })),
1512
+ { owner: 'common-instruction', path: commonDestination },
1513
+ ...generatedSurfaces.flatMap(([providerId, surface]) => {
1514
+ const instructionMaterializer = resolveManifestMaterializer(
1515
+ manifest,
1516
+ 'instructionViews',
1517
+ surface.instructionMaterializerId,
1518
+ `${providerId}.instructionMaterializerId`,
1519
+ )
1520
+ return [
1521
+ ...(instructionMaterializer.engine === 'shared-instruction-v1' ? [] : [{
1522
+ owner: `${providerId}:instruction`,
1523
+ path: normalizeRepositoryRelative(surface.instructionDestination, `${providerId} instruction materialization destination`),
1524
+ }]),
1525
+ ...(surface.hookDestination === null ? [] : [{
1526
+ owner: `${providerId}:hook`,
1527
+ path: normalizeRepositoryRelative(surface.hookDestination, `${providerId} hook materialization destination`),
1528
+ }]),
1529
+ ]
1530
+ }),
1531
+ ...launcherNames.map((name) => ({ owner: `shared-launcher:${name}`, path: `${launcherDestination}/${name}` })),
1532
+ ...compatibilityCategories.flatMap((category) => (
1533
+ category.entries.map((entry) => ({
1534
+ owner: `compatibility:${category.name}:${entry}`,
1535
+ path: `${category.destinationRoot}/${entry}`,
1536
+ }))
1537
+ )),
1538
+ ]
1539
+ const prefixMaterializationClaims = generatedSurfaces.flatMap(([providerId, surface]) => [
1540
+ ...surface.skills.map((name) => ({
1541
+ owner: `${providerId}:skill:${name}`,
1542
+ path: `${normalizeRepositoryRelative(surface.skillDestination, `${providerId} skill materialization destination`)}/${name}`,
1543
+ })),
1544
+ ...surface.trees.map((tree) => ({
1545
+ owner: `${providerId}:tree:${tree.name}`,
1546
+ path: normalizeRepositoryRelative(tree.destination, `${providerId} tree materialization destination ${tree.name}`),
1547
+ })),
1548
+ ])
1549
+ const ownerClaims = [
1550
+ ...exactMaterializationClaims.filter((claim) => !claim.owner.startsWith('shared-launcher:')),
1551
+ { owner: 'shared-launchers', path: launcherDestination },
1552
+ ...prefixMaterializationClaims,
1553
+ ]
1554
+ .sort((left, right) => (
1555
+ compareUtf8Bytes(left.path, right.path) || compareUtf8Bytes(left.owner, right.owner)
1556
+ ))
1557
+ for (const claim of ownerClaims.filter((item) => !item.owner.startsWith('consumer-control-plane:'))) {
1558
+ const controlPlaneAuthority = consumerControlPlaneAuthority(claim.path)
1559
+ if (controlPlaneAuthority) {
1560
+ throw new Error(
1561
+ 'non-provider materialization authority overlaps consumer control plane:'
1562
+ + `${claim.owner}:${claim.path} <> ${controlPlaneAuthority}`,
1563
+ )
1564
+ }
1565
+ }
1566
+ for (let left = 0; left < ownerClaims.length; left += 1) for (let right = left + 1; right < ownerClaims.length; right += 1) {
1567
+ if (repositoryPathsOverlap(ownerClaims[left].path, ownerClaims[right].path)) {
1568
+ throw new Error(
1569
+ 'non-provider materialization authorities overlap:'
1570
+ + `${ownerClaims[left].owner}:${ownerClaims[left].path}`
1571
+ + ` <> ${ownerClaims[right].owner}:${ownerClaims[right].path}`,
1572
+ )
1573
+ }
1574
+ }
1575
+ const expectedExactMaterialization = [...new Set(exactMaterializationClaims.map((claim) => claim.path))].sort()
1576
+ const canonicalExactMaterialization = exactMaterialization.map((path, index) => {
1577
+ const normalized = normalizeRepositoryRelative(path, `consumer exact materialization[${index}]`)
1578
+ if (path !== normalized) throw new Error(`consumer exact materialization path is not canonical:${path}`)
1579
+ return normalized
1580
+ })
1581
+ if (JSON.stringify(canonicalExactMaterialization) !== JSON.stringify(expectedExactMaterialization)) {
1582
+ throw new Error('consumer exact materialization inventory must be sorted, unique, canonical, and exactly derived from authenticated corpus')
1583
+ }
1584
+ const expectedPrefixMaterialization = [...new Set(prefixMaterializationClaims.map((claim) => `${claim.path}/`))].sort()
1585
+ const canonicalPrefixMaterialization = prefixMaterialization.map((prefix, index) => {
1586
+ if (typeof prefix !== 'string') throw new Error(`consumer prefix materialization[${index}] must be a string`)
1587
+ const normalized = `${normalizeRepositoryRelative(prefix, `consumer prefix materialization[${index}]`)}/`
1588
+ if (prefix !== normalized) throw new Error(`consumer prefix materialization path is not canonical:${prefix}`)
1589
+ return normalized
1590
+ })
1591
+ if (JSON.stringify(canonicalPrefixMaterialization) !== JSON.stringify(expectedPrefixMaterialization)) {
1592
+ throw new Error('consumer prefix materialization inventory must be sorted, unique, canonical, and exactly derived from authenticated corpus')
1593
+ }
1594
+ for (const name of launcherNames) {
1595
+ assertLockedArtifact(`launchers/${name}`, `shared launcher artifact ${name}`)
1596
+ }
1597
+ return {
1598
+ projectDir,
1599
+ forkRoot,
1600
+ manifest,
1601
+ activeProviders,
1602
+ bom,
1603
+ corpusLock,
1604
+ evidence: {
1605
+ releaseVersion: dsPackage.version,
1606
+ consumerBomSha256: fileSha256(bomPath),
1607
+ forkCorpusLockSha256: fileSha256(corpusLockPath),
1608
+ manifestSha256: fileSha256(manifestPath),
1609
+ providerLifecycleSha256: bom.payload.providerLifecycleSha256,
1610
+ },
1611
+ }
1612
+ }
1613
+
1614
+ export function collectProviderMutationPaths(manifest, authenticatedActiveProviders = null) {
1615
+ const records = []
1616
+ for (const provider of authenticatedActiveProviders || validateForkManifestProviderSurfaces(manifest)) records.push(...provider.surfaces)
1617
+ for (const retirement of manifest?.providerLifecycle?.retiredProviders || []) {
1618
+ for (const surface of retirement.surfaces || []) {
1619
+ const validated = validateRetiredSurface(surface, `${retirement.id} retired mutation path`)
1620
+ records.push({ path: validated.path, kind: validated.kind })
1621
+ }
1622
+ }
1623
+ const byPath = new Map()
1624
+ for (const record of records) {
1625
+ const key = portableRepositoryPathKey(record.path)
1626
+ const prior = byPath.get(key)
1627
+ if (prior && (prior.kind !== record.kind || prior.path !== record.path)) throw new Error(`provider mutation path has conflicting portable aliases:${prior.path}:${record.path}`)
1628
+ byPath.set(key, record)
1629
+ }
1630
+ return [...byPath.values()].map(({ path, kind }) => ({ path, kind }))
1631
+ .sort((left, right) => compareUtf8Bytes(left.path, right.path))
1632
+ }
1633
+
1634
+ const pathsOverlap = repositoryPathsOverlap
1635
+ export const CONSUMER_CONTROL_PLANE_PATHS = Object.freeze([
1636
+ 'package.json',
1637
+ 'package-lock.json',
1638
+ 'npm-shrinkwrap.json',
1639
+ 'governance/lock.json',
1640
+ 'governance/lock.schema.json',
1641
+ 'scripts/governance-check.mjs',
1642
+ ])
1643
+ export function consumerControlPlaneAuthority(providerPath) {
1644
+ const normalized = normalizeRepositoryRelative(providerPath, 'provider control-plane collision path')
1645
+ const rootSegment = normalized.split('/')[0]
1646
+ if (/^package[^/]*\.json$/.test(portableRepositoryPathKey(rootSegment))) return rootSegment
1647
+ return CONSUMER_CONTROL_PLANE_PATHS.find((reserved) => pathsOverlap(normalized, reserved)) || null
1648
+ }
1649
+ const validatedProviderTransitions = new WeakSet()
1650
+ const deepFreeze = (value) => {
1651
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value
1652
+ for (const child of Object.values(value)) deepFreeze(child)
1653
+ return Object.freeze(value)
1654
+ }
1655
+ const certifyProviderTransition = (transition) => {
1656
+ deepFreeze(transition)
1657
+ validatedProviderTransitions.add(transition)
1658
+ return transition
1659
+ }
1660
+
1661
+ const nonProviderTransitionAuthority = (corpus, label) => {
1662
+ const consumer = corpus?.manifest?.consumer
1663
+ if (!consumer || typeof consumer !== 'object' || Array.isArray(consumer)) {
1664
+ throw new Error(`${label} consumer authority is missing`)
1665
+ }
1666
+ const launcherDestination = normalizeRepositoryRelative(
1667
+ consumer.launcherDestination,
1668
+ `${label} shared launcher destination`,
1669
+ )
1670
+ const discoveryPolicy = structuredClone(validateDiscoveryPolicy(corpus?.manifest?.discoveryPolicy, `${label} discovery policy`))
1671
+ const launchers = sortedUniqueStrings(corpus?.manifest?.launchers, `${label} shared launcher inventory`)
1672
+ for (const [index, name] of launchers.entries()) {
1673
+ if (!/^[A-Za-z0-9._-]+\.(?:sh|mjs|py)$/.test(name)) throw new Error(`${label} shared launcher[${index}] is invalid`)
1674
+ }
1675
+
1676
+ const managedFiles = consumer.managedFiles
1677
+ if (!managedFiles || typeof managedFiles !== 'object' || Array.isArray(managedFiles)) {
1678
+ throw new Error(`${label} consumer managed-file authority must be an object`)
1679
+ }
1680
+ const managedDestinations = Object.keys(managedFiles).map((destination) => {
1681
+ const normalized = normalizeRepositoryRelative(destination, `${label} consumer managed-file destination`)
1682
+ if (normalized !== destination || typeof managedFiles[destination] !== 'string' || !managedFiles[destination]) {
1683
+ throw new Error(`${label} consumer managed-file mapping is invalid:${destination}`)
1684
+ }
1685
+ return normalized
1686
+ }).sort()
1687
+ if (managedDestinations.length !== new Set(managedDestinations.map(portableRepositoryPathKey)).size) {
1688
+ throw new Error(`${label} consumer managed-file authority has portable aliases`)
1689
+ }
1690
+ // The authenticated shared-launcher substrate reserves its parent governance namespace too.
1691
+ // This lets a later release add exact-hash, non-executable governance data beside governance/bin
1692
+ // without claiming a product-owned root or requiring an artificial bootstrap. The protected
1693
+ // evidence verifier still rejects every governance/bin/** ordinary-upgrade mutation.
1694
+ const managedNamespaceRoots = [
1695
+ ...managedDestinations.filter((destination) => destination.includes('/'))
1696
+ .map((destination) => destination.split('/').slice(0, -1).join('/')),
1697
+ ...(launcherDestination.includes('/') ? [launcherDestination.split('/').slice(0, -1).join('/')] : []),
1698
+ ]
1699
+ .sort((left, right) => (
1700
+ left.split('/').length - right.split('/').length || compareUtf8Bytes(left, right)
1701
+ ))
1702
+ .filter((candidate, index, values) => !values.slice(0, index).some((root) => {
1703
+ const candidateKey = portableRepositoryPathKey(candidate)
1704
+ const rootKey = portableRepositoryPathKey(root)
1705
+ return candidateKey === rootKey || candidateKey.startsWith(`${rootKey}/`)
1706
+ }))
1707
+ .sort()
1708
+
1709
+ const requiredScripts = corpus?.bom?.payload?.requiredScripts
1710
+ mergeRequiredPackageScripts({ scripts: {} }, requiredScripts)
1711
+ const requiredScriptNames = Object.keys(requiredScripts)
1712
+ const exactMaterialization = sortedUniqueStrings(
1713
+ consumer?.materialization?.exactPaths,
1714
+ `${label} exact materialization inventory`,
1715
+ ).map((path, index) => normalizeRepositoryRelative(path, `${label} exact materialization[${index}]`))
1716
+ const exactMaterializationPaths = new Set(exactMaterialization)
1717
+ const ownedMaterialization = [
1718
+ ...launchers.map((name) => `${launcherDestination}/${name}`),
1719
+ ...managedDestinations,
1720
+ 'package.json',
1721
+ ].sort()
1722
+ for (const path of ownedMaterialization) {
1723
+ if (!exactMaterializationPaths.has(path)) {
1724
+ throw new Error(`${label} materialization inventory omits non-provider authority:${path}`)
1725
+ }
1726
+ }
1727
+
1728
+ return {
1729
+ discoveryPolicy,
1730
+ launcherDestination,
1731
+ launchers,
1732
+ managedDestinations,
1733
+ managedNamespaceRoots,
1734
+ managedFiles: Object.fromEntries(Object.entries(managedFiles).sort(([left], [right]) => compareUtf8Bytes(left, right))),
1735
+ requiredScriptNames,
1736
+ requiredScripts: Object.fromEntries(Object.entries(requiredScripts)),
1737
+ }
1738
+ }
1739
+
1740
+ const assertMonotonicNonProviderAuthority = (previousCorpus, currentCorpus, { exact }) => {
1741
+ const previous = nonProviderTransitionAuthority(previousCorpus, 'previous installed corpus')
1742
+ const current = nonProviderTransitionAuthority(currentCorpus, 'incoming installed corpus')
1743
+ if (current.launcherDestination !== previous.launcherDestination) {
1744
+ throw new Error('ordinary upgrade may not rename the shared launcher destination')
1745
+ }
1746
+ if (exact) {
1747
+ if (JSON.stringify(current) !== JSON.stringify(previous)) {
1748
+ throw new Error('same-version refresh is not an exact non-provider lifecycle replay')
1749
+ }
1750
+ return { previous, current }
1751
+ }
1752
+ for (const [kind, previousNames, currentNames] of [
1753
+ ['shared launcher', previous.launchers, current.launchers],
1754
+ ['consumer managed-file authority', previous.managedDestinations, current.managedDestinations],
1755
+ ['required package script', previous.requiredScriptNames, current.requiredScriptNames],
1756
+ ]) {
1757
+ const incoming = new Set(currentNames)
1758
+ for (const name of previousNames) {
1759
+ if (!incoming.has(name)) {
1760
+ throw new Error(`ordinary upgrade may not remove or rename ${kind}; it would leave an orphan:${name}`)
1761
+ }
1762
+ }
1763
+ }
1764
+ for (const name of previous.requiredScriptNames) {
1765
+ if (current.requiredScripts[name] !== previous.requiredScripts[name]) {
1766
+ throw new Error(`ordinary upgrade may not change an existing required package script command; move command evolution through the reviewed bootstrap boundary:${name}`)
1767
+ }
1768
+ }
1769
+ const previousManagedDestinations = new Set(previous.managedDestinations.map(portableRepositoryPathKey))
1770
+ for (const destination of current.managedDestinations) {
1771
+ const destinationKey = portableRepositoryPathKey(destination)
1772
+ if (previousManagedDestinations.has(destinationKey)) continue
1773
+ const reserved = previous.managedNamespaceRoots.some((root) => {
1774
+ const rootKey = portableRepositoryPathKey(root)
1775
+ return destinationKey.startsWith(`${rootKey}/`)
1776
+ })
1777
+ if (!reserved) {
1778
+ throw new Error(
1779
+ 'ordinary upgrade may not establish consumer managed-file authority in a new product namespace; '
1780
+ + `use the reviewed bootstrap boundary:${destination}`,
1781
+ )
1782
+ }
1783
+ }
1784
+ for (const key of DISCOVERY_KEYS) {
1785
+ const incoming = new Set(current.discoveryPolicy[key].map(portableRepositoryPathKey))
1786
+ for (const entry of previous.discoveryPolicy[key]) {
1787
+ if (!incoming.has(portableRepositoryPathKey(entry))) {
1788
+ throw new Error(`ordinary upgrade may not shrink or rename discovery policy ${key}:${entry}`)
1789
+ }
1790
+ }
1791
+ const previousEntries = new Set(previous.discoveryPolicy[key].map(portableRepositoryPathKey))
1792
+ for (const entry of current.discoveryPolicy[key]) {
1793
+ if (
1794
+ !previousEntries.has(portableRepositoryPathKey(entry))
1795
+ && !discoveryPolicyReservesPath(previous.discoveryPolicy, entry)
1796
+ ) {
1797
+ throw new Error(
1798
+ 'ordinary upgrade may not establish a new provider discovery namespace; '
1799
+ + `use the reviewed bootstrap boundary:${key}:${entry}`,
1800
+ )
1801
+ }
1802
+ }
1803
+ }
1804
+ return { previous, current }
1805
+ }
1806
+
1807
+ // Ordinary upgrades authenticate both ends of the transition. Provider surfaces may disappear only
1808
+ // through an exact tombstone. Shared launchers, consumer-managed files, and required package scripts
1809
+ // are monotonic because the generic materializer updates/adds them but intentionally has no unsigned
1810
+ // deletion/rename path; accepting a drop would leave stale executable authority in the consumer.
1811
+ // Historical tombstones are an append-only prefix and same-version repair is an exact replay.
1812
+ export function validateInstalledProviderTransition(previousCorpus, currentCorpus) {
1813
+ const previousLifecycle = previousCorpus?.manifest?.providerLifecycle
1814
+ const currentLifecycle = currentCorpus?.manifest?.providerLifecycle
1815
+ if (!previousLifecycle || !currentLifecycle) throw new Error('provider transition requires two validated installed corpora')
1816
+ for (const [label, corpus, lifecycle] of [
1817
+ ['previous', previousCorpus, previousLifecycle],
1818
+ ['current', currentCorpus, currentLifecycle],
1819
+ ]) {
1820
+ if (lifecycle.schemaVersion !== 4) continue
1821
+ const snapshotView = snapshotActiveSurfaceView(lifecycle.currentSnapshot)
1822
+ const activeView = snapshotActiveSurfaceView({ providers: corpus.activeProviders })
1823
+ if (JSON.stringify(snapshotView) !== JSON.stringify(activeView)) {
1824
+ throw new Error(`${label} corpus active provider ids/surfaces differ from its authenticated currentSnapshot`)
1825
+ }
1826
+ }
1827
+ const ordering = compareVersion(currentLifecycle.releaseVersion, previousLifecycle.releaseVersion)
1828
+ if (ordering < 0) throw new Error('provider transition may not downgrade')
1829
+ const nonProviderAuthority = assertMonotonicNonProviderAuthority(previousCorpus, currentCorpus, { exact: ordering === 0 })
1830
+ if (ordering === 0) {
1831
+ for (const [label, evidence] of [
1832
+ ['previous provider corpus evidence', previousCorpus.evidence],
1833
+ ['current provider corpus evidence', currentCorpus.evidence],
1834
+ ]) {
1835
+ exactKeys(evidence, [
1836
+ 'consumerBomSha256', 'forkCorpusLockSha256', 'manifestSha256',
1837
+ 'providerLifecycleSha256', 'releaseVersion',
1838
+ ], label)
1839
+ if (
1840
+ !EXACT_SEMVER.test(evidence.releaseVersion || '')
1841
+ || evidence.releaseVersion !== currentLifecycle.releaseVersion
1842
+ || ![
1843
+ evidence.consumerBomSha256,
1844
+ evidence.forkCorpusLockSha256,
1845
+ evidence.manifestSha256,
1846
+ evidence.providerLifecycleSha256,
1847
+ ].every((digest) => SHA256.test(digest || ''))
1848
+ ) throw new Error(`${label} is invalid or release-mismatched`)
1849
+ }
1850
+ if (
1851
+ JSON.stringify(currentCorpus.evidence) !== JSON.stringify(previousCorpus.evidence)
1852
+ ||
1853
+ currentLifecycle.currentSnapshotSha256 !== previousLifecycle.currentSnapshotSha256
1854
+ || currentLifecycle.currentProviderInventorySha256 !== previousLifecycle.currentProviderInventorySha256
1855
+ || JSON.stringify(currentLifecycle.retiredProviders) !== JSON.stringify(previousLifecycle.retiredProviders)
1856
+ || JSON.stringify(currentCorpus.activeProviders) !== JSON.stringify(previousCorpus.activeProviders)
1857
+ ) throw new Error(`${currentLifecycle.releaseVersion}:same-version provider refresh is not an exact corpus/lifecycle replay`)
1858
+ return certifyProviderTransition({
1859
+ paths: collectProviderMutationPaths(currentCorpus.manifest, currentCorpus.activeProviders),
1860
+ additions: [],
1861
+ managedAdditions: [],
1862
+ retirements: [],
1863
+ mode: 'replay',
1864
+ })
1865
+ }
1866
+ if (currentLifecycle.schemaVersion !== 4) {
1867
+ throw new Error(`${currentLifecycle.releaseVersion}:legacy provider lifecycle v3 may be a prior corpus or exact same-version replay, never a new upgrade target`)
1868
+ }
1869
+
1870
+ const immutableHeadSurfaceView = snapshotActiveSurfaceView(currentLifecycle.immutableHeadSnapshot)
1871
+ const priorActiveSurfaceView = snapshotActiveSurfaceView({ providers: previousCorpus.activeProviders })
1872
+ if (JSON.stringify(immutableHeadSurfaceView) !== JSON.stringify(priorActiveSurfaceView)) {
1873
+ throw new Error(`${currentLifecycle.releaseVersion}:immutableHeadSnapshot provider ids/surfaces do not exactly match the prior active corpus`)
1874
+ }
1875
+ if (
1876
+ previousLifecycle.schemaVersion === 4
1877
+ && JSON.stringify(currentLifecycle.immutableHeadSnapshot) !== JSON.stringify(previousLifecycle.currentSnapshot)
1878
+ ) {
1879
+ throw new Error(`${currentLifecycle.releaseVersion}:immutableHeadSnapshot is not the exact previous authenticated currentSnapshot`)
1880
+ }
1881
+
1882
+ const previousCommon = previousCorpus.manifest?.consumer?.commonInstruction
1883
+ const currentCommon = currentCorpus.manifest?.consumer?.commonInstruction
1884
+ if (
1885
+ !previousCommon
1886
+ || !currentCommon
1887
+ || currentCommon.destination !== previousCommon.destination
1888
+ || currentCommon.materializerId !== previousCommon.materializerId
1889
+ ) {
1890
+ throw new Error(`${currentLifecycle.releaseVersion}:ordinary upgrade may not rename or rematerialize the common instruction authority`)
1891
+ }
1892
+
1893
+ if (currentLifecycle.previousSnapshotSha256 !== previousLifecycle.currentSnapshotSha256) {
1894
+ throw new Error(`${currentLifecycle.releaseVersion}:provider transition does not bind immediately previous release ${previousLifecycle.releaseVersion}`)
1895
+ }
1896
+ if (
1897
+ currentLifecycle.immutableHead.releaseVersion !== previousLifecycle.releaseVersion
1898
+ || currentLifecycle.immutableHead.snapshotSha256 !== previousLifecycle.currentSnapshotSha256
1899
+ || currentLifecycle.immutableHead.providerInventorySha256 !== previousLifecycle.currentProviderInventorySha256
1900
+ ) throw new Error(`${currentLifecycle.releaseVersion}:immutable provider head does not bind previous release inventory`)
1901
+
1902
+ const previousHistory = previousLifecycle.retiredProviders
1903
+ const currentHistory = currentLifecycle.retiredProviders
1904
+ if (currentHistory.length < previousHistory.length || JSON.stringify(currentHistory.slice(0, previousHistory.length)) !== JSON.stringify(previousHistory)) {
1905
+ throw new Error(`${currentLifecycle.releaseVersion}:retired provider history is not append-only`)
1906
+ }
1907
+ const previousById = new Map(currentLifecycle.immutableHeadSnapshot.providers.map((provider) => [provider.id, provider]))
1908
+ const currentById = new Map(currentLifecycle.currentSnapshot.providers.map((provider) => [provider.id, provider]))
1909
+ for (const [id, previous] of previousById) {
1910
+ const current = currentById.get(id)
1911
+ if (!current) continue
1912
+ const currentKinds = new Map(current.surfaces.map((surface) => [surface.path, surface.kind]))
1913
+ for (const surface of previous.surfaces) {
1914
+ if (currentKinds.get(surface.path) !== surface.kind) {
1915
+ throw new Error(`${currentLifecycle.releaseVersion}:${id} removed or changed ${surface.path} without retiring the provider`)
1916
+ }
1917
+ }
1918
+ const previousSurfacePaths = new Set(previous.surfaces.map((surface) => portableRepositoryPathKey(surface.path)))
1919
+ for (const surface of current.surfaces) {
1920
+ if (
1921
+ !previousSurfacePaths.has(portableRepositoryPathKey(surface.path))
1922
+ && !discoveryPolicyReservesPath(previous.discovery, surface.path)
1923
+ ) {
1924
+ throw new Error(
1925
+ `${currentLifecycle.releaseVersion}:${id} added managed surface outside its immutable provider discovery namespace:`
1926
+ + `${surface.path}; establish new namespaces through reviewed bootstrap`,
1927
+ )
1928
+ }
1929
+ }
1930
+ }
1931
+ const removedIds = [...previousById.keys()].filter((id) => !currentById.has(id)).sort()
1932
+ const appended = currentHistory.slice(previousHistory.length)
1933
+ const appendedIds = appended.map((retirement) => retirement.id).sort()
1934
+ if (JSON.stringify(removedIds) !== JSON.stringify(appendedIds)) {
1935
+ throw new Error(`${currentLifecycle.releaseVersion}:provider additions/removals do not match appended retirement history`)
1936
+ }
1937
+ const activeSurfaces = currentLifecycle.currentSnapshot.providers.flatMap((provider) => provider.surfaces.map((surface) => ({ ...surface, providerId: provider.id })))
1938
+ for (const retirement of appended) {
1939
+ const previous = previousById.get(retirement.id)
1940
+ const transfers = retirement.transfers || []
1941
+ const partition = [
1942
+ ...retirement.surfaces.map(({ path, kind }) => ({ path, kind })),
1943
+ ...transfers.map(({ path, kind }) => ({ path, kind })),
1944
+ ].sort((left, right) => compareUtf8Bytes(left.path, right.path))
1945
+ if (partition.length !== new Set(partition.map((surface) => portableRepositoryPathKey(surface.path))).size || JSON.stringify(partition) !== JSON.stringify(previous.surfaces)) {
1946
+ throw new Error(`${retirement.id}:deletion and transfer records do not exactly partition previously managed destinations`)
1947
+ }
1948
+ const replacement = retirement.replacementProviderId === null ? null : currentById.get(retirement.replacementProviderId)
1949
+ if (retirement.replacementProviderId !== null && (!replacement || retirement.replacementProviderId === retirement.id)) {
1950
+ throw new Error(`${retirement.id}:replacementProviderId must name a distinct active current provider`)
1951
+ }
1952
+ if (!replacement && transfers.length) throw new Error(`${retirement.id}:null replacementProviderId cannot transfer surfaces`)
1953
+ for (const surface of retirement.surfaces) {
1954
+ if (activeSurfaces.some((candidate) => pathsOverlap(candidate.path, surface.path))) {
1955
+ throw new Error(`${retirement.id}:deletion tombstone remains owned by an active provider:${surface.path}`)
1956
+ }
1957
+ }
1958
+ for (const surface of transfers) {
1959
+ if (!replacement.surfaces.some((candidate) => candidate.path === surface.path && candidate.kind === surface.kind)) {
1960
+ throw new Error(`${retirement.id}:transfer is not exactly owned by replacement ${retirement.replacementProviderId}:${surface.path}`)
1961
+ }
1962
+ if (activeSurfaces.some((candidate) => candidate.providerId !== replacement.id && pathsOverlap(candidate.path, surface.path))) {
1963
+ throw new Error(`${retirement.id}:transfer is also owned by a non-replacement provider:${surface.path}`)
1964
+ }
1965
+ }
1966
+ if (
1967
+ retirement.retiredInVersion !== currentLifecycle.releaseVersion
1968
+ || retirement.priorReleaseVersion !== previousLifecycle.releaseVersion
1969
+ || retirement.priorSnapshotSha256 !== previousLifecycle.currentSnapshotSha256
1970
+ ) throw new Error(`${retirement.id}:retirement version/origin does not bind the current transition`)
1971
+ }
1972
+ const previousActivePaths = new Map(currentLifecycle.immutableHeadSnapshot.providers.flatMap((provider) => (
1973
+ provider.surfaces.map((surface) => [surface.path, surface.kind])
1974
+ )))
1975
+ const additions = currentLifecycle.currentSnapshot.providers.flatMap((provider) => provider.surfaces
1976
+ .filter((surface) => previousActivePaths.get(surface.path) !== surface.kind)
1977
+ .map((surface) => ({ providerId: provider.id, path: surface.path, kind: surface.kind })))
1978
+ .sort((left, right) => (
1979
+ compareUtf8Bytes(left.path, right.path) || compareUtf8Bytes(left.providerId, right.providerId)
1980
+ ))
1981
+ for (const addition of additions) {
1982
+ if (!discoveryPolicyReservesPath(nonProviderAuthority.previous.discoveryPolicy, addition.path)) {
1983
+ throw new Error(
1984
+ `${currentLifecycle.releaseVersion}:${addition.providerId} added managed surface outside every previously reviewed provider namespace:`
1985
+ + `${addition.path}; establish the namespace through reviewed bootstrap`,
1986
+ )
1987
+ }
1988
+ }
1989
+ const previousManagedDestinations = new Set(
1990
+ nonProviderAuthority.previous.managedDestinations.map(portableRepositoryPathKey),
1991
+ )
1992
+ const managedAdditions = nonProviderAuthority.current.managedDestinations
1993
+ .filter((destination) => !previousManagedDestinations.has(portableRepositoryPathKey(destination)))
1994
+ .sort()
1995
+ return certifyProviderTransition({
1996
+ paths: collectProviderMutationPaths(currentCorpus.manifest, currentCorpus.activeProviders),
1997
+ additions,
1998
+ managedAdditions,
1999
+ retirements: structuredClone(appended),
2000
+ mode: 'upgrade',
2001
+ })
2002
+ }
2003
+
2004
+ export function assertUnclaimedManagedAdditions(projectDir, managedAdditions) {
2005
+ projectDir = canonicalRepositoryRoot(projectDir)
2006
+ if (!Array.isArray(managedAdditions)) throw new Error('managed additions must be a closed array')
2007
+ const normalized = managedAdditions.map((destination, index) => {
2008
+ const path = normalizeRepositoryRelative(destination, `managed transition addition[${index}]`)
2009
+ if (path !== destination) throw new Error(`managed transition addition[${index}] is not canonical`)
2010
+ return path
2011
+ })
2012
+ if (
2013
+ JSON.stringify(normalized) !== JSON.stringify([...new Set(normalized)].sort())
2014
+ || normalized.length !== new Set(normalized.map(portableRepositoryPathKey)).size
2015
+ ) throw new Error('managed additions must be sorted, unique, and portable')
2016
+ for (const destination of normalized) {
2017
+ const collision = existingPortablePathCollision(projectDir, destination)
2018
+ if (collision) {
2019
+ throw new Error(`new consumer managed-file target already exists:${destination}`)
2020
+ }
2021
+ assertNoSymlinkPath(projectDir, join(projectDir, destination), `new consumer managed-file target:${destination}`)
2022
+ }
2023
+ return normalized
2024
+ }
2025
+
2026
+ const refreshTransactionCapabilities = new WeakSet()
2027
+ export function authorizeProviderRefreshTransaction({ verifiedCorpus, providerTransition, journalProviderSnapshot }) {
2028
+ if (!verifiedCorpus || !providerTransition || !journalProviderSnapshot) throw new Error('provider refresh authorization requires validated corpus, transition, and durable journal snapshot')
2029
+ exactKeys(journalProviderSnapshot, ['entries', 'evidence', 'evidenceRoot', 'paths'], 'durable provider journal snapshot')
2030
+ if (
2031
+ !validatedProviderTransitions.has(providerTransition)
2032
+ ||
2033
+ JSON.stringify(journalProviderSnapshot.evidence) !== JSON.stringify(verifiedCorpus.evidence)
2034
+ || typeof journalProviderSnapshot.evidenceRoot !== 'string'
2035
+ || !isAbsolute(journalProviderSnapshot.evidenceRoot)
2036
+ || JSON.stringify(journalProviderSnapshot.paths) !== JSON.stringify(providerTransition.paths)
2037
+ || !Array.isArray(journalProviderSnapshot.entries)
2038
+ || journalProviderSnapshot.entries.length === 0
2039
+ || journalProviderSnapshot.entries.length !== providerTransition.paths.length
2040
+ ) throw new Error('provider refresh authorization is not bound to the durable journal/corpus path set')
2041
+ const backupPaths = new Set()
2042
+ for (const [index, entry] of journalProviderSnapshot.entries.entries()) {
2043
+ exactKeys(entry, ['backup', 'path', 'present', 'source'], `durable provider journal entry[${index}]`)
2044
+ const expectedPath = providerTransition.paths[index].path
2045
+ const expectedSource = join(verifiedCorpus.projectDir, expectedPath)
2046
+ if (
2047
+ entry.path !== expectedPath
2048
+ || entry.source !== expectedSource
2049
+ || typeof entry.backup !== 'string'
2050
+ || !isAbsolute(entry.backup)
2051
+ || entry.backup === entry.source
2052
+ || typeof entry.present !== 'boolean'
2053
+ || backupPaths.has(portableRepositoryPathKey(entry.backup))
2054
+ ) throw new Error(`durable provider journal entry[${index}] is not a closed recovery record`)
2055
+ backupPaths.add(portableRepositoryPathKey(entry.backup))
2056
+ }
2057
+ const capability = Object.freeze({ mode: 'durable', verifiedCorpus, providerTransition, journalProviderSnapshot })
2058
+ refreshTransactionCapabilities.add(capability)
2059
+ return capability
2060
+ }
2061
+
2062
+ // Evidence reconstruction and clean-room tests intentionally mutate only disposable sandboxes and
2063
+ // therefore have no crash-recovery journal to bind. Keep that authority explicit, project-bound,
2064
+ // validated, and one-shot rather than weakening the production durable authorizer with fake entries.
2065
+ export function authorizeDisposableProviderRefreshTransaction({ projectDir, verifiedCorpus, providerTransition }) {
2066
+ const disposableRoot = canonicalRepositoryRoot(projectDir)
2067
+ if (
2068
+ !verifiedCorpus
2069
+ || disposableRoot !== verifiedCorpus.projectDir
2070
+ || !validatedProviderTransitions.has(providerTransition)
2071
+ || JSON.stringify(providerTransition.paths) !== JSON.stringify(collectProviderMutationPaths(verifiedCorpus.manifest))
2072
+ ) throw new Error('disposable provider refresh authorization is not bound to its validated sandbox corpus/transition')
2073
+ const capability = Object.freeze({
2074
+ mode: 'disposable',
2075
+ projectDir: disposableRoot,
2076
+ verifiedCorpus,
2077
+ providerTransition,
2078
+ })
2079
+ refreshTransactionCapabilities.add(capability)
2080
+ return capability
2081
+ }
2082
+
2083
+ // 刷新 projectDir 的接線骨架;回傳 {copied, removed, settingsMerged, skills, commands, agents, codex, governance, managed, codexSkipped, skipped, dryRun}
2084
+ // opts.dryRun = true → 只計算會做什麼(result 照填),不寫任何檔(§15 dry-run 契約)
2085
+ export function refreshLaunchers(projectDir, opts = {}) {
2086
+ projectDir = canonicalRepositoryRoot(projectDir)
2087
+ const dryRun = !!opts.dryRun
2088
+ const result = { copied: [], removed: [], retired: [], settingsMerged: false, skills: [], commands: [], agents: [], providers: {}, codex: [], governance: [], managed: [], codexSkipped: [], skipped: null, dryRun }
2089
+
2090
+ // opt-out:fork user 明確不要官方覆蓋骨架
2091
+ if (existsSync(join(projectDir, '.github/no-governance-sync'))) {
2092
+ result.skipped = 'opt-out(.github/no-governance-sync 存在)'
2093
+ return result
2094
+ }
2095
+
2096
+ const candidateForkRoot = join(projectDir, 'node_modules/@qijenchen/design-system/ds-canonical/fork')
2097
+ const src = join(candidateForkRoot, 'launchers')
2098
+ assertSafeTree(projectDir, src, 'installed launcher corpus', { allowMissing: true })
2099
+ if (!existsSync(join(src, 'settings-hooks.json'))) {
2100
+ // 只有「治理 corpus 整個不在」才是合法 skip(舊 npm / 未安裝)。corpus 在、卻沒有本世代的
2101
+ // settings-hooks.json = 另一世代把 merge policy 搬走了 → fail-closed throw,絕不靜默 skip
2102
+ //(F6 對偶:靜默 skip 讓 fork 永遠停在 stale 接線,治理斷線無人知)。
2103
+ if (existsSync(join(candidateForkRoot, 'manifest.json'))) {
2104
+ throw new Error(
2105
+ 'installed fork corpus exists but ships no launchers/settings-hooks.json — the installed release uses a scaffold generation this scripts/refresh-fork-launchers.mjs does not understand; '
2106
+ + 'migrate the fork scaffold first (npm run sync-all -- --apply --to <exact-version>) instead of refreshing with this script generation.'
2107
+ )
2108
+ }
2109
+ result.skipped = 'launchers 未 ship(npm 套件版本過舊或治理本體未安裝)'
2110
+ return result
2111
+ }
2112
+ const verifiedCorpus = opts.verifiedCorpus || validateInstalledForkCorpus(projectDir)
2113
+ const { forkRoot, manifest } = verifiedCorpus
2114
+ const providerTransition = opts.providerTransition || validateInstalledProviderTransition(verifiedCorpus, verifiedCorpus)
2115
+ if (
2116
+ !validatedProviderTransitions.has(providerTransition)
2117
+ || JSON.stringify(providerTransition.paths) !== JSON.stringify(collectProviderMutationPaths(manifest))
2118
+ ) {
2119
+ throw new Error('prepared provider transition does not match the validated installed manifest')
2120
+ }
2121
+ if (
2122
+ !Array.isArray(providerTransition.additions)
2123
+ || !Array.isArray(providerTransition.managedAdditions)
2124
+ || !Array.isArray(providerTransition.retirements)
2125
+ ) {
2126
+ throw new Error('prepared provider transition has no closed addition/retirement authorization')
2127
+ }
2128
+ if (!dryRun) {
2129
+ const capability = opts.transactionCapability
2130
+ if (
2131
+ !refreshTransactionCapabilities.has(capability)
2132
+ || capability.verifiedCorpus !== verifiedCorpus
2133
+ || capability.providerTransition !== providerTransition
2134
+ || !['durable', 'disposable'].includes(capability.mode)
2135
+ || (capability.mode === 'disposable' && capability.projectDir !== projectDir)
2136
+ || (capability.mode === 'durable' && !capability.journalProviderSnapshot)
2137
+ ) throw new Error('provider refresh mutation requires an authorized one-shot transaction capability')
2138
+ // One capability authorizes one materialization attempt. Rollback remains sync-all's job.
2139
+ refreshTransactionCapabilities.delete(capability)
2140
+ }
2141
+
2142
+ // Parse and close-shape the BOM-bound settings migration policy before the first workspace
2143
+ // mutation. A malformed generated policy can therefore never leave a partial launcher refresh.
2144
+ const canonical = validateCanonicalSettingsWiring(JSON.parse(readFileSync(join(src, 'settings-hooks.json'), 'utf8')), manifest)
2145
+ const packageManifestPath = regularUnaliasedFile(projectDir, join(projectDir, 'package.json'), 'consumer package manifest')
2146
+ const packageManifestInfo = lstatSync(packageManifestPath)
2147
+ const currentPackageManifest = JSON.parse(readFileSync(packageManifestPath, 'utf8'))
2148
+ const requiredPackageManifest = mergeRequiredPackageScripts(currentPackageManifest, verifiedCorpus.bom.payload.requiredScripts)
2149
+ const packageScriptsChanged = JSON.stringify(currentPackageManifest.scripts || {}) !== JSON.stringify(requiredPackageManifest.scripts)
2150
+
2151
+ // A generic materializer is intentionally future-compatible, but that cannot become authority
2152
+ // to adopt an existing product file merely because the candidate added a destination under an
2153
+ // already reserved namespace. Every newly claimed managed file must still be absent (including
2154
+ // portable case/Unicode aliases) before the first mutation.
2155
+ assertUnclaimedManagedAdditions(projectDir, providerTransition.managedAdditions)
2156
+
2157
+ // A newly claimed provider root has no prior consumer ownership proof. An authenticated release
2158
+ // may declare the new surface, but it may not silently adopt or clobber a pre-existing product
2159
+ // file/tree at that destination. Retained and explicitly transferred surfaces remain governed.
2160
+ for (const [index, addition] of providerTransition.additions.entries()) {
2161
+ exactKeys(addition, ['kind', 'path', 'providerId'], `provider transition addition[${index}]`)
2162
+ validateSurface({ path: addition.path, kind: addition.kind }, `provider transition addition[${index}]`)
2163
+ if (!/^[a-z][a-z0-9-]*$/.test(addition.providerId || '')) throw new Error(`provider transition addition[${index}].providerId is invalid`)
2164
+ const target = join(projectDir, addition.path)
2165
+ const portableCollision = existingPortablePathCollision(projectDir, addition.path)
2166
+ if (portableCollision) {
2167
+ throw new Error(`new provider surface target already exists:${addition.providerId}:${addition.path}`)
2168
+ }
2169
+ assertNoSymlinkPath(projectDir, target, `new provider surface target:${addition.providerId}:${addition.path}`)
2170
+ }
2171
+
2172
+ // Resolve and validate every closed-tree source/target before the first provider mutation. The
2173
+ // installed manifest and corpus lock authorize the mapping; filesystem aliases may not redirect
2174
+ // either side outside its authenticated root.
2175
+ const productTreePlans = new Map()
2176
+ for (const [providerId, surface] of Object.entries(manifest.providerSurfaces).sort(([a], [b]) => compareUtf8Bytes(a, b))) {
2177
+ if (!surface.generated) continue
2178
+ for (const tree of surface.trees) {
2179
+ if (!safeRelative(forkRoot, tree.artifactRoot) || !safeRelative(projectDir, tree.destination)) {
2180
+ throw new Error(`unsafe ${providerId} product managed tree mapping:${tree.destination} <- ${tree.artifactRoot}`)
2181
+ }
2182
+ const source = join(forkRoot, tree.artifactRoot)
2183
+ const target = join(projectDir, tree.destination)
2184
+ assertSafeTree(projectDir, source, `${providerId} product managed tree ${tree.name} source`)
2185
+ if (!lstatSync(source).isDirectory()) throw new Error(`${providerId} product managed tree source is not a directory:${tree.name}`)
2186
+ assertNoSymlinkPath(projectDir, target, `${providerId} product managed tree ${tree.name} target`)
2187
+ if (pathEntryExists(target)) assertSafeTree(projectDir, target, `${providerId} product managed tree ${tree.name} target`)
2188
+ productTreePlans.set(`${providerId}/${tree.name}`, { source, target, destination: tree.destination })
2189
+ }
2190
+ }
2191
+
2192
+ // A provider rename/removal is an authenticated migration, not an inference from missing current
2193
+ // records. Only exact versioned tombstones in the installed corpus may delete old destinations.
2194
+ const retirementPlan = []
2195
+ for (const retired of providerTransition.retirements) {
2196
+ for (const surface of retired.surfaces) {
2197
+ const validated = validateRetiredSurface(surface, `${retired.id} authenticated tombstone`)
2198
+ if (pathsOverlap(validated.path, manifest.consumer.commonInstruction.destination)) {
2199
+ throw new Error(`${retired.id}:provider tombstone may not delete the common instruction authority`)
2200
+ }
2201
+ if (!safeRelative(projectDir, validated.path)) throw new Error(`unsafe retired provider tombstone:${retired.id}:${validated.path}`)
2202
+ const target = join(projectDir, validated.path)
2203
+ if (!pathEntryExists(target)) continue
2204
+ assertNoSymlinkPath(projectDir, target, `retired provider tombstone ${validated.path}`, { allowMissing: false })
2205
+ const info = lstatSync(target)
2206
+ if ((validated.kind === 'file' && !info.isFile()) || (validated.kind === 'tree' && !info.isDirectory())) {
2207
+ throw new Error(`retired provider tombstone kind mismatch:${validated.path}:${validated.kind}`)
2208
+ }
2209
+ if (validated.kind === 'tree') assertSafeTree(projectDir, target, `retired provider tombstone ${validated.path}`)
2210
+ const actualDigest = providerSurfaceDigest(projectDir, validated)
2211
+ if (actualDigest !== validated.sha256) {
2212
+ throw new Error(`retired provider tombstone content differs from immutable prior artifact:${retired.id}:${validated.path}`)
2213
+ }
2214
+ retirementPlan.push({ ...validated, target })
2215
+ }
2216
+ }
2217
+ // Validate the complete authenticated deletion plan before deleting its first path. A malformed
2218
+ // later record can therefore never leave an earlier provider half-retired.
2219
+ if (!dryRun && packageScriptsChanged) {
2220
+ atomicReplaceRepositoryFile(projectDir, packageManifestPath, JSON.stringify(requiredPackageManifest, null, 2) + '\n', {
2221
+ mode: packageManifestInfo.mode & 0o777,
2222
+ label: 'consumer package governance scripts',
2223
+ })
2224
+ }
2225
+ for (const surface of retirementPlan) {
2226
+ if (!dryRun) rmSync(surface.target, { recursive: surface.kind === 'tree', force: false })
2227
+ result.retired.push(surface.path)
2228
+ }
2229
+
2230
+ // 1. Materialize one provider-neutral launcher tree. Provider configs may reference it, but no
2231
+ // provider owns it; retiring `.claude` therefore cannot delete Codex/future runtime dependencies.
2232
+ const launcherDestination = normalizeRepositoryRelative(manifest.consumer.launcherDestination, 'shared launcher destination')
2233
+ const launcherDir = join(projectDir, launcherDestination)
2234
+ assertNoSymlinkPath(projectDir, launcherDir, 'shared launcher directory')
2235
+ if (!dryRun) {
2236
+ mkdirSync(launcherDir, { recursive: true })
2237
+ assertNoSymlinkPath(projectDir, launcherDir, 'shared launcher directory', { allowMissing: false })
2238
+ }
2239
+ const launcherFiles = readdirSync(src).filter((f) => f.endsWith('.sh') || f.endsWith('.mjs') || f.endsWith('.py')).sort()
2240
+ if (JSON.stringify(launcherFiles) !== JSON.stringify(manifest.launchers)) {
2241
+ throw new Error('installed launcher artifact tree differs from its closed manifest inventory')
2242
+ }
2243
+ for (const f of launcherFiles) {
2244
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source: join(src, f), targetRoot: projectDir, target: join(launcherDir, f), label: `launcher ${f}` })
2245
+ result.copied.push(f)
2246
+ }
2247
+ // 2. Idempotently merge every registered template-backed hook surface. The policy inventory,
2248
+ // materializer and base-template plugin are all manifest/corpus facts; provider ids never select
2249
+ // implementation behavior.
2250
+ for (const [mergeProviderId, policy] of Object.entries(canonical.surfaces).sort(([a], [b]) => compareUtf8Bytes(a, b))) {
2251
+ const settingsRelative = normalizeRepositoryRelative(policy.hookDestination, `${mergeProviderId} template-backed hook destination`)
2252
+ const settingsPath = join(projectDir, settingsRelative)
2253
+ const canonicalHookPath = join(forkRoot, policy.hookArtifact)
2254
+ assertNoSymlinkPath(projectDir, settingsPath, settingsRelative)
2255
+ assertNoSymlinkPath(projectDir, canonicalHookPath, `${mergeProviderId} canonical hook artifact`, { allowMissing: false })
2256
+ const canonicalConfig = JSON.parse(readFileSync(canonicalHookPath, 'utf8'))
2257
+ const currentSettings = existsSync(settingsPath) ? parseJsonc(readFileSync(settingsPath, 'utf8'), settingsRelative) : {}
2258
+ const merged = mergeProviderHookSettings({
2259
+ settings: currentSettings,
2260
+ canonicalConfig,
2261
+ policy,
2262
+ label: `${mergeProviderId} ${settingsRelative}`,
2263
+ })
2264
+ for (const retiredId of merged.retiredIds) if (!result.removed.includes(retiredId)) result.removed.push(retiredId)
2265
+ if (!dryRun) {
2266
+ atomicReplaceRepositoryFile(projectDir, settingsPath, JSON.stringify(merged.settings, null, 2) + '\n', {
2267
+ mode: 0o600,
2268
+ label: settingsRelative,
2269
+ })
2270
+ }
2271
+ result.settingsMerged = true
2272
+ }
2273
+
2274
+ // 3. Materialize only registry-declared legacy discovery leaves. Their exact destinations are
2275
+ // provider lifecycle surfaces, so retiring the owning provider removes them and this phase cannot
2276
+ // resurrect a provider-specific commands/agents tree.
2277
+ for (const category of manifest.consumer.compatibilityCategories) {
2278
+ for (const name of category.entries) {
2279
+ const source = join(forkRoot, category.artifactRoot, name)
2280
+ const destination = join(projectDir, category.destinationRoot, name)
2281
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source, targetRoot: projectDir, target: destination, label: `${category.name}/${name}` })
2282
+ result[category.name].push(name)
2283
+ }
2284
+ }
2285
+
2286
+ // Materialize every BOM-enforced body from the exact installed corpus. This is deliberately
2287
+ // generic: a future release may add a managed file without requiring an older consumer's
2288
+ // sync-all implementation to know that filename. Product-owned files are never in this map.
2289
+ for (const [destination, artifact] of Object.entries(manifest?.consumer?.managedFiles || {}).sort(([a], [b]) => compareUtf8Bytes(a, b))) {
2290
+ if (!safeRelative(projectDir, destination) || !safeRelative(forkRoot, artifact)) {
2291
+ throw new Error(`unsafe consumer managed-file mapping:${destination} <- ${artifact}`)
2292
+ }
2293
+ const source = join(forkRoot, artifact)
2294
+ const target = join(projectDir, destination)
2295
+ if (!dryRun) safeCopyFile({
2296
+ sourceRoot: projectDir,
2297
+ source,
2298
+ targetRoot: projectDir,
2299
+ target,
2300
+ label: `consumer managed body ${destination}`,
2301
+ })
2302
+ result.managed.push(destination)
2303
+ }
2304
+
2305
+ // The shared instruction is materialized once from its consumer-owned artifact. A provider using
2306
+ // shared-instruction-v1 only references this destination; provider refresh and retirement never
2307
+ // own, duplicate, or delete it.
2308
+ const commonInstruction = manifest.consumer.commonInstruction
2309
+ const commonSource = join(forkRoot, commonInstruction.artifact)
2310
+ const commonDestination = join(projectDir, commonInstruction.destination)
2311
+ if (!dryRun) safeCopyFile({
2312
+ sourceRoot: projectDir,
2313
+ source: commonSource,
2314
+ targetRoot: projectDir,
2315
+ target: commonDestination,
2316
+ label: 'common instruction authority',
2317
+ })
2318
+ result.governance.push(commonInstruction.destination)
2319
+
2320
+ // 4. Provider surfaces—the installed manifest is the inventory. New providers materialize
2321
+ // without adding another provider-id branch here. The template-backed hook view is merged above so
2322
+ // consumer-owned non-governance hooks survive; all other declared hook views are exact generated
2323
+ // files. Skills clobber only the governance-owned names listed by the manifest.
2324
+ if (manifest?.providerSurfaces) {
2325
+ for (const [providerId, surface] of Object.entries(manifest.providerSurfaces).sort(([a], [b]) => compareUtf8Bytes(a, b))) {
2326
+ result.providers[providerId] = { installed: [], exclusions: surface.exclusions || [] }
2327
+ if (!surface.generated) continue
2328
+ const hookMaterializer = surface.hookMaterializerId
2329
+ ? resolveManifestMaterializer(manifest, 'hookViews', surface.hookMaterializerId, `${providerId}.hookMaterializerId`)
2330
+ : null
2331
+ const instructionMaterializer = resolveManifestMaterializer(
2332
+ manifest,
2333
+ 'instructionViews',
2334
+ surface.instructionMaterializerId,
2335
+ `${providerId}.instructionMaterializerId`,
2336
+ )
2337
+ const mappings = [
2338
+ ...(instructionMaterializer.engine === 'shared-instruction-v1'
2339
+ ? []
2340
+ : [['instruction', surface.instructionArtifact, surface.instructionDestination]]),
2341
+ ...(surface.hookArtifact && surface.hookDestination && hookMaterializer?.mergeStrategy === 'replace-document-v1'
2342
+ ? [['hook', surface.hookArtifact, surface.hookDestination]]
2343
+ : []),
2344
+ ]
2345
+ for (const [kind, sourceRel, destination] of mappings) {
2346
+ if (!safeRelative(forkRoot, sourceRel) || !safeRelative(projectDir, destination)) throw new Error(`unsafe ${providerId} ${kind} mapping:${destination} <- ${sourceRel}`)
2347
+ const source = join(forkRoot, sourceRel)
2348
+ if (!existsSync(source)) throw new Error(`${providerId} ${kind} artifact missing:${sourceRel}`)
2349
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source, targetRoot: projectDir, target: join(projectDir, destination), label: `${providerId} ${kind} adapter` })
2350
+ result.providers[providerId].installed.push(destination)
2351
+ if (providerId === 'codex') result.codex.push(destination)
2352
+ }
2353
+ if (hookMaterializer?.mergeStrategy === 'merge-hook-map-into-base-v1') result.providers[providerId].installed.push(surface.hookDestination)
2354
+ for (const name of surface.skills || []) {
2355
+ const sourceRel = `${surface.skillArtifactRoot}/${name}`
2356
+ const destination = `${surface.skillDestination}/${name}`
2357
+ if (!safeRelative(forkRoot, sourceRel) || !safeRelative(projectDir, destination)) throw new Error(`unsafe ${providerId} skill mapping:${destination} <- ${sourceRel}`)
2358
+ const source = join(forkRoot, sourceRel)
2359
+ if (!existsSync(source)) throw new Error(`${providerId} skill artifact missing:${sourceRel}`)
2360
+ if (!dryRun) safeReplaceTree({ sourceRoot: projectDir, source, targetRoot: projectDir, target: join(projectDir, destination), label: `${providerId} skill ${name}` })
2361
+ result.providers[providerId].installed.push(destination)
2362
+ if (!result.skills.includes(name)) result.skills.push(name)
2363
+ if (providerId === 'codex') result.codex.push(destination)
2364
+ }
2365
+ for (const tree of surface.trees) {
2366
+ const plan = productTreePlans.get(`${providerId}/${tree.name}`)
2367
+ if (!plan) throw new Error(`${providerId} product managed tree has no validated materialization plan:${tree.name}`)
2368
+ if (!dryRun) safeReplaceTree({
2369
+ sourceRoot: projectDir,
2370
+ source: plan.source,
2371
+ targetRoot: projectDir,
2372
+ target: plan.target,
2373
+ label: `${providerId} product managed tree ${tree.name}`,
2374
+ })
2375
+ result.providers[providerId].installed.push(plan.destination)
2376
+ if (providerId === 'codex') result.codex.push(plan.destination)
2377
+ }
2378
+ }
2379
+ } else if (manifest?.codex) {
2380
+ // Immutable older releases did not yet contain providerSurfaces. Keep a bounded compatibility
2381
+ // reader so exact upgrades from them can reach the first provider-neutral release.
2382
+ const codexMeta = manifest.codex
2383
+ if (codexMeta.agentsMd && codexMeta.instructionDestination && existsSync(join(forkRoot, codexMeta.agentsMd))) {
2384
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source: join(forkRoot, codexMeta.agentsMd), targetRoot: projectDir, target: join(projectDir, codexMeta.instructionDestination), label: 'legacy common instruction adapter' })
2385
+ result.codex.push(codexMeta.instructionDestination)
2386
+ }
2387
+ if ((codexMeta.hooksJson || []).length && codexMeta.hookArtifact && codexMeta.hookDestination && existsSync(join(forkRoot, codexMeta.hookArtifact))) {
2388
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source: join(forkRoot, codexMeta.hookArtifact), targetRoot: projectDir, target: join(projectDir, codexMeta.hookDestination), label: 'legacy provider hook adapter' })
2389
+ result.codex.push(codexMeta.hookDestination)
2390
+ }
2391
+ for (const name of codexMeta.agentsSkills || []) {
2392
+ const source = join(forkRoot, codexMeta.skillArtifactRoot, name)
2393
+ if (!existsSync(source)) continue
2394
+ const destination = `${codexMeta.skillDestination}/${name}`
2395
+ if (!dryRun) safeReplaceTree({ sourceRoot: projectDir, source, targetRoot: projectDir, target: join(projectDir, destination), label: `legacy provider skill ${name}` })
2396
+ result.codex.push(destination)
2397
+ }
2398
+ }
2399
+
2400
+ // 5. Immutable consumer BOM/schema. These two paths are governance-owned generated views;
2401
+ // local product policy belongs in governance/overlay.md and is never touched here.
2402
+ if (manifest?.consumer) {
2403
+ for (const [sourceKey, destination] of [['governanceLock', 'lock.json'], ['governanceLockSchema', 'lock.schema.json']]) {
2404
+ const sourceRel = manifest.consumer[sourceKey]
2405
+ if (!sourceRel || !existsSync(join(forkRoot, sourceRel))) continue
2406
+ if (!dryRun) {
2407
+ safeCopyFile({ sourceRoot: projectDir, source: join(forkRoot, sourceRel), targetRoot: projectDir, target: join(projectDir, 'governance', destination), label: `governance/${destination}` })
2408
+ }
2409
+ result.governance.push(`governance/${destination}`)
2410
+ }
2411
+ const checkerSource = manifest.consumer.governanceCheck
2412
+ if (checkerSource && existsSync(join(forkRoot, checkerSource))) {
2413
+ const checkerDestination = join(projectDir, 'scripts/governance-check.mjs')
2414
+ if (!dryRun) {
2415
+ safeCopyFile({
2416
+ sourceRoot: projectDir,
2417
+ source: join(forkRoot, checkerSource),
2418
+ targetRoot: projectDir,
2419
+ target: checkerDestination,
2420
+ label: 'governance checker',
2421
+ mode: 0o755,
2422
+ })
2423
+ }
2424
+ result.governance.push('scripts/governance-check.mjs')
2425
+ }
2426
+ // providerSurfaces installs every instruction. Only older immutable corpora need the legacy
2427
+ // consumer.claudeMd fallback.
2428
+ if (!manifest.providerSurfaces) {
2429
+ const claudeSource = manifest.consumer.claudeMd
2430
+ if (claudeSource && existsSync(join(forkRoot, claudeSource))) {
2431
+ if (!dryRun) safeCopyFile({ sourceRoot: projectDir, source: join(forkRoot, claudeSource), targetRoot: projectDir, target: join(projectDir, claudeSource), label: 'legacy provider instruction adapter' })
2432
+ result.governance.push(claudeSource)
2433
+ }
2434
+ }
2435
+ }
2436
+ result.skills.sort()
2437
+ return result
2438
+ }
2439
+
2440
+ // 允許直接 `node scripts/refresh-fork-launchers.mjs [--dry-run] [--json]`(inject hook self-heal 用);
2441
+ // 被 import(sync-all)時不執行。--dry-run 只算不寫;--json 輸出 machine-readable 結果(§15 契約)。
2442
+ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
2443
+ const apply = process.argv.includes('--apply')
2444
+ if (apply) {
2445
+ console.error('refresh-fork-launchers: --apply requires the durable sync-all transaction; run sync-all --apply --to <exact-version>')
2446
+ process.exit(2)
2447
+ }
2448
+ const dryRun = true
2449
+ const asJson = process.argv.includes('--json')
2450
+ const r = refreshLaunchers(process.cwd(), { dryRun })
2451
+ if (asJson) console.log(JSON.stringify(r))
2452
+ else if (r.skipped) console.log(`refresh-fork-launchers: skip(${r.skipped})`)
2453
+ else console.log(`refresh-fork-launchers${dryRun ? '(dry-run)' : ''}: launchers ${r.copied.length} / skills ${(r.skills || []).length} / codex ${(r.codex || []).length} / settings ${r.settingsMerged ? 'merged' : '-'}`)
2454
+ }