@wp-typia/project-tools 0.23.1 → 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 (152) hide show
  1. package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
  2. package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
  3. package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
  4. package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
  5. package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
  6. package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
  7. package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
  8. package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
  9. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
  10. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
  11. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
  12. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
  13. package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
  14. package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
  15. package/dist/runtime/cli-add-collision.js +8 -0
  16. package/dist/runtime/cli-add-help.js +10 -7
  17. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  18. package/dist/runtime/cli-add-kind-ids.js +1 -0
  19. package/dist/runtime/cli-add-types.d.ts +28 -1
  20. package/dist/runtime/cli-add-types.js +2 -0
  21. package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
  22. package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
  23. package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
  24. package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
  25. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
  26. package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -311
  27. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +1 -1
  28. package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
  29. package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -232
  30. package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
  31. package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
  32. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -145
  33. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
  34. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
  35. package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
  36. package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
  37. package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
  38. package/dist/runtime/cli-add-workspace-assets.js +6 -950
  39. package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
  40. package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
  41. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
  42. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
  43. package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
  44. package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
  45. package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
  46. package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
  47. package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
  48. package/dist/runtime/cli-add-workspace-block-style.js +148 -0
  49. package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
  50. package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
  51. package/dist/runtime/cli-add-workspace-contract.js +1 -1
  52. package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
  53. package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
  54. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
  55. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
  56. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
  57. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
  58. package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
  59. package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
  60. package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
  61. package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
  62. package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
  63. package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
  64. package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
  65. package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
  66. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
  67. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
  68. package/dist/runtime/cli-add-workspace-integration-env.js +5 -345
  69. package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
  70. package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
  71. package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
  72. package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
  73. package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
  74. package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
  75. package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
  76. package/dist/runtime/cli-add-workspace-pattern.js +99 -0
  77. package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
  78. package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
  79. package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
  80. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +6 -9
  81. package/dist/runtime/cli-add-workspace-rest-anchors.js +6 -466
  82. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
  83. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
  84. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
  85. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
  86. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
  87. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
  88. package/dist/runtime/cli-add-workspace-rest-generated.js +5 -3
  89. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
  90. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
  91. package/dist/runtime/cli-add-workspace-rest-manual.js +3 -16
  92. package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +1 -7
  93. package/dist/runtime/cli-add-workspace-rest-php-templates.js +3 -322
  94. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
  95. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
  96. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
  97. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
  98. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
  99. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
  100. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -99
  101. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -663
  102. package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
  103. package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
  104. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
  105. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
  106. package/dist/runtime/cli-add-workspace-rest-types.d.ts +3 -3
  107. package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
  108. package/dist/runtime/cli-add-workspace-variation.js +162 -0
  109. package/dist/runtime/cli-add-workspace.d.ts +42 -107
  110. package/dist/runtime/cli-add-workspace.js +42 -674
  111. package/dist/runtime/cli-add.d.ts +3 -3
  112. package/dist/runtime/cli-add.js +2 -2
  113. package/dist/runtime/cli-core.d.ts +2 -1
  114. package/dist/runtime/cli-core.js +1 -1
  115. package/dist/runtime/cli-doctor-workspace-bindings.js +59 -0
  116. package/dist/runtime/cli-doctor-workspace-block-addons.js +33 -5
  117. package/dist/runtime/cli-doctor.d.ts +2 -0
  118. package/dist/runtime/cli-doctor.js +13 -2
  119. package/dist/runtime/cli-help.js +6 -4
  120. package/dist/runtime/index.d.ts +5 -2
  121. package/dist/runtime/index.js +4 -2
  122. package/dist/runtime/local-dev-presets.js +2 -1
  123. package/dist/runtime/package-versions.d.ts +1 -0
  124. package/dist/runtime/package-versions.js +10 -2
  125. package/dist/runtime/pattern-catalog.d.ts +122 -0
  126. package/dist/runtime/pattern-catalog.js +471 -0
  127. package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
  128. package/dist/runtime/post-meta-binding-fields.js +135 -0
  129. package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
  130. package/dist/runtime/typia-llm-json-schema.js +33 -0
  131. package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
  132. package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
  133. package/dist/runtime/typia-llm-projection.d.ts +25 -0
  134. package/dist/runtime/typia-llm-projection.js +58 -0
  135. package/dist/runtime/typia-llm-render.d.ts +21 -0
  136. package/dist/runtime/typia-llm-render.js +252 -0
  137. package/dist/runtime/typia-llm-sync.d.ts +10 -0
  138. package/dist/runtime/typia-llm-sync.js +63 -0
  139. package/dist/runtime/typia-llm-types.d.ts +197 -0
  140. package/dist/runtime/typia-llm-types.js +1 -0
  141. package/dist/runtime/typia-llm.d.ts +9 -255
  142. package/dist/runtime/typia-llm.js +5 -634
  143. package/dist/runtime/workspace-inventory-mutations.js +13 -0
  144. package/dist/runtime/workspace-inventory-section-descriptors.js +9 -1
  145. package/dist/runtime/workspace-inventory-templates.d.ts +2 -2
  146. package/dist/runtime/workspace-inventory-templates.js +9 -1
  147. package/dist/runtime/workspace-inventory-types.d.ts +9 -1
  148. package/package.json +8 -3
  149. package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
  150. package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
  151. package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
  152. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
@@ -2,6 +2,7 @@ import { quoteTsString } from "./cli-add-shared.js";
2
2
  import { buildAiFeatureEndpointManifest } from "./ai-feature-artifacts.js";
3
3
  import { OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY, createScaffoldCompatibilityConfig, renderScaffoldCompatibilityConfig, resolveScaffoldCompatibilityPolicy, } from "./scaffold-compatibility.js";
4
4
  import { toPascalCase, toTitleCase } from "./string-case.js";
5
+ export { buildAiFeatureSyncScriptSource, } from "./cli-add-workspace-ai-sync-script-source.js";
5
6
  function indentMultiline(source, prefix) {
6
7
  return source
7
8
  .split("\n")
@@ -323,148 +324,3 @@ export {
323
324
  };
324
325
  `;
325
326
  }
326
- /**
327
- * Generate the `scripts/sync-ai-features.ts` source that projects AI-safe schemas for workspace features.
328
- */
329
- export function buildAiFeatureSyncScriptSource() {
330
- return `/* eslint-disable no-console */
331
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
332
- import path from 'node:path';
333
-
334
- import { projectWordPressAiSchema } from '@wp-typia/project-tools/ai-artifacts';
335
-
336
- import {
337
- \tAI_FEATURES,
338
- \ttype WorkspaceAiFeatureConfig,
339
- } from './block-config';
340
-
341
- function parseCliOptions( argv: string[] ) {
342
- \tconst options = {
343
- \t\tcheck: false,
344
- \t};
345
-
346
- \tfor ( const argument of argv ) {
347
- \t\tif ( argument === '--check' ) {
348
- \t\t\toptions.check = true;
349
- \t\t\tcontinue;
350
- \t\t}
351
-
352
- \t\tthrow new Error( \`Unknown sync-ai flag: \${ argument }\` );
353
- \t}
354
-
355
- \treturn options;
356
- }
357
-
358
- function isWorkspaceAiFeature(
359
- \tfeature: WorkspaceAiFeatureConfig
360
- ): feature is WorkspaceAiFeatureConfig & {
361
- \taiSchemaFile: string;
362
- \ttypesFile: string;
363
- } {
364
- \treturn (
365
- \t\ttypeof feature.aiSchemaFile === 'string' &&
366
- \t\ttypeof feature.typesFile === 'string'
367
- \t);
368
- }
369
-
370
- function normalizeGeneratedArtifactContent( content: string ) {
371
- \treturn content.replace( /\\r\\n?/g, '\\n' );
372
- }
373
-
374
- async function reconcileGeneratedArtifact( options: {
375
- \tcheck: boolean;
376
- \tcontent: string;
377
- \tfilePath: string;
378
- \tlabel: string;
379
- } ) {
380
- \tif ( ! options.check ) {
381
- \t\tawait mkdir( path.dirname( options.filePath ), {
382
- \t\t\trecursive: true,
383
- \t\t} );
384
- \t\tawait writeFile( options.filePath, options.content, 'utf8' );
385
- \t\treturn;
386
- \t}
387
-
388
- \tconst current = normalizeGeneratedArtifactContent(
389
- \t\tawait readFile( options.filePath, 'utf8' )
390
- \t);
391
- \tconst expected = normalizeGeneratedArtifactContent( options.content );
392
- \tif ( current !== expected ) {
393
- \t\tthrow new Error(
394
- \t\t\t\`Generated AI feature artifact is stale: \${ options.label } (\${ options.filePath }).\`
395
- \t\t);
396
- \t}
397
- }
398
-
399
- async function loadJsonDocument( filePath: string ) {
400
- \tlet source: string;
401
- \ttry {
402
- \t\tsource = await readFile( filePath, 'utf8' );
403
- \t} catch ( error ) {
404
- \t\tthrow new Error(
405
- \t\t\t\`Failed to read AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
406
- \t\t);
407
- \t}
408
-
409
- \tlet decoded: unknown;
410
- \ttry {
411
- \t\tdecoded = JSON.parse( source ) as unknown;
412
- \t} catch ( error ) {
413
- \t\tthrow new Error(
414
- \t\t\t\`Failed to parse AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
415
- \t\t);
416
- \t}
417
- \tif ( ! decoded || typeof decoded !== 'object' || Array.isArray( decoded ) ) {
418
- \t\tthrow new Error( \`Expected \${ filePath } to decode to a JSON object.\` );
419
- \t}
420
-
421
- \treturn decoded as Parameters< typeof projectWordPressAiSchema >[ 0 ];
422
- }
423
-
424
- async function main() {
425
- \tconst options = parseCliOptions( process.argv.slice( 2 ) );
426
- \tconst aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );
427
- \tif ( AI_FEATURES.length > 0 && aiFeatures.length === 0 ) {
428
- \t\tconsole.warn(
429
- \t\t\t'⚠️ AI_FEATURES entries exist, but none satisfied the generated sync-ai guard. Check for missing aiSchemaFile/typesFile fields in scripts/block-config.ts.'
430
- \t\t);
431
- \t}
432
-
433
- \tif ( aiFeatures.length === 0 ) {
434
- \t\tconsole.log(
435
- \t\t\toptions.check
436
- \t\t\t\t? 'ℹ️ No workspace AI features are registered yet. \`sync-ai --check\` is already clean.'
437
- \t\t\t\t: 'ℹ️ No workspace AI features are registered yet.'
438
- \t\t);
439
- \t\treturn;
440
- \t}
441
-
442
- \tfor ( const feature of aiFeatures ) {
443
- \t\tconst sourceSchemaPath = path.join(
444
- \t\t\tpath.dirname( feature.typesFile ),
445
- \t\t\t'api-schemas',
446
- \t\t\t'feature-result.schema.json'
447
- \t\t);
448
- \t\tconst sourceSchema = await loadJsonDocument( sourceSchemaPath );
449
- \t\tconst aiSchema = projectWordPressAiSchema( sourceSchema );
450
- \t\tawait reconcileGeneratedArtifact( {
451
- \t\t\tcheck: options.check,
452
- \t\t\tcontent: \`\${ JSON.stringify( aiSchema, null, 2 ) }\\n\`,
453
- \t\t\tfilePath: feature.aiSchemaFile,
454
- \t\t\tlabel: feature.slug,
455
- \t\t} );
456
- \t}
457
-
458
- \tconsole.log(
459
- \t\toptions.check
460
- \t\t\t? '✅ AI feature structured-output schemas are already synchronized.'
461
- \t\t\t: '✅ AI feature structured-output schemas were synchronized.'
462
- \t);
463
- }
464
-
465
- main().catch( ( error ) => {
466
- \tconsole.error( '❌ AI feature sync failed:', error );
467
- \tprocess.exit( 1 );
468
- } );
469
- `;
470
- }
@@ -0,0 +1,5 @@
1
+ import type { WorkspaceProject } from "./workspace-project.js";
2
+ /**
3
+ * Patch `scripts/sync-rest-contracts.ts` after sync-project wiring so AI feature REST artifacts join the split sync flow.
4
+ */
5
+ export declare function ensureAiFeatureSyncRestAnchors(workspace: WorkspaceProject): Promise<void>;
@@ -0,0 +1,236 @@
1
+ import path from "node:path";
2
+ import { patchFile } from "./cli-add-shared.js";
3
+ function assertSyncRestAnchor(nextSource, target, anchorDescription, hasAnchor, syncRestScriptPath) {
4
+ if (!nextSource.includes(target) && !hasAnchor) {
5
+ throw new Error([
6
+ `ensureAiFeatureSyncRestAnchors could not patch ${path.basename(syncRestScriptPath)}.`,
7
+ `Missing expected ${anchorDescription} anchor in scripts/sync-rest-contracts.ts.`,
8
+ "Restore the generated template or add the AI feature wiring manually before retrying.",
9
+ ].join(" "));
10
+ }
11
+ }
12
+ function replaceRequiredSyncRestSource(nextSource, target, anchor, replacement, anchorDescription, syncRestScriptPath) {
13
+ if (nextSource.includes(target)) {
14
+ return nextSource;
15
+ }
16
+ const hasAnchor = typeof anchor === "string" ? nextSource.includes(anchor) : anchor.test(nextSource);
17
+ assertSyncRestAnchor(nextSource, target, anchorDescription, hasAnchor, syncRestScriptPath);
18
+ return nextSource.replace(anchor, replacement);
19
+ }
20
+ function replaceBlockConfigImportForAiFeatures(nextSource, syncRestScriptPath) {
21
+ const importPatterns = [
22
+ /^import\s*\{\n(?:\t[^\n]*\n)+\} from ["']\.\/block-config["'];?$/mu,
23
+ /^import\s*\{[^\n]*\}\s*from\s*["']\.\/block-config["'];?$/mu,
24
+ ];
25
+ const importMatch = importPatterns.map((pattern) => pattern.exec(nextSource)).find(Boolean) ??
26
+ null;
27
+ if (!importMatch) {
28
+ throw new Error([
29
+ `ensureAiFeatureSyncRestAnchors could not patch ${path.basename(syncRestScriptPath)}.`,
30
+ "Missing expected workspace inventory import anchor in scripts/sync-rest-contracts.ts.",
31
+ "Restore the generated template or add the AI feature wiring manually before retrying.",
32
+ ].join(" "));
33
+ }
34
+ const importSource = importMatch[0];
35
+ if (importSource.includes("AI_FEATURES") &&
36
+ importSource.includes("WorkspaceAiFeatureConfig")) {
37
+ return nextSource;
38
+ }
39
+ const hasContracts = importSource.includes("CONTRACTS");
40
+ const hasContractConfig = importSource.includes("WorkspaceContractConfig");
41
+ const hasPostMeta = importSource.includes("POST_META");
42
+ const hasPostMetaConfig = importSource.includes("WorkspacePostMetaConfig");
43
+ const replacement = [
44
+ "import {",
45
+ "\tAI_FEATURES,",
46
+ "\tBLOCKS,",
47
+ ...(hasContracts ? ["\tCONTRACTS,"] : []),
48
+ ...(hasPostMeta ? ["\tPOST_META,"] : []),
49
+ "\tREST_RESOURCES,",
50
+ "\ttype WorkspaceAiFeatureConfig,",
51
+ "\ttype WorkspaceBlockConfig,",
52
+ ...(hasContractConfig ? ["\ttype WorkspaceContractConfig,"] : []),
53
+ ...(hasPostMetaConfig ? ["\ttype WorkspacePostMetaConfig,"] : []),
54
+ "\ttype WorkspaceRestResourceConfig,",
55
+ "} from './block-config';",
56
+ ].join("\n");
57
+ return nextSource.replace(importSource, replacement);
58
+ }
59
+ function replaceAiFeatureSyncSummaryCopy(nextSource, syncRestScriptPath) {
60
+ const standaloneSummary = "workspace blocks, standalone contracts, and plugin-level resources";
61
+ const standaloneAiSummary = "workspace blocks, standalone contracts, plugin-level resources, and AI features";
62
+ const standalonePostMetaSummary = "workspace blocks, standalone contracts, post meta contracts, and plugin-level resources";
63
+ const standalonePostMetaAiSummary = "workspace blocks, standalone contracts, post meta contracts, plugin-level resources, and AI features";
64
+ const postMetaSummary = "workspace blocks, post meta contracts, and plugin-level resources";
65
+ const postMetaAiSummary = "workspace blocks, post meta contracts, plugin-level resources, and AI features";
66
+ const restResourceSummary = "workspace blocks and plugin-level resources";
67
+ const restResourceAiSummary = "workspace blocks, plugin-level resources, and AI features";
68
+ if (nextSource.includes(standalonePostMetaSummary)) {
69
+ return nextSource
70
+ .split(standalonePostMetaSummary)
71
+ .join(standalonePostMetaAiSummary);
72
+ }
73
+ if (nextSource.includes(standaloneSummary)) {
74
+ return nextSource.split(standaloneSummary).join(standaloneAiSummary);
75
+ }
76
+ if (nextSource.includes(postMetaSummary)) {
77
+ return nextSource.split(postMetaSummary).join(postMetaAiSummary);
78
+ }
79
+ if (nextSource.includes(restResourceSummary)) {
80
+ return nextSource.split(restResourceSummary).join(restResourceAiSummary);
81
+ }
82
+ if (nextSource.includes(standaloneAiSummary) ||
83
+ nextSource.includes(standalonePostMetaAiSummary) ||
84
+ nextSource.includes(postMetaAiSummary) ||
85
+ nextSource.includes(restResourceAiSummary)) {
86
+ return nextSource;
87
+ }
88
+ throw new Error([
89
+ `ensureAiFeatureSyncRestAnchors could not patch ${path.basename(syncRestScriptPath)}.`,
90
+ "Missing expected sync summary copy anchor in scripts/sync-rest-contracts.ts.",
91
+ "Restore the generated template or add the AI feature wiring manually before retrying.",
92
+ ].join(" "));
93
+ }
94
+ function formatNoResourcesSubject(subjects) {
95
+ if (subjects.length <= 2) {
96
+ return subjects.join(" or ");
97
+ }
98
+ const lastSubject = subjects[subjects.length - 1];
99
+ return `${subjects.slice(0, -1).join(", ")}, or ${lastSubject}`;
100
+ }
101
+ function buildAiFeatureNoResourcesGuard({ hasPostMeta, hasStandaloneContracts, }) {
102
+ const condition = ["restBlocks.length === 0"];
103
+ if (hasStandaloneContracts) {
104
+ condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
105
+ condition.push("standaloneContracts.length === 0");
106
+ }
107
+ if (hasPostMeta) {
108
+ condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
109
+ condition.push("postMetaContracts.length === 0");
110
+ }
111
+ condition[condition.length - 1] = `${condition[condition.length - 1]} &&`;
112
+ condition.push("restResources.length === 0 &&");
113
+ condition.push("aiFeatures.length === 0");
114
+ const noResourcesSubject = formatNoResourcesSubject([
115
+ "REST-enabled workspace blocks",
116
+ ...(hasStandaloneContracts ? ["standalone contracts"] : []),
117
+ ...(hasPostMeta ? ["post meta contracts"] : []),
118
+ "plugin-level REST resources",
119
+ "AI features",
120
+ ]);
121
+ return [
122
+ "if (",
123
+ ...condition.map((line) => `\t\t${line}`),
124
+ "\t) {",
125
+ "\t\tconsole.log(",
126
+ "\t\t\toptions.check",
127
+ `\t\t\t\t? 'ℹ️ No ${noResourcesSubject} are registered yet. \`sync-rest --check\` is already clean.'`,
128
+ `\t\t\t\t: 'ℹ️ No ${noResourcesSubject} are registered yet.'`,
129
+ "\t\t);",
130
+ "\t\treturn;",
131
+ "\t}",
132
+ ].join("\n");
133
+ }
134
+ const NO_RESOURCES_GUARD_PATTERN = /if \(\s*restBlocks\.length === 0(?:\s*&&\s*standaloneContracts\.length === 0)?(?:\s*&&\s*postMetaContracts\.length === 0)?\s*&&\s*restResources\.length === 0(?:\s*&&\s*aiFeatures\.length === 0)?\s*\) \{[\s\S]*?\n\t\treturn;\n\t\}/u;
135
+ /**
136
+ * Patch `scripts/sync-rest-contracts.ts` after sync-project wiring so AI feature REST artifacts join the split sync flow.
137
+ */
138
+ export async function ensureAiFeatureSyncRestAnchors(workspace) {
139
+ const syncRestScriptPath = path.join(workspace.projectDir, "scripts", "sync-rest-contracts.ts");
140
+ await patchFile(syncRestScriptPath, (source) => {
141
+ let nextSource = replaceBlockConfigImportForAiFeatures(source, syncRestScriptPath);
142
+ const helperInsertionAnchor = "async function assertTypeArtifactsCurrent";
143
+ const restResourcesAnchor = "const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );";
144
+ const consoleLogPattern = /\n\tconsole\.log\(\n\t\toptions\.check/u;
145
+ nextSource = replaceRequiredSyncRestSource(nextSource, "function isWorkspaceAiFeature(", helperInsertionAnchor, [
146
+ "function isWorkspaceAiFeature(",
147
+ "\tfeature: WorkspaceAiFeatureConfig",
148
+ "): feature is WorkspaceAiFeatureConfig & {",
149
+ "\taiSchemaFile: string;",
150
+ "\tclientFile: string;",
151
+ "\topenApiFile: string;",
152
+ "\trestManifest: NonNullable< WorkspaceAiFeatureConfig[ 'restManifest' ] >;",
153
+ "\ttypesFile: string;",
154
+ "\tvalidatorsFile: string;",
155
+ "} {",
156
+ "\treturn (",
157
+ "\t\ttypeof feature.aiSchemaFile === 'string' &&",
158
+ "\t\ttypeof feature.clientFile === 'string' &&",
159
+ "\t\ttypeof feature.openApiFile === 'string' &&",
160
+ "\t\ttypeof feature.typesFile === 'string' &&",
161
+ "\t\ttypeof feature.validatorsFile === 'string' &&",
162
+ "\t\ttypeof feature.restManifest === 'object' &&",
163
+ "\t\tfeature.restManifest !== null &&",
164
+ "\t\ttypeof feature.restManifest.contracts === 'object' &&",
165
+ "\t\tfeature.restManifest.contracts !== null",
166
+ "\t);",
167
+ "}",
168
+ "",
169
+ "async function assertTypeArtifactsCurrent",
170
+ ].join("\n"), "type artifact assertion helper", syncRestScriptPath);
171
+ nextSource = replaceRequiredSyncRestSource(nextSource, "const aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );", restResourcesAnchor, [
172
+ "const restResources = REST_RESOURCES.filter( isWorkspaceRestResource );",
173
+ "const aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );",
174
+ ].join("\n"), "rest resource filter", syncRestScriptPath);
175
+ nextSource = replaceRequiredSyncRestSource(nextSource, "aiFeatures.length === 0", NO_RESOURCES_GUARD_PATTERN, buildAiFeatureNoResourcesGuard({
176
+ hasPostMeta: nextSource.includes("const postMetaContracts = POST_META.filter( isWorkspacePostMetaContract );"),
177
+ hasStandaloneContracts: nextSource.includes("const standaloneContracts = CONTRACTS.filter( isWorkspaceStandaloneContract );"),
178
+ }), "no-resources guard", syncRestScriptPath);
179
+ nextSource = replaceRequiredSyncRestSource(nextSource, "for ( const feature of aiFeatures ) {", consoleLogPattern, [
180
+ "",
181
+ "\tfor ( const feature of aiFeatures ) {",
182
+ "\t\tconst contracts = feature.restManifest.contracts;",
183
+ "",
184
+ "\t\tfor ( const [ baseName, contract ] of Object.entries( contracts ) ) {",
185
+ "\t\t\tawait syncTypeSchemas(",
186
+ "\t\t\t\t{",
187
+ "\t\t\t\t\tjsonSchemaFile: path.join(",
188
+ "\t\t\t\t\t\tpath.dirname( feature.typesFile ),",
189
+ "\t\t\t\t\t\t'api-schemas',",
190
+ "\t\t\t\t\t\t`${ baseName }.schema.json`",
191
+ "\t\t\t\t\t),",
192
+ "\t\t\t\t\topenApiFile: path.join(",
193
+ "\t\t\t\t\t\tpath.dirname( feature.typesFile ),",
194
+ "\t\t\t\t\t\t'api-schemas',",
195
+ "\t\t\t\t\t\t`${ baseName }.openapi.json`",
196
+ "\t\t\t\t\t),",
197
+ "\t\t\t\t\tsourceTypeName: contract.sourceTypeName,",
198
+ "\t\t\t\t\ttypesFile: feature.typesFile,",
199
+ "\t\t\t\t},",
200
+ "\t\t\t\t{",
201
+ "\t\t\t\t\tcheck: options.check,",
202
+ "\t\t\t\t}",
203
+ "\t\t\t);",
204
+ "\t\t}",
205
+ "",
206
+ "\t\tawait syncRestOpenApi(",
207
+ "\t\t\t{",
208
+ "\t\t\t\tmanifest: feature.restManifest,",
209
+ "\t\t\t\topenApiFile: feature.openApiFile,",
210
+ "\t\t\t\ttypesFile: feature.typesFile,",
211
+ "\t\t\t},",
212
+ "\t\t\t{",
213
+ "\t\t\t\tcheck: options.check,",
214
+ "\t\t\t}",
215
+ "\t\t);",
216
+ "",
217
+ "\t\tawait syncEndpointClient(",
218
+ "\t\t\t{",
219
+ "\t\t\t\tclientFile: feature.clientFile,",
220
+ "\t\t\t\tmanifest: feature.restManifest,",
221
+ "\t\t\t\ttypesFile: feature.typesFile,",
222
+ "\t\t\t\tvalidatorsFile: feature.validatorsFile,",
223
+ "\t\t\t},",
224
+ "\t\t\t{",
225
+ "\t\t\t\tcheck: options.check,",
226
+ "\t\t\t}",
227
+ "\t\t);",
228
+ "\t}",
229
+ "",
230
+ "\tconsole.log(",
231
+ "\t\toptions.check",
232
+ ].join("\n"), "final sync summary", syncRestScriptPath);
233
+ nextSource = replaceAiFeatureSyncSummaryCopy(nextSource, syncRestScriptPath);
234
+ return nextSource;
235
+ });
236
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Generate the `scripts/sync-ai-features.ts` source that projects AI-safe schemas for workspace features.
3
+ */
4
+ export declare function buildAiFeatureSyncScriptSource(): string;
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Generate the `scripts/sync-ai-features.ts` source that projects AI-safe schemas for workspace features.
3
+ */
4
+ export function buildAiFeatureSyncScriptSource() {
5
+ return `/* eslint-disable no-console */
6
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
7
+ import path from 'node:path';
8
+
9
+ import { projectWordPressAiSchema } from '@wp-typia/project-tools/ai-artifacts';
10
+
11
+ import {
12
+ \tAI_FEATURES,
13
+ \ttype WorkspaceAiFeatureConfig,
14
+ } from './block-config';
15
+
16
+ function parseCliOptions( argv: string[] ) {
17
+ \tconst options = {
18
+ \t\tcheck: false,
19
+ \t};
20
+
21
+ \tfor ( const argument of argv ) {
22
+ \t\tif ( argument === '--check' ) {
23
+ \t\t\toptions.check = true;
24
+ \t\t\tcontinue;
25
+ \t\t}
26
+
27
+ \t\tthrow new Error( \`Unknown sync-ai flag: \${ argument }\` );
28
+ \t}
29
+
30
+ \treturn options;
31
+ }
32
+
33
+ function isWorkspaceAiFeature(
34
+ \tfeature: WorkspaceAiFeatureConfig
35
+ ): feature is WorkspaceAiFeatureConfig & {
36
+ \taiSchemaFile: string;
37
+ \ttypesFile: string;
38
+ } {
39
+ \treturn (
40
+ \t\ttypeof feature.aiSchemaFile === 'string' &&
41
+ \t\ttypeof feature.typesFile === 'string'
42
+ \t);
43
+ }
44
+
45
+ function normalizeGeneratedArtifactContent( content: string ) {
46
+ \treturn content.replace( /\\r\\n?/g, '\\n' );
47
+ }
48
+
49
+ async function reconcileGeneratedArtifact( options: {
50
+ \tcheck: boolean;
51
+ \tcontent: string;
52
+ \tfilePath: string;
53
+ \tlabel: string;
54
+ } ) {
55
+ \tif ( ! options.check ) {
56
+ \t\tawait mkdir( path.dirname( options.filePath ), {
57
+ \t\t\trecursive: true,
58
+ \t\t} );
59
+ \t\tawait writeFile( options.filePath, options.content, 'utf8' );
60
+ \t\treturn;
61
+ \t}
62
+
63
+ \tconst current = normalizeGeneratedArtifactContent(
64
+ \t\tawait readFile( options.filePath, 'utf8' )
65
+ \t);
66
+ \tconst expected = normalizeGeneratedArtifactContent( options.content );
67
+ \tif ( current !== expected ) {
68
+ \t\tthrow new Error(
69
+ \t\t\t\`Generated AI feature artifact is stale: \${ options.label } (\${ options.filePath }).\`
70
+ \t\t);
71
+ \t}
72
+ }
73
+
74
+ async function loadJsonDocument( filePath: string ) {
75
+ \tlet source: string;
76
+ \ttry {
77
+ \t\tsource = await readFile( filePath, 'utf8' );
78
+ \t} catch ( error ) {
79
+ \t\tthrow new Error(
80
+ \t\t\t\`Failed to read AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
81
+ \t\t);
82
+ \t}
83
+
84
+ \tlet decoded: unknown;
85
+ \ttry {
86
+ \t\tdecoded = JSON.parse( source ) as unknown;
87
+ \t} catch ( error ) {
88
+ \t\tthrow new Error(
89
+ \t\t\t\`Failed to parse AI schema document at \${ filePath }: \${ error instanceof Error ? error.message : String( error ) }\`
90
+ \t\t);
91
+ \t}
92
+ \tif ( ! decoded || typeof decoded !== 'object' || Array.isArray( decoded ) ) {
93
+ \t\tthrow new Error( \`Expected \${ filePath } to decode to a JSON object.\` );
94
+ \t}
95
+
96
+ \treturn decoded as Parameters< typeof projectWordPressAiSchema >[ 0 ];
97
+ }
98
+
99
+ async function main() {
100
+ \tconst options = parseCliOptions( process.argv.slice( 2 ) );
101
+ \tconst aiFeatures = AI_FEATURES.filter( isWorkspaceAiFeature );
102
+ \tif ( AI_FEATURES.length > 0 && aiFeatures.length === 0 ) {
103
+ \t\tconsole.warn(
104
+ \t\t\t'⚠️ AI_FEATURES entries exist, but none satisfied the generated sync-ai guard. Check for missing aiSchemaFile/typesFile fields in scripts/block-config.ts.'
105
+ \t\t);
106
+ \t}
107
+
108
+ \tif ( aiFeatures.length === 0 ) {
109
+ \t\tconsole.log(
110
+ \t\t\toptions.check
111
+ \t\t\t\t? 'ℹ️ No workspace AI features are registered yet. \`sync-ai --check\` is already clean.'
112
+ \t\t\t\t: 'ℹ️ No workspace AI features are registered yet.'
113
+ \t\t);
114
+ \t\treturn;
115
+ \t}
116
+
117
+ \tfor ( const feature of aiFeatures ) {
118
+ \t\tconst sourceSchemaPath = path.join(
119
+ \t\t\tpath.dirname( feature.typesFile ),
120
+ \t\t\t'api-schemas',
121
+ \t\t\t'feature-result.schema.json'
122
+ \t\t);
123
+ \t\tconst sourceSchema = await loadJsonDocument( sourceSchemaPath );
124
+ \t\tconst aiSchema = projectWordPressAiSchema( sourceSchema );
125
+ \t\tawait reconcileGeneratedArtifact( {
126
+ \t\t\tcheck: options.check,
127
+ \t\t\tcontent: \`\${ JSON.stringify( aiSchema, null, 2 ) }\\n\`,
128
+ \t\t\tfilePath: feature.aiSchemaFile,
129
+ \t\t\tlabel: feature.slug,
130
+ \t\t} );
131
+ \t}
132
+
133
+ \tconsole.log(
134
+ \t\toptions.check
135
+ \t\t\t? '✅ AI feature structured-output schemas are already synchronized.'
136
+ \t\t\t: '✅ AI feature structured-output schemas were synchronized.'
137
+ \t);
138
+ }
139
+
140
+ main().catch( ( error ) => {
141
+ \tconsole.error( '❌ AI feature sync failed:', error );
142
+ \tprocess.exit( 1 );
143
+ } );
144
+ `;
145
+ }
@@ -1,66 +1,9 @@
1
- import { type RunAddBindingSourceCommandOptions, type RunAddEditorPluginCommandOptions, type RunAddPatternCommandOptions } from "./cli-add-shared.js";
2
1
  /**
3
- * Add one document-level editor plugin scaffold to an official workspace project.
2
+ * Compatibility facade for workspace asset add commands.
4
3
  *
5
- * @param options Command options for the editor-plugin scaffold workflow.
6
- * @param options.cwd Working directory used to resolve the nearest official workspace.
7
- * Defaults to `process.cwd()`.
8
- * @param options.editorPluginName Human-entered editor-plugin name that will be
9
- * normalized and validated before files are written.
10
- * @param options.slot Optional editor plugin shell slot. Defaults to `sidebar`.
11
- * @returns A promise that resolves with the normalized `editorPluginSlug`, chosen
12
- * `slot`, and owning `projectDir` after the scaffold files and inventory entry
13
- * are written successfully.
14
- * @throws {Error} When the command is run outside an official workspace, when the
15
- * slug or slot is invalid, or when a conflicting file or inventory entry exists.
4
+ * Keep the public runtime import path stable while each workflow lives in a
5
+ * focused implementation module.
16
6
  */
17
- export declare function runAddEditorPluginCommand({ cwd, editorPluginName, slot, }: RunAddEditorPluginCommandOptions): Promise<{
18
- editorPluginSlug: string;
19
- projectDir: string;
20
- slot: string;
21
- }>;
22
- /**
23
- * Add one PHP block pattern shell to an official workspace project.
24
- *
25
- * @param options Command options for the pattern scaffold workflow.
26
- * @param options.cwd Working directory used to resolve the nearest official workspace.
27
- * Defaults to `process.cwd()`.
28
- * @param options.patternName Human-entered pattern name that will be normalized
29
- * and validated before files are written.
30
- * @returns A promise that resolves with the normalized `patternSlug` and
31
- * owning `projectDir` after the pattern file and inventory entry have been
32
- * written successfully.
33
- * @throws {Error} When the command is run outside an official workspace, when
34
- * the pattern slug is invalid, or when a conflicting file or inventory entry
35
- * already exists.
36
- */
37
- export declare function runAddPatternCommand({ cwd, patternName, }: RunAddPatternCommandOptions): Promise<{
38
- patternSlug: string;
39
- projectDir: string;
40
- }>;
41
- /**
42
- * Add one block binding source scaffold to an official workspace project.
43
- *
44
- * @param options Command options for the binding-source scaffold workflow.
45
- * @param options.attributeName Optional generated block attribute to declare as
46
- * bindable. Must be provided together with `blockName`.
47
- * @param options.blockName Optional generated block slug or full block name to
48
- * receive the bindable attribute wiring. Must be provided together with
49
- * `attributeName`.
50
- * @param options.bindingSourceName Human-entered binding source name that will
51
- * be normalized and validated before files are written.
52
- * @param options.cwd Working directory used to resolve the nearest official
53
- * workspace. Defaults to `process.cwd()`.
54
- * @returns A promise that resolves with the normalized `bindingSourceSlug` and
55
- * owning `projectDir` after the server/editor files, optional target block
56
- * metadata, and inventory entry have been written successfully.
57
- * @throws {Error} When the command is run outside an official workspace, when
58
- * the slug is invalid, when a binding target is incomplete or unknown, or when
59
- * a conflicting file or inventory entry exists.
60
- */
61
- export declare function runAddBindingSourceCommand({ attributeName, bindingSourceName, blockName, cwd, }: RunAddBindingSourceCommandOptions): Promise<{
62
- attributeName?: string;
63
- bindingSourceSlug: string;
64
- blockSlug?: string;
65
- projectDir: string;
66
- }>;
7
+ export { runAddBindingSourceCommand, } from "./cli-add-workspace-binding-source.js";
8
+ export { runAddEditorPluginCommand } from "./cli-add-workspace-editor-plugin.js";
9
+ export { runAddPatternCommand } from "./cli-add-workspace-pattern.js";