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

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 +75 -0
  24. package/dist/components/AgentPanel/agent-logo.d.ts.map +1 -0
  25. package/dist/components/AgentPanel/agent-logo.js +371 -0
  26. package/dist/components/AgentPanel/agent-logo.js.map +1 -0
  27. package/dist/components/AgentPanel/agent-panel.d.ts +183 -0
  28. package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -0
  29. package/dist/components/AgentPanel/agent-panel.js +900 -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 +16 -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} +59 -0
  656. package/dist/index.d.ts +121 -67
  657. package/dist/index.d.ts.map +1 -1
  658. package/dist/index.js +143 -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 +1321 -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 +1321 -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 +672 -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 +1791 -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 +126 -0
  1242. package/src/components/AgentPanel/agent-logo.tsx +491 -0
  1243. package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +127 -0
  1244. package/src/components/AgentPanel/agent-panel.css +59 -0
  1245. package/src/components/AgentPanel/agent-panel.principles.stories.tsx +57 -0
  1246. package/src/components/AgentPanel/agent-panel.spec.md +319 -0
  1247. package/src/components/AgentPanel/agent-panel.stories.tsx +360 -0
  1248. package/src/components/AgentPanel/agent-panel.tsx +1241 -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 +651 -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 +60 -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,2639 @@
1
+ #!/usr/bin/env node
2
+ // Explicit, exact consumer upgrade entrypoint.
3
+ //
4
+ // Default behaviour is read-only planning. Workspace mutation requires BOTH an exact
5
+ // version and `--apply`; mutable dist-tags (`beta`, `latest`) and semver ranges are
6
+ // rejected. Normal fleet upgrades should be performed on a bot/user branch and reviewed
7
+ // as a PR. SessionStart must never call this command with --apply.
8
+
9
+ import {
10
+ closeSync,
11
+ constants as fsConstants,
12
+ cpSync,
13
+ existsSync,
14
+ fstatSync,
15
+ fsyncSync,
16
+ linkSync,
17
+ lstatSync,
18
+ mkdirSync,
19
+ openSync,
20
+ readFileSync,
21
+ readlinkSync,
22
+ readdirSync,
23
+ realpathSync,
24
+ renameSync,
25
+ rmSync,
26
+ writeFileSync,
27
+ } from 'node:fs'
28
+ import { createHash, randomUUID } from 'node:crypto'
29
+ import { spawnSync } from 'node:child_process'
30
+ import { hostname } from 'node:os'
31
+ import { join, dirname, resolve } from 'node:path'
32
+ import { pathToFileURL } from 'node:url'
33
+ import {
34
+ assertNoSymlinkPath,
35
+ assertSafeTree,
36
+ canonicalRepositoryRoot,
37
+ collectProviderMutationPaths,
38
+ normalizeRepositoryRelative,
39
+ pathEntryExists,
40
+ validateInstalledForkCorpus,
41
+ } from './refresh-fork-launchers.mjs'
42
+ import { validateUpgradeTrustPolicy } from './verify-upgrade-provenance.mjs'
43
+ import { reconstructExpectedUpgrade } from './verify-upgrade-evidence.mjs'
44
+ import { REVIEWED_CONTROL_PLANE_UPDATE_ROUTE } from './lib/consumer-control-plane-policy.mjs'
45
+ import { assertNoRootNpmShrinkwrap } from './lib/governance-dependency-bootstrap.mjs'
46
+ import {
47
+ assertClosedGitLocalConfiguration,
48
+ runClosedGit,
49
+ } from './lib/closed-tool-execution.mjs'
50
+ import { compareUtf8Bytes } from './lib/provider-lifecycle.mjs'
51
+
52
+ const repoRoot = canonicalRepositoryRoot(process.cwd())
53
+ assertNoRootNpmShrinkwrap(repoRoot, { errorPrefix: 'GOV-UPGRADE-LOCK-001' })
54
+ const journalPath = join(repoRoot, '.governance-upgrade-journal.json')
55
+ const OWNER_MARKER = '.governance-upgrade-owner.json'
56
+ const LEGACY_JOURNAL_PUBLISH = '.governance-upgrade-journal.publish'
57
+ const JOURNAL_LEASE_SOURCE = '.governance-upgrade-journal.lease'
58
+ const JOURNAL_LEASE_KIND = 'governance-upgrade-journal-lease'
59
+ const JOURNAL_STATE_DIRECTORY = '.governance-upgrade-journal-states'
60
+ const JOURNAL_STATE_KIND = 'governance-upgrade-journal-state'
61
+ const JOURNAL_STATE_NAME = /^state-([0-9]{16})\.json$/
62
+ const JOURNAL_STATE_PUBLISH_NAME = /^\.state-([0-9]{16})\.publish$/
63
+ const TEST_RELEASE_HANDSHAKE_OPTION = '--test-journal-release-handshake'
64
+ const TEST_RELEASE_ACK = '.governance-upgrade-test-release-ack'
65
+ const TEST_GC_FAILURE_OPTION = '--test-transaction-gc-failure'
66
+ const TEST_NODE_MODULES_PUBLISH_HANDSHAKE_OPTION = '--test-node-modules-publish-handshake'
67
+ const TEST_NODE_MODULES_PUBLISH_ACK = '.governance-upgrade-test-node-modules-publish-ack'
68
+ const TEST_CONSUMER_ROLE_GAP_HANDSHAKE_OPTION = '--test-consumer-role-gap-handshake'
69
+ const TEST_CONSUMER_ROLE_GAP_ACK = '.governance-upgrade-test-consumer-role-gap-ack'
70
+ const PROVIDER_CLI_AUTHORITY_MANIFEST = 'infra/governance/providers/provider-cli-toolchain.json'
71
+ const PROVIDER_CLI_CONSUMER_MANIFEST = 'governance/provider-cli-toolchain.json'
72
+ const authorityProviderManifestPresent = pathEntryExists(join(repoRoot, PROVIDER_CLI_AUTHORITY_MANIFEST))
73
+ const TRANSACTION_PATHS = Object.freeze([
74
+ 'package.json', 'package-lock.json', 'npm-shrinkwrap.json', '.npmrc',
75
+ 'governance', 'schemas', '.devcontainer', '.github', 'scripts',
76
+ ])
77
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
78
+ const SHA256_RE = /^[a-f0-9]{64}$/
79
+ const sha256 = (value) => createHash('sha256').update(value).digest('hex')
80
+ const ignoredRepositoryPaths = (repository, paths, label) => {
81
+ const normalized = [...new Set(paths.map((path, index) => (
82
+ normalizeRepositoryRelative(path, `${label} path[${index}]`)
83
+ )))].sort()
84
+ if (!normalized.length) return []
85
+ const probe = runClosedGit([
86
+ 'ls-files', '--others', '--ignored', '--exclude-standard', '-z', '--', ...normalized,
87
+ ], { cwd: repository, output: 'buffer', maxOutputBytes: 64 * 1024 * 1024 })
88
+ if (probe.error || probe.signal !== null || probe.status !== 0 || !Buffer.isBuffer(probe.stdout)) {
89
+ throw new Error(`${label} ignored-inventory probe failed`)
90
+ }
91
+ return Buffer.from(probe.stdout)
92
+ .toString('utf8')
93
+ .split('\0')
94
+ .filter(Boolean)
95
+ .sort()
96
+ }
97
+ const assertNoIgnoredManagedContent = (repository, paths, label) => {
98
+ const ignored = ignoredRepositoryPaths(repository, paths, label)
99
+ if (ignored.length) {
100
+ throw new Error(`${label} contains ignored content outside the reviewable patch boundary:${ignored.join(',')}`)
101
+ }
102
+ }
103
+ const processIsAlive = (pid) => {
104
+ try {
105
+ process.kill(pid, 0)
106
+ return true
107
+ } catch (error) {
108
+ return error?.code !== 'ESRCH'
109
+ }
110
+ }
111
+ const exactKeys = (value, keys, label) => {
112
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object`)
113
+ const actual = Object.keys(value).sort()
114
+ const expected = [...keys].sort()
115
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
116
+ throw new Error(`${label} has an open or incomplete schema`)
117
+ }
118
+ }
119
+ const providerCliStaticReceipt = (value, label, { setup = false } = {}) => {
120
+ exactKeys(
121
+ value,
122
+ ['authorityDigest', 'lockDigest', 'platform', 'role', 'staticVerified', 'status', 'target', 'executablesProbed', 'versions'],
123
+ label,
124
+ )
125
+ if (
126
+ !SHA256_RE.test(value.authorityDigest)
127
+ || !SHA256_RE.test(value.lockDigest)
128
+ || !/^(?:darwin|linux)-(?:arm64|x64)$/.test(value.platform)
129
+ || value.role !== 'consumer'
130
+ || value.staticVerified !== true
131
+ || value.executablesProbed !== false
132
+ || value.versions !== null
133
+ || typeof value.target !== 'string'
134
+ || !value.target
135
+ || !(setup ? ['installed', 'ready'].includes(value.status) : value.status === 'static-verified')
136
+ ) throw new Error(`${label} is not a closed static-only provider CLI receipt`)
137
+ return Object.freeze({
138
+ authorityDigest: value.authorityDigest,
139
+ lockDigest: value.lockDigest,
140
+ platform: value.platform,
141
+ role: value.role,
142
+ staticVerified: true,
143
+ executablesProbed: false,
144
+ runtimeCertified: false,
145
+ })
146
+ }
147
+ const assertSameProviderCliIdentity = (left, right, label) => {
148
+ if (JSON.stringify(left) !== JSON.stringify(right)) {
149
+ throw new Error(`${label} provider CLI identity differs across static verification boundaries`)
150
+ }
151
+ }
152
+ const regularFile = (path, label) => {
153
+ const info = lstatSync(path)
154
+ if (info.isSymbolicLink() || !info.isFile() || info.nlink !== 1) throw new Error(`${label} must be one regular non-symlink file`)
155
+ return path
156
+ }
157
+ const sameFileIdentity = (left, right) => left.dev === right.dev && left.ino === right.ino
158
+ const stableRegularFile = (path, label, { links = null, mode = 0o600 } = {}) => {
159
+ const before = lstatSync(path, { bigint: true })
160
+ if (
161
+ !before.isFile()
162
+ || before.isSymbolicLink()
163
+ || (Array.isArray(links) && !links.includes(Number(before.nlink)))
164
+ || Number(before.mode & 0o777n) !== mode
165
+ ) throw new Error(`${label} is not one closed regular file`)
166
+ const bytes = readFileSync(path)
167
+ const after = lstatSync(path, { bigint: true })
168
+ if (
169
+ !after.isFile()
170
+ || after.isSymbolicLink()
171
+ || !sameFileIdentity(after, before)
172
+ || after.nlink !== before.nlink
173
+ || after.mode !== before.mode
174
+ || after.size !== before.size
175
+ || after.mtimeNs !== before.mtimeNs
176
+ || after.ctimeNs !== before.ctimeNs
177
+ || BigInt(bytes.length) !== before.size
178
+ ) throw new Error(`${label} changed while it was read`)
179
+ return { bytes, info: after }
180
+ }
181
+ const writeFsyncedExclusive = (path, bytes, label) => {
182
+ let descriptor
183
+ try {
184
+ descriptor = openSync(path, 'wx', 0o600)
185
+ writeFileSync(descriptor, bytes)
186
+ fsyncSync(descriptor)
187
+ closeSync(descriptor)
188
+ descriptor = undefined
189
+ } finally {
190
+ if (descriptor !== undefined) closeSync(descriptor)
191
+ }
192
+ const written = stableRegularFile(path, label, { links: [1] })
193
+ if (!written.bytes.equals(bytes)) throw new Error(`${label} readback differs from the published bytes`)
194
+ return written.info
195
+ }
196
+ const journalStateNames = (sequence) => {
197
+ if (!Number.isSafeInteger(sequence) || sequence < 0 || sequence > 9_999_999_999_999_999) {
198
+ throw new Error('upgrade journal state sequence is invalid')
199
+ }
200
+ const suffix = String(sequence).padStart(16, '0')
201
+ return {
202
+ final: `state-${suffix}.json`,
203
+ publish: `.state-${suffix}.publish`,
204
+ }
205
+ }
206
+ const publishJournalState = ({ transactionRoot, journal, sequence, previousStateSha256 }) => {
207
+ const stateRoot = join(transactionRoot, JOURNAL_STATE_DIRECTORY)
208
+ if (sequence === 0) mkdirSync(stateRoot, { mode: 0o700 })
209
+ const rootInfo = lstatSync(stateRoot)
210
+ if (
211
+ !rootInfo.isDirectory()
212
+ || rootInfo.isSymbolicLink()
213
+ || realpathSync(stateRoot) !== stateRoot
214
+ || (rootInfo.mode & 0o777) !== 0o700
215
+ ) throw new Error('upgrade journal state root is unsafe')
216
+ const envelope = {
217
+ schemaVersion: 1,
218
+ kind: JOURNAL_STATE_KIND,
219
+ sequence,
220
+ previousStateSha256,
221
+ journal: structuredClone(journal),
222
+ }
223
+ const bytes = Buffer.from(`${JSON.stringify(envelope, null, 2)}\n`)
224
+ const names = journalStateNames(sequence)
225
+ const publishPath = join(stateRoot, names.publish)
226
+ const finalPath = join(stateRoot, names.final)
227
+ const publishInfo = writeFsyncedExclusive(publishPath, bytes, `upgrade journal state ${sequence} publication object`)
228
+ linkSync(publishPath, finalPath)
229
+ const final = stableRegularFile(finalPath, `upgrade journal state ${sequence}`, { links: [2] })
230
+ const alias = lstatSync(publishPath, { bigint: true })
231
+ if (
232
+ !sameFileIdentity(final.info, publishInfo)
233
+ || !sameFileIdentity(final.info, alias)
234
+ || alias.nlink !== 2n
235
+ ) throw new Error(`upgrade journal state ${sequence} publication alias is not exact`)
236
+ return sha256(bytes)
237
+ }
238
+ const loadLatestJournalState = (transactionRoot, lease) => {
239
+ const stateRoot = join(transactionRoot, JOURNAL_STATE_DIRECTORY)
240
+ const rootInfo = lstatSync(stateRoot)
241
+ if (
242
+ !rootInfo.isDirectory()
243
+ || rootInfo.isSymbolicLink()
244
+ || realpathSync(stateRoot) !== stateRoot
245
+ || (rootInfo.mode & 0o777) !== 0o700
246
+ ) throw new Error('upgrade recovery journal state root is unsafe')
247
+ const names = readdirSync(stateRoot).sort()
248
+ const finalSequences = names
249
+ .map(name => name.match(JOURNAL_STATE_NAME))
250
+ .filter(Boolean)
251
+ .map(match => Number(match[1]))
252
+ if (!finalSequences.length) throw new Error('upgrade recovery journal has no committed state')
253
+ for (const [index, sequence] of finalSequences.entries()) {
254
+ if (sequence !== index) throw new Error('upgrade recovery journal state sequence is not contiguous')
255
+ }
256
+ const finalSet = new Set(finalSequences)
257
+ const publishSequences = names
258
+ .map(name => name.match(JOURNAL_STATE_PUBLISH_NAME))
259
+ .filter(Boolean)
260
+ .map(match => Number(match[1]))
261
+ const recognized = new Set([
262
+ ...finalSequences.map(sequence => journalStateNames(sequence).final),
263
+ ...publishSequences.map(sequence => journalStateNames(sequence).publish),
264
+ ])
265
+ if (recognized.size !== names.length || names.some(name => !recognized.has(name))) {
266
+ throw new Error('upgrade recovery journal state inventory is open')
267
+ }
268
+ let previousStateSha256 = null
269
+ let latestJournal = null
270
+ for (const sequence of finalSequences) {
271
+ const stateNames = journalStateNames(sequence)
272
+ if (!publishSequences.includes(sequence)) throw new Error(`upgrade recovery journal state ${sequence} lost its publication object`)
273
+ const final = stableRegularFile(join(stateRoot, stateNames.final), `upgrade recovery journal state ${sequence}`, { links: [2] })
274
+ const alias = lstatSync(join(stateRoot, stateNames.publish), { bigint: true })
275
+ if (
276
+ !alias.isFile()
277
+ || alias.isSymbolicLink()
278
+ || alias.nlink !== 2n
279
+ || Number(alias.mode & 0o777n) !== 0o600
280
+ || !sameFileIdentity(alias, final.info)
281
+ ) throw new Error(`upgrade recovery journal state ${sequence} publication alias differs`)
282
+ let envelope
283
+ try { envelope = JSON.parse(final.bytes.toString('utf8')) } catch { throw new Error(`upgrade recovery journal state ${sequence} is invalid JSON`) }
284
+ exactKeys(envelope, ['schemaVersion', 'kind', 'sequence', 'previousStateSha256', 'journal'], `upgrade recovery journal state ${sequence}`)
285
+ if (
286
+ envelope.schemaVersion !== 1
287
+ || envelope.kind !== JOURNAL_STATE_KIND
288
+ || envelope.sequence !== sequence
289
+ || envelope.previousStateSha256 !== previousStateSha256
290
+ ) throw new Error(`upgrade recovery journal state ${sequence} chain binding is invalid`)
291
+ if (
292
+ envelope.journal?.repoRoot !== lease.repoRoot
293
+ || envelope.journal?.transactionId !== lease.transactionId
294
+ || envelope.journal?.transactionRoot !== lease.transactionRoot
295
+ || JSON.stringify(envelope.journal?.owner) !== JSON.stringify(lease.owner)
296
+ ) throw new Error(`upgrade recovery journal state ${sequence} differs from its immutable lease`)
297
+ latestJournal = envelope.journal
298
+ previousStateSha256 = sha256(final.bytes)
299
+ }
300
+ const trailing = publishSequences.filter(sequence => !finalSet.has(sequence))
301
+ if (
302
+ trailing.length > 1
303
+ || (trailing.length === 1 && trailing[0] !== finalSequences.at(-1) + 1)
304
+ ) throw new Error('upgrade recovery journal has an invalid uncommitted state publication')
305
+ if (trailing.length === 1) {
306
+ const pending = lstatSync(join(stateRoot, journalStateNames(trailing[0]).publish), { bigint: true })
307
+ if (
308
+ !pending.isFile()
309
+ || pending.isSymbolicLink()
310
+ || pending.nlink !== 1n
311
+ || Number(pending.mode & 0o777n) !== 0o600
312
+ ) throw new Error('upgrade recovery journal pending state object is unsafe')
313
+ }
314
+ return { journal: latestJournal, sequence: finalSequences.at(-1), stateSha256: previousStateSha256 }
315
+ }
316
+ const journalLeaseBody = ({ transactionRoot, transactionId, owner }) => ({
317
+ schemaVersion: 1,
318
+ kind: JOURNAL_LEASE_KIND,
319
+ repoRoot,
320
+ transactionId,
321
+ transactionRoot,
322
+ owner: structuredClone(owner),
323
+ })
324
+ const publishJournalLease = (lease) => {
325
+ const source = join(lease.transactionRoot, JOURNAL_LEASE_SOURCE)
326
+ const bytes = Buffer.from(`${JSON.stringify(lease, null, 2)}\n`)
327
+ const sourceInfo = writeFsyncedExclusive(source, bytes, 'upgrade journal lease source')
328
+ let linked = false
329
+ try {
330
+ linkSync(source, journalPath)
331
+ linked = true
332
+ const published = stableRegularFile(journalPath, 'published upgrade journal lease', { links: [2] })
333
+ const sourceAfter = lstatSync(source, { bigint: true })
334
+ if (
335
+ !published.bytes.equals(bytes)
336
+ || !sameFileIdentity(published.info, sourceInfo)
337
+ || !sameFileIdentity(published.info, sourceAfter)
338
+ || sourceAfter.nlink !== 2n
339
+ ) throw new Error('published upgrade journal lease differs from its capability source')
340
+ return { bytes, info: published.info, source }
341
+ } catch (error) {
342
+ if (linked) {
343
+ try {
344
+ releaseJournalPointer({
345
+ expectedIdentity: { bytes, info: sourceInfo, kind: JOURNAL_LEASE_KIND },
346
+ transactionRoot: lease.transactionRoot,
347
+ label: 'failed upgrade journal lease publication',
348
+ })
349
+ } catch (releaseError) {
350
+ releaseError.preserveTransactionRoot = true
351
+ throw releaseError
352
+ }
353
+ }
354
+ throw error
355
+ }
356
+ }
357
+ const assertPublishedJournalLease = (leaseIdentity) => {
358
+ assertNoSymlinkPath(repoRoot, journalPath, 'owned upgrade journal lease', { allowMissing: false })
359
+ const published = stableRegularFile(journalPath, 'owned upgrade journal lease', { links: [2] })
360
+ const source = stableRegularFile(leaseIdentity.source, 'owned upgrade journal lease source', { links: [2] })
361
+ if (
362
+ !sameFileIdentity(published.info, leaseIdentity.info)
363
+ || !sameFileIdentity(source.info, leaseIdentity.info)
364
+ || !published.bytes.equals(leaseIdentity.bytes)
365
+ || !source.bytes.equals(leaseIdentity.bytes)
366
+ ) throw new Error('upgrade journal lease ownership changed during transaction')
367
+ return published.info
368
+ }
369
+ const releaseJournalPointer = ({ expectedIdentity, transactionRoot, label }) => {
370
+ assertNoSymlinkPath(repoRoot, dirname(journalPath), `${label} parent`, { allowMissing: false })
371
+ const captureRoot = join(transactionRoot, `.governance-upgrade-lease-release-${randomUUID()}`)
372
+ mkdirSync(captureRoot, { mode: 0o700 })
373
+ const capturedPath = join(captureRoot, 'captured')
374
+ // Rename preserves whichever inode currently occupies the public name. It never overwrites an
375
+ // existing destination because the destination lives in a freshly-created random capability slot.
376
+ renameSync(journalPath, capturedPath)
377
+ let captured
378
+ try {
379
+ captured = stableRegularFile(capturedPath, `${label} captured pointer`, {
380
+ links: expectedIdentity.kind === JOURNAL_LEASE_KIND ? [2] : [1, 2],
381
+ })
382
+ } catch (error) {
383
+ try { linkSync(capturedPath, journalPath) } catch (restoreError) {
384
+ if (restoreError?.code !== 'EEXIST') throw restoreError
385
+ }
386
+ throw new Error(`${label} could not be validated after capture; captured bytes were preserved`, { cause: error })
387
+ }
388
+ if (!sameFileIdentity(captured.info, expectedIdentity.info) || !captured.bytes.equals(expectedIdentity.bytes)) {
389
+ // Restore the unknown bytes with atomic create-if-absent. If another writer has already claimed
390
+ // the public name, both versions remain preserved: one there and one in this capability root.
391
+ try { linkSync(capturedPath, journalPath) } catch (error) {
392
+ if (error?.code !== 'EEXIST') throw error
393
+ }
394
+ throw new Error(`${label} changed before release; substituted bytes were preserved`)
395
+ }
396
+ return capturedPath
397
+ }
398
+ const pathFingerprint = (path, label, { allowHardlinks = false } = {}) => {
399
+ if (!pathEntryExists(path)) return null
400
+ const rows = []
401
+ const visit = (absolute, relativePath = '.') => {
402
+ const info = lstatSync(absolute)
403
+ if (info.isSymbolicLink()) throw new Error(`${label} contains a symbolic link:${relativePath}`)
404
+ const mode = (info.mode & 0o777).toString(8).padStart(3, '0')
405
+ if (info.isDirectory()) {
406
+ rows.push(`tree:${relativePath}:${mode}`)
407
+ for (const name of readdirSync(absolute).sort()) visit(join(absolute, name), relativePath === '.' ? name : `${relativePath}/${name}`)
408
+ return
409
+ }
410
+ if (!info.isFile() || (!allowHardlinks && info.nlink !== 1) || (allowHardlinks && info.nlink > 2)) {
411
+ throw new Error(`${label} contains an unsupported or hard-linked entry:${relativePath}`)
412
+ }
413
+ rows.push(`file:${relativePath}:${mode}:${sha256(readFileSync(absolute))}`)
414
+ }
415
+ visit(path)
416
+ return sha256(`${rows.join('\n')}\n`)
417
+ }
418
+ const nodeModulesFingerprint = (path, label) => {
419
+ if (!pathEntryExists(path)) return null
420
+ const rows = []
421
+ const stableIdentity = (before, after) => (
422
+ before.dev === after.dev
423
+ && before.ino === after.ino
424
+ && before.mode === after.mode
425
+ && before.size === after.size
426
+ && before.mtimeNs === after.mtimeNs
427
+ && before.ctimeNs === after.ctimeNs
428
+ && before.nlink === after.nlink
429
+ )
430
+ const directoryNames = (absolute, relativePath) => readdirSync(absolute, { encoding: 'buffer' })
431
+ .map((bytes) => {
432
+ const name = bytes.toString('utf8')
433
+ if (
434
+ !Buffer.from(name, 'utf8').equals(bytes)
435
+ || !name
436
+ || name === '.'
437
+ || name === '..'
438
+ || name.includes('/')
439
+ || name.includes('\0')
440
+ ) throw new Error(`${label} contains an unsupported directory name:${relativePath}`)
441
+ return { bytes, name }
442
+ })
443
+ .sort((left, right) => Buffer.compare(left.bytes, right.bytes))
444
+ const visit = (absolute, relativePath) => {
445
+ const before = lstatSync(absolute, { bigint: true })
446
+ const mode = Number(before.mode & 0o777n)
447
+ if (before.isSymbolicLink()) {
448
+ if (before.nlink !== 1n) throw new Error(`${label} contains a hard-linked symbolic link:${relativePath}`)
449
+ const target = readlinkSync(absolute, { encoding: 'buffer' })
450
+ const after = lstatSync(absolute, { bigint: true })
451
+ if (!after.isSymbolicLink() || !stableIdentity(before, after)) {
452
+ throw new Error(`${label} symbolic link changed while hashing:${relativePath}`)
453
+ }
454
+ rows.push(JSON.stringify({
455
+ kind: 'symlink',
456
+ mode,
457
+ path: relativePath,
458
+ targetSha256: sha256(target),
459
+ targetBytes: target.length,
460
+ }))
461
+ return
462
+ }
463
+ if (before.isDirectory()) {
464
+ const names = directoryNames(absolute, relativePath)
465
+ rows.push(JSON.stringify({ kind: 'directory', mode, path: relativePath }))
466
+ for (const { name } of names) {
467
+ visit(join(absolute, name), relativePath === '.' ? name : `${relativePath}/${name}`)
468
+ }
469
+ const namesAfter = directoryNames(absolute, relativePath)
470
+ const after = lstatSync(absolute, { bigint: true })
471
+ if (
472
+ !after.isDirectory()
473
+ || !stableIdentity(before, after)
474
+ || names.length !== namesAfter.length
475
+ || names.some((entry, index) => !entry.bytes.equals(namesAfter[index].bytes))
476
+ ) throw new Error(`${label} directory changed while hashing:${relativePath}`)
477
+ return
478
+ }
479
+ if (!before.isFile() || before.nlink !== 1n) {
480
+ throw new Error(`${label} contains an unsupported or hard-linked entry:${relativePath}`)
481
+ }
482
+ let descriptor = null
483
+ let opened
484
+ let openedAfter
485
+ let bytes
486
+ try {
487
+ const noFollow = typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0
488
+ descriptor = openSync(absolute, fsConstants.O_RDONLY | noFollow)
489
+ opened = fstatSync(descriptor, { bigint: true })
490
+ if (!opened.isFile() || opened.nlink !== 1n || !stableIdentity(before, opened)) {
491
+ throw new Error(`${label} file changed before hashing:${relativePath}`)
492
+ }
493
+ bytes = readFileSync(descriptor)
494
+ openedAfter = fstatSync(descriptor, { bigint: true })
495
+ } finally {
496
+ if (descriptor !== null) closeSync(descriptor)
497
+ }
498
+ const after = lstatSync(absolute, { bigint: true })
499
+ if (
500
+ BigInt(bytes.length) !== before.size
501
+ || !openedAfter.isFile()
502
+ || !stableIdentity(opened, openedAfter)
503
+ || !after.isFile()
504
+ || !stableIdentity(before, after)
505
+ ) throw new Error(`${label} file changed while hashing:${relativePath}`)
506
+ rows.push(JSON.stringify({
507
+ bytes: bytes.length,
508
+ contentSha256: sha256(bytes),
509
+ kind: 'file',
510
+ mode,
511
+ path: relativePath,
512
+ }))
513
+ }
514
+ const root = lstatSync(path)
515
+ if (!root.isDirectory() || root.isSymbolicLink() || realpathSync(path) !== resolve(path)) {
516
+ throw new Error(`${label} root must be one real directory`)
517
+ }
518
+ visit(path, '.')
519
+ return sha256(`qijenchen-node-modules-tree-v1\0${rows.join('\n')}\n`)
520
+ }
521
+ const attachBeforeState = (entry, label) => ({
522
+ ...entry,
523
+ beforeFingerprint: entry.present ? pathFingerprint(entry.backup, `${label} before-image`) : null,
524
+ afterRecorded: false,
525
+ afterPresent: false,
526
+ afterFingerprint: null,
527
+ replacementStarted: false,
528
+ replacementCompleted: false,
529
+ })
530
+ const captureCandidateState = (entry, candidatePath, label) => {
531
+ const present = pathEntryExists(candidatePath)
532
+ return {
533
+ ...entry,
534
+ afterRecorded: true,
535
+ afterPresent: present,
536
+ afterFingerprint: present ? pathFingerprint(candidatePath, `${label} candidate after-image`) : null,
537
+ replacementStarted: false,
538
+ replacementCompleted: false,
539
+ }
540
+ }
541
+ const validateStateRecord = (entry, label) => {
542
+ if (
543
+ typeof entry.present !== 'boolean'
544
+ || typeof entry.afterRecorded !== 'boolean'
545
+ || typeof entry.afterPresent !== 'boolean'
546
+ || typeof entry.replacementStarted !== 'boolean'
547
+ || typeof entry.replacementCompleted !== 'boolean'
548
+ ) {
549
+ throw new Error(`${label} state flags are invalid`)
550
+ }
551
+ if (entry.present ? !SHA256_RE.test(entry.beforeFingerprint || '') : entry.beforeFingerprint !== null) {
552
+ throw new Error(`${label} before-image fingerprint is invalid`)
553
+ }
554
+ if (!entry.afterRecorded) {
555
+ if (
556
+ entry.afterPresent !== false
557
+ || entry.afterFingerprint !== null
558
+ || entry.replacementStarted
559
+ || entry.replacementCompleted
560
+ ) throw new Error(`${label} uncommitted after-image is invalid`)
561
+ } else if (entry.afterPresent ? !SHA256_RE.test(entry.afterFingerprint || '') : entry.afterFingerprint !== null) {
562
+ throw new Error(`${label} after-image fingerprint is invalid`)
563
+ }
564
+ if (entry.replacementCompleted && !entry.replacementStarted) {
565
+ throw new Error(`${label} completed replacement was never started`)
566
+ }
567
+ }
568
+ const NODE_MODULES_STATE_KEYS = Object.freeze([
569
+ 'source', 'backup', 'present', 'beforeFingerprint',
570
+ 'afterRecorded', 'afterPresent', 'afterFingerprint',
571
+ 'replacementStarted', 'replacementCompleted',
572
+ ])
573
+ const validateNodeModulesStateRecord = (entry, label) => {
574
+ exactKeys(entry, NODE_MODULES_STATE_KEYS, label)
575
+ validateStateRecord(entry, label)
576
+ if (entry.afterRecorded && entry.afterPresent !== true) {
577
+ throw new Error(`${label} must bind one present candidate node_modules tree`)
578
+ }
579
+ }
580
+ const captureNodeModulesAfterState = (entry, candidatePath, label) => {
581
+ const fingerprint = nodeModulesFingerprint(candidatePath, `${label} candidate after-image`)
582
+ if (!SHA256_RE.test(fingerprint || '')) throw new Error(`${label} candidate node_modules tree is absent`)
583
+ entry.afterRecorded = true
584
+ entry.afterPresent = true
585
+ entry.afterFingerprint = fingerprint
586
+ entry.replacementStarted = false
587
+ entry.replacementCompleted = false
588
+ return entry
589
+ }
590
+ const inspectNodeModulesJournalState = (entry, candidatePath, label) => {
591
+ validateNodeModulesStateRecord(entry, `${label} state`)
592
+ const sourcePresent = pathEntryExists(entry.source)
593
+ const backupPresent = pathEntryExists(entry.backup)
594
+ const candidatePresent = candidatePath !== null && pathEntryExists(candidatePath)
595
+ const sourceFingerprint = sourcePresent
596
+ ? nodeModulesFingerprint(entry.source, `${label} live source`)
597
+ : null
598
+ const backupFingerprint = backupPresent
599
+ ? nodeModulesFingerprint(entry.backup, `${label} recovery backup`)
600
+ : null
601
+ const candidateFingerprint = candidatePresent
602
+ ? nodeModulesFingerprint(candidatePath, `${label} candidate source`)
603
+ : null
604
+
605
+ if (backupPresent && (!entry.present || backupFingerprint !== entry.beforeFingerprint)) {
606
+ throw new Error(`${label} recovery backup is an unknown node_modules image`)
607
+ }
608
+ if (candidatePresent && (!entry.afterRecorded || candidateFingerprint !== entry.afterFingerprint)) {
609
+ throw new Error(`${label} candidate source is an unknown node_modules image`)
610
+ }
611
+ const sourceIsBefore = sourcePresent
612
+ && entry.present
613
+ && sourceFingerprint === entry.beforeFingerprint
614
+ const sourceIsAfter = sourcePresent
615
+ && entry.afterRecorded
616
+ && sourceFingerprint === entry.afterFingerprint
617
+ const exactBeforeState = sourceIsBefore && !backupPresent
618
+ const exactAfterState = sourceIsAfter
619
+ && entry.replacementStarted
620
+ && backupPresent === entry.present
621
+ && !candidatePresent
622
+ const controlledGap = !sourcePresent
623
+ && entry.replacementStarted
624
+ && !entry.replacementCompleted
625
+ && (
626
+ (entry.present && backupPresent)
627
+ || (!entry.present && !backupPresent)
628
+ )
629
+ const originalAbsence = !sourcePresent
630
+ && !entry.present
631
+ && !backupPresent
632
+ && !entry.replacementCompleted
633
+ if (!(exactBeforeState || exactAfterState || controlledGap || originalAbsence)) {
634
+ throw new Error(`${label} recovery blocked by unknown post-journal node_modules content`)
635
+ }
636
+ if (entry.replacementCompleted && !exactAfterState && !exactBeforeState) {
637
+ throw new Error(`${label} completed replacement has no exact live image`)
638
+ }
639
+ return {
640
+ backupFingerprint,
641
+ backupPresent,
642
+ candidateFingerprint,
643
+ candidatePresent,
644
+ exactAfterState,
645
+ exactBeforeState,
646
+ sourceFingerprint,
647
+ sourceIsAfter,
648
+ sourceIsBefore,
649
+ sourcePresent,
650
+ }
651
+ }
652
+ const assertNodeModulesBeforeState = (entry, candidatePath, label) => {
653
+ const state = inspectNodeModulesJournalState(entry, candidatePath, label)
654
+ if (!state.exactBeforeState && !(entry.present === false && state.sourcePresent === false && state.backupPresent === false)) {
655
+ throw new Error(`${label} base changed during disposable reconstruction`)
656
+ }
657
+ if (!entry.afterRecorded || !state.candidatePresent) {
658
+ throw new Error(`${label} candidate after-image is not capability-bound`)
659
+ }
660
+ }
661
+ const assertNodeModulesCommitState = (entry, label) => {
662
+ const state = inspectNodeModulesJournalState(entry, null, label)
663
+ if (!entry.replacementCompleted || !state.exactAfterState) {
664
+ throw new Error(`${label} is not the exact completed candidate image`)
665
+ }
666
+ }
667
+ const restoreNodeModulesFromJournal = (entry, candidatePath, label) => {
668
+ const state = inspectNodeModulesJournalState(entry, candidatePath, label)
669
+ if (state.exactBeforeState || (!entry.present && !state.sourcePresent && !state.backupPresent)) return
670
+ if (state.sourcePresent) {
671
+ if (!state.sourceIsAfter) throw new Error(`${label} refuses to remove an unknown live node_modules image`)
672
+ safeRemoveRepositoryTarget('node_modules')
673
+ }
674
+ if (entry.present) {
675
+ if (!pathEntryExists(entry.backup)) throw new Error(`${label} lost its exact predecessor node_modules image`)
676
+ renameSync(entry.backup, entry.source)
677
+ }
678
+ const finalPresent = pathEntryExists(entry.source)
679
+ const finalFingerprint = finalPresent
680
+ ? nodeModulesFingerprint(entry.source, `${label} restored predecessor`)
681
+ : null
682
+ if (finalPresent !== entry.present || finalFingerprint !== entry.beforeFingerprint) {
683
+ throw new Error(`${label} did not restore the exact predecessor node_modules image`)
684
+ }
685
+ }
686
+ const assertRecoverableLiveState = (
687
+ entry,
688
+ label,
689
+ transientPath = null,
690
+ transientCandidatePath = null,
691
+ transientRestorePath = null,
692
+ transientRecoveryMovedPath = null,
693
+ ) => {
694
+ const movedBeforePresent = transientPath !== null && pathEntryExists(transientPath)
695
+ if (movedBeforePresent) {
696
+ if (!entry.present || !entry.replacementStarted) {
697
+ throw new Error(`recovery has an impossible moved before-image:${entry.path}`)
698
+ }
699
+ if (pathFingerprint(transientPath, `${label} moved before-image`) !== entry.beforeFingerprint) {
700
+ throw new Error(`recovery blocked by changed moved before-image:${entry.path}`)
701
+ }
702
+ } else if (entry.present && entry.replacementCompleted) {
703
+ throw new Error(`recovery lost the completed replacement before-image:${entry.path}`)
704
+ }
705
+ const present = pathEntryExists(entry.source)
706
+ let linkedCandidate = false
707
+ const possibleAliases = [transientCandidatePath, transientRestorePath]
708
+ .filter((path) => path !== null && pathEntryExists(path))
709
+ if (present && possibleAliases.length) {
710
+ const sourceInfo = lstatSync(entry.source)
711
+ linkedCandidate = sourceInfo.isFile()
712
+ && !sourceInfo.isSymbolicLink()
713
+ && sourceInfo.nlink === 2
714
+ && possibleAliases.some((alias) => {
715
+ const aliasInfo = lstatSync(alias)
716
+ return aliasInfo.isFile()
717
+ && !aliasInfo.isSymbolicLink()
718
+ && aliasInfo.nlink === 2
719
+ && sourceInfo.dev === aliasInfo.dev
720
+ && sourceInfo.ino === aliasInfo.ino
721
+ })
722
+ }
723
+ const fingerprint = present
724
+ ? pathFingerprint(entry.source, `${label} live target`, { allowHardlinks: linkedCandidate })
725
+ : null
726
+ const beforeMatches = present === entry.present && fingerprint === entry.beforeFingerprint
727
+ const afterMatches = entry.afterRecorded && present === entry.afterPresent && fingerprint === entry.afterFingerprint
728
+ const candidatePresent = transientCandidatePath !== null && pathEntryExists(transientCandidatePath)
729
+ const afterHasCapabilityEvidence = entry.replacementCompleted
730
+ || (
731
+ entry.replacementStarted
732
+ && (
733
+ entry.present
734
+ ? movedBeforePresent
735
+ : !entry.afterPresent
736
+ || !candidatePresent
737
+ || (present && sameRegularInode(entry.source, transientCandidatePath))
738
+ )
739
+ )
740
+ const controlledTransientAbsence = entry.replacementStarted
741
+ && !entry.replacementCompleted
742
+ && entry.present
743
+ && !present
744
+ && movedBeforePresent
745
+ const controlledRecoveryAbsence = entry.replacementStarted
746
+ && !present
747
+ && transientRecoveryMovedPath !== null
748
+ && pathEntryExists(transientRecoveryMovedPath)
749
+ && (
750
+ knownFingerprint(
751
+ entry,
752
+ transientRecoveryMovedPath,
753
+ `${label} recovery-moved image`,
754
+ transientCandidatePath,
755
+ ),
756
+ true
757
+ )
758
+ const validState = beforeMatches
759
+ || (afterMatches && afterHasCapabilityEvidence)
760
+ || controlledTransientAbsence
761
+ || controlledRecoveryAbsence
762
+ if (!validState) {
763
+ throw new Error(`recovery blocked by unknown post-journal content:${entry.path}`)
764
+ }
765
+ }
766
+ const assertBeforeLiveState = (entry, label) => {
767
+ const present = pathEntryExists(entry.source)
768
+ const fingerprint = present ? pathFingerprint(entry.source, `${label} live before-image`) : null
769
+ if (present !== entry.present || fingerprint !== entry.beforeFingerprint) {
770
+ throw new Error(`transaction base changed during disposable reconstruction:${entry.path}`)
771
+ }
772
+ }
773
+ const sameRegularInode = (left, right) => {
774
+ if (!pathEntryExists(left) || !pathEntryExists(right)) return false
775
+ const leftInfo = lstatSync(left)
776
+ const rightInfo = lstatSync(right)
777
+ return leftInfo.isFile()
778
+ && rightInfo.isFile()
779
+ && !leftInfo.isSymbolicLink()
780
+ && !rightInfo.isSymbolicLink()
781
+ && leftInfo.dev === rightInfo.dev
782
+ && leftInfo.ino === rightInfo.ino
783
+ }
784
+ const knownFingerprint = (entry, path, label, aliasPath = null) => {
785
+ const allowHardlinks = aliasPath !== null && sameRegularInode(path, aliasPath)
786
+ const fingerprint = pathFingerprint(path, label, { allowHardlinks })
787
+ if (fingerprint !== entry.beforeFingerprint && (!entry.afterRecorded || fingerprint !== entry.afterFingerprint)) {
788
+ throw new Error(`recovery blocked by unknown moved content:${entry.path}`)
789
+ }
790
+ return fingerprint
791
+ }
792
+ const recoveryArtifactPaths = (transactionRoot, category, index) => {
793
+ const slot = join(transactionRoot, 'recovery-staging', category, String(index))
794
+ return {
795
+ slot,
796
+ restoreTemporary: join(slot, 'restore.tmp'),
797
+ restore: join(slot, 'restore'),
798
+ moved: join(slot, 'moved'),
799
+ }
800
+ }
801
+ const validateRecoveryArtifactSlot = ({ entry, transactionRoot, category, index, label }) => {
802
+ const paths = recoveryArtifactPaths(transactionRoot, category, index)
803
+ if (!pathEntryExists(paths.slot)) return paths
804
+ const slotInfo = lstatSync(paths.slot)
805
+ if (!slotInfo.isDirectory() || slotInfo.isSymbolicLink() || realpathSync(paths.slot) !== paths.slot) {
806
+ throw new Error(`${label} recovery slot is unsafe`)
807
+ }
808
+ const allowed = new Set(['restore.tmp', 'restore', 'moved'])
809
+ for (const name of readdirSync(paths.slot)) {
810
+ if (!allowed.has(name)) throw new Error(`${label} recovery slot has unowned content:${name}`)
811
+ }
812
+ if (pathEntryExists(paths.restoreTemporary)) {
813
+ if (!entry.present) throw new Error(`${label} absent before-image has a temporary recovery copy`)
814
+ assertSafeTree(transactionRoot, paths.restoreTemporary, `${label} temporary recovery copy`)
815
+ const temporaryInfo = lstatSync(paths.restoreTemporary)
816
+ const backupInfo = lstatSync(entry.backup)
817
+ if (temporaryInfo.isDirectory() !== backupInfo.isDirectory() || temporaryInfo.isFile() !== backupInfo.isFile()) {
818
+ throw new Error(`${label} temporary recovery copy has the wrong kind`)
819
+ }
820
+ }
821
+ if (pathEntryExists(paths.restore)) {
822
+ if (!entry.present) throw new Error(`${label} absent before-image has a recovery copy`)
823
+ const linkedLive = sameRegularInode(entry.source, paths.restore)
824
+ if (linkedLive) {
825
+ const restoreInfo = lstatSync(paths.restore)
826
+ const sourceInfo = lstatSync(entry.source)
827
+ if (restoreInfo.nlink !== 2 || sourceInfo.nlink !== 2) {
828
+ throw new Error(`${label} recovery publication has an unexpected hard-link shape`)
829
+ }
830
+ } else {
831
+ assertSafeTree(transactionRoot, paths.restore, `${label} recovery copy`)
832
+ }
833
+ if (pathFingerprint(paths.restore, `${label} recovery copy`, { allowHardlinks: linkedLive }) !== entry.beforeFingerprint) {
834
+ throw new Error(`${label} recovery copy differs from before-image`)
835
+ }
836
+ }
837
+ if (pathEntryExists(paths.moved)) {
838
+ const candidatePath = join(transactionRoot, 'candidate-staging', entry.path)
839
+ const linkedCandidate = sameRegularInode(paths.moved, candidatePath)
840
+ if (linkedCandidate) {
841
+ const movedInfo = lstatSync(paths.moved)
842
+ const candidateInfo = lstatSync(candidatePath)
843
+ if (movedInfo.nlink !== 2 || candidateInfo.nlink !== 2) {
844
+ throw new Error(`${label} recovery moved image has an unexpected hard-link shape`)
845
+ }
846
+ } else {
847
+ assertSafeTree(transactionRoot, paths.moved, `${label} recovery moved image`)
848
+ }
849
+ knownFingerprint(entry, paths.moved, `${label} recovery moved image`, candidatePath)
850
+ }
851
+ return paths
852
+ }
853
+ const restoreEntryAtomically = ({ entry, transactionRoot, category, index, label }) => {
854
+ const { slot, restoreTemporary, restore: restorePath, moved: movedPath } = recoveryArtifactPaths(
855
+ transactionRoot,
856
+ category,
857
+ index,
858
+ )
859
+ const candidatePath = join(transactionRoot, 'candidate-staging', entry.path)
860
+ const activeMovedPath = join(transactionRoot, 'live-staging', category, String(index))
861
+ mkdirSync(slot, { recursive: true })
862
+ assertNoSymlinkPath(transactionRoot, slot, `${label} recovery slot`, { allowMissing: false })
863
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category, index, label })
864
+
865
+ // A crash can land between link(2) and unlinking the restore alias. Close that exact inode pair
866
+ // first; no other hard-link shape is accepted as a recovery state.
867
+ if (sameRegularInode(entry.source, restorePath)) rmSync(restorePath)
868
+
869
+ if (pathEntryExists(movedPath)) {
870
+ knownFingerprint(entry, movedPath, `${label} prior recovery move`, candidatePath)
871
+ }
872
+
873
+ assertRecoverableLiveState(entry, label, activeMovedPath, candidatePath, restorePath, movedPath)
874
+
875
+ const sourcePresent = pathEntryExists(entry.source)
876
+ const sourceFingerprint = sourcePresent
877
+ ? pathFingerprint(entry.source, `${label} recovery live target`, {
878
+ allowHardlinks: sameRegularInode(entry.source, candidatePath),
879
+ })
880
+ : null
881
+ const beforeMatches = sourcePresent === entry.present && sourceFingerprint === entry.beforeFingerprint
882
+ if (beforeMatches) return
883
+
884
+ if (entry.present) {
885
+ if (pathEntryExists(restoreTemporary)) rmSync(restoreTemporary, { recursive: true, force: true })
886
+ if (!pathEntryExists(restorePath)) {
887
+ cpSync(entry.backup, restoreTemporary, { recursive: true, verbatimSymlinks: true })
888
+ if (pathFingerprint(restoreTemporary, `${label} complete temporary recovery copy`) !== entry.beforeFingerprint) {
889
+ throw new Error(`recovery copy differs from before-image:${entry.path}`)
890
+ }
891
+ renameSync(restoreTemporary, restorePath)
892
+ }
893
+ } else if (pathEntryExists(restorePath) || pathEntryExists(restoreTemporary)) {
894
+ throw new Error(`absent before-image has an unexpected recovery copy:${entry.path}`)
895
+ }
896
+
897
+ if (pathEntryExists(movedPath)) {
898
+ knownFingerprint(entry, movedPath, `${label} prior recovery move`, candidatePath)
899
+ if (pathEntryExists(entry.source)) {
900
+ throw new Error(`recovery target was recreated after its known image was preserved:${entry.path}`)
901
+ }
902
+ } else if (pathEntryExists(entry.source)) {
903
+ renameSync(entry.source, movedPath)
904
+ try {
905
+ knownFingerprint(entry, movedPath, `${label} atomically moved recovery image`, candidatePath)
906
+ } catch (error) {
907
+ if (!pathEntryExists(entry.source)) renameSync(movedPath, entry.source)
908
+ throw error
909
+ }
910
+ }
911
+
912
+ if (pathEntryExists(entry.source)) {
913
+ throw new Error(`recovery destination appeared during restore:${entry.path}`)
914
+ }
915
+ if (entry.present) {
916
+ const restoreInfo = lstatSync(restorePath)
917
+ if (restoreInfo.isFile() && !restoreInfo.isSymbolicLink()) {
918
+ linkSync(restorePath, entry.source)
919
+ rmSync(restorePath)
920
+ } else {
921
+ renameSync(restorePath, entry.source)
922
+ }
923
+ }
924
+ const finalPresent = pathEntryExists(entry.source)
925
+ const finalFingerprint = finalPresent ? pathFingerprint(entry.source, `${label} restored before-image`) : null
926
+ if (finalPresent !== entry.present || finalFingerprint !== entry.beforeFingerprint) {
927
+ throw new Error(`recovery did not converge to before-image:${entry.path}`)
928
+ }
929
+ assertRecoverableLiveState(entry, label, activeMovedPath, candidatePath, restorePath, movedPath)
930
+ }
931
+ const expectedTransactionRoot = (transactionId) => join(dirname(repoRoot), `.governance-upgrade-${transactionId}`)
932
+ const validateTransactionRoot = (rawRoot, transactionId, owner) => {
933
+ if (!UUID_RE.test(transactionId || '')) throw new Error('journal transactionId is invalid')
934
+ const expected = expectedTransactionRoot(transactionId)
935
+ if (typeof rawRoot !== 'string' || rawRoot !== expected || resolve(rawRoot) !== expected) {
936
+ throw new Error('journal transactionRoot is not the exact capability-bound sibling path')
937
+ }
938
+ const info = lstatSync(expected)
939
+ if (!info.isDirectory() || info.isSymbolicLink() || realpathSync(expected) !== expected) {
940
+ throw new Error('journal transactionRoot must be a real sibling directory')
941
+ }
942
+ const markerPath = join(expected, OWNER_MARKER)
943
+ regularFile(markerPath, 'transaction owner marker')
944
+ const marker = JSON.parse(readFileSync(markerPath, 'utf8'))
945
+ exactKeys(marker, ['schemaVersion', 'repoRoot', 'transactionId', 'owner'], 'transaction owner marker')
946
+ exactKeys(marker.owner, ['host', 'pid'], 'transaction owner marker owner')
947
+ if (
948
+ marker.schemaVersion !== 2
949
+ || marker.repoRoot !== repoRoot
950
+ || marker.transactionId !== transactionId
951
+ || JSON.stringify(marker.owner) !== JSON.stringify(owner)
952
+ ) {
953
+ throw new Error('transaction owner marker does not bind this repository and capability')
954
+ }
955
+ return expected
956
+ }
957
+ const safeRemoveRepositoryTarget = (relativePath) => {
958
+ const normalized = normalizeRepositoryRelative(relativePath, 'transaction target')
959
+ const target = join(repoRoot, normalized)
960
+ // Only the final target may have been replaced by the interrupted install. rmSync removes a
961
+ // final symlink itself; every parent remains inside the canonical repository and non-symlink.
962
+ assertNoSymlinkPath(repoRoot, dirname(target), `transaction target parent:${normalized}`, { allowMissing: false })
963
+ if (pathEntryExists(target)) {
964
+ rmSync(target, { recursive: true, force: true })
965
+ }
966
+ }
967
+ const validateRecoveryJournal = () => {
968
+ assertNoSymlinkPath(repoRoot, journalPath, 'upgrade recovery journal', { allowMissing: false })
969
+ const pointer = stableRegularFile(journalPath, 'upgrade recovery journal pointer', { links: [1, 2] })
970
+ let pointerValue
971
+ try { pointerValue = JSON.parse(pointer.bytes.toString('utf8')) } catch { throw new Error('upgrade recovery journal pointer is invalid JSON') }
972
+ const versioned = pointerValue?.kind === JOURNAL_LEASE_KIND
973
+ let journal
974
+ let journalInfo = pointer.info
975
+ let transactionRoot
976
+ if (versioned) {
977
+ exactKeys(pointerValue, ['schemaVersion', 'kind', 'repoRoot', 'transactionId', 'transactionRoot', 'owner'], 'upgrade recovery journal lease')
978
+ if (pointerValue.schemaVersion !== 1 || pointerValue.repoRoot !== repoRoot) {
979
+ throw new Error('upgrade recovery journal lease repository/schema binding mismatch')
980
+ }
981
+ } else {
982
+ journal = pointerValue
983
+ }
984
+ const binding = versioned ? pointerValue : journal
985
+ if (!UUID_RE.test(binding.transactionId || '')) throw new Error('journal transactionId is invalid')
986
+ exactKeys(binding.owner, ['host', 'pid'], 'upgrade recovery journal owner')
987
+ if (
988
+ typeof binding.owner.host !== 'string'
989
+ || !binding.owner.host
990
+ || !Number.isSafeInteger(binding.owner.pid)
991
+ || binding.owner.pid <= 0
992
+ ) throw new Error('upgrade recovery journal owner is invalid')
993
+ if (binding.owner.host !== hostname()) {
994
+ throw new Error(`transaction owner host cannot be proven inactive:${binding.owner.host}`)
995
+ }
996
+ if (processIsAlive(binding.owner.pid)) throw new Error(`upgrade transaction is still active on pid ${binding.owner.pid}`)
997
+ transactionRoot = validateTransactionRoot(binding.transactionRoot, binding.transactionId, binding.owner)
998
+ if (versioned) {
999
+ const leaseSource = stableRegularFile(
1000
+ join(transactionRoot, JOURNAL_LEASE_SOURCE),
1001
+ 'upgrade recovery journal lease source',
1002
+ { links: [2] },
1003
+ )
1004
+ if (
1005
+ journalInfo.nlink !== 2n
1006
+ || !sameFileIdentity(leaseSource.info, journalInfo)
1007
+ || !leaseSource.bytes.equals(pointer.bytes)
1008
+ ) throw new Error('upgrade recovery journal lease differs from its capability source')
1009
+ journal = loadLatestJournalState(transactionRoot, pointerValue).journal
1010
+ } else {
1011
+ // Legacy schema-v5 journals remain recoverable across the lease protocol rollout. A two-link
1012
+ // crash state is accepted only when the exact capability-owned publication alias still exists.
1013
+ if (journalInfo.nlink === 2n) {
1014
+ const initialTemporary = join(transactionRoot, LEGACY_JOURNAL_PUBLISH)
1015
+ const temporary = stableRegularFile(initialTemporary, 'legacy upgrade journal publication alias', { links: [2] })
1016
+ if (!sameFileIdentity(temporary.info, journalInfo) || !temporary.bytes.equals(pointer.bytes)) {
1017
+ throw new Error('upgrade recovery journal has an unbound hard-link alias')
1018
+ }
1019
+ } else if (journalInfo.nlink !== 1n) {
1020
+ throw new Error('upgrade recovery journal has an unexpected hard-link alias')
1021
+ }
1022
+ }
1023
+ exactKeys(journal, ['schemaVersion', 'repoRoot', 'transactionId', 'transactionRoot', 'owner', 'entries', 'nodeModules', 'providerSnapshot', 'commonSnapshot'], 'upgrade recovery journal')
1024
+ const modernJournal = journal.schemaVersion === 6
1025
+ const legacyJournal = journal.schemaVersion === 5
1026
+ if ((!modernJournal && !legacyJournal) || journal.repoRoot !== repoRoot) throw new Error('journal repository/schema binding mismatch')
1027
+ if (!UUID_RE.test(journal.transactionId || '')) throw new Error('journal transactionId is invalid')
1028
+ exactKeys(journal.owner, ['host', 'pid'], 'upgrade recovery journal owner')
1029
+ if (
1030
+ typeof journal.owner.host !== 'string'
1031
+ || !journal.owner.host
1032
+ || !Number.isSafeInteger(journal.owner.pid)
1033
+ || journal.owner.pid <= 0
1034
+ ) throw new Error('upgrade recovery journal owner is invalid')
1035
+ if (
1036
+ journal.transactionId !== binding.transactionId
1037
+ || journal.transactionRoot !== transactionRoot
1038
+ || JSON.stringify(journal.owner) !== JSON.stringify(binding.owner)
1039
+ ) throw new Error('upgrade recovery journal state differs from its pointer binding')
1040
+ if (!Array.isArray(journal.entries) || journal.entries.length !== TRANSACTION_PATHS.length) {
1041
+ throw new Error('journal entries do not match the closed transaction allowlist')
1042
+ }
1043
+ const entries = journal.entries.map((entry, index) => {
1044
+ exactKeys(entry, ['path', 'source', 'backup', 'present', 'beforeFingerprint', 'afterRecorded', 'afterPresent', 'afterFingerprint', 'replacementStarted', 'replacementCompleted'], `journal entry ${index}`)
1045
+ const expectedPath = TRANSACTION_PATHS[index]
1046
+ const expectedSource = join(repoRoot, expectedPath)
1047
+ const expectedBackup = join(transactionRoot, String(index))
1048
+ if (
1049
+ entry.path !== expectedPath || entry.source !== expectedSource || entry.backup !== expectedBackup
1050
+ || typeof entry.present !== 'boolean'
1051
+ ) throw new Error(`journal entry ${index} is not the exact fixed transaction target`)
1052
+ validateStateRecord(entry, `journal entry ${index}`)
1053
+ assertNoSymlinkPath(repoRoot, dirname(expectedSource), `journal source parent:${expectedPath}`, { allowMissing: false })
1054
+ assertNoSymlinkPath(transactionRoot, expectedBackup, `journal backup:${expectedPath}`)
1055
+ if (entry.present) {
1056
+ if (!pathEntryExists(expectedBackup)) throw new Error(`missing recovery backup:${expectedPath}`)
1057
+ assertSafeTree(transactionRoot, expectedBackup, `journal backup tree:${expectedPath}`)
1058
+ if (pathFingerprint(expectedBackup, `journal backup:${expectedPath}`) !== entry.beforeFingerprint) {
1059
+ throw new Error(`recovery backup fingerprint mismatch:${expectedPath}`)
1060
+ }
1061
+ } else if (pathEntryExists(expectedBackup)) throw new Error(`unexpected backup for absent target:${expectedPath}`)
1062
+ return { ...entry }
1063
+ })
1064
+ const expectedModulesSource = join(repoRoot, 'node_modules')
1065
+ const expectedModulesBackup = join(transactionRoot, 'node_modules')
1066
+ if (modernJournal) validateNodeModulesStateRecord(journal.nodeModules, 'journal nodeModules')
1067
+ else exactKeys(journal.nodeModules, ['source', 'backup', 'present'], 'legacy journal nodeModules')
1068
+ if (
1069
+ journal.nodeModules.source !== expectedModulesSource
1070
+ || journal.nodeModules.backup !== expectedModulesBackup
1071
+ || typeof journal.nodeModules.present !== 'boolean'
1072
+ ) throw new Error('invalid node_modules journal entry')
1073
+ assertNoSymlinkPath(repoRoot, dirname(expectedModulesSource), 'node_modules source parent', { allowMissing: false })
1074
+ assertNoSymlinkPath(transactionRoot, expectedModulesBackup, 'node_modules recovery backup')
1075
+ const modulesBackupPresent = pathEntryExists(expectedModulesBackup)
1076
+ if (modulesBackupPresent) {
1077
+ const info = lstatSync(expectedModulesBackup)
1078
+ if (!info.isDirectory() || info.isSymbolicLink()) throw new Error('node_modules recovery backup must be a real directory')
1079
+ } else if (journal.nodeModules.present) {
1080
+ assertNoSymlinkPath(repoRoot, expectedModulesSource, 'unmoved node_modules recovery source', { allowMissing: false })
1081
+ const info = lstatSync(expectedModulesSource)
1082
+ if (!info.isDirectory() || info.isSymbolicLink()) throw new Error('missing both safe node_modules recovery source and backup')
1083
+ }
1084
+ if (!journal.nodeModules.present && modulesBackupPresent) throw new Error('unexpected node_modules backup for absent original')
1085
+ if (modernJournal) {
1086
+ inspectNodeModulesJournalState(
1087
+ journal.nodeModules,
1088
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
1089
+ 'journal node_modules',
1090
+ )
1091
+ }
1092
+ let providerSnapshot = null
1093
+ let authenticatedIncomingCorpus = null
1094
+ if (journal.providerSnapshot !== null) {
1095
+ exactKeys(journal.providerSnapshot, ['entries', 'evidence', 'evidenceRoot', 'paths'], 'journal providerSnapshot')
1096
+ exactKeys(journal.providerSnapshot.evidence, [
1097
+ 'consumerBomSha256', 'forkCorpusLockSha256', 'manifestSha256', 'providerLifecycleSha256', 'releaseVersion',
1098
+ ], 'journal providerSnapshot evidence')
1099
+ const expectedEvidenceRoot = join(transactionRoot, 'provider-evidence')
1100
+ if (journal.providerSnapshot.evidenceRoot !== expectedEvidenceRoot) throw new Error('journal provider evidence root is not capability-bound')
1101
+ assertSafeTree(transactionRoot, expectedEvidenceRoot, 'journal provider evidence corpus')
1102
+ const installed = validateInstalledForkCorpus(expectedEvidenceRoot)
1103
+ authenticatedIncomingCorpus = installed
1104
+ if (JSON.stringify(journal.providerSnapshot.evidence) !== JSON.stringify(installed.evidence)) {
1105
+ throw new Error('journal provider snapshot is not bound to the installed manifest/corpus')
1106
+ }
1107
+ const expectedPaths = collectProviderMutationPaths(installed.manifest)
1108
+ if (JSON.stringify(journal.providerSnapshot.paths) !== JSON.stringify(expectedPaths)) {
1109
+ throw new Error('journal provider paths do not match the authenticated installed manifest')
1110
+ }
1111
+ if (!Array.isArray(journal.providerSnapshot.entries) || journal.providerSnapshot.entries.length !== expectedPaths.length) {
1112
+ throw new Error('journal provider entries do not match the authenticated provider path set')
1113
+ }
1114
+ const providerEntries = journal.providerSnapshot.entries.map((entry, index) => {
1115
+ exactKeys(entry, ['backup', 'path', 'present', 'source', 'beforeFingerprint', 'afterRecorded', 'afterPresent', 'afterFingerprint', 'replacementStarted', 'replacementCompleted'], `journal provider entry ${index}`)
1116
+ const expectedPath = expectedPaths[index]
1117
+ const expectedSource = join(repoRoot, expectedPath.path)
1118
+ const expectedBackup = join(transactionRoot, 'provider-staging', String(index))
1119
+ if (
1120
+ entry.path !== expectedPath.path || entry.source !== expectedSource || entry.backup !== expectedBackup
1121
+ || typeof entry.present !== 'boolean'
1122
+ ) throw new Error(`journal provider entry ${index} is not the authenticated provider target`)
1123
+ validateStateRecord(entry, `journal provider entry ${index}`)
1124
+ assertNoSymlinkPath(repoRoot, dirname(expectedSource), `journal provider source parent:${entry.path}`, { allowMissing: false })
1125
+ assertNoSymlinkPath(transactionRoot, expectedBackup, `journal provider backup:${entry.path}`)
1126
+ if (entry.present) {
1127
+ if (!pathEntryExists(expectedBackup)) throw new Error(`missing provider recovery backup:${entry.path}`)
1128
+ const info = lstatSync(expectedBackup)
1129
+ if ((expectedPath.kind === 'file' && !info.isFile()) || (expectedPath.kind === 'tree' && !info.isDirectory())) {
1130
+ throw new Error(`provider recovery backup kind mismatch:${entry.path}`)
1131
+ }
1132
+ assertSafeTree(transactionRoot, expectedBackup, `journal provider backup tree:${entry.path}`)
1133
+ if (pathFingerprint(expectedBackup, `journal provider backup:${entry.path}`) !== entry.beforeFingerprint) {
1134
+ throw new Error(`provider recovery backup fingerprint mismatch:${entry.path}`)
1135
+ }
1136
+ } else if (pathEntryExists(expectedBackup)) throw new Error(`unexpected provider backup for absent target:${entry.path}`)
1137
+ return { ...entry }
1138
+ })
1139
+ const providerStagingRoot = join(transactionRoot, 'provider-staging')
1140
+ const expectedProviderBackups = providerEntries
1141
+ .flatMap((entry, index) => entry.present ? [String(index)] : [])
1142
+ .sort()
1143
+ const actualProviderBackups = pathEntryExists(providerStagingRoot)
1144
+ ? readdirSync(providerStagingRoot).sort()
1145
+ : []
1146
+ if (JSON.stringify(actualProviderBackups) !== JSON.stringify(expectedProviderBackups)) {
1147
+ throw new Error('journal provider-staging inventory is not closed')
1148
+ }
1149
+ providerSnapshot = { ...journal.providerSnapshot, entries: providerEntries }
1150
+ } else if (pathEntryExists(join(transactionRoot, 'provider-staging'))) {
1151
+ // A crash may occur after inert provider backups are staged but before the atomically replaced
1152
+ // journal binds them. They are never used for restore and disappear with the transaction root.
1153
+ assertSafeTree(transactionRoot, join(transactionRoot, 'provider-staging'), 'unbound provider staging tree')
1154
+ }
1155
+ if (journal.providerSnapshot === null && pathEntryExists(join(transactionRoot, 'provider-evidence'))) {
1156
+ assertSafeTree(transactionRoot, join(transactionRoot, 'provider-evidence'), 'unbound provider evidence tree')
1157
+ }
1158
+ let commonSnapshot = null
1159
+ if (journal.commonSnapshot !== null) {
1160
+ if (!authenticatedIncomingCorpus) throw new Error('journal common snapshot has no authenticated incoming corpus')
1161
+ exactKeys(journal.commonSnapshot, ['backup', 'path', 'present', 'source', 'beforeFingerprint', 'afterRecorded', 'afterPresent', 'afterFingerprint', 'replacementStarted', 'replacementCompleted'], 'journal commonSnapshot')
1162
+ const expectedPath = normalizeRepositoryRelative(
1163
+ authenticatedIncomingCorpus.manifest.consumer.commonInstruction.destination,
1164
+ 'authenticated common instruction destination',
1165
+ )
1166
+ const coveredByFixedRoot = TRANSACTION_PATHS.some(root => expectedPath === root || expectedPath.startsWith(`${root}/`))
1167
+ if (coveredByFixedRoot) throw new Error('journal common snapshot duplicates a fixed transaction target')
1168
+ const expectedSource = join(repoRoot, expectedPath)
1169
+ const expectedBackup = join(transactionRoot, 'common-staging', '0')
1170
+ if (
1171
+ journal.commonSnapshot.path !== expectedPath
1172
+ || journal.commonSnapshot.source !== expectedSource
1173
+ || journal.commonSnapshot.backup !== expectedBackup
1174
+ || typeof journal.commonSnapshot.present !== 'boolean'
1175
+ ) throw new Error('journal common snapshot is not bound to the authenticated common instruction')
1176
+ validateStateRecord(journal.commonSnapshot, 'journal commonSnapshot')
1177
+ assertNoSymlinkPath(repoRoot, dirname(expectedSource), 'journal common source parent', { allowMissing: false })
1178
+ assertNoSymlinkPath(transactionRoot, expectedBackup, 'journal common backup')
1179
+ if (journal.commonSnapshot.present) {
1180
+ if (!pathEntryExists(expectedBackup)) throw new Error('missing common-instruction recovery backup')
1181
+ const info = lstatSync(expectedBackup)
1182
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) throw new Error('common-instruction recovery backup must be one regular unaliased file')
1183
+ if (pathFingerprint(expectedBackup, 'journal common backup') !== journal.commonSnapshot.beforeFingerprint) {
1184
+ throw new Error('common-instruction recovery backup fingerprint mismatch')
1185
+ }
1186
+ } else if (pathEntryExists(expectedBackup)) throw new Error('unexpected common-instruction backup for absent target')
1187
+ const commonStagingRoot = join(transactionRoot, 'common-staging')
1188
+ const expectedCommonBackups = journal.commonSnapshot.present ? ['0'] : []
1189
+ const actualCommonBackups = pathEntryExists(commonStagingRoot) ? readdirSync(commonStagingRoot).sort() : []
1190
+ if (JSON.stringify(actualCommonBackups) !== JSON.stringify(expectedCommonBackups)) {
1191
+ throw new Error('journal common-staging inventory is not closed')
1192
+ }
1193
+ commonSnapshot = { ...journal.commonSnapshot }
1194
+ } else {
1195
+ if (authenticatedIncomingCorpus) {
1196
+ const expectedPath = normalizeRepositoryRelative(
1197
+ authenticatedIncomingCorpus.manifest.consumer.commonInstruction.destination,
1198
+ 'authenticated common instruction destination',
1199
+ )
1200
+ const coveredByFixedRoot = TRANSACTION_PATHS.some(root => expectedPath === root || expectedPath.startsWith(`${root}/`))
1201
+ if (!coveredByFixedRoot) throw new Error('journal omits the authenticated common-instruction transaction target')
1202
+ }
1203
+ if (pathEntryExists(join(transactionRoot, 'common-staging'))) {
1204
+ // Inert common backup staged before the second journal replacement is never recovery authority.
1205
+ assertSafeTree(transactionRoot, join(transactionRoot, 'common-staging'), 'unbound common-instruction staging tree')
1206
+ }
1207
+ }
1208
+ const recoveryRoot = join(transactionRoot, 'recovery-staging')
1209
+ if (pathEntryExists(recoveryRoot)) {
1210
+ const recoveryInfo = lstatSync(recoveryRoot)
1211
+ if (!recoveryInfo.isDirectory() || recoveryInfo.isSymbolicLink() || realpathSync(recoveryRoot) !== recoveryRoot) {
1212
+ throw new Error('journal recovery-staging root is unsafe')
1213
+ }
1214
+ const categories = new Map([
1215
+ ['fixed', entries],
1216
+ ['provider', providerSnapshot?.entries || []],
1217
+ ['common', commonSnapshot ? [commonSnapshot] : []],
1218
+ ])
1219
+ for (const category of readdirSync(recoveryRoot)) {
1220
+ const categoryEntries = categories.get(category)
1221
+ if (!categoryEntries?.length) throw new Error(`journal recovery-staging has unknown category:${category}`)
1222
+ const categoryRoot = join(recoveryRoot, category)
1223
+ const categoryInfo = lstatSync(categoryRoot)
1224
+ if (!categoryInfo.isDirectory() || categoryInfo.isSymbolicLink() || realpathSync(categoryRoot) !== categoryRoot) {
1225
+ throw new Error(`journal recovery-staging category is unsafe:${category}`)
1226
+ }
1227
+ for (const indexName of readdirSync(categoryRoot)) {
1228
+ if (!/^(0|[1-9][0-9]*)$/.test(indexName)) {
1229
+ throw new Error(`journal recovery-staging has invalid index:${category}/${indexName}`)
1230
+ }
1231
+ const index = Number(indexName)
1232
+ const entry = categoryEntries[index]
1233
+ if (!entry) throw new Error(`journal recovery-staging has unbound index:${category}/${indexName}`)
1234
+ validateRecoveryArtifactSlot({
1235
+ entry,
1236
+ transactionRoot,
1237
+ category,
1238
+ index,
1239
+ label: `journal ${category} target:${entry.path}`,
1240
+ })
1241
+ }
1242
+ }
1243
+ }
1244
+ const liveStaging = join(transactionRoot, 'live-staging')
1245
+ if (pathEntryExists(liveStaging)) {
1246
+ const liveInfo = lstatSync(liveStaging)
1247
+ if (!liveInfo.isDirectory() || liveInfo.isSymbolicLink() || realpathSync(liveStaging) !== liveStaging) {
1248
+ throw new Error('journal live-staging root is unsafe')
1249
+ }
1250
+ const categories = new Map([
1251
+ ['fixed', entries],
1252
+ ['provider', providerSnapshot?.entries || []],
1253
+ ['common', commonSnapshot ? [commonSnapshot] : []],
1254
+ ])
1255
+ for (const category of readdirSync(liveStaging)) {
1256
+ const categoryEntries = categories.get(category)
1257
+ if (!categoryEntries?.length) throw new Error(`journal live-staging has unknown category:${category}`)
1258
+ const categoryRoot = join(liveStaging, category)
1259
+ const categoryInfo = lstatSync(categoryRoot)
1260
+ if (!categoryInfo.isDirectory() || categoryInfo.isSymbolicLink() || realpathSync(categoryRoot) !== categoryRoot) {
1261
+ throw new Error(`journal live-staging category is unsafe:${category}`)
1262
+ }
1263
+ for (const indexName of readdirSync(categoryRoot)) {
1264
+ if (!/^(0|[1-9][0-9]*)$/.test(indexName)) {
1265
+ throw new Error(`journal live-staging has invalid index:${category}/${indexName}`)
1266
+ }
1267
+ const entry = categoryEntries[Number(indexName)]
1268
+ if (!entry || !entry.present || !entry.replacementStarted) {
1269
+ throw new Error(`journal live-staging has unbound index:${category}/${indexName}`)
1270
+ }
1271
+ }
1272
+ }
1273
+ }
1274
+ for (const inertRoot of ['candidate-staging', 'candidate-staging.tmp', 'live-staging']) {
1275
+ const absolute = join(transactionRoot, inertRoot)
1276
+ if (!pathEntryExists(absolute)) continue
1277
+ const info = lstatSync(absolute)
1278
+ if (!info.isDirectory() || info.isSymbolicLink() || realpathSync(absolute) !== absolute) {
1279
+ throw new Error(`journal inert transaction root is unsafe:${inertRoot}`)
1280
+ }
1281
+ // candidate-staging may contain npm's legitimate .bin symlinks. It is never recovery
1282
+ // authority; recovery only removes the capability-bound sibling root. The moved live tree is
1283
+ // authoritative and was already validated before mutation, so keep its stronger closed-tree check.
1284
+ if (inertRoot === 'live-staging') assertSafeTree(transactionRoot, absolute, `journal inert transaction tree:${inertRoot}`)
1285
+ }
1286
+ const pendingJournalPublication = join(transactionRoot, LEGACY_JOURNAL_PUBLISH)
1287
+ if (pathEntryExists(pendingJournalPublication)) {
1288
+ const info = lstatSync(pendingJournalPublication)
1289
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) {
1290
+ throw new Error('journal pending publication is not one inert regular file')
1291
+ }
1292
+ }
1293
+ const allowedRootNames = new Set([
1294
+ OWNER_MARKER,
1295
+ ...(pathEntryExists(pendingJournalPublication) ? [LEGACY_JOURNAL_PUBLISH] : []),
1296
+ ...(versioned ? [JOURNAL_LEASE_SOURCE, JOURNAL_STATE_DIRECTORY] : []),
1297
+ ...entries.flatMap((entry, index) => entry.present ? [String(index)] : []),
1298
+ ...(modulesBackupPresent ? ['node_modules'] : []),
1299
+ ...(pathEntryExists(join(transactionRoot, 'provider-staging')) ? ['provider-staging'] : []),
1300
+ ...(pathEntryExists(join(transactionRoot, 'provider-evidence')) ? ['provider-evidence'] : []),
1301
+ ...(pathEntryExists(join(transactionRoot, 'common-staging')) ? ['common-staging'] : []),
1302
+ ...(pathEntryExists(join(transactionRoot, 'candidate-staging')) ? ['candidate-staging'] : []),
1303
+ ...(pathEntryExists(join(transactionRoot, 'candidate-staging.tmp')) ? ['candidate-staging.tmp'] : []),
1304
+ ...(pathEntryExists(join(transactionRoot, 'live-staging')) ? ['live-staging'] : []),
1305
+ ...(pathEntryExists(recoveryRoot) ? ['recovery-staging'] : []),
1306
+ ])
1307
+ for (const name of readdirSync(transactionRoot)) {
1308
+ if (!allowedRootNames.has(name)) throw new Error(`transaction root has unowned content:${name}`)
1309
+ }
1310
+ // Validate every live authoritative target before the first restore mutation. A crash-recovery
1311
+ // journal is not permission to erase edits made after the last committed transaction state.
1312
+ for (const [index, entry] of entries.entries()) {
1313
+ assertRecoverableLiveState(
1314
+ entry,
1315
+ `journal fixed target:${entry.path}`,
1316
+ join(transactionRoot, 'live-staging', 'fixed', String(index)),
1317
+ join(transactionRoot, 'candidate-staging', entry.path),
1318
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'restore'),
1319
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'moved'),
1320
+ )
1321
+ }
1322
+ for (const [index, entry] of (providerSnapshot?.entries || []).entries()) {
1323
+ assertRecoverableLiveState(
1324
+ entry,
1325
+ `journal provider target:${entry.path}`,
1326
+ join(transactionRoot, 'live-staging', 'provider', String(index)),
1327
+ join(transactionRoot, 'candidate-staging', entry.path),
1328
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'restore'),
1329
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'moved'),
1330
+ )
1331
+ }
1332
+ if (commonSnapshot) {
1333
+ assertRecoverableLiveState(
1334
+ commonSnapshot,
1335
+ 'journal common-instruction target',
1336
+ join(transactionRoot, 'live-staging', 'common', '0'),
1337
+ join(transactionRoot, 'candidate-staging', commonSnapshot.path),
1338
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'restore'),
1339
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'moved'),
1340
+ )
1341
+ }
1342
+ return {
1343
+ journal,
1344
+ journalPointerIdentity: {
1345
+ bytes: pointer.bytes,
1346
+ info: pointer.info,
1347
+ kind: versioned ? JOURNAL_LEASE_KIND : 'legacy-schema-v5-journal',
1348
+ },
1349
+ transactionRoot,
1350
+ entries,
1351
+ providerSnapshot,
1352
+ commonSnapshot,
1353
+ modules: {
1354
+ entry: { ...journal.nodeModules },
1355
+ backupPresent: modulesBackupPresent,
1356
+ modern: modernJournal,
1357
+ },
1358
+ }
1359
+ }
1360
+ let recoveredInterruptedTransaction = false
1361
+ const assertRecoveryConsumerRole = (entries) => {
1362
+ const governanceEntry = entries.find((entry) => entry.path === 'governance')
1363
+ if (!governanceEntry?.present) {
1364
+ throw new Error('upgrade recovery journal has no consumer governance before-image')
1365
+ }
1366
+ const manifestPath = join(governanceEntry.backup, 'provider-cli-toolchain.json')
1367
+ assertNoSymlinkPath(
1368
+ governanceEntry.backup,
1369
+ manifestPath,
1370
+ 'upgrade recovery consumer provider CLI manifest',
1371
+ { allowMissing: false },
1372
+ )
1373
+ const manifestFile = stableRegularFile(
1374
+ manifestPath,
1375
+ 'upgrade recovery consumer provider CLI manifest',
1376
+ { links: [1], mode: 0o644 },
1377
+ )
1378
+ let manifest
1379
+ try {
1380
+ manifest = JSON.parse(manifestFile.bytes.toString('utf8'))
1381
+ } catch {
1382
+ throw new Error('upgrade recovery consumer provider CLI manifest is not valid JSON')
1383
+ }
1384
+ if (
1385
+ manifest?.kind !== 'provider-cli-toolchain'
1386
+ || !Number.isSafeInteger(manifest.schemaVersion)
1387
+ || manifest.schemaVersion < 1
1388
+ || manifest.packageLock?.consumerPath !== 'governance/provider-cli-toolchain.package-lock.json'
1389
+ ) throw new Error('upgrade recovery journal before-image is not a consumer provider CLI authority mirror')
1390
+ }
1391
+
1392
+ // A SIGKILL or abrupt process termination cannot run a finally block. Recover the exact, validated
1393
+ // sibling backup on the next invocation before reading package.json or checking worktree cleanliness.
1394
+ // This is a process-crash contract, not a physical power-loss/filesystem-durability claim.
1395
+ if (!authorityProviderManifestPresent && pathEntryExists(journalPath)) {
1396
+ try {
1397
+ const {
1398
+ transactionRoot,
1399
+ journalPointerIdentity,
1400
+ entries,
1401
+ providerSnapshot,
1402
+ commonSnapshot,
1403
+ modules,
1404
+ } = validateRecoveryJournal()
1405
+ // The live consumer manifest can be path-absent when SIGKILL lands between the two atomic
1406
+ // governance-directory renames. Authenticate the immutable before-image instead of mistaking
1407
+ // that controlled gap for a non-consumer root. The authority marker is outside transaction
1408
+ // scope and was rejected before this journal was inspected.
1409
+ assertRecoveryConsumerRole(entries)
1410
+ // No mutation occurs until the entire journal, capability marker, fixed allowlist, every
1411
+ // backup, and the transaction-root inventory have been validated.
1412
+ for (const [index, entry] of entries.entries()) {
1413
+ restoreEntryAtomically({ entry, transactionRoot, category: 'fixed', index, label: `restore fixed target:${entry.path}` })
1414
+ }
1415
+ for (const [index, entry] of (providerSnapshot?.entries || []).entries()) {
1416
+ restoreEntryAtomically({ entry, transactionRoot, category: 'provider', index, label: `restore provider target:${entry.path}` })
1417
+ }
1418
+ if (commonSnapshot) {
1419
+ restoreEntryAtomically({ entry: commonSnapshot, transactionRoot, category: 'common', index: 0, label: 'restore common-instruction target' })
1420
+ }
1421
+ if (modules.modern) {
1422
+ restoreNodeModulesFromJournal(
1423
+ modules.entry,
1424
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
1425
+ 'restore node_modules',
1426
+ )
1427
+ } else if (modules.entry.present) {
1428
+ // The journal is written before the same-filesystem rename. Abrupt process termination may
1429
+ // therefore leave either the original source or the backup; both are safe, unambiguous states.
1430
+ if (modules.backupPresent) {
1431
+ safeRemoveRepositoryTarget('node_modules')
1432
+ renameSync(modules.entry.backup, modules.entry.source)
1433
+ }
1434
+ } else {
1435
+ safeRemoveRepositoryTarget('node_modules')
1436
+ }
1437
+ // Re-read every path-visible predecessor/recovery image immediately before deleting the
1438
+ // capability root. A writer that changed a moved inode after the first validation must leave
1439
+ // this journal intact for manual reconciliation rather than lose those bytes.
1440
+ for (const [index, entry] of entries.entries()) {
1441
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category: 'fixed', index, label: `final restore fixed target:${entry.path}` })
1442
+ assertRecoverableLiveState(
1443
+ entry,
1444
+ `final restore fixed target:${entry.path}`,
1445
+ join(transactionRoot, 'live-staging', 'fixed', String(index)),
1446
+ join(transactionRoot, 'candidate-staging', entry.path),
1447
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'restore'),
1448
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'moved'),
1449
+ )
1450
+ }
1451
+ for (const [index, entry] of (providerSnapshot?.entries || []).entries()) {
1452
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category: 'provider', index, label: `final restore provider target:${entry.path}` })
1453
+ assertRecoverableLiveState(
1454
+ entry,
1455
+ `final restore provider target:${entry.path}`,
1456
+ join(transactionRoot, 'live-staging', 'provider', String(index)),
1457
+ join(transactionRoot, 'candidate-staging', entry.path),
1458
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'restore'),
1459
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'moved'),
1460
+ )
1461
+ }
1462
+ if (commonSnapshot) {
1463
+ validateRecoveryArtifactSlot({ entry: commonSnapshot, transactionRoot, category: 'common', index: 0, label: 'final restore common-instruction target' })
1464
+ assertRecoverableLiveState(
1465
+ commonSnapshot,
1466
+ 'final restore common-instruction target',
1467
+ join(transactionRoot, 'live-staging', 'common', '0'),
1468
+ join(transactionRoot, 'candidate-staging', commonSnapshot.path),
1469
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'restore'),
1470
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'moved'),
1471
+ )
1472
+ }
1473
+ if (modules.modern) {
1474
+ const restored = inspectNodeModulesJournalState(
1475
+ modules.entry,
1476
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
1477
+ 'final restore node_modules',
1478
+ )
1479
+ if (
1480
+ modules.entry.present
1481
+ ? !restored.exactBeforeState
1482
+ : restored.sourcePresent || restored.backupPresent
1483
+ ) throw new Error('final restore node_modules differs from its exact predecessor')
1484
+ }
1485
+ releaseJournalPointer({
1486
+ expectedIdentity: journalPointerIdentity,
1487
+ transactionRoot,
1488
+ label: 'upgrade recovery journal pointer',
1489
+ })
1490
+ // Releasing the public pointer is the recovery commit point. Capability-root deletion is
1491
+ // post-commit garbage collection and must never turn a completed restore into an unjournaled
1492
+ // second rollback attempt.
1493
+ try {
1494
+ rmSync(transactionRoot, { recursive: true, force: true })
1495
+ } catch (error) {
1496
+ console.error(`GOV-UPGRADE-RECOVERY-GC-DEFERRED:${transactionRoot}:${error?.message || error}`)
1497
+ }
1498
+ recoveredInterruptedTransaction = true
1499
+ } catch (error) {
1500
+ console.error(`GOV-UPGRADE-RECOVERY-BLOCKED:${error?.message || error}`)
1501
+ process.exit(2)
1502
+ }
1503
+ }
1504
+ const consumerProviderManifestPresent = pathEntryExists(join(repoRoot, PROVIDER_CLI_CONSUMER_MANIFEST))
1505
+
1506
+ const argv = process.argv.slice(2)
1507
+ const cliFailure = (message) => {
1508
+ const diagnostic = {
1509
+ ruleId: 'GOV-UPGRADE-CLI-001',
1510
+ severity: 'BLOCKER',
1511
+ message,
1512
+ }
1513
+ if (argv.filter((token) => token === '--json').length === 1) {
1514
+ process.stdout.write(JSON.stringify({
1515
+ ok: false,
1516
+ mode: 'invalid',
1517
+ mutationAuthorized: false,
1518
+ syntaxValid: false,
1519
+ targetVerification: 'not-started',
1520
+ targetVerified: false,
1521
+ ready: false,
1522
+ diagnostics: [diagnostic],
1523
+ }, null, 2) + '\n')
1524
+ } else console.error(`${diagnostic.ruleId}:${message}`)
1525
+ process.exit(1)
1526
+ }
1527
+ const testReleaseHandshakeAuthorized = process.env.NODE_ENV === 'test'
1528
+ const booleanOptions = new Set([
1529
+ '--apply',
1530
+ '--dry-run',
1531
+ '--json',
1532
+ ...(testReleaseHandshakeAuthorized ? [TEST_RELEASE_HANDSHAKE_OPTION] : []),
1533
+ ...(testReleaseHandshakeAuthorized ? [TEST_GC_FAILURE_OPTION] : []),
1534
+ ...(testReleaseHandshakeAuthorized ? [TEST_NODE_MODULES_PUBLISH_HANDSHAKE_OPTION] : []),
1535
+ ...(testReleaseHandshakeAuthorized ? [TEST_CONSUMER_ROLE_GAP_HANDSHAKE_OPTION] : []),
1536
+ ])
1537
+ const valueOptions = new Set(['--to', '--design-system', '--storybook'])
1538
+ const parsedOptions = new Map()
1539
+ for (let index = 0; index < argv.length; index += 1) {
1540
+ const token = argv[index]
1541
+ if (!booleanOptions.has(token) && !valueOptions.has(token)) cliFailure(`unknown or positional option:${token}`)
1542
+ if (parsedOptions.has(token)) cliFailure(`duplicate option:${token}`)
1543
+ if (booleanOptions.has(token)) {
1544
+ parsedOptions.set(token, true)
1545
+ continue
1546
+ }
1547
+ const value = argv[index + 1]
1548
+ if (!value || value.startsWith('--')) cliFailure(`${token} requires one exact-version value`)
1549
+ parsedOptions.set(token, value)
1550
+ index += 1
1551
+ }
1552
+ if (parsedOptions.has('--apply') && parsedOptions.has('--dry-run')) cliFailure('--apply and --dry-run are mutually exclusive')
1553
+ if (
1554
+ parsedOptions.has(TEST_RELEASE_HANDSHAKE_OPTION)
1555
+ && (!parsedOptions.has('--apply') || !parsedOptions.has('--json'))
1556
+ ) cliFailure(`${TEST_RELEASE_HANDSHAKE_OPTION} requires --apply and --json`)
1557
+ if (
1558
+ parsedOptions.has(TEST_GC_FAILURE_OPTION)
1559
+ && (!parsedOptions.has('--apply') || !parsedOptions.has('--json'))
1560
+ ) cliFailure(`${TEST_GC_FAILURE_OPTION} requires --apply and --json`)
1561
+ if (
1562
+ parsedOptions.has(TEST_NODE_MODULES_PUBLISH_HANDSHAKE_OPTION)
1563
+ && (!parsedOptions.has('--apply') || !parsedOptions.has('--json'))
1564
+ ) cliFailure(`${TEST_NODE_MODULES_PUBLISH_HANDSHAKE_OPTION} requires --apply and --json`)
1565
+ if (
1566
+ parsedOptions.has(TEST_CONSUMER_ROLE_GAP_HANDSHAKE_OPTION)
1567
+ && (!parsedOptions.has('--apply') || !parsedOptions.has('--json'))
1568
+ ) cliFailure(`${TEST_CONSUMER_ROLE_GAP_HANDSHAKE_OPTION} requires --apply and --json`)
1569
+ if (parsedOptions.has('--to') && (parsedOptions.has('--design-system') || parsedOptions.has('--storybook'))) {
1570
+ cliFailure('--to cannot be combined with --design-system or --storybook')
1571
+ }
1572
+ if (parsedOptions.has('--design-system') !== parsedOptions.has('--storybook')) {
1573
+ cliFailure('--design-system and --storybook must be supplied together')
1574
+ }
1575
+ if (parsedOptions.has('--apply') && !parsedOptions.has('--to') && !parsedOptions.has('--design-system')) {
1576
+ cliFailure('--apply requires --to or both explicit package targets')
1577
+ }
1578
+
1579
+ const APPLY = parsedOptions.has('--apply')
1580
+ const AS_JSON = parsedOptions.has('--json')
1581
+ const TEST_RELEASE_HANDSHAKE = parsedOptions.has(TEST_RELEASE_HANDSHAKE_OPTION)
1582
+ const TEST_GC_FAILURE = parsedOptions.has(TEST_GC_FAILURE_OPTION)
1583
+ const TEST_NODE_MODULES_PUBLISH_HANDSHAKE = parsedOptions.has(TEST_NODE_MODULES_PUBLISH_HANDSHAKE_OPTION)
1584
+ const TEST_CONSUMER_ROLE_GAP_HANDSHAKE = parsedOptions.has(TEST_CONSUMER_ROLE_GAP_HANDSHAKE_OPTION)
1585
+ const DRY_RUN = !APPLY
1586
+ const sharedTarget = parsedOptions.get('--to')
1587
+ const dsTarget = parsedOptions.get('--design-system') || sharedTarget
1588
+ const storybookTarget = parsedOptions.get('--storybook') || sharedTarget
1589
+ const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?(?:\+[0-9A-Za-z][0-9A-Za-z.-]*)?$/
1590
+ const parseVersion = (value) => {
1591
+ const match = String(value || '').match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/)
1592
+ if (!match) return null
1593
+ return { core: match.slice(1, 4).map(Number), pre: match[4]?.split('.') ?? null }
1594
+ }
1595
+ const compareVersion = (a, b) => {
1596
+ const left = parseVersion(a); const right = parseVersion(b)
1597
+ if (!left || !right) return null
1598
+ for (let i = 0; i < 3; i += 1) if (left.core[i] !== right.core[i]) return left.core[i] - right.core[i]
1599
+ if (left.pre === null || right.pre === null) return left.pre === right.pre ? 0 : left.pre === null ? 1 : -1
1600
+ for (let i = 0; i < Math.max(left.pre.length, right.pre.length); i += 1) {
1601
+ if (left.pre[i] === undefined || right.pre[i] === undefined) return left.pre[i] === undefined ? -1 : 1
1602
+ if (left.pre[i] === right.pre[i]) continue
1603
+ const ln = /^\d+$/.test(left.pre[i]); const rn = /^\d+$/.test(right.pre[i])
1604
+ if (ln && rn) return Number(left.pre[i]) - Number(right.pre[i])
1605
+ if (ln !== rn) return ln ? -1 : 1
1606
+ // SemVer prerelease identifiers are ASCII-only. UTF-8 byte order is therefore the exact
1607
+ // locale-independent ASCII lexical order required for non-numeric identifiers.
1608
+ return compareUtf8Bytes(left.pre[i], right.pre[i])
1609
+ }
1610
+ return 0
1611
+ }
1612
+
1613
+ const project = JSON.parse(readFileSync('package.json', 'utf8'))
1614
+ const allDeps = { ...(project.dependencies || {}), ...(project.devDependencies || {}) }
1615
+ const current = {
1616
+ designSystem: allDeps['@qijenchen/design-system'] || null,
1617
+ storybook: allDeps['@qijenchen/storybook-config'] || null,
1618
+ }
1619
+ let currentLock = null
1620
+ try { currentLock = JSON.parse(readFileSync('package-lock.json', 'utf8')) } catch { /* checker reports malformed lock */ }
1621
+ const currentResolved = {
1622
+ designSystem: currentLock?.packages?.['node_modules/@qijenchen/design-system']?.version || null,
1623
+ storybook: currentLock?.packages?.['node_modules/@qijenchen/storybook-config']?.version || null,
1624
+ }
1625
+
1626
+ const report = {
1627
+ ok: true,
1628
+ mode: DRY_RUN ? 'plan' : 'apply',
1629
+ mutationAuthorized: APPLY,
1630
+ syntaxValid: true,
1631
+ targetVerification: DRY_RUN ? 'deferred' : 'pending',
1632
+ targetVerified: false,
1633
+ ready: false,
1634
+ current,
1635
+ target: { designSystem: dsTarget || null, storybook: storybookTarget || null },
1636
+ refresh: null,
1637
+ provenance: null,
1638
+ toolchain: null,
1639
+ verification: null,
1640
+ providerCli: null,
1641
+ rollback: null,
1642
+ transactionGarbageCollection: null,
1643
+ diagnostics: [],
1644
+ }
1645
+
1646
+ if (authorityProviderManifestPresent || !consumerProviderManifestPresent) {
1647
+ report.ok = false
1648
+ report.diagnostics.push({
1649
+ ruleId: 'GOV-UPGRADE-ROLE-001',
1650
+ severity: 'BLOCKER',
1651
+ message: authorityProviderManifestPresent
1652
+ ? 'sync-all 是 consumer-only upgrade 入口;DS authority 必須使用受審查的 authority control-plane/update 流程。'
1653
+ : `sync-all consumer 缺少必要的 provider CLI authority mirror:${PROVIDER_CLI_CONSUMER_MANIFEST}`,
1654
+ })
1655
+ }
1656
+
1657
+ if (recoveredInterruptedTransaction) {
1658
+ report.diagnostics.push({
1659
+ ruleId: 'GOV-UPGRADE-RECOVERY-001',
1660
+ severity: 'INFO',
1661
+ message: '已先從 process-crash recovery journal 完整還原前次中斷的 tracked snapshot 與 node_modules,再處理本次命令。',
1662
+ })
1663
+ }
1664
+
1665
+ const emit = () => {
1666
+ if (AS_JSON) {
1667
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n')
1668
+ return
1669
+ }
1670
+ console.log(`Governance upgrade ${report.mode.toUpperCase()}(mutable dist-tags disabled)`)
1671
+ console.log(` current: design-system=${current.designSystem || 'missing'} / storybook=${current.storybook || 'missing'}`)
1672
+ console.log(` target : design-system=${dsTarget || 'not selected'} / storybook=${storybookTarget || 'not selected'}`)
1673
+ console.log(` syntaxValid=${report.syntaxValid} / targetVerification=${report.targetVerification} / targetVerified=${report.targetVerified} / ready=${report.ready}`)
1674
+ for (const diagnostic of report.diagnostics) console.log(` ${diagnostic.severity}: ${diagnostic.message}`)
1675
+ }
1676
+
1677
+ const transactionFailureRule = (error) => {
1678
+ const message = String(error?.message || error || '')
1679
+ if (
1680
+ error?.code === 'GOV-PROVIDER-CLI-CONTROL-PLANE-UPDATE-REQUIRED'
1681
+ || message.includes('GOV-PROVIDER-CLI-CONTROL-PLANE-UPDATE-REQUIRED')
1682
+ ) return 'GOV-UPGRADE-BOOTSTRAP-001'
1683
+ if (message.includes('GOV-UPGRADE-BOOTSTRAP-001')) return 'GOV-UPGRADE-BOOTSTRAP-001'
1684
+ if (message.includes('GOV-UPGRADE-BOOTSTRAP-002')) return 'GOV-UPGRADE-BOOTSTRAP-002'
1685
+ if (/audit(?:\s|[^a-z]).*(?:high|vulnerab)|(?:high|vulnerab).*audit/i.test(message)) return 'GOV-SUPPLY-005'
1686
+ if (/signature|attestation bundle|certificate verification/i.test(message)) return 'GOV-SUPPLY-002'
1687
+ if (/provenance|slsa|immutable release|release bom|release asset|source workflow|workflow mismatch|git commit|git tag/i.test(message)) return 'GOV-SUPPLY-003'
1688
+ if (/verified exact npm|npm (?:runtime|toolchain|tarball)|tar integrity|registry.*npm/i.test(message)) return 'GOV-SUPPLY-004'
1689
+ if (/npm (?:ci|install)|dependency install/i.test(message)) return 'GOV-UPGRADE-003'
1690
+ if (/corpus|provider lifecycle|materiali[sz]ation|mutation authority|governance lock|managed path|launcher destination/i.test(message)) return 'GOV-UPGRADE-008'
1691
+ return 'GOV-UPGRADE-007'
1692
+ }
1693
+ const transactionFailureMessage = (error) => {
1694
+ const message = String(error?.message || error || '')
1695
+ const ruleId = transactionFailureRule(error)
1696
+ if (
1697
+ (ruleId === 'GOV-UPGRADE-BOOTSTRAP-001' || ruleId === 'GOV-UPGRADE-BOOTSTRAP-002')
1698
+ && !message.includes(REVIEWED_CONTROL_PLANE_UPDATE_ROUTE)
1699
+ ) {
1700
+ return `${message}; ${REVIEWED_CONTROL_PLANE_UPDATE_ROUTE}`
1701
+ }
1702
+ return message
1703
+ }
1704
+
1705
+ for (const [name, version] of [['design-system', dsTarget], ['storybook', storybookTarget]]) {
1706
+ if (version && !exactVersion.test(version)) {
1707
+ report.ok = false
1708
+ report.syntaxValid = false
1709
+ report.diagnostics.push({
1710
+ ruleId: 'GOV-VERSION-001',
1711
+ severity: 'BLOCKER',
1712
+ message: `${name} 必須是 exact semver;拒絕 dist-tag/range: ${version}`,
1713
+ })
1714
+ }
1715
+ }
1716
+ if (dsTarget && storybookTarget && dsTarget !== storybookTarget) {
1717
+ report.ok = false
1718
+ report.syntaxValid = false
1719
+ report.diagnostics.push({
1720
+ ruleId: 'GOV-VERSION-002',
1721
+ severity: 'BLOCKER',
1722
+ message: `design-system / storybook-config 必須採同一不可變 release;收到 ${dsTarget} / ${storybookTarget}。`,
1723
+ })
1724
+ }
1725
+ for (const [name, target, installed] of [
1726
+ ['design-system', dsTarget, currentResolved.designSystem],
1727
+ ['storybook-config', storybookTarget, currentResolved.storybook],
1728
+ ]) {
1729
+ if (target && installed && compareVersion(target, installed) < 0) {
1730
+ report.ok = false
1731
+ report.diagnostics.push({
1732
+ ruleId: 'GOV-VERSION-003',
1733
+ severity: 'BLOCKER',
1734
+ message: `${name} monotonic upgrade required;拒絕 ${installed} → ${target} downgrade。Rollback 使用 transaction,不靠發布舊版本。`,
1735
+ })
1736
+ }
1737
+ }
1738
+
1739
+ if (!dsTarget || !storybookTarget) {
1740
+ report.diagnostics.push({
1741
+ ruleId: 'GOV-UPGRADE-001',
1742
+ severity: 'INFO',
1743
+ message: '未選 target;本次只讀取現況,不查詢 registry、不修改 package/lock/generated adapters。',
1744
+ })
1745
+ emit()
1746
+ process.exit(report.ok ? 0 : 1)
1747
+ }
1748
+
1749
+ if (DRY_RUN && report.syntaxValid) {
1750
+ report.ok = false
1751
+ report.diagnostics.push({
1752
+ ruleId: 'GOV-UPGRADE-VERIFICATION-001',
1753
+ severity: 'INFO',
1754
+ message: 'target syntax 已通過,但此 read-only plan 未查詢或驗證 immutable release、Release BOM、npm provenance 與簽章;targetVerification=deferred、ready=false。只有受保護的 --apply 流程才會先完成這些驗證,任一 target 不存在或證據無效時會在 live mutation 前 fail closed。',
1755
+ })
1756
+ }
1757
+
1758
+ if (!report.ok || DRY_RUN) {
1759
+ emit()
1760
+ process.exit(1)
1761
+ }
1762
+
1763
+ try {
1764
+ const governanceLockPath = join(repoRoot, 'governance/lock.json')
1765
+ assertNoSymlinkPath(repoRoot, governanceLockPath, 'current governance lock', { allowMissing: false })
1766
+ validateUpgradeTrustPolicy(JSON.parse(readFileSync(regularFile(governanceLockPath, 'current governance lock'), 'utf8')).upgradeTrust)
1767
+ } catch (error) {
1768
+ report.ok = false
1769
+ report.diagnostics.push({
1770
+ ruleId: 'GOV-SUPPLY-001',
1771
+ severity: 'BLOCKER',
1772
+ message: `目前受信任 governance lock 缺少 closed upgradeTrust policy:${error?.message || error}`,
1773
+ })
1774
+ emit()
1775
+ process.exit(1)
1776
+ }
1777
+
1778
+ let git
1779
+ try {
1780
+ assertClosedGitLocalConfiguration(repoRoot)
1781
+ git = runClosedGit([
1782
+ 'status',
1783
+ '--porcelain=v1',
1784
+ '-z',
1785
+ '--untracked-files=all',
1786
+ '--ignore-submodules=all',
1787
+ '--no-ahead-behind',
1788
+ '--no-renames',
1789
+ ], { cwd: repoRoot })
1790
+ } catch (error) {
1791
+ git = { status: null, signal: null, error, stdout: '' }
1792
+ }
1793
+ if (git.error || git.signal !== null || git.status !== 0 || git.stdout.length !== 0) {
1794
+ report.ok = false
1795
+ report.diagnostics.push({
1796
+ ruleId: 'GOV-UPGRADE-002',
1797
+ severity: 'BLOCKER',
1798
+ message: `upgrade apply 只允許在封閉 Git 邊界驗證為乾淨的 working tree 執行;請先保全既有變更並使用專用 upgrade branch。${git.error ? ` (${git.error.message})` : ''}`,
1799
+ })
1800
+ emit()
1801
+ process.exit(1)
1802
+ }
1803
+
1804
+ const branch = runClosedGit(['symbolic-ref', '--quiet', '--short', 'HEAD'], { cwd: repoRoot })
1805
+ const branchName = !branch.error && branch.signal === null && branch.status === 0 ? branch.stdout.trim() : ''
1806
+ if (!branchName || /^(?:main|master)$/.test(branchName)) {
1807
+ report.ok = false
1808
+ report.diagnostics.push({
1809
+ ruleId: 'GOV-UPGRADE-009',
1810
+ severity: 'BLOCKER',
1811
+ message: branchName
1812
+ ? `upgrade apply 不得直接在 ${branchName} 執行;請建立專用 upgrade branch 後再試。`
1813
+ : 'upgrade apply 不得在 detached HEAD 或無法驗證的 branch 執行;請切換到專用 upgrade branch。',
1814
+ })
1815
+ emit()
1816
+ process.exit(1)
1817
+ }
1818
+
1819
+ const protectedBaseProbe = runClosedGit(['rev-parse', 'HEAD'], { cwd: repoRoot })
1820
+ const protectedBaseSha = !protectedBaseProbe.error && protectedBaseProbe.signal === null && protectedBaseProbe.status === 0
1821
+ ? protectedBaseProbe.stdout.trim()
1822
+ : ''
1823
+ if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(protectedBaseSha)) {
1824
+ report.ok = false
1825
+ report.diagnostics.push({
1826
+ ruleId: 'GOV-UPGRADE-009',
1827
+ severity: 'BLOCKER',
1828
+ message: 'upgrade apply 無法綁定一個 exact protected-base commit。',
1829
+ })
1830
+ emit()
1831
+ process.exit(1)
1832
+ }
1833
+
1834
+ try {
1835
+ validateInstalledForkCorpus(repoRoot)
1836
+ } catch (error) {
1837
+ report.ok = false
1838
+ report.diagnostics.push({
1839
+ ruleId: 'GOV-UPGRADE-008',
1840
+ severity: 'BLOCKER',
1841
+ message: `目前安裝的 provider corpus 無法作為 ordinary upgrade 的 immutable predecessor:${error?.message || error}`,
1842
+ })
1843
+ emit()
1844
+ process.exit(1)
1845
+ }
1846
+
1847
+ // The host's ignored node_modules is never a toolchain trust root. The protected reconstruction
1848
+ // independently downloads, measures and extracts the exact npm tarball bound by the committed
1849
+ // package-lock, then uses only that disposable runtime for ci/install/signature/high-audit gates.
1850
+
1851
+ // Transaction boundary is a UUID capability-bound sibling of the repository, so node_modules can
1852
+ // be moved atomically on the same filesystem. Reject symlinks anywhere in every managed tree before
1853
+ // making even the first backup: a lexical in-repo path must never redirect a copy outside the repo.
1854
+ const transactionId = randomUUID()
1855
+ const transactionRoot = expectedTransactionRoot(transactionId)
1856
+ const transactionOwner = { host: hostname(), pid: process.pid }
1857
+ let transactionState
1858
+ let nodeModulesState
1859
+ let journal
1860
+ let journalLeaseIdentity = null
1861
+ let journalStateSequence = -1
1862
+ let journalStateSha256 = null
1863
+ try {
1864
+ assertNoIgnoredManagedContent(repoRoot, TRANSACTION_PATHS, 'live fixed transaction authority')
1865
+ for (const path of TRANSACTION_PATHS) {
1866
+ assertSafeTree(repoRoot, join(repoRoot, path), `transaction source:${path}`, { allowMissing: true })
1867
+ }
1868
+ const initialNodeModulesPresent = pathEntryExists(join(repoRoot, 'node_modules'))
1869
+ assertNoSymlinkPath(repoRoot, join(repoRoot, 'node_modules'), 'node_modules transaction source')
1870
+ if (initialNodeModulesPresent) {
1871
+ const info = lstatSync(join(repoRoot, 'node_modules'))
1872
+ if (!info.isDirectory() || info.isSymbolicLink()) throw new Error('node_modules transaction source must be a real directory')
1873
+ }
1874
+ mkdirSync(transactionRoot, { mode: 0o700 })
1875
+ writeFileSync(join(transactionRoot, OWNER_MARKER), JSON.stringify({
1876
+ schemaVersion: 2,
1877
+ repoRoot,
1878
+ transactionId,
1879
+ owner: transactionOwner,
1880
+ }, null, 2) + '\n', { flag: 'wx', mode: 0o600 })
1881
+ transactionState = TRANSACTION_PATHS.map((path, index) => {
1882
+ const source = join(repoRoot, path)
1883
+ const backup = join(transactionRoot, String(index))
1884
+ const present = pathEntryExists(source)
1885
+ assertNoSymlinkPath(transactionRoot, backup, `transaction backup:${path}`)
1886
+ if (present) cpSync(source, backup, { recursive: true })
1887
+ return attachBeforeState({ path, source, backup, present }, `fixed transaction target:${path}`)
1888
+ })
1889
+ // Repeat after every before-image is complete. An ignored file created during a recursive copy
1890
+ // must remain live and block the transaction; it must never become invisible backup content that
1891
+ // is later deleted by a whole-tree replacement.
1892
+ assertNoIgnoredManagedContent(repoRoot, TRANSACTION_PATHS, 'snapshotted live fixed transaction authority')
1893
+ nodeModulesState = {
1894
+ source: join(repoRoot, 'node_modules'),
1895
+ backup: join(transactionRoot, 'node_modules'),
1896
+ present: initialNodeModulesPresent,
1897
+ beforeFingerprint: initialNodeModulesPresent
1898
+ ? nodeModulesFingerprint(join(repoRoot, 'node_modules'), 'initial node_modules before-image')
1899
+ : null,
1900
+ afterRecorded: false,
1901
+ afterPresent: false,
1902
+ afterFingerprint: null,
1903
+ replacementStarted: false,
1904
+ replacementCompleted: false,
1905
+ }
1906
+ assertNoSymlinkPath(transactionRoot, nodeModulesState.backup, 'node_modules transaction backup')
1907
+ journal = {
1908
+ schemaVersion: 6,
1909
+ repoRoot,
1910
+ transactionId,
1911
+ transactionRoot,
1912
+ owner: transactionOwner,
1913
+ entries: transactionState,
1914
+ nodeModules: nodeModulesState,
1915
+ providerSnapshot: null,
1916
+ commonSnapshot: null,
1917
+ }
1918
+ } catch (error) {
1919
+ rmSync(transactionRoot, { recursive: true, force: true })
1920
+ report.ok = false
1921
+ report.diagnostics.push({
1922
+ ruleId: 'GOV-UPGRADE-007',
1923
+ severity: 'BLOCKER',
1924
+ message: `無法建立 closed upgrade transaction:${error?.message || error}`,
1925
+ })
1926
+ emit()
1927
+ process.exit(1)
1928
+ }
1929
+ const journalLease = journalLeaseBody({ transactionRoot, transactionId, owner: transactionOwner })
1930
+ const persistJournal = ({ initial = false } = {}) => {
1931
+ if (initial !== (journalStateSequence === -1)) {
1932
+ throw new Error('upgrade journal initial/subsequent state transition is invalid')
1933
+ }
1934
+ if (!initial) assertPublishedJournalLease(journalLeaseIdentity)
1935
+ const nextSequence = journalStateSequence + 1
1936
+ const nextSha256 = publishJournalState({
1937
+ transactionRoot,
1938
+ journal,
1939
+ sequence: nextSequence,
1940
+ previousStateSha256: journalStateSha256,
1941
+ })
1942
+ journalStateSequence = nextSequence
1943
+ journalStateSha256 = nextSha256
1944
+ if (initial) journalLeaseIdentity = publishJournalLease(journalLease)
1945
+ else assertPublishedJournalLease(journalLeaseIdentity)
1946
+ }
1947
+ try {
1948
+ persistJournal({ initial: true })
1949
+ } catch (error) {
1950
+ if (!error?.preserveTransactionRoot) rmSync(transactionRoot, { recursive: true, force: true })
1951
+ report.ok = false
1952
+ report.diagnostics.push({
1953
+ ruleId: 'GOV-UPGRADE-010',
1954
+ severity: 'BLOCKER',
1955
+ message: `無法獨占取得 upgrade transaction;另一個 sync-all 可能仍在執行:${error?.message || error}`,
1956
+ })
1957
+ emit()
1958
+ process.exit(1)
1959
+ }
1960
+
1961
+ let transactionClosed = false
1962
+ let liveMutationStarted = false
1963
+ let providerTransactionState = []
1964
+ let commonTransactionState = null
1965
+ let liveProviderCliCommitIdentity = null
1966
+ const assertTransactionDiscardablesKnown = () => {
1967
+ if (!liveMutationStarted) return
1968
+ inspectNodeModulesJournalState(
1969
+ nodeModulesState,
1970
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
1971
+ 'cleanup node_modules',
1972
+ )
1973
+ for (const [index, entry] of journal.entries.entries()) {
1974
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category: 'fixed', index, label: `cleanup fixed target:${entry.path}` })
1975
+ assertRecoverableLiveState(
1976
+ entry,
1977
+ `cleanup fixed target:${entry.path}`,
1978
+ join(transactionRoot, 'live-staging', 'fixed', String(index)),
1979
+ join(transactionRoot, 'candidate-staging', entry.path),
1980
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'restore'),
1981
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'moved'),
1982
+ )
1983
+ }
1984
+ for (const [index, entry] of (journal.providerSnapshot?.entries || []).entries()) {
1985
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category: 'provider', index, label: `cleanup provider target:${entry.path}` })
1986
+ assertRecoverableLiveState(
1987
+ entry,
1988
+ `cleanup provider target:${entry.path}`,
1989
+ join(transactionRoot, 'live-staging', 'provider', String(index)),
1990
+ join(transactionRoot, 'candidate-staging', entry.path),
1991
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'restore'),
1992
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'moved'),
1993
+ )
1994
+ }
1995
+ if (journal.commonSnapshot) {
1996
+ const entry = journal.commonSnapshot
1997
+ validateRecoveryArtifactSlot({ entry, transactionRoot, category: 'common', index: 0, label: 'cleanup common-instruction target' })
1998
+ assertRecoverableLiveState(
1999
+ entry,
2000
+ 'cleanup common-instruction target',
2001
+ join(transactionRoot, 'live-staging', 'common', '0'),
2002
+ join(transactionRoot, 'candidate-staging', entry.path),
2003
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'restore'),
2004
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'moved'),
2005
+ )
2006
+ }
2007
+ }
2008
+ const waitForTestAcknowledgment = ({ enabled, readyMarker, acknowledgmentName, label }) => {
2009
+ if (!enabled) return
2010
+ const acknowledgmentPath = join(transactionRoot, acknowledgmentName)
2011
+ process.stderr.write(`${readyMarker}\n`)
2012
+ const deadline = Date.now() + 10_000
2013
+ while (Date.now() < deadline) {
2014
+ if (pathEntryExists(acknowledgmentPath)) {
2015
+ const acknowledgment = stableRegularFile(
2016
+ acknowledgmentPath,
2017
+ `${label} acknowledgment`,
2018
+ { links: [1] },
2019
+ )
2020
+ if (!acknowledgment.bytes.equals(Buffer.from('ACK\n'))) {
2021
+ throw new Error(`${label} acknowledgment is invalid`)
2022
+ }
2023
+ rmSync(acknowledgmentPath)
2024
+ return
2025
+ }
2026
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10)
2027
+ }
2028
+ throw new Error(`${label} acknowledgment timed out`)
2029
+ }
2030
+ const cleanupTransaction = ({ commit = false } = {}) => {
2031
+ // Revalidate every predecessor and recovery image immediately before discarding the capability
2032
+ // root. Path-visible concurrent edits therefore remain preserved behind the journal and fail
2033
+ // closed. Uncooperative writers that retain an old open fd are outside the pathname-CAS contract.
2034
+ assertTransactionDiscardablesKnown()
2035
+ // Capture whichever inode is currently public before discarding the capability root. Only the
2036
+ // exact immutable lease can authorize deletion; substituted bytes are moved, restored with
2037
+ // create-if-absent, and preserved behind this transaction for manual reconciliation.
2038
+ assertPublishedJournalLease(journalLeaseIdentity)
2039
+ waitForTestAcknowledgment({
2040
+ enabled: TEST_RELEASE_HANDSHAKE,
2041
+ readyMarker: 'GOV-UPGRADE-TEST-JOURNAL-RELEASE-READY',
2042
+ acknowledgmentName: TEST_RELEASE_ACK,
2043
+ label: 'test journal release',
2044
+ })
2045
+ if (commit) {
2046
+ assertNodeModulesCommitState(nodeModulesState, 'commit node_modules')
2047
+ if (
2048
+ typeof protectedProviderCliStaticVerifier !== 'function'
2049
+ || !liveProviderCliCommitIdentity
2050
+ ) throw new Error('commit lost its protected-base provider CLI verifier capability')
2051
+ const commitProviderCli = providerCliStaticReceipt(
2052
+ protectedProviderCliStaticVerifier({ root: repoRoot }),
2053
+ 'commit-bound live provider CLI',
2054
+ )
2055
+ assertSameProviderCliIdentity(
2056
+ liveProviderCliCommitIdentity,
2057
+ commitProviderCli,
2058
+ 'live-to-commit',
2059
+ )
2060
+ }
2061
+ releaseJournalPointer({
2062
+ expectedIdentity: { ...journalLeaseIdentity, kind: JOURNAL_LEASE_KIND },
2063
+ transactionRoot,
2064
+ label: 'owned upgrade journal lease',
2065
+ })
2066
+ // The successful no-replace pointer release is the commit point. From here onward rollback has
2067
+ // no authority: deleting this private capability root is best-effort garbage collection only.
2068
+ transactionClosed = true
2069
+ try {
2070
+ if (commit && TEST_GC_FAILURE) {
2071
+ throw new Error('test-only transaction garbage-collection failure')
2072
+ }
2073
+ rmSync(transactionRoot, { recursive: true, force: true })
2074
+ report.transactionGarbageCollection = { completed: true, retainedPath: null }
2075
+ } catch (error) {
2076
+ report.transactionGarbageCollection = { completed: false, retainedPath: transactionRoot }
2077
+ report.diagnostics.push({
2078
+ ruleId: 'GOV-UPGRADE-GC-001',
2079
+ severity: 'INFO',
2080
+ message: `transaction 已提交;private recovery root 延後清理且不得觸發 rollback:${transactionRoot}:${error?.message || error}`,
2081
+ })
2082
+ }
2083
+ }
2084
+ const rollbackTransaction = (reason) => {
2085
+ if (transactionClosed) return
2086
+ if (!liveMutationStarted) {
2087
+ report.rollback = { restored: true, reason, derivedState: 'disposable reconstruction never mutated the live repository' }
2088
+ return
2089
+ }
2090
+ const fixedEntries = journal.entries
2091
+ const providerEntries = journal.providerSnapshot?.entries || []
2092
+ const commonEntry = journal.commonSnapshot
2093
+ // Validate the ignored installed tree before restoring any tracked path. Unknown bytes are never
2094
+ // removed under rollback authority; the immutable journal remains for manual reconciliation.
2095
+ inspectNodeModulesJournalState(
2096
+ nodeModulesState,
2097
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
2098
+ 'rollback node_modules',
2099
+ )
2100
+ // The owner may restore only states committed by the same closed journal. Concurrent unknown
2101
+ // edits are preserved and turn the transaction into an explicit manual-recovery blocker.
2102
+ for (const [index, entry] of fixedEntries.entries()) {
2103
+ assertRecoverableLiveState(
2104
+ entry,
2105
+ `rollback fixed target:${entry.path}`,
2106
+ join(liveStagingRoot, 'fixed', String(index)),
2107
+ join(transactionRoot, 'candidate-staging', entry.path),
2108
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'restore'),
2109
+ join(transactionRoot, 'recovery-staging', 'fixed', String(index), 'moved'),
2110
+ )
2111
+ }
2112
+ for (const [index, entry] of providerEntries.entries()) {
2113
+ assertRecoverableLiveState(
2114
+ entry,
2115
+ `rollback provider target:${entry.path}`,
2116
+ join(liveStagingRoot, 'provider', String(index)),
2117
+ join(transactionRoot, 'candidate-staging', entry.path),
2118
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'restore'),
2119
+ join(transactionRoot, 'recovery-staging', 'provider', String(index), 'moved'),
2120
+ )
2121
+ }
2122
+ if (commonEntry) {
2123
+ assertRecoverableLiveState(
2124
+ commonEntry,
2125
+ 'rollback common-instruction target',
2126
+ join(liveStagingRoot, 'common', '0'),
2127
+ join(transactionRoot, 'candidate-staging', commonEntry.path),
2128
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'restore'),
2129
+ join(transactionRoot, 'recovery-staging', 'common', '0', 'moved'),
2130
+ )
2131
+ }
2132
+ for (const [index, entry] of fixedEntries.entries()) {
2133
+ restoreEntryAtomically({ entry, transactionRoot, category: 'fixed', index, label: `rollback fixed target:${entry.path}` })
2134
+ }
2135
+ for (const [index, entry] of providerEntries.entries()) {
2136
+ restoreEntryAtomically({ entry, transactionRoot, category: 'provider', index, label: `rollback provider target:${entry.path}` })
2137
+ }
2138
+ if (commonEntry) {
2139
+ restoreEntryAtomically({ entry: commonEntry, transactionRoot, category: 'common', index: 0, label: 'rollback common-instruction target' })
2140
+ }
2141
+ restoreNodeModulesFromJournal(
2142
+ nodeModulesState,
2143
+ join(transactionRoot, 'candidate-staging', 'node_modules'),
2144
+ 'rollback node_modules',
2145
+ )
2146
+ report.rollback = { restored: true, reason, derivedState: 'original node_modules restored byte-for-byte by same-filesystem rename' }
2147
+ }
2148
+
2149
+ const exitForSignal = { SIGINT: 130, SIGTERM: 143, SIGHUP: 129 }
2150
+ for (const signal of Object.keys(exitForSignal)) process.once(signal, () => {
2151
+ try { rollbackTransaction(`interrupted by ${signal}`); cleanupTransaction() }
2152
+ catch (error) { console.error(`GOV-UPGRADE-ROLLBACK-BLOCKED:${error?.message || error}`) }
2153
+ process.exit(exitForSignal[signal])
2154
+ })
2155
+
2156
+ const candidateRoot = join(transactionRoot, 'candidate-staging')
2157
+ const candidateTemporary = join(transactionRoot, 'candidate-staging.tmp')
2158
+ const liveStagingRoot = join(transactionRoot, 'live-staging')
2159
+ let reconstructedUpgrade = null
2160
+ let reconstructedContext = null
2161
+ let protectedProviderCliStaticVerifier = null
2162
+
2163
+ const copyClosedCandidatePath = (sandbox, relativePath) => {
2164
+ const normalized = normalizeRepositoryRelative(relativePath, 'candidate materialization path')
2165
+ const source = join(sandbox, normalized)
2166
+ const destination = join(candidateTemporary, normalized)
2167
+ assertNoSymlinkPath(sandbox, source, `candidate materialization source:${normalized}`)
2168
+ if (!pathEntryExists(source)) return
2169
+ assertSafeTree(sandbox, source, `candidate materialization source:${normalized}`)
2170
+ mkdirSync(dirname(destination), { recursive: true })
2171
+ cpSync(source, destination, { recursive: true })
2172
+ }
2173
+
2174
+ const captureDisposableCandidate = async ({ sandbox, incomingCorpus, providerTransition, provenance, toolchain, authority, operations }) => {
2175
+ assertNoSymlinkPath(transactionRoot, candidateTemporary, 'candidate materialization temporary root')
2176
+ mkdirSync(candidateTemporary, { mode: 0o700 })
2177
+ for (const path of TRANSACTION_PATHS) copyClosedCandidatePath(sandbox, path)
2178
+
2179
+ const providerPaths = providerTransition.paths.map((record) => ({ ...record }))
2180
+ for (const record of providerPaths) {
2181
+ const covered = TRANSACTION_PATHS.some((root) => record.path === root || record.path.startsWith(`${root}/`))
2182
+ if (covered) throw new Error(`provider path overlaps fixed transaction authority:${record.path}`)
2183
+ copyClosedCandidatePath(sandbox, record.path)
2184
+ }
2185
+ const commonPath = normalizeRepositoryRelative(
2186
+ incomingCorpus.manifest.consumer.commonInstruction.destination,
2187
+ 'candidate common instruction destination',
2188
+ )
2189
+ if (
2190
+ providerPaths.some((record) => commonPath === record.path || commonPath.startsWith(`${record.path}/`) || record.path.startsWith(`${commonPath}/`))
2191
+ ) throw new Error(`common instruction overlaps provider transaction authority:${commonPath}`)
2192
+ const commonCovered = TRANSACTION_PATHS.some((root) => commonPath === root || commonPath.startsWith(`${root}/`))
2193
+ if (!commonCovered) copyClosedCandidatePath(sandbox, commonPath)
2194
+
2195
+ assertNoIgnoredManagedContent(
2196
+ sandbox,
2197
+ [...TRANSACTION_PATHS, ...providerPaths.map((record) => record.path), commonPath],
2198
+ 'disposable candidate managed authority',
2199
+ )
2200
+
2201
+ // `reconstructExpectedUpgrade` created this private checkout from the exact protected-base index,
2202
+ // proved its tree equals protectedBaseSha, and rejected every scripts/** candidate operation before
2203
+ // invoking this callback. Load the privileged provider implementation only from that closed
2204
+ // checkout. A poisoned live worktree hidden behind skip-worktree/assume-unchanged is never imported.
2205
+ // 2026-08-12 GOV-UPGRADE-BOOTSTRAP-001 同族退役(理由同 verify-upgrade-evidence.mjs 主閘):
2206
+ // 「交易期間不執行 incoming 程式」的安全性質由下方「provider module 只從 protected-base
2207
+ // sandbox 載入」原樣保持;scripts/** 改動只以資料入 PR diff,合併後的未來 run 才會執行。
2208
+ if (operations.some((entry) => entry.path === 'scripts' || entry.path.startsWith('scripts/'))) {
2209
+ console.error('INFO: release-bound scripts/** update carried as data(GOV-UPGRADE-BOOTSTRAP-001 retired 2026-08-12); provider module still loads from protected base only')
2210
+ }
2211
+ const providerModulePath = join(sandbox, 'scripts/setup-provider-cli-toolchain.mjs')
2212
+ assertNoSymlinkPath(sandbox, providerModulePath, 'protected-base provider CLI module', { allowMissing: false })
2213
+ regularFile(providerModulePath, 'protected-base provider CLI module')
2214
+ const providerModuleUrl = pathToFileURL(providerModulePath)
2215
+ providerModuleUrl.searchParams.set('protectedBaseSha', protectedBaseSha)
2216
+ const providerModule = await import(providerModuleUrl.href)
2217
+ if (
2218
+ typeof providerModule.setupProviderCliToolchain !== 'function'
2219
+ || typeof providerModule.verifyProviderCliToolchainStatic !== 'function'
2220
+ ) throw new Error('protected-base provider CLI module has an incompatible static API')
2221
+ const {
2222
+ setupProviderCliToolchain: protectedSetupProviderCliToolchain,
2223
+ verifyProviderCliToolchainStatic: protectedVerifyProviderCliToolchainStatic,
2224
+ } = providerModule
2225
+ protectedProviderCliStaticVerifier = protectedVerifyProviderCliToolchainStatic
2226
+
2227
+ // Provider binaries are content-verified but deliberately not executed.
2228
+ const sandboxProviderCli = providerCliStaticReceipt(await protectedSetupProviderCliToolchain({
2229
+ root: sandbox,
2230
+ probeExecutables: false,
2231
+ }), 'disposable sandbox provider CLI setup', { setup: true })
2232
+
2233
+ const candidateModulesSource = join(sandbox, 'node_modules')
2234
+ if (!pathEntryExists(candidateModulesSource)) throw new Error('disposable reconstruction did not produce node_modules')
2235
+ const candidateModulesInfo = lstatSync(candidateModulesSource)
2236
+ if (!candidateModulesInfo.isDirectory() || candidateModulesInfo.isSymbolicLink()) {
2237
+ throw new Error('disposable reconstructed node_modules is not a real directory')
2238
+ }
2239
+ // npm's .bin links are relative to their containing node_modules. Node's default cp behavior
2240
+ // resolves and rewrites those links to the disposable sandbox, which is deleted immediately
2241
+ // after reconstruction. Preserve the link bytes verbatim so the atomic directory move keeps
2242
+ // every executable link relative and live.
2243
+ cpSync(candidateModulesSource, join(candidateTemporary, 'node_modules'), {
2244
+ recursive: true,
2245
+ verbatimSymlinks: true,
2246
+ })
2247
+ renameSync(candidateTemporary, candidateRoot)
2248
+ const candidateProviderCli = providerCliStaticReceipt(
2249
+ protectedVerifyProviderCliToolchainStatic({ root: candidateRoot }),
2250
+ 'captured candidate provider CLI',
2251
+ )
2252
+ assertSameProviderCliIdentity(
2253
+ sandboxProviderCli,
2254
+ candidateProviderCli,
2255
+ 'sandbox-to-candidate',
2256
+ )
2257
+ captureNodeModulesAfterState(
2258
+ nodeModulesState,
2259
+ join(candidateRoot, 'node_modules'),
2260
+ 'captured candidate node_modules',
2261
+ )
2262
+ reconstructedContext = {
2263
+ incomingCorpusEvidence: { ...incomingCorpus.evidence },
2264
+ providerPaths,
2265
+ commonPath,
2266
+ provenance: structuredClone(provenance),
2267
+ toolchain: structuredClone(toolchain),
2268
+ authoritySha256: sha256(JSON.stringify(authority)),
2269
+ operations: operations.map((entry) => ({ ...entry })),
2270
+ providerCli: {
2271
+ identity: candidateProviderCli,
2272
+ sandboxStaticVerified: true,
2273
+ candidateStaticVerified: true,
2274
+ },
2275
+ }
2276
+ }
2277
+
2278
+ const replaceFromCandidate = (entry, candidatePath, movedPath, label) => {
2279
+ const candidatePresent = pathEntryExists(candidatePath)
2280
+ const candidateFingerprint = candidatePresent ? pathFingerprint(candidatePath, `${label} staged candidate`) : null
2281
+ if (
2282
+ !entry.afterRecorded
2283
+ || candidatePresent !== entry.afterPresent
2284
+ || candidateFingerprint !== entry.afterFingerprint
2285
+ || !entry.replacementStarted
2286
+ || entry.replacementCompleted
2287
+ ) throw new Error(`${label} candidate no longer matches the write-ahead journal`)
2288
+ if (entry.present) {
2289
+ mkdirSync(dirname(movedPath), { recursive: true })
2290
+ assertNoSymlinkPath(transactionRoot, movedPath, `${label} moved live before-image`)
2291
+ renameSync(entry.source, movedPath)
2292
+ try {
2293
+ if (pathFingerprint(movedPath, `${label} atomically moved before-image`) !== entry.beforeFingerprint) {
2294
+ throw new Error(`${label} changed between its final CAS check and atomic rename`)
2295
+ }
2296
+ } catch (error) {
2297
+ // The candidate has not been published. Put the exact bytes we just moved back whenever the
2298
+ // source name is still free; if another writer claimed it, preserve both names and leave the
2299
+ // recovery journal for explicit inspection rather than overwriting either edit.
2300
+ if (!pathEntryExists(entry.source) && pathEntryExists(movedPath)) renameSync(movedPath, entry.source)
2301
+ throw error
2302
+ }
2303
+ if (entry.path === 'governance') {
2304
+ waitForTestAcknowledgment({
2305
+ enabled: TEST_CONSUMER_ROLE_GAP_HANDSHAKE,
2306
+ readyMarker: 'GOV-UPGRADE-TEST-CONSUMER-ROLE-GAP-READY',
2307
+ acknowledgmentName: TEST_CONSUMER_ROLE_GAP_ACK,
2308
+ label: 'test consumer role gap',
2309
+ })
2310
+ }
2311
+ }
2312
+ if (entry.afterPresent) {
2313
+ mkdirSync(dirname(entry.source), { recursive: true })
2314
+ assertNoSymlinkPath(repoRoot, dirname(entry.source), `${label} destination parent`, { allowMissing: false })
2315
+ const candidateInfo = lstatSync(candidatePath)
2316
+ if (candidateInfo.isFile() && !candidateInfo.isSymbolicLink()) {
2317
+ // link(2) is an atomic create-if-absent publication on the same filesystem. It cannot erase
2318
+ // a file concurrently created after the last CAS check. The short two-link crash state is
2319
+ // explicitly recognized only when both inodes match inside this capability root.
2320
+ linkSync(candidatePath, entry.source)
2321
+ rmSync(candidatePath)
2322
+ } else {
2323
+ // POSIX directory rename refuses a non-empty or wrong-kind destination. Recheck immediately;
2324
+ // an externally created destination therefore fails closed instead of being pre-removed.
2325
+ if (pathEntryExists(entry.source)) throw new Error(`${label} destination appeared during transaction`)
2326
+ renameSync(candidatePath, entry.source)
2327
+ }
2328
+ }
2329
+ }
2330
+
2331
+ const replaceJournaledEntry = (entry, candidatePath, movedPath, label) => {
2332
+ assertBeforeLiveState(entry, label)
2333
+ entry.replacementStarted = true
2334
+ persistJournal()
2335
+ replaceFromCandidate(entry, candidatePath, movedPath, label)
2336
+ assertExactAfterImage(entry, label)
2337
+ entry.replacementCompleted = true
2338
+ persistJournal()
2339
+ }
2340
+
2341
+ const assertExactAfterImage = (entry, label) => {
2342
+ const present = pathEntryExists(entry.source)
2343
+ const fingerprint = present ? pathFingerprint(entry.source, `${label} live after-image`) : null
2344
+ if (!entry.afterRecorded || present !== entry.afterPresent || fingerprint !== entry.afterFingerprint) {
2345
+ throw new Error(`${label} live after-image differs from disposable reconstruction`)
2346
+ }
2347
+ }
2348
+
2349
+ try {
2350
+ // Build and authenticate the complete target in a disposable protected-base checkout. No
2351
+ // incoming script/checker runs in the live repository, and no live path changes until every
2352
+ // after-image and rollback backup is closed in the owner-bound journal.
2353
+ reconstructedUpgrade = await reconstructExpectedUpgrade({
2354
+ repository: repoRoot,
2355
+ expectedBaseSha: protectedBaseSha,
2356
+ expectedVersion: dsTarget,
2357
+ captureMaterialized: captureDisposableCandidate,
2358
+ })
2359
+ report.targetVerification = 'verified'
2360
+ report.targetVerified = true
2361
+ if (!reconstructedContext || !pathEntryExists(candidateRoot)) throw new Error('disposable reconstruction did not publish a candidate snapshot')
2362
+ if (typeof protectedProviderCliStaticVerifier !== 'function') {
2363
+ throw new Error('protected-base provider CLI verifier capability was not retained')
2364
+ }
2365
+
2366
+ assertClosedGitLocalConfiguration(repoRoot)
2367
+ const freshHead = runClosedGit(['rev-parse', 'HEAD'], { cwd: repoRoot })
2368
+ const freshStatus = runClosedGit([
2369
+ 'status',
2370
+ '--porcelain=v1',
2371
+ '-z',
2372
+ '--untracked-files=all',
2373
+ '--ignore-submodules=all',
2374
+ '--no-ahead-behind',
2375
+ '--no-renames',
2376
+ ], { cwd: repoRoot, output: 'buffer' })
2377
+ if (
2378
+ freshHead.error
2379
+ || freshHead.signal !== null
2380
+ || freshHead.status !== 0
2381
+ || freshHead.stdout.trim() !== protectedBaseSha
2382
+ || freshStatus.error
2383
+ || freshStatus.signal !== null
2384
+ || freshStatus.status !== 0
2385
+ || !Buffer.isBuffer(freshStatus.stdout)
2386
+ || freshStatus.stdout.length !== 0
2387
+ ) {
2388
+ throw new Error('protected base changed during disposable reconstruction')
2389
+ }
2390
+
2391
+ const incomingForkCorpus = validateInstalledForkCorpus(candidateRoot)
2392
+ if (
2393
+ incomingForkCorpus.evidence.releaseVersion !== dsTarget
2394
+ || JSON.stringify(incomingForkCorpus.evidence) !== JSON.stringify(reconstructedContext.incomingCorpusEvidence)
2395
+ ) throw new Error('captured candidate corpus differs from protected-base reconstruction')
2396
+ const providerPaths = collectProviderMutationPaths(incomingForkCorpus.manifest)
2397
+ if (JSON.stringify(providerPaths) !== JSON.stringify(reconstructedContext.providerPaths)) {
2398
+ throw new Error('captured candidate provider path set differs from protected-base transition')
2399
+ }
2400
+ assertNoIgnoredManagedContent(
2401
+ repoRoot,
2402
+ [...providerPaths.map((record) => record.path), reconstructedContext.commonPath],
2403
+ 'live provider/common transaction authority',
2404
+ )
2405
+
2406
+ for (const managedPath of Object.keys(incomingForkCorpus.manifest.consumer.managedFiles || {}).sort()) {
2407
+ const normalized = normalizeRepositoryRelative(managedPath, 'incoming managed path')
2408
+ if (!TRANSACTION_PATHS.some((root) => normalized === root || normalized.startsWith(`${root}/`))) {
2409
+ throw new Error(`incoming managed path is outside fixed transaction authority:${managedPath}`)
2410
+ }
2411
+ }
2412
+ const launcherDestination = normalizeRepositoryRelative(
2413
+ incomingForkCorpus.manifest.consumer.launcherDestination,
2414
+ 'incoming shared launcher destination',
2415
+ )
2416
+ if (!TRANSACTION_PATHS.some((root) => launcherDestination === root || launcherDestination.startsWith(`${root}/`))) {
2417
+ throw new Error(`incoming launcher destination is outside fixed transaction authority:${launcherDestination}`)
2418
+ }
2419
+
2420
+ journal.entries = transactionState.map((entry) => captureCandidateState(
2421
+ entry,
2422
+ join(candidateRoot, entry.path),
2423
+ `fixed transaction target:${entry.path}`,
2424
+ ))
2425
+
2426
+ const evidenceRoot = join(transactionRoot, 'provider-evidence')
2427
+ const candidateDesignSystem = join(candidateRoot, 'node_modules/@qijenchen/design-system')
2428
+ const evidenceDesignSystem = join(evidenceRoot, 'node_modules/@qijenchen/design-system')
2429
+ mkdirSync(evidenceDesignSystem, { recursive: true })
2430
+ for (const runtimePath of ['package.json', 'package-lock.json']) {
2431
+ cpSync(join(candidateRoot, runtimePath), join(evidenceRoot, runtimePath))
2432
+ }
2433
+ cpSync(join(candidateDesignSystem, 'package.json'), join(evidenceDesignSystem, 'package.json'))
2434
+ cpSync(join(candidateDesignSystem, 'ds-canonical/fork'), join(evidenceDesignSystem, 'ds-canonical/fork'), { recursive: true })
2435
+ mkdirSync(join(evidenceDesignSystem, 'src/tokens'), { recursive: true })
2436
+ cpSync(
2437
+ join(candidateDesignSystem, 'src/tokens/utility-registry.json'),
2438
+ join(evidenceDesignSystem, 'src/tokens/utility-registry.json'),
2439
+ )
2440
+ assertSafeTree(transactionRoot, evidenceRoot, 'captured provider evidence corpus')
2441
+ const evidenceCorpus = validateInstalledForkCorpus(evidenceRoot)
2442
+ if (JSON.stringify(evidenceCorpus.evidence) !== JSON.stringify(incomingForkCorpus.evidence)) {
2443
+ throw new Error('captured provider evidence differs from candidate corpus')
2444
+ }
2445
+
2446
+ const providerStaging = join(transactionRoot, 'provider-staging')
2447
+ mkdirSync(providerStaging)
2448
+ providerTransactionState = providerPaths.map((record, index) => {
2449
+ const source = join(repoRoot, record.path)
2450
+ const backup = join(providerStaging, String(index))
2451
+ const present = pathEntryExists(source)
2452
+ assertNoSymlinkPath(repoRoot, source, `provider transaction source:${record.path}`)
2453
+ if (present) {
2454
+ const info = lstatSync(source)
2455
+ if ((record.kind === 'file' && !info.isFile()) || (record.kind === 'tree' && !info.isDirectory())) {
2456
+ throw new Error(`provider transaction source kind mismatch:${record.path}:${record.kind}`)
2457
+ }
2458
+ assertSafeTree(repoRoot, source, `provider transaction source:${record.path}`)
2459
+ cpSync(source, backup, { recursive: true })
2460
+ }
2461
+ return captureCandidateState(
2462
+ attachBeforeState({ path: record.path, source, backup, present }, `provider transaction target:${record.path}`),
2463
+ join(candidateRoot, record.path),
2464
+ `provider transaction target:${record.path}`,
2465
+ )
2466
+ })
2467
+ journal.providerSnapshot = {
2468
+ evidence: { ...incomingForkCorpus.evidence },
2469
+ evidenceRoot,
2470
+ paths: providerPaths.map((record) => ({ ...record })),
2471
+ entries: providerTransactionState.map((entry) => ({ ...entry })),
2472
+ }
2473
+
2474
+ const commonPath = reconstructedContext.commonPath
2475
+ const commonCovered = TRANSACTION_PATHS.some((root) => commonPath === root || commonPath.startsWith(`${root}/`))
2476
+ if (!commonCovered) {
2477
+ const commonSource = join(repoRoot, commonPath)
2478
+ const commonBackup = join(transactionRoot, 'common-staging', '0')
2479
+ mkdirSync(dirname(commonBackup), { recursive: true })
2480
+ const present = pathEntryExists(commonSource)
2481
+ assertNoSymlinkPath(repoRoot, commonSource, 'common-instruction transaction source')
2482
+ if (present) {
2483
+ const info = lstatSync(commonSource)
2484
+ if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) {
2485
+ throw new Error('common-instruction transaction source must be one regular unaliased file')
2486
+ }
2487
+ cpSync(commonSource, commonBackup)
2488
+ }
2489
+ commonTransactionState = captureCandidateState(
2490
+ attachBeforeState({ path: commonPath, source: commonSource, backup: commonBackup, present }, `common transaction target:${commonPath}`),
2491
+ join(candidateRoot, commonPath),
2492
+ `common transaction target:${commonPath}`,
2493
+ )
2494
+ journal.commonSnapshot = { ...commonTransactionState }
2495
+ }
2496
+
2497
+ // The second live scan closes the reconstruction/backup window for every dynamic provider and
2498
+ // common path. Any later path-visible edit is caught by the per-entry fingerprint CAS.
2499
+ assertNoIgnoredManagedContent(
2500
+ repoRoot,
2501
+ [...TRANSACTION_PATHS, ...providerPaths.map((record) => record.path), commonPath],
2502
+ 'fully snapshotted live transaction authority',
2503
+ )
2504
+
2505
+ // Publish all exact before/after states and replacement intent before the first live rename.
2506
+ persistJournal()
2507
+ liveMutationStarted = true
2508
+ mkdirSync(liveStagingRoot)
2509
+ for (const [index, entry] of journal.entries.entries()) {
2510
+ replaceJournaledEntry(entry, join(candidateRoot, entry.path), join(liveStagingRoot, 'fixed', String(index)), `fixed target:${entry.path}`)
2511
+ }
2512
+ for (const [index, entry] of journal.providerSnapshot.entries.entries()) {
2513
+ replaceJournaledEntry(entry, join(candidateRoot, entry.path), join(liveStagingRoot, 'provider', String(index)), `provider target:${entry.path}`)
2514
+ }
2515
+ if (journal.commonSnapshot) {
2516
+ replaceJournaledEntry(journal.commonSnapshot, join(candidateRoot, journal.commonSnapshot.path), join(liveStagingRoot, 'common', '0'), 'common-instruction target')
2517
+ }
2518
+ const candidateModules = join(candidateRoot, 'node_modules')
2519
+ waitForTestAcknowledgment({
2520
+ enabled: TEST_NODE_MODULES_PUBLISH_HANDSHAKE,
2521
+ readyMarker: 'GOV-UPGRADE-TEST-NODE-MODULES-PUBLISH-READY',
2522
+ acknowledgmentName: TEST_NODE_MODULES_PUBLISH_ACK,
2523
+ label: 'test node_modules publication',
2524
+ })
2525
+ assertNodeModulesBeforeState(
2526
+ nodeModulesState,
2527
+ candidateModules,
2528
+ 'node_modules publication',
2529
+ )
2530
+ nodeModulesState.replacementStarted = true
2531
+ persistJournal()
2532
+ if (nodeModulesState.present) renameSync(nodeModulesState.source, nodeModulesState.backup)
2533
+ if (!pathEntryExists(candidateModules)) throw new Error('candidate node_modules disappeared before replacement')
2534
+ renameSync(candidateModules, nodeModulesState.source)
2535
+ if (
2536
+ nodeModulesFingerprint(nodeModulesState.source, 'published node_modules after-image')
2537
+ !== nodeModulesState.afterFingerprint
2538
+ ) throw new Error('published node_modules differs from the journaled candidate after-image')
2539
+ nodeModulesState.replacementCompleted = true
2540
+ persistJournal()
2541
+ const liveProviderCli = providerCliStaticReceipt(
2542
+ protectedProviderCliStaticVerifier({ root: repoRoot }),
2543
+ 'live upgraded provider CLI',
2544
+ )
2545
+ assertSameProviderCliIdentity(
2546
+ reconstructedContext.providerCli.identity,
2547
+ liveProviderCli,
2548
+ 'candidate-to-live',
2549
+ )
2550
+ liveProviderCliCommitIdentity = liveProviderCli
2551
+
2552
+ for (const entry of journal.entries) assertExactAfterImage(entry, `fixed target:${entry.path}`)
2553
+ for (const entry of journal.providerSnapshot.entries) assertExactAfterImage(entry, `provider target:${entry.path}`)
2554
+ if (journal.commonSnapshot) assertExactAfterImage(journal.commonSnapshot, 'common-instruction target')
2555
+ assertNoIgnoredManagedContent(
2556
+ repoRoot,
2557
+ [...TRANSACTION_PATHS, ...providerPaths.map((record) => record.path), commonPath],
2558
+ 'live upgraded transaction authority',
2559
+ )
2560
+ assertClosedGitLocalConfiguration(repoRoot)
2561
+ const livePatch = runClosedGit(
2562
+ ['diff', '--binary', '--full-index', '--no-ext-diff', '--no-textconv', '--no-renames'],
2563
+ { cwd: repoRoot, output: 'buffer', maxOutputBytes: 64 * 1024 * 1024 },
2564
+ )
2565
+ const stagedDiff = runClosedGit(
2566
+ ['diff', '--cached', '--name-only', '-z', '--no-ext-diff', '--no-textconv'],
2567
+ { cwd: repoRoot, output: 'buffer' },
2568
+ )
2569
+ const endingHead = runClosedGit(['rev-parse', 'HEAD'], { cwd: repoRoot })
2570
+ const endingBranch = runClosedGit(['symbolic-ref', '--quiet', '--short', 'HEAD'], { cwd: repoRoot })
2571
+ if (
2572
+ livePatch.error
2573
+ || livePatch.signal !== null
2574
+ || livePatch.status !== 0
2575
+ || !Buffer.isBuffer(livePatch.stdout)
2576
+ || !livePatch.stdout.equals(reconstructedUpgrade.patchBytes)
2577
+ || stagedDiff.error
2578
+ || stagedDiff.signal !== null
2579
+ || stagedDiff.status !== 0
2580
+ || !Buffer.isBuffer(stagedDiff.stdout)
2581
+ || stagedDiff.stdout.length !== 0
2582
+ || endingHead.error
2583
+ || endingHead.signal !== null
2584
+ || endingHead.status !== 0
2585
+ || endingHead.stdout.trim() !== protectedBaseSha
2586
+ || endingBranch.error
2587
+ || endingBranch.signal !== null
2588
+ || endingBranch.status !== 0
2589
+ || endingBranch.stdout.trim() !== branchName
2590
+ ) throw new Error('live upgrade patch/index/base differs from protected-base reconstruction')
2591
+
2592
+ report.provenance = structuredClone(reconstructedUpgrade.authority.provenance)
2593
+ report.toolchain = structuredClone(reconstructedUpgrade.authority.toolchain)
2594
+ report.refresh = {
2595
+ changed: reconstructedUpgrade.operations.map((entry) => entry.path),
2596
+ mode: 'protected-base-disposable-reconstruction',
2597
+ }
2598
+ report.verification = {
2599
+ ok: true,
2600
+ mode: 'protected-base-disposable-reconstruction',
2601
+ attestationDigest: reconstructedUpgrade.authoritySha256,
2602
+ patchSha256: sha256(reconstructedUpgrade.patchBytes),
2603
+ treeSha256: reconstructedUpgrade.treeSha256,
2604
+ candidateCodeExecutedInWriter: false,
2605
+ providerCliExecutableRunsInWriter: false,
2606
+ }
2607
+ report.providerCli = {
2608
+ ...liveProviderCli,
2609
+ sandboxStaticVerified: reconstructedContext.providerCli.sandboxStaticVerified,
2610
+ candidateStaticVerified: reconstructedContext.providerCli.candidateStaticVerified,
2611
+ liveStaticVerified: true,
2612
+ }
2613
+ report.diagnostics.push({
2614
+ ruleId: 'GOV-UPGRADE-005',
2615
+ severity: 'INFO',
2616
+ message: 'exact release 已由 protected-base 在 disposable checkout 重建、驗證並以已綁定 after-image 套用;請檢視 diff 後透過受保護 PR 合併。',
2617
+ })
2618
+ cleanupTransaction({ commit: true })
2619
+ report.ready = true
2620
+ emit()
2621
+ process.exit(0)
2622
+
2623
+ } catch (error) {
2624
+ report.ok = false
2625
+ report.ready = false
2626
+ report.diagnostics.push({
2627
+ ruleId: transactionFailureRule(error),
2628
+ severity: 'BLOCKER',
2629
+ message: `transaction exception:${transactionFailureMessage(error)}`,
2630
+ })
2631
+ try {
2632
+ rollbackTransaction('unexpected transaction exception')
2633
+ cleanupTransaction()
2634
+ } catch (rollbackError) {
2635
+ report.rollback = { restored: false, reason: `${rollbackError?.message || rollbackError}`, recoveryJournal: journalPath }
2636
+ }
2637
+ emit()
2638
+ process.exit(1)
2639
+ }