fundus 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +137 -130
  2. package/build/client/_app/immutable/assets/0.CHekvMpo.css +1 -0
  3. package/build/client/_app/immutable/assets/0.CHekvMpo.css.br +0 -0
  4. package/build/client/_app/immutable/assets/0.CHekvMpo.css.gz +0 -0
  5. package/build/client/_app/immutable/assets/2.Bf0JkVBM.css +1 -0
  6. package/build/client/_app/immutable/assets/2.Bf0JkVBM.css.br +0 -0
  7. package/build/client/_app/immutable/assets/2.Bf0JkVBM.css.gz +0 -0
  8. package/build/client/_app/immutable/assets/FileChangeBadge.C6wwUZJS.css +1 -0
  9. package/build/client/_app/immutable/assets/FileChangeBadge.C6wwUZJS.css.br +0 -0
  10. package/build/client/_app/immutable/assets/FileChangeBadge.C6wwUZJS.css.gz +0 -0
  11. package/build/client/_app/immutable/assets/LibraryContextMenu.BSnKt_Is.css +1 -0
  12. package/build/client/_app/immutable/assets/LibraryContextMenu.BSnKt_Is.css.br +0 -0
  13. package/build/client/_app/immutable/assets/LibraryContextMenu.BSnKt_Is.css.gz +0 -0
  14. package/build/client/_app/immutable/assets/ManifestSelector.Cue3sCA1.css +1 -0
  15. package/build/client/_app/immutable/assets/ManifestSelector.Cue3sCA1.css.br +0 -0
  16. package/build/client/_app/immutable/assets/ManifestSelector.Cue3sCA1.css.gz +0 -0
  17. package/build/client/_app/immutable/chunks/B9iWbZmZ.js +1 -0
  18. package/build/client/_app/immutable/chunks/B9iWbZmZ.js.br +0 -0
  19. package/build/client/_app/immutable/chunks/B9iWbZmZ.js.gz +0 -0
  20. package/build/client/_app/immutable/chunks/BD3hQKzV.js +1 -0
  21. package/build/client/_app/immutable/chunks/BD3hQKzV.js.br +0 -0
  22. package/build/client/_app/immutable/chunks/BD3hQKzV.js.gz +0 -0
  23. package/build/client/_app/immutable/chunks/Blpvahbd.js +108 -0
  24. package/build/client/_app/immutable/chunks/Blpvahbd.js.br +0 -0
  25. package/build/client/_app/immutable/chunks/Blpvahbd.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/C7Cs5PXV.js +1 -0
  27. package/build/client/_app/immutable/chunks/C7Cs5PXV.js.br +0 -0
  28. package/build/client/_app/immutable/chunks/C7Cs5PXV.js.gz +0 -0
  29. package/build/client/_app/immutable/chunks/DPZDGjcn.js +1 -0
  30. package/build/client/_app/immutable/chunks/DPZDGjcn.js.br +0 -0
  31. package/build/client/_app/immutable/chunks/DPZDGjcn.js.gz +0 -0
  32. package/build/client/_app/immutable/chunks/{CN-G-m-B.js → DrsNq6gf.js} +1 -1
  33. package/build/client/_app/immutable/chunks/DrsNq6gf.js.br +0 -0
  34. package/build/client/_app/immutable/chunks/DrsNq6gf.js.gz +0 -0
  35. package/build/client/_app/immutable/chunks/DylBiD8l.js +1 -0
  36. package/build/client/_app/immutable/chunks/DylBiD8l.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/DylBiD8l.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/NblqapDQ.js +3 -0
  39. package/build/client/_app/immutable/chunks/NblqapDQ.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/NblqapDQ.js.gz +0 -0
  41. package/build/client/_app/immutable/entry/app.CFPPKVrc.js +2 -0
  42. package/build/client/_app/immutable/entry/app.CFPPKVrc.js.br +0 -0
  43. package/build/client/_app/immutable/entry/app.CFPPKVrc.js.gz +0 -0
  44. package/build/client/_app/immutable/entry/start.tn-ZAKbY.js +1 -0
  45. package/build/client/_app/immutable/entry/start.tn-ZAKbY.js.br +0 -0
  46. package/build/client/_app/immutable/entry/start.tn-ZAKbY.js.gz +0 -0
  47. package/build/client/_app/immutable/nodes/0.BS8VwNas.js +2 -0
  48. package/build/client/_app/immutable/nodes/0.BS8VwNas.js.br +0 -0
  49. package/build/client/_app/immutable/nodes/0.BS8VwNas.js.gz +0 -0
  50. package/build/client/_app/immutable/nodes/1.Dpaug5O_.js +1 -0
  51. package/build/client/_app/immutable/nodes/1.Dpaug5O_.js.br +2 -0
  52. package/build/client/_app/immutable/nodes/1.Dpaug5O_.js.gz +0 -0
  53. package/build/client/_app/immutable/nodes/2.KyqEUB3M.js +3 -0
  54. package/build/client/_app/immutable/nodes/2.KyqEUB3M.js.br +0 -0
  55. package/build/client/_app/immutable/nodes/2.KyqEUB3M.js.gz +0 -0
  56. package/build/client/_app/immutable/nodes/3.j8JVBjzd.js +1 -0
  57. package/build/client/_app/immutable/nodes/3.j8JVBjzd.js.br +0 -0
  58. package/build/client/_app/immutable/nodes/3.j8JVBjzd.js.gz +0 -0
  59. package/build/client/_app/immutable/nodes/4.CiYE8hwS.js +2 -0
  60. package/build/client/_app/immutable/nodes/4.CiYE8hwS.js.br +0 -0
  61. package/build/client/_app/immutable/nodes/4.CiYE8hwS.js.gz +0 -0
  62. package/build/client/_app/version.json +1 -1
  63. package/build/client/_app/version.json.br +0 -0
  64. package/build/client/_app/version.json.gz +0 -0
  65. package/build/handler.js +7 -7
  66. package/build/index.js +7 -7
  67. package/build/server/chunks/chunks/{context.js-bXe5hzjI.js → context.js-CLnT3cF3.js} +124 -7
  68. package/build/server/chunks/chunks/context.js-CLnT3cF3.js.map +1 -0
  69. package/build/server/chunks/chunks/{contract.js-sHny3b-s.js → contract.js-DGMufT2e.js} +191 -178
  70. package/build/server/chunks/chunks/contract.js-DGMufT2e.js.map +1 -0
  71. package/build/server/chunks/chunks/{core.js-Clg1CHb6.js → core.js-DNIuZ9y-.js} +88 -2
  72. package/build/server/chunks/chunks/core.js-DNIuZ9y-.js.map +1 -0
  73. package/build/server/chunks/chunks/{exports.js-FRj9eAnR.js → exports.js-CAJ9ZQQx.js} +2 -2
  74. package/build/server/chunks/chunks/{exports.js-FRj9eAnR.js.map → exports.js-CAJ9ZQQx.js.map} +1 -1
  75. package/build/server/chunks/chunks/{http.js--6sDZFfm.js → http.js-DWYlsbZd.js} +2 -2
  76. package/build/server/chunks/chunks/{http.js--6sDZFfm.js.map → http.js-DWYlsbZd.js.map} +1 -1
  77. package/build/server/chunks/chunks/{internal.js-D2Tk-vi1.js → internal.js-CdY4S4Uy.js} +3 -3
  78. package/build/server/chunks/chunks/{internal.js-D2Tk-vi1.js.map → internal.js-CdY4S4Uy.js.map} +1 -1
  79. package/build/server/chunks/chunks/internal2.js-BlXt2rfE.js.map +1 -1
  80. package/build/server/chunks/chunks/manifest-membership.js-CJnQXrL4.js +213 -0
  81. package/build/server/chunks/chunks/manifest-membership.js-CJnQXrL4.js.map +1 -0
  82. package/build/server/chunks/chunks/raw-reconciliation.js-_D9lZ_sc.js +11 -0
  83. package/build/server/chunks/chunks/raw-reconciliation.js-_D9lZ_sc.js.map +1 -0
  84. package/build/server/chunks/chunks/{raw-reconciliation.js-DOFtjkgu.js → raw-reconciliation2.js-C2No1QIL.js} +3 -34
  85. package/build/server/chunks/chunks/raw-reconciliation2.js-C2No1QIL.js.map +1 -0
  86. package/build/server/chunks/chunks/{shared.js-hvokB2mY.js → shared.js-C34rGnTQ.js} +2 -2
  87. package/build/server/chunks/chunks/{shared.js-hvokB2mY.js.map → shared.js-C34rGnTQ.js.map} +1 -1
  88. package/build/server/chunks/chunks/{utils.js-VGlYdWt0.js → utils.js-BMCQVogA.js} +3 -3
  89. package/build/server/chunks/chunks/{utils.js-VGlYdWt0.js.map → utils.js-BMCQVogA.js.map} +1 -1
  90. package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-CkSErIdC.js → _server.ts.js-Bmyh2WUa.js} +7 -6
  91. package/build/server/chunks/entries/endpoints/api/_...path_/{_server.ts.js-CkSErIdC.js.map → _server.ts.js-Bmyh2WUa.js.map} +1 -1
  92. package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-Csnt5ISN.js → _server.ts.js-IMleqOQb.js} +8 -7
  93. package/build/server/chunks/entries/endpoints/api/assets/_id_/{_server.ts.js-Csnt5ISN.js.map → _server.ts.js-IMleqOQb.js.map} +1 -1
  94. package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-BVEQaFEu.js → _server.ts.js-DzFoWnCN.js} +8 -7
  95. package/build/server/chunks/entries/endpoints/api/assets/_id_/raw/{_server.ts.js-BVEQaFEu.js.map → _server.ts.js-DzFoWnCN.js.map} +1 -1
  96. package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-DIaT5h8R.js → _server.ts.js-0LjvQ5dF.js} +8 -7
  97. package/build/server/chunks/entries/endpoints/api/assets/_id_/reimport/{_server.ts.js-DIaT5h8R.js.map → _server.ts.js-0LjvQ5dF.js.map} +1 -1
  98. package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-CgCr-jFC.js → _server.ts.js-BUbO2k7N.js} +8 -7
  99. package/build/server/chunks/entries/endpoints/api/assets/{_server.ts.js-CgCr-jFC.js.map → _server.ts.js-BUbO2k7N.js.map} +1 -1
  100. package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-BCvv4wq4.js → _server.ts.js-CwFLvCzR.js} +8 -7
  101. package/build/server/chunks/entries/endpoints/api/assets/delete/{_server.ts.js-BCvv4wq4.js.map → _server.ts.js-CwFLvCzR.js.map} +1 -1
  102. package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-GbxbM9uI.js → _server.ts.js-BA6bgOR_.js} +8 -7
  103. package/build/server/chunks/entries/endpoints/api/assets/move/{_server.ts.js-GbxbM9uI.js.map → _server.ts.js-BA6bgOR_.js.map} +1 -1
  104. package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-BGjOvpRm.js → _server.ts.js-CzzmQqXq.js} +8 -7
  105. package/build/server/chunks/entries/endpoints/api/folders/_path_/{_server.ts.js-BGjOvpRm.js.map → _server.ts.js-CzzmQqXq.js.map} +1 -1
  106. package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-CJuzJXPs.js → _server.ts.js-aqJkae-h.js} +8 -7
  107. package/build/server/chunks/entries/endpoints/api/folders/{_server.ts.js-CJuzJXPs.js.map → _server.ts.js-aqJkae-h.js.map} +1 -1
  108. package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-BYp42p6V.js → _server.ts.js-CGsIZ1tO.js} +8 -7
  109. package/build/server/chunks/entries/endpoints/api/imports/{_server.ts.js-BYp42p6V.js.map → _server.ts.js-CGsIZ1tO.js.map} +1 -1
  110. package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-l_tkhnQ-.js → _server.ts.js-DbaeknBw.js} +8 -7
  111. package/build/server/chunks/entries/endpoints/api/manifests/_name_/{_server.ts.js-l_tkhnQ-.js.map → _server.ts.js-DbaeknBw.js.map} +1 -1
  112. package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-B-VXO3Xr.js → _server.ts.js-BhY5m7VP.js} +8 -7
  113. package/build/server/chunks/entries/endpoints/api/manifests/{_server.ts.js-B-VXO3Xr.js.map → _server.ts.js-BhY5m7VP.js.map} +1 -1
  114. package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-DV7s20GV.js → _server.ts.js-PT92H6EE.js} +8 -7
  115. package/build/server/chunks/entries/endpoints/api/raw/adopt/{_server.ts.js-DV7s20GV.js.map → _server.ts.js-PT92H6EE.js.map} +1 -1
  116. package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-CYgOpWYC.js → _server.ts.js-DtiUkpdM.js} +8 -7
  117. package/build/server/chunks/entries/endpoints/api/raw/edited/accept/{_server.ts.js-CYgOpWYC.js.map → _server.ts.js-DtiUkpdM.js.map} +1 -1
  118. package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-7loll6HR.js → _server.ts.js-tVkpwUwF.js} +8 -7
  119. package/build/server/chunks/entries/endpoints/api/raw/edited/dismiss/{_server.ts.js-7loll6HR.js.map → _server.ts.js-tVkpwUwF.js.map} +1 -1
  120. package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-CdxeTMZj.js → _server.ts.js-Cq85RWhU.js} +8 -7
  121. package/build/server/chunks/entries/endpoints/api/reconcile/{_server.ts.js-CdxeTMZj.js.map → _server.ts.js-Cq85RWhU.js.map} +1 -1
  122. package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-CZWIskM4.js → _server.ts.js-DDdYWvN4.js} +8 -7
  123. package/build/server/chunks/entries/endpoints/api/reveal/{_server.ts.js-CZWIskM4.js.map → _server.ts.js-DDdYWvN4.js.map} +1 -1
  124. package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-CZFfpJkl.js → _server.ts.js-DxSPXWoT.js} +8 -7
  125. package/build/server/chunks/entries/endpoints/api/state/{_server.ts.js-CZFfpJkl.js.map → _server.ts.js-DxSPXWoT.js.map} +1 -1
  126. package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-DB3i4juR.js → _server.ts.js-DVtQlFHS.js} +7 -6
  127. package/build/server/chunks/entries/endpoints/files/_...path_/{_server.ts.js-DB3i4juR.js.map → _server.ts.js-DVtQlFHS.js.map} +1 -1
  128. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-BqarqenW.js → _server.ts.js-DuStxYsU.js} +8 -7
  129. package/build/server/chunks/entries/endpoints/files/proxy/_...path_/{_server.ts.js-BqarqenW.js.map → _server.ts.js-DuStxYsU.js.map} +1 -1
  130. package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-CXbrUCmh.js → _server.ts.js-CxoKyl-h.js} +8 -7
  131. package/build/server/chunks/entries/endpoints/files/raw/_...path_/{_server.ts.js-CXbrUCmh.js.map → _server.ts.js-CxoKyl-h.js.map} +1 -1
  132. package/build/server/chunks/entries/{hooks.server.js-6Yf-GF0J.js → hooks.server.js-DLJAlp7i.js} +7 -6
  133. package/build/server/chunks/entries/{hooks.server.js-6Yf-GF0J.js.map → hooks.server.js-DLJAlp7i.js.map} +1 -1
  134. package/build/server/chunks/{handler-DHAu99Rv.js → handler-Bn4TsL93.js} +5 -5
  135. package/build/server/chunks/{handler-DHAu99Rv.js.map → handler-Bn4TsL93.js.map} +1 -1
  136. package/build/server/chunks/{index.js-Bm1XIAPD.js → index.js-DzYQtf0T.js} +5 -5
  137. package/build/server/chunks/{index.js-Bm1XIAPD.js.map → index.js-DzYQtf0T.js.map} +1 -1
  138. package/build/server/chunks/{manifest.js-CCc26-hb.js → manifest.js-DewM2Q1D.js} +28 -28
  139. package/build/server/chunks/{manifest.js-CCc26-hb.js.map → manifest.js-DewM2Q1D.js.map} +1 -1
  140. package/build/server/chunks/nodes/0.js-CZe1W9_P.js +11 -0
  141. package/build/server/chunks/nodes/0.js-CZe1W9_P.js.map +1 -0
  142. package/build/server/chunks/nodes/1.js-DKVH5bGU.js +7 -0
  143. package/build/server/chunks/nodes/{1.js-CXgbNa8h.js.map → 1.js-DKVH5bGU.js.map} +1 -1
  144. package/build/server/chunks/nodes/2.js-BpN0Hxjo.js +7 -0
  145. package/build/server/chunks/nodes/2.js-BpN0Hxjo.js.map +1 -0
  146. package/build/server/chunks/nodes/3.js-D3kgOm0S.js +7 -0
  147. package/build/server/chunks/nodes/3.js-D3kgOm0S.js.map +1 -0
  148. package/build/server/chunks/nodes/4.js-CZwje1Lo.js +7 -0
  149. package/build/server/chunks/nodes/{4.js-BUgaRCEY.js.map → 4.js-CZwje1Lo.js.map} +1 -1
  150. package/dist/core/api-types.d.ts +4 -0
  151. package/dist/core/index.d.ts +2 -2
  152. package/dist/core/index.js +1 -1
  153. package/dist/core/plugins/slice.d.ts +28 -4
  154. package/dist/core/plugins/slice.js +50 -0
  155. package/dist/server/cli-commands.d.ts +1 -1
  156. package/dist/server/cli-commands.js +125 -11
  157. package/dist/server/config-loader.d.ts +2 -0
  158. package/dist/server/config-loader.js +1 -0
  159. package/dist/server/git.d.ts +9 -0
  160. package/dist/server/git.js +121 -0
  161. package/dist/server/library-store.d.ts +1 -1
  162. package/dist/server/library-store.js +5 -1
  163. package/dist/server/operations.js +28 -2
  164. package/dist/server/plugins/slice.d.ts +3 -2
  165. package/dist/server/plugins/slice.js +21 -9
  166. package/dist/server/processing/slice-processing.d.ts +14 -0
  167. package/dist/server/processing/slice-processing.js +148 -0
  168. package/package.json +1 -1
  169. package/build/client/_app/immutable/assets/0.inkPq3ni.css +0 -1
  170. package/build/client/_app/immutable/assets/0.inkPq3ni.css.br +0 -0
  171. package/build/client/_app/immutable/assets/0.inkPq3ni.css.gz +0 -0
  172. package/build/client/_app/immutable/assets/2.DLP0pEak.css +0 -1
  173. package/build/client/_app/immutable/assets/2.DLP0pEak.css.br +0 -0
  174. package/build/client/_app/immutable/assets/2.DLP0pEak.css.gz +0 -0
  175. package/build/client/_app/immutable/assets/LibraryContextMenu.CVb-Lqdf.css +0 -1
  176. package/build/client/_app/immutable/assets/LibraryContextMenu.CVb-Lqdf.css.br +0 -0
  177. package/build/client/_app/immutable/assets/LibraryContextMenu.CVb-Lqdf.css.gz +0 -0
  178. package/build/client/_app/immutable/assets/ManifestSelector.Il8p28r8.css +0 -1
  179. package/build/client/_app/immutable/assets/ManifestSelector.Il8p28r8.css.br +0 -0
  180. package/build/client/_app/immutable/assets/ManifestSelector.Il8p28r8.css.gz +0 -0
  181. package/build/client/_app/immutable/chunks/B1UabfW7.js +0 -1
  182. package/build/client/_app/immutable/chunks/B1UabfW7.js.br +0 -0
  183. package/build/client/_app/immutable/chunks/B1UabfW7.js.gz +0 -0
  184. package/build/client/_app/immutable/chunks/BmCZn5E-.js +0 -108
  185. package/build/client/_app/immutable/chunks/BmCZn5E-.js.br +0 -0
  186. package/build/client/_app/immutable/chunks/BmCZn5E-.js.gz +0 -0
  187. package/build/client/_app/immutable/chunks/BoEHtxM8.js +0 -1
  188. package/build/client/_app/immutable/chunks/BoEHtxM8.js.br +0 -0
  189. package/build/client/_app/immutable/chunks/BoEHtxM8.js.gz +0 -0
  190. package/build/client/_app/immutable/chunks/C-T1_s5P.js +0 -1
  191. package/build/client/_app/immutable/chunks/C-T1_s5P.js.br +0 -0
  192. package/build/client/_app/immutable/chunks/C-T1_s5P.js.gz +0 -0
  193. package/build/client/_app/immutable/chunks/CN-G-m-B.js.br +0 -4
  194. package/build/client/_app/immutable/chunks/CN-G-m-B.js.gz +0 -0
  195. package/build/client/_app/immutable/chunks/D5sQSsUv.js +0 -1
  196. package/build/client/_app/immutable/chunks/D5sQSsUv.js.br +0 -0
  197. package/build/client/_app/immutable/chunks/D5sQSsUv.js.gz +0 -0
  198. package/build/client/_app/immutable/chunks/D65cSBhe.js +0 -3
  199. package/build/client/_app/immutable/chunks/D65cSBhe.js.br +0 -0
  200. package/build/client/_app/immutable/chunks/D65cSBhe.js.gz +0 -0
  201. package/build/client/_app/immutable/chunks/D6VoU_x4.js +0 -1
  202. package/build/client/_app/immutable/chunks/D6VoU_x4.js.br +0 -0
  203. package/build/client/_app/immutable/chunks/D6VoU_x4.js.gz +0 -0
  204. package/build/client/_app/immutable/entry/app.fVDDVV_y.js +0 -2
  205. package/build/client/_app/immutable/entry/app.fVDDVV_y.js.br +0 -0
  206. package/build/client/_app/immutable/entry/app.fVDDVV_y.js.gz +0 -0
  207. package/build/client/_app/immutable/entry/start.BiWgLLju.js +0 -1
  208. package/build/client/_app/immutable/entry/start.BiWgLLju.js.br +0 -1
  209. package/build/client/_app/immutable/entry/start.BiWgLLju.js.gz +0 -0
  210. package/build/client/_app/immutable/nodes/0.BLnSe7Ya.js +0 -2
  211. package/build/client/_app/immutable/nodes/0.BLnSe7Ya.js.br +0 -0
  212. package/build/client/_app/immutable/nodes/0.BLnSe7Ya.js.gz +0 -0
  213. package/build/client/_app/immutable/nodes/1.DEw3d5yL.js +0 -1
  214. package/build/client/_app/immutable/nodes/1.DEw3d5yL.js.br +0 -0
  215. package/build/client/_app/immutable/nodes/1.DEw3d5yL.js.gz +0 -0
  216. package/build/client/_app/immutable/nodes/2.DnVTXPVk.js +0 -3
  217. package/build/client/_app/immutable/nodes/2.DnVTXPVk.js.br +0 -0
  218. package/build/client/_app/immutable/nodes/2.DnVTXPVk.js.gz +0 -0
  219. package/build/client/_app/immutable/nodes/3.1Hco6zU7.js +0 -1
  220. package/build/client/_app/immutable/nodes/3.1Hco6zU7.js.br +0 -0
  221. package/build/client/_app/immutable/nodes/3.1Hco6zU7.js.gz +0 -0
  222. package/build/client/_app/immutable/nodes/4.CKbcoBw2.js +0 -2
  223. package/build/client/_app/immutable/nodes/4.CKbcoBw2.js.br +0 -0
  224. package/build/client/_app/immutable/nodes/4.CKbcoBw2.js.gz +0 -0
  225. package/build/server/chunks/chunks/asset-id.js-CFsW8jeL.js +0 -48
  226. package/build/server/chunks/chunks/asset-id.js-CFsW8jeL.js.map +0 -1
  227. package/build/server/chunks/chunks/context.js-bXe5hzjI.js.map +0 -1
  228. package/build/server/chunks/chunks/contract.js-sHny3b-s.js.map +0 -1
  229. package/build/server/chunks/chunks/core.js-Clg1CHb6.js.map +0 -1
  230. package/build/server/chunks/chunks/raw-reconciliation.js-DOFtjkgu.js.map +0 -1
  231. package/build/server/chunks/chunks/raw-reconciliation2.js-DFwky2ou.js +0 -11
  232. package/build/server/chunks/chunks/raw-reconciliation2.js-DFwky2ou.js.map +0 -1
  233. package/build/server/chunks/nodes/0.js-Bpzcq6LZ.js +0 -11
  234. package/build/server/chunks/nodes/0.js-Bpzcq6LZ.js.map +0 -1
  235. package/build/server/chunks/nodes/1.js-CXgbNa8h.js +0 -7
  236. package/build/server/chunks/nodes/2.js-D56ryWAu.js +0 -7
  237. package/build/server/chunks/nodes/2.js-D56ryWAu.js.map +0 -1
  238. package/build/server/chunks/nodes/3.js-DMaZRwrN.js +0 -7
  239. package/build/server/chunks/nodes/3.js-DMaZRwrN.js.map +0 -1
  240. package/build/server/chunks/nodes/4.js-BUgaRCEY.js +0 -7
@@ -257,10 +257,13 @@ Example:
257
257
  export const ASSET_INGEST_HELP = `fundus asset ingest — acquire a file or Figma selection as a typed asset
258
258
 
259
259
  Usage: fundus asset ingest <file> [--type <type>] [--id <id>] [--folder <path|root>]
260
- [--manifests <a,b>] [--parameters <json>] [--from file] [--json]
260
+ [--manifests <a,b>] [--parameters <json>]
261
+ [--compression-x <0-100>] [--compression-y <0-100>]
262
+ [--from file] [--json]
261
263
  fundus asset ingest <figma-selection-link> --from figma --type <image|slice> --id <id>
262
264
  [--scale <1|2|3|4>] [--folder <path|root>]
263
- [--manifests <a,b>] [--parameters <json>] [--json]
265
+ [--manifests <a,b>] [--parameters <json>]
266
+ [--compression-x <0-100>] [--compression-y <0-100>] [--json]
264
267
 
265
268
  File ingest remains the default and behaves like an editor upload. Figma
266
269
  ingest materializes one selection as PNG through the same importer-neutral
@@ -278,6 +281,10 @@ Flags:
278
281
  --manifests <a,b> explicit manifest membership (every name must exist)
279
282
  --parameters <json> shallow parameter patch merged after ingest seeding
280
283
  (see \`fundus asset set --help\`)
284
+ --compression-x <0-100>
285
+ --compression-y <0-100>
286
+ percentage compression of a Slice asset's horizontal or
287
+ vertical stretch region; omitted axes default to 0
281
288
  --scale <1|2|3|4> Figma export scale; default:
282
289
  import.figma.defaults.scale from fundus.config.ts
283
290
  (invalid for file ingest)
@@ -287,7 +294,8 @@ Flags:
287
294
  A failed ingest leaves neither a raw file nor a record behind.
288
295
 
289
296
  Example:
290
- fundus asset ingest ./exports/navigation_panel@2x.png --type slice --json
297
+ fundus asset ingest ./exports/navigation_panel@2x.png --type slice \\
298
+ --compression-x 75 --compression-y 25 --json
291
299
  fundus asset ingest 'https://www.figma.com/design/abc/UI?node-id=12-34' \\
292
300
  --from figma --type slice --id navigationPanel --scale 3 --json
293
301
  `;
@@ -332,10 +340,11 @@ Example:
332
340
  `;
333
341
  export const ASSET_SET_HELP = `fundus asset set — update an asset's parameters and/or memberships
334
342
 
335
- Usage: fundus asset set <id> [--parameters <json>] [--manifests <a,b>] [--json]
343
+ Usage: fundus asset set <id> [--parameters <json>] [--manifests <a,b>]
344
+ [--compression-x <0-100>] [--compression-y <0-100>] [--json]
336
345
 
337
- At least one of --parameters/--manifests is required. Runs the full
338
- autosave chain (write library → process → regenerate manifest modules).
346
+ At least one change flag is required. Runs the full autosave chain
347
+ (write library → process → regenerate manifest modules).
339
348
 
340
349
  Flags:
341
350
  --parameters <json> SHALLOW MERGE at the top level onto the current
@@ -351,6 +360,12 @@ Flags:
351
360
  reference
352
361
  --manifests <a,b> REPLACES the explicit membership set (declarative,
353
362
  idempotent); --manifests "" clears it
363
+ --compression-x <0-100>
364
+ --compression-y <0-100>
365
+ set one Slice stretch-compression axis while preserving
366
+ the omitted axis; setting both axes to 0 removes
367
+ compression. These values override compression supplied
368
+ through --parameters in the same invocation
354
369
  --json print {"ok": true, "asset": <AssetStateDto>, "issues": […]}
355
370
  --help this help
356
371
 
@@ -360,6 +375,7 @@ asset, a reference cycle, or an unknown manifest name. Ingest reference
360
375
  targets before pointing at them.
361
376
 
362
377
  Example:
378
+ fundus asset set navigationPanel --compression-x 75 --compression-y 25 --json
363
379
  fundus asset set characterIdle \\
364
380
  --parameters '{"mask": {"$asset": "characterIdleMask"}}' --json
365
381
  `;
@@ -492,6 +508,70 @@ function inferTypeForFileName(fileName) {
492
508
  }
493
509
  throw new Error(`The ".${extension}" extension is ambiguous — pass --type <${candidates.join('|')}>.`);
494
510
  }
511
+ function parseCompressionPercentage(name, value, commandPath) {
512
+ if (value === undefined)
513
+ return undefined;
514
+ if (typeof value !== 'string' || !/^\d+$/.test(value) || Number(value) > 100) {
515
+ throw new CliUsageError(`Flag "--${name}" must be an integer from 0 to 100 — run \`${commandPath} --help\`.`);
516
+ }
517
+ return Number(value);
518
+ }
519
+ function parseSliceCompressionFlags(flags, commandPath) {
520
+ const x = parseCompressionPercentage('compression-x', flags['compression-x'], commandPath);
521
+ const y = parseCompressionPercentage('compression-y', flags['compression-y'], commandPath);
522
+ if (x === undefined && y === undefined)
523
+ return undefined;
524
+ return {
525
+ ...(x !== undefined ? { x } : {}),
526
+ ...(y !== undefined ? { y } : {})
527
+ };
528
+ }
529
+ function parameterPatchRecord(parametersPatch) {
530
+ if (typeof parametersPatch !== 'object' ||
531
+ parametersPatch === null ||
532
+ Array.isArray(parametersPatch)) {
533
+ throw new Error('The parameter patch must be a JSON object, e.g. {"preset": "default"}.');
534
+ }
535
+ return parametersPatch;
536
+ }
537
+ function compressionFromParameters(parameters) {
538
+ if (typeof parameters !== 'object' || parameters === null || Array.isArray(parameters)) {
539
+ return { x: 0, y: 0 };
540
+ }
541
+ const compression = parameters.compression;
542
+ if (typeof compression !== 'object' || compression === null || Array.isArray(compression)) {
543
+ return { x: 0, y: 0 };
544
+ }
545
+ return compression;
546
+ }
547
+ /** Add the ergonomic per-axis flags to the generic top-level parameter patch. */
548
+ function applySliceCompressionFlags(options) {
549
+ if (options.flags === undefined)
550
+ return options.parametersPatch;
551
+ if (options.type !== 'slice') {
552
+ throw new CliUsageError(`Flags "--compression-x" and "--compression-y" are only valid for Slice assets — run \`${options.commandPath} --help\`.`);
553
+ }
554
+ const patch = options.parametersPatch === undefined ? {} : parameterPatchRecord(options.parametersPatch);
555
+ let compression = compressionFromParameters(options.currentParameters);
556
+ if (Object.hasOwn(patch, 'compression')) {
557
+ if (patch.compression === null) {
558
+ compression = { x: 0, y: 0 };
559
+ }
560
+ else if (typeof patch.compression === 'object' &&
561
+ patch.compression !== null &&
562
+ !Array.isArray(patch.compression)) {
563
+ compression = { ...compression, ...patch.compression };
564
+ }
565
+ else {
566
+ throw new Error('Slice compression must be an object with x/y percentages.');
567
+ }
568
+ }
569
+ const nextCompression = { ...compression, ...options.flags };
570
+ return {
571
+ ...patch,
572
+ compression: nextCompression.x === 0 && nextCompression.y === 0 ? null : nextCompression
573
+ };
574
+ }
495
575
  async function runAssetIngest(argumentList) {
496
576
  const parsed = parseArguments(argumentList, {
497
577
  ...COMMON_FLAGS,
@@ -499,6 +579,8 @@ async function runAssetIngest(argumentList) {
499
579
  id: { takesValue: true },
500
580
  manifests: { takesValue: true },
501
581
  parameters: { takesValue: true },
582
+ 'compression-x': { takesValue: true },
583
+ 'compression-y': { takesValue: true },
502
584
  folder: { takesValue: true },
503
585
  from: { takesValue: true },
504
586
  scale: { takesValue: true }
@@ -514,9 +596,10 @@ async function runAssetIngest(argumentList) {
514
596
  if (from === 'file' && scale !== undefined) {
515
597
  throw new CliUsageError('Flag "--scale" is only valid with `--from figma` — run `fundus asset ingest --help`.');
516
598
  }
517
- const parametersPatch = typeof parsed.flags.parameters === 'string'
599
+ let parametersPatch = typeof parsed.flags.parameters === 'string'
518
600
  ? parseJsonFlag('parameters', parsed.flags.parameters)
519
601
  : undefined;
602
+ const compressionFlags = parseSliceCompressionFlags(parsed.flags, 'fundus asset ingest');
520
603
  const manifests = typeof parsed.flags.manifests === 'string'
521
604
  ? parseManifestList(parsed.flags.manifests)
522
605
  : undefined;
@@ -531,6 +614,12 @@ async function runAssetIngest(argumentList) {
531
614
  }
532
615
  const id = parsed.flags.id;
533
616
  const type = parsed.flags.type;
617
+ parametersPatch = applySliceCompressionFlags({
618
+ type,
619
+ flags: compressionFlags,
620
+ parametersPatch,
621
+ commandPath: 'fundus asset ingest'
622
+ });
534
623
  const operations = await createOperations();
535
624
  const state = await operations.importAsset({
536
625
  importer: 'figma',
@@ -561,6 +650,12 @@ async function runAssetIngest(argumentList) {
561
650
  const fileName = basename(absolutePath);
562
651
  const type = typeof parsed.flags.type === 'string' ? parsed.flags.type : inferTypeForFileName(fileName);
563
652
  const id = typeof parsed.flags.id === 'string' ? parsed.flags.id : proposeAssetId(fileName);
653
+ parametersPatch = applySliceCompressionFlags({
654
+ type,
655
+ flags: compressionFlags,
656
+ parametersPatch,
657
+ commandPath: 'fundus asset ingest'
658
+ });
564
659
  const operations = await createOperations();
565
660
  const state = await operations.ingest({
566
661
  fileName,
@@ -649,18 +744,37 @@ async function runAssetReplace(argumentList) {
649
744
  printMutationResult(`Replaced raw file for asset "${id}" with "${fileName}".`, asset, state);
650
745
  }
651
746
  async function runAssetSet(argumentList) {
652
- const parsed = parseArguments(argumentList, { ...COMMON_FLAGS, parameters: { takesValue: true }, manifests: { takesValue: true } }, 'fundus asset set');
747
+ const parsed = parseArguments(argumentList, {
748
+ ...COMMON_FLAGS,
749
+ parameters: { takesValue: true },
750
+ manifests: { takesValue: true },
751
+ 'compression-x': { takesValue: true },
752
+ 'compression-y': { takesValue: true }
753
+ }, 'fundus asset set');
653
754
  const [id] = requirePositionals(parsed, ['<id>'], 'fundus asset set');
654
- if (parsed.flags.parameters === undefined && parsed.flags.manifests === undefined) {
655
- throw new CliUsageError('`fundus asset set` needs --parameters and/or --manifests — run `fundus asset set --help`.');
755
+ const compressionFlags = parseSliceCompressionFlags(parsed.flags, 'fundus asset set');
756
+ if (parsed.flags.parameters === undefined &&
757
+ parsed.flags.manifests === undefined &&
758
+ compressionFlags === undefined) {
759
+ throw new CliUsageError('`fundus asset set` needs --parameters and/or --manifests, or a compression flag — run `fundus asset set --help`.');
656
760
  }
657
- const parametersPatch = typeof parsed.flags.parameters === 'string'
761
+ let parametersPatch = typeof parsed.flags.parameters === 'string'
658
762
  ? parseJsonFlag('parameters', parsed.flags.parameters)
659
763
  : undefined;
660
764
  const manifests = typeof parsed.flags.manifests === 'string'
661
765
  ? parseManifestList(parsed.flags.manifests)
662
766
  : undefined;
663
767
  const operations = await createOperations();
768
+ if (compressionFlags !== undefined) {
769
+ const currentAsset = assetById(await operations.state(), id);
770
+ parametersPatch = applySliceCompressionFlags({
771
+ type: currentAsset.type,
772
+ flags: compressionFlags,
773
+ parametersPatch,
774
+ currentParameters: currentAsset.parameters,
775
+ commandPath: 'fundus asset set'
776
+ });
777
+ }
664
778
  const state = await operations.setAsset(id, { parametersPatch, manifests });
665
779
  const asset = assetById(state, id);
666
780
  if (parsed.flags.json) {
@@ -14,6 +14,8 @@ export interface ResolvedAudioPluginConfig {
14
14
  presets: Record<string, AudioPreset>;
15
15
  }
16
16
  export interface ResolvedFundusConfig {
17
+ /** Absolute host project directory containing fundus.config.ts. */
18
+ projectRoot: string;
17
19
  /** All paths absolute. */
18
20
  rawDir: string;
19
21
  proxyDir: string;
@@ -71,6 +71,7 @@ export function resolveConfig(projectRoot, value, registry = serverPluginsByType
71
71
  throw new Error('fundus.config: "import.figma.defaults.scale" must be 1, 2, 3, or 4.');
72
72
  }
73
73
  return {
74
+ projectRoot: resolve(projectRoot),
74
75
  rawDir: resolvePath(projectRoot, requiredString(value, 'rawDir')),
75
76
  proxyDir: resolvePath(projectRoot, requiredString(value, 'proxyDir')),
76
77
  library: resolvePath(projectRoot, requiredString(value, 'library')),
@@ -0,0 +1,9 @@
1
+ export type GitFileChange = 'new' | 'edited';
2
+ /** Current branch of the repository containing projectRoot; null outside Git or when detached. */
3
+ export declare function currentGitBranch(projectRoot: string): Promise<string | null>;
4
+ /**
5
+ * Raw Git file changes made since this branch diverged from the repository's
6
+ * default branch. Staged, unstaged, and untracked files are included so the
7
+ * editor updates immediately after an asset mutation, before the next commit.
8
+ */
9
+ export declare function gitFileChanges(projectRoot: string): Promise<Map<string, GitFileChange>>;
@@ -0,0 +1,121 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { resolve } from 'node:path';
3
+ import { promisify } from 'node:util';
4
+ const execFileAsync = promisify(execFile);
5
+ async function git(projectRoot, args) {
6
+ const { stdout } = await execFileAsync('git', ['-C', projectRoot, ...args], {
7
+ encoding: 'utf8'
8
+ });
9
+ return stdout;
10
+ }
11
+ /** Current branch of the repository containing projectRoot; null outside Git or when detached. */
12
+ export async function currentGitBranch(projectRoot) {
13
+ try {
14
+ return (await git(projectRoot, ['branch', '--show-current'])).trim() || null;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ async function firstExistingRef(projectRoot, refs) {
21
+ for (const ref of refs) {
22
+ try {
23
+ await git(projectRoot, ['rev-parse', '--verify', '--quiet', ref]);
24
+ return ref;
25
+ }
26
+ catch {
27
+ // Try the next conventional default-branch ref.
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+ async function defaultBranchRef(projectRoot) {
33
+ try {
34
+ const remoteHead = (await git(projectRoot, ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'])).trim();
35
+ if (remoteHead)
36
+ return remoteHead;
37
+ }
38
+ catch {
39
+ // Repositories without an origin/HEAD fall back to conventional branch names.
40
+ }
41
+ return firstExistingRef(projectRoot, [
42
+ 'refs/remotes/origin/main',
43
+ 'refs/remotes/origin/master',
44
+ 'refs/heads/main',
45
+ 'refs/heads/master'
46
+ ]);
47
+ }
48
+ function parseDiffNames(output, root) {
49
+ const changes = new Map();
50
+ const fields = output.split('\0');
51
+ for (let index = 0; index < fields.length;) {
52
+ const status = fields[index++];
53
+ if (!status)
54
+ continue;
55
+ const sourcePath = fields[index++];
56
+ if (!sourcePath)
57
+ continue;
58
+ if (status.startsWith('R') || status.startsWith('C')) {
59
+ const destinationPath = fields[index++];
60
+ if (!destinationPath)
61
+ continue;
62
+ changes.set(resolve(root, destinationPath), status.startsWith('C') ? 'new' : 'edited');
63
+ }
64
+ else if (status === 'A') {
65
+ changes.set(resolve(root, sourcePath), 'new');
66
+ }
67
+ else if (status !== 'D') {
68
+ changes.set(resolve(root, sourcePath), 'edited');
69
+ }
70
+ }
71
+ return changes;
72
+ }
73
+ /**
74
+ * Raw Git file changes made since this branch diverged from the repository's
75
+ * default branch. Staged, unstaged, and untracked files are included so the
76
+ * editor updates immediately after an asset mutation, before the next commit.
77
+ */
78
+ export async function gitFileChanges(projectRoot) {
79
+ try {
80
+ const prefixParts = (await git(projectRoot, ['rev-parse', '--show-prefix']))
81
+ .trim()
82
+ .split('/')
83
+ .filter(Boolean);
84
+ const root = resolve(projectRoot, ...prefixParts.map(() => '..'));
85
+ const defaultRef = await defaultBranchRef(projectRoot);
86
+ let changes = new Map();
87
+ if (defaultRef) {
88
+ try {
89
+ const mergeBase = (await git(projectRoot, ['merge-base', 'HEAD', defaultRef])).trim();
90
+ if (mergeBase) {
91
+ changes = parseDiffNames(await git(projectRoot, [
92
+ 'diff',
93
+ '--name-status',
94
+ '-z',
95
+ '--find-renames',
96
+ mergeBase,
97
+ '--'
98
+ ]), root);
99
+ }
100
+ }
101
+ catch {
102
+ // An unborn or unrelated branch still has useful untracked-file state.
103
+ }
104
+ }
105
+ const untracked = await git(projectRoot, [
106
+ 'ls-files',
107
+ '--others',
108
+ '--exclude-standard',
109
+ '--full-name',
110
+ '-z'
111
+ ]);
112
+ for (const path of untracked.split('\0')) {
113
+ if (path)
114
+ changes.set(resolve(root, path), 'new');
115
+ }
116
+ return changes;
117
+ }
118
+ catch {
119
+ return new Map();
120
+ }
121
+ }
@@ -77,7 +77,7 @@ export declare class LibraryStore {
77
77
  */
78
78
  replaceRawFile(id: string, options: ReplaceRawFileOptions): Promise<Library>;
79
79
  /** CAS-protected replacement used only by a repeatable import source. */
80
- replaceRawFromImportSource(id: string, bytes: Uint8Array, expected: ImportSourceExpectation, nextSource?: ImportSourceRecord): Promise<Library>;
80
+ replaceRawFromImportSource(id: string, bytes: Uint8Array, expected: ImportSourceExpectation, nextSource?: ImportSourceRecord, updateParameters?: (parameters: unknown) => unknown): Promise<Library>;
81
81
  /** Replace an asset's parameters (validated by the owning plugin). */
82
82
  updateParameters(id: string, parameters: unknown): Promise<Library>;
83
83
  /** Replace an asset's manifest membership (every name must exist). */
@@ -248,7 +248,7 @@ export class LibraryStore {
248
248
  return library;
249
249
  }
250
250
  /** CAS-protected replacement used only by a repeatable import source. */
251
- async replaceRawFromImportSource(id, bytes, expected, nextSource) {
251
+ async replaceRawFromImportSource(id, bytes, expected, nextSource, updateParameters) {
252
252
  return this.#enqueue(async () => {
253
253
  const library = await this.read();
254
254
  const record = this.#requireAsset(library, id);
@@ -272,6 +272,7 @@ export class LibraryStore {
272
272
  const backupPath = `${absolutePath}.fundus-reimport-${token}`;
273
273
  const previousHash = record.rawHash;
274
274
  const previousSource = structuredClone(record.importSource);
275
+ const previousParameters = structuredClone(record.parameters);
275
276
  let staged = false;
276
277
  let installed = false;
277
278
  try {
@@ -283,11 +284,14 @@ export class LibraryStore {
283
284
  record.rawHash = sha256Hex(bytes);
284
285
  if (nextSource)
285
286
  record.importSource = structuredClone(nextSource);
287
+ if (updateParameters)
288
+ record.parameters = updateParameters(record.parameters);
286
289
  await this.write(library);
287
290
  }
288
291
  catch (cause) {
289
292
  record.rawHash = previousHash;
290
293
  record.importSource = previousSource;
294
+ record.parameters = previousParameters;
291
295
  if (installed)
292
296
  await unlink(absolutePath).catch(() => { });
293
297
  if (staged)
@@ -5,7 +5,7 @@
5
5
  * and the CLI consume this class, so every
6
6
  * operation has exactly one implementation and there is no other save path.
7
7
  */
8
- import { join } from 'node:path';
8
+ import { join, resolve } from 'node:path';
9
9
  import { assetIdError, allDeliveredAssetIds, canonicalizeParameters, collectAllReferences, compareCodeUnits, computeLibraryMembership, folderOfRawPath, normalizeFolderPath, parentFolderPath, portableFolderPathKey, proposeAssetId, rawFileNameOfPath, typesForFileName } from '../core/index.js';
10
10
  import { LibraryStore } from './library-store.js';
11
11
  import { generateManifestModules } from './codegen.js';
@@ -16,6 +16,8 @@ import { classifyRawDirectory, verifyStableRawFile } from './raw-reconciliation.
16
16
  import { rawSafetyIssues } from './raw-safety.js';
17
17
  import { serverImporters } from './importers.js';
18
18
  import { SourceImportError } from './importers/contract.js';
19
+ import { validateFigmaSourceParameters } from './importers/figma.js';
20
+ import { currentGitBranch, gitFileChanges } from './git.js';
19
21
  /**
20
22
  * The CLI's `--parameters` merge semantics (M7): a SHALLOW merge at the top
21
23
  * level onto the current parameters — a nested object value replaces the whole
@@ -42,6 +44,11 @@ export function mergeParameterPatch(currentParameters, patch) {
42
44
  }
43
45
  return merged;
44
46
  }
47
+ function figmaSlicePixelRatio(raw, type) {
48
+ if (type !== 'slice' || raw.importSource?.importer !== 'figma')
49
+ return undefined;
50
+ return validateFigmaSourceParameters(raw.importSource.parameters).scale;
51
+ }
45
52
  export class FundusOperations {
46
53
  #config;
47
54
  #registry;
@@ -310,9 +317,17 @@ export class FundusOperations {
310
317
  if (!plugin.descriptor.accepts.includes(raw.extension)) {
311
318
  throw new SourceImportError('invalid-response', `The ${snapshot.expected.type} type does not accept ".${raw.extension}" files.`);
312
319
  }
320
+ // A missing input is a refresh of the saved source and deliberately
321
+ // preserves authored parameters. An explicit input is a reimport and
322
+ // synchronizes a Figma slice's pixel ratio to its new export scale.
323
+ const pixelRatio = snapshot.input === undefined
324
+ ? undefined
325
+ : figmaSlicePixelRatio(raw, snapshot.expected.type);
313
326
  let library;
314
327
  try {
315
- library = await this.#store.replaceRawFromImportSource(id, raw.bytes, snapshot.expected, raw.importSource);
328
+ library = await this.#store.replaceRawFromImportSource(id, raw.bytes, snapshot.expected, raw.importSource, pixelRatio === undefined
329
+ ? undefined
330
+ : (parameters) => plugin.descriptor.validateParameters(mergeParameterPatch(parameters, { pixelRatio })));
316
331
  }
317
332
  catch (cause) {
318
333
  if (cause instanceof Error && cause.message === 'stale-import') {
@@ -347,6 +362,11 @@ export class FundusOperations {
347
362
  if (seeded !== undefined)
348
363
  next = seeded;
349
364
  }
365
+ // Source scale is a default: an explicit parametersPatch below still wins.
366
+ const pixelRatio = figmaSlicePixelRatio(raw, options.type);
367
+ if (pixelRatio !== undefined) {
368
+ next = mergeParameterPatch(next, { pixelRatio });
369
+ }
350
370
  if (options.parametersPatch !== undefined) {
351
371
  next = mergeParameterPatch(next, options.parametersPatch);
352
372
  }
@@ -642,6 +662,10 @@ export class FundusOperations {
642
662
  };
643
663
  }
644
664
  async #buildState(library, issues, classification) {
665
+ const [gitBranch, changedGitFiles] = await Promise.all([
666
+ currentGitBranch(this.#config.projectRoot),
667
+ gitFileChanges(this.#config.projectRoot)
668
+ ]);
645
669
  const referencesByAsset = collectAllReferences(library, descriptorsByType(this.#registry));
646
670
  const membershipByManifest = computeLibraryMembership(library, referencesByAsset);
647
671
  const delivered = allDeliveredAssetIds(membershipByManifest);
@@ -706,6 +730,7 @@ export class FundusOperations {
706
730
  folder: folderOfRawPath(record.raw),
707
731
  rawUrl: `/files/raw/${encodeRelativePathForUrl(record.raw)}?v=${record.rawHash.slice(0, 12)}`,
708
732
  rawHash: record.rawHash,
733
+ gitStatus: changedGitFiles.get(resolve(this.#config.rawDir, record.raw)) ?? null,
709
734
  importSource: record.importSource,
710
735
  parameters: record.parameters,
711
736
  manifests: record.manifests,
@@ -747,6 +772,7 @@ export class FundusOperations {
747
772
  }
748
773
  const rawIngestionQueue = this.#buildRawIngestionQueue(library, classification);
749
774
  return {
775
+ gitBranch,
750
776
  library,
751
777
  assets,
752
778
  importDefaults: { figma: { scale: this.#config.import.figma.defaults.scale } },
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Slice plugin (server part): the same sharp conversion as the image plugin,
3
- * never resized insets are authored in source pixels, so the delivered proxy
4
- * keeps the source dimensions. The slicing data is entry-only.
3
+ * fixed caps keep their source-pixel size, while optional compression removes
4
+ * redundant pixels from the stretchable regions. The slicing data itself is
5
+ * entry-only.
5
6
  */
6
7
  import { type ImagePreset, type SliceParameters } from '../../core/index.js';
7
8
  import { type ServerAssetTypePlugin, type ServerPluginConfigDefinition } from './contract.js';
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Slice plugin (server part): the same sharp conversion as the image plugin,
3
- * never resized insets are authored in source pixels, so the delivered proxy
4
- * keeps the source dimensions. The slicing data is entry-only.
3
+ * fixed caps keep their source-pixel size, while optional compression removes
4
+ * redundant pixels from the stretchable regions. The slicing data itself is
5
+ * entry-only.
5
6
  */
6
- import { SLICE_BUILT_IN_PRESETS, defaultInsetsForSize, slicePlugin, validateImagePreset } from '../../core/index.js';
7
- import { processImageFile, readImageDimensions } from '../processing/image-processing.js';
7
+ import { SLICE_BUILT_IN_PRESETS, defaultInsetsForSize, processedSliceInsets, slicePlugin, validateImagePreset } from '../../core/index.js';
8
+ import { readImageDimensions } from '../processing/image-processing.js';
9
+ import { processSliceImageFile } from '../processing/slice-processing.js';
8
10
  import { extensionForImageFormat } from './image.js';
9
11
  import { mergePresets } from './config.js';
10
12
  import { requireProxyField, resolveNamedPreset } from './contract.js';
@@ -51,16 +53,26 @@ export const sliceServerPlugin = {
51
53
  pixelRatio: detectPixelRatio(rawFileName)
52
54
  };
53
55
  },
54
- process: (job) => processImageFile({
56
+ process: (job) => processSliceImageFile({
55
57
  sourcePath: job.sourcePath,
56
58
  targetPath: job.targetPath,
57
- preset: job.preset
59
+ preset: job.preset,
60
+ mode: job.parameters.mode,
61
+ insets: job.parameters.insets,
62
+ overdraw: job.parameters.overdraw,
63
+ compression: job.parameters.compression
58
64
  }),
59
65
  readProxyInfo: (proxyPath) => readImageDimensions(proxyPath),
60
66
  buildManifestEntry: ({ parameters, src, proxy }) => {
67
+ const sourceWidth = requireProxyField(proxy, 'width');
68
+ const sourceHeight = requireProxyField(proxy, 'height');
61
69
  const slicing = {
62
70
  mode: parameters.mode,
63
- insets: parameters.insets,
71
+ insets: processedSliceInsets({
72
+ ...parameters,
73
+ width: sourceWidth,
74
+ height: sourceHeight
75
+ }),
64
76
  pixelRatio: parameters.pixelRatio,
65
77
  // An all-zero overdraw is semantically "none" — keep the entry minimal.
66
78
  ...(hasAnySide(parameters.overdraw) ? { overdraw: parameters.overdraw } : {})
@@ -69,8 +81,8 @@ export const sliceServerPlugin = {
69
81
  kind: 'slice',
70
82
  src,
71
83
  slicing,
72
- sourceWidth: requireProxyField(proxy, 'width'),
73
- sourceHeight: requireProxyField(proxy, 'height')
84
+ sourceWidth,
85
+ sourceHeight
74
86
  };
75
87
  }
76
88
  };
@@ -0,0 +1,14 @@
1
+ import { type ImagePreset, type SliceCompression, type SliceInsets, type SliceMode } from '../../core/index.js';
2
+ import { type ImageProcessingOutput } from './image-processing.js';
3
+ /** The length after percentage-based compression, with one stretch pixel kept. */
4
+ export declare function compressedStretchSize(size: number, compression: number): number;
5
+ export declare function assertSliceCompressionDimensions(width: number, height: number): void;
6
+ export declare function processSliceImageFile(options: {
7
+ sourcePath: string;
8
+ targetPath: string;
9
+ preset: ImagePreset;
10
+ mode: SliceMode;
11
+ insets: SliceInsets;
12
+ overdraw?: SliceInsets;
13
+ compression?: SliceCompression;
14
+ }): Promise<ImageProcessingOutput>;