canopycms 0.0.67-int.90 → 0.0.67

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 (539) hide show
  1. package/README.md +30 -3
  2. package/dist/ai/generate.js +1 -27
  3. package/dist/ai/handler.d.ts +0 -4
  4. package/dist/ai/handler.js +0 -11
  5. package/dist/ai/index.d.ts +1 -8
  6. package/dist/ai/index.js +1 -8
  7. package/dist/ai/json-to-markdown.js +15 -58
  8. package/dist/ai/resolve-branch.d.ts +2 -7
  9. package/dist/ai/resolve-branch.js +2 -8
  10. package/dist/ai/strip-mdx.d.ts +5 -13
  11. package/dist/ai/strip-mdx.js +5 -17
  12. package/dist/ai/to-plain-text.d.ts +10 -28
  13. package/dist/ai/to-plain-text.js +10 -28
  14. package/dist/ai/transform-components.d.ts +2 -4
  15. package/dist/ai/transform-components.js +8 -19
  16. package/dist/ai/types.d.ts +5 -10
  17. package/dist/api/admin-branch-health.d.ts +4 -12
  18. package/dist/api/admin-branch-health.js +26 -66
  19. package/dist/api/admin.d.ts +4 -12
  20. package/dist/api/admin.js +10 -26
  21. package/dist/api/assets.d.ts +0 -25
  22. package/dist/api/assets.js +50 -91
  23. package/dist/api/branch-merge.d.ts +1 -1
  24. package/dist/api/branch-merge.js +0 -2
  25. package/dist/api/branch-review.d.ts +0 -8
  26. package/dist/api/branch-review.js +0 -13
  27. package/dist/api/branch-status.d.ts +0 -3
  28. package/dist/api/branch-status.js +8 -33
  29. package/dist/api/branch-withdraw.d.ts +0 -1
  30. package/dist/api/branch-withdraw.js +6 -9
  31. package/dist/api/branch.d.ts +7 -12
  32. package/dist/api/branch.js +7 -44
  33. package/dist/api/client.d.ts +71 -224
  34. package/dist/api/client.js +82 -233
  35. package/dist/api/comments.d.ts +2 -4
  36. package/dist/api/comments.js +0 -17
  37. package/dist/api/content.d.ts +0 -6
  38. package/dist/api/content.js +66 -142
  39. package/dist/api/entries-constants.d.ts +5 -9
  40. package/dist/api/entries-constants.js +5 -9
  41. package/dist/api/entries.d.ts +8 -13
  42. package/dist/api/entries.js +20 -51
  43. package/dist/api/github-sync.d.ts +2 -4
  44. package/dist/api/github-sync.js +4 -8
  45. package/dist/api/groups.d.ts +3 -0
  46. package/dist/api/groups.js +8 -21
  47. package/dist/api/guards.d.ts +4 -16
  48. package/dist/api/guards.js +3 -22
  49. package/dist/api/index.d.ts +4 -4
  50. package/dist/api/permissions.d.ts +2 -0
  51. package/dist/api/permissions.js +18 -40
  52. package/dist/api/reference-options.d.ts +0 -1
  53. package/dist/api/reference-options.js +3 -11
  54. package/dist/api/request-body-hash.d.ts +12 -23
  55. package/dist/api/request-body-hash.js +12 -23
  56. package/dist/api/resolve-references.d.ts +0 -1
  57. package/dist/api/resolve-references.js +13 -28
  58. package/dist/api/route-builder.d.ts +3 -7
  59. package/dist/api/route-builder.js +1 -1
  60. package/dist/api/routes.d.ts +12 -0
  61. package/dist/api/routes.js +47 -0
  62. package/dist/api/schema.d.ts +23 -33
  63. package/dist/api/schema.js +20 -74
  64. package/dist/api/settings-helpers.js +4 -5
  65. package/dist/api/types.d.ts +0 -5
  66. package/dist/api/user.js +0 -5
  67. package/dist/api/validators.d.ts +14 -52
  68. package/dist/api/validators.js +14 -52
  69. package/dist/assets/asset-prefixes.d.ts +4 -8
  70. package/dist/assets/asset-prefixes.js +4 -8
  71. package/dist/assets/asset-src.d.ts +5 -22
  72. package/dist/assets/asset-src.js +5 -21
  73. package/dist/assets/factory.d.ts +1 -2
  74. package/dist/assets/factory.js +1 -2
  75. package/dist/assets/finalize.d.ts +3 -1
  76. package/dist/assets/finalize.js +3 -1
  77. package/dist/assets/index.d.ts +3 -3
  78. package/dist/assets/index.js +1 -1
  79. package/dist/assets/keys.d.ts +5 -3
  80. package/dist/assets/keys.js +6 -3
  81. package/dist/assets/pipeline.d.ts +3 -2
  82. package/dist/assets/pipeline.js +22 -56
  83. package/dist/assets/sharp-loader.d.ts +2 -10
  84. package/dist/assets/sharp-loader.js +2 -10
  85. package/dist/assets/store-local.d.ts +1 -2
  86. package/dist/assets/store-local.js +1 -2
  87. package/dist/assets/store-s3.d.ts +3 -4
  88. package/dist/assets/svg-sanitizer.d.ts +6 -14
  89. package/dist/assets/svg-sanitizer.js +6 -14
  90. package/dist/assets/transform-directives.d.ts +3 -4
  91. package/dist/assets/transform-directives.js +1 -1
  92. package/dist/assets/transform.d.ts +19 -30
  93. package/dist/assets/transform.js +18 -31
  94. package/dist/auth/cache.d.ts +2 -3
  95. package/dist/auth/cache.js +2 -3
  96. package/dist/auth/caching-auth-plugin.d.ts +11 -22
  97. package/dist/auth/caching-auth-plugin.js +12 -14
  98. package/dist/auth/context-helpers.d.ts +6 -20
  99. package/dist/auth/context-helpers.js +5 -17
  100. package/dist/auth/file-based-auth-cache.d.ts +10 -21
  101. package/dist/auth/file-based-auth-cache.js +23 -51
  102. package/dist/auth/plugin.d.ts +29 -61
  103. package/dist/auth/plugin.js +9 -13
  104. package/dist/auth/types.d.ts +11 -20
  105. package/dist/authorization/branch.d.ts +30 -49
  106. package/dist/authorization/branch.js +16 -42
  107. package/dist/authorization/content.d.ts +11 -40
  108. package/dist/authorization/content.js +13 -45
  109. package/dist/authorization/groups/index.d.ts +0 -3
  110. package/dist/authorization/groups/index.js +0 -3
  111. package/dist/authorization/groups/loader.d.ts +14 -28
  112. package/dist/authorization/groups/loader.js +14 -38
  113. package/dist/authorization/groups/schema.d.ts +0 -6
  114. package/dist/authorization/groups/schema.js +4 -7
  115. package/dist/authorization/helpers.d.ts +9 -28
  116. package/dist/authorization/helpers.js +9 -28
  117. package/dist/authorization/index.d.ts +3 -25
  118. package/dist/authorization/index.js +3 -35
  119. package/dist/authorization/path.d.ts +6 -13
  120. package/dist/authorization/path.js +8 -25
  121. package/dist/authorization/permissions/index.d.ts +0 -3
  122. package/dist/authorization/permissions/index.js +0 -3
  123. package/dist/authorization/permissions/loader.d.ts +14 -27
  124. package/dist/authorization/permissions/loader.js +14 -32
  125. package/dist/authorization/permissions/schema.d.ts +1 -6
  126. package/dist/authorization/permissions/schema.js +6 -13
  127. package/dist/authorization/protected-branch.d.ts +36 -65
  128. package/dist/authorization/protected-branch.js +29 -41
  129. package/dist/authorization/settings-file-store.d.ts +38 -81
  130. package/dist/authorization/settings-file-store.js +38 -79
  131. package/dist/authorization/types.d.ts +4 -26
  132. package/dist/authorization/types.js +0 -6
  133. package/dist/authorization/validation.d.ts +1 -23
  134. package/dist/authorization/validation.js +1 -24
  135. package/dist/branch-health.d.ts +39 -67
  136. package/dist/branch-health.js +27 -43
  137. package/dist/branch-metadata-file.d.ts +16 -32
  138. package/dist/branch-metadata-file.js +13 -26
  139. package/dist/branch-metadata.d.ts +49 -80
  140. package/dist/branch-metadata.js +57 -87
  141. package/dist/branch-registry.d.ts +26 -64
  142. package/dist/branch-registry.js +44 -93
  143. package/dist/branch-schema-cache.d.ts +34 -124
  144. package/dist/branch-schema-cache.js +49 -155
  145. package/dist/branch-workspace.d.ts +4 -4
  146. package/dist/branch-workspace.js +15 -19
  147. package/dist/build/generate-ai-content.d.ts +1 -0
  148. package/dist/build/generate-ai-content.js +12 -25
  149. package/dist/build-canopy.d.ts +17 -27
  150. package/dist/build-canopy.js +16 -23
  151. package/dist/build-mode.d.ts +25 -27
  152. package/dist/build-mode.js +25 -29
  153. package/dist/cli/cli.d.ts +15 -26
  154. package/dist/cli/cli.js +601 -978
  155. package/dist/cli/generate-ai-content.js +351 -628
  156. package/dist/cli/github-app-manifest.d.ts +84 -0
  157. package/dist/cli/github-app-manifest.js +161 -0
  158. package/dist/cli/init-github-app.d.ts +110 -444
  159. package/dist/cli/init-github-app.js +236 -773
  160. package/dist/cli/init.js +39 -80
  161. package/dist/cli/migrate.d.ts +13 -10
  162. package/dist/cli/migrate.js +22 -30
  163. package/dist/cli/project-detect.d.ts +17 -31
  164. package/dist/cli/project-detect.js +31 -42
  165. package/dist/cli/project-root.d.ts +4 -11
  166. package/dist/cli/project-root.js +4 -11
  167. package/dist/cli/prompt.d.ts +10 -0
  168. package/dist/cli/prompt.js +67 -0
  169. package/dist/cli/sync.d.ts +0 -8
  170. package/dist/cli/sync.js +8 -28
  171. package/dist/cli/template-files/middleware.ts.template +15 -29
  172. package/dist/cli/templates.d.ts +2 -12
  173. package/dist/cli/templates.js +4 -4
  174. package/dist/client.d.ts +1 -1
  175. package/dist/comment-store.d.ts +32 -53
  176. package/dist/comment-store.js +32 -52
  177. package/dist/config/flatten.d.ts +0 -3
  178. package/dist/config/flatten.js +2 -12
  179. package/dist/config/helpers.js +2 -2
  180. package/dist/config/index.d.ts +2 -2
  181. package/dist/config/index.js +1 -4
  182. package/dist/config/schemas/collection.d.ts +0 -8
  183. package/dist/config/schemas/collection.js +0 -10
  184. package/dist/config/schemas/config.d.ts +6 -78
  185. package/dist/config/schemas/config.js +38 -54
  186. package/dist/config/schemas/field.d.ts +2 -242
  187. package/dist/config/schemas/field.js +9 -20
  188. package/dist/config/schemas/media.js +1 -1
  189. package/dist/config/schemas/permissions.js +0 -2
  190. package/dist/config/schemas/url.d.ts +5 -6
  191. package/dist/config/schemas/url.js +5 -6
  192. package/dist/config/types.d.ts +45 -33
  193. package/dist/config/types.js +0 -1
  194. package/dist/config.d.ts +1 -8
  195. package/dist/config.js +1 -9
  196. package/dist/content-id-index.d.ts +76 -188
  197. package/dist/content-id-index.js +79 -230
  198. package/dist/content-index-generation.d.ts +27 -48
  199. package/dist/content-index-generation.js +35 -84
  200. package/dist/content-index-registry.d.ts +15 -24
  201. package/dist/content-index-registry.js +5 -9
  202. package/dist/content-listing.d.ts +64 -107
  203. package/dist/content-listing.js +68 -118
  204. package/dist/content-reader.d.ts +20 -29
  205. package/dist/content-reader.js +10 -18
  206. package/dist/content-store.d.ts +210 -336
  207. package/dist/content-store.js +413 -657
  208. package/dist/content-tree.d.ts +44 -86
  209. package/dist/content-tree.js +26 -54
  210. package/dist/context.d.ts +67 -94
  211. package/dist/context.js +53 -72
  212. package/dist/dev-content-watcher.d.ts +18 -18
  213. package/dist/dev-content-watcher.js +41 -44
  214. package/dist/editor/BranchManager.d.ts +3 -6
  215. package/dist/editor/BranchManager.js +24 -44
  216. package/dist/editor/CanopyEditor.js +5 -2
  217. package/dist/editor/CommentsPanel.js +0 -2
  218. package/dist/editor/Editor.js +19 -76
  219. package/dist/editor/EditorAuthGate.d.ts +27 -0
  220. package/dist/editor/EditorAuthGate.js +140 -0
  221. package/dist/editor/EntryNavigator.js +0 -20
  222. package/dist/editor/FormRenderer.d.ts +1 -2
  223. package/dist/editor/FormRenderer.js +8 -23
  224. package/dist/editor/admin/SystemHealthPanel.js +20 -37
  225. package/dist/editor/admin/useSystemHealth.d.ts +2 -3
  226. package/dist/editor/admin/useSystemHealth.js +10 -12
  227. package/dist/editor/client-reference-resolver.d.ts +2 -5
  228. package/dist/editor/client-reference-resolver.js +2 -19
  229. package/dist/editor/comments/BranchComments.js +0 -4
  230. package/dist/editor/comments/EntryComments.js +0 -4
  231. package/dist/editor/comments/FieldWrapper.js +0 -4
  232. package/dist/editor/comments/InlineCommentThread.js +0 -2
  233. package/dist/editor/comments/ThreadCarousel.d.ts +0 -58
  234. package/dist/editor/comments/ThreadCarousel.js +0 -12
  235. package/dist/editor/components/EditorFooter.d.ts +0 -8
  236. package/dist/editor/components/EditorFooter.js +0 -5
  237. package/dist/editor/components/EditorHeader.d.ts +0 -31
  238. package/dist/editor/components/EditorHeader.js +21 -71
  239. package/dist/editor/components/EditorSidebar.d.ts +0 -19
  240. package/dist/editor/components/EditorSidebar.js +0 -16
  241. package/dist/editor/components/EntryCreateModal.d.ts +4 -4
  242. package/dist/editor/components/EntryCreateModal.js +7 -22
  243. package/dist/editor/components/RenameEntryModal.js +0 -4
  244. package/dist/editor/components/UserBadge.js +0 -10
  245. package/dist/editor/components/index.js +0 -2
  246. package/dist/editor/context/ApiClientContext.d.ts +8 -7
  247. package/dist/editor/context/ApiClientContext.js +39 -11
  248. package/dist/editor/context/AssetContext.d.ts +7 -17
  249. package/dist/editor/context/AssetContext.js +7 -17
  250. package/dist/editor/context/EditorIdentityContext.d.ts +13 -0
  251. package/dist/editor/context/EditorIdentityContext.js +7 -0
  252. package/dist/editor/context/EditorStateContext.d.ts +10 -41
  253. package/dist/editor/context/EditorStateContext.js +7 -23
  254. package/dist/editor/context/SWRProvider.d.ts +3 -6
  255. package/dist/editor/context/index.d.ts +1 -20
  256. package/dist/editor/context/index.js +1 -20
  257. package/dist/editor/editor-utils.d.ts +8 -47
  258. package/dist/editor/editor-utils.js +19 -72
  259. package/dist/editor/fields/BlockField.d.ts +2 -2
  260. package/dist/editor/fields/BlockField.js +1 -2
  261. package/dist/editor/fields/CodeField.d.ts +0 -1
  262. package/dist/editor/fields/CodeField.js +0 -1
  263. package/dist/editor/fields/DateTimeField.d.ts +15 -22
  264. package/dist/editor/fields/DateTimeField.js +17 -26
  265. package/dist/editor/fields/ImageField.d.ts +2 -2
  266. package/dist/editor/fields/ImageField.js +8 -14
  267. package/dist/editor/fields/InlineGroupField.d.ts +0 -1
  268. package/dist/editor/fields/InlineGroupField.js +0 -1
  269. package/dist/editor/fields/MarkdownField.d.ts +0 -1
  270. package/dist/editor/fields/MarkdownField.js +6 -11
  271. package/dist/editor/fields/MdxImageDialog.d.ts +1 -1
  272. package/dist/editor/fields/MdxImageDialog.js +0 -1
  273. package/dist/editor/fields/NumberField.d.ts +9 -19
  274. package/dist/editor/fields/NumberField.js +11 -22
  275. package/dist/editor/fields/NumberListField.d.ts +7 -10
  276. package/dist/editor/fields/NumberListField.js +7 -10
  277. package/dist/editor/fields/ObjectField.d.ts +5 -8
  278. package/dist/editor/fields/ObjectField.js +0 -1
  279. package/dist/editor/fields/ReferenceField.d.ts +1 -1
  280. package/dist/editor/fields/ReferenceField.js +11 -16
  281. package/dist/editor/fields/SelectField.d.ts +2 -2
  282. package/dist/editor/fields/SelectField.js +0 -1
  283. package/dist/editor/fields/StringListField.d.ts +0 -4
  284. package/dist/editor/fields/StringListField.js +4 -9
  285. package/dist/editor/fields/TextField.d.ts +0 -1
  286. package/dist/editor/fields/TextField.js +0 -1
  287. package/dist/editor/fields/ToggleField.d.ts +0 -1
  288. package/dist/editor/fields/ToggleField.js +0 -1
  289. package/dist/editor/fields/entry-link/EntryLinkContext.js +2 -4
  290. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +0 -3
  291. package/dist/editor/fields/entry-link/InsertEntryLink.js +0 -4
  292. package/dist/editor/group-manager/ExternalGroupsTab.d.ts +0 -3
  293. package/dist/editor/group-manager/ExternalGroupsTab.js +0 -1
  294. package/dist/editor/group-manager/GroupCard.d.ts +0 -3
  295. package/dist/editor/group-manager/GroupForm.d.ts +0 -3
  296. package/dist/editor/group-manager/InternalGroupsTab.d.ts +0 -3
  297. package/dist/editor/group-manager/InternalGroupsTab.js +0 -2
  298. package/dist/editor/group-manager/MemberList.d.ts +0 -3
  299. package/dist/editor/group-manager/hooks/useExternalGroupSearch.d.ts +0 -3
  300. package/dist/editor/group-manager/hooks/useExternalGroupSearch.js +0 -3
  301. package/dist/editor/group-manager/hooks/useGroupState.d.ts +0 -3
  302. package/dist/editor/group-manager/hooks/useGroupState.js +0 -5
  303. package/dist/editor/group-manager/hooks/useUserSearch.d.ts +0 -3
  304. package/dist/editor/group-manager/hooks/useUserSearch.js +0 -3
  305. package/dist/editor/group-manager/index.d.ts +0 -6
  306. package/dist/editor/group-manager/index.js +0 -10
  307. package/dist/editor/group-manager/types.d.ts +2 -5
  308. package/dist/editor/group-manager/types.js +0 -3
  309. package/dist/editor/hooks/index.d.ts +6 -11
  310. package/dist/editor/hooks/index.js +6 -12
  311. package/dist/editor/hooks/useBranchActions.d.ts +0 -14
  312. package/dist/editor/hooks/useBranchActions.js +0 -22
  313. package/dist/editor/hooks/useBranchManager.d.ts +2 -48
  314. package/dist/editor/hooks/useBranchManager.js +4 -64
  315. package/dist/editor/hooks/useBranchesData.d.ts +7 -6
  316. package/dist/editor/hooks/useBranchesData.js +7 -6
  317. package/dist/editor/hooks/useCommentSystem.d.ts +0 -49
  318. package/dist/editor/hooks/useCommentSystem.js +1 -36
  319. package/dist/editor/hooks/useDraftManager.d.ts +2 -35
  320. package/dist/editor/hooks/useDraftManager.js +23 -64
  321. package/dist/editor/hooks/useEditorLayout.d.ts +0 -20
  322. package/dist/editor/hooks/useEditorLayout.js +0 -23
  323. package/dist/editor/hooks/useEntriesData.d.ts +1 -0
  324. package/dist/editor/hooks/useEntriesData.js +2 -3
  325. package/dist/editor/hooks/useEntryLinkResolution.d.ts +2 -2
  326. package/dist/editor/hooks/useEntryLinkResolution.js +2 -2
  327. package/dist/editor/hooks/useEntryManager.d.ts +2 -27
  328. package/dist/editor/hooks/useEntryManager.js +29 -78
  329. package/dist/editor/hooks/useGroupManager.d.ts +0 -21
  330. package/dist/editor/hooks/useGroupManager.js +0 -21
  331. package/dist/editor/hooks/usePermissionManager.d.ts +0 -20
  332. package/dist/editor/hooks/usePermissionManager.js +0 -20
  333. package/dist/editor/hooks/useReferenceResolution.d.ts +2 -33
  334. package/dist/editor/hooks/useReferenceResolution.js +1 -48
  335. package/dist/editor/hooks/useSchemaManager.d.ts +8 -27
  336. package/dist/editor/hooks/useSchemaManager.js +0 -19
  337. package/dist/editor/hooks/useUserContext.d.ts +2 -9
  338. package/dist/editor/hooks/useUserContext.js +10 -10
  339. package/dist/editor/hooks/useUserMetadata.d.ts +0 -2
  340. package/dist/editor/hooks/useUserMetadata.js +0 -3
  341. package/dist/editor/media/AssetCard.d.ts +0 -1
  342. package/dist/editor/media/AssetCard.js +1 -2
  343. package/dist/editor/media/CropStep.d.ts +0 -1
  344. package/dist/editor/media/CropStep.js +0 -1
  345. package/dist/editor/media/MediaLibrary.d.ts +1 -2
  346. package/dist/editor/media/MediaLibrary.js +1 -2
  347. package/dist/editor/media/MediaLibraryBody.d.ts +0 -1
  348. package/dist/editor/media/MediaLibraryBody.js +0 -1
  349. package/dist/editor/media/crop-math.d.ts +1 -1
  350. package/dist/editor/media/crop-math.js +1 -1
  351. package/dist/editor/permission-manager/GroupSelector.d.ts +0 -3
  352. package/dist/editor/permission-manager/PermissionEditor.d.ts +0 -4
  353. package/dist/editor/permission-manager/PermissionEditor.js +0 -1
  354. package/dist/editor/permission-manager/PermissionLevelBadge.d.ts +0 -7
  355. package/dist/editor/permission-manager/PermissionLevelBadge.js +0 -4
  356. package/dist/editor/permission-manager/PermissionTree.d.ts +0 -4
  357. package/dist/editor/permission-manager/UserSelector.d.ts +0 -3
  358. package/dist/editor/permission-manager/constants.d.ts +0 -3
  359. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.d.ts +0 -3
  360. package/dist/editor/permission-manager/hooks/useGroupsAndUsers.js +0 -10
  361. package/dist/editor/permission-manager/hooks/usePermissionTree.d.ts +0 -14
  362. package/dist/editor/permission-manager/hooks/usePermissionTree.js +0 -11
  363. package/dist/editor/permission-manager/index.d.ts +0 -7
  364. package/dist/editor/permission-manager/index.js +0 -16
  365. package/dist/editor/permission-manager/types.d.ts +2 -12
  366. package/dist/editor/permission-manager/types.js +0 -3
  367. package/dist/editor/permission-manager/utils.d.ts +0 -28
  368. package/dist/editor/permission-manager/utils.js +9 -23
  369. package/dist/editor/preview-bridge.d.ts +5 -1
  370. package/dist/editor/preview-bridge.js +4 -4
  371. package/dist/editor/schema-editor/CollectionEditor.d.ts +0 -5
  372. package/dist/editor/schema-editor/CollectionEditor.js +9 -31
  373. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +0 -6
  374. package/dist/editor/schema-editor/EntryTypeEditor.js +3 -24
  375. package/dist/editor/schema-editor/index.d.ts +0 -7
  376. package/dist/editor/schema-editor/index.js +0 -7
  377. package/dist/editor/utils/env.d.ts +3 -18
  378. package/dist/editor/utils/env.js +6 -25
  379. package/dist/entry-link-resolver.d.ts +13 -35
  380. package/dist/entry-link-resolver.js +20 -53
  381. package/dist/entry-schema-registry.d.ts +20 -60
  382. package/dist/entry-schema-registry.js +20 -69
  383. package/dist/entry-schema.d.ts +118 -223
  384. package/dist/entry-schema.js +46 -91
  385. package/dist/git-manager.d.ts +101 -200
  386. package/dist/git-manager.js +211 -384
  387. package/dist/github-service.d.ts +34 -75
  388. package/dist/github-service.js +37 -91
  389. package/dist/http/handler.d.ts +6 -37
  390. package/dist/http/handler.js +65 -120
  391. package/dist/http/router.d.ts +15 -32
  392. package/dist/http/router.js +34 -99
  393. package/dist/http/types.d.ts +15 -40
  394. package/dist/http/types.js +3 -7
  395. package/dist/id.d.ts +4 -10
  396. package/dist/id.js +4 -10
  397. package/dist/index.js +6 -9
  398. package/dist/operating-mode/client-safe-strategy.d.ts +7 -14
  399. package/dist/operating-mode/client-safe-strategy.js +8 -28
  400. package/dist/operating-mode/client-unsafe-strategy.d.ts +6 -16
  401. package/dist/operating-mode/client-unsafe-strategy.js +9 -34
  402. package/dist/operating-mode/client.d.ts +3 -10
  403. package/dist/operating-mode/client.js +3 -8
  404. package/dist/operating-mode/deployment-name-fixtures.d.ts +14 -18
  405. package/dist/operating-mode/deployment-name-fixtures.js +14 -18
  406. package/dist/operating-mode/deployment-name.d.ts +19 -29
  407. package/dist/operating-mode/deployment-name.js +29 -47
  408. package/dist/operating-mode/index.d.ts +4 -25
  409. package/dist/operating-mode/index.js +9 -31
  410. package/dist/operating-mode/mode-env.d.ts +32 -54
  411. package/dist/operating-mode/mode-env.js +36 -58
  412. package/dist/operating-mode/types.d.ts +24 -72
  413. package/dist/operating-mode/types.js +1 -7
  414. package/dist/paths/branch-name.d.ts +30 -40
  415. package/dist/paths/branch-name.js +30 -40
  416. package/dist/paths/branch.d.ts +4 -18
  417. package/dist/paths/branch.js +6 -22
  418. package/dist/paths/index.d.ts +2 -13
  419. package/dist/paths/index.js +3 -23
  420. package/dist/paths/normalize-server.d.ts +3 -15
  421. package/dist/paths/normalize-server.js +3 -15
  422. package/dist/paths/normalize.d.ts +13 -33
  423. package/dist/paths/normalize.js +13 -33
  424. package/dist/paths/resolve.d.ts +4 -17
  425. package/dist/paths/resolve.js +4 -22
  426. package/dist/paths/types.d.ts +12 -34
  427. package/dist/paths/types.js +5 -7
  428. package/dist/paths/validation.d.ts +22 -119
  429. package/dist/paths/validation.js +30 -148
  430. package/dist/reference-resolver.d.ts +0 -13
  431. package/dist/reference-resolver.js +0 -18
  432. package/dist/resolve-canopy-user.d.ts +16 -18
  433. package/dist/resolve-canopy-user.js +17 -26
  434. package/dist/resource-generation.d.ts +16 -25
  435. package/dist/resource-generation.js +34 -97
  436. package/dist/schema/meta-loader.d.ts +2 -14
  437. package/dist/schema/meta-loader.js +15 -64
  438. package/dist/schema/resolver.d.ts +1 -4
  439. package/dist/schema/resolver.js +1 -6
  440. package/dist/schema/schema-store-types.d.ts +0 -12
  441. package/dist/schema/schema-store.d.ts +61 -138
  442. package/dist/schema/schema-store.js +85 -282
  443. package/dist/schema/types.d.ts +0 -4
  444. package/dist/server.d.ts +62 -93
  445. package/dist/server.js +63 -94
  446. package/dist/services.d.ts +23 -47
  447. package/dist/services.js +55 -98
  448. package/dist/settings-workspace.d.ts +17 -30
  449. package/dist/settings-workspace.js +51 -81
  450. package/dist/static/index.d.ts +26 -52
  451. package/dist/static/index.js +33 -67
  452. package/dist/{worker/task-queue.d.ts → task-queue/cms-task-queue.d.ts} +7 -9
  453. package/dist/task-queue/cms-task-queue.js +13 -0
  454. package/dist/task-queue/task-queue-config.d.ts +3 -0
  455. package/dist/{worker → task-queue}/task-queue-config.js +1 -6
  456. package/dist/task-queue/task-queue.d.ts +16 -22
  457. package/dist/task-queue/task-queue.js +20 -44
  458. package/dist/task-queue/types.d.ts +0 -1
  459. package/dist/task-queue/worker-status.d.ts +35 -0
  460. package/dist/task-queue/worker-status.js +40 -0
  461. package/dist/types.d.ts +40 -51
  462. package/dist/url-collision.d.ts +26 -40
  463. package/dist/url-collision.js +47 -63
  464. package/dist/url-exclusivity-fixtures.d.ts +15 -20
  465. package/dist/url-exclusivity-fixtures.js +14 -19
  466. package/dist/url-path-resolver.d.ts +8 -16
  467. package/dist/url-path-resolver.js +19 -29
  468. package/dist/user.d.ts +8 -21
  469. package/dist/user.js +10 -19
  470. package/dist/utils/async-mutex.js +4 -6
  471. package/dist/utils/atomic-write.d.ts +2 -11
  472. package/dist/utils/atomic-write.js +2 -11
  473. package/dist/utils/body-field.d.ts +8 -15
  474. package/dist/utils/body-field.js +8 -15
  475. package/dist/utils/content-serialize.d.ts +18 -24
  476. package/dist/utils/content-serialize.js +109 -160
  477. package/dist/utils/content-write-lock.d.ts +51 -106
  478. package/dist/utils/content-write-lock.js +66 -111
  479. package/dist/utils/debug.d.ts +7 -23
  480. package/dist/utils/debug.js +7 -23
  481. package/dist/utils/entry-url.d.ts +11 -23
  482. package/dist/utils/entry-url.js +11 -26
  483. package/dist/utils/error.d.ts +25 -90
  484. package/dist/utils/error.js +60 -147
  485. package/dist/utils/flatten-group-fields.d.ts +5 -7
  486. package/dist/utils/flatten-group-fields.js +5 -7
  487. package/dist/utils/format.d.ts +1 -5
  488. package/dist/utils/format.js +1 -5
  489. package/dist/utils/fs.d.ts +3 -4
  490. package/dist/utils/fs.js +3 -4
  491. package/dist/utils/git.d.ts +52 -83
  492. package/dist/utils/git.js +79 -125
  493. package/dist/utils/logger.d.ts +35 -50
  494. package/dist/utils/logger.js +35 -52
  495. package/dist/utils/provisioning-lock.d.ts +23 -35
  496. package/dist/utils/provisioning-lock.js +49 -69
  497. package/dist/utils/sanitize-href.d.ts +5 -10
  498. package/dist/utils/sanitize-href.js +8 -18
  499. package/dist/utils/title-field.d.ts +17 -20
  500. package/dist/utils/title-field.js +18 -27
  501. package/dist/utils/typed-filename.d.ts +20 -48
  502. package/dist/utils/typed-filename.js +25 -61
  503. package/dist/utils/url-prefix.d.ts +3 -3
  504. package/dist/utils/url-prefix.js +3 -3
  505. package/dist/validation/block-structural-keys.d.ts +16 -31
  506. package/dist/validation/block-structural-keys.js +19 -29
  507. package/dist/validation/deletion-checker.d.ts +0 -34
  508. package/dist/validation/deletion-checker.js +1 -43
  509. package/dist/validation/entry-link-validator.d.ts +6 -13
  510. package/dist/validation/entry-link-validator.js +4 -13
  511. package/dist/validation/entry-type-reference-validator.d.ts +13 -18
  512. package/dist/validation/entry-type-reference-validator.js +13 -18
  513. package/dist/validation/entry-validator.d.ts +13 -25
  514. package/dist/validation/entry-validator.js +15 -32
  515. package/dist/validation/field-traversal.d.ts +3 -30
  516. package/dist/validation/field-traversal.js +1 -32
  517. package/dist/validation/reference-validator.d.ts +5 -24
  518. package/dist/validation/reference-validator.js +5 -30
  519. package/dist/worker/cms-worker.d.ts +172 -232
  520. package/dist/worker/cms-worker.js +241 -333
  521. package/dist/worker/git-sync.d.ts +32 -133
  522. package/dist/worker/git-sync.js +129 -191
  523. package/dist/worker/github-auth.d.ts +13 -19
  524. package/dist/worker/github-auth.js +13 -19
  525. package/dist/worker/history-rewrite.d.ts +53 -66
  526. package/dist/worker/history-rewrite.js +54 -60
  527. package/dist/worker/log.d.ts +24 -41
  528. package/dist/worker/log.js +25 -42
  529. package/dist/worker/rebase.d.ts +20 -110
  530. package/dist/worker/rebase.js +279 -354
  531. package/dist/worker/task-runner.d.ts +32 -66
  532. package/dist/worker/task-runner.js +126 -162
  533. package/dist/worker/worker-context.d.ts +41 -81
  534. package/package.json +4 -4
  535. package/dist/cli/template-files/middleware-clerk.ts.template +0 -37
  536. package/dist/worker/task-queue-config.d.ts +0 -8
  537. package/dist/worker/task-queue.js +0 -19
  538. package/dist/worker/worker-status.d.ts +0 -47
  539. package/dist/worker/worker-status.js +0 -52
@@ -9,8 +9,8 @@ import { getErrorMessage, isNodeError, redactCredentials } from '../utils/error.
9
9
  import { isNonFastForwardRejection } from '../utils/git.js';
10
10
  import { hasPendingHistoryRewrite } from './history-rewrite.js';
11
11
  import { runRebaseCycle } from './rebase.js';
12
- import { cleanupOldTasks } from './task-queue.js';
13
- import { writeWorkerStatus } from './worker-status.js';
12
+ import { cleanupOldTasks } from '../task-queue/cms-task-queue.js';
13
+ import { writeWorkerStatus } from '../task-queue/worker-status.js';
14
14
  import { workerLog, workerLogError, workerLogWarn } from './log.js';
15
15
  /**
16
16
  * [C1] Retention window for `.trash-*` branch directories left behind by the
@@ -37,22 +37,17 @@ function parseTrashStamp(stamp) {
37
37
  }
38
38
  /**
39
39
  * Push THIS deployment's own settings branch (`ensureSettingsBranch()`) from
40
- * remote.git to GitHub. Non-fatal: a no-op push for an up-to-date branch
41
- * just succeeds quietly.
40
+ * remote.git to GitHub. Non-fatal: a no-op push for an up-to-date branch just
41
+ * succeeds quietly.
42
42
  *
43
- * Deliberately narrowed to one branch — this used to push EVERY local
44
- * branch matching `canopycms-settings-*`. With the tracking-namespace fetch
45
- * fix (GITHUB_TRACKING_REF_PREFIX), `reconcileTrackedBranches` creates local
46
- * heads for branches that exist on GitHub, so ANOTHER deployment's settings
47
- * branch (sharing this same GitHub repo) can legitimately show up as a
48
- * local head here too. Pushing it would be this deployment shipping
49
- * settings state it doesn't own.
43
+ * Narrowed to that ONE branch, never every local `canopycms-settings-*`:
44
+ * `reconcileTrackedBranches` creates local heads for branches that exist on
45
+ * GitHub, so ANOTHER deployment's settings branch (sharing this GitHub repo)
46
+ * can legitimately show up as a local head here. Pushing it would be this
47
+ * deployment shipping settings state it does not own.
50
48
  */
51
49
  export async function pushSettingsBranches(ctx, git, trackedNames) {
52
50
  try {
53
- // Resolved once here rather than at each use below: ensureSettingsBranch()
54
- // is idempotent, but a local reads better and keeps the eight references
55
- // in this method obviously talking about one value.
56
51
  const settingsBranch = ctx.ensureSettingsBranch();
57
52
  const branches = await git.branch();
58
53
  const settingsBranches = branches.all.filter((b) => b.startsWith(RESERVED_SETTINGS_BRANCH_PREFIX));
@@ -66,19 +61,17 @@ export async function pushSettingsBranches(ctx, git, trackedNames) {
66
61
  // Check the full branch list, not the `canopycms-settings-*` subset: an
67
62
  // adopter-supplied `settingsBranch` override need not carry that prefix.
68
63
  const ownBranchMissing = !branches.all.includes(settingsBranch);
69
- // [SYNC-M3] A settings branch present in remote.git but absent from
70
- // GitHub's tracking refs was pushed here LOCALLY -- only this
71
- // deployment's own API can write to remote.git -- and has never
72
- // reached GitHub. That is the discriminating signature: in the
73
- // SUPPORTED two-deployments-one-repo case the foreign branch arrives
74
- // through the GitHub fetch and therefore always has a tracking ref, so
75
- // the warn above cannot tell the two apart on its own and a
76
- // "owned-branch-absent" test alone would fire on every deployment that
77
- // simply has not had a settings edit yet.
64
+ // [SYNC-M3] A settings branch in remote.git but absent from GitHub's
65
+ // tracking refs was pushed here LOCALLY (only this deployment's own API
66
+ // writes to remote.git) and has never reached GitHub. That absence is the
67
+ // discriminating signature: in the SUPPORTED two-deployments-one-repo case
68
+ // the foreign branch arrives through the GitHub fetch and so always has a
69
+ // tracking ref, while an "owned-branch-absent" test alone would fire on
70
+ // every deployment that has simply had no settings edit yet.
78
71
  //
79
- // With this deployment's own branch also missing, the API and this
80
- // worker have resolved different deploymentNames, and every settings
81
- // change the API commits is stranded in remote.git forever.
72
+ // With this deployment's own branch also missing, the API and this worker
73
+ // have resolved different deploymentNames, and every settings change the
74
+ // API commits is stranded in remote.git forever.
82
75
  const strandedLocal = foreign.filter((b) => !trackedNames.has(b));
83
76
  if (strandedLocal.length > 0) {
84
77
  workerLogWarn(ownBranchMissing
@@ -97,25 +90,20 @@ export async function pushSettingsBranches(ctx, git, trackedNames) {
97
90
  return;
98
91
  }
99
92
  try {
100
- // Resolved in place rather than hoisted: this is the only push in the
101
- // function, so there is no second call to keep consistent, and the
102
- // resolution would have to move out to syncGit and arrive as an argument
103
- // -- changing pushSettingsBranches' signature, which cms-worker.test.ts
104
- // calls directly through the instance against an inline type naming it
105
- // (see the `PushSettingsBranchesInternals` suite).
93
+ // Resolved in place, not hoisted: this is the only push in the function,
94
+ // so there is no second call to keep consistent, and hoisting would move
95
+ // the resolution out to syncGit and change this signature -- which
96
+ // cms-worker.test.ts pins by calling the method through the instance.
106
97
  await git.push(await ctx.buildGitHubUrl(), settingsBranch);
107
98
  workerLog(`Pushed settings branch ${settingsBranch} to GitHub`);
108
99
  }
109
100
  catch (err) {
110
- // Non-fatal: branch may already be up-to-date. This call site has no
111
- // task to throw a PermanentTaskError into (unlike pushBranchToGitHub)
112
- // and is deliberately not restructured to add one -- but a
113
- // non-fast-forward rejection here is the highest-signal instance of
114
- // this whole failure class: it means another CanopyCMS deployment's
115
- // worker already pushed ITS OWN state to its own settings branch on
116
- // GitHub (an actual settings-branch name collision, not just the
117
- // "foreign branch found locally" case warned about above), so make
118
- // that explicit instead of a generic "push failed" line.
101
+ // Non-fatal: the branch may already be up to date, and this call site has
102
+ // no task to throw a PermanentTaskError into (unlike pushBranchToGitHub).
103
+ // A non-fast-forward rejection here still gets its own wording: it means
104
+ // another deployment's worker already pushed ITS OWN state to this
105
+ // settings-branch name on GitHub -- an actual collision, not just the
106
+ // "foreign branch found locally" case warned about above.
119
107
  const message = getErrorMessage(err);
120
108
  if (isNonFastForwardRejection(message)) {
121
109
  workerLogWarn(`Settings push for ${settingsBranch} was rejected (non-fast-forward): another ` +
@@ -135,49 +123,32 @@ export async function pushSettingsBranches(ctx, git, trackedNames) {
135
123
  }
136
124
  /**
137
125
  * Bring `refs/heads/*` in `remote.git` toward what was just fetched into
138
- * `GITHUB_TRACKING_REF_PREFIX` -- WITHOUT ever force-rewinding or deleting
139
- * a local head. This is the non-destructive replacement for what the old
140
- * `+refs/heads/*:refs/heads/*` fetch refspec used to do implicitly (and
141
- * destructively) as part of the fetch itself; see
142
- * `GITHUB_TRACKING_REF_PREFIX`'s doc comment for the two failure modes
143
- * that refspec caused.
126
+ * `GITHUB_TRACKING_REF_PREFIX` -- WITHOUT ever force-rewinding or deleting a
127
+ * local head (see that constant's doc comment for the two failure modes a
128
+ * `+refs/heads/*:refs/heads/*` fetch refspec causes).
144
129
  *
145
- * Per tracked branch:
146
- * - no local `refs/heads/<name>` yet -> create it at the tracked commit
147
- * (a branch created on GitHub, or by another deployment sharing this
148
- * GitHub repo, becomes visible locally).
149
- * - local is a strict ancestor of tracked (behind) -> fast-forward it.
150
- * - local === tracked -> nothing to do.
151
- * - tracked is a strict ancestor of local (ahead) -> LEAVE IT ALONE. This
152
- * is unpushed editor/settings work; the queued push task (or
153
- * pushSettingsBranches) ships it. This is exactly the branch state the
154
- * old refspec used to destroy.
155
- * - neither is an ancestor of the other (diverged) -> LEAVE IT ALONE and
156
- * count/log it. A real collision (e.g. another deployment moved the
157
- * same branch name on GitHub); the next push attempt will be rejected
158
- * non-fast-forward, which is the correct, visible outcome -- this
159
- * method must never silently pick a winner. The one expected, benign
160
- * form of this -- our own rebase loop having published a rewrite into
161
- * remote.git with the GitHub push still queued -- is split out into the
162
- * `rewritten` bucket so the collision warning stays meaningful.
130
+ * Per tracked branch: no local `refs/heads/<name>` -> create it at the tracked
131
+ * commit; local behind -> fast-forward; equal -> nothing to do; local AHEAD ->
132
+ * LEAVE IT ALONE, since that is unpushed editor/settings work the queued push
133
+ * task (or pushSettingsBranches) ships; diverged -> LEAVE IT ALONE, count and
134
+ * log it. Divergence is a real collision (another deployment moved the same
135
+ * branch name on GitHub) and the next push is rejected non-fast-forward, the
136
+ * correct visible outcome -- this must never silently pick a winner. The one
137
+ * benign form, our own rebase loop having published a rewrite with the GitHub
138
+ * push still queued, is split into `rewritten` so that warning stays meaningful.
163
139
  *
164
- * Never deletes a local head: a branch removed on GitHub simply stops
165
- * being tracked here; the local ref persists until removed through its
166
- * own explicit path (the sync loop must not be one of them).
140
+ * Never deletes a local head: a branch removed on GitHub simply stops being
141
+ * tracked here; the local ref persists until removed through its own explicit
142
+ * path, which the sync loop must not be.
167
143
  *
168
- * `remote.git` is bare, so there is no worktree to invalidate by moving
169
- * these refs -- unlike a non-bare repo, updating the ref that happens to
170
- * be "checked out" is a non-issue here.
171
- *
172
- * Concurrency: `remote.git` is bare and on EFS, and the Lambda pushes into
173
- * it concurrently (`GitManager.push()`'s `target:target` refspec) while
174
- * this runs. Every `update-ref` below passes the expected old value (the
175
- * all-zeros OID for "must not exist yet" on creation, the previously-read
176
- * SHA for the fast-forward case) so a concurrent Lambda write landing in
177
- * the gap between the read and the write loses the ref update instead of
178
- * being silently clobbered -- the branch is simply revisited next cycle.
144
+ * Concurrency: `remote.git` is bare and on EFS, and the Lambda pushes into it
145
+ * while this runs. Every `update-ref` below passes the expected old value (the
146
+ * all-zeros OID for "must not exist yet" on creation, the just-read SHA for a
147
+ * fast-forward), so a concurrent Lambda write landing between the read and the
148
+ * write loses the ref update instead of silently clobbering it -- that branch
149
+ * is simply revisited next cycle.
179
150
  */
180
- export async function reconcileTrackedBranches(ctx, git) {
151
+ async function reconcileTrackedBranches(ctx, git) {
181
152
  const GIT_ZERO_OID = '0000000000000000000000000000000000000000';
182
153
  const created = [];
183
154
  const fastForwarded = [];
@@ -186,7 +157,7 @@ export async function reconcileTrackedBranches(ctx, git) {
186
157
  const rewritten = [];
187
158
  // One invocation enumerates both namespaces: refs/heads/<name> (what the
188
159
  // Lambda pushes into and branch clones read from) and
189
- // GITHUB_TRACKING_REF_PREFIX<name> (GitHub's tip, just fetched above).
160
+ // GITHUB_TRACKING_REF_PREFIX<name> (GitHub's tip).
190
161
  const raw = await git.raw([
191
162
  'for-each-ref',
192
163
  '--format=%(refname) %(objectname)',
@@ -212,9 +183,9 @@ export async function reconcileTrackedBranches(ctx, git) {
212
183
  const localRef = `refs/heads/${name}`;
213
184
  if (!localSha) {
214
185
  try {
215
- // Zero old-value asserts the ref does not already exist -- guards
216
- // against a concurrent Lambda push creating this exact branch
217
- // name between the for-each-ref read above and this update.
186
+ // The zero old-value asserts the ref does not already exist, guarding
187
+ // against a concurrent Lambda push creating this exact branch name
188
+ // between the for-each-ref read above and this update.
218
189
  await git.raw(['update-ref', localRef, trackedSha, GIT_ZERO_OID]);
219
190
  created.push(name);
220
191
  }
@@ -225,30 +196,26 @@ export async function reconcileTrackedBranches(ctx, git) {
225
196
  }
226
197
  if (localSha === trackedSha)
227
198
  continue; // nothing to do
228
- // [SYNC-M2] Everything below is per-branch best-effort. The rev-list
229
- // used to sit between the two guarded update-ref calls with no guard
230
- // of its own, so a single ref pointing at a missing or partially
231
- // written object -- plausible on EFS with the Lambda writing
232
- // concurrently -- threw out of this loop, out of syncGit()'s try, and
233
- // skipped pushSettingsBranches(), refreshBaseBranchWorkspace() and
234
- // rebaseActiveBranches() entirely. Nothing self-healed, so it recurred
235
- // every cycle. One unreadable ref must cost its own branch, not the
236
- // whole sync cycle.
199
+ // [SYNC-M2] Everything below is per-branch best-effort: one unreadable ref
200
+ // must cost its own branch, not the whole sync cycle. A ref pointing at a
201
+ // missing or partially written object is plausible on EFS with the Lambda
202
+ // writing concurrently, and an unguarded throw here escapes syncGit()'s try
203
+ // -- skipping pushSettingsBranches(), refreshBaseBranchWorkspace() and the
204
+ // rebase cycle, with nothing to self-heal it on the next pass.
237
205
  try {
238
- // Count commits unique to each side in one call: left = commits local
239
- // has that tracked doesn't (ahead), right = commits tracked has that
240
- // local doesn't (behind). Exits 0 regardless of ancestry direction,
241
- // unlike `merge-base --is-ancestor` (which simple-git would throw on
242
- // a non-zero exit for the common "not an ancestor" case).
206
+ // Commits unique to each side in one call: left = local's (ahead), right
207
+ // = tracked's (behind). Exits 0 regardless of ancestry direction, unlike
208
+ // `merge-base --is-ancestor`, whose non-zero exit for the common "not an
209
+ // ancestor" case simple-git would throw on.
243
210
  const counts = (await git.raw(['rev-list', '--left-right', '--count', `${localSha}...${trackedSha}`])).trim();
244
211
  const [leftStr, rightStr] = counts.split(/\s+/);
245
212
  const localAheadCount = parseInt(leftStr, 10);
246
213
  const localBehindCount = parseInt(rightStr, 10);
247
214
  if (!Number.isInteger(localAheadCount) || !Number.isInteger(localBehindCount)) {
248
- // Unparseable output means we could not read this branch, NOT that
249
- // it diverged: falling through to the `diverged` bucket below would
250
- // warn operators about a cross-deployment collision that never
251
- // happened (parseInt yields NaN, and NaN fails both comparisons).
215
+ // Unparseable output means this branch could not be read, NOT that it
216
+ // diverged: falling through to the `diverged` bucket (parseInt yields
217
+ // NaN, which fails both comparisons) would warn operators about a
218
+ // cross-deployment collision that never happened.
252
219
  workerLogWarn(` Tracked-branch reconcile: skipping ${name}: unparseable rev-list output ${JSON.stringify(counts)}`);
253
220
  continue;
254
221
  }
@@ -264,15 +231,14 @@ export async function reconcileTrackedBranches(ctx, git) {
264
231
  }
265
232
  }
266
233
  else if (localBehindCount === 0 && localAheadCount > 0) {
267
- // Unpushed local work -- exactly what the old destructive refspec
268
- // used to force-rewind or delete. Leave it.
234
+ // Unpushed local work. Leave it.
269
235
  ahead.push(name);
270
236
  }
271
237
  else if (await hasPendingHistoryRewrite(ctx, name)) {
272
- // [SYNC-H1] Our own rebase published a rewrite into remote.git and
273
- // the GitHub push has not landed yet. Ref-level this is identical
274
- // to a collision, but it is expected and self-resolving, so it must
275
- // not fire the collision warning below.
238
+ // [SYNC-H1] Our own rebase published a rewrite into remote.git and the
239
+ // GitHub push has not landed yet. Ref-level this is identical to a
240
+ // collision, but expected and self-resolving, so it must not fire the
241
+ // collision warning below.
276
242
  rewritten.push(name);
277
243
  }
278
244
  else {
@@ -291,10 +257,9 @@ export async function reconcileTrackedBranches(ctx, git) {
291
257
  if (rewritten.length > 0) {
292
258
  workerLog(` Tracked-branch reconcile: ${rewritten.length} branch(es) rebased locally with the GitHub push still pending: ${rewritten.join(', ')}`);
293
259
  }
294
- // trackedNames is returned alongside the summary (rather than folded into
295
- // it) because it is a working set for pushSettingsBranches' stranded-
296
- // branch check, not part of the worker-status snapshot -- it lists every
297
- // branch on GitHub and would bloat worker-status.json for no reader.
260
+ // trackedNames is returned alongside the summary rather than folded into it:
261
+ // it is a working set for pushSettingsBranches' stranded-branch check, and
262
+ // listing every branch on GitHub would bloat worker-status.json for no reader.
298
263
  return {
299
264
  summary: { created, fastForwarded, ahead, diverged, rewritten },
300
265
  trackedNames: new Set(tracked.keys()),
@@ -312,24 +277,21 @@ export async function syncGit(ctx) {
312
277
  // is inactivity-based, so a slow-but-flowing transfer is unaffected.
313
278
  timeout: { block: ctx.taskTimeoutMs },
314
279
  });
315
- // This instance also drives pushSettingsBranches(git) below, whose
316
- // classification of a rejected settings-branch push (see that method)
317
- // needs the same stable-English guarantee as pushBranchToGitHub. Network
318
- // env for the same reason: the fetch and push here reach GitHub.
280
+ // gitNetworkChildEnv because the fetch and push here reach GitHub, and
281
+ // because pushSettingsBranches(git) below needs its stable-English guarantee
282
+ // to classify a rejected settings-branch push.
319
283
  git.env(gitNetworkChildEnv());
320
- // PR-W1: the whole cycle is wrapped so both outcomes -- success and
321
- // hard failure (e.g. the fetch throwing against a poisoned remote.git)
322
- // -- record a worker-status.json snapshot. The status write itself is
323
- // always best-effort (.catch below): it must never turn an otherwise
324
- // successful cycle into a failure, and must never mask the real error
325
- // on a failed one. On failure we rethrow so scheduleLoop's existing
284
+ // The whole cycle is wrapped so both outcomes -- success and hard failure
285
+ // (e.g. the fetch throwing against a poisoned remote.git) -- record a
286
+ // worker-status.json snapshot. The status write itself is always best-effort
287
+ // (.catch below): it must never turn a successful cycle into a failure, nor
288
+ // mask the real error on a failed one. Failures rethrow, so scheduleLoop's
326
289
  // per-cycle catch stays the loud path.
327
290
  try {
328
- // Fetch all branches from GitHub using direct URL (no named remote),
329
- // into the GITHUB_TRACKING_REF_PREFIX remote-tracking namespace rather
330
- // than refs/heads/* directly -- see that constant's doc comment for
331
- // the destructive-fetch bug this avoids. We use raw git commands since
332
- // simple-git's fetch() with a URL doesn't support --prune directly.
291
+ // Direct URL (no named remote), into the GITHUB_TRACKING_REF_PREFIX
292
+ // remote-tracking namespace rather than refs/heads/* -- see that constant's
293
+ // doc comment for the destructive-fetch bug this avoids. Raw git, because
294
+ // simple-git's fetch() with a URL does not support --prune.
333
295
  await git.raw([
334
296
  'fetch',
335
297
  await ctx.buildGitHubUrl(),
@@ -337,9 +299,6 @@ export async function syncGit(ctx) {
337
299
  `+refs/heads/*:${GITHUB_TRACKING_REF_PREFIX}*`,
338
300
  ]);
339
301
  workerLog('Fetched from GitHub');
340
- // Bring refs/heads/* toward what was just fetched, WITHOUT ever
341
- // force-rewinding or deleting a local head -- see
342
- // reconcileTrackedBranches()'s doc comment.
343
302
  const { summary: trackedSummary, trackedNames } = await reconcileTrackedBranches(ctx, git);
344
303
  // Push settings branches to GitHub (belt-and-suspenders for task queue).
345
304
  // Ensures settings reach GitHub even if a task queue entry is lost.
@@ -349,12 +308,11 @@ export async function syncGit(ctx) {
349
308
  await pushSettingsBranches(ctx, git, trackedNames);
350
309
  await refreshBaseBranchWorkspace(ctx);
351
310
  const rebaseSummary = await runRebaseCycle(ctx);
352
- // Periodically clean up old completed/failed tasks
353
311
  await cleanupOldTasks(ctx.taskDir, undefined, ctx.log);
354
- // [C1] Sweep branch directories the admin purge action trashed more
355
- // than TRASH_RETENTION_MS ago. Worker-only by design: purge itself
356
- // never deletes anything (reversible), and this cycle is the sole
357
- // place actual removal happens.
312
+ // [C1] Sweep branch directories the admin purge action trashed more than
313
+ // TRASH_RETENTION_MS ago. Worker-only by design: purge itself never deletes
314
+ // anything (it stays reversible), and this is the sole place removal
315
+ // actually happens.
358
316
  const trashRemoved = await cleanupTrashedBranchDirs(ctx);
359
317
  if (trashRemoved > 0) {
360
318
  workerLog(`Removed ${trashRemoved} expired trashed branch dir(s)`);
@@ -386,14 +344,12 @@ export async function syncGit(ctx) {
386
344
  }
387
345
  }
388
346
  /**
389
- * [C1] Remove `.trash-*` branch directories (created by the admin purge
390
- * action, api/admin-branch-health.ts) whose name-embedded stamp is older
391
- * than {@link TRASH_RETENTION_MS}. Names that don't match the expected
392
- * `.trash-{dirName}-{STAMP}` shape, or whose stamp fails to parse, are
393
- * left alone (logged once per cycle, not per file, to avoid flooding logs
394
- * if something odd accumulates) -- purge is the only writer of this
395
- * naming scheme, so an unparseable name is unexpected and worth a human
396
- * looking rather than a silent skip.
347
+ * [C1] Remove `.trash-*` branch directories (created by the admin purge action,
348
+ * api/admin-branch-health.ts) whose name-embedded stamp is older than
349
+ * {@link TRASH_RETENTION_MS}. A name that doesn't match `.trash-{dirName}-
350
+ * {STAMP}`, or whose stamp fails to parse, is left alone and logged once per
351
+ * cycle: purge is the only writer of this naming scheme, so an unparseable name
352
+ * is unexpected and worth a human looking rather than a silent skip.
397
353
  */
398
354
  export async function cleanupTrashedBranchDirs(ctx) {
399
355
  let entries;
@@ -439,24 +395,17 @@ export async function cleanupTrashedBranchDirs(ctx) {
439
395
  }
440
396
  /**
441
397
  * Fast-forward the base branch's own working-tree clone
442
- * (content-branches/<baseBranch>) to match origin/<baseBranch>.
398
+ * (content-branches/<baseBranch>) to match origin/<baseBranch>, every sync
399
+ * cycle, so the drift window is bounded by gitSyncInterval.
443
400
  *
444
- * Previously this clone was refreshed only incidentally, by the generic
445
- * rebase loop below (rebaseActiveBranches): for a branch with status
446
- * 'editing', rebasing onto origin/<baseBranch> degenerates to a
447
- * fast-forward when the clone IS the base branch. But that loop's skip
448
- * paths -- a dirty tree, a missing .git -- are silent, which is the
449
- * suspected live failure mode: a wedged base clone with no diagnosable
450
- * signal in the logs. This dedicated step makes the refresh explicit,
451
- * ff-only, and loud, so a stuck base view (an editor forking a new branch
452
- * "from base" that's actually a stale snapshot) is diagnosable from logs.
453
- * This runs every sync cycle so the drift window is bounded by
454
- * gitSyncInterval.
401
+ * A dedicated, explicit and LOUD step rather than a side effect of the rebase
402
+ * loop, whose skip paths (a dirty tree, a missing .git) are silent: a wedged
403
+ * base clone otherwise leaves no diagnosable signal, and an editor forking a
404
+ * new branch "from base" silently gets a stale snapshot.
455
405
  *
456
406
  * ff-only on purpose: this clone must stay a linear mirror of
457
- * origin/<baseBranch>, so a merge that isn't a fast-forward (diverged
458
- * local history) is treated as a should-never-happen condition and left
459
- * untouched rather than force-resolved.
407
+ * origin/<baseBranch>, so a merge that isn't a fast-forward (diverged local
408
+ * history) is left untouched rather than force-resolved.
460
409
  */
461
410
  export async function refreshBaseBranchWorkspace(ctx) {
462
411
  // Sanitized name for the workspace directory (a base branch containing
@@ -478,28 +427,22 @@ export async function refreshBaseBranchWorkspace(ctx) {
478
427
  const baseGit = simpleGit({
479
428
  baseDir: basePath,
480
429
  // Keep git non-interactive during the merge so it never blocks on an
481
- // editor. simple-git >=3.32 blocks setting core.editor unless
482
- // explicitly opted in; the value here is a hardcoded literal
483
- // ("true", the shell no-op), not user input, so enabling
484
- // allowUnsafeEditor carries no injection risk (same as the rebase
485
- // loop's git config below).
430
+ // editor. simple-git >=3.32 requires opting in to set core.editor; the
431
+ // value is a hardcoded literal ("true", the shell no-op), not user input,
432
+ // so allowUnsafeEditor carries no injection risk here.
486
433
  config: ['core.editor=true'],
487
434
  unsafe: { allowUnsafeEditor: true },
488
- // DEP-H1: a hung fetch/merge against this EFS-backed clone would
489
- // stall the sync loop forever (scheduleLoop only reschedules after
490
- // completion). The block timeout is inactivity-based, so a
491
- // slow-but-flowing transfer is unaffected -- same as syncGit()'s
492
- // remote handle.
435
+ // DEP-H1: a hung fetch/merge against this EFS-backed clone would stall
436
+ // the sync loop forever (scheduleLoop only reschedules after completion).
437
+ // Inactivity-based, so a slow-but-flowing transfer is unaffected.
493
438
  timeout: { block: ctx.taskTimeoutMs },
494
439
  });
495
- // Nothing makes this clone read-only. A direct edit here (or a stray
496
- // process) wedges every editor's view of the base branch until an
497
- // operator intervenes, so a dirty tree is loud, not a quiet skip.
498
- // Only TRACKED changes block the refresh: a stray untracked file (e.g.
499
- // runtime metadata missing from .git/info/exclude) must not wedge the
500
- // fast-forward forever — if an untracked file would collide with
501
- // incoming content, the --ff-only merge below refuses on its own and
502
- // that failure is already logged loudly.
440
+ // Nothing makes this clone read-only, and a direct edit here wedges every
441
+ // editor's view of the base branch until an operator intervenes, so a dirty
442
+ // tree is loud, not a quiet skip. Only TRACKED changes block the refresh: a
443
+ // stray untracked file must not wedge the fast-forward forever, and if one
444
+ // would collide with incoming content the --ff-only merge below refuses on
445
+ // its own and that failure is already logged loudly.
503
446
  const status = await baseGit.status();
504
447
  const trackedDirty = status.files.filter((f) => f.index !== '?' || f.working_dir !== '?');
505
448
  if (trackedDirty.length > 0) {
@@ -510,16 +453,12 @@ export async function refreshBaseBranchWorkspace(ctx) {
510
453
  // against origin/<baseBranch>, not filesystem paths, so they must use
511
454
  // the same name GitHub knows the branch by.
512
455
  await baseGit.fetch('origin', ctx.baseBranch);
513
- // Use rev-list instead of status.behind for the same reason as the
514
- // rebase loop below: status.behind only works with an upstream
515
- // tracking branch configured, which isn't guaranteed here.
516
- // Compare against the just-fetched tip rather than origin/<base>:
517
- // workspaces are cloned --single-branch (git-manager.ts), so their
518
- // fetch refspec only materializes a remote-tracking ref for the branch
519
- // they were cloned from — for any other base branch, origin/<base>
520
- // simply never exists and rev-list dies with "ambiguous argument".
521
- // Pin FETCH_HEAD to a SHA immediately: FETCH_HEAD is one shared mutable
522
- // file per repo, silently repointed by ANY other fetch in this clone.
456
+ // rev-list, not status.behind, which needs an upstream tracking branch that
457
+ // is not guaranteed here. Against the just-fetched tip rather than
458
+ // origin/<base>: workspaces are cloned --single-branch (git-manager.ts), so
459
+ // for any other base branch origin/<base> never exists and rev-list dies
460
+ // with "ambiguous argument". Pin FETCH_HEAD to a SHA immediately -- it is
461
+ // one shared mutable file per repo, silently repointed by any other fetch.
523
462
  const fetchedTip = (await baseGit.revparse(['FETCH_HEAD'])).trim();
524
463
  const behindCount = parseInt((await baseGit.raw(['rev-list', '--count', `HEAD..${fetchedTip}`])).trim(), 10);
525
464
  if (behindCount > 0) {
@@ -533,11 +472,10 @@ export async function refreshBaseBranchWorkspace(ctx) {
533
472
  await invalidateBranchContentCaches(basePath);
534
473
  }
535
474
  // Hygiene: conflictStatus/conflictFiles are meaningless for the base
536
- // branch's own metadata and may be left over from before the base was
537
- // excluded from rebaseActiveBranches()'s conflict-resolution loop.
538
- // Reuse the already-clean no-op-save guard from that loop: save()
539
- // eager-regenerates the branch registry (O(branch count) EFS reads),
540
- // so skip it when there's nothing to clear.
475
+ // branch's own metadata, which is excluded from the rebase loop's
476
+ // conflict-resolution pass. Guarded on already-clean, like that loop:
477
+ // save() eager-regenerates the branch registry (O(branch count) EFS reads),
478
+ // so skip it when there is nothing to clear.
541
479
  const currentMeta = await BranchMetadataFileManager.loadOnly(basePath);
542
480
  const conflictStatus = currentMeta?.branch.conflictStatus;
543
481
  const conflictFiles = currentMeta?.branch.conflictFiles;
@@ -192,6 +192,7 @@ export declare function resolveWorkerGitHubAuth(config: GitHubAuthConfig): Resol
192
192
  * A named class rather than a bare Error because `isTransientAuthFailure`
193
193
  * below has to recognise it: a timeout carries no HTTP status, and the
194
194
  * fail-closed rule there would otherwise read "slow network" as "wrong key".
195
+ * @internal Exported for tests.
195
196
  */
196
197
  export declare class MintTimeoutError extends Error {
197
198
  constructor(timeoutMs: number);
@@ -244,25 +245,18 @@ export declare function isTransientAuthFailure(err: unknown): boolean;
244
245
  * is configured, naming the key — rather than surfacing later as an opaque
245
246
  * JWT signing failure.
246
247
  *
247
- * The PKCS#1 → PKCS#8 conversion is INSURANCE, not a fix for a current
248
- * failure. GitHub issues App keys as PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`),
249
- * and whether that is accepted depends on which build of
250
- * `universal-github-app-jwt` a bundler resolves, never on the key:
251
- * - At the pin we install (`@octokit/auth-app@6` → `universal-github-app-jwt@1.2.0`,
252
- * which has no `exports` field) the worker's own flags,
253
- * `esbuild --platform=node --format=esm`, resolve `main` → the `dist-node`
254
- * build, which signs via `jsonwebtoken` and takes PKCS#1 happily. Measured
255
- * by bundling with exactly those flags: an unconverted key works.
256
- * - That same package's `module`/`browser` entry is a WebCrypto build that
257
- * throws "Private Key is in PKCS#1 format, but only PKCS#8 is supported".
258
- * Any resolver preferring `module` reaches it.
259
- * - Per their published package.json files (neither is installed here),
260
- * `@octokit/auth-app@7` moves to `universal-github-app-jwt@2`, which is
261
- * WebCrypto-only and converts PKCS#1 solely under the **`node` condition of
262
- * its `imports` map** (`"#crypto"` → `lib/crypto-node.js`); the `default`
263
- * sibling's `convertPrivateKey` is a literal no-op, and the key throws.
264
- *
265
- * So a bundler flag or a dependency bump can turn a working key into a boot
248
+ * The PKCS#1 → PKCS#8 conversion is INSURANCE, not a fix for a current failure.
249
+ * GitHub issues App keys as PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), and
250
+ * whether that is accepted depends on which build of `universal-github-app-jwt`
251
+ * a bundler resolves, never on the key: at the pin we install
252
+ * (`@octokit/auth-app@6` → `universal-github-app-jwt@1.2.0`, no `exports`
253
+ * field) the worker's `esbuild --platform=node --format=esm` reaches `main` →
254
+ * the `dist-node` build, which signs via `jsonwebtoken` and takes PKCS#1; that
255
+ * same package's `module`/`browser` entry is a WebCrypto build that rejects it;
256
+ * and `universal-github-app-jwt@2` (what `@octokit/auth-app@7` pulls in) is
257
+ * WebCrypto-only, converting PKCS#1 solely under the `node` condition of its
258
+ * `imports` map, its `default` sibling's `convertPrivateKey` being a no-op. So
259
+ * a bundler flag or a dependency bump can turn a working key into a boot
266
260
  * failure without the key changing. Three lines here remove that coupling.
267
261
  */
268
262
  export declare function normalizeGitHubAppPrivateKey(privateKey: string): string;
@@ -232,6 +232,7 @@ async function mintInstallationToken(app, timeoutMs) {
232
232
  * A named class rather than a bare Error because `isTransientAuthFailure`
233
233
  * below has to recognise it: a timeout carries no HTTP status, and the
234
234
  * fail-closed rule there would otherwise read "slow network" as "wrong key".
235
+ * @internal Exported for tests.
235
236
  */
236
237
  export class MintTimeoutError extends Error {
237
238
  constructor(timeoutMs) {
@@ -343,25 +344,18 @@ function getHttpStatus(err) {
343
344
  * is configured, naming the key — rather than surfacing later as an opaque
344
345
  * JWT signing failure.
345
346
  *
346
- * The PKCS#1 → PKCS#8 conversion is INSURANCE, not a fix for a current
347
- * failure. GitHub issues App keys as PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`),
348
- * and whether that is accepted depends on which build of
349
- * `universal-github-app-jwt` a bundler resolves, never on the key:
350
- * - At the pin we install (`@octokit/auth-app@6` → `universal-github-app-jwt@1.2.0`,
351
- * which has no `exports` field) the worker's own flags,
352
- * `esbuild --platform=node --format=esm`, resolve `main` → the `dist-node`
353
- * build, which signs via `jsonwebtoken` and takes PKCS#1 happily. Measured
354
- * by bundling with exactly those flags: an unconverted key works.
355
- * - That same package's `module`/`browser` entry is a WebCrypto build that
356
- * throws "Private Key is in PKCS#1 format, but only PKCS#8 is supported".
357
- * Any resolver preferring `module` reaches it.
358
- * - Per their published package.json files (neither is installed here),
359
- * `@octokit/auth-app@7` moves to `universal-github-app-jwt@2`, which is
360
- * WebCrypto-only and converts PKCS#1 solely under the **`node` condition of
361
- * its `imports` map** (`"#crypto"` → `lib/crypto-node.js`); the `default`
362
- * sibling's `convertPrivateKey` is a literal no-op, and the key throws.
363
- *
364
- * So a bundler flag or a dependency bump can turn a working key into a boot
347
+ * The PKCS#1 → PKCS#8 conversion is INSURANCE, not a fix for a current failure.
348
+ * GitHub issues App keys as PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`), and
349
+ * whether that is accepted depends on which build of `universal-github-app-jwt`
350
+ * a bundler resolves, never on the key: at the pin we install
351
+ * (`@octokit/auth-app@6` → `universal-github-app-jwt@1.2.0`, no `exports`
352
+ * field) the worker's `esbuild --platform=node --format=esm` reaches `main` →
353
+ * the `dist-node` build, which signs via `jsonwebtoken` and takes PKCS#1; that
354
+ * same package's `module`/`browser` entry is a WebCrypto build that rejects it;
355
+ * and `universal-github-app-jwt@2` (what `@octokit/auth-app@7` pulls in) is
356
+ * WebCrypto-only, converting PKCS#1 solely under the `node` condition of its
357
+ * `imports` map, its `default` sibling's `convertPrivateKey` being a no-op. So
358
+ * a bundler flag or a dependency bump can turn a working key into a boot
365
359
  * failure without the key changing. Three lines here remove that coupling.
366
360
  */
367
361
  export function normalizeGitHubAppPrivateKey(privateKey) {