canopycms 0.0.68-int.98 → 0.1.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 (688) hide show
  1. package/CHANGELOG.md +2131 -0
  2. package/README.md +47 -63
  3. package/dist/ai/generate.d.ts +5 -0
  4. package/dist/ai/generate.js +244 -115
  5. package/dist/ai/index.d.ts +1 -1
  6. package/dist/ai/json-to-markdown.d.ts +21 -1
  7. package/dist/ai/json-to-markdown.js +120 -57
  8. package/dist/ai/references.d.ts +72 -0
  9. package/dist/ai/references.js +223 -0
  10. package/dist/ai/resolve-branch.js +9 -2
  11. package/dist/ai/to-plain-text.d.ts +17 -8
  12. package/dist/ai/to-plain-text.js +18 -15
  13. package/dist/ai/types.d.ts +84 -3
  14. package/dist/api/admin-branch-health.d.ts +24 -1
  15. package/dist/api/admin-branch-health.js +52 -20
  16. package/dist/api/admin.d.ts +23 -5
  17. package/dist/api/admin.js +36 -1
  18. package/dist/api/assets.js +88 -78
  19. package/dist/api/branch-create-window.d.ts +12 -0
  20. package/dist/api/branch-create-window.js +13 -0
  21. package/dist/api/branch-merge.d.ts +1 -1
  22. package/dist/api/branch-merge.js +1 -1
  23. package/dist/api/branch-review.d.ts +3 -3
  24. package/dist/api/branch-review.js +16 -7
  25. package/dist/api/branch-status.d.ts +16 -6
  26. package/dist/api/branch-status.js +57 -12
  27. package/dist/api/branch-withdraw.d.ts +2 -2
  28. package/dist/api/branch-withdraw.js +8 -3
  29. package/dist/api/branch.d.ts +25 -12
  30. package/dist/api/branch.js +164 -103
  31. package/dist/api/client.d.ts +78 -58
  32. package/dist/api/client.js +150 -117
  33. package/dist/api/comments.d.ts +12 -3
  34. package/dist/api/comments.js +118 -9
  35. package/dist/api/content.d.ts +9 -9
  36. package/dist/api/content.js +131 -22
  37. package/dist/api/entries-constants.d.ts +14 -3
  38. package/dist/api/entries-constants.js +14 -3
  39. package/dist/api/entries.d.ts +40 -2
  40. package/dist/api/entries.js +102 -6
  41. package/dist/api/github-sync.d.ts +19 -0
  42. package/dist/api/github-sync.js +50 -3
  43. package/dist/api/groups.d.ts +4 -4
  44. package/dist/api/groups.js +2 -1
  45. package/dist/api/guards.js +23 -3
  46. package/dist/api/index.d.ts +3 -1
  47. package/dist/api/index.js +1 -0
  48. package/dist/api/permissions.d.ts +21 -2
  49. package/dist/api/permissions.js +50 -3
  50. package/dist/api/request-deadline.d.ts +59 -0
  51. package/dist/api/request-deadline.js +73 -0
  52. package/dist/api/resolve-references.js +8 -7
  53. package/dist/api/route-builder.d.ts +14 -0
  54. package/dist/api/route-builder.js +14 -1
  55. package/dist/api/schema.d.ts +11 -9
  56. package/dist/api/schema.js +2 -0
  57. package/dist/api/settings-helpers.d.ts +5 -1
  58. package/dist/api/settings-helpers.js +10 -2
  59. package/dist/api/types.d.ts +18 -0
  60. package/dist/api/users-constants.d.ts +6 -0
  61. package/dist/api/users-constants.js +6 -0
  62. package/dist/assets/asset-url.d.ts +28 -16
  63. package/dist/assets/asset-url.js +51 -25
  64. package/dist/assets/finalize.js +3 -0
  65. package/dist/assets/index.d.ts +1 -1
  66. package/dist/assets/materialize.d.ts +153 -0
  67. package/dist/assets/materialize.js +402 -0
  68. package/dist/assets/store-local.d.ts +19 -5
  69. package/dist/assets/store-local.js +69 -10
  70. package/dist/assets/store-s3.d.ts +38 -7
  71. package/dist/assets/store-s3.js +128 -22
  72. package/dist/assets/transform-directives.d.ts +52 -13
  73. package/dist/assets/transform-directives.js +87 -27
  74. package/dist/assets/transform.d.ts +3 -3
  75. package/dist/assets/transform.js +13 -8
  76. package/dist/assets/types.d.ts +31 -4
  77. package/dist/auth/cache.d.ts +1 -1
  78. package/dist/auth/cache.js +1 -1
  79. package/dist/auth/caching-auth-plugin.d.ts +2 -0
  80. package/dist/auth/caching-auth-plugin.js +12 -2
  81. package/dist/auth/file-based-auth-cache.d.ts +8 -0
  82. package/dist/auth/file-based-auth-cache.js +18 -8
  83. package/dist/auth/person-name.d.ts +5 -0
  84. package/dist/auth/person-name.js +8 -0
  85. package/dist/auth/plugin.d.ts +10 -1
  86. package/dist/auth/types.d.ts +2 -0
  87. package/dist/auth/user-metadata-lookup.d.ts +21 -0
  88. package/dist/auth/user-metadata-lookup.js +116 -0
  89. package/dist/authorization/branch.d.ts +1 -1
  90. package/dist/authorization/branch.js +12 -13
  91. package/dist/authorization/groups/schema.d.ts +4 -4
  92. package/dist/authorization/helpers.d.ts +8 -0
  93. package/dist/authorization/helpers.js +8 -0
  94. package/dist/authorization/index.d.ts +1 -1
  95. package/dist/authorization/index.js +1 -1
  96. package/dist/authorization/protected-branch.d.ts +5 -4
  97. package/dist/authorization/protected-branch.js +7 -5
  98. package/dist/branch-health.d.ts +35 -8
  99. package/dist/branch-health.js +54 -18
  100. package/dist/branch-metadata-error.d.ts +27 -0
  101. package/dist/branch-metadata-error.js +23 -0
  102. package/dist/branch-metadata-file.d.ts +205 -24
  103. package/dist/branch-metadata-file.js +126 -25
  104. package/dist/branch-metadata.d.ts +45 -6
  105. package/dist/branch-metadata.js +142 -50
  106. package/dist/branch-provisioning.d.ts +167 -0
  107. package/dist/branch-provisioning.js +501 -0
  108. package/dist/branch-registry.d.ts +8 -0
  109. package/dist/branch-registry.js +61 -9
  110. package/dist/branch-schema-cache.d.ts +29 -12
  111. package/dist/branch-schema-cache.js +64 -21
  112. package/dist/branch-sparse.d.ts +23 -0
  113. package/dist/branch-sparse.js +118 -0
  114. package/dist/branch-workspace.d.ts +42 -3
  115. package/dist/branch-workspace.js +239 -100
  116. package/dist/build/asset-refs.d.ts +94 -0
  117. package/dist/build/asset-refs.js +267 -0
  118. package/dist/build/generate-ai-content.js +5 -0
  119. package/dist/build/inline-flight.d.ts +37 -0
  120. package/dist/build/inline-flight.js +142 -0
  121. package/dist/cli/asset-refs.d.ts +52 -0
  122. package/dist/cli/asset-refs.js +194 -0
  123. package/dist/cli/cli.d.ts +15 -1
  124. package/dist/cli/cli.js +8543 -3193
  125. package/dist/cli/configured-asset-store.d.ts +12 -0
  126. package/dist/cli/configured-asset-store.js +46 -0
  127. package/dist/cli/generate-ai-content.js +4244 -1072
  128. package/dist/cli/init.js +217 -126
  129. package/dist/cli/project-detect.d.ts +2 -0
  130. package/dist/cli/project-detect.js +2 -0
  131. package/dist/cli/template-files/Dockerfile.cms.template +13 -5
  132. package/dist/cli/template-files/cms-stack.ts.template +16 -13
  133. package/dist/client.d.ts +1 -2
  134. package/dist/client.js +1 -2
  135. package/dist/comment-store.d.ts +25 -0
  136. package/dist/comment-store.js +43 -8
  137. package/dist/config/flatten.js +2 -0
  138. package/dist/config/helpers.js +2 -2
  139. package/dist/config/index.d.ts +1 -1
  140. package/dist/config/schemas/config.d.ts +12 -29
  141. package/dist/config/schemas/config.js +9 -12
  142. package/dist/config/schemas/field.d.ts +3 -0
  143. package/dist/config/schemas/field.js +58 -4
  144. package/dist/config/schemas/media.d.ts +4 -13
  145. package/dist/config/schemas/media.js +5 -8
  146. package/dist/config/schemas/url.d.ts +2 -20
  147. package/dist/config/schemas/url.js +2 -25
  148. package/dist/config/types.d.ts +116 -22
  149. package/dist/config/types.js +3 -9
  150. package/dist/config/validation.d.ts +25 -4
  151. package/dist/config/validation.js +116 -3
  152. package/dist/content-id-index.js +2 -2
  153. package/dist/content-index-generation.d.ts +1 -1
  154. package/dist/content-index-generation.js +1 -1
  155. package/dist/content-listing.d.ts +10 -1
  156. package/dist/content-listing.js +22 -5
  157. package/dist/content-reader.d.ts +9 -0
  158. package/dist/content-reader.js +16 -11
  159. package/dist/content-store.d.ts +75 -12
  160. package/dist/content-store.js +249 -86
  161. package/dist/content-tree.js +2 -2
  162. package/dist/context.js +5 -2
  163. package/dist/dangling-reference-log.d.ts +17 -0
  164. package/dist/dangling-reference-log.js +29 -0
  165. package/dist/dev-content-watcher.d.ts +1 -1
  166. package/dist/dev-content-watcher.js +1 -1
  167. package/dist/editor/BranchManager.d.ts +23 -7
  168. package/dist/editor/BranchManager.js +119 -54
  169. package/dist/editor/CanopyEditor.d.ts +1 -1
  170. package/dist/editor/CanopyEditor.js +1 -2
  171. package/dist/editor/CommentsPanel.d.ts +14 -0
  172. package/dist/editor/CommentsPanel.js +68 -43
  173. package/dist/editor/Editor.d.ts +11 -5
  174. package/dist/editor/Editor.js +891 -218
  175. package/dist/editor/EditorAuthGate.d.ts +7 -1
  176. package/dist/editor/EditorAuthGate.js +41 -9
  177. package/dist/editor/EntryNavigator.d.ts +22 -0
  178. package/dist/editor/EntryNavigator.js +353 -105
  179. package/dist/editor/FormHeader.d.ts +25 -0
  180. package/dist/editor/FormHeader.js +82 -0
  181. package/dist/editor/FormRenderer.d.ts +27 -3
  182. package/dist/editor/FormRenderer.js +171 -76
  183. package/dist/editor/PreviewFrame.d.ts +40 -0
  184. package/dist/editor/PreviewFrame.js +215 -0
  185. package/dist/editor/PreviewPane.d.ts +47 -0
  186. package/dist/editor/PreviewPane.js +147 -0
  187. package/dist/editor/PreviewToolbarTools.d.ts +22 -0
  188. package/dist/editor/PreviewToolbarTools.js +73 -0
  189. package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
  190. package/dist/editor/admin/SystemHealthPanel.js +163 -33
  191. package/dist/editor/admin/useSystemHealth.d.ts +18 -0
  192. package/dist/editor/admin/useSystemHealth.js +70 -1
  193. package/dist/editor/branch-status.d.ts +17 -0
  194. package/dist/editor/branch-status.js +29 -0
  195. package/dist/editor/canopy-path.d.ts +9 -6
  196. package/dist/editor/canopy-path.js +8 -11
  197. package/dist/editor/client-reference-resolver.d.ts +43 -16
  198. package/dist/editor/client-reference-resolver.js +155 -64
  199. package/dist/editor/comments/BranchComments.d.ts +1 -1
  200. package/dist/editor/comments/BranchComments.js +2 -2
  201. package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
  202. package/dist/editor/comments/CloseRefusedNotice.js +7 -0
  203. package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
  204. package/dist/editor/comments/CommentThreadsPopover.js +274 -0
  205. package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
  206. package/dist/editor/comments/CommentWriteAlert.js +13 -0
  207. package/dist/editor/comments/EntryComments.d.ts +10 -4
  208. package/dist/editor/comments/EntryComments.js +14 -17
  209. package/dist/editor/comments/FieldWrapper.d.ts +18 -4
  210. package/dist/editor/comments/FieldWrapper.js +62 -28
  211. package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
  212. package/dist/editor/comments/InlineCommentThread.js +11 -47
  213. package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
  214. package/dist/editor/comments/ThreadCarousel.js +18 -21
  215. package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
  216. package/dist/editor/comments/ThreadReplyControls.js +92 -0
  217. package/dist/editor/comments/field-comment-context.d.ts +14 -0
  218. package/dist/editor/comments/field-comment-context.js +14 -0
  219. package/dist/editor/comments/form-comments.d.ts +48 -0
  220. package/dist/editor/comments/form-comments.js +178 -0
  221. package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
  222. package/dist/editor/comments/item-anchor-copy.js +6 -0
  223. package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
  224. package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
  225. package/dist/editor/comments/popover-placement.d.ts +18 -0
  226. package/dist/editor/comments/popover-placement.js +58 -0
  227. package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
  228. package/dist/editor/comments/use-tracked-writes.js +53 -0
  229. package/dist/editor/components/BranchAccessList.d.ts +15 -0
  230. package/dist/editor/components/BranchAccessList.js +52 -0
  231. package/dist/editor/components/BranchLockBanner.d.ts +22 -0
  232. package/dist/editor/components/BranchLockBanner.js +39 -0
  233. package/dist/editor/components/BranchPill.d.ts +32 -0
  234. package/dist/editor/components/BranchPill.js +33 -0
  235. package/dist/editor/components/BranchesDrawer.d.ts +11 -0
  236. package/dist/editor/components/BranchesDrawer.js +5 -0
  237. package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
  238. package/dist/editor/components/ConfirmDeleteModal.js +3 -2
  239. package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
  240. package/dist/editor/components/DestructiveMenuItem.js +8 -0
  241. package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
  242. package/dist/editor/components/EditorCrashScreen.js +22 -0
  243. package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
  244. package/dist/editor/components/EditorErrorBoundary.js +40 -0
  245. package/dist/editor/components/EditorHeader.d.ts +56 -106
  246. package/dist/editor/components/EditorHeader.js +130 -131
  247. package/dist/editor/components/EditorRail.d.ts +49 -0
  248. package/dist/editor/components/EditorRail.js +65 -0
  249. package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
  250. package/dist/editor/components/EntryBreadcrumb.js +56 -0
  251. package/dist/editor/components/EntryCreateModal.d.ts +12 -7
  252. package/dist/editor/components/EntryCreateModal.js +51 -57
  253. package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
  254. package/dist/editor/components/NoEditPermissionNotice.js +5 -4
  255. package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
  256. package/dist/editor/components/QuickOpenPalette.js +66 -0
  257. package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
  258. package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
  259. package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
  260. package/dist/editor/components/ReasonedMenuItem.js +15 -0
  261. package/dist/editor/components/ReferencedByList.d.ts +11 -0
  262. package/dist/editor/components/ReferencedByList.js +28 -0
  263. package/dist/editor/components/RelativeTime.d.ts +10 -0
  264. package/dist/editor/components/RelativeTime.js +10 -0
  265. package/dist/editor/components/RenameEntryModal.d.ts +9 -1
  266. package/dist/editor/components/RenameEntryModal.js +19 -31
  267. package/dist/editor/components/RetryToastMessage.d.ts +9 -0
  268. package/dist/editor/components/RetryToastMessage.js +6 -0
  269. package/dist/editor/components/SaveAllResult.d.ts +25 -0
  270. package/dist/editor/components/SaveAllResult.js +86 -0
  271. package/dist/editor/components/SaveSplitButton.d.ts +30 -0
  272. package/dist/editor/components/SaveSplitButton.js +108 -0
  273. package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
  274. package/dist/editor/components/StagedChangesDrawer.js +92 -0
  275. package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
  276. package/dist/editor/components/UnavailableEntryNotice.js +9 -0
  277. package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
  278. package/dist/editor/components/UnavailableTypeMessage.js +9 -0
  279. package/dist/editor/components/UndoToastMessage.d.ts +18 -0
  280. package/dist/editor/components/UndoToastMessage.js +10 -0
  281. package/dist/editor/components/UserBadge.d.ts +2 -5
  282. package/dist/editor/components/UserBadge.js +62 -33
  283. package/dist/editor/components/ValidationSummary.d.ts +14 -0
  284. package/dist/editor/components/ValidationSummary.js +24 -0
  285. package/dist/editor/components/index.d.ts +2 -2
  286. package/dist/editor/components/index.js +2 -2
  287. package/dist/editor/context/ApiClientContext.d.ts +8 -2
  288. package/dist/editor/context/ApiClientContext.js +19 -8
  289. package/dist/editor/context/AssetContext.d.ts +13 -35
  290. package/dist/editor/context/AssetContext.js +12 -31
  291. package/dist/editor/context/EditorStateContext.d.ts +4 -4
  292. package/dist/editor/context/EditorStateContext.js +4 -4
  293. package/dist/editor/context/SWRProvider.d.ts +3 -3
  294. package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
  295. package/dist/editor/context/SiteMdxAllowContext.js +7 -0
  296. package/dist/editor/context/index.d.ts +2 -1
  297. package/dist/editor/context/index.js +2 -1
  298. package/dist/editor/contrast.d.ts +19 -0
  299. package/dist/editor/contrast.js +41 -0
  300. package/dist/editor/copy.d.ts +18 -0
  301. package/dist/editor/copy.js +18 -0
  302. package/dist/editor/editor-config.js +16 -0
  303. package/dist/editor/editor-utils.d.ts +34 -8
  304. package/dist/editor/editor-utils.js +42 -20
  305. package/dist/editor/entry-search.d.ts +20 -0
  306. package/dist/editor/entry-search.js +34 -0
  307. package/dist/editor/field-breadcrumb.d.ts +12 -0
  308. package/dist/editor/field-breadcrumb.js +85 -0
  309. package/dist/editor/field-props.d.ts +86 -0
  310. package/dist/editor/field-props.js +27 -0
  311. package/dist/editor/field-target.d.ts +30 -0
  312. package/dist/editor/field-target.js +77 -0
  313. package/dist/editor/fields/BlockField.d.ts +12 -0
  314. package/dist/editor/fields/BlockField.js +89 -73
  315. package/dist/editor/fields/CodeField.d.ts +2 -0
  316. package/dist/editor/fields/CodeField.js +6 -2
  317. package/dist/editor/fields/DateTimeField.d.ts +4 -29
  318. package/dist/editor/fields/DateTimeField.js +79 -41
  319. package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
  320. package/dist/editor/fields/ExpandAllButton.js +4 -0
  321. package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
  322. package/dist/editor/fields/FieldCrashFallback.js +30 -0
  323. package/dist/editor/fields/FieldLabel.d.ts +37 -0
  324. package/dist/editor/fields/FieldLabel.js +19 -0
  325. package/dist/editor/fields/ImageField.d.ts +4 -0
  326. package/dist/editor/fields/ImageField.js +29 -14
  327. package/dist/editor/fields/InlineGroupField.js +4 -3
  328. package/dist/editor/fields/ItemList.d.ts +42 -0
  329. package/dist/editor/fields/ItemList.js +130 -0
  330. package/dist/editor/fields/MarkdownField.d.ts +32 -0
  331. package/dist/editor/fields/MarkdownField.js +223 -46
  332. package/dist/editor/fields/MdxImageDialog.js +1 -1
  333. package/dist/editor/fields/NumberField.d.ts +2 -0
  334. package/dist/editor/fields/NumberField.js +8 -5
  335. package/dist/editor/fields/NumberListField.d.ts +2 -0
  336. package/dist/editor/fields/NumberListField.js +19 -16
  337. package/dist/editor/fields/ObjectField.d.ts +2 -7
  338. package/dist/editor/fields/ObjectField.js +15 -5
  339. package/dist/editor/fields/ObjectListField.d.ts +29 -0
  340. package/dist/editor/fields/ObjectListField.js +57 -0
  341. package/dist/editor/fields/ReferenceField.d.ts +2 -0
  342. package/dist/editor/fields/ReferenceField.js +34 -9
  343. package/dist/editor/fields/SelectField.d.ts +2 -0
  344. package/dist/editor/fields/SelectField.js +11 -2
  345. package/dist/editor/fields/StringListField.d.ts +4 -1
  346. package/dist/editor/fields/StringListField.js +22 -8
  347. package/dist/editor/fields/TextField.d.ts +2 -0
  348. package/dist/editor/fields/TextField.js +6 -2
  349. package/dist/editor/fields/ToggleField.d.ts +2 -0
  350. package/dist/editor/fields/ToggleField.js +8 -3
  351. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
  352. package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
  353. package/dist/editor/fields/form-expansion.d.ts +9 -0
  354. package/dist/editor/fields/form-expansion.js +2 -0
  355. package/dist/editor/fields/item-expansion.d.ts +15 -0
  356. package/dist/editor/fields/item-expansion.js +60 -0
  357. package/dist/editor/fields/list-item-keys.d.ts +8 -0
  358. package/dist/editor/fields/list-item-keys.js +50 -0
  359. package/dist/editor/fields/list-item-title.d.ts +20 -0
  360. package/dist/editor/fields/list-item-title.js +85 -0
  361. package/dist/editor/fields/markdown-export-options.d.ts +2 -0
  362. package/dist/editor/fields/markdown-export-options.js +8 -0
  363. package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
  364. package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
  365. package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
  366. package/dist/editor/fields/mdx-jsx-support.js +157 -69
  367. package/dist/editor/fields/rich-text-failures.d.ts +5 -0
  368. package/dist/editor/fields/rich-text-failures.js +26 -0
  369. package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
  370. package/dist/editor/fields/toolbar-wrap.js +35 -0
  371. package/dist/editor/form-outline.d.ts +13 -0
  372. package/dist/editor/form-outline.js +70 -0
  373. package/dist/editor/group-manager/GroupCard.d.ts +4 -1
  374. package/dist/editor/group-manager/GroupCard.js +12 -3
  375. package/dist/editor/group-manager/GroupForm.js +1 -1
  376. package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
  377. package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
  378. package/dist/editor/group-manager/MemberList.d.ts +2 -1
  379. package/dist/editor/group-manager/MemberList.js +15 -4
  380. package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
  381. package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
  382. package/dist/editor/group-manager/index.js +34 -5
  383. package/dist/editor/group-manager/types.d.ts +5 -2
  384. package/dist/editor/hooks/create-branch-request.d.ts +20 -0
  385. package/dist/editor/hooks/create-branch-request.js +54 -0
  386. package/dist/editor/hooks/save-all.d.ts +68 -0
  387. package/dist/editor/hooks/save-all.js +61 -0
  388. package/dist/editor/hooks/useBranchActions.d.ts +11 -1
  389. package/dist/editor/hooks/useBranchActions.js +42 -19
  390. package/dist/editor/hooks/useBranchManager.d.ts +21 -0
  391. package/dist/editor/hooks/useBranchManager.js +321 -125
  392. package/dist/editor/hooks/useBranchesData.d.ts +8 -4
  393. package/dist/editor/hooks/useBranchesData.js +9 -5
  394. package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
  395. package/dist/editor/hooks/useCommentSystem.js +79 -55
  396. package/dist/editor/hooks/useCommentsData.d.ts +11 -7
  397. package/dist/editor/hooks/useCommentsData.js +20 -19
  398. package/dist/editor/hooks/useDraftManager.d.ts +77 -3
  399. package/dist/editor/hooks/useDraftManager.js +887 -94
  400. package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
  401. package/dist/editor/hooks/useEditorLayout.js +98 -20
  402. package/dist/editor/hooks/useEntriesData.d.ts +2 -1
  403. package/dist/editor/hooks/useEntriesData.js +18 -4
  404. package/dist/editor/hooks/useEntryManager.d.ts +41 -2
  405. package/dist/editor/hooks/useEntryManager.js +227 -41
  406. package/dist/editor/hooks/useGroupManager.js +13 -16
  407. package/dist/editor/hooks/usePermissionManager.js +14 -6
  408. package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
  409. package/dist/editor/hooks/usePreviewMarks.js +33 -0
  410. package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
  411. package/dist/editor/hooks/useReferenceResolution.js +34 -177
  412. package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
  413. package/dist/editor/hooks/useSchemaManager.js +97 -39
  414. package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
  415. package/dist/editor/hooks/useUserMetadata.js +76 -47
  416. package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
  417. package/dist/editor/hooks/user-metadata-batcher.js +33 -0
  418. package/dist/editor/media/AssetCard.d.ts +6 -7
  419. package/dist/editor/media/AssetCard.js +24 -31
  420. package/dist/editor/media/AssetListRow.d.ts +16 -0
  421. package/dist/editor/media/AssetListRow.js +41 -0
  422. package/dist/editor/media/CropStep.js +6 -1
  423. package/dist/editor/media/MediaLibrary.d.ts +4 -3
  424. package/dist/editor/media/MediaLibrary.js +11 -4
  425. package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
  426. package/dist/editor/media/MediaLibraryBody.js +195 -80
  427. package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
  428. package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
  429. package/dist/editor/media/crop-math.d.ts +3 -4
  430. package/dist/editor/media/crop-math.js +11 -22
  431. package/dist/editor/media/editor-image-src.d.ts +8 -0
  432. package/dist/editor/media/editor-image-src.js +10 -0
  433. package/dist/editor/media/format-bytes.d.ts +2 -0
  434. package/dist/editor/media/format-bytes.js +23 -0
  435. package/dist/editor/media/media-library-prefs.d.ts +23 -0
  436. package/dist/editor/media/media-library-prefs.js +49 -0
  437. package/dist/editor/media/media-library-view.d.ts +34 -0
  438. package/dist/editor/media/media-library-view.js +40 -0
  439. package/dist/editor/media/useAssetLibrary.d.ts +30 -0
  440. package/dist/editor/media/useAssetLibrary.js +126 -0
  441. package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
  442. package/dist/editor/media/useStableAssetOrder.js +37 -0
  443. package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
  444. package/dist/editor/media/useThumbnailFailure.js +16 -0
  445. package/dist/editor/permission-manager/GroupSelector.js +2 -2
  446. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
  447. package/dist/editor/permission-manager/PermissionEditor.js +15 -4
  448. package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
  449. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
  450. package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
  451. package/dist/editor/permission-manager/UserSelector.js +3 -3
  452. package/dist/editor/permission-manager/index.js +12 -3
  453. package/dist/editor/permission-manager/types.d.ts +5 -2
  454. package/dist/editor/platform.d.ts +3 -0
  455. package/dist/editor/platform.js +9 -0
  456. package/dist/editor/preview-asset-base.d.ts +9 -0
  457. package/dist/editor/preview-asset-base.js +17 -0
  458. package/dist/editor/preview-bridge.d.ts +51 -27
  459. package/dist/editor/preview-bridge.js +103 -144
  460. package/dist/editor/preview-marks.d.ts +15 -0
  461. package/dist/editor/preview-marks.js +74 -0
  462. package/dist/editor/preview-path.d.ts +12 -0
  463. package/dist/editor/preview-path.js +45 -1
  464. package/dist/editor/preview-scale.d.ts +27 -0
  465. package/dist/editor/preview-scale.js +34 -0
  466. package/dist/editor/raw-asset-base.d.ts +5 -0
  467. package/dist/editor/raw-asset-base.js +14 -0
  468. package/dist/editor/relative-time.d.ts +4 -4
  469. package/dist/editor/relative-time.js +16 -8
  470. package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
  471. package/dist/editor/schema-editor/CollectionEditor.js +361 -62
  472. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
  473. package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
  474. package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
  475. package/dist/editor/schema-editor/collection-draft.js +40 -0
  476. package/dist/editor/schema-editor/index.d.ts +1 -1
  477. package/dist/editor/schema-label.d.ts +10 -0
  478. package/dist/editor/schema-label.js +17 -0
  479. package/dist/editor/settings-conflict.d.ts +5 -0
  480. package/dist/editor/settings-conflict.js +8 -0
  481. package/dist/editor/shell/ActivityRail.d.ts +37 -0
  482. package/dist/editor/shell/ActivityRail.js +91 -0
  483. package/dist/editor/shell/EditorShell.d.ts +17 -0
  484. package/dist/editor/shell/EditorShell.js +31 -0
  485. package/dist/editor/shell/PaneLayout.d.ts +28 -0
  486. package/dist/editor/shell/PaneLayout.js +116 -0
  487. package/dist/editor/shell/SidePanelHost.d.ts +35 -0
  488. package/dist/editor/shell/SidePanelHost.js +184 -0
  489. package/dist/editor/shell/TopBar.d.ts +12 -0
  490. package/dist/editor/shell/TopBar.js +14 -0
  491. package/dist/editor/shell/host-chrome.d.ts +16 -0
  492. package/dist/editor/shell/host-chrome.js +69 -0
  493. package/dist/editor/slug.d.ts +16 -0
  494. package/dist/editor/slug.js +43 -0
  495. package/dist/editor/theme.d.ts +2 -1
  496. package/dist/editor/theme.js +314 -13
  497. package/dist/editor/unanswered.d.ts +17 -0
  498. package/dist/editor/unanswered.js +26 -0
  499. package/dist/editor/unavailable-entry-type.d.ts +20 -0
  500. package/dist/editor/unavailable-entry-type.js +28 -0
  501. package/dist/editor/undo-removal.d.ts +57 -0
  502. package/dist/editor/undo-removal.js +163 -0
  503. package/dist/editor/user-display.d.ts +4 -0
  504. package/dist/editor/user-display.js +5 -0
  505. package/dist/editor/utils/confirm-modal.d.ts +8 -0
  506. package/dist/editor/utils/confirm-modal.js +12 -0
  507. package/dist/editor/utils/editor-errors.d.ts +19 -0
  508. package/dist/editor/utils/editor-errors.js +32 -0
  509. package/dist/editor/utils/focus-return.d.ts +56 -0
  510. package/dist/editor/utils/focus-return.js +106 -0
  511. package/dist/entry-link-resolver.d.ts +11 -1
  512. package/dist/entry-link-resolver.js +65 -5
  513. package/dist/entry-schema-registry.d.ts +3 -3
  514. package/dist/entry-schema-registry.js +7 -4
  515. package/dist/entry-schema.d.ts +49 -3
  516. package/dist/entry-schema.js +18 -0
  517. package/dist/git-manager.d.ts +172 -10
  518. package/dist/git-manager.js +449 -107
  519. package/dist/github-service.d.ts +39 -2
  520. package/dist/github-service.js +101 -7
  521. package/dist/http/handler.js +74 -9
  522. package/dist/http/types.d.ts +2 -0
  523. package/dist/http/worker-not-ready.d.ts +9 -4
  524. package/dist/http/worker-not-ready.js +59 -6
  525. package/dist/index.d.ts +2 -0
  526. package/dist/index.js +3 -0
  527. package/dist/item-keys.d.ts +46 -0
  528. package/dist/item-keys.js +235 -0
  529. package/dist/operating-mode/editor-mode-check.d.ts +15 -0
  530. package/dist/operating-mode/editor-mode-check.js +24 -0
  531. package/dist/operating-mode/mode-env.d.ts +13 -14
  532. package/dist/operating-mode/mode-env.js +13 -14
  533. package/dist/operating-mode/types.d.ts +2 -2
  534. package/dist/paths/branch.d.ts +0 -1
  535. package/dist/paths/branch.js +1 -8
  536. package/dist/paths/index.d.ts +1 -1
  537. package/dist/paths/index.js +1 -1
  538. package/dist/paths/validation.js +0 -2
  539. package/dist/preview.d.ts +8 -0
  540. package/dist/preview.js +7 -0
  541. package/dist/reference-resolver.js +1 -0
  542. package/dist/resolve-canopy-user.d.ts +1 -1
  543. package/dist/resolve-canopy-user.js +1 -1
  544. package/dist/schema/meta-loader.d.ts +18 -8
  545. package/dist/schema/meta-loader.js +42 -9
  546. package/dist/schema/registry-fingerprint.d.ts +14 -0
  547. package/dist/schema/registry-fingerprint.js +63 -0
  548. package/dist/schema/resolver.d.ts +7 -4
  549. package/dist/schema/resolver.js +7 -6
  550. package/dist/schema/schema-store.d.ts +7 -10
  551. package/dist/schema/schema-store.js +13 -11
  552. package/dist/schema/schema-unavailable-error.d.ts +11 -0
  553. package/dist/schema/schema-unavailable-error.js +15 -0
  554. package/dist/schema/types.d.ts +22 -0
  555. package/dist/schema-registry-record.d.ts +35 -0
  556. package/dist/schema-registry-record.js +134 -0
  557. package/dist/server.d.ts +79 -9
  558. package/dist/server.js +62 -8
  559. package/dist/services.d.ts +33 -5
  560. package/dist/services.js +155 -37
  561. package/dist/settings-workspace.d.ts +23 -3
  562. package/dist/settings-workspace.js +159 -45
  563. package/dist/stamp-on-publish.d.ts +36 -0
  564. package/dist/stamp-on-publish.js +71 -0
  565. package/dist/static/index.d.ts +58 -5
  566. package/dist/static/index.js +133 -3
  567. package/dist/static/seo.d.ts +5 -5
  568. package/dist/static/seo.js +5 -5
  569. package/dist/submission-attribution.d.ts +8 -0
  570. package/dist/submission-attribution.js +22 -0
  571. package/dist/system-users.d.ts +12 -0
  572. package/dist/system-users.js +12 -0
  573. package/dist/task-queue/cms-task-queue.d.ts +1 -1
  574. package/dist/task-queue/cms-task-queue.js +1 -1
  575. package/dist/task-queue/index.d.ts +1 -1
  576. package/dist/task-queue/index.js +1 -1
  577. package/dist/task-queue/task-queue.d.ts +6 -0
  578. package/dist/task-queue/task-queue.js +29 -0
  579. package/dist/task-queue/worker-status.d.ts +35 -9
  580. package/dist/task-queue/worker-status.js +84 -17
  581. package/dist/types.d.ts +90 -9
  582. package/dist/url-collision.js +3 -3
  583. package/dist/url-exclusivity-fixtures.d.ts +8 -1
  584. package/dist/url-exclusivity-fixtures.js +11 -1
  585. package/dist/user.js +2 -1
  586. package/dist/utils/atomic-write.js +2 -1
  587. package/dist/utils/base-branch.d.ts +13 -0
  588. package/dist/utils/base-branch.js +23 -0
  589. package/dist/utils/content-serialize.d.ts +15 -7
  590. package/dist/utils/content-serialize.js +353 -51
  591. package/dist/utils/content-write-lock.d.ts +6 -1
  592. package/dist/utils/content-write-lock.js +21 -6
  593. package/dist/utils/debug.d.ts +1 -1
  594. package/dist/utils/debug.js +5 -3
  595. package/dist/utils/error.js +13 -2
  596. package/dist/utils/escape-text.d.ts +7 -0
  597. package/dist/utils/escape-text.js +27 -0
  598. package/dist/utils/fs.d.ts +12 -4
  599. package/dist/utils/fs.js +18 -5
  600. package/dist/utils/git.d.ts +21 -1
  601. package/dist/utils/git.js +63 -8
  602. package/dist/utils/json-source-splice.d.ts +14 -0
  603. package/dist/utils/json-source-splice.js +120 -0
  604. package/dist/utils/markdown-body-splice.d.ts +39 -0
  605. package/dist/utils/markdown-body-splice.js +421 -0
  606. package/dist/utils/occ-json-write.js +18 -12
  607. package/dist/utils/provision-log.d.ts +25 -0
  608. package/dist/utils/provision-log.js +49 -0
  609. package/dist/utils/provisioning-lock.d.ts +32 -1
  610. package/dist/utils/provisioning-lock.js +78 -32
  611. package/dist/utils/sanitize-href.d.ts +9 -23
  612. package/dist/utils/sanitize-href.js +14 -28
  613. package/dist/utils/title-field.d.ts +10 -0
  614. package/dist/utils/title-field.js +47 -0
  615. package/dist/utils/yaml-source-splice.d.ts +58 -0
  616. package/dist/utils/yaml-source-splice.js +515 -0
  617. package/dist/validation/block-structural-keys.d.ts +1 -1
  618. package/dist/validation/block-structural-keys.js +1 -1
  619. package/dist/validation/deletion-checker.d.ts +21 -29
  620. package/dist/validation/deletion-checker.js +41 -117
  621. package/dist/validation/entry-validator.d.ts +6 -10
  622. package/dist/validation/entry-validator.js +19 -26
  623. package/dist/validation/field-traversal.d.ts +22 -0
  624. package/dist/validation/field-traversal.js +39 -8
  625. package/dist/validation/markdown-safety.d.ts +68 -0
  626. package/dist/validation/markdown-safety.js +596 -0
  627. package/dist/validation/mdx-allowlist.d.ts +55 -0
  628. package/dist/validation/mdx-allowlist.js +183 -0
  629. package/dist/validation/reference-validator.d.ts +2 -0
  630. package/dist/validation/reference-validator.js +3 -0
  631. package/dist/version.d.ts +1 -1
  632. package/dist/version.js +1 -1
  633. package/dist/worker/branch-policy.d.ts +124 -0
  634. package/dist/worker/branch-policy.js +243 -0
  635. package/dist/worker/bundle-header.d.ts +117 -0
  636. package/dist/worker/bundle-header.js +253 -0
  637. package/dist/worker/cms-worker.d.ts +236 -142
  638. package/dist/worker/cms-worker.js +772 -285
  639. package/dist/worker/gateway-egress.d.ts +43 -0
  640. package/dist/worker/gateway-egress.js +209 -0
  641. package/dist/worker/gateway-instance.d.ts +42 -0
  642. package/dist/worker/gateway-instance.js +129 -0
  643. package/dist/worker/git-process.d.ts +81 -0
  644. package/dist/worker/git-process.js +234 -0
  645. package/dist/worker/git-sync.d.ts +34 -17
  646. package/dist/worker/git-sync.js +394 -131
  647. package/dist/worker/github-auth.d.ts +9 -9
  648. package/dist/worker/github-auth.js +13 -15
  649. package/dist/worker/github-gateway-http.d.ts +62 -0
  650. package/dist/worker/github-gateway-http.js +977 -0
  651. package/dist/worker/github-gateway-wire.d.ts +590 -0
  652. package/dist/worker/github-gateway-wire.js +488 -0
  653. package/dist/worker/github-gateway.d.ts +238 -0
  654. package/dist/worker/github-gateway.js +726 -0
  655. package/dist/worker/github-mirror-upkeep.d.ts +75 -0
  656. package/dist/worker/github-mirror-upkeep.js +266 -0
  657. package/dist/worker/github-mirror.d.ts +364 -0
  658. package/dist/worker/github-mirror.js +1030 -0
  659. package/dist/worker/github-transfer.d.ts +56 -0
  660. package/dist/worker/github-transfer.js +444 -0
  661. package/dist/worker/history-rewrite.d.ts +4 -5
  662. package/dist/worker/history-rewrite.js +12 -17
  663. package/dist/worker/provisioned-workspace.d.ts +5 -5
  664. package/dist/worker/provisioned-workspace.js +5 -5
  665. package/dist/worker/rebase.d.ts +1 -1
  666. package/dist/worker/rebase.js +58 -54
  667. package/dist/worker/remote-git-maintenance.d.ts +3 -0
  668. package/dist/worker/remote-git-maintenance.js +12 -0
  669. package/dist/worker/schema-gate.d.ts +49 -0
  670. package/dist/worker/schema-gate.js +226 -0
  671. package/dist/worker/self-checks.d.ts +107 -0
  672. package/dist/worker/self-checks.js +358 -0
  673. package/dist/worker/shared-repo-git.d.ts +96 -0
  674. package/dist/worker/shared-repo-git.js +459 -0
  675. package/dist/worker/sparse-cone.d.ts +20 -0
  676. package/dist/worker/sparse-cone.js +136 -0
  677. package/dist/worker/stale-mirror.d.ts +82 -0
  678. package/dist/worker/stale-mirror.js +130 -0
  679. package/dist/worker/task-runner.d.ts +5 -3
  680. package/dist/worker/task-runner.js +287 -186
  681. package/dist/worker/worker-context.d.ts +36 -37
  682. package/package.json +35 -7
  683. package/dist/editor/EditorPanes.d.ts +0 -10
  684. package/dist/editor/EditorPanes.js +0 -98
  685. package/dist/editor/components/EditorFooter.d.ts +0 -11
  686. package/dist/editor/components/EditorFooter.js +0 -9
  687. package/dist/editor/components/EditorSidebar.d.ts +0 -67
  688. package/dist/editor/components/EditorSidebar.js +0 -22
@@ -0,0 +1,56 @@
1
+ import { type GitHubGateway, type GitHubPushOutcome, type GitHubPushRequest } from './github-gateway.js';
2
+ /** What the transfers need from the worker. */
3
+ export interface TransferContext {
4
+ github(): GitHubGateway;
5
+ readonly remoteGitPath: string;
6
+ /**
7
+ * The inactivity bound on each git here run through worker/git-process.ts; its simple-git calls
8
+ * (init, for-each-ref, rev-parse) carry none.
9
+ */
10
+ readonly taskTimeoutMs: number;
11
+ }
12
+ /**
13
+ * Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
14
+ * which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
15
+ * bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
16
+ * remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
17
+ */
18
+ export declare function fetchGitHubIntoRemoteGit(ctx: TransferContext, signal?: AbortSignal): Promise<{
19
+ refs: ReadonlyMap<string, string>;
20
+ needsOperator: string | null;
21
+ }>;
22
+ /**
23
+ * Seed the new bare repository at `gitDir`, which must not exist yet, with every GitHub branch as
24
+ * `refs/heads/*`, and return those branches. Refuses, before creating anything, when GitHub has no
25
+ * `baseBranch`.
26
+ */
27
+ export declare function seedFromGitHub(ctx: TransferContext, gitDir: string, baseBranch: string, signal?: AbortSignal): Promise<ReadonlyMap<string, string>>;
28
+ /**
29
+ * Of `ids`, the ones that are not a commit reachable from one of `tips` in the repository at
30
+ * `gitDir`, an annotated tag counting as the commit it points at. One `cat-file --batch-check`
31
+ * and one walk, so the answer is exactly what that repository holds.
32
+ */
33
+ export declare function unreachableFrom(ctx: TransferContext, gitDir: string, ids: readonly string[], tips: readonly string[]): Promise<Set<string>>;
34
+ /** A push to GitHub of the commit `readSha` finds, as {@link pushToGitHub} takes it. */
35
+ export interface TransferPushRequest extends Omit<GitHubPushRequest, 'sha' | 'prerequisites'> {
36
+ /**
37
+ * Branches whose GitHub tips, as `remote.git`'s tracking namespace holds them, a bundle of
38
+ * `branch` is built on: the branch itself, and the base for a content branch. Missing ones are
39
+ * skipped.
40
+ */
41
+ prerequisiteBranches: readonly string[];
42
+ }
43
+ /**
44
+ * Push the commit `readSha` reads to GitHub, and resolve with it and what the push did. The push
45
+ * is asked for without objects first, which covers everything GitHub already holds; only when the
46
+ * gateway answers `need-objects` is a bundle built from `remote.git` and sent.
47
+ *
48
+ * The bundle must say what was read: its one head is `<sha> refs/heads/<branch>`, checked as it
49
+ * starts to stream. When the Lambda moved the branch in between, the push starts again from
50
+ * `readSha` (the caller's lease and history-rewrite marker are keyed to that commit), at most
51
+ * {@link MAX_PUSH_RESTARTS} times, so a ref moved on every pass cannot hold a task for ever.
52
+ */
53
+ export declare function pushToGitHub(ctx: TransferContext, request: TransferPushRequest, readSha: () => Promise<string>, signal?: AbortSignal): Promise<{
54
+ sha: string;
55
+ outcome: GitHubPushOutcome;
56
+ }>;
@@ -0,0 +1,444 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { Readable } from 'node:stream';
4
+ import { GITHUB_TRACKING_REF_PREFIX } from '../git-manager.js';
5
+ import { getErrorMessage } from '../utils/error.js';
6
+ import { BundleHeaderReader, hasOnlyHead } from './bundle-header.js';
7
+ import { runGit, spawnGit } from './git-process.js';
8
+ import { MAX_FETCH_HAVE, } from './github-gateway.js';
9
+ import { GitHubTransientError } from './github-mirror.js';
10
+ import { workerLogWarn } from './log.js';
11
+ import { sharedRepoGit, sharedRepoProcessOptions } from './shared-repo-git.js';
12
+ /**
13
+ * The worker's side of moving objects between `remote.git` and GitHub, through the GitHub
14
+ * gateway (worker/github-gateway.ts), which never runs git in, or opens a path in, anything the
15
+ * Lambda can write. Objects cross as git bundles:
16
+ * - **GitHub → remote.git:** the gateway answers a fetch with GitHub's branches and a bundle of
17
+ * what `remote.git` lacks; the worker unbundles it here, under the pins, and moves the tracking
18
+ * namespace to those branches itself ({@link fetchGitHubIntoRemoteGit}, {@link seedFromGitHub});
19
+ * - **remote.git → GitHub:** the worker asks for the push first, and only when the gateway answers
20
+ * `need-objects` builds a bundle here and sends it ({@link pushToGitHub}).
21
+ *
22
+ * The worker does not fsck what it receives: its peer is the gateway, and the objects came from
23
+ * GitHub. The gateway checks every object it is sent.
24
+ */
25
+ const GIT_ZERO_OID = '0000000000000000000000000000000000000000';
26
+ /** How many times a push restarts because the branch moved while its bundle was built. */
27
+ const MAX_PUSH_RESTARTS = 3;
28
+ /**
29
+ * Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
30
+ * which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
31
+ * bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
32
+ * remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
33
+ */
34
+ export async function fetchGitHubIntoRemoteGit(ctx, signal) {
35
+ const gitDir = ctx.remoteGitPath;
36
+ const { refs, bundleId } = await ctx.github().fetch({ have: await haveOf(gitDir) }, signal);
37
+ if (bundleId !== null)
38
+ await unbundle(ctx, gitDir, bundleId, signal);
39
+ const needsOperator = await moveTrackingRefs(ctx, gitDir, refs, signal);
40
+ return { refs, needsOperator };
41
+ }
42
+ /**
43
+ * Seed the new bare repository at `gitDir`, which must not exist yet, with every GitHub branch as
44
+ * `refs/heads/*`, and return those branches. Refuses, before creating anything, when GitHub has no
45
+ * `baseBranch`.
46
+ */
47
+ export async function seedFromGitHub(ctx, gitDir, baseBranch, signal) {
48
+ const { refs, bundleId } = await ctx.github().fetch({ have: [] }, signal);
49
+ if (!refs.has(baseBranch))
50
+ throw new Error(`GitHub has no branch '${baseBranch}'`);
51
+ await fs.mkdir(gitDir);
52
+ await sharedRepoGit(gitDir, 'bare').raw(['init', '--quiet', '--bare']);
53
+ if (bundleId !== null)
54
+ await unbundle(ctx, gitDir, bundleId, signal);
55
+ await updateRefs(ctx, gitDir, [...refs].map(([name, sha]) => ({ ref: `refs/heads/${name}`, to: sha, from: GIT_ZERO_OID })), signal);
56
+ return refs;
57
+ }
58
+ /**
59
+ * Of `ids`, the ones that are not a commit reachable from one of `tips` in the repository at
60
+ * `gitDir`, an annotated tag counting as the commit it points at. One `cat-file --batch-check`
61
+ * and one walk, so the answer is exactly what that repository holds.
62
+ */
63
+ export async function unreachableFrom(ctx, gitDir, ids, tips) {
64
+ const unreachable = new Set();
65
+ const peeled = new Map();
66
+ const valid = ids.filter((id) => {
67
+ if (OBJECT_ID.test(id))
68
+ return true;
69
+ unreachable.add(id);
70
+ return false;
71
+ });
72
+ if (valid.length > 0) {
73
+ const lines = (await runGit(['cat-file', '--batch-check=%(objectname) %(objecttype)', '--end-of-options'], {
74
+ ...sharedRepoProcessOptions(gitDir, 'bare'),
75
+ stdin: valid.map((id) => `${id}^{commit}\n`).join(''),
76
+ inactivityTimeoutMs: ctx.taskTimeoutMs,
77
+ })).split('\n');
78
+ valid.forEach((id, i) => {
79
+ const match = /^([0-9a-f]{40}|[0-9a-f]{64}) commit$/.exec(lines[i] ?? '');
80
+ if (match)
81
+ peeled.set(id, match[1]);
82
+ else
83
+ unreachable.add(id);
84
+ });
85
+ }
86
+ const commits = [...new Set(peeled.values())];
87
+ if (commits.length > 0) {
88
+ const notReached = new Set((await runGit(['rev-list', '--stdin', '--end-of-options'], {
89
+ ...sharedRepoProcessOptions(gitDir, 'bare'),
90
+ stdin: [...commits, ...tips.map((tip) => `^${tip}`)].map((l) => `${l}\n`).join(''),
91
+ inactivityTimeoutMs: ctx.taskTimeoutMs,
92
+ }))
93
+ .split('\n')
94
+ .filter(Boolean));
95
+ for (const [id, commit] of peeled)
96
+ if (notReached.has(commit))
97
+ unreachable.add(id);
98
+ }
99
+ return unreachable;
100
+ }
101
+ /**
102
+ * Push the commit `readSha` reads to GitHub, and resolve with it and what the push did. The push
103
+ * is asked for without objects first, which covers everything GitHub already holds; only when the
104
+ * gateway answers `need-objects` is a bundle built from `remote.git` and sent.
105
+ *
106
+ * The bundle must say what was read: its one head is `<sha> refs/heads/<branch>`, checked as it
107
+ * starts to stream. When the Lambda moved the branch in between, the push starts again from
108
+ * `readSha` (the caller's lease and history-rewrite marker are keyed to that commit), at most
109
+ * {@link MAX_PUSH_RESTARTS} times, so a ref moved on every pass cannot hold a task for ever.
110
+ */
111
+ export async function pushToGitHub(ctx, request, readSha, signal) {
112
+ const { prerequisiteBranches, ...rest } = request;
113
+ for (let restarts = 0;; restarts++) {
114
+ const sha = await readSha();
115
+ const prerequisites = await trackingTips(ctx.remoteGitPath, prerequisiteBranches);
116
+ const ask = { ...rest, sha, prerequisites };
117
+ const first = await ctx.github().push(ask, undefined, signal);
118
+ if (first.kind === 'pushed')
119
+ return { sha, outcome: outcomeOf(first) };
120
+ const bundle = await startBundle(ctx, request.branch, sha, first.usable, signal);
121
+ if (bundle === 'moved') {
122
+ if (restarts < MAX_PUSH_RESTARTS)
123
+ continue;
124
+ throw new GitHubTransientError('ref-kept-moving', `${request.branch} moved in remote.git while its push was being prepared, ` +
125
+ `${MAX_PUSH_RESTARTS + 1} times in a row`);
126
+ }
127
+ // Nothing to bundle: what is left to send, GitHub has. A second `need-objects` would only
128
+ // ask for the same again.
129
+ const second = await (bundle === 'empty'
130
+ ? ctx.github().push(ask, undefined, signal)
131
+ : sendBundle(ctx, ask, bundle, signal));
132
+ if (second.kind === 'pushed')
133
+ return { sha, outcome: outcomeOf(second) };
134
+ throw new GitHubTransientError('objects-still-needed', `The GitHub gateway still lacks objects for ${request.branch} after they were offered`);
135
+ }
136
+ }
137
+ function outcomeOf(answer) {
138
+ const { kind: _kind, ...outcome } = answer;
139
+ return outcome;
140
+ }
141
+ /**
142
+ * Start `bundle create` of `refs/heads/<branch>` in `remote.git`, built on `usable`, and read its
143
+ * header: `moved` when its head is not `sha`, `empty` when git refused an empty bundle (GitHub
144
+ * already has every commit it would hold), else the bundle to send, each prerequisite's comment
145
+ * shortened to what the gateway takes.
146
+ */
147
+ async function startBundle(ctx, branch, sha, usable, signal) {
148
+ const proc = spawnGit(['bundle', 'create', '--progress', '--end-of-options', '-', `refs/heads/${branch}`, '--stdin'], {
149
+ ...sharedRepoProcessOptions(ctx.remoteGitPath, 'bare'),
150
+ stdin: usable
151
+ .filter((id) => OBJECT_ID.test(id))
152
+ .map((id) => `^${id}\n`)
153
+ .join(''),
154
+ inactivityTimeoutMs: ctx.taskTimeoutMs,
155
+ signal,
156
+ });
157
+ const chunks = proc.stdout[Symbol.asyncIterator]();
158
+ // A prerequisite's comment is a commit subject, any length; the gateway takes only a short one.
159
+ const reader = new BundleHeaderReader('shorten');
160
+ let unreadable = null;
161
+ try {
162
+ for (;;) {
163
+ const next = await chunks.next();
164
+ if (next.done)
165
+ break;
166
+ let read;
167
+ try {
168
+ read = reader.push(next.value);
169
+ }
170
+ catch (err) {
171
+ unreadable = err;
172
+ break;
173
+ }
174
+ if (read === null)
175
+ continue;
176
+ if (!hasOnlyHead(read.header, sha, branch)) {
177
+ proc.kill('the branch moved');
178
+ return 'moved';
179
+ }
180
+ const { bytes, rest: first } = read;
181
+ const stream = Readable.from((async function* () {
182
+ yield bytes;
183
+ if (first.length > 0)
184
+ yield first;
185
+ for (;;) {
186
+ const rest = await chunks.next();
187
+ if (rest.done)
188
+ return;
189
+ yield rest.value;
190
+ }
191
+ })());
192
+ return { process: proc, stream };
193
+ }
194
+ }
195
+ catch (err) {
196
+ throw await causeOf(proc, err, 'its header could not be read');
197
+ }
198
+ if (unreadable !== null) {
199
+ // git writes a header with no head before it refuses an empty bundle, so its exit says which
200
+ // this is. Otherwise the header is the failure, whatever git makes of losing its reader.
201
+ proc.stdout.destroy();
202
+ if (await refusedAsEmpty(proc).catch(() => false))
203
+ return 'empty';
204
+ throw unreadable;
205
+ }
206
+ // stdout ended before a whole header: git failed, or found nothing to bundle.
207
+ if (await refusedAsEmpty(proc))
208
+ return 'empty';
209
+ throw new Error(`git bundle create printed no header for ${branch}`);
210
+ }
211
+ /** Whether `bundle create` exited refusing an empty bundle; any other failure is thrown. */
212
+ async function refusedAsEmpty(proc) {
213
+ try {
214
+ await proc.exited;
215
+ return false;
216
+ }
217
+ catch (err) {
218
+ if (/Refusing to create empty bundle/.test(getErrorMessage(err)))
219
+ return true;
220
+ throw err;
221
+ }
222
+ }
223
+ /**
224
+ * Send a started bundle with the push. When the push fails, git's own failure, if it had one,
225
+ * is the cause; otherwise the gateway's.
226
+ */
227
+ async function sendBundle(ctx, request, bundle, signal) {
228
+ let answer;
229
+ try {
230
+ answer = await ctx.github().push(request, bundle.stream, signal);
231
+ }
232
+ catch (err) {
233
+ throw await causeOf(bundle.process, err, 'the push failed');
234
+ }
235
+ // An answer is the push's outcome; how git exits after it changes nothing.
236
+ await bundle.process.exited.catch(() => undefined);
237
+ return answer;
238
+ }
239
+ /**
240
+ * What to report for a failure while `proc` was writing a bundle: git's own failure when it had
241
+ * one first (an abort, an inactivity kill, an error of its own), of which a stream error is only
242
+ * the symptom, else `err`. Stops git either way, with `reason`.
243
+ */
244
+ async function causeOf(proc, err, reason) {
245
+ proc.kill(reason);
246
+ const own = await proc.exited.then(() => null, (gitErr) => gitErr);
247
+ return own !== null && getErrorMessage(own) !== reason ? own : err;
248
+ }
249
+ /**
250
+ * Unbundle the gateway's bundle `bundleId` into the repository at `gitDir`, under the pins. It
251
+ * adds objects and moves no ref.
252
+ */
253
+ async function unbundle(ctx, gitDir, bundleId, signal) {
254
+ const stream = await ctx.github().openBundle(bundleId);
255
+ try {
256
+ await runGit(['bundle', 'unbundle', '--progress', '--end-of-options', '-'], {
257
+ ...sharedRepoProcessOptions(gitDir, 'bare'),
258
+ stdin: stream,
259
+ inactivityTimeoutMs: ctx.taskTimeoutMs,
260
+ signal,
261
+ });
262
+ }
263
+ finally {
264
+ stream.destroy();
265
+ }
266
+ }
267
+ /**
268
+ * Move the tracking namespace to exactly `refs`, every move stating the value it expects: all
269
+ * deletions in one `update-ref` transaction, then every create and update in another. One
270
+ * transaction cannot do both: deleting `a` and creating `a/b` together fails on the
271
+ * directory/file conflict, and a transaction is all-or-nothing, so a GitHub-side rename of
272
+ * `release` to `release/1.0` would freeze the namespace for ever. When a transaction fails on a
273
+ * ref (see {@link lostRace}), each of its moves is tried on its own, and the losers are logged;
274
+ * the next fetch retries them. The Lambda only reads this namespace, so per-ref
275
+ * atomicity is all it needs.
276
+ */
277
+ async function moveTrackingRefs(ctx, gitDir, refs, signal) {
278
+ let needsOperator = null;
279
+ const current = new Map();
280
+ const listing = await sharedRepoGit(gitDir, 'bare').raw([
281
+ 'for-each-ref',
282
+ '--format=%(objectname) %(refname)',
283
+ '--end-of-options',
284
+ GITHUB_TRACKING_REF_PREFIX,
285
+ ]);
286
+ for (const line of listing.split('\n')) {
287
+ const space = line.indexOf(' ');
288
+ if (space !== -1)
289
+ current.set(line.slice(space + 1), line.slice(0, space));
290
+ }
291
+ const deletions = [];
292
+ for (const [ref, sha] of current) {
293
+ if (!refs.has(ref.slice(GITHUB_TRACKING_REF_PREFIX.length))) {
294
+ deletions.push({ ref, to: null, from: sha });
295
+ }
296
+ }
297
+ const updates = [];
298
+ for (const [name, sha] of refs) {
299
+ const ref = `${GITHUB_TRACKING_REF_PREFIX}${name}`;
300
+ const from = current.get(ref);
301
+ if (from !== sha)
302
+ updates.push({ ref, to: sha, from: from ?? GIT_ZERO_OID });
303
+ }
304
+ for (const moves of [deletions, updates]) {
305
+ if (moves.length === 0)
306
+ continue;
307
+ try {
308
+ await updateRefs(ctx, gitDir, moves, signal);
309
+ }
310
+ catch (err) {
311
+ if (!lostRace(err))
312
+ throw err;
313
+ const losers = [];
314
+ if (PACKED_REFS_LOCKED.test(getErrorMessage(err))) {
315
+ // Every deletion takes packed-refs.lock, so each would wait for it and lose the same way.
316
+ losers.push(...moves.map((move) => move.ref));
317
+ needsOperator = await stalePackedRefsLock(gitDir);
318
+ }
319
+ else {
320
+ for (const move of moves) {
321
+ await updateRefs(ctx, gitDir, [move], signal).catch((moveErr) => {
322
+ if (!lostRace(moveErr))
323
+ throw moveErr;
324
+ losers.push(move.ref);
325
+ });
326
+ }
327
+ }
328
+ if (losers.length > 0) {
329
+ workerLogWarn(`Could not move ${losers.length} GitHub tracking ref(s), retrying next sync: ` +
330
+ `${losers.join(', ')} (${getErrorMessage(err).trim()})`);
331
+ }
332
+ }
333
+ }
334
+ return needsOperator;
335
+ }
336
+ const PACKED_REFS_LOCKED = /Unable to create '[^']*packed-refs\.lock': File exists/;
337
+ /** How old remote.git's packed-refs.lock must be before the worker reports it as left behind. */
338
+ const STALE_PACKED_REFS_LOCK_MS = 10 * 60 * 1000;
339
+ /**
340
+ * What to tell an operator about remote.git's `packed-refs.lock` once it is older than
341
+ * {@link STALE_PACKED_REFS_LOCK_MS}, which no git holds it for: a writer killed mid-delete left
342
+ * it, and it blocks every branch deletion there, the Lambda's included. The worker never removes
343
+ * it: the Lambda shares the repository, and the worker cannot tell a lock left behind from one
344
+ * a live writer holds on a host whose clock or NFS attributes it does not see.
345
+ */
346
+ async function stalePackedRefsLock(gitDir) {
347
+ const lock = path.join(gitDir, 'packed-refs.lock');
348
+ const stat = await fs.stat(lock).catch(() => null);
349
+ if (stat === null || Date.now() - stat.mtimeMs < STALE_PACKED_REFS_LOCK_MS)
350
+ return null;
351
+ return (`${lock} has been there since ${stat.mtime.toISOString()}: a git killed while it deleted a ` +
352
+ `branch left it, and every branch deletion in remote.git fails until it is removed. ` +
353
+ `Check that no git is running in remote.git, then remove that file.`);
354
+ }
355
+ /**
356
+ * Whether `update-ref` failed because a ref was not at the value a move stated, a lock was held
357
+ * (a ref's own, or `packed-refs.lock`, which every deletion takes), or a directory/file conflict
358
+ * stood in the way: a failure confined to the namespace's refs, logged and retried by the next
359
+ * fetch, which never holds back the other transaction. Anything else (an abort, a missing object)
360
+ * is thrown.
361
+ */
362
+ function lostRace(err) {
363
+ return /cannot lock ref|Unable to create '[^']*\.lock': File exists|exists; cannot create/.test(getErrorMessage(err));
364
+ }
365
+ /** Apply `moves` as one `update-ref` transaction, NUL-separated, so no refname can split a line. */
366
+ async function updateRefs(ctx, gitDir, moves, signal) {
367
+ const input = moves
368
+ .map((move) => {
369
+ if (move.ref.includes('\0'))
370
+ throw new Error(`A ref name holds a NUL: ${JSON.stringify(move.ref)}`);
371
+ return move.to === null
372
+ ? `delete ${move.ref}\0${move.from}\0`
373
+ : `update ${move.ref}\0${move.to}\0${move.from}\0`;
374
+ })
375
+ .join('');
376
+ await runGit(['update-ref', '-z', '--stdin', '--end-of-options'], {
377
+ ...sharedRepoProcessOptions(gitDir, 'bare'),
378
+ stdin: input,
379
+ inactivityTimeoutMs: ctx.taskTimeoutMs,
380
+ signal,
381
+ });
382
+ }
383
+ /**
384
+ * What `gitDir` has, for a fetch's `have`, up to {@link MAX_FETCH_HAVE} IDs: its GitHub tracking
385
+ * tips first, which describe most of what GitHub has, then its branches' tips. With no tracking
386
+ * ref at all (a remote.git no fetch has written yet), a branch ahead of GitHub names no commit
387
+ * the gateway holds, and the bundle would resend history remote.git already has, so each branch
388
+ * then adds its first-parent ancestors 1, 2, 4, … commits back, as git's own negotiation does.
389
+ */
390
+ async function haveOf(gitDir) {
391
+ const list = async (namespace) => (await sharedRepoGit(gitDir, 'bare').raw([
392
+ 'for-each-ref',
393
+ '--format=%(objectname)',
394
+ '--end-of-options',
395
+ namespace,
396
+ ]))
397
+ .split('\n')
398
+ .filter((id) => OBJECT_ID.test(id));
399
+ const tracking = await list(GITHUB_TRACKING_REF_PREFIX);
400
+ const heads = await list('refs/heads/');
401
+ const have = new Set([...tracking, ...heads]);
402
+ if (tracking.length === 0) {
403
+ for (const tip of new Set(heads)) {
404
+ if (have.size >= MAX_FETCH_HAVE)
405
+ break;
406
+ const ancestors = (await sharedRepoGit(gitDir, 'bare').raw([
407
+ 'rev-list',
408
+ '--first-parent',
409
+ `--max-count=${SKIP_LIST_DEPTH}`,
410
+ '--end-of-options',
411
+ tip,
412
+ ]))
413
+ .split('\n')
414
+ .filter((id) => OBJECT_ID.test(id));
415
+ for (let step = 1; step < ancestors.length; step *= 2)
416
+ have.add(ancestors[step]);
417
+ if (ancestors.length > 0)
418
+ have.add(ancestors[ancestors.length - 1]);
419
+ }
420
+ }
421
+ return [...have].slice(0, MAX_FETCH_HAVE);
422
+ }
423
+ /** How far back {@link haveOf} looks along one branch. */
424
+ const SKIP_LIST_DEPTH = 4096;
425
+ /** The tracking-namespace tips of `branches` in `gitDir`, skipping any it lacks. */
426
+ async function trackingTips(gitDir, branches) {
427
+ const tips = [];
428
+ for (const branch of new Set(branches)) {
429
+ const sha = await sharedRepoGit(gitDir, 'bare')
430
+ .raw([
431
+ 'rev-parse',
432
+ '--verify',
433
+ '--quiet',
434
+ '--end-of-options',
435
+ `${GITHUB_TRACKING_REF_PREFIX}${branch}`,
436
+ ])
437
+ .then((out) => out.split('\n')[0] ?? '')
438
+ .catch(() => '');
439
+ if (OBJECT_ID.test(sha) && !tips.includes(sha))
440
+ tips.push(sha);
441
+ }
442
+ return tips;
443
+ }
444
+ const OBJECT_ID = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
@@ -23,10 +23,9 @@ export type HistoryRewriteContext = Pick<WorkerContext, 'remoteGitPath' | 'conte
23
23
  * What `remote.git` currently holds for `branchRef`, or null when this branch
24
24
  * was never published there (never submitted) or the ref is unreadable.
25
25
  *
26
- * Explicit `--git-dir`, like verifyBaseBranchExists() in cms-worker.ts:
27
- * reading a bare repo that way does not depend on `safe.bareRepository` being
28
- * permissive, which is why prod code takes this route rather than the config
29
- * override the test-only `openBareRepo` helper uses.
26
+ * Names the repository outright (sharedRepoGit's GIT_DIR), like
27
+ * verifyBaseBranchExists() in cms-worker.ts: reading a bare repo that way does
28
+ * not depend on `safe.bareRepository` being permissive.
30
29
  */
31
30
  export declare function readPublishedSha(ctx: Pick<HistoryRewriteContext, 'remoteGitPath'>, branchRef: string): Promise<string | null>;
32
31
  /**
@@ -55,7 +54,7 @@ export declare function markHistoryRewritten(ctx: Pick<HistoryRewriteContext, 'c
55
54
  * it on GitHub" diagnosis that is false -- we did.
56
55
  *
57
56
  * Tracked, with the concurrent-clear race that can drop a marker mid-arming,
58
- * in .claude/future-tasks/worker-history-rewrite-marker-races.md.
57
+ * in safeinsights/canopycms#902.
59
58
  */
60
59
  export declare function clearHistoryRewrittenMarker(ctx: Pick<HistoryRewriteContext, 'contentBranchesPath'>, branchPath: string, branchDir: string): Promise<void>;
61
60
  /**
@@ -1,26 +1,22 @@
1
1
  import path from 'node:path';
2
- import { simpleGit } from 'simple-git';
3
2
  import { BranchMetadataFileManager, getBranchMetadataFileManager } from '../branch-metadata.js';
4
- import { gitChildEnv } from '../git-manager.js';
5
3
  import { sanitizeBranchName } from '../paths/branch-name.js';
6
4
  import { getErrorMessage, redactCredentials } from '../utils/error.js';
7
5
  import { isStaleLeaseRejection } from '../utils/git.js';
8
6
  import { enqueueTask, listTasks } from '../task-queue/cms-task-queue.js';
7
+ import { pinnedReceivePack, sharedRepoGit } from './shared-repo-git.js';
9
8
  import { workerLog, workerLogWarn } from './log.js';
10
9
  /**
11
10
  * What `remote.git` currently holds for `branchRef`, or null when this branch
12
11
  * was never published there (never submitted) or the ref is unreadable.
13
12
  *
14
- * Explicit `--git-dir`, like verifyBaseBranchExists() in cms-worker.ts:
15
- * reading a bare repo that way does not depend on `safe.bareRepository` being
16
- * permissive, which is why prod code takes this route rather than the config
17
- * override the test-only `openBareRepo` helper uses.
13
+ * Names the repository outright (sharedRepoGit's GIT_DIR), like
14
+ * verifyBaseBranchExists() in cms-worker.ts: reading a bare repo that way does
15
+ * not depend on `safe.bareRepository` being permissive.
18
16
  */
19
17
  export async function readPublishedSha(ctx, branchRef) {
20
18
  try {
21
- const out = await simpleGit().raw([
22
- '--git-dir',
23
- ctx.remoteGitPath,
19
+ const out = await sharedRepoGit(ctx.remoteGitPath, 'bare').raw([
24
20
  'rev-parse',
25
21
  '--verify',
26
22
  `refs/heads/${branchRef}`,
@@ -66,7 +62,7 @@ export async function markHistoryRewritten(ctx, branchPath, branchDir, expectedS
66
62
  * it on GitHub" diagnosis that is false -- we did.
67
63
  *
68
64
  * Tracked, with the concurrent-clear race that can drop a marker mid-arming,
69
- * in .claude/future-tasks/worker-history-rewrite-marker-races.md.
65
+ * in safeinsights/canopycms#902.
70
66
  */
71
67
  export async function clearHistoryRewrittenMarker(ctx, branchPath, branchDir) {
72
68
  try {
@@ -94,17 +90,16 @@ export async function clearHistoryRewrittenMarker(ctx, branchPath, branchDir) {
94
90
  * push moved the ref; logged and retried by the self-heal pass, never thrown.
95
91
  */
96
92
  export async function forcePublishToLocalRemote(ctx, branchPath, branchRef, expectedSha) {
97
- // A dedicated instance rather than the caller's: `.env()` replaces the whole
98
- // child environment, and the rebase loop's instance must keep its ambient
99
- // one. gitChildEnv (not gitNetworkChildEnv) because this push targets the
100
- // local bare repo -- and its locale pin is what keeps isStaleLeaseRejection
101
- // below from silently becoming a no-op on a non-English host.
102
- const pushGit = simpleGit({ baseDir: branchPath, timeout: { block: ctx.taskTimeoutMs } });
103
- pushGit.env(gitChildEnv({}));
93
+ // sharedRepoGit's env is gitChildEnv's, whose C-locale pin is what keeps
94
+ // isStaleLeaseRejection below from silently becoming a no-op on a
95
+ // non-English host.
96
+ const pushGit = sharedRepoGit(branchPath, 'worktree', { timeout: { block: ctx.taskTimeoutMs } });
104
97
  try {
105
98
  await pushGit.raw([
106
99
  'push',
107
100
  `--force-with-lease=${branchRef}:${expectedSha}`,
101
+ // Otherwise remote.git's own hooks run, as the worker.
102
+ `--receive-pack=${pinnedReceivePack()}`,
108
103
  // Real flags must precede --end-of-options; everything after it is
109
104
  // positional (see GitManager.push() for the same guard).
110
105
  '--end-of-options',
@@ -18,17 +18,17 @@ export type ProvisionedWorkspaceHold = {
18
18
  };
19
19
  /**
20
20
  * Take a branch workspace's provisioning lock for the sync loop, the same cross-host lock the
21
- * Lambda holds while it clones the workspace (`branch-workspace.ts`), so the worker never runs git
22
- * against a half-made clone. The caller holds it across its dirty check and every git step, and
21
+ * Lambda holds while it publishes the workspace (branch-provisioning.ts) and admin actions hold
22
+ * while they repair or purge it. The caller holds it across its dirty check and every git step, and
23
23
  * releases it in a `finally`.
24
24
  *
25
25
  * Zero retries: the worker skips and retries next cycle rather than wait, so it never blocks on
26
26
  * the Lambda and cannot deadlock with it. The rebase nests the content-write lock inside this one;
27
27
  * the worker takes that one try-only as well, so the nesting cannot deadlock either.
28
28
  *
29
- * Provisioned means a `.git` directory AND `branch.json`. The Lambda clones directly into the
30
- * target path, so `.git` appears early, and writes `branch.json` only after the clone and its
31
- * lock are done.
29
+ * Provisioned means a `.git` directory AND `branch.json`. A workspace is published complete with
30
+ * both ([PROV-1], branch-provisioning.ts), so anything else at a branch name is a leftover for
31
+ * `repairBranchDirResidue` (git-sync.ts).
32
32
  */
33
33
  export declare function holdProvisionedWorkspace(contentBranchesPath: string, dirName: string): Promise<ProvisionedWorkspaceHold>;
34
34
  /** Release a hold, logging rather than throwing: the sync loop's callers never throw. */
@@ -6,17 +6,17 @@ import { branchProvisioningLockName, tryAcquireProvisioningLock } from '../utils
6
6
  import { workerLogWarn } from './log.js';
7
7
  /**
8
8
  * Take a branch workspace's provisioning lock for the sync loop, the same cross-host lock the
9
- * Lambda holds while it clones the workspace (`branch-workspace.ts`), so the worker never runs git
10
- * against a half-made clone. The caller holds it across its dirty check and every git step, and
9
+ * Lambda holds while it publishes the workspace (branch-provisioning.ts) and admin actions hold
10
+ * while they repair or purge it. The caller holds it across its dirty check and every git step, and
11
11
  * releases it in a `finally`.
12
12
  *
13
13
  * Zero retries: the worker skips and retries next cycle rather than wait, so it never blocks on
14
14
  * the Lambda and cannot deadlock with it. The rebase nests the content-write lock inside this one;
15
15
  * the worker takes that one try-only as well, so the nesting cannot deadlock either.
16
16
  *
17
- * Provisioned means a `.git` directory AND `branch.json`. The Lambda clones directly into the
18
- * target path, so `.git` appears early, and writes `branch.json` only after the clone and its
19
- * lock are done.
17
+ * Provisioned means a `.git` directory AND `branch.json`. A workspace is published complete with
18
+ * both ([PROV-1], branch-provisioning.ts), so anything else at a branch name is a leftover for
19
+ * `repairBranchDirResidue` (git-sync.ts).
20
20
  */
21
21
  export async function holdProvisionedWorkspace(contentBranchesPath, dirName) {
22
22
  let release;
@@ -20,7 +20,7 @@ import type { WorkerContext } from './worker-context.js';
20
20
  * but still need their PR's resolution polled, and this loop is the only thing
21
21
  * that walks every branch workspace.
22
22
  */
23
- export type RebaseContext = Pick<WorkerContext, 'githubOwner' | 'githubRepo' | 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'contentRoot' | 'remoteGitPath' | 'taskDir' | 'taskTimeoutMs' | 'octokit' | 'afterConflictDetectedForTesting' | 'afterRebaseCompletedForTesting' | 'ensureSettingsBranch'>;
23
+ export type RebaseContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'contentRoot' | 'remoteGitPath' | 'taskDir' | 'taskTimeoutMs' | 'github' | 'afterConflictDetectedForTesting' | 'afterRebaseCompletedForTesting' | 'ensureSettingsBranch' | 'isDraining'>;
24
24
  /**
25
25
  * Per-cycle outcome of `rebaseActiveBranches()`, folded by `syncGit()` into the
26
26
  * worker's self-reported status (`WorkerStatusReport.lastGitSync`, see