@wp-typia/project-tools 0.23.0 → 0.24.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 (228) hide show
  1. package/dist/runtime/ai-feature-artifacts.js +4 -1
  2. package/dist/runtime/block-generator-service-spec.js +2 -1
  3. package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
  4. package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
  5. package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
  6. package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
  7. package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
  8. package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
  9. package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
  10. package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
  11. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
  12. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
  13. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
  14. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
  15. package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
  16. package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
  17. package/dist/runtime/cli-add-block-json.js +5 -1
  18. package/dist/runtime/cli-add-collision.js +8 -0
  19. package/dist/runtime/cli-add-help.js +14 -10
  20. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  21. package/dist/runtime/cli-add-kind-ids.js +1 -0
  22. package/dist/runtime/cli-add-types.d.ts +45 -6
  23. package/dist/runtime/cli-add-types.js +2 -0
  24. package/dist/runtime/cli-add-validation.d.ts +7 -0
  25. package/dist/runtime/cli-add-validation.js +9 -0
  26. package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
  27. package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
  28. package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
  29. package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
  30. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
  31. package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -308
  32. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +6 -2
  33. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
  34. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
  35. package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
  36. package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
  37. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
  38. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
  39. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
  40. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
  41. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
  42. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
  43. package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +18 -27
  44. package/dist/runtime/cli-add-workspace-admin-view-templates.js +30 -1326
  45. package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
  46. package/dist/runtime/cli-add-workspace-ai-anchors.js +8 -233
  47. package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
  48. package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
  49. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -129
  50. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
  51. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
  52. package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
  53. package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
  54. package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
  55. package/dist/runtime/cli-add-workspace-assets.js +6 -950
  56. package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
  57. package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
  58. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
  59. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
  60. package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
  61. package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
  62. package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
  63. package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
  64. package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
  65. package/dist/runtime/cli-add-workspace-block-style.js +148 -0
  66. package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
  67. package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
  68. package/dist/runtime/cli-add-workspace-contract.js +1 -1
  69. package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
  70. package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
  71. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
  72. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
  73. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
  74. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
  75. package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
  76. package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
  77. package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
  78. package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
  79. package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
  80. package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
  81. package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
  82. package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
  83. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
  84. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
  85. package/dist/runtime/cli-add-workspace-integration-env.d.ts +3 -1
  86. package/dist/runtime/cli-add-workspace-integration-env.js +10 -313
  87. package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
  88. package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
  89. package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
  90. package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
  91. package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
  92. package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
  93. package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
  94. package/dist/runtime/cli-add-workspace-pattern.js +99 -0
  95. package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
  96. package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
  97. package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
  98. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +9 -4
  99. package/dist/runtime/cli-add-workspace-rest-anchors.js +9 -428
  100. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
  101. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
  102. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
  103. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
  104. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
  105. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
  106. package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
  107. package/dist/runtime/cli-add-workspace-rest-generated.js +160 -0
  108. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
  109. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
  110. package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
  111. package/dist/runtime/cli-add-workspace-rest-manual.js +266 -0
  112. package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +18 -0
  113. package/dist/runtime/cli-add-workspace-rest-php-templates.js +359 -0
  114. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
  115. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
  116. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
  117. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
  118. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
  119. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
  120. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -91
  121. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -642
  122. package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
  123. package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
  124. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
  125. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
  126. package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
  127. package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
  128. package/dist/runtime/cli-add-workspace-rest.d.ts +3 -20
  129. package/dist/runtime/cli-add-workspace-rest.js +33 -788
  130. package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
  131. package/dist/runtime/cli-add-workspace-variation.js +162 -0
  132. package/dist/runtime/cli-add-workspace.d.ts +42 -107
  133. package/dist/runtime/cli-add-workspace.js +42 -674
  134. package/dist/runtime/cli-add.d.ts +3 -3
  135. package/dist/runtime/cli-add.js +2 -2
  136. package/dist/runtime/cli-core.d.ts +3 -2
  137. package/dist/runtime/cli-core.js +2 -2
  138. package/dist/runtime/cli-diagnostics.d.ts +3 -1
  139. package/dist/runtime/cli-diagnostics.js +17 -5
  140. package/dist/runtime/cli-doctor-workspace-bindings.js +63 -1
  141. package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
  142. package/dist/runtime/cli-doctor-workspace-block-addons.js +162 -0
  143. package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
  144. package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
  145. package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
  146. package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
  147. package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
  148. package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
  149. package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
  150. package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
  151. package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
  152. package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
  153. package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
  154. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
  155. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
  156. package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
  157. package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
  158. package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
  159. package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
  160. package/dist/runtime/cli-doctor-workspace-features.js +14 -487
  161. package/dist/runtime/cli-doctor.d.ts +54 -3
  162. package/dist/runtime/cli-doctor.js +92 -10
  163. package/dist/runtime/cli-help.js +12 -7
  164. package/dist/runtime/cli-init-package-json.js +4 -2
  165. package/dist/runtime/cli-prompt.d.ts +16 -2
  166. package/dist/runtime/cli-prompt.js +29 -12
  167. package/dist/runtime/cli-scaffold.d.ts +2 -1
  168. package/dist/runtime/cli-scaffold.js +19 -10
  169. package/dist/runtime/external-template-guards.js +4 -6
  170. package/dist/runtime/index.d.ts +6 -3
  171. package/dist/runtime/index.js +4 -2
  172. package/dist/runtime/json-utils.d.ts +62 -4
  173. package/dist/runtime/json-utils.js +78 -4
  174. package/dist/runtime/local-dev-presets.js +6 -2
  175. package/dist/runtime/migration-ui-capability.js +4 -1
  176. package/dist/runtime/migration-utils.js +4 -1
  177. package/dist/runtime/package-managers.js +6 -1
  178. package/dist/runtime/package-versions.d.ts +1 -0
  179. package/dist/runtime/package-versions.js +16 -3
  180. package/dist/runtime/pattern-catalog.d.ts +122 -0
  181. package/dist/runtime/pattern-catalog.js +471 -0
  182. package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
  183. package/dist/runtime/post-meta-binding-fields.js +135 -0
  184. package/dist/runtime/scaffold-bootstrap.js +7 -2
  185. package/dist/runtime/scaffold-package-manager-files.js +5 -1
  186. package/dist/runtime/scaffold-repository-reference.js +4 -2
  187. package/dist/runtime/scaffold-template-variables.js +2 -1
  188. package/dist/runtime/scaffold.d.ts +18 -1
  189. package/dist/runtime/scaffold.js +55 -2
  190. package/dist/runtime/temp-roots.js +4 -1
  191. package/dist/runtime/template-layers.js +4 -1
  192. package/dist/runtime/template-registry.js +9 -3
  193. package/dist/runtime/template-source-contracts.d.ts +2 -0
  194. package/dist/runtime/template-source-normalization.js +2 -1
  195. package/dist/runtime/template-source-remote.js +18 -5
  196. package/dist/runtime/template-source-seeds.js +10 -3
  197. package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
  198. package/dist/runtime/typia-llm-json-schema.js +33 -0
  199. package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
  200. package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
  201. package/dist/runtime/typia-llm-projection.d.ts +25 -0
  202. package/dist/runtime/typia-llm-projection.js +58 -0
  203. package/dist/runtime/typia-llm-render.d.ts +21 -0
  204. package/dist/runtime/typia-llm-render.js +252 -0
  205. package/dist/runtime/typia-llm-sync.d.ts +10 -0
  206. package/dist/runtime/typia-llm-sync.js +63 -0
  207. package/dist/runtime/typia-llm-types.d.ts +197 -0
  208. package/dist/runtime/typia-llm-types.js +1 -0
  209. package/dist/runtime/typia-llm.d.ts +9 -255
  210. package/dist/runtime/typia-llm.js +5 -634
  211. package/dist/runtime/workspace-inventory-mutations.js +15 -1
  212. package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
  213. package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
  214. package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
  215. package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
  216. package/dist/runtime/workspace-inventory-parser.d.ts +3 -45
  217. package/dist/runtime/workspace-inventory-parser.js +3 -581
  218. package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
  219. package/dist/runtime/workspace-inventory-section-descriptors.js +443 -0
  220. package/dist/runtime/workspace-inventory-templates.d.ts +3 -3
  221. package/dist/runtime/workspace-inventory-templates.js +10 -1
  222. package/dist/runtime/workspace-inventory-types.d.ts +10 -1
  223. package/dist/runtime/workspace-project.js +4 -6
  224. package/package.json +8 -3
  225. package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
  226. package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
  227. package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
  228. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
@@ -8,15 +8,17 @@ export function formatAddHelpText() {
8
8
  return `Usage:
9
9
  wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>] [--dry-run]
10
10
  wp-typia add block <name> [--template <${ADD_BLOCK_TEMPLATE_IDS.join("|")}>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--dry-run]
11
- wp-typia add integration-env <name> [--wp-env] [--service <none|docker-compose>] [--dry-run]
12
- wp-typia add variation <name> --block <block-slug> [--dry-run]
13
- wp-typia add style <name> --block <block-slug> [--dry-run]
14
- wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug> [--dry-run]
15
- wp-typia add pattern <name> [--dry-run]
16
- wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--dry-run]
11
+ wp-typia add integration-env <name> [--wp-env] [--release-zip] [--service <none|docker-compose>] [--dry-run]
12
+ wp-typia add core-variation <block-name> <name> [--dry-run]
13
+ wp-typia add core-variation <name> --block <namespace/block> [--dry-run]
14
+ wp-typia add variation <name> --block <block-slug> [--dry-run]
15
+ wp-typia add style <name> --block <block-slug> [--dry-run]
16
+ wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug> [--dry-run]
17
+ wp-typia add pattern <name> [--scope <full|section>] [--section-role <role>] [--tags <tag,...>] [--thumbnail-url <url>] [--dry-run]
18
+ wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--from-post-meta|--post-meta <post-meta> [--meta-path <field>]] [--dry-run]
17
19
  wp-typia add contract <name> [--type <ExportedTypeName>] [--dry-run]
18
20
  wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <${REST_RESOURCE_METHOD_IDS.join(",")}>] [--route-pattern <route-pattern>] [--permission-callback <callback>] [--controller-class <ClassName>] [--controller-extends <BaseClass>] [--dry-run]
19
- wp-typia add rest-resource <name> --manual [--namespace <vendor/v1>] [--method <GET|POST|PUT|PATCH|DELETE>] [--auth <public|authenticated|public-write-protected>] [--path <route-pattern>] [--query-type <Type>] [--body-type <Type>] [--response-type <Type>] [--dry-run]
21
+ wp-typia add rest-resource <name> --manual [--namespace <vendor/v1>] [--method <GET|POST|PUT|PATCH|DELETE>] [--auth <public|authenticated|public-write-protected>] [--path <route-pattern>|--route-pattern <route-pattern>] [--permission-callback <callback>] [--controller-class <ClassName>] [--controller-extends <BaseClass>] [--query-type <Type>] [--body-type <Type>] [--response-type <Type>] [--secret-field <field>] [--secret-state-field|--secret-has-value-field <field>] [--secret-preserve-on-empty <true|false>] [--dry-run]
20
22
  wp-typia add post-meta <name> --post-type <post-type> [--type <ExportedTypeName>] [--meta-key <meta-key>] [--hide-from-rest] [--dry-run]
21
23
  wp-typia add ability <name> [--dry-run]
22
24
  wp-typia add ai-feature <name> [--namespace <vendor/v1>] [--dry-run]
@@ -27,21 +29,23 @@ Notes:
27
29
  \`wp-typia add\` runs only inside official ${WORKSPACE_TEMPLATE_PACKAGE} workspaces scaffolded via \`wp-typia create <project-dir> --template workspace\`.
28
30
  Pass \`--dry-run\` to preview the workspace files that would change without writing them.
29
31
  Interactive add flows let you choose a template when \`--template\` is omitted; non-interactive runs default to \`basic\`.
32
+ \`add core-variation\` registers editor-side variations for existing core or external blocks without generating block.json or Typia manifests.
30
33
  \`add admin-view\` scaffolds an opt-in DataViews-powered WordPress admin screen under \`src/admin-views/\`.
31
34
  Pass \`--source rest-resource:<slug>\` to reuse a list-capable REST resource.
32
35
  Pass \`--source core-data:postType/post\` or \`--source core-data:taxonomy/category\` to bind a WordPress-owned entity collection.
33
36
  Generated admin-view workspaces add \`@wp-typia/dataviews\` and the needed WordPress DataViews packages as opt-in dependencies.
34
37
  \`add integration-env\` generates an opt-in local smoke starter under \`scripts/integration-smoke/\`, updates \`.env.example\`, and can add \`@wordpress/env\` plus \`.wp-env.json\` when \`--wp-env\` is passed.
38
+ Pass \`--release-zip\` to add \`release:zip\`, \`release:zip:check\`, and \`qa:check\` scripts for plugin QA packaging.
35
39
  Pass \`--service docker-compose\` to include a placeholder local service stack that can be adapted to project-specific dependencies.
36
40
  \`query-loop\` is a create-time scaffold family. Use \`wp-typia create <project-dir> --template query-loop\` instead of \`wp-typia add block\`.
37
41
  \`add variation\` targets an existing block slug from \`scripts/block-config.ts\`.
38
42
  \`add style\` registers a Block Styles option for an existing generated block.
39
43
  \`add transform\` adds a block-to-block transform into an existing generated block.
40
- \`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/\`.
41
- \`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`; pass \`--block\` and \`--attribute\` together to declare an end-to-end bindable attribute on an existing generated block.
44
+ \`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/full/\` or \`src/patterns/sections/\` and records typed catalog metadata in \`PATTERNS\`.
45
+ \`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`; pass \`--block\` and \`--attribute\` together to declare an end-to-end bindable attribute on an existing generated block. Pass \`--from-post-meta\` or \`--post-meta\` to generate a source backed by a typed post-meta contract; \`--meta-path\` selects one top-level field as the default binding arg.
42
46
  \`add contract\` registers a standalone TypeScript wire contract under \`src/contracts/\` and generates a stable JSON Schema artifact without creating PHP route glue.
43
47
  \`add rest-resource\` scaffolds plugin-level TypeScript REST contracts under \`src/rest/\` and PHP route glue under \`inc/rest/\`. Use \`--route-pattern\`, \`--permission-callback\`, \`--controller-class\`, and \`--controller-extends\` when an existing WordPress controller or permission model needs to own part of the generated route surface.
44
- Pass \`--manual\` with \`add rest-resource\` to track an external REST route with typed schemas, OpenAPI, clients, and drift checks without generating PHP route/controller files.
48
+ Pass \`--manual\` with \`add rest-resource\` to track an external/provider REST route with typed schemas, OpenAPI, clients, and drift checks without generating PHP route/controller files. Manual routes may still declare \`--permission-callback\`, \`--controller-class\`, and \`--controller-extends\` as metadata for the route owner. Settings contracts can add \`--secret-field\` with \`--secret-preserve-on-empty\` metadata so generated schemas, clients, and admin forms treat blank secret submissions as preserve-by-default.
45
49
  \`add post-meta\` scaffolds a typed post meta contract under \`src/post-meta/\`, generates a schema artifact, and wires \`register_post_meta()\` helpers under \`inc/post-meta/\`.
46
50
  \`add ability\` scaffolds typed workflow abilities under \`src/abilities/\` and server registration under \`inc/abilities/\`.
47
51
  \`add ai-feature\` scaffolds server-owned AI feature endpoints under \`src/ai-features/\` and PHP route glue under \`inc/ai-features/\`.
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Keep this order stable because it drives help output and command metadata.
6
6
  */
7
- export declare const ADD_KIND_IDS: readonly ["admin-view", "block", "integration-env", "variation", "style", "transform", "pattern", "binding-source", "contract", "rest-resource", "post-meta", "ability", "ai-feature", "hooked-block", "editor-plugin"];
7
+ export declare const ADD_KIND_IDS: readonly ["admin-view", "block", "integration-env", "core-variation", "variation", "style", "transform", "pattern", "binding-source", "contract", "rest-resource", "post-meta", "ability", "ai-feature", "hooked-block", "editor-plugin"];
8
8
  /**
9
9
  * Union of supported top-level `wp-typia add` kind ids.
10
10
  */
@@ -8,6 +8,7 @@ export const ADD_KIND_IDS = [
8
8
  "admin-view",
9
9
  "block",
10
10
  "integration-env",
11
+ "core-variation",
11
12
  "variation",
12
13
  "style",
13
14
  "transform",
@@ -1,5 +1,8 @@
1
+ import { PATTERN_CATALOG_SCOPE_IDS, type PatternCatalogScope } from "./pattern-catalog.js";
1
2
  export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
2
3
  export type { AddKindId } from "./cli-add-kind-ids.js";
4
+ export { PATTERN_CATALOG_SCOPE_IDS };
5
+ export type { PatternCatalogScope };
3
6
  /**
4
7
  * Supported plugin-level REST resource methods accepted by
5
8
  * `wp-typia add rest-resource --methods`.
@@ -87,6 +90,18 @@ export interface RunAddVariationCommandOptions {
87
90
  cwd?: string;
88
91
  variationName: string;
89
92
  }
93
+ /**
94
+ * Options for `wp-typia add core-variation`.
95
+ *
96
+ * @property cwd Working directory used to resolve the nearest official workspace.
97
+ * @property targetBlockName Full `namespace/block` name that receives the variation.
98
+ * @property variationName Human-entered variation name normalized into a slug.
99
+ */
100
+ export interface RunAddCoreVariationCommandOptions {
101
+ cwd?: string;
102
+ targetBlockName: string;
103
+ variationName: string;
104
+ }
90
105
  /**
91
106
  * Options for `wp-typia add style`.
92
107
  *
@@ -126,8 +141,14 @@ export interface RunAddBlockTransformCommandOptions {
126
141
  * @property patternName Human-entered pattern name normalized into a slug.
127
142
  */
128
143
  export interface RunAddPatternCommandOptions {
144
+ catalogTitle?: string;
145
+ contentFile?: string;
129
146
  cwd?: string;
130
147
  patternName: string;
148
+ patternScope?: PatternCatalogScope | string;
149
+ sectionRole?: string;
150
+ tags?: readonly string[] | string;
151
+ thumbnailUrl?: string;
131
152
  }
132
153
  /**
133
154
  * Options for `wp-typia add binding-source`.
@@ -136,12 +157,18 @@ export interface RunAddPatternCommandOptions {
136
157
  * @property blockName Optional existing workspace block slug or full block name.
137
158
  * @property bindingSourceName Human-entered binding source name normalized into a slug.
138
159
  * @property cwd Working directory used to resolve the nearest official workspace.
160
+ * @property metaPath Optional top-level post-meta field used as the default
161
+ * source argument when `postMetaName` is provided.
162
+ * @property postMetaName Optional generated post-meta contract slug used to
163
+ * back the binding source with `get_post_meta()`.
139
164
  */
140
165
  export interface RunAddBindingSourceCommandOptions {
141
166
  attributeName?: string;
142
167
  blockName?: string;
143
168
  bindingSourceName: string;
144
169
  cwd?: string;
170
+ metaPath?: string;
171
+ postMetaName?: string;
145
172
  }
146
173
  /**
147
174
  * Options for `wp-typia add contract`.
@@ -189,17 +216,17 @@ export interface RunAddPostMetaCommandOptions {
189
216
  * @property auth Optional auth intent for manual mode. Defaults to public.
190
217
  * @property bodyTypeName Optional exported TypeScript body type for manual
191
218
  * mode. Defaults to `<PascalName>Request` for write methods.
192
- * @property controllerClass Optional generated REST controller class reference.
193
- * When present, route callbacks delegate through an instantiated controller.
219
+ * @property controllerClass Optional REST controller class reference. Generated
220
+ * routes delegate through it; manual/provider routes record it as owner metadata.
194
221
  * @property controllerExtends Optional base class for the generated controller
195
- * wrapper when `controllerClass` is a global class name.
222
+ * wrapper or declared manual/provider controller owner.
196
223
  * @property cwd Working directory used to resolve the nearest official workspace.
197
224
  * @property manual Whether to scaffold a type-only external REST contract.
198
225
  * @property method HTTP method for manual REST contract mode. Defaults to GET.
199
226
  * @property methods Optional comma-separated REST method list.
200
227
  * @property namespace Optional REST namespace, defaulting to the workspace namespace.
201
228
  * @property permissionCallback Optional PHP callback used for generated REST
202
- * route permission checks.
229
+ * route permission checks or declared manual/provider route ownership.
203
230
  * @property pathPattern Route path pattern for manual mode, relative to the
204
231
  * namespace. Defaults to `/<name>`.
205
232
  * @property queryTypeName Optional exported TypeScript query type for manual
@@ -207,10 +234,17 @@ export interface RunAddPostMetaCommandOptions {
207
234
  * @property restResourceName Human-entered resource name normalized into a slug.
208
235
  * @property responseTypeName Optional exported TypeScript response type for
209
236
  * manual mode. Defaults to `<PascalName>Response`.
210
- * @property routePattern Optional generated item route pattern, relative to the
211
- * namespace. Defaults to `/<name>/item`.
237
+ * @property routePattern Optional generated item route pattern, or manual
238
+ * provider-route alias for `pathPattern`, relative to the namespace.
239
+ * Generated mode defaults to `/<name>/item`; manual mode defaults to `/<name>`.
212
240
  * @property secretFieldName Optional write-only secret field name for manual
213
241
  * settings contracts. Requires a request body.
242
+ * @property secretHasValueFieldName Optional alias for `secretStateFieldName`
243
+ * when the response field is a safe presence indicator.
244
+ * @property secretMaskedResponseFieldName Optional alias for
245
+ * `secretStateFieldName` when the response field represents masked state.
246
+ * @property secretPreserveOnEmpty Whether blank secret submissions should
247
+ * preserve the existing value. Defaults to true when `secretFieldName` is set.
214
248
  * @property secretStateFieldName Optional masked response boolean field for
215
249
  * `secretFieldName`. Defaults to `has<PascalSecretField>`.
216
250
  */
@@ -231,6 +265,9 @@ export interface RunAddRestResourceCommandOptions {
231
265
  responseTypeName?: string;
232
266
  routePattern?: string;
233
267
  secretFieldName?: string;
268
+ secretHasValueFieldName?: string;
269
+ secretMaskedResponseFieldName?: string;
270
+ secretPreserveOnEmpty?: boolean;
234
271
  secretStateFieldName?: string;
235
272
  }
236
273
  /**
@@ -310,12 +347,14 @@ export interface RunAddEditorPluginCommandOptions {
310
347
  * @property integrationEnvName Human-entered environment name that will be
311
348
  * normalized into script and documentation paths.
312
349
  * @property service Optional local service starter. Defaults to `none`.
350
+ * @property withReleaseZip Whether to add release zip packaging scripts.
313
351
  * @property withWpEnv Whether to add a local `@wordpress/env` preset and scripts.
314
352
  */
315
353
  export interface RunAddIntegrationEnvCommandOptions {
316
354
  cwd?: string;
317
355
  integrationEnvName: string;
318
356
  service?: string;
357
+ withReleaseZip?: boolean;
319
358
  withWpEnv?: boolean;
320
359
  }
321
360
  /**
@@ -1,5 +1,7 @@
1
1
  import { suggestCloseId } from "./id-suggestions.js";
2
+ import { PATTERN_CATALOG_SCOPE_IDS, } from "./pattern-catalog.js";
2
3
  export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
4
+ export { PATTERN_CATALOG_SCOPE_IDS };
3
5
  /**
4
6
  * Supported plugin-level REST resource methods accepted by
5
7
  * `wp-typia add rest-resource --methods`.
@@ -110,6 +110,13 @@ export declare function assertValidManualRestContractAuth(auth?: string): Manual
110
110
  * @returns True when the pattern has no regex groups or uses only `(?P<id>...)`.
111
111
  */
112
112
  export declare function isGeneratedRestResourceRoutePatternCompatible(routePattern: string): boolean;
113
+ /**
114
+ * Collect unique WordPress named capture parameters from a REST route pattern.
115
+ *
116
+ * @param routePattern Route pattern relative to the namespace.
117
+ * @returns Capture names in first-seen order.
118
+ */
119
+ export declare function collectRestRouteNamedCaptureNames(routePattern: string): string[];
113
120
  export declare function resolveManualRestContractPathPattern(slug: string, pathPattern?: string): string;
114
121
  /**
115
122
  * Normalize and validate a generated REST resource item route pattern.
@@ -332,6 +332,15 @@ export function isGeneratedRestResourceRoutePatternCompatible(routePattern) {
332
332
  return (!hasUnsupportedCapture &&
333
333
  (!hasRegexGroup || (namedCaptures.length === 1 && namedCaptures[0] === "id")));
334
334
  }
335
+ /**
336
+ * Collect unique WordPress named capture parameters from a REST route pattern.
337
+ *
338
+ * @param routePattern Route pattern relative to the namespace.
339
+ * @returns Capture names in first-seen order.
340
+ */
341
+ export function collectRestRouteNamedCaptureNames(routePattern) {
342
+ return Array.from(new Set(Array.from(routePattern.matchAll(REST_ROUTE_NAMED_CAPTURE_PATTERN), (match) => match[1])));
343
+ }
335
344
  export function resolveManualRestContractPathPattern(slug, pathPattern) {
336
345
  return resolveRestRoutePathPattern({
337
346
  defaultPath: `/${slug}`,
@@ -0,0 +1,24 @@
1
+ import type { WorkspaceProject } from "./workspace-project.js";
2
+ /**
3
+ * Ensure the workspace bootstrap loads generated ability PHP modules and
4
+ * enqueues the generated ability editor script module.
5
+ */
6
+ export declare function ensureAbilityBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
7
+ /**
8
+ * Ensure ability package scripts and WordPress ability runtime dependencies
9
+ * are present without downgrading existing compatible ranges.
10
+ */
11
+ export declare function ensureAbilityPackageScripts(workspace: WorkspaceProject): Promise<void>;
12
+ /**
13
+ * Ensure `scripts/sync-project.ts` delegates to the generated ability sync
14
+ * script when present.
15
+ */
16
+ export declare function ensureAbilitySyncProjectAnchors(workspace: WorkspaceProject): Promise<void>;
17
+ /**
18
+ * Ensure the workspace build script includes optional ability client entries.
19
+ */
20
+ export declare function ensureAbilityBuildScriptAnchors(workspace: WorkspaceProject): Promise<void>;
21
+ /**
22
+ * Ensure webpack discovers the optional ability client registry bundle.
23
+ */
24
+ export declare function ensureAbilityWebpackAnchors(workspace: WorkspaceProject): Promise<void>;
@@ -0,0 +1,294 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import semver from "semver";
4
+ import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
5
+ import { ABILITY_EDITOR_ASSET, ABILITY_EDITOR_SCRIPT, ABILITY_SERVER_GLOB, WP_ABILITIES_SCRIPT_MODULE_ID, WP_CORE_ABILITIES_SCRIPT_MODULE_ID, } from "./cli-add-workspace-ability-types.js";
6
+ import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
7
+ import { readJsonFile } from "./json-utils.js";
8
+ import { DEFAULT_WORDPRESS_ABILITIES_VERSION, DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION, } from "./package-versions.js";
9
+ import { findPhpFunctionRange, hasPhpFunctionCall, hasPhpFunctionDefinition, replacePhpFunctionDefinition, } from "./php-utils.js";
10
+ function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
11
+ if (!existingVersion) {
12
+ return requiredVersion;
13
+ }
14
+ const existingMinimum = semver.minVersion(existingVersion);
15
+ const requiredMinimum = semver.minVersion(requiredVersion);
16
+ if (!existingMinimum || !requiredMinimum) {
17
+ return requiredVersion;
18
+ }
19
+ return semver.gte(existingMinimum, requiredMinimum)
20
+ ? existingVersion
21
+ : requiredVersion;
22
+ }
23
+ /**
24
+ * Ensure the workspace bootstrap loads generated ability PHP modules and
25
+ * enqueues the generated ability editor script module.
26
+ */
27
+ export async function ensureAbilityBootstrapAnchors(workspace) {
28
+ const bootstrapPath = getWorkspaceBootstrapPath(workspace);
29
+ await patchFile(bootstrapPath, (source) => {
30
+ let nextSource = source;
31
+ const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
32
+ const loadFunctionName = `${workspace.workspace.phpPrefix}_load_workflow_abilities`;
33
+ const enqueueFunctionName = `${workspace.workspace.phpPrefix}_enqueue_workflow_abilities`;
34
+ const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
35
+ const adminEnqueueHook = `add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );`;
36
+ const editorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
37
+ const loadFunction = `
38
+
39
+ function ${loadFunctionName}() {
40
+ \tforeach ( glob( __DIR__ . '${ABILITY_SERVER_GLOB}' ) ?: array() as $ability_module ) {
41
+ \t\trequire_once $ability_module;
42
+ \t}
43
+ }
44
+ `;
45
+ const enqueueFunction = `
46
+
47
+ function ${enqueueFunctionName}() {
48
+ \tif ( ! class_exists( 'WP_Ability' ) ) {
49
+ \t\treturn;
50
+ \t}
51
+
52
+ \t$script_path = __DIR__ . '/${ABILITY_EDITOR_SCRIPT}';
53
+ \t$asset_path = __DIR__ . '/${ABILITY_EDITOR_ASSET}';
54
+
55
+ \tif ( ! file_exists( $script_path ) || ! file_exists( $asset_path ) ) {
56
+ \t\treturn;
57
+ \t}
58
+
59
+ \t$asset = require $asset_path;
60
+ \tif ( ! is_array( $asset ) ) {
61
+ \t\t$asset = array();
62
+ \t}
63
+
64
+ \t$dependencies = isset( $asset['dependencies'] ) && is_array( $asset['dependencies'] )
65
+ \t\t? $asset['dependencies']
66
+ \t\t: array();
67
+
68
+ \tforeach ( array( '${WP_CORE_ABILITIES_SCRIPT_MODULE_ID}', '${WP_ABILITIES_SCRIPT_MODULE_ID}' ) as $ability_dependency ) {
69
+ \t\t$has_dependency = false;
70
+ \t\tforeach ( $dependencies as $dependency ) {
71
+ \t\t\t$dependency_id = is_array( $dependency ) && isset( $dependency['id'] )
72
+ \t\t\t\t? $dependency['id']
73
+ \t\t\t\t: $dependency;
74
+ \t\t\tif ( $dependency_id === $ability_dependency ) {
75
+ \t\t\t\t$has_dependency = true;
76
+ \t\t\t\tbreak;
77
+ \t\t\t}
78
+ \t\t}
79
+ \t\tif ( ! $has_dependency ) {
80
+ \t\t\t$dependencies[] = $ability_dependency;
81
+ \t\t}
82
+ \t}
83
+
84
+ \tif ( ! function_exists( 'wp_enqueue_script_module' ) ) {
85
+ \t\treturn;
86
+ \t}
87
+
88
+ \twp_enqueue_script_module(
89
+ \t\t'${workspaceBaseName}-abilities',
90
+ \t\tplugins_url( '${ABILITY_EDITOR_SCRIPT}', __FILE__ ),
91
+ \t\t$dependencies,
92
+ \t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path )
93
+ \t);
94
+ }
95
+ `;
96
+ if (!hasPhpFunctionDefinition(nextSource, loadFunctionName)) {
97
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, loadFunction);
98
+ }
99
+ if (!hasPhpFunctionDefinition(nextSource, enqueueFunctionName)) {
100
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, enqueueFunction);
101
+ }
102
+ else {
103
+ const functionRange = findPhpFunctionRange(nextSource, enqueueFunctionName);
104
+ const functionSource = functionRange
105
+ ? nextSource.slice(functionRange.start, functionRange.end)
106
+ : "";
107
+ if (!hasPhpFunctionCall(functionSource, "wp_enqueue_script_module")) {
108
+ const replacedSource = replacePhpFunctionDefinition(nextSource, enqueueFunctionName, enqueueFunction, { trimReplacementStart: true });
109
+ if (!replacedSource) {
110
+ throw new Error(`Unable to repair ${path.basename(bootstrapPath)} for ${enqueueFunctionName}.`);
111
+ }
112
+ nextSource = replacedSource;
113
+ }
114
+ }
115
+ if (!nextSource.includes(loadHook)) {
116
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, loadHook);
117
+ }
118
+ if (!nextSource.includes(adminEnqueueHook)) {
119
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, adminEnqueueHook);
120
+ }
121
+ if (!nextSource.includes(editorEnqueueHook)) {
122
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, editorEnqueueHook);
123
+ }
124
+ return nextSource;
125
+ });
126
+ }
127
+ /**
128
+ * Ensure ability package scripts and WordPress ability runtime dependencies
129
+ * are present without downgrading existing compatible ranges.
130
+ */
131
+ export async function ensureAbilityPackageScripts(workspace) {
132
+ const packageJsonPath = path.join(workspace.projectDir, "package.json");
133
+ const packageJson = await readJsonFile(packageJsonPath, {
134
+ context: "workspace package manifest",
135
+ });
136
+ const nextScripts = {
137
+ ...(packageJson.scripts ?? {}),
138
+ "sync-abilities": packageJson.scripts?.["sync-abilities"] ?? "tsx scripts/sync-abilities.ts",
139
+ };
140
+ const nextDependencies = {
141
+ ...(packageJson.dependencies ?? {}),
142
+ [WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_ABILITIES_VERSION),
143
+ [WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION),
144
+ };
145
+ if (JSON.stringify(nextScripts) === JSON.stringify(packageJson.scripts ?? {}) &&
146
+ JSON.stringify(nextDependencies) ===
147
+ JSON.stringify(packageJson.dependencies ?? {})) {
148
+ return;
149
+ }
150
+ packageJson.scripts = nextScripts;
151
+ packageJson.dependencies = nextDependencies;
152
+ await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
153
+ }
154
+ /**
155
+ * Ensure `scripts/sync-project.ts` delegates to the generated ability sync
156
+ * script when present.
157
+ */
158
+ export async function ensureAbilitySyncProjectAnchors(workspace) {
159
+ const syncProjectScriptPath = path.join(workspace.projectDir, "scripts", "sync-project.ts");
160
+ await patchFile(syncProjectScriptPath, (source) => {
161
+ let nextSource = source;
162
+ const syncRestConst = "const syncRestScriptPath = path.join( 'scripts', 'sync-rest-contracts.ts' );";
163
+ const syncAbilitiesConst = "const syncAbilitiesScriptPath = path.join( 'scripts', 'sync-abilities.ts' );";
164
+ const syncRestBlockPattern = /if \( fs\.existsSync\( path\.resolve\( process\.cwd\(\), syncRestScriptPath \) \) \) \{\n\s*runSyncScript\( syncRestScriptPath, options \);\n\s*\}/u;
165
+ const syncAbilitiesBlock = [
166
+ "if ( fs.existsSync( path.resolve( process.cwd(), syncAbilitiesScriptPath ) ) ) {",
167
+ "\trunSyncScript( syncAbilitiesScriptPath, options );",
168
+ "}",
169
+ ].join("\n");
170
+ if (!nextSource.includes(syncAbilitiesConst)) {
171
+ if (!nextSource.includes(syncRestConst)) {
172
+ throw new Error([
173
+ `ensureAbilitySyncProjectAnchors could not patch ${path.basename(syncProjectScriptPath)}.`,
174
+ "Missing the expected sync-rest script constant in scripts/sync-project.ts.",
175
+ "Restore the generated template or wire sync-abilities manually before retrying.",
176
+ ].join(" "));
177
+ }
178
+ nextSource = nextSource.replace(syncRestConst, `${syncRestConst}\n${syncAbilitiesConst}`);
179
+ }
180
+ if (!nextSource.includes("runSyncScript( syncAbilitiesScriptPath, options );")) {
181
+ if (!syncRestBlockPattern.test(nextSource)) {
182
+ throw new Error([
183
+ `ensureAbilitySyncProjectAnchors could not patch ${path.basename(syncProjectScriptPath)}.`,
184
+ "Missing the expected sync-rest invocation block in scripts/sync-project.ts.",
185
+ "Restore the generated template or wire sync-abilities manually before retrying.",
186
+ ].join(" "));
187
+ }
188
+ nextSource = nextSource.replace(syncRestBlockPattern, (match) => `${match}\n\n${syncAbilitiesBlock}`);
189
+ }
190
+ return nextSource;
191
+ });
192
+ }
193
+ /**
194
+ * Ensure the workspace build script includes optional ability client entries.
195
+ */
196
+ export async function ensureAbilityBuildScriptAnchors(workspace) {
197
+ const buildScriptPath = path.join(workspace.projectDir, "scripts", "build-workspace.mjs");
198
+ await patchFile(buildScriptPath, (source) => {
199
+ let nextSource = source;
200
+ if (/['"]src\/abilities\/index\.(?:ts|js)['"]/u.test(nextSource)) {
201
+ return nextSource;
202
+ }
203
+ const sharedEntriesPattern = /(for\s*\(\s*const\s+relativePath\s+of\s+\[)([\s\S]*?)(\]\s*\)\s*\{)/u;
204
+ const match = nextSource.match(sharedEntriesPattern);
205
+ if (!match ||
206
+ !/['"]src\/bindings\/index\.(?:ts|js)['"]/u.test(match[2]) ||
207
+ !/['"]src\/editor-plugins\/index\.(?:tsx|ts|js)['"]/u.test(match[2])) {
208
+ throw new Error([
209
+ `ensureAbilityBuildScriptAnchors could not patch ${path.basename(buildScriptPath)}.`,
210
+ "Missing the expected shared editor entries array in scripts/build-workspace.mjs.",
211
+ "Restore the generated template or wire abilities/index manually before retrying.",
212
+ ].join(" "));
213
+ }
214
+ nextSource = nextSource.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
215
+ const missingAbilityEntries = [
216
+ "'src/abilities/index.ts'",
217
+ "'src/abilities/index.js'",
218
+ ].filter((entry) => !sharedEntries.includes(entry));
219
+ if (missingAbilityEntries.length === 0) {
220
+ return fullMatch;
221
+ }
222
+ const itemIndent = sharedEntries.match(/\n([ \t]*)['"]/u)?.[1] ?? "\t\t";
223
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
224
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
225
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
226
+ const nextEntries = `${trimmedEntries}${separator}` +
227
+ missingAbilityEntries.map((entry) => `\n${itemIndent}${entry},`).join("") +
228
+ trailingWhitespace;
229
+ return fullMatch.replace(sharedEntries, nextEntries);
230
+ });
231
+ return nextSource;
232
+ });
233
+ }
234
+ /**
235
+ * Ensure webpack discovers the optional ability client registry bundle.
236
+ */
237
+ export async function ensureAbilityWebpackAnchors(workspace) {
238
+ const webpackConfigPath = path.join(workspace.projectDir, "webpack.config.js");
239
+ await patchFile(webpackConfigPath, (source) => {
240
+ if (/['"]abilities\/index['"]/u.test(source)) {
241
+ return source;
242
+ }
243
+ const optionalModuleReturnPattern = /(function\s+getOptionalModuleEntries\s*\(\)\s*\{[\s\S]*?)(\n\treturn Object\.fromEntries\(\s*entries\s*\);\n\})/u;
244
+ if (optionalModuleReturnPattern.test(source)) {
245
+ return source.replace(optionalModuleReturnPattern, `$1
246
+
247
+ \tfor ( const [ entryName, candidates ] of [
248
+ \t\t[
249
+ \t\t\t'abilities/index',
250
+ \t\t\t[ 'src/abilities/index.ts', 'src/abilities/index.js' ],
251
+ \t\t],
252
+ \t] ) {
253
+ \t\tfor ( const relativePath of candidates ) {
254
+ \t\t\tconst entryPath = path.resolve( process.cwd(), relativePath );
255
+ \t\t\tif ( ! fs.existsSync( entryPath ) ) {
256
+ \t\t\t\tcontinue;
257
+ \t\t\t}
258
+
259
+ \t\t\tentries.push( [ entryName, entryPath ] );
260
+ \t\t\tbreak;
261
+ \t\t}
262
+ \t}$2`);
263
+ }
264
+ const sharedEntriesPattern = /for\s*\(\s*const\s+\[\s*entryName\s*,\s*candidates\s*\]\s+of\s+\[([\s\S]*?)\]\s*\)\s*\{/u;
265
+ const match = source.match(sharedEntriesPattern);
266
+ if (!match ||
267
+ !match[1].includes("bindings/index") ||
268
+ !match[1].includes("editor-plugins/index")) {
269
+ throw new Error([
270
+ `ensureAbilityWebpackAnchors could not patch ${path.basename(webpackConfigPath)}.`,
271
+ "Missing the expected shared editor entries block in webpack.config.js.",
272
+ "Restore the generated template or wire abilities/index manually before retrying.",
273
+ ].join(" "));
274
+ }
275
+ return source.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
276
+ if (/['"]abilities\/index['"]/u.test(sharedEntries)) {
277
+ return fullMatch;
278
+ }
279
+ const tupleIndent = sharedEntries.match(/\n([ \t]*)\[/u)?.[1] ?? "\t\t";
280
+ const nestedIndent = `${tupleIndent}\t`;
281
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
282
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
283
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
284
+ const abilityTuple = [
285
+ `${tupleIndent}[`,
286
+ `${nestedIndent}'abilities/index',`,
287
+ `${nestedIndent}[ 'src/abilities/index.ts', 'src/abilities/index.js' ],`,
288
+ `${tupleIndent}],`,
289
+ ].join("\n");
290
+ const nextEntries = `${trimmedEntries}${separator}\n${abilityTuple}` + trailingWhitespace;
291
+ return fullMatch.replace(sharedEntries, nextEntries);
292
+ });
293
+ });
294
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Resolve the workspace ability client registry path, preserving JS registries
3
+ * when older projects already use them.
4
+ */
5
+ export declare function resolveAbilityRegistryPath(projectDir: string): Promise<string>;
6
+ /**
7
+ * Rewrite the generated ability client registry while preserving existing
8
+ * generated entries and extension-suffixed exports.
9
+ */
10
+ export declare function writeAbilityRegistry(projectDir: string, abilitySlug: string): Promise<void>;
@@ -0,0 +1,51 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import { readOptionalUtf8File, pathExists } from "./fs-async.js";
4
+ import { buildAbilityRegistrySource, } from "./cli-add-workspace-ability-templates.js";
5
+ import { ABILITY_REGISTRY_END_MARKER, ABILITY_REGISTRY_START_MARKER, } from "./cli-add-workspace-ability-types.js";
6
+ import { escapeRegex } from "./php-utils.js";
7
+ import { readWorkspaceInventoryAsync, } from "./workspace-inventory.js";
8
+ /**
9
+ * Resolve the workspace ability client registry path, preserving JS registries
10
+ * when older projects already use them.
11
+ */
12
+ export async function resolveAbilityRegistryPath(projectDir) {
13
+ const abilitiesDir = path.join(projectDir, "src", "abilities");
14
+ for (const candidatePath of [
15
+ path.join(abilitiesDir, "index.ts"),
16
+ path.join(abilitiesDir, "index.js"),
17
+ ]) {
18
+ if (await pathExists(candidatePath)) {
19
+ return candidatePath;
20
+ }
21
+ }
22
+ return path.join(abilitiesDir, "index.ts");
23
+ }
24
+ async function readAbilityRegistrySlugs(registryPath) {
25
+ const source = await readOptionalUtf8File(registryPath);
26
+ if (source === null) {
27
+ return [];
28
+ }
29
+ return Array.from(source.matchAll(/^\s*export\s+\*\s+from\s+['"]\.\/([^/'"]+)\/client(?:\.[cm]?[jt]sx?)?['"];?\s*$/gmu)).map((match) => match[1]);
30
+ }
31
+ /**
32
+ * Rewrite the generated ability client registry while preserving existing
33
+ * generated entries and extension-suffixed exports.
34
+ */
35
+ export async function writeAbilityRegistry(projectDir, abilitySlug) {
36
+ const abilitiesDir = path.join(projectDir, "src", "abilities");
37
+ const registryPath = await resolveAbilityRegistryPath(projectDir);
38
+ await fsp.mkdir(abilitiesDir, { recursive: true });
39
+ const existingAbilitySlugs = (await readWorkspaceInventoryAsync(projectDir)).abilities.map((entry) => entry.slug);
40
+ const existingRegistrySlugs = await readAbilityRegistrySlugs(registryPath);
41
+ const nextAbilitySlugs = Array.from(new Set([...existingAbilitySlugs, ...existingRegistrySlugs, abilitySlug])).sort();
42
+ const generatedSection = buildAbilityRegistrySource(nextAbilitySlugs);
43
+ const existingSource = (await readOptionalUtf8File(registryPath)) ?? "";
44
+ const generatedSectionPattern = new RegExp(`${escapeRegex(ABILITY_REGISTRY_START_MARKER)}[\\s\\S]*?${escapeRegex(ABILITY_REGISTRY_END_MARKER)}\\n?`, "u");
45
+ const nextSource = existingSource
46
+ ? generatedSectionPattern.test(existingSource)
47
+ ? existingSource.replace(generatedSectionPattern, generatedSection)
48
+ : `${existingSource.trimEnd()}\n\n${generatedSection}`
49
+ : generatedSection;
50
+ await fsp.writeFile(registryPath, nextSource, "utf8");
51
+ }
@@ -1,4 +1,4 @@
1
- import { type ScaffoldAbilityWorkspaceOptions } from "./cli-add-workspace-ability-types.js";
1
+ import type { ScaffoldAbilityWorkspaceOptions } from "./cli-add-workspace-ability-types.js";
2
2
  /**
3
3
  * Write generated workflow ability sources and patch shared workspace anchors.
4
4
  */