wp-typia 0.22.1 → 0.22.3

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.
@@ -36308,93 +36308,192 @@ function getMutableBlockHooks(blockJson, blockJsonRelativePath) {
36308
36308
  }
36309
36309
  return blockHooks;
36310
36310
  }
36311
- function assertVariationDoesNotExist(projectDir, blockSlug, variationSlug, inventory) {
36312
- const variationPath = path12.join(projectDir, "src", "blocks", blockSlug, "variations", `${variationSlug}.ts`);
36313
- if (fs8.existsSync(variationPath)) {
36314
- throw new Error(`A variation already exists at ${path12.relative(projectDir, variationPath)}. Choose a different name.`);
36311
+ function assertScaffoldDoesNotExist(options) {
36312
+ for (const collision of options.filesystemCollisions) {
36313
+ const targetPath = path12.join(options.projectDir, collision.relativePath);
36314
+ if (fs8.existsSync(targetPath)) {
36315
+ throw new Error(`${collision.label} already exists at ${path12.relative(options.projectDir, targetPath)}. Choose a different name.`);
36316
+ }
36315
36317
  }
36316
- if (inventory.variations.some((entry) => entry.block === blockSlug && entry.slug === variationSlug)) {
36317
- throw new Error(`A variation inventory entry already exists for ${blockSlug}/${variationSlug}. Choose a different name.`);
36318
+ if (options.inventoryCollision && options.inventoryCollision.entries.some(options.inventoryCollision.exists)) {
36319
+ throw new Error(options.inventoryCollision.message);
36318
36320
  }
36319
36321
  }
36322
+ function assertVariationDoesNotExist(projectDir, blockSlug, variationSlug, inventory) {
36323
+ assertScaffoldDoesNotExist({
36324
+ filesystemCollisions: [
36325
+ {
36326
+ label: "A variation",
36327
+ relativePath: path12.join("src", "blocks", blockSlug, "variations", `${variationSlug}.ts`)
36328
+ }
36329
+ ],
36330
+ inventoryCollision: {
36331
+ entries: inventory.variations,
36332
+ exists: (entry) => entry.block === blockSlug && entry.slug === variationSlug,
36333
+ message: `A variation inventory entry already exists for ${blockSlug}/${variationSlug}. Choose a different name.`
36334
+ },
36335
+ projectDir
36336
+ });
36337
+ }
36338
+ function assertBlockStyleDoesNotExist(projectDir, blockSlug, styleSlug, inventory) {
36339
+ assertScaffoldDoesNotExist({
36340
+ filesystemCollisions: [
36341
+ {
36342
+ label: "A block style",
36343
+ relativePath: path12.join("src", "blocks", blockSlug, "styles", `${styleSlug}.ts`)
36344
+ }
36345
+ ],
36346
+ inventoryCollision: {
36347
+ entries: inventory.blockStyles,
36348
+ exists: (entry) => entry.block === blockSlug && entry.slug === styleSlug,
36349
+ message: `A block style inventory entry already exists for ${blockSlug}/${styleSlug}. Choose a different name.`
36350
+ },
36351
+ projectDir
36352
+ });
36353
+ }
36354
+ function assertBlockTransformDoesNotExist(projectDir, blockSlug, transformSlug, inventory) {
36355
+ assertScaffoldDoesNotExist({
36356
+ filesystemCollisions: [
36357
+ {
36358
+ label: "A block transform",
36359
+ relativePath: path12.join("src", "blocks", blockSlug, "transforms", `${transformSlug}.ts`)
36360
+ }
36361
+ ],
36362
+ inventoryCollision: {
36363
+ entries: inventory.blockTransforms,
36364
+ exists: (entry) => entry.block === blockSlug && entry.slug === transformSlug,
36365
+ message: `A block transform inventory entry already exists for ${blockSlug}/${transformSlug}. Choose a different name.`
36366
+ },
36367
+ projectDir
36368
+ });
36369
+ }
36320
36370
  function assertPatternDoesNotExist(projectDir, patternSlug, inventory) {
36321
- const patternPath = path12.join(projectDir, "src", "patterns", `${patternSlug}.php`);
36322
- if (fs8.existsSync(patternPath)) {
36323
- throw new Error(`A pattern already exists at ${path12.relative(projectDir, patternPath)}. Choose a different name.`);
36324
- }
36325
- if (inventory.patterns.some((entry) => entry.slug === patternSlug)) {
36326
- throw new Error(`A pattern inventory entry already exists for ${patternSlug}. Choose a different name.`);
36327
- }
36371
+ assertScaffoldDoesNotExist({
36372
+ filesystemCollisions: [
36373
+ {
36374
+ label: "A pattern",
36375
+ relativePath: path12.join("src", "patterns", `${patternSlug}.php`)
36376
+ }
36377
+ ],
36378
+ inventoryCollision: {
36379
+ entries: inventory.patterns,
36380
+ exists: (entry) => entry.slug === patternSlug,
36381
+ message: `A pattern inventory entry already exists for ${patternSlug}. Choose a different name.`
36382
+ },
36383
+ projectDir
36384
+ });
36328
36385
  }
36329
36386
  function assertBindingSourceDoesNotExist(projectDir, bindingSourceSlug, inventory) {
36330
- const bindingSourceDir = path12.join(projectDir, "src", "bindings", bindingSourceSlug);
36331
- if (fs8.existsSync(bindingSourceDir)) {
36332
- throw new Error(`A binding source already exists at ${path12.relative(projectDir, bindingSourceDir)}. Choose a different name.`);
36333
- }
36334
- if (inventory.bindingSources.some((entry) => entry.slug === bindingSourceSlug)) {
36335
- throw new Error(`A binding source inventory entry already exists for ${bindingSourceSlug}. Choose a different name.`);
36336
- }
36387
+ assertScaffoldDoesNotExist({
36388
+ filesystemCollisions: [
36389
+ {
36390
+ label: "A binding source",
36391
+ relativePath: path12.join("src", "bindings", bindingSourceSlug)
36392
+ }
36393
+ ],
36394
+ inventoryCollision: {
36395
+ entries: inventory.bindingSources,
36396
+ exists: (entry) => entry.slug === bindingSourceSlug,
36397
+ message: `A binding source inventory entry already exists for ${bindingSourceSlug}. Choose a different name.`
36398
+ },
36399
+ projectDir
36400
+ });
36337
36401
  }
36338
36402
  function assertRestResourceDoesNotExist(projectDir, restResourceSlug, inventory) {
36339
- const restResourceDir = path12.join(projectDir, "src", "rest", restResourceSlug);
36340
- const restResourcePhpPath = path12.join(projectDir, "inc", "rest", `${restResourceSlug}.php`);
36341
- if (fs8.existsSync(restResourceDir)) {
36342
- throw new Error(`A REST resource already exists at ${path12.relative(projectDir, restResourceDir)}. Choose a different name.`);
36343
- }
36344
- if (fs8.existsSync(restResourcePhpPath)) {
36345
- throw new Error(`A REST resource bootstrap already exists at ${path12.relative(projectDir, restResourcePhpPath)}. Choose a different name.`);
36346
- }
36347
- if (inventory.restResources.some((entry) => entry.slug === restResourceSlug)) {
36348
- throw new Error(`A REST resource inventory entry already exists for ${restResourceSlug}. Choose a different name.`);
36349
- }
36403
+ assertScaffoldDoesNotExist({
36404
+ filesystemCollisions: [
36405
+ {
36406
+ label: "A REST resource",
36407
+ relativePath: path12.join("src", "rest", restResourceSlug)
36408
+ },
36409
+ {
36410
+ label: "A REST resource bootstrap",
36411
+ relativePath: path12.join("inc", "rest", `${restResourceSlug}.php`)
36412
+ }
36413
+ ],
36414
+ inventoryCollision: {
36415
+ entries: inventory.restResources,
36416
+ exists: (entry) => entry.slug === restResourceSlug,
36417
+ message: `A REST resource inventory entry already exists for ${restResourceSlug}. Choose a different name.`
36418
+ },
36419
+ projectDir
36420
+ });
36350
36421
  }
36351
36422
  function assertAdminViewDoesNotExist(projectDir, adminViewSlug, inventory) {
36352
- const adminViewDir = path12.join(projectDir, "src", "admin-views", adminViewSlug);
36353
- const adminViewPhpPath = path12.join(projectDir, "inc", "admin-views", `${adminViewSlug}.php`);
36354
- if (fs8.existsSync(adminViewDir)) {
36355
- throw new Error(`An admin view already exists at ${path12.relative(projectDir, adminViewDir)}. Choose a different name.`);
36356
- }
36357
- if (fs8.existsSync(adminViewPhpPath)) {
36358
- throw new Error(`An admin view bootstrap already exists at ${path12.relative(projectDir, adminViewPhpPath)}. Choose a different name.`);
36359
- }
36360
- if (inventory.adminViews.some((entry) => entry.slug === adminViewSlug)) {
36361
- throw new Error(`An admin view inventory entry already exists for ${adminViewSlug}. Choose a different name.`);
36362
- }
36423
+ assertScaffoldDoesNotExist({
36424
+ filesystemCollisions: [
36425
+ {
36426
+ label: "An admin view",
36427
+ relativePath: path12.join("src", "admin-views", adminViewSlug)
36428
+ },
36429
+ {
36430
+ label: "An admin view bootstrap",
36431
+ relativePath: path12.join("inc", "admin-views", `${adminViewSlug}.php`)
36432
+ }
36433
+ ],
36434
+ inventoryCollision: {
36435
+ entries: inventory.adminViews,
36436
+ exists: (entry) => entry.slug === adminViewSlug,
36437
+ message: `An admin view inventory entry already exists for ${adminViewSlug}. Choose a different name.`
36438
+ },
36439
+ projectDir
36440
+ });
36363
36441
  }
36364
36442
  function assertAbilityDoesNotExist(projectDir, abilitySlug, inventory) {
36365
- const abilityDir = path12.join(projectDir, "src", "abilities", abilitySlug);
36366
- const abilityPhpPath = path12.join(projectDir, "inc", "abilities", `${abilitySlug}.php`);
36367
- if (fs8.existsSync(abilityDir)) {
36368
- throw new Error(`An ability scaffold already exists at ${path12.relative(projectDir, abilityDir)}. Choose a different name.`);
36369
- }
36370
- if (fs8.existsSync(abilityPhpPath)) {
36371
- throw new Error(`An ability bootstrap already exists at ${path12.relative(projectDir, abilityPhpPath)}. Choose a different name.`);
36372
- }
36373
- if (inventory.abilities.some((entry) => entry.slug === abilitySlug)) {
36374
- throw new Error(`An ability inventory entry already exists for ${abilitySlug}. Choose a different name.`);
36375
- }
36443
+ assertScaffoldDoesNotExist({
36444
+ filesystemCollisions: [
36445
+ {
36446
+ label: "An ability scaffold",
36447
+ relativePath: path12.join("src", "abilities", abilitySlug)
36448
+ },
36449
+ {
36450
+ label: "An ability bootstrap",
36451
+ relativePath: path12.join("inc", "abilities", `${abilitySlug}.php`)
36452
+ }
36453
+ ],
36454
+ inventoryCollision: {
36455
+ entries: inventory.abilities,
36456
+ exists: (entry) => entry.slug === abilitySlug,
36457
+ message: `An ability inventory entry already exists for ${abilitySlug}. Choose a different name.`
36458
+ },
36459
+ projectDir
36460
+ });
36376
36461
  }
36377
36462
  function assertAiFeatureDoesNotExist(projectDir, aiFeatureSlug, inventory) {
36378
- const aiFeatureDir = path12.join(projectDir, "src", "ai-features", aiFeatureSlug);
36379
- const aiFeaturePhpPath = path12.join(projectDir, "inc", "ai-features", `${aiFeatureSlug}.php`);
36380
- if (fs8.existsSync(aiFeatureDir)) {
36381
- throw new Error(`An AI feature already exists at ${path12.relative(projectDir, aiFeatureDir)}. Choose a different name.`);
36382
- }
36383
- if (fs8.existsSync(aiFeaturePhpPath)) {
36384
- throw new Error(`An AI feature bootstrap already exists at ${path12.relative(projectDir, aiFeaturePhpPath)}. Choose a different name.`);
36385
- }
36386
- if (inventory.aiFeatures.some((entry) => entry.slug === aiFeatureSlug)) {
36387
- throw new Error(`An AI feature inventory entry already exists for ${aiFeatureSlug}. Choose a different name.`);
36388
- }
36463
+ assertScaffoldDoesNotExist({
36464
+ filesystemCollisions: [
36465
+ {
36466
+ label: "An AI feature",
36467
+ relativePath: path12.join("src", "ai-features", aiFeatureSlug)
36468
+ },
36469
+ {
36470
+ label: "An AI feature bootstrap",
36471
+ relativePath: path12.join("inc", "ai-features", `${aiFeatureSlug}.php`)
36472
+ }
36473
+ ],
36474
+ inventoryCollision: {
36475
+ entries: inventory.aiFeatures,
36476
+ exists: (entry) => entry.slug === aiFeatureSlug,
36477
+ message: `An AI feature inventory entry already exists for ${aiFeatureSlug}. Choose a different name.`
36478
+ },
36479
+ projectDir
36480
+ });
36389
36481
  }
36390
36482
  function assertEditorPluginDoesNotExist(projectDir, editorPluginSlug, inventory) {
36391
- const editorPluginDir = path12.join(projectDir, "src", "editor-plugins", editorPluginSlug);
36392
- if (fs8.existsSync(editorPluginDir)) {
36393
- throw new Error(`An editor plugin already exists at ${path12.relative(projectDir, editorPluginDir)}. Choose a different name.`);
36394
- }
36395
- if (inventory.editorPlugins.some((entry) => entry.slug === editorPluginSlug)) {
36396
- throw new Error(`An editor plugin inventory entry already exists for ${editorPluginSlug}. Choose a different name.`);
36397
- }
36483
+ assertScaffoldDoesNotExist({
36484
+ filesystemCollisions: [
36485
+ {
36486
+ label: "An editor plugin",
36487
+ relativePath: path12.join("src", "editor-plugins", editorPluginSlug)
36488
+ }
36489
+ ],
36490
+ inventoryCollision: {
36491
+ entries: inventory.editorPlugins,
36492
+ exists: (entry) => entry.slug === editorPluginSlug,
36493
+ message: `An editor plugin inventory entry already exists for ${editorPluginSlug}. Choose a different name.`
36494
+ },
36495
+ projectDir
36496
+ });
36398
36497
  }
36399
36498
  function formatAddHelpText() {
36400
36499
  return `Usage:
@@ -211339,6 +211438,27 @@ function ensureInterfaceField(source, interfaceName, fieldName, fieldSource) {
211339
211438
  return `${start}${body}${body.length > 0 && !body.endsWith(lineEnding) ? lineEnding : ""}${formattedFieldSource}${end}`;
211340
211439
  });
211341
211440
  }
211441
+ function normalizeInterfaceFieldBlock(source, interfaceName, fieldName, fieldSource, requiredFragments) {
211442
+ const interfacePattern = new RegExp(`(export\\s+interface\\s+${escapeRegex2(interfaceName)}\\s*\\{\\r?\\n)([\\s\\S]*?)(\\r?\\n\\})`, "u");
211443
+ return source.replace(interfacePattern, (match3, start, body, end) => {
211444
+ const fieldPattern = new RegExp(`(^([ \\t]*)${escapeRegex2(fieldName)}\\??:\\s*\\{[ \\t]*\\r?\\n)([\\s\\S]*?)(^\\2\\};\\r?\\n?)`, "mu");
211445
+ const fieldMatch = fieldPattern.exec(body);
211446
+ if (!fieldMatch) {
211447
+ return match3;
211448
+ }
211449
+ const existingFieldSource = fieldMatch[0];
211450
+ if (requiredFragments.every((fragment) => existingFieldSource.includes(fragment))) {
211451
+ return match3;
211452
+ }
211453
+ const lineEnding = start.endsWith(`\r
211454
+ `) ? `\r
211455
+ ` : `
211456
+ `;
211457
+ const formattedFieldSource = `${fieldSource.replace(/\r?\n$/u, "").split(`
211458
+ `).join(lineEnding)}${lineEnding}`;
211459
+ return `${start}${body.slice(0, fieldMatch.index)}${formattedFieldSource}${body.slice(fieldMatch.index + existingFieldSource.length)}${end}`;
211460
+ });
211461
+ }
211342
211462
  function updateWorkspaceInventorySource(source, {
211343
211463
  blockEntries = [],
211344
211464
  blockStyleEntries = [],
@@ -211370,7 +211490,9 @@ function updateWorkspaceInventorySource(source, {
211370
211490
  nextSource = ensureInterfaceField(nextSource, "WorkspaceBindingSourceConfig", "attribute", "\tattribute?: string;");
211371
211491
  nextSource = ensureInterfaceField(nextSource, "WorkspaceBindingSourceConfig", "block", "\tblock?: string;");
211372
211492
  nextSource = ensureInterfaceField(nextSource, "WorkspaceAbilityConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD);
211493
+ nextSource = normalizeInterfaceFieldBlock(nextSource, "WorkspaceAbilityConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD, ["optionalFeatureIds: string[];", "requiredFeatureIds: string[];"]);
211373
211494
  nextSource = ensureInterfaceField(nextSource, "WorkspaceAiFeatureConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD);
211495
+ nextSource = normalizeInterfaceFieldBlock(nextSource, "WorkspaceAiFeatureConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD, ["optionalFeatureIds: string[];", "requiredFeatureIds: string[];"]);
211374
211496
  nextSource = appendEntriesAtMarker(nextSource, EDITOR_PLUGIN_CONFIG_ENTRY_MARKER, editorPluginEntries);
211375
211497
  return nextSource;
211376
211498
  }
@@ -211473,7 +211595,9 @@ export const REST_RESOURCES: WorkspaceRestResourceConfig[] = [
211473
211595
  wordpress?: string;
211474
211596
  };
211475
211597
  mode: 'baseline' | 'optional' | 'required';
211598
+ optionalFeatureIds: string[];
211476
211599
  optionalFeatures: string[];
211600
+ requiredFeatureIds: string[];
211477
211601
  requiredFeatures: string[];
211478
211602
  runtimeGates: string[];
211479
211603
  };
@@ -224640,7 +224764,9 @@ function createScaffoldCompatibilityConfig(policy) {
224640
224764
  return {
224641
224765
  hardMinimums: capabilityPlan.hardMinimums,
224642
224766
  mode: getPolicyMode(capabilityPlan),
224767
+ optionalFeatureIds: capabilityPlan.optionalFeatures.map((feature) => feature.id),
224643
224768
  optionalFeatures: capabilityPlan.optionalFeatures.map((feature) => feature.label),
224769
+ requiredFeatureIds: capabilityPlan.requiredFeatures.map((feature) => feature.id),
224644
224770
  requiredFeatures: capabilityPlan.requiredFeatures.map((feature) => feature.label),
224645
224771
  runtimeGates: [
224646
224772
  ...capabilityPlan.requiredFeatures.flatMap(formatRuntimeGate),
@@ -226882,7 +227008,9 @@ type InteractivityActionShape = object;
226882
227008
  type InteractivityCallbackShape = object;
226883
227009
  type InteractivityContextShape = object;
226884
227010
  type InteractivityStateShape = object;
226885
- type InteractivityCallable = CallableFunction;
227011
+ type InteractivityCallable =
227012
+ | ((...args: unknown[]) => unknown)
227013
+ | ReturnType<typeof import('@wordpress/interactivity').withSyncEvent>;
226886
227014
  type InteractivityKey<T extends object> = Extract<keyof T, string>;
226887
227015
  type InteractivityMethodKey<T extends object> = {
226888
227016
  [Key in InteractivityKey<T>]: T[Key] extends InteractivityCallable ? Key : never;
@@ -226985,7 +227113,7 @@ export function defineInteractivityStore<
226985
227113
  };
226986
227114
  }
226987
227115
 
226988
- type InteractivityActionHandler = CallableFunction;
227116
+ type InteractivityActionHandler = InteractivityCallable;
226989
227117
 
226990
227118
  export interface {{pascalCase}}StoreActions {
226991
227119
  handleClick: InteractivityActionHandler;
@@ -232316,8 +232444,10 @@ registerBlockBindingsSource( {
232316
232444
  `;
232317
232445
  }
232318
232446
  function resolveBindingTarget(options, namespace) {
232319
- const hasBlock = options.blockName !== undefined && options.blockName.trim().length > 0;
232320
- const hasAttribute = options.attributeName !== undefined && options.attributeName.trim().length > 0;
232447
+ const blockName = normalizeOptionalCliString(options.blockName);
232448
+ const attributeName = normalizeOptionalCliString(options.attributeName);
232449
+ const hasBlock = blockName !== undefined;
232450
+ const hasAttribute = attributeName !== undefined;
232321
232451
  if (!hasBlock && !hasAttribute) {
232322
232452
  return;
232323
232453
  }
@@ -232325,8 +232455,8 @@ function resolveBindingTarget(options, namespace) {
232325
232455
  throw new Error("`wp-typia add binding-source` requires --block and --attribute to be provided together.");
232326
232456
  }
232327
232457
  return {
232328
- attributeName: assertValidBindingAttributeName(options.attributeName ?? ""),
232329
- blockSlug: resolveBindingTargetBlockSlug(options.blockName ?? "", namespace)
232458
+ attributeName: assertValidBindingAttributeName(attributeName ?? ""),
232459
+ blockSlug: resolveBindingTargetBlockSlug(blockName ?? "", namespace)
232330
232460
  };
232331
232461
  }
232332
232462
  function formatBindingAttributeTypeMember(attributeName) {
@@ -233082,6 +233212,7 @@ var init_cli_add_workspace_assets = __esm(() => {
233082
233212
  init_workspace_project();
233083
233213
  init_workspace_inventory();
233084
233214
  init_cli_add_shared();
233215
+ init_cli_validation();
233085
233216
  import_typescript2 = __toESM(require_typescript(), 1);
233086
233217
  BINDING_ATTRIBUTE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/u;
233087
233218
  });
@@ -234331,22 +234462,10 @@ var init_cli_add_workspace_rest = __esm(() => {
234331
234462
  init_workspace_project();
234332
234463
  });
234333
234464
 
234334
- // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability.ts
234335
- import fs44 from "fs";
234336
- import { promises as fsp21 } from "fs";
234337
- import path57 from "path";
234338
- import { syncTypeSchemas as syncTypeSchemas3 } from "@wp-typia/block-runtime/metadata-core";
234339
- function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
234340
- if (!existingVersion) {
234341
- return requiredVersion;
234342
- }
234343
- const existingMinimum = import_semver2.default.minVersion(existingVersion);
234344
- const requiredMinimum = import_semver2.default.minVersion(requiredVersion);
234345
- if (!existingMinimum || !requiredMinimum) {
234346
- return requiredVersion;
234347
- }
234348
- return import_semver2.default.gte(existingMinimum, requiredMinimum) ? existingVersion : requiredVersion;
234349
- }
234465
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-types.ts
234466
+ var ABILITY_SERVER_GLOB = "/inc/abilities/*.php", ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end", ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start", WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities", WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
234467
+
234468
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-templates.ts
234350
234469
  function toAbilityCategorySlug(workspaceNamespace) {
234351
234470
  const normalizedNamespace = workspaceNamespace.replace(/[^a-z0-9-]+/gu, "-").replace(/-{2,}/gu, "-").replace(/^-|-$/gu, "");
234352
234471
  return `${normalizedNamespace || "workspace"}-workflows`;
@@ -234811,6 +234930,27 @@ function buildAbilityRegistrySource(abilitySlugs) {
234811
234930
  `).concat(`
234812
234931
  `);
234813
234932
  }
234933
+ var init_cli_add_workspace_ability_templates = __esm(() => {
234934
+ init_scaffold_compatibility();
234935
+ init_cli_add_shared();
234936
+ });
234937
+
234938
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability-scaffold.ts
234939
+ import fs44 from "fs";
234940
+ import { promises as fsp21 } from "fs";
234941
+ import path57 from "path";
234942
+ import { syncTypeSchemas as syncTypeSchemas3 } from "@wp-typia/block-runtime/metadata-core";
234943
+ function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
234944
+ if (!existingVersion) {
234945
+ return requiredVersion;
234946
+ }
234947
+ const existingMinimum = import_semver2.default.minVersion(existingVersion);
234948
+ const requiredMinimum = import_semver2.default.minVersion(requiredVersion);
234949
+ if (!existingMinimum || !requiredMinimum) {
234950
+ return requiredVersion;
234951
+ }
234952
+ return import_semver2.default.gte(existingMinimum, requiredMinimum) ? existingVersion : requiredVersion;
234953
+ }
234814
234954
  function resolveAbilityRegistryPath(projectDir) {
234815
234955
  const abilitiesDir = path57.join(projectDir, "src", "abilities");
234816
234956
  return [path57.join(abilitiesDir, "index.ts"), path57.join(abilitiesDir, "index.js")].find((candidatePath) => fs44.existsSync(candidatePath)) ?? path57.join(abilitiesDir, "index.ts");
@@ -235022,21 +235162,29 @@ async function ensureAbilityBuildScriptAnchors(workspace) {
235022
235162
  }
235023
235163
  const sharedEntriesPattern = /(for\s*\(\s*const\s+relativePath\s+of\s+\[)([\s\S]*?)(\]\s*\)\s*\{)/u;
235024
235164
  const match3 = nextSource.match(sharedEntriesPattern);
235025
- if (!match3 || !match3[2].includes("src/bindings/index.ts") || !match3[2].includes("src/editor-plugins/index.ts")) {
235165
+ if (!match3 || !/['"]src\/bindings\/index\.(?:ts|js)['"]/u.test(match3[2]) || !/['"]src\/editor-plugins\/index\.(?:tsx|ts|js)['"]/u.test(match3[2])) {
235026
235166
  throw new Error([
235027
235167
  `ensureAbilityBuildScriptAnchors could not patch ${path57.basename(buildScriptPath)}.`,
235028
235168
  "Missing the expected shared editor entries array in scripts/build-workspace.mjs.",
235029
235169
  "Restore the generated template or wire abilities/index manually before retrying."
235030
235170
  ].join(" "));
235031
235171
  }
235032
- nextSource = nextSource.replace(sharedEntriesPattern, `$1
235033
- 'src/bindings/index.ts',
235034
- 'src/bindings/index.js',
235035
- 'src/editor-plugins/index.ts',
235036
- 'src/editor-plugins/index.js',
235037
- 'src/abilities/index.ts',
235038
- 'src/abilities/index.js',
235039
- $3`);
235172
+ nextSource = nextSource.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
235173
+ const missingAbilityEntries = [
235174
+ "'src/abilities/index.ts'",
235175
+ "'src/abilities/index.js'"
235176
+ ].filter((entry) => !sharedEntries.includes(entry));
235177
+ if (missingAbilityEntries.length === 0) {
235178
+ return fullMatch;
235179
+ }
235180
+ const itemIndent = sharedEntries.match(/\n([ \t]*)['"]/u)?.[1] ?? "\t\t";
235181
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
235182
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
235183
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
235184
+ const nextEntries = `${trimmedEntries}${separator}` + missingAbilityEntries.map((entry) => `
235185
+ ${itemIndent}${entry},`).join("") + trailingWhitespace;
235186
+ return fullMatch.replace(sharedEntries, nextEntries);
235187
+ });
235040
235188
  return nextSource;
235041
235189
  });
235042
235190
  }
@@ -235065,8 +235213,7 @@ async function ensureAbilityWebpackAnchors(workspace) {
235065
235213
  entries.push( [ entryName, entryPath ] );
235066
235214
  break;
235067
235215
  }
235068
- }
235069
- $2`);
235216
+ }$2`);
235070
235217
  }
235071
235218
  const sharedEntriesPattern = /for\s*\(\s*const\s+\[\s*entryName\s*,\s*candidates\s*\]\s+of\s+\[([\s\S]*?)\]\s*\)\s*\{/u;
235072
235219
  const match3 = source.match(sharedEntriesPattern);
@@ -235077,31 +235224,33 @@ $2`);
235077
235224
  "Restore the generated template or wire abilities/index manually before retrying."
235078
235225
  ].join(" "));
235079
235226
  }
235080
- return source.replace(sharedEntriesPattern, `for ( const [ entryName, candidates ] of [
235081
- [
235082
- 'bindings/index',
235083
- [ 'src/bindings/index.ts', 'src/bindings/index.js' ],
235084
- ],
235085
- [
235086
- 'editor-plugins/index',
235087
- [ 'src/editor-plugins/index.ts', 'src/editor-plugins/index.js' ],
235088
- ],
235089
- [
235090
- 'abilities/index',
235091
- [ 'src/abilities/index.ts', 'src/abilities/index.js' ],
235092
- ],
235093
- ] ) {`);
235227
+ return source.replace(sharedEntriesPattern, (fullMatch, sharedEntries) => {
235228
+ if (/['"]abilities\/index['"]/u.test(sharedEntries)) {
235229
+ return fullMatch;
235230
+ }
235231
+ const tupleIndent = sharedEntries.match(/\n([ \t]*)\[/u)?.[1] ?? "\t\t";
235232
+ const nestedIndent = `${tupleIndent} `;
235233
+ const trimmedEntries = sharedEntries.replace(/\s*$/u, "");
235234
+ const trailingWhitespace = sharedEntries.slice(trimmedEntries.length);
235235
+ const separator = trimmedEntries.trimEnd().endsWith(",") ? "" : ",";
235236
+ const abilityTuple = [
235237
+ `${tupleIndent}[`,
235238
+ `${nestedIndent}'abilities/index',`,
235239
+ `${nestedIndent}[ 'src/abilities/index.ts', 'src/abilities/index.js' ],`,
235240
+ `${tupleIndent}],`
235241
+ ].join(`
235242
+ `);
235243
+ const nextEntries = `${trimmedEntries}${separator}
235244
+ ${abilityTuple}` + trailingWhitespace;
235245
+ return fullMatch.replace(sharedEntries, nextEntries);
235246
+ });
235094
235247
  });
235095
235248
  }
235096
- async function runAddAbilityCommand({
235097
- abilityName,
235098
- cwd = process.cwd()
235249
+ async function scaffoldAbilityWorkspace({
235250
+ abilitySlug,
235251
+ compatibilityPolicy,
235252
+ workspace
235099
235253
  }) {
235100
- const workspace = resolveWorkspaceProject(cwd);
235101
- const abilitySlug = assertValidGeneratedSlug("Ability name", normalizeBlockSlug(abilityName), "wp-typia add ability <name>");
235102
- const inventory = readWorkspaceInventory(workspace.projectDir);
235103
- assertAbilityDoesNotExist(workspace.projectDir, abilitySlug, inventory);
235104
- const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY);
235105
235254
  const blockConfigPath = path57.join(workspace.projectDir, "scripts", "block-config.ts");
235106
235255
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
235107
235256
  const buildScriptPath = path57.join(workspace.projectDir, "scripts", "build-workspace.mjs");
@@ -235160,27 +235309,53 @@ async function runAddAbilityCommand({
235160
235309
  });
235161
235310
  await writeAbilityRegistry(workspace.projectDir, abilitySlug);
235162
235311
  await appendWorkspaceInventoryEntries(workspace.projectDir, {
235163
- abilityEntries: [buildAbilityConfigEntry(abilitySlug, compatibilityPolicy)]
235312
+ abilityEntries: [
235313
+ buildAbilityConfigEntry(abilitySlug, compatibilityPolicy)
235314
+ ]
235164
235315
  });
235165
- return {
235166
- abilitySlug,
235167
- projectDir: workspace.projectDir
235168
- };
235169
235316
  } catch (error48) {
235170
235317
  await rollbackWorkspaceMutation(mutationSnapshot);
235171
235318
  throw error48;
235172
235319
  }
235173
235320
  }
235174
- var import_semver2, ABILITY_SERVER_GLOB = "/inc/abilities/*.php", ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end", ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start", WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities", WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
235175
- var init_cli_add_workspace_ability = __esm(() => {
235321
+ var import_semver2;
235322
+ var init_cli_add_workspace_ability_scaffold = __esm(() => {
235176
235323
  init_workspace_inventory();
235177
- init_workspace_project();
235324
+ init_cli_add_workspace_ability_templates();
235178
235325
  init_cli_add_shared();
235179
235326
  init_scaffold_compatibility();
235180
235327
  init_package_versions();
235181
235328
  import_semver2 = __toESM(require_semver2(), 1);
235182
235329
  });
235183
235330
 
235331
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ability.ts
235332
+ async function runAddAbilityCommand({
235333
+ abilityName,
235334
+ cwd = process.cwd()
235335
+ }) {
235336
+ const workspace = resolveWorkspaceProject(cwd);
235337
+ const abilitySlug = assertValidGeneratedSlug("Ability name", normalizeBlockSlug(abilityName), "wp-typia add ability <name>");
235338
+ const inventory = readWorkspaceInventory(workspace.projectDir);
235339
+ assertAbilityDoesNotExist(workspace.projectDir, abilitySlug, inventory);
235340
+ const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(REQUIRED_WORKSPACE_ABILITY_COMPATIBILITY);
235341
+ await scaffoldAbilityWorkspace({
235342
+ abilitySlug,
235343
+ compatibilityPolicy,
235344
+ workspace
235345
+ });
235346
+ return {
235347
+ abilitySlug,
235348
+ projectDir: workspace.projectDir
235349
+ };
235350
+ }
235351
+ var init_cli_add_workspace_ability = __esm(() => {
235352
+ init_cli_add_shared();
235353
+ init_cli_add_workspace_ability_scaffold();
235354
+ init_workspace_inventory();
235355
+ init_workspace_project();
235356
+ init_scaffold_compatibility();
235357
+ });
235358
+
235184
235359
  // ../wp-typia-project-tools/src/runtime/schema-core.ts
235185
235360
  var exports_schema_core = {};
235186
235361
  import"@wp-typia/block-runtime/schema-core";
@@ -235415,6 +235590,45 @@ export interface ${pascalCase}AiFeatureResponse {
235415
235590
  result: ${pascalCase}AiFeatureResult;
235416
235591
  telemetry: ${pascalCase}AiFeatureTelemetry;
235417
235592
  }
235593
+
235594
+ export type ${pascalCase}AiFeatureSupportProbeMode = 'request-time';
235595
+
235596
+ export type ${pascalCase}AiFeatureUnavailableErrorCode =
235597
+ 'ai_client_unavailable';
235598
+
235599
+ export type ${pascalCase}AiFeatureUnavailableReasonCode =
235600
+ | 'missing-wordpress-ai-client'
235601
+ | 'request-time-support-probe';
235602
+
235603
+ export interface ${pascalCase}AiFeatureSupportReason {
235604
+ code: ${pascalCase}AiFeatureUnavailableReasonCode;
235605
+ label: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
235606
+ message: string & tags.MinLength< 1 > & tags.MaxLength< 4000 >;
235607
+ }
235608
+
235609
+ export interface ${pascalCase}AiFeatureSupportMetadata {
235610
+ featureLabel: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
235611
+ featureSlug: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
235612
+ compatibility: {
235613
+ hardMinimums: {
235614
+ php?: string;
235615
+ wordpress?: string;
235616
+ };
235617
+ mode: 'baseline' | 'optional' | 'required';
235618
+ optionalFeatureIds: string[];
235619
+ optionalFeatures: string[];
235620
+ requiredFeatureIds: string[];
235621
+ requiredFeatures: string[];
235622
+ runtimeGates: string[];
235623
+ };
235624
+ supportProbe: {
235625
+ endpointMethod: 'POST';
235626
+ endpointPath: string & tags.MinLength< 1 > & tags.MaxLength< 200 >;
235627
+ mode: ${pascalCase}AiFeatureSupportProbeMode;
235628
+ unavailableErrorCode: ${pascalCase}AiFeatureUnavailableErrorCode;
235629
+ };
235630
+ unavailableReasons: ${pascalCase}AiFeatureSupportReason[];
235631
+ }
235418
235632
  `;
235419
235633
  }
235420
235634
  function buildAiFeatureValidatorsSource(aiFeatureSlug) {
@@ -235450,6 +235664,8 @@ export const apiValidators = {
235450
235664
  }
235451
235665
  function buildAiFeatureApiSource(aiFeatureSlug) {
235452
235666
  const pascalCase = toPascalCase(aiFeatureSlug);
235667
+ const compatibility = createScaffoldCompatibilityConfig(resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY));
235668
+ const title = toTitleCase(aiFeatureSlug);
235453
235669
  return `import {
235454
235670
  callEndpoint,
235455
235671
  resolveRestRouteUrl,
@@ -235457,6 +235673,7 @@ function buildAiFeatureApiSource(aiFeatureSlug) {
235457
235673
 
235458
235674
  import type {
235459
235675
  ${pascalCase}AiFeatureRequest,
235676
+ ${pascalCase}AiFeatureSupportMetadata,
235460
235677
  } from './api-types';
235461
235678
  import {
235462
235679
  run${pascalCase}AiFeatureEndpoint,
@@ -235483,6 +235700,14 @@ function resolveRestNonce( fallback?: string ): string | undefined {
235483
235700
  : undefined;
235484
235701
  }
235485
235702
 
235703
+ function isPlainObject( value: unknown ): value is Record< string, unknown > {
235704
+ return (
235705
+ !! value &&
235706
+ typeof value === 'object' &&
235707
+ ! Array.isArray( value )
235708
+ );
235709
+ }
235710
+
235486
235711
  export const aiFeatureRunEndpoint = {
235487
235712
  ...run${pascalCase}AiFeatureEndpoint,
235488
235713
  buildRequestOptions: () => {
@@ -235498,6 +235723,63 @@ export const aiFeatureRunEndpoint = {
235498
235723
  },
235499
235724
  };
235500
235725
 
235726
+ export const aiFeatureSupportMetadata = {
235727
+ compatibility: ${JSON.stringify(compatibility, null, "\t")},
235728
+ featureLabel: ${quoteTsString(title)},
235729
+ featureSlug: ${quoteTsString(aiFeatureSlug)},
235730
+ supportProbe: {
235731
+ endpointMethod: 'POST',
235732
+ endpointPath: aiFeatureRunEndpoint.path,
235733
+ mode: 'request-time',
235734
+ unavailableErrorCode: 'ai_client_unavailable',
235735
+ },
235736
+ unavailableReasons: [
235737
+ {
235738
+ code: 'missing-wordpress-ai-client',
235739
+ label: 'WordPress AI Client unavailable',
235740
+ message:
235741
+ 'This AI feature stays disabled until the WordPress AI Client is available on the site.',
235742
+ },
235743
+ {
235744
+ code: 'request-time-support-probe',
235745
+ label: 'Support is checked at request time',
235746
+ message:
235747
+ 'Support is verified when the feature runs, so editor and admin UIs should degrade gracefully when the site rejects the request.',
235748
+ },
235749
+ ],
235750
+ } satisfies ${pascalCase}AiFeatureSupportMetadata;
235751
+
235752
+ export function getAiFeatureSupportHintLines() {
235753
+ return aiFeatureSupportMetadata.unavailableReasons.map(
235754
+ ( reason ) => reason.message
235755
+ );
235756
+ }
235757
+
235758
+ export function isAiFeatureSupportUnavailableError( error: unknown ) {
235759
+ if ( ! isPlainObject( error ) ) {
235760
+ return false;
235761
+ }
235762
+
235763
+ const data = isPlainObject( error.data ) ? error.data : undefined;
235764
+ return (
235765
+ error.code === aiFeatureSupportMetadata.supportProbe.unavailableErrorCode ||
235766
+ data?.status === 501
235767
+ );
235768
+ }
235769
+
235770
+ export function resolveAiFeatureUnavailableMessage( error: unknown ) {
235771
+ if (
235772
+ isPlainObject( error ) &&
235773
+ typeof error.message === 'string' &&
235774
+ error.message.length > 0
235775
+ ) {
235776
+ return error.message;
235777
+ }
235778
+
235779
+ return aiFeatureSupportMetadata.unavailableReasons[ 0 ]?.message ??
235780
+ 'This AI feature is currently unavailable.';
235781
+ }
235782
+
235501
235783
  export function runAiFeature( request: ${pascalCase}AiFeatureRequest ) {
235502
235784
  return callEndpoint( aiFeatureRunEndpoint, request );
235503
235785
  }
@@ -235516,6 +235798,10 @@ import type {
235516
235798
  } from './api-types';
235517
235799
  import {
235518
235800
  aiFeatureRunEndpoint,
235801
+ aiFeatureSupportMetadata,
235802
+ getAiFeatureSupportHintLines,
235803
+ isAiFeatureSupportUnavailableError,
235804
+ resolveAiFeatureUnavailableMessage,
235519
235805
  } from './api';
235520
235806
 
235521
235807
  export type UseRun${pascalCase}AiFeatureMutationOptions =
@@ -235530,6 +235816,13 @@ export function useRun${pascalCase}AiFeatureMutation(
235530
235816
  ) {
235531
235817
  return useEndpointMutation( aiFeatureRunEndpoint, options );
235532
235818
  }
235819
+
235820
+ export {
235821
+ aiFeatureSupportMetadata,
235822
+ getAiFeatureSupportHintLines,
235823
+ isAiFeatureSupportUnavailableError,
235824
+ resolveAiFeatureUnavailableMessage,
235825
+ };
235533
235826
  `;
235534
235827
  }
235535
235828
  function buildAiFeatureSyncScriptSource() {
@@ -235942,9 +236235,7 @@ var init_cli_add_workspace_ai_anchors = __esm(() => {
235942
236235
  init_cli_add_shared();
235943
236236
  });
235944
236237
 
235945
- // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai.ts
235946
- import { promises as fsp23 } from "fs";
235947
- import path60 from "path";
236238
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai-templates.ts
235948
236239
  function buildAiFeaturePhpSource(aiFeatureSlug, namespace, phpPrefix, textDomain) {
235949
236240
  const aiFeatureTitle = toTitleCase(aiFeatureSlug);
235950
236241
  const aiFeaturePhpId = aiFeatureSlug.replace(/-/g, "_");
@@ -235953,18 +236244,40 @@ function buildAiFeaturePhpSource(aiFeatureSlug, namespace, phpPrefix, textDomain
235953
236244
  const normalizeSchemaFunctionName = `${phpPrefix}_${aiFeaturePhpId}_sanitize_ai_feature_schema`;
235954
236245
  const validatePayloadFunctionName = `${phpPrefix}_${aiFeaturePhpId}_validate_ai_feature_payload`;
235955
236246
  const canManageFunctionName = `${phpPrefix}_${aiFeaturePhpId}_can_manage_ai_feature`;
236247
+ const normalizePromptPayloadFunctionName = `${phpPrefix}_${aiFeaturePhpId}_normalize_ai_feature_prompt_payload`;
235956
236248
  const buildPromptFunctionName = `${phpPrefix}_${aiFeaturePhpId}_build_ai_feature_prompt`;
236249
+ const resolvePromptOptionsFunctionName = `${phpPrefix}_${aiFeaturePhpId}_resolve_ai_feature_prompt_options`;
235957
236250
  const normalizeProviderTypeFunctionName = `${phpPrefix}_${aiFeaturePhpId}_normalize_provider_type`;
235958
236251
  const buildTelemetryFunctionName = `${phpPrefix}_${aiFeaturePhpId}_build_ai_feature_telemetry`;
236252
+ const resolveUnavailableMessageFunctionName = `${phpPrefix}_${aiFeaturePhpId}_resolve_ai_feature_unavailable_message`;
235959
236253
  const isSupportedFunctionName = `${phpPrefix}_${aiFeaturePhpId}_is_ai_feature_supported`;
235960
236254
  const adminNoticeFunctionName = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_admin_notice`;
235961
236255
  const handlerFunctionName = `${phpPrefix}_${aiFeaturePhpId}_handle_run_ai_feature`;
235962
236256
  const registerRoutesFunctionName = `${phpPrefix}_${aiFeaturePhpId}_register_ai_feature_routes`;
236257
+ const permissionFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_permission`;
236258
+ const promptPayloadFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_prompt_payload`;
236259
+ const promptFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_prompt`;
236260
+ const promptOptionsFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_prompt_options`;
236261
+ const adminNoticeMessageFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_admin_notice_message`;
236262
+ const unavailableMessageFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_unavailable_message`;
236263
+ const telemetryFilterHook = `${phpPrefix}_${aiFeaturePhpId}_ai_feature_telemetry`;
235963
236264
  return `<?php
235964
236265
  if ( ! defined( 'ABSPATH' ) ) {
235965
236266
  return;
235966
236267
  }
235967
236268
 
236269
+ /*
236270
+ * Customization hooks for the ${aiFeatureTitle} AI feature:
236271
+ *
236272
+ * - ${quotePhpString(permissionFilterHook)} filters the default current_user_can( 'edit_posts' ) capability check.
236273
+ * - ${quotePhpString(promptPayloadFilterHook)} filters the validated request payload array before prompt serialization.
236274
+ * - ${quotePhpString(promptFilterHook)} filters the final prompt string after payload normalization.
236275
+ * - ${quotePhpString(promptOptionsFilterHook)} filters prompt options with \`temperature\` and \`modelPreference\` keys.
236276
+ * - ${quotePhpString(adminNoticeMessageFilterHook)} filters the wp-admin notice shown when AI support is unavailable.
236277
+ * - ${quotePhpString(unavailableMessageFilterHook)} filters REST-facing unavailable messages by reason code.
236278
+ * - ${quotePhpString(telemetryFilterHook)} filters the response telemetry array before schema validation. Return a schema-compatible array.
236279
+ */
236280
+
235968
236281
  if ( ! function_exists( '${loadSchemaFunctionName}' ) ) {
235969
236282
  function ${loadSchemaFunctionName}( $schema_name ) {
235970
236283
  $project_root = dirname( __DIR__, 2 );
@@ -236031,17 +236344,111 @@ if ( ! function_exists( '${validatePayloadFunctionName}' ) ) {
236031
236344
  }
236032
236345
 
236033
236346
  if ( ! function_exists( '${canManageFunctionName}' ) ) {
236034
- function ${canManageFunctionName}() {
236035
- return current_user_can( 'edit_posts' );
236347
+ function ${canManageFunctionName}( WP_REST_Request $request = null ) {
236348
+ $permission = apply_filters(
236349
+ ${quotePhpString(permissionFilterHook)},
236350
+ current_user_can( 'edit_posts' ),
236351
+ $request
236352
+ );
236353
+ if ( is_wp_error( $permission ) ) {
236354
+ return $permission;
236355
+ }
236356
+ return (bool) $permission;
236357
+ }
236358
+ }
236359
+
236360
+ if ( ! function_exists( '${normalizePromptPayloadFunctionName}' ) ) {
236361
+ function ${normalizePromptPayloadFunctionName}( array $payload ) {
236362
+ $normalized_payload = apply_filters(
236363
+ ${quotePhpString(promptPayloadFilterHook)},
236364
+ $payload
236365
+ );
236366
+ return is_array( $normalized_payload ) ? $normalized_payload : $payload;
236036
236367
  }
236037
236368
  }
236038
236369
 
236039
236370
  if ( ! function_exists( '${buildPromptFunctionName}' ) ) {
236040
236371
  function ${buildPromptFunctionName}( array $payload ) {
236041
- return sprintf(
236372
+ $normalized_payload = ${normalizePromptPayloadFunctionName}( $payload );
236373
+ $prompt = sprintf(
236042
236374
  'You are helping with the %1$s AI workflow. Read the JSON request payload and return JSON that matches the provided schema. Request payload: %2$s',
236043
236375
  ${quotePhpString(aiFeatureTitle)},
236044
- wp_json_encode( $payload )
236376
+ wp_json_encode( $normalized_payload )
236377
+ );
236378
+ $filtered_prompt = apply_filters(
236379
+ ${quotePhpString(promptFilterHook)},
236380
+ $prompt,
236381
+ $normalized_payload,
236382
+ $payload
236383
+ );
236384
+ return is_string( $filtered_prompt ) && '' !== $filtered_prompt ? $filtered_prompt : $prompt;
236385
+ }
236386
+ }
236387
+
236388
+ if ( ! function_exists( '${resolvePromptOptionsFunctionName}' ) ) {
236389
+ function ${resolvePromptOptionsFunctionName}( array $payload = array() ) {
236390
+ $options = apply_filters(
236391
+ ${quotePhpString(promptOptionsFilterHook)},
236392
+ array(
236393
+ 'modelPreference' => array(),
236394
+ 'temperature' => 0.2,
236395
+ ),
236396
+ $payload
236397
+ );
236398
+ if ( ! is_array( $options ) ) {
236399
+ $options = array();
236400
+ }
236401
+
236402
+ $temperature = 0.2;
236403
+ if ( array_key_exists( 'temperature', $options ) ) {
236404
+ if ( null === $options['temperature'] ) {
236405
+ $temperature = null;
236406
+ } elseif ( is_numeric( $options['temperature'] ) ) {
236407
+ $temperature = (float) $options['temperature'];
236408
+ }
236409
+ }
236410
+
236411
+ $model_preferences = array();
236412
+ if ( isset( $options['modelPreference'] ) ) {
236413
+ $raw_model_preferences = $options['modelPreference'];
236414
+ if ( is_string( $raw_model_preferences ) && '' !== $raw_model_preferences ) {
236415
+ $model_preferences = array( $raw_model_preferences );
236416
+ } elseif ( is_array( $raw_model_preferences ) ) {
236417
+ $model_preferences = array_values(
236418
+ array_filter(
236419
+ array_map(
236420
+ static function ( $candidate ) {
236421
+ if ( is_string( $candidate ) && '' !== $candidate ) {
236422
+ return $candidate;
236423
+ }
236424
+ if ( ! is_array( $candidate ) ) {
236425
+ return null;
236426
+ }
236427
+
236428
+ $normalized = array_values(
236429
+ array_filter(
236430
+ $candidate,
236431
+ static function ( $value ) {
236432
+ return is_string( $value ) && '' !== $value;
236433
+ }
236434
+ )
236435
+ );
236436
+
236437
+ return count( $normalized ) > 0 ? $normalized : null;
236438
+ },
236439
+ $raw_model_preferences
236440
+ ),
236441
+ static function ( $candidate ) {
236442
+ return null !== $candidate;
236443
+ }
236444
+ )
236445
+ );
236446
+ }
236447
+ }
236448
+
236449
+ return array(
236450
+ 'modelPreference' => $model_preferences,
236451
+ 'temperature' => $temperature,
236045
236452
  );
236046
236453
  }
236047
236454
  }
@@ -236057,7 +236464,7 @@ if ( ! function_exists( '${normalizeProviderTypeFunctionName}' ) ) {
236057
236464
  }
236058
236465
 
236059
236466
  if ( ! function_exists( '${buildTelemetryFunctionName}' ) ) {
236060
- function ${buildTelemetryFunctionName}( $result ) {
236467
+ function ${buildTelemetryFunctionName}( $result, array $payload = array(), array $normalized_result = array() ) {
236061
236468
  if (
236062
236469
  ! is_object( $result ) ||
236063
236470
  ! method_exists( $result, 'getId' ) ||
@@ -236117,47 +236524,95 @@ if ( ! function_exists( '${buildTelemetryFunctionName}' ) ) {
236117
236524
  }
236118
236525
  }
236119
236526
 
236120
- return $telemetry;
236527
+ $filtered_telemetry = apply_filters(
236528
+ ${quotePhpString(telemetryFilterHook)},
236529
+ $telemetry,
236530
+ $result,
236531
+ $payload,
236532
+ $normalized_result
236533
+ );
236534
+ return is_array( $filtered_telemetry ) ? $filtered_telemetry : $telemetry;
236535
+ }
236536
+ }
236537
+
236538
+ if ( ! function_exists( '${resolveUnavailableMessageFunctionName}' ) ) {
236539
+ function ${resolveUnavailableMessageFunctionName}( $message, $reason, array $context = array() ) {
236540
+ $filtered_message = apply_filters(
236541
+ ${quotePhpString(unavailableMessageFilterHook)},
236542
+ $message,
236543
+ $reason,
236544
+ $context
236545
+ );
236546
+ return is_string( $filtered_message ) && '' !== $filtered_message ? $filtered_message : $message;
236121
236547
  }
236122
236548
  }
236123
236549
 
236124
236550
  if ( ! function_exists( '${isSupportedFunctionName}' ) ) {
236125
- function ${isSupportedFunctionName}() {
236551
+ function ${isSupportedFunctionName}( array $payload = array(), $cache_result = true ) {
236126
236552
  static $is_supported = null;
236127
- if ( null !== $is_supported ) {
236553
+ $use_cache = $cache_result && count( $payload ) === 0;
236554
+ if ( $use_cache && null !== $is_supported ) {
236128
236555
  return $is_supported;
236129
236556
  }
236130
236557
 
236131
236558
  if ( ! function_exists( 'wp_ai_client_prompt' ) ) {
236132
- $is_supported = false;
236133
- return $is_supported;
236559
+ if ( $use_cache ) {
236560
+ $is_supported = false;
236561
+ }
236562
+ return false;
236134
236563
  }
236135
236564
 
236136
236565
  $schema = ${loadAiSchemaFunctionName}();
236137
236566
  if ( ! is_array( $schema ) ) {
236138
- $is_supported = false;
236139
- return $is_supported;
236567
+ if ( $use_cache ) {
236568
+ $is_supported = false;
236569
+ }
236570
+ return false;
236140
236571
  }
236141
236572
 
236142
236573
  $prompt = wp_ai_client_prompt( 'AI feature support probe.' );
236143
236574
  if ( ! is_object( $prompt ) || ! method_exists( $prompt, 'as_json_response' ) ) {
236144
- $is_supported = false;
236145
- return $is_supported;
236575
+ if ( $use_cache ) {
236576
+ $is_supported = false;
236577
+ }
236578
+ return false;
236579
+ }
236580
+ $prompt_options = ${resolvePromptOptionsFunctionName}( $payload );
236581
+ if (
236582
+ array_key_exists( 'temperature', $prompt_options ) &&
236583
+ null !== $prompt_options['temperature'] &&
236584
+ method_exists( $prompt, 'using_temperature' )
236585
+ ) {
236586
+ $prompt = $prompt->using_temperature( $prompt_options['temperature'] );
236587
+ }
236588
+ if (
236589
+ ! empty( $prompt_options['modelPreference'] ) &&
236590
+ method_exists( $prompt, 'using_model_preference' )
236591
+ ) {
236592
+ $prompt = $prompt->using_model_preference( ...$prompt_options['modelPreference'] );
236146
236593
  }
236147
236594
 
236148
236595
  $structured_prompt = $prompt->as_json_response( $schema );
236149
236596
  if ( ! is_object( $structured_prompt ) ) {
236150
- $is_supported = false;
236151
- return $is_supported;
236597
+ if ( $use_cache ) {
236598
+ $is_supported = false;
236599
+ }
236600
+ return false;
236152
236601
  }
236153
236602
 
236154
236603
  if ( method_exists( $structured_prompt, 'is_supported_for_text_generation' ) ) {
236155
- $is_supported = (bool) $structured_prompt->is_supported_for_text_generation();
236156
- return $is_supported;
236604
+ $supported = (bool) $structured_prompt->is_supported_for_text_generation();
236605
+ if ( $use_cache ) {
236606
+ $is_supported = $supported;
236607
+ }
236608
+ return $supported;
236157
236609
  }
236158
236610
 
236159
- $is_supported = method_exists( $structured_prompt, 'generate_text_result' );
236160
- return $is_supported;
236611
+ $supported = method_exists( $structured_prompt, 'generate_text_result' );
236612
+ if ( $use_cache ) {
236613
+ $is_supported = $supported;
236614
+ }
236615
+ return $supported;
236161
236616
  }
236162
236617
  }
236163
236618
 
@@ -236172,6 +236627,18 @@ if ( ! function_exists( '${adminNoticeFunctionName}' ) ) {
236172
236627
  __( 'The %s AI feature is optional and remains disabled until the WordPress AI Client is available with structured text generation support for the generated schema.', ${quotePhpString(textDomain)} ),
236173
236628
  ${quotePhpString(aiFeatureTitle)}
236174
236629
  );
236630
+ $filtered_message = apply_filters(
236631
+ ${quotePhpString(adminNoticeMessageFilterHook)},
236632
+ $message,
236633
+ array(
236634
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236635
+ 'featureTitle' => ${quotePhpString(aiFeatureTitle)},
236636
+ 'namespace' => ${quotePhpString(namespace)},
236637
+ )
236638
+ );
236639
+ if ( is_string( $filtered_message ) && '' !== $filtered_message ) {
236640
+ $message = $filtered_message;
236641
+ }
236175
236642
  printf( '<div class="notice notice-warning"><p>%s</p></div>', esc_html( $message ) );
236176
236643
  }
236177
236644
  }
@@ -236183,10 +236650,16 @@ if ( ! function_exists( '${handlerFunctionName}' ) ) {
236183
236650
  return $payload;
236184
236651
  }
236185
236652
 
236186
- if ( ! ${isSupportedFunctionName}() ) {
236653
+ if ( ! ${isSupportedFunctionName}( $payload, false ) ) {
236187
236654
  return new WP_Error(
236188
236655
  'ai_client_unavailable',
236189
- 'The WordPress AI Client is unavailable or does not support this feature endpoint.',
236656
+ ${resolveUnavailableMessageFunctionName}(
236657
+ 'The WordPress AI Client is unavailable or does not support this feature endpoint.',
236658
+ 'support_probe_failed',
236659
+ array(
236660
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236661
+ )
236662
+ ),
236190
236663
  array( 'status' => 501 )
236191
236664
  );
236192
236665
  }
@@ -236200,22 +236673,45 @@ if ( ! function_exists( '${handlerFunctionName}' ) ) {
236200
236673
  );
236201
236674
  }
236202
236675
 
236676
+ $prompt_options = ${resolvePromptOptionsFunctionName}( $payload );
236203
236677
  $prompt = wp_ai_client_prompt( ${buildPromptFunctionName}( $payload ) );
236204
236678
  if ( ! is_object( $prompt ) ) {
236205
236679
  return new WP_Error(
236206
236680
  'ai_client_unavailable',
236207
- 'The WordPress AI Client prompt builder is unavailable on this site.',
236681
+ ${resolveUnavailableMessageFunctionName}(
236682
+ 'The WordPress AI Client prompt builder is unavailable on this site.',
236683
+ 'prompt_builder_missing',
236684
+ array(
236685
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236686
+ )
236687
+ ),
236208
236688
  array( 'status' => 501 )
236209
236689
  );
236210
236690
  }
236211
236691
 
236212
- if ( method_exists( $prompt, 'using_temperature' ) ) {
236213
- $prompt = $prompt->using_temperature( 0.2 );
236692
+ if (
236693
+ array_key_exists( 'temperature', $prompt_options ) &&
236694
+ null !== $prompt_options['temperature'] &&
236695
+ method_exists( $prompt, 'using_temperature' )
236696
+ ) {
236697
+ $prompt = $prompt->using_temperature( $prompt_options['temperature'] );
236698
+ }
236699
+ if (
236700
+ ! empty( $prompt_options['modelPreference'] ) &&
236701
+ method_exists( $prompt, 'using_model_preference' )
236702
+ ) {
236703
+ $prompt = $prompt->using_model_preference( ...$prompt_options['modelPreference'] );
236214
236704
  }
236215
236705
  if ( ! method_exists( $prompt, 'as_json_response' ) ) {
236216
236706
  return new WP_Error(
236217
236707
  'ai_client_unavailable',
236218
- 'The current WordPress AI Client does not expose as_json_response().',
236708
+ ${resolveUnavailableMessageFunctionName}(
236709
+ 'The current WordPress AI Client does not expose as_json_response().',
236710
+ 'as_json_response_missing',
236711
+ array(
236712
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236713
+ )
236714
+ ),
236219
236715
  array( 'status' => 501 )
236220
236716
  );
236221
236717
  }
@@ -236224,7 +236720,13 @@ if ( ! function_exists( '${handlerFunctionName}' ) ) {
236224
236720
  if ( ! is_object( $structured_prompt ) ) {
236225
236721
  return new WP_Error(
236226
236722
  'ai_client_unavailable',
236227
- 'The current WordPress AI Client could not prepare a structured-output prompt.',
236723
+ ${resolveUnavailableMessageFunctionName}(
236724
+ 'The current WordPress AI Client could not prepare a structured-output prompt.',
236725
+ 'structured_prompt_missing',
236726
+ array(
236727
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236728
+ )
236729
+ ),
236228
236730
  array( 'status' => 501 )
236229
236731
  );
236230
236732
  }
@@ -236235,14 +236737,26 @@ if ( ! function_exists( '${handlerFunctionName}' ) ) {
236235
236737
  ) {
236236
236738
  return new WP_Error(
236237
236739
  'ai_client_unavailable',
236238
- 'The current WordPress AI Client provider or model does not support this structured-output feature.',
236740
+ ${resolveUnavailableMessageFunctionName}(
236741
+ 'The current WordPress AI Client provider or model does not support this structured-output feature.',
236742
+ 'text_generation_unsupported',
236743
+ array(
236744
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236745
+ )
236746
+ ),
236239
236747
  array( 'status' => 501 )
236240
236748
  );
236241
236749
  }
236242
236750
  if ( ! method_exists( $structured_prompt, 'generate_text_result' ) ) {
236243
236751
  return new WP_Error(
236244
236752
  'ai_client_unavailable',
236245
- 'The current WordPress AI Client does not expose generate_text_result() after as_json_response().',
236753
+ ${resolveUnavailableMessageFunctionName}(
236754
+ 'The current WordPress AI Client does not expose generate_text_result() after as_json_response().',
236755
+ 'generate_text_result_missing',
236756
+ array(
236757
+ 'featureSlug' => ${quotePhpString(aiFeatureSlug)},
236758
+ )
236759
+ ),
236246
236760
  array( 'status' => 501 )
236247
236761
  );
236248
236762
  }
@@ -236277,7 +236791,7 @@ if ( ! function_exists( '${handlerFunctionName}' ) ) {
236277
236791
  );
236278
236792
  }
236279
236793
 
236280
- $telemetry = ${buildTelemetryFunctionName}( $result );
236794
+ $telemetry = ${buildTelemetryFunctionName}( $result, $payload, $normalized_result );
236281
236795
  if ( is_wp_error( $telemetry ) ) {
236282
236796
  return $telemetry;
236283
236797
  }
@@ -236322,17 +236836,17 @@ add_action( 'admin_notices', '${adminNoticeFunctionName}' );
236322
236836
  add_action( 'rest_api_init', '${registerRoutesFunctionName}' );
236323
236837
  `;
236324
236838
  }
236325
- async function runAddAiFeatureCommand({
236326
- aiFeatureName,
236327
- cwd = process.cwd(),
236328
- namespace
236839
+ var init_cli_add_workspace_ai_templates = () => {};
236840
+
236841
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai-scaffold.ts
236842
+ import { promises as fsp23 } from "fs";
236843
+ import path60 from "path";
236844
+ async function scaffoldAiFeatureWorkspace({
236845
+ aiFeatureSlug,
236846
+ compatibilityPolicy,
236847
+ namespace,
236848
+ workspace
236329
236849
  }) {
236330
- const workspace = resolveWorkspaceProject(cwd);
236331
- const aiFeatureSlug = assertValidGeneratedSlug("AI feature name", normalizeBlockSlug(aiFeatureName), "wp-typia add ai-feature <name> [--namespace <vendor/v1>]");
236332
- const resolvedNamespace = resolveRestResourceNamespace(workspace.workspace.namespace, namespace);
236333
- const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY);
236334
- const inventory = readWorkspaceInventory(workspace.projectDir);
236335
- assertAiFeatureDoesNotExist(workspace.projectDir, aiFeatureSlug, inventory);
236336
236850
  const blockConfigPath = path60.join(workspace.projectDir, "scripts", "block-config.ts");
236337
236851
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
236338
236852
  const packageJsonPath = path60.join(workspace.projectDir, "package.json");
@@ -236370,7 +236884,7 @@ async function runAddAiFeatureCommand({
236370
236884
  await fsp23.writeFile(validatorsFilePath, buildAiFeatureValidatorsSource(aiFeatureSlug), "utf8");
236371
236885
  await fsp23.writeFile(apiFilePath, buildAiFeatureApiSource(aiFeatureSlug), "utf8");
236372
236886
  await fsp23.writeFile(dataFilePath, buildAiFeatureDataSource(aiFeatureSlug), "utf8");
236373
- await fsp23.writeFile(phpFilePath, buildAiFeaturePhpSource(aiFeatureSlug, resolvedNamespace, workspace.workspace.phpPrefix, workspace.workspace.textDomain), "utf8");
236887
+ await fsp23.writeFile(phpFilePath, buildAiFeaturePhpSource(aiFeatureSlug, namespace, workspace.workspace.phpPrefix, workspace.workspace.textDomain), "utf8");
236374
236888
  const pascalCase = toPascalCase(aiFeatureSlug);
236375
236889
  await syncAiFeatureRestArtifacts({
236376
236890
  clientFile: `src/ai-features/${aiFeatureSlug}/api-client.ts`,
@@ -236379,7 +236893,7 @@ async function runAddAiFeatureCommand({
236379
236893
  typesFile: `src/ai-features/${aiFeatureSlug}/api-types.ts`,
236380
236894
  validatorsFile: `src/ai-features/${aiFeatureSlug}/api-validators.ts`,
236381
236895
  variables: {
236382
- namespace: resolvedNamespace,
236896
+ namespace,
236383
236897
  pascalCase,
236384
236898
  slugKebabCase: aiFeatureSlug,
236385
236899
  title: toTitleCase(aiFeatureSlug)
@@ -236392,14 +236906,11 @@ async function runAddAiFeatureCommand({
236392
236906
  });
236393
236907
  await appendWorkspaceInventoryEntries(workspace.projectDir, {
236394
236908
  aiFeatureEntries: [
236395
- buildAiFeatureConfigEntry(aiFeatureSlug, resolvedNamespace)
236909
+ buildAiFeatureConfigEntry(aiFeatureSlug, namespace)
236396
236910
  ],
236397
236911
  transformSource: ensureBlockConfigCanAddRestManifests
236398
236912
  });
236399
236913
  return {
236400
- aiFeatureSlug,
236401
- namespace: resolvedNamespace,
236402
- projectDir: workspace.projectDir,
236403
236914
  warnings: packageScriptChanges.addedProjectToolsDependency ? [
236404
236915
  "Added `@wp-typia/project-tools` to devDependencies for `sync-ai`. If this workspace was already installed, rerun your package manager install command before the first `wp-typia sync ai`."
236405
236916
  ] : []
@@ -236409,12 +236920,45 @@ async function runAddAiFeatureCommand({
236409
236920
  throw error48;
236410
236921
  }
236411
236922
  }
236412
- var init_cli_add_workspace_ai = __esm(() => {
236413
- init_cli_add_shared();
236923
+ var init_cli_add_workspace_ai_scaffold = __esm(() => {
236414
236924
  init_cli_add_block_legacy_validator();
236415
236925
  init_cli_add_workspace_ai_source_emitters();
236416
236926
  init_cli_add_workspace_ai_anchors();
236927
+ init_cli_add_workspace_ai_templates();
236928
+ init_workspace_inventory();
236929
+ init_cli_add_shared();
236930
+ init_scaffold_compatibility();
236417
236931
  init_ai_feature_artifacts();
236932
+ });
236933
+
236934
+ // ../wp-typia-project-tools/src/runtime/cli-add-workspace-ai.ts
236935
+ async function runAddAiFeatureCommand({
236936
+ aiFeatureName,
236937
+ cwd = process.cwd(),
236938
+ namespace
236939
+ }) {
236940
+ const workspace = resolveWorkspaceProject(cwd);
236941
+ const aiFeatureSlug = assertValidGeneratedSlug("AI feature name", normalizeBlockSlug(aiFeatureName), "wp-typia add ai-feature <name> [--namespace <vendor/v1>]");
236942
+ const resolvedNamespace = resolveRestResourceNamespace(workspace.workspace.namespace, namespace);
236943
+ const compatibilityPolicy = resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY);
236944
+ const inventory = readWorkspaceInventory(workspace.projectDir);
236945
+ assertAiFeatureDoesNotExist(workspace.projectDir, aiFeatureSlug, inventory);
236946
+ const scaffoldResult = await scaffoldAiFeatureWorkspace({
236947
+ aiFeatureSlug,
236948
+ compatibilityPolicy,
236949
+ namespace: resolvedNamespace,
236950
+ workspace
236951
+ });
236952
+ return {
236953
+ aiFeatureSlug,
236954
+ namespace: resolvedNamespace,
236955
+ projectDir: workspace.projectDir,
236956
+ warnings: scaffoldResult.warnings
236957
+ };
236958
+ }
236959
+ var init_cli_add_workspace_ai = __esm(() => {
236960
+ init_cli_add_shared();
236961
+ init_cli_add_workspace_ai_scaffold();
236418
236962
  init_workspace_inventory();
236419
236963
  init_workspace_project();
236420
236964
  init_scaffold_compatibility();
@@ -236890,24 +237434,6 @@ async function writeBlockTransformRegistry(projectDir, blockSlug, transformSlug)
236890
237434
  const nextTransformSlugs = Array.from(new Set([...existingTransformSlugs, transformSlug])).sort();
236891
237435
  await fsp24.writeFile(transformsIndexPath, buildBlockTransformIndexSource(nextTransformSlugs), "utf8");
236892
237436
  }
236893
- function assertBlockStyleDoesNotExist(projectDir, blockSlug, styleSlug, inventory) {
236894
- const stylePath = path61.join(projectDir, "src", "blocks", blockSlug, "styles", `${styleSlug}.ts`);
236895
- if (fs45.existsSync(stylePath)) {
236896
- throw new Error(`A block style already exists at ${path61.relative(projectDir, stylePath)}. Choose a different name.`);
236897
- }
236898
- if (inventory.blockStyles.some((entry) => entry.block === blockSlug && entry.slug === styleSlug)) {
236899
- throw new Error(`A block style inventory entry already exists for ${blockSlug}/${styleSlug}. Choose a different name.`);
236900
- }
236901
- }
236902
- function assertBlockTransformDoesNotExist(projectDir, blockSlug, transformSlug, inventory) {
236903
- const transformPath = path61.join(projectDir, "src", "blocks", blockSlug, "transforms", `${transformSlug}.ts`);
236904
- if (fs45.existsSync(transformPath)) {
236905
- throw new Error(`A block transform already exists at ${path61.relative(projectDir, transformPath)}. Choose a different name.`);
236906
- }
236907
- if (inventory.blockTransforms.some((entry) => entry.block === blockSlug && entry.slug === transformSlug)) {
236908
- throw new Error(`A block transform inventory entry already exists for ${blockSlug}/${transformSlug}. Choose a different name.`);
236909
- }
236910
- }
236911
237437
  function assertFullBlockName(blockName, flagName) {
236912
237438
  const trimmed = blockName.trim();
236913
237439
  if (!trimmed) {
@@ -237283,16 +237809,153 @@ var init_cli_doctor_environment = __esm(() => {
237283
237809
  init_template_registry();
237284
237810
  });
237285
237811
 
237286
- // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
237812
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-shared.ts
237287
237813
  import fs47 from "fs";
237288
237814
  import path63 from "path";
237289
- import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata2 } from "@wp-typia/block-runtime/blocks";
237290
237815
  function createDoctorCheck2(label, status, detail, code) {
237291
237816
  return code ? { code, detail, label, status } : { detail, label, status };
237292
237817
  }
237293
237818
  function createDoctorScopeCheck(status, detail) {
237294
237819
  return createDoctorCheck2("Doctor scope", status, detail);
237295
237820
  }
237821
+ function getWorkspaceBootstrapRelativePath(packageName) {
237822
+ return `${packageName.split("/").pop() ?? packageName}.php`;
237823
+ }
237824
+ function checkExistingFiles(projectDir, label, filePaths) {
237825
+ const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs47.existsSync(path63.join(projectDir, filePath)));
237826
+ return createDoctorCheck2(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
237827
+ }
237828
+ var WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php", WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js", WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php", WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php", WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php", WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php", WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php", WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js", WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php", WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css", WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js", WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php", WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css", WORKSPACE_GENERATED_BLOCK_ARTIFACTS, WORKSPACE_FULL_BLOCK_NAME_PATTERN;
237829
+ var init_cli_doctor_workspace_shared = __esm(() => {
237830
+ WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
237831
+ "block.json",
237832
+ "typia.manifest.json",
237833
+ "typia.schema.json",
237834
+ "typia-validator.php",
237835
+ "typia.openapi.json"
237836
+ ];
237837
+ WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
237838
+ });
237839
+
237840
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-bindings.ts
237841
+ import fs48 from "fs";
237842
+ import path64 from "path";
237843
+ import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata2 } from "@wp-typia/block-runtime/blocks";
237844
+ function checkWorkspaceBindingBootstrap(projectDir, packageName) {
237845
+ const packageBaseName = packageName.split("/").pop() ?? packageName;
237846
+ const bootstrapPath = path64.join(projectDir, `${packageBaseName}.php`);
237847
+ if (!fs48.existsSync(bootstrapPath)) {
237848
+ return createDoctorCheck2("Binding bootstrap", "fail", `Missing ${path64.basename(bootstrapPath)}`);
237849
+ }
237850
+ const source = fs48.readFileSync(bootstrapPath, "utf8");
237851
+ const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
237852
+ const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
237853
+ const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
237854
+ const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
237855
+ return createDoctorCheck2("Binding bootstrap", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "pass" : "fail", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "Binding source PHP and editor bootstrap hooks are present" : "Missing binding source PHP require glob or editor enqueue hook");
237856
+ }
237857
+ function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
237858
+ const indexRelativePath = [path64.join("src", "bindings", "index.ts"), path64.join("src", "bindings", "index.js")].find((relativePath) => fs48.existsSync(path64.join(projectDir, relativePath)));
237859
+ if (!indexRelativePath) {
237860
+ return createDoctorCheck2("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
237861
+ }
237862
+ const indexPath = path64.join(projectDir, indexRelativePath);
237863
+ const source = fs48.readFileSync(indexPath, "utf8");
237864
+ const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
237865
+ return createDoctorCheck2("Binding sources index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Binding source editor registrations are aggregated" : `Missing editor imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
237866
+ }
237867
+ function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
237868
+ const hasBlock = bindingSource.block !== undefined;
237869
+ const hasAttribute = bindingSource.attribute !== undefined;
237870
+ if (!hasBlock && !hasAttribute) {
237871
+ return;
237872
+ }
237873
+ if (!bindingSource.block || !bindingSource.attribute) {
237874
+ return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
237875
+ }
237876
+ if (!registeredBlockSlugs.has(bindingSource.block)) {
237877
+ return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
237878
+ }
237879
+ const blockJsonRelativePath = path64.join("src", "blocks", bindingSource.block, "block.json");
237880
+ const blockJsonPath = path64.join(projectDir, blockJsonRelativePath);
237881
+ const issues = [];
237882
+ try {
237883
+ const blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs48.readFileSync(blockJsonPath, "utf8")));
237884
+ const attributes = blockJson.attributes;
237885
+ if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) {
237886
+ issues.push(`${blockJsonRelativePath} must define an attributes object`);
237887
+ } else {
237888
+ const attributeConfig = attributes[bindingSource.attribute];
237889
+ if (!attributeConfig || typeof attributeConfig !== "object" || Array.isArray(attributeConfig)) {
237890
+ issues.push(`${blockJsonRelativePath} must declare attribute "${bindingSource.attribute}"`);
237891
+ }
237892
+ }
237893
+ } catch (error48) {
237894
+ issues.push(error48 instanceof Error ? `Unable to read ${blockJsonRelativePath}: ${error48.message}` : `Unable to read ${blockJsonRelativePath}.`);
237895
+ }
237896
+ const serverPath = path64.join(projectDir, bindingSource.serverFile);
237897
+ if (fs48.existsSync(serverPath)) {
237898
+ const serverSource = fs48.readFileSync(serverPath, "utf8");
237899
+ const supportedAttributesFilter = `block_bindings_supported_attributes_${workspace.workspace.namespace}/${bindingSource.block}`;
237900
+ if (!serverSource.includes(supportedAttributesFilter)) {
237901
+ issues.push(`${bindingSource.serverFile} must register ${supportedAttributesFilter}`);
237902
+ }
237903
+ if (!new RegExp(`(['"])${escapeRegex2(bindingSource.attribute)}\\1`, "u").test(serverSource)) {
237904
+ issues.push(`${bindingSource.serverFile} must expose attribute "${bindingSource.attribute}"`);
237905
+ }
237906
+ } else {
237907
+ issues.push(`Missing ${bindingSource.serverFile}`);
237908
+ }
237909
+ const editorPath = path64.join(projectDir, bindingSource.editorFile);
237910
+ if (fs48.existsSync(editorPath)) {
237911
+ const editorSource = fs48.readFileSync(editorPath, "utf8");
237912
+ const blockName = `${workspace.workspace.namespace}/${bindingSource.block}`;
237913
+ const bindingSourceTargetMatch = editorSource.match(/export\s+const\s+BINDING_SOURCE_TARGET\s*=\s*\{([\s\S]*?)\}\s+as\s+const\s*;/u);
237914
+ if (!bindingSourceTargetMatch) {
237915
+ issues.push(`${bindingSource.editorFile} must export BINDING_SOURCE_TARGET`);
237916
+ } else {
237917
+ const targetSource = bindingSourceTargetMatch[1] ?? "";
237918
+ const attributePattern = new RegExp(`\\battribute\\s*:\\s*["']${escapeRegex2(bindingSource.attribute)}["']`, "u");
237919
+ const blockPattern = new RegExp(`\\bblock\\s*:\\s*["']${escapeRegex2(blockName)}["']`, "u");
237920
+ if (!attributePattern.test(targetSource)) {
237921
+ issues.push(`${bindingSource.editorFile} must document target attribute "${bindingSource.attribute}"`);
237922
+ }
237923
+ if (!blockPattern.test(targetSource)) {
237924
+ issues.push(`${bindingSource.editorFile} must document target block "${blockName}"`);
237925
+ }
237926
+ }
237927
+ } else {
237928
+ issues.push(`Missing ${bindingSource.editorFile}`);
237929
+ }
237930
+ return createDoctorCheck2(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
237931
+ }
237932
+ function getWorkspaceBindingDoctorChecks(workspace, inventory) {
237933
+ const checks3 = [];
237934
+ if (inventory.bindingSources.length > 0) {
237935
+ checks3.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
237936
+ checks3.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
237937
+ }
237938
+ const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
237939
+ for (const bindingSource of inventory.bindingSources) {
237940
+ checks3.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
237941
+ bindingSource.serverFile,
237942
+ bindingSource.editorFile
237943
+ ]));
237944
+ const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
237945
+ if (bindingTargetCheck) {
237946
+ checks3.push(bindingTargetCheck);
237947
+ }
237948
+ }
237949
+ return checks3;
237950
+ }
237951
+ var init_cli_doctor_workspace_bindings = __esm(() => {
237952
+ init_cli_doctor_workspace_shared();
237953
+ });
237954
+
237955
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-blocks.ts
237956
+ import fs49 from "fs";
237957
+ import path65 from "path";
237958
+ import { parseScaffoldBlockMetadata as parseScaffoldBlockMetadata3 } from "@wp-typia/block-runtime/blocks";
237296
237959
  function maskSourceSegment2(segment) {
237297
237960
  return segment.replace(/[^\n\r]/gu, " ");
237298
237961
  }
@@ -237355,7 +238018,7 @@ function hasExecutablePattern2(source, pattern) {
237355
238018
  return pattern.test(maskTypeScriptCommentsAndLiterals2(source));
237356
238019
  }
237357
238020
  function normalizePathSeparators(relativePath) {
237358
- return relativePath.split(path63.sep).join("/");
238021
+ return relativePath.split(path65.sep).join("/");
237359
238022
  }
237360
238023
  function hasRegisteredBlockAsset(value2) {
237361
238024
  if (typeof value2 === "string") {
@@ -237367,25 +238030,19 @@ function hasRegisteredBlockAsset(value2) {
237367
238030
  return false;
237368
238031
  }
237369
238032
  function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
237370
- const blockJsonRelativePath = path63.join("src", "blocks", blockSlug, "block.json");
237371
- const blockJsonPath = path63.join(projectDir, blockJsonRelativePath);
237372
- if (!fs47.existsSync(blockJsonPath)) {
238033
+ const blockJsonRelativePath = path65.join("src", "blocks", blockSlug, "block.json");
238034
+ const blockJsonPath = path65.join(projectDir, blockJsonRelativePath);
238035
+ if (!fs49.existsSync(blockJsonPath)) {
237373
238036
  return {
237374
238037
  blockJsonRelativePath,
237375
238038
  error: `Missing ${blockJsonRelativePath}`
237376
238039
  };
237377
238040
  }
237378
238041
  try {
237379
- const parsed = JSON.parse(fs47.readFileSync(blockJsonPath, "utf8"));
237380
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
237381
- return {
237382
- blockJsonRelativePath,
237383
- error: `${blockJsonRelativePath} must contain a JSON object`
237384
- };
237385
- }
238042
+ const document2 = parseScaffoldBlockMetadata3(JSON.parse(fs49.readFileSync(blockJsonPath, "utf8")));
237386
238043
  return {
237387
238044
  blockJsonRelativePath,
237388
- document: parsed
238045
+ document: document2
237389
238046
  };
237390
238047
  } catch (error48) {
237391
238048
  return {
@@ -237395,156 +238052,126 @@ function readWorkspaceBlockIframeMetadata(projectDir, blockSlug) {
237395
238052
  }
237396
238053
  }
237397
238054
  function isWorkspaceBlockEditorSource(relativePath) {
237398
- const normalizedPath = normalizePathSeparators(relativePath);
237399
- const normalizedLowerPath = normalizedPath.toLowerCase();
237400
- if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(normalizedLowerPath) || /\.d\.[cm]?[jt]s$/u.test(normalizedLowerPath)) {
238055
+ if (!WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN.test(relativePath)) {
237401
238056
  return false;
237402
238057
  }
237403
- const segments = normalizedLowerPath.split("/");
237404
- const fileName = segments[segments.length - 1] ?? "";
237405
- const baseName = fileName.replace(/\.[^.]+$/u, "");
237406
- if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(baseName)) {
238058
+ const normalizedRelativePath = normalizePathSeparators(relativePath);
238059
+ const normalizedDirName = path65.posix.dirname(normalizedRelativePath);
238060
+ const normalizedBaseName = path65.posix.basename(normalizedRelativePath, path65.posix.extname(normalizedRelativePath));
238061
+ if (WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES.has(normalizedBaseName)) {
237407
238062
  return true;
237408
238063
  }
237409
- return segments.slice(0, -1).some((segment) => WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES.has(segment));
238064
+ const pathSegments = normalizedDirName.split("/");
238065
+ return pathSegments.some((segment) => WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES.has(segment));
237410
238066
  }
237411
238067
  function isWorkspaceBlockSaveSource(relativePath) {
237412
- const fileName = normalizePathSeparators(relativePath).split("/").pop() ?? "";
237413
- return fileName.replace(/\.[^.]+$/u, "").toLowerCase() === "save";
238068
+ const normalizedBaseName = path65.basename(relativePath, path65.extname(relativePath));
238069
+ return normalizedBaseName === "save";
237414
238070
  }
237415
238071
  function collectWorkspaceBlockEditorSources(projectDir, blockSlug) {
237416
- const blockDir = path63.join(projectDir, "src", "blocks", blockSlug);
237417
- if (!fs47.existsSync(blockDir)) {
238072
+ const blockDir = path65.join(projectDir, "src", "blocks", blockSlug);
238073
+ if (!fs49.existsSync(blockDir)) {
237418
238074
  return [];
237419
238075
  }
237420
- const sources = [];
237421
- const visitDirectory = (directory) => {
237422
- for (const entry of fs47.readdirSync(directory, { withFileTypes: true })) {
237423
- const entryPath = path63.join(directory, entry.name);
238076
+ const collected = [];
238077
+ const queue = [blockDir];
238078
+ while (queue.length > 0) {
238079
+ const currentDir = queue.pop();
238080
+ if (!currentDir) {
238081
+ continue;
238082
+ }
238083
+ for (const entry of fs49.readdirSync(currentDir, { withFileTypes: true })) {
238084
+ const absolutePath = path65.join(currentDir, entry.name);
237424
238085
  if (entry.isDirectory()) {
237425
- visitDirectory(entryPath);
238086
+ queue.push(absolutePath);
237426
238087
  continue;
237427
238088
  }
237428
238089
  if (!entry.isFile()) {
237429
238090
  continue;
237430
238091
  }
237431
- const relativePath = normalizePathSeparators(path63.relative(projectDir, entryPath));
237432
- const blockRelativePath = path63.relative(blockDir, entryPath);
237433
- if (!isWorkspaceBlockEditorSource(blockRelativePath)) {
238092
+ const relativePath = path65.relative(projectDir, absolutePath);
238093
+ if (!isWorkspaceBlockEditorSource(relativePath)) {
237434
238094
  continue;
237435
238095
  }
237436
- sources.push({
237437
- relativePath,
237438
- source: fs47.readFileSync(entryPath, "utf8")
238096
+ collected.push({
238097
+ relativePath: normalizePathSeparators(relativePath),
238098
+ source: fs49.readFileSync(absolutePath, "utf8")
237439
238099
  });
237440
238100
  }
237441
- };
237442
- visitDirectory(blockDir);
237443
- return sources;
238101
+ }
238102
+ return collected.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
237444
238103
  }
237445
238104
  function getSourceLineNumber(source, index) {
237446
- let lineNumber = 1;
238105
+ let line = 1;
237447
238106
  for (let cursor = 0;cursor < index; cursor += 1) {
237448
238107
  if (source[cursor] === `
237449
238108
  `) {
237450
- lineNumber += 1;
238109
+ line += 1;
237451
238110
  }
237452
238111
  }
237453
- return lineNumber;
238112
+ return line;
237454
238113
  }
237455
- function isGlobalDomAccessCandidate(maskedSource, index, token) {
237456
- if (token === "document" || token === "window") {
237457
- return true;
238114
+ function isGlobalDomAccessCandidate(source, index, identifier) {
238115
+ const lineStart = source.lastIndexOf(`
238116
+ `, index - 1) + 1;
238117
+ const lineEndCandidate = source.indexOf(`
238118
+ `, index);
238119
+ const lineEnd = lineEndCandidate === -1 ? source.length : lineEndCandidate;
238120
+ const lineSource = source.slice(lineStart, lineEnd);
238121
+ const trimmedLine = lineSource.trimStart();
238122
+ if (trimmedLine.startsWith("import ")) {
238123
+ return false;
237458
238124
  }
237459
- const before = maskedSource.slice(0, index);
237460
- const after = maskedSource.slice(index + token.length);
237461
- const previousNonWhitespace = before.match(/\S(?=\s*$)/u)?.[0] ?? "";
237462
- const nextNonWhitespace = after.match(/^\s*(\S)/u)?.[1] ?? "";
237463
- if (previousNonWhitespace === "." || previousNonWhitespace === "{" || previousNonWhitespace === ",") {
238125
+ if (trimmedLine.startsWith("const ") || trimmedLine.startsWith("let ") || trimmedLine.startsWith("var ")) {
237464
238126
  return false;
237465
238127
  }
237466
- if (nextNonWhitespace === ":") {
238128
+ if (trimmedLine.startsWith("function ") || trimmedLine.startsWith("class ")) {
237467
238129
  return false;
237468
238130
  }
237469
- if (/\b(?:const|function|let|var)\s+$/u.test(before)) {
238131
+ const precedingCharacter = index > 0 ? source[index - 1] : "";
238132
+ if (precedingCharacter === "." || precedingCharacter === "'" || precedingCharacter === '"') {
237470
238133
  return false;
237471
238134
  }
237472
- return true;
238135
+ return identifier === "document" || identifier === "window" || identifier === "parent" || identifier === "top";
237473
238136
  }
237474
- function findWorkspaceBlockGlobalDomAccesses(sources) {
237475
- const findings = [];
237476
- for (const { relativePath, source } of sources) {
238137
+ function findWorkspaceBlockGlobalDomAccesses(editorSources) {
238138
+ return editorSources.flatMap(({ relativePath, source }) => {
237477
238139
  const maskedSource = maskTypeScriptCommentsAndLiterals2(source);
237478
238140
  const matches = maskedSource.matchAll(WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN);
238141
+ const findings = [];
237479
238142
  for (const match3 of matches) {
237480
- const index = match3.index ?? 0;
237481
- const matchedToken = match3[0].replace(/\W+/gu, "");
237482
- if (!isGlobalDomAccessCandidate(maskedSource, index, matchedToken)) {
238143
+ const identifier = match3[0];
238144
+ const matchIndex = match3.index ?? -1;
238145
+ if (matchIndex < 0) {
237483
238146
  continue;
237484
238147
  }
237485
- findings.push(`${relativePath}:${getSourceLineNumber(source, index)} (${matchedToken})`);
237486
- if (findings.length >= 5) {
237487
- return findings;
238148
+ if (!isGlobalDomAccessCandidate(source, matchIndex, identifier)) {
238149
+ continue;
237488
238150
  }
238151
+ findings.push(`${relativePath}:${getSourceLineNumber(source, matchIndex)}`);
237489
238152
  }
237490
- }
237491
- return findings;
237492
- }
237493
- function getWorkspaceBootstrapRelativePath(packageName) {
237494
- const packageBaseName = packageName.split("/").pop() ?? packageName;
237495
- return `${packageBaseName}.php`;
237496
- }
237497
- function checkExistingFiles(projectDir, label, filePaths) {
237498
- const missing = filePaths.filter((filePath) => typeof filePath === "string").filter((filePath) => !fs47.existsSync(path63.join(projectDir, filePath)));
237499
- return createDoctorCheck2(label, missing.length === 0 ? "pass" : "fail", missing.length === 0 ? "All referenced files exist" : `Missing: ${missing.join(", ")}`);
237500
- }
237501
- function checkWorkspacePackageMetadata(workspace, packageJson) {
237502
- const issues = [];
237503
- const packageName = packageJson.name;
237504
- const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
237505
- const wpTypia = packageJson.wpTypia;
237506
- if (typeof packageName !== "string" || packageName.length === 0) {
237507
- issues.push("package.json must define a string name for workspace bootstrap resolution");
237508
- }
237509
- if (wpTypia?.projectType !== "workspace") {
237510
- issues.push('wpTypia.projectType must be "workspace"');
237511
- }
237512
- if (wpTypia?.templatePackage !== WORKSPACE_TEMPLATE_PACKAGE) {
237513
- issues.push(`wpTypia.templatePackage must be "${WORKSPACE_TEMPLATE_PACKAGE}"`);
237514
- }
237515
- if (wpTypia?.namespace !== workspace.workspace.namespace) {
237516
- issues.push(`wpTypia.namespace must equal "${workspace.workspace.namespace}"`);
237517
- }
237518
- if (wpTypia?.textDomain !== workspace.workspace.textDomain) {
237519
- issues.push(`wpTypia.textDomain must equal "${workspace.workspace.textDomain}"`);
237520
- }
237521
- if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
237522
- issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
237523
- }
237524
- if (!fs47.existsSync(path63.join(workspace.projectDir, bootstrapRelativePath))) {
237525
- issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
237526
- }
237527
- return createDoctorCheck2("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${bootstrapRelativePath}` : issues.join("; "));
238153
+ return findings;
238154
+ });
237528
238155
  }
237529
238156
  function getWorkspaceBlockRequiredFiles(block) {
237530
- const blockDir = path63.join("src", "blocks", block.slug);
238157
+ const blockDir = path65.join("src", "blocks", block.slug);
237531
238158
  return Array.from(new Set([
237532
238159
  block.typesFile,
237533
238160
  block.apiTypesFile,
237534
238161
  block.openApiFile,
237535
- path63.join(blockDir, "index.tsx"),
237536
- ...WORKSPACE_GENERATED_BLOCK_ARTIFACTS.map((fileName) => path63.join(blockDir, fileName))
238162
+ path65.join(blockDir, "index.tsx"),
238163
+ ...WORKSPACE_GENERATED_BLOCK_ARTIFACTS.map((fileName) => path65.join(blockDir, fileName))
237537
238164
  ].filter((filePath) => typeof filePath === "string")));
237538
238165
  }
237539
238166
  function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
237540
- const blockJsonRelativePath = path63.join("src", "blocks", block.slug, "block.json");
237541
- const blockJsonPath = path63.join(projectDir, blockJsonRelativePath);
237542
- if (!fs47.existsSync(blockJsonPath)) {
238167
+ const blockJsonRelativePath = path65.join("src", "blocks", block.slug, "block.json");
238168
+ const blockJsonPath = path65.join(projectDir, blockJsonRelativePath);
238169
+ if (!fs49.existsSync(blockJsonPath)) {
237543
238170
  return createDoctorCheck2(`Block metadata ${block.slug}`, "fail", `Missing ${blockJsonRelativePath}`);
237544
238171
  }
237545
238172
  let blockJson;
237546
238173
  try {
237547
- blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs47.readFileSync(blockJsonPath, "utf8")));
238174
+ blockJson = parseScaffoldBlockMetadata3(JSON.parse(fs49.readFileSync(blockJsonPath, "utf8")));
237548
238175
  } catch (error48) {
237549
238176
  return createDoctorCheck2(`Block metadata ${block.slug}`, "fail", error48 instanceof Error ? error48.message : String(error48));
237550
238177
  }
@@ -237559,14 +238186,14 @@ function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
237559
238186
  return createDoctorCheck2(`Block metadata ${block.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `block.json matches ${expectedName} and ${workspace.workspace.textDomain}` : issues.join("; "));
237560
238187
  }
237561
238188
  function checkWorkspaceBlockHooks(projectDir, blockSlug) {
237562
- const blockJsonRelativePath = path63.join("src", "blocks", blockSlug, "block.json");
237563
- const blockJsonPath = path63.join(projectDir, blockJsonRelativePath);
237564
- if (!fs47.existsSync(blockJsonPath)) {
238189
+ const blockJsonRelativePath = path65.join("src", "blocks", blockSlug, "block.json");
238190
+ const blockJsonPath = path65.join(projectDir, blockJsonRelativePath);
238191
+ if (!fs49.existsSync(blockJsonPath)) {
237565
238192
  return createDoctorCheck2(`Block hooks ${blockSlug}`, "fail", `Missing ${blockJsonRelativePath}`);
237566
238193
  }
237567
238194
  let blockJson;
237568
238195
  try {
237569
- blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs47.readFileSync(blockJsonPath, "utf8")));
238196
+ blockJson = parseScaffoldBlockMetadata3(JSON.parse(fs49.readFileSync(blockJsonPath, "utf8")));
237570
238197
  } catch (error48) {
237571
238198
  return createDoctorCheck2(`Block hooks ${blockSlug}`, "fail", error48 instanceof Error ? error48.message : String(error48));
237572
238199
  }
@@ -237582,12 +238209,12 @@ function checkWorkspaceBlockHooks(projectDir, blockSlug) {
237582
238209
  return createDoctorCheck2(`Block hooks ${blockSlug}`, invalidEntries.length === 0 ? "pass" : "fail", invalidEntries.length === 0 ? `blockHooks metadata is valid${Object.keys(blockHooks).length > 0 ? ` (${Object.keys(blockHooks).join(", ")})` : ""}` : `Invalid blockHooks entries: ${invalidEntries.map(([anchor, position]) => `${anchor || "<empty>"} => ${String(position)}`).join(", ")}`);
237583
238210
  }
237584
238211
  function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
237585
- const entryRelativePath = path63.join("src", "blocks", blockSlug, "index.tsx");
237586
- const entryPath = path63.join(projectDir, entryRelativePath);
237587
- if (!fs47.existsSync(entryPath)) {
238212
+ const entryRelativePath = path65.join("src", "blocks", blockSlug, "index.tsx");
238213
+ const entryPath = path65.join(projectDir, entryRelativePath);
238214
+ if (!fs49.existsSync(entryPath)) {
237588
238215
  return createDoctorCheck2(`Block collection ${blockSlug}`, "fail", `Missing ${entryRelativePath}`);
237589
238216
  }
237590
- const source = fs47.readFileSync(entryPath, "utf8");
238217
+ const source = fs49.readFileSync(entryPath, "utf8");
237591
238218
  const hasCollectionImport = WORKSPACE_COLLECTION_IMPORT_PATTERN.test(source);
237592
238219
  return createDoctorCheck2(`Block collection ${blockSlug}`, hasCollectionImport ? "pass" : "fail", hasCollectionImport ? "Shared block collection import is present" : `Missing a shared collection import like ${WORKSPACE_COLLECTION_IMPORT_LINE}`);
237593
238220
  }
@@ -237600,8 +238227,8 @@ function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
237600
238227
  }
237601
238228
  const blockJson = metadataResult.document;
237602
238229
  const apiVersion = typeof blockJson.apiVersion === "number" && Number.isFinite(blockJson.apiVersion) ? blockJson.apiVersion : null;
237603
- const blockDir = path63.join(projectDir, "src", "blocks", blockSlug);
237604
- const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) => fs47.existsSync(path63.join(blockDir, fileName))).map((fileName) => normalizePathSeparators(path63.join("src", "blocks", blockSlug, fileName)));
238230
+ const blockDir = path65.join(projectDir, "src", "blocks", blockSlug);
238231
+ const localStyleFiles = WORKSPACE_BLOCK_LOCAL_STYLE_FILES.filter((fileName) => fs49.existsSync(path65.join(blockDir, fileName))).map((fileName) => normalizePathSeparators(path65.join("src", "blocks", blockSlug, fileName)));
237605
238232
  const hasRegisteredEditorStyles = hasRegisteredBlockAsset(blockJson.style) || hasRegisteredBlockAsset(blockJson.editorStyle);
237606
238233
  const editorSources = collectWorkspaceBlockEditorSources(projectDir, blockSlug);
237607
238234
  const editorWrapperSources = editorSources.filter((source) => !isWorkspaceBlockSaveSource(source.relativePath));
@@ -237619,103 +238246,162 @@ function checkWorkspaceBlockIframeCompatibility(projectDir, blockSlug) {
237619
238246
  }
237620
238247
  function checkWorkspacePatternBootstrap(projectDir, packageName) {
237621
238248
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237622
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237623
- if (!fs47.existsSync(bootstrapPath)) {
237624
- return createDoctorCheck2("Pattern bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238249
+ const bootstrapPath = path65.join(projectDir, `${packageBaseName}.php`);
238250
+ if (!fs49.existsSync(bootstrapPath)) {
238251
+ return createDoctorCheck2("Pattern bootstrap", "fail", `Missing ${path65.basename(bootstrapPath)}`);
237625
238252
  }
237626
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238253
+ const source = fs49.readFileSync(bootstrapPath, "utf8");
237627
238254
  const hasCategoryAnchor = source.includes("register_block_pattern_category");
237628
238255
  const hasPatternGlob = source.includes("/src/patterns/*.php");
237629
238256
  return createDoctorCheck2("Pattern bootstrap", hasCategoryAnchor && hasPatternGlob ? "pass" : "fail", hasCategoryAnchor && hasPatternGlob ? "Pattern category and loader hooks are present" : "Missing pattern category registration or src/patterns loader hook");
237630
238257
  }
237631
- function checkWorkspaceBindingBootstrap(projectDir, packageName) {
237632
- const packageBaseName = packageName.split("/").pop() ?? packageName;
237633
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237634
- if (!fs47.existsSync(bootstrapPath)) {
237635
- return createDoctorCheck2("Binding bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238258
+ function checkVariationEntrypoint(projectDir, blockSlug) {
238259
+ const entryPath = path65.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
238260
+ if (!fs49.existsSync(entryPath)) {
238261
+ return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path65.relative(projectDir, entryPath)}`);
237636
238262
  }
237637
- const source = fs47.readFileSync(bootstrapPath, "utf8");
237638
- const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
237639
- const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
237640
- const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
237641
- const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
237642
- return createDoctorCheck2("Binding bootstrap", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "pass" : "fail", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "Binding source PHP and editor bootstrap hooks are present" : "Missing binding source PHP require glob or editor enqueue hook");
238263
+ const source = fs49.readFileSync(entryPath, "utf8");
238264
+ const hasImport = hasUncommentedPattern2(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
238265
+ const hasCall = hasExecutablePattern2(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
238266
+ return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
237643
238267
  }
237644
- function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
237645
- const indexRelativePath = [path63.join("src", "bindings", "index.ts"), path63.join("src", "bindings", "index.js")].find((relativePath) => fs47.existsSync(path63.join(projectDir, relativePath)));
237646
- if (!indexRelativePath) {
237647
- return createDoctorCheck2("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
238268
+ function checkBlockStyleEntrypoint(projectDir, blockSlug) {
238269
+ const entryPath = path65.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
238270
+ if (!fs49.existsSync(entryPath)) {
238271
+ return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path65.relative(projectDir, entryPath)}`);
237648
238272
  }
237649
- const indexPath = path63.join(projectDir, indexRelativePath);
237650
- const source = fs47.readFileSync(indexPath, "utf8");
237651
- const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
237652
- return createDoctorCheck2("Binding sources index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Binding source editor registrations are aggregated" : `Missing editor imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
238273
+ const source = fs49.readFileSync(entryPath, "utf8");
238274
+ const hasImport = hasUncommentedPattern2(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
238275
+ const hasCall = hasExecutablePattern2(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
238276
+ return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
237653
238277
  }
237654
- function checkWorkspaceBindingTarget(projectDir, workspace, registeredBlockSlugs, bindingSource) {
237655
- const hasBlock = bindingSource.block !== undefined;
237656
- const hasAttribute = bindingSource.attribute !== undefined;
237657
- if (!hasBlock && !hasAttribute) {
237658
- return;
238278
+ function checkBlockTransformEntrypoint(projectDir, blockSlug) {
238279
+ const entryPath = path65.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
238280
+ if (!fs49.existsSync(entryPath)) {
238281
+ return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path65.relative(projectDir, entryPath)}`);
237659
238282
  }
237660
- if (!bindingSource.block || !bindingSource.attribute) {
237661
- return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", "Binding target entries must include both block and attribute.");
238283
+ const source = fs49.readFileSync(entryPath, "utf8");
238284
+ const hasImport = hasUncommentedPattern2(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
238285
+ const hasCall = hasExecutablePattern2(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
238286
+ return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block transform registration hook is present" : "Missing ./transforms import or applyWorkspaceBlockTransforms(registration.settings) call");
238287
+ }
238288
+ function checkBlockTransformConfig(workspace, transform2) {
238289
+ const expectedTo = `${workspace.workspace.namespace}/${transform2.block}`;
238290
+ const issues = [];
238291
+ if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform2.from)) {
238292
+ issues.push("from must use full namespace/block format");
237662
238293
  }
237663
- if (!registeredBlockSlugs.has(bindingSource.block)) {
237664
- return createDoctorCheck2(`Binding target ${bindingSource.slug}`, "fail", `Binding target references unknown block "${bindingSource.block}".`);
238294
+ if (transform2.to !== expectedTo) {
238295
+ issues.push(`to must equal "${expectedTo}" for workspace block "${transform2.block}"`);
237665
238296
  }
237666
- const blockJsonRelativePath = path63.join("src", "blocks", bindingSource.block, "block.json");
237667
- const blockJsonPath = path63.join(projectDir, blockJsonRelativePath);
237668
- const issues = [];
237669
- try {
237670
- const blockJson = parseScaffoldBlockMetadata2(JSON.parse(fs47.readFileSync(blockJsonPath, "utf8")));
237671
- const attributes = blockJson.attributes;
237672
- if (!attributes || typeof attributes !== "object" || Array.isArray(attributes)) {
237673
- issues.push(`${blockJsonRelativePath} must define an attributes object`);
237674
- } else {
237675
- const attributeConfig = attributes[bindingSource.attribute];
237676
- if (!attributeConfig || typeof attributeConfig !== "object" || Array.isArray(attributeConfig)) {
237677
- issues.push(`${blockJsonRelativePath} must declare attribute "${bindingSource.attribute}"`);
237678
- }
238297
+ return createDoctorCheck2(`Block transform config ${transform2.block}/${transform2.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${transform2.from} transforms into ${transform2.to}` : issues.join("; "));
238298
+ }
238299
+ function getWorkspaceBlockDoctorChecks(workspace, inventory) {
238300
+ const checks3 = [];
238301
+ for (const block of inventory.blocks) {
238302
+ checks3.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)));
238303
+ checks3.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
238304
+ checks3.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
238305
+ checks3.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
238306
+ checks3.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
238307
+ }
238308
+ const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
238309
+ const variationTargetBlocks = new Set;
238310
+ for (const variation of inventory.variations) {
238311
+ if (!registeredBlockSlugs.has(variation.block)) {
238312
+ checks3.push(createDoctorCheck2(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
238313
+ continue;
237679
238314
  }
237680
- } catch (error48) {
237681
- issues.push(error48 instanceof Error ? `Unable to read ${blockJsonRelativePath}: ${error48.message}` : `Unable to read ${blockJsonRelativePath}.`);
238315
+ variationTargetBlocks.add(variation.block);
238316
+ checks3.push(checkExistingFiles(workspace.projectDir, `Variation ${variation.block}/${variation.slug}`, [variation.file]));
237682
238317
  }
237683
- const serverPath = path63.join(projectDir, bindingSource.serverFile);
237684
- if (fs47.existsSync(serverPath)) {
237685
- const serverSource = fs47.readFileSync(serverPath, "utf8");
237686
- const supportedAttributesFilter = `block_bindings_supported_attributes_${workspace.workspace.namespace}/${bindingSource.block}`;
237687
- if (!serverSource.includes(supportedAttributesFilter)) {
237688
- issues.push(`${bindingSource.serverFile} must register ${supportedAttributesFilter}`);
237689
- }
237690
- if (!new RegExp(`'${escapeRegex2(bindingSource.attribute)}'`, "u").test(serverSource)) {
237691
- issues.push(`${bindingSource.serverFile} must expose attribute "${bindingSource.attribute}"`);
238318
+ for (const blockSlug of variationTargetBlocks) {
238319
+ checks3.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
238320
+ }
238321
+ const blockStyleTargetBlocks = new Set;
238322
+ for (const blockStyle of inventory.blockStyles) {
238323
+ if (!registeredBlockSlugs.has(blockStyle.block)) {
238324
+ checks3.push(createDoctorCheck2(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
238325
+ continue;
237692
238326
  }
237693
- } else {
237694
- issues.push(`Missing ${bindingSource.serverFile}`);
238327
+ blockStyleTargetBlocks.add(blockStyle.block);
238328
+ checks3.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
237695
238329
  }
237696
- const editorPath = path63.join(projectDir, bindingSource.editorFile);
237697
- if (fs47.existsSync(editorPath)) {
237698
- const editorSource = fs47.readFileSync(editorPath, "utf8");
237699
- const blockName = `${workspace.workspace.namespace}/${bindingSource.block}`;
237700
- const bindingSourceTargetMatch = editorSource.match(/export\s+const\s+BINDING_SOURCE_TARGET\s*=\s*\{([\s\S]*?)\}\s+as\s+const\s*;/u);
237701
- if (!bindingSourceTargetMatch) {
237702
- issues.push(`${bindingSource.editorFile} must export BINDING_SOURCE_TARGET`);
237703
- } else {
237704
- const targetSource = bindingSourceTargetMatch[1] ?? "";
237705
- const attributePattern = new RegExp(`\\battribute\\s*:\\s*["']${escapeRegex2(bindingSource.attribute)}["']`, "u");
237706
- const blockPattern = new RegExp(`\\bblock\\s*:\\s*["']${escapeRegex2(blockName)}["']`, "u");
237707
- if (!attributePattern.test(targetSource)) {
237708
- issues.push(`${bindingSource.editorFile} must document target attribute "${bindingSource.attribute}"`);
237709
- }
237710
- if (!blockPattern.test(targetSource)) {
237711
- issues.push(`${bindingSource.editorFile} must document target block "${blockName}"`);
237712
- }
238330
+ for (const blockSlug of blockStyleTargetBlocks) {
238331
+ checks3.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
238332
+ path65.join("src", "blocks", blockSlug, "styles", "index.ts")
238333
+ ]));
238334
+ checks3.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
238335
+ }
238336
+ const blockTransformTargetBlocks = new Set;
238337
+ for (const blockTransform of inventory.blockTransforms) {
238338
+ if (!registeredBlockSlugs.has(blockTransform.block)) {
238339
+ checks3.push(createDoctorCheck2(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
238340
+ continue;
237713
238341
  }
237714
- } else {
237715
- issues.push(`Missing ${bindingSource.editorFile}`);
238342
+ blockTransformTargetBlocks.add(blockTransform.block);
238343
+ checks3.push(checkBlockTransformConfig(workspace, blockTransform));
238344
+ checks3.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
237716
238345
  }
237717
- return createDoctorCheck2(`Binding target ${bindingSource.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${bindingSource.block}.${bindingSource.attribute} is declared and supported` : issues.join("; "));
238346
+ for (const blockSlug of blockTransformTargetBlocks) {
238347
+ checks3.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
238348
+ path65.join("src", "blocks", blockSlug, "transforms", "index.ts")
238349
+ ]));
238350
+ checks3.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
238351
+ }
238352
+ const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs49.existsSync(path65.join(workspace.projectDir, "src", "patterns"));
238353
+ if (shouldCheckPatternBootstrap) {
238354
+ checks3.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
238355
+ }
238356
+ for (const pattern of inventory.patterns) {
238357
+ checks3.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [pattern.file]));
238358
+ }
238359
+ return checks3;
237718
238360
  }
238361
+ var WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';", WORKSPACE_COLLECTION_IMPORT_PATTERN, WORKSPACE_VARIATIONS_IMPORT_PATTERN, WORKSPACE_VARIATIONS_CALL_PATTERN, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN, WORKSPACE_BLOCK_STYLES_CALL_PATTERN, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN, WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL = "https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/block-migration-for-iframe-editor-compatibility/", WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES, WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN, WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES, WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES, WORKSPACE_BLOCK_LOCAL_STYLE_FILES, WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN, WORKSPACE_BLOCK_PROPS_PATTERN;
238362
+ var init_cli_doctor_workspace_blocks = __esm(() => {
238363
+ init_cli_doctor_workspace_shared();
238364
+ init_hooked_blocks();
238365
+ WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
238366
+ WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
238367
+ WORKSPACE_VARIATIONS_CALL_PATTERN = /registerWorkspaceVariations\s*\(\s*\)\s*;?/u;
238368
+ WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
238369
+ WORKSPACE_BLOCK_STYLES_CALL_PATTERN = /registerWorkspaceBlockStyles\s*\(\s*\)\s*;?/u;
238370
+ WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN = /^\s*import\s*\{\s*applyWorkspaceBlockTransforms\s*\}\s*from\s*["']\.\/transforms["']\s*;?\s*$/mu;
238371
+ WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
238372
+ WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES = {
238373
+ API_VERSION: "wp-typia.workspace.block.iframe.api-version",
238374
+ BLOCK_PROPS: "wp-typia.workspace.block.iframe.block-props",
238375
+ EDITOR_GLOBALS: "wp-typia.workspace.block.iframe.editor-globals",
238376
+ EDITOR_STYLES: "wp-typia.workspace.block.iframe.editor-styles"
238377
+ };
238378
+ WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/u;
238379
+ WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES = new Set([
238380
+ "edit",
238381
+ "editor",
238382
+ "index",
238383
+ "save"
238384
+ ]);
238385
+ WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES = new Set([
238386
+ "components",
238387
+ "controls",
238388
+ "editor",
238389
+ "inspector"
238390
+ ]);
238391
+ WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
238392
+ "editor.css",
238393
+ "editor.scss",
238394
+ "index.css",
238395
+ "style.css",
238396
+ "style.scss"
238397
+ ];
238398
+ WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
238399
+ WORKSPACE_BLOCK_PROPS_PATTERN = /\buse(?:Block|InnerBlocks)Props(?:\.save)?\s*\(/u;
238400
+ });
238401
+
238402
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-features.ts
238403
+ import fs50 from "fs";
238404
+ import path66 from "path";
237719
238405
  function getWorkspaceRestResourceRequiredFiles(restResource) {
237720
238406
  const schemaNames = new Set;
237721
238407
  if (restResource.methods.includes("list")) {
@@ -237741,7 +238427,7 @@ function getWorkspaceRestResourceRequiredFiles(restResource) {
237741
238427
  }
237742
238428
  return Array.from(new Set([
237743
238429
  restResource.apiFile,
237744
- ...Array.from(schemaNames, (schemaName) => path63.join(path63.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
238430
+ ...Array.from(schemaNames, (schemaName) => path66.join(path66.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
237745
238431
  restResource.clientFile,
237746
238432
  restResource.dataFile,
237747
238433
  restResource.openApiFile,
@@ -237757,11 +238443,11 @@ function checkWorkspaceRestResourceConfig(restResource) {
237757
238443
  }
237758
238444
  function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
237759
238445
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237760
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237761
- if (!fs47.existsSync(bootstrapPath)) {
237762
- return createDoctorCheck2("REST resource bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238446
+ const bootstrapPath = path66.join(projectDir, `${packageBaseName}.php`);
238447
+ if (!fs50.existsSync(bootstrapPath)) {
238448
+ return createDoctorCheck2("REST resource bootstrap", "fail", `Missing ${path66.basename(bootstrapPath)}`);
237763
238449
  }
237764
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238450
+ const source = fs50.readFileSync(bootstrapPath, "utf8");
237765
238451
  const registerFunctionName = `${phpPrefix}_register_rest_resources`;
237766
238452
  const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
237767
238453
  const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
@@ -237780,12 +238466,12 @@ function getWorkspaceAbilityRequiredFiles(ability) {
237780
238466
  ]));
237781
238467
  }
237782
238468
  function checkWorkspaceAbilityConfig(projectDir, ability) {
237783
- const configPath = path63.join(projectDir, ability.configFile);
237784
- if (!fs47.existsSync(configPath)) {
238469
+ const configPath = path66.join(projectDir, ability.configFile);
238470
+ if (!fs50.existsSync(configPath)) {
237785
238471
  return createDoctorCheck2(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
237786
238472
  }
237787
238473
  try {
237788
- const config2 = JSON.parse(fs47.readFileSync(configPath, "utf8"));
238474
+ const config2 = JSON.parse(fs50.readFileSync(configPath, "utf8"));
237789
238475
  const abilityId = typeof config2.abilityId === "string" ? config2.abilityId.trim() : "";
237790
238476
  const categorySlug = typeof config2.category?.slug === "string" ? config2.category.slug.trim() : "";
237791
238477
  const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
@@ -237797,11 +238483,11 @@ function checkWorkspaceAbilityConfig(projectDir, ability) {
237797
238483
  }
237798
238484
  function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
237799
238485
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237800
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237801
- if (!fs47.existsSync(bootstrapPath)) {
237802
- return createDoctorCheck2("Ability bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238486
+ const bootstrapPath = path66.join(projectDir, `${packageBaseName}.php`);
238487
+ if (!fs50.existsSync(bootstrapPath)) {
238488
+ return createDoctorCheck2("Ability bootstrap", "fail", `Missing ${path66.basename(bootstrapPath)}`);
237803
238489
  }
237804
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238490
+ const source = fs50.readFileSync(bootstrapPath, "utf8");
237805
238491
  const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
237806
238492
  const enqueueFunctionName = `${phpPrefix}_enqueue_workflow_abilities`;
237807
238493
  const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
@@ -237818,14 +238504,14 @@ function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
237818
238504
  }
237819
238505
  function checkWorkspaceAbilityIndex(projectDir, abilities) {
237820
238506
  const indexRelativePath = [
237821
- path63.join("src", "abilities", "index.ts"),
237822
- path63.join("src", "abilities", "index.js")
237823
- ].find((relativePath) => fs47.existsSync(path63.join(projectDir, relativePath)));
238507
+ path66.join("src", "abilities", "index.ts"),
238508
+ path66.join("src", "abilities", "index.js")
238509
+ ].find((relativePath) => fs50.existsSync(path66.join(projectDir, relativePath)));
237824
238510
  if (!indexRelativePath) {
237825
238511
  return createDoctorCheck2("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
237826
238512
  }
237827
- const indexPath = path63.join(projectDir, indexRelativePath);
237828
- const source = fs47.readFileSync(indexPath, "utf8");
238513
+ const indexPath = path66.join(projectDir, indexRelativePath);
238514
+ const source = fs50.readFileSync(indexPath, "utf8");
237829
238515
  const missingExports = abilities.filter((ability) => {
237830
238516
  const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex2(ability.slug)}\\/client['"\`]`, "mu");
237831
238517
  return !exportPattern.test(source);
@@ -237836,9 +238522,9 @@ function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
237836
238522
  return Array.from(new Set([
237837
238523
  aiFeature.aiSchemaFile,
237838
238524
  aiFeature.apiFile,
237839
- path63.join(path63.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
237840
- path63.join(path63.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
237841
- path63.join(path63.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
238525
+ path66.join(path66.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
238526
+ path66.join(path66.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
238527
+ path66.join(path66.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
237842
238528
  aiFeature.clientFile,
237843
238529
  aiFeature.dataFile,
237844
238530
  aiFeature.openApiFile,
@@ -237853,11 +238539,11 @@ function checkWorkspaceAiFeatureConfig(aiFeature) {
237853
238539
  }
237854
238540
  function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
237855
238541
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237856
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237857
- if (!fs47.existsSync(bootstrapPath)) {
237858
- return createDoctorCheck2("AI feature bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238542
+ const bootstrapPath = path66.join(projectDir, `${packageBaseName}.php`);
238543
+ if (!fs50.existsSync(bootstrapPath)) {
238544
+ return createDoctorCheck2("AI feature bootstrap", "fail", `Missing ${path66.basename(bootstrapPath)}`);
237859
238545
  }
237860
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238546
+ const source = fs50.readFileSync(bootstrapPath, "utf8");
237861
238547
  const registerFunctionName = `${phpPrefix}_register_ai_features`;
237862
238548
  const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
237863
238549
  const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
@@ -237865,14 +238551,14 @@ function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
237865
238551
  return createDoctorCheck2("AI feature bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook ? "AI feature PHP loader hook is present" : "Missing AI feature PHP require glob or init hook");
237866
238552
  }
237867
238553
  function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
237868
- const editorPluginDir = path63.join("src", "editor-plugins", editorPlugin.slug);
237869
- const surfaceFile = editorPlugin.slot === "PluginSidebar" ? path63.join(editorPluginDir, "Sidebar.tsx") : path63.join(editorPluginDir, "Surface.tsx");
238554
+ const editorPluginDir = path66.join("src", "editor-plugins", editorPlugin.slug);
238555
+ const surfaceFile = editorPlugin.slot === "PluginSidebar" ? path66.join(editorPluginDir, "Sidebar.tsx") : path66.join(editorPluginDir, "Surface.tsx");
237870
238556
  return Array.from(new Set([
237871
238557
  editorPlugin.file,
237872
238558
  surfaceFile,
237873
- path63.join(editorPluginDir, "data.ts"),
237874
- path63.join(editorPluginDir, "types.ts"),
237875
- path63.join(editorPluginDir, "style.scss")
238559
+ path66.join(editorPluginDir, "data.ts"),
238560
+ path66.join(editorPluginDir, "types.ts"),
238561
+ path66.join(editorPluginDir, "style.scss")
237876
238562
  ]));
237877
238563
  }
237878
238564
  function checkWorkspaceEditorPluginConfig(editorPlugin) {
@@ -237882,11 +238568,11 @@ function checkWorkspaceEditorPluginConfig(editorPlugin) {
237882
238568
  }
237883
238569
  function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
237884
238570
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237885
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237886
- if (!fs47.existsSync(bootstrapPath)) {
237887
- return createDoctorCheck2("Editor plugin bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238571
+ const bootstrapPath = path66.join(projectDir, `${packageBaseName}.php`);
238572
+ if (!fs50.existsSync(bootstrapPath)) {
238573
+ return createDoctorCheck2("Editor plugin bootstrap", "fail", `Missing ${path66.basename(bootstrapPath)}`);
237888
238574
  }
237889
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238575
+ const source = fs50.readFileSync(bootstrapPath, "utf8");
237890
238576
  const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
237891
238577
  const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
237892
238578
  const hasEditorEnqueueHook = source.includes(enqueueHook);
@@ -237897,14 +238583,14 @@ function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix)
237897
238583
  }
237898
238584
  function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
237899
238585
  const indexRelativePath = [
237900
- path63.join("src", "editor-plugins", "index.ts"),
237901
- path63.join("src", "editor-plugins", "index.js")
237902
- ].find((relativePath) => fs47.existsSync(path63.join(projectDir, relativePath)));
238586
+ path66.join("src", "editor-plugins", "index.ts"),
238587
+ path66.join("src", "editor-plugins", "index.js")
238588
+ ].find((relativePath) => fs50.existsSync(path66.join(projectDir, relativePath)));
237903
238589
  if (!indexRelativePath) {
237904
238590
  return createDoctorCheck2("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
237905
238591
  }
237906
- const indexPath = path63.join(projectDir, indexRelativePath);
237907
- const source = fs47.readFileSync(indexPath, "utf8");
238592
+ const indexPath = path66.join(projectDir, indexRelativePath);
238593
+ const source = fs50.readFileSync(indexPath, "utf8");
237908
238594
  const missingImports = editorPlugins.filter((editorPlugin) => {
237909
238595
  const importPattern = new RegExp(`['"\`]\\./${escapeRegex2(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
237910
238596
  return !importPattern.test(source);
@@ -237912,15 +238598,15 @@ function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
237912
238598
  return createDoctorCheck2("Editor plugins index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Editor plugin registrations are aggregated" : `Missing editor plugin imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
237913
238599
  }
237914
238600
  function getWorkspaceAdminViewRequiredFiles(adminView) {
237915
- const adminViewDir = path63.join("src", "admin-views", adminView.slug);
238601
+ const adminViewDir = path66.join("src", "admin-views", adminView.slug);
237916
238602
  return Array.from(new Set([
237917
238603
  adminView.file,
237918
238604
  adminView.phpFile,
237919
- path63.join(adminViewDir, "Screen.tsx"),
237920
- path63.join(adminViewDir, "config.ts"),
237921
- path63.join(adminViewDir, "data.ts"),
237922
- path63.join(adminViewDir, "style.scss"),
237923
- path63.join(adminViewDir, "types.ts")
238605
+ path66.join(adminViewDir, "Screen.tsx"),
238606
+ path66.join(adminViewDir, "config.ts"),
238607
+ path66.join(adminViewDir, "data.ts"),
238608
+ path66.join(adminViewDir, "style.scss"),
238609
+ path66.join(adminViewDir, "types.ts")
237924
238610
  ]));
237925
238611
  }
237926
238612
  function checkWorkspaceAdminViewConfig(adminView, inventory) {
@@ -237937,11 +238623,11 @@ function checkWorkspaceAdminViewConfig(adminView, inventory) {
237937
238623
  }
237938
238624
  function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
237939
238625
  const packageBaseName = packageName.split("/").pop() ?? packageName;
237940
- const bootstrapPath = path63.join(projectDir, `${packageBaseName}.php`);
237941
- if (!fs47.existsSync(bootstrapPath)) {
237942
- return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${path63.basename(bootstrapPath)}`);
238626
+ const bootstrapPath = path66.join(projectDir, `${packageBaseName}.php`);
238627
+ if (!fs50.existsSync(bootstrapPath)) {
238628
+ return createDoctorCheck2("Admin view bootstrap", "fail", `Missing ${path66.basename(bootstrapPath)}`);
237943
238629
  }
237944
- const source = fs47.readFileSync(bootstrapPath, "utf8");
238630
+ const source = fs50.readFileSync(bootstrapPath, "utf8");
237945
238631
  const loadFunctionName = `${phpPrefix}_load_admin_views`;
237946
238632
  const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
237947
238633
  const hasLoaderHook = source.includes(loadHook);
@@ -237950,14 +238636,14 @@ function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
237950
238636
  }
237951
238637
  function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
237952
238638
  const indexRelativePath = [
237953
- path63.join("src", "admin-views", "index.ts"),
237954
- path63.join("src", "admin-views", "index.js")
237955
- ].find((relativePath) => fs47.existsSync(path63.join(projectDir, relativePath)));
238639
+ path66.join("src", "admin-views", "index.ts"),
238640
+ path66.join("src", "admin-views", "index.js")
238641
+ ].find((relativePath) => fs50.existsSync(path66.join(projectDir, relativePath)));
237956
238642
  if (!indexRelativePath) {
237957
238643
  return createDoctorCheck2("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
237958
238644
  }
237959
- const indexPath = path63.join(projectDir, indexRelativePath);
237960
- const source = fs47.readFileSync(indexPath, "utf8");
238645
+ const indexPath = path66.join(projectDir, indexRelativePath);
238646
+ const source = fs50.readFileSync(indexPath, "utf8");
237961
238647
  const missingImports = adminViews.filter((adminView) => {
237962
238648
  const importPattern = new RegExp(`['"\`]\\./${escapeRegex2(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
237963
238649
  return !importPattern.test(source);
@@ -237965,11 +238651,11 @@ function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
237965
238651
  return createDoctorCheck2("Admin views index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0 ? "Admin view registrations are aggregated" : `Missing admin view imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
237966
238652
  }
237967
238653
  function checkWorkspaceAdminViewPhp(projectDir, adminView) {
237968
- const phpPath = path63.join(projectDir, adminView.phpFile);
237969
- if (!fs47.existsSync(phpPath)) {
238654
+ const phpPath = path66.join(projectDir, adminView.phpFile);
238655
+ if (!fs50.existsSync(phpPath)) {
237970
238656
  return createDoctorCheck2(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
237971
238657
  }
237972
- const source = fs47.readFileSync(phpPath, "utf8");
238658
+ const source = fs50.readFileSync(phpPath, "utf8");
237973
238659
  const hasAdminMenu = source.includes("add_submenu_page");
237974
238660
  const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
237975
238661
  const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
@@ -237978,56 +238664,115 @@ function checkWorkspaceAdminViewPhp(projectDir, adminView) {
237978
238664
  const hasComponentsStyleDependency = source.includes("'wp-components'");
237979
238665
  return createDoctorCheck2(`Admin view PHP ${adminView.slug}`, hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "pass" : "fail", hasAdminMenu && hasAdminEnqueue && hasScript && hasAsset && hasStyle && hasComponentsStyleDependency ? "Admin menu, script, style, and wp-components style dependency are wired" : "Missing admin menu, enqueue hook, build/admin-views asset reference, or wp-components style dependency");
237980
238666
  }
237981
- function checkVariationEntrypoint(projectDir, blockSlug) {
237982
- const entryPath = path63.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
237983
- if (!fs47.existsSync(entryPath)) {
237984
- return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, "fail", `Missing ${path63.relative(projectDir, entryPath)}`);
238667
+ function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
238668
+ const checks3 = [];
238669
+ if (inventory.restResources.length > 0) {
238670
+ checks3.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
237985
238671
  }
237986
- const source = fs47.readFileSync(entryPath, "utf8");
237987
- const hasImport = hasUncommentedPattern2(source, WORKSPACE_VARIATIONS_IMPORT_PATTERN);
237988
- const hasCall = hasExecutablePattern2(source, WORKSPACE_VARIATIONS_CALL_PATTERN);
237989
- return createDoctorCheck2(`Variation entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Variations registration hook is present" : "Missing ./variations import or registerWorkspaceVariations() call");
237990
- }
237991
- function checkBlockStyleEntrypoint(projectDir, blockSlug) {
237992
- const entryPath = path63.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
237993
- if (!fs47.existsSync(entryPath)) {
237994
- return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, "fail", `Missing ${path63.relative(projectDir, entryPath)}`);
238672
+ for (const restResource of inventory.restResources) {
238673
+ checks3.push(checkWorkspaceRestResourceConfig(restResource));
238674
+ checks3.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
237995
238675
  }
237996
- const source = fs47.readFileSync(entryPath, "utf8");
237997
- const hasImport = hasUncommentedPattern2(source, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN);
237998
- const hasCall = hasExecutablePattern2(source, WORKSPACE_BLOCK_STYLES_CALL_PATTERN);
237999
- return createDoctorCheck2(`Block style entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block style registration hook is present" : "Missing ./styles import or registerWorkspaceBlockStyles() call");
238000
- }
238001
- function checkBlockTransformEntrypoint(projectDir, blockSlug) {
238002
- const entryPath = path63.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
238003
- if (!fs47.existsSync(entryPath)) {
238004
- return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, "fail", `Missing ${path63.relative(projectDir, entryPath)}`);
238676
+ if (inventory.abilities.length > 0) {
238677
+ checks3.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238678
+ checks3.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
238005
238679
  }
238006
- const source = fs47.readFileSync(entryPath, "utf8");
238007
- const hasImport = hasUncommentedPattern2(source, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN);
238008
- const hasCall = hasExecutablePattern2(source, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN);
238009
- return createDoctorCheck2(`Block transform entrypoint ${blockSlug}`, hasImport && hasCall ? "pass" : "fail", hasImport && hasCall ? "Block transform registration hook is present" : "Missing ./transforms import or applyWorkspaceBlockTransforms(registration.settings) call");
238680
+ for (const ability of inventory.abilities) {
238681
+ checks3.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
238682
+ checks3.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
238683
+ }
238684
+ if (inventory.aiFeatures.length > 0) {
238685
+ checks3.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238686
+ }
238687
+ for (const aiFeature of inventory.aiFeatures) {
238688
+ checks3.push(checkWorkspaceAiFeatureConfig(aiFeature));
238689
+ checks3.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
238690
+ }
238691
+ if (inventory.editorPlugins.length > 0) {
238692
+ checks3.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238693
+ checks3.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
238694
+ }
238695
+ for (const editorPlugin of inventory.editorPlugins) {
238696
+ checks3.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
238697
+ checks3.push(checkWorkspaceEditorPluginConfig(editorPlugin));
238698
+ }
238699
+ if (inventory.adminViews.length > 0) {
238700
+ checks3.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238701
+ checks3.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
238702
+ }
238703
+ for (const adminView of inventory.adminViews) {
238704
+ checks3.push(checkWorkspaceAdminViewConfig(adminView, inventory));
238705
+ checks3.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
238706
+ checks3.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
238707
+ }
238708
+ return checks3;
238010
238709
  }
238011
- function checkBlockTransformConfig(workspace, transform2) {
238012
- const expectedTo = `${workspace.workspace.namespace}/${transform2.block}`;
238710
+ var init_cli_doctor_workspace_features = __esm(() => {
238711
+ init_cli_add_shared();
238712
+ init_cli_doctor_workspace_shared();
238713
+ });
238714
+
238715
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace-package.ts
238716
+ import fs51 from "fs";
238717
+ import path67 from "path";
238718
+ function getWorkspacePackageMetadataCheck(workspace, packageJson) {
238013
238719
  const issues = [];
238014
- if (!WORKSPACE_FULL_BLOCK_NAME_PATTERN.test(transform2.from)) {
238015
- issues.push("from must use full namespace/block format");
238720
+ const packageName = packageJson.name;
238721
+ const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
238722
+ const wpTypia = packageJson.wpTypia;
238723
+ if (typeof packageName !== "string" || packageName.length === 0) {
238724
+ issues.push("package.json must define a string name for workspace bootstrap resolution");
238016
238725
  }
238017
- if (transform2.to !== expectedTo) {
238018
- issues.push(`to must equal "${expectedTo}" for workspace block "${transform2.block}"`);
238726
+ if (wpTypia?.projectType !== "workspace") {
238727
+ issues.push('wpTypia.projectType must be "workspace"');
238019
238728
  }
238020
- return createDoctorCheck2(`Block transform config ${transform2.block}/${transform2.slug}`, issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `${transform2.from} transforms into ${transform2.to}` : issues.join("; "));
238729
+ if (wpTypia?.templatePackage !== WORKSPACE_TEMPLATE_PACKAGE) {
238730
+ issues.push(`wpTypia.templatePackage must be "${WORKSPACE_TEMPLATE_PACKAGE}"`);
238731
+ }
238732
+ if (wpTypia?.namespace !== workspace.workspace.namespace) {
238733
+ issues.push(`wpTypia.namespace must equal "${workspace.workspace.namespace}"`);
238734
+ }
238735
+ if (wpTypia?.textDomain !== workspace.workspace.textDomain) {
238736
+ issues.push(`wpTypia.textDomain must equal "${workspace.workspace.textDomain}"`);
238737
+ }
238738
+ if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
238739
+ issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
238740
+ }
238741
+ if (!fs51.existsSync(path67.join(workspace.projectDir, bootstrapRelativePath))) {
238742
+ issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
238743
+ }
238744
+ return createDoctorCheck2("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0 ? `package.json metadata aligns with ${workspace.packageName} and ${bootstrapRelativePath}` : issues.join("; "));
238021
238745
  }
238022
- function checkMigrationWorkspaceHint(workspace, packageJson) {
238746
+ function getMigrationWorkspaceHintCheck(workspace, packageJson) {
238023
238747
  const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
238024
- const migrationConfigRelativePath = path63.join("src", "migrations", "config.ts");
238025
- const hasMigrationConfig = fs47.existsSync(path63.join(workspace.projectDir, migrationConfigRelativePath));
238748
+ const migrationConfigRelativePath = path67.join("src", "migrations", "config.ts");
238749
+ const hasMigrationConfig = fs51.existsSync(path67.join(workspace.projectDir, migrationConfigRelativePath));
238026
238750
  if (!hasMigrationScript && !hasMigrationConfig) {
238027
238751
  return null;
238028
238752
  }
238029
238753
  return createDoctorCheck2("Migration workspace", hasMigrationConfig ? "pass" : "fail", hasMigrationConfig ? "Run `wp-typia migrate doctor --all` for migration target, snapshot, fixture, and generated artifact checks" : `Missing ${migrationConfigRelativePath} for the configured migration workspace`);
238030
238754
  }
238755
+ var init_cli_doctor_workspace_package = __esm(() => {
238756
+ init_cli_doctor_workspace_shared();
238757
+ init_workspace_project();
238758
+ });
238759
+
238760
+ // ../wp-typia-project-tools/src/runtime/cli-doctor-workspace.ts
238761
+ function formatWorkspaceInventorySummary(inventory) {
238762
+ return [
238763
+ `${inventory.blocks.length} block(s)`,
238764
+ `${inventory.variations.length} variation(s)`,
238765
+ `${inventory.blockStyles.length} block style(s)`,
238766
+ `${inventory.blockTransforms.length} block transform(s)`,
238767
+ `${inventory.patterns.length} pattern(s)`,
238768
+ `${inventory.bindingSources.length} binding source(s)`,
238769
+ `${inventory.restResources.length} REST resource(s)`,
238770
+ `${inventory.abilities.length} ability scaffold(s)`,
238771
+ `${inventory.aiFeatures.length} AI feature(s)`,
238772
+ `${inventory.editorPlugins.length} editor plugin(s)`,
238773
+ `${inventory.adminViews.length} admin view(s)`
238774
+ ].join(", ");
238775
+ }
238031
238776
  function getWorkspaceDoctorChecks(cwd) {
238032
238777
  const checks3 = [];
238033
238778
  let workspace = null;
@@ -238057,122 +238802,14 @@ function getWorkspaceDoctorChecks(cwd) {
238057
238802
  checks3.push(createDoctorCheck2("Workspace package metadata", "fail", error48 instanceof Error ? error48.message : String(error48)));
238058
238803
  return checks3;
238059
238804
  }
238060
- checks3.push(checkWorkspacePackageMetadata(workspace, workspacePackageJson));
238805
+ checks3.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson));
238061
238806
  try {
238062
238807
  const inventory = readWorkspaceInventory(workspace.projectDir);
238063
- checks3.push(createDoctorCheck2("Workspace inventory", "pass", `${inventory.blocks.length} block(s), ${inventory.variations.length} variation(s), ${inventory.blockStyles.length} block style(s), ${inventory.blockTransforms.length} block transform(s), ${inventory.patterns.length} pattern(s), ${inventory.bindingSources.length} binding source(s), ${inventory.restResources.length} REST resource(s), ${inventory.abilities.length} ability scaffold(s), ${inventory.aiFeatures.length} AI feature(s), ${inventory.editorPlugins.length} editor plugin(s), ${inventory.adminViews.length} admin view(s)`));
238064
- for (const block of inventory.blocks) {
238065
- checks3.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, getWorkspaceBlockRequiredFiles(block)));
238066
- checks3.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
238067
- checks3.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
238068
- checks3.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
238069
- checks3.push(...checkWorkspaceBlockIframeCompatibility(workspace.projectDir, block.slug));
238070
- }
238071
- const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
238072
- const variationTargetBlocks = new Set;
238073
- for (const variation of inventory.variations) {
238074
- if (!registeredBlockSlugs.has(variation.block)) {
238075
- checks3.push(createDoctorCheck2(`Variation ${variation.block}/${variation.slug}`, "fail", `Variation references unknown block "${variation.block}"`));
238076
- continue;
238077
- }
238078
- variationTargetBlocks.add(variation.block);
238079
- checks3.push(checkExistingFiles(workspace.projectDir, `Variation ${variation.block}/${variation.slug}`, [variation.file]));
238080
- }
238081
- for (const blockSlug of variationTargetBlocks) {
238082
- checks3.push(checkVariationEntrypoint(workspace.projectDir, blockSlug));
238083
- }
238084
- const blockStyleTargetBlocks = new Set;
238085
- for (const blockStyle of inventory.blockStyles) {
238086
- if (!registeredBlockSlugs.has(blockStyle.block)) {
238087
- checks3.push(createDoctorCheck2(`Block style ${blockStyle.block}/${blockStyle.slug}`, "fail", `Block style references unknown block "${blockStyle.block}"`));
238088
- continue;
238089
- }
238090
- blockStyleTargetBlocks.add(blockStyle.block);
238091
- checks3.push(checkExistingFiles(workspace.projectDir, `Block style ${blockStyle.block}/${blockStyle.slug}`, [blockStyle.file]));
238092
- }
238093
- for (const blockSlug of blockStyleTargetBlocks) {
238094
- checks3.push(checkExistingFiles(workspace.projectDir, `Block style registry ${blockSlug}`, [
238095
- path63.join("src", "blocks", blockSlug, "styles", "index.ts")
238096
- ]));
238097
- checks3.push(checkBlockStyleEntrypoint(workspace.projectDir, blockSlug));
238098
- }
238099
- const blockTransformTargetBlocks = new Set;
238100
- for (const blockTransform of inventory.blockTransforms) {
238101
- if (!registeredBlockSlugs.has(blockTransform.block)) {
238102
- checks3.push(createDoctorCheck2(`Block transform ${blockTransform.block}/${blockTransform.slug}`, "fail", `Block transform references unknown block "${blockTransform.block}"`));
238103
- continue;
238104
- }
238105
- blockTransformTargetBlocks.add(blockTransform.block);
238106
- checks3.push(checkBlockTransformConfig(workspace, blockTransform));
238107
- checks3.push(checkExistingFiles(workspace.projectDir, `Block transform ${blockTransform.block}/${blockTransform.slug}`, [blockTransform.file]));
238108
- }
238109
- for (const blockSlug of blockTransformTargetBlocks) {
238110
- checks3.push(checkExistingFiles(workspace.projectDir, `Block transform registry ${blockSlug}`, [
238111
- path63.join("src", "blocks", blockSlug, "transforms", "index.ts")
238112
- ]));
238113
- checks3.push(checkBlockTransformEntrypoint(workspace.projectDir, blockSlug));
238114
- }
238115
- const shouldCheckPatternBootstrap = inventory.patterns.length > 0 || fs47.existsSync(path63.join(workspace.projectDir, "src", "patterns"));
238116
- if (shouldCheckPatternBootstrap) {
238117
- checks3.push(checkWorkspacePatternBootstrap(workspace.projectDir, workspace.packageName));
238118
- }
238119
- for (const pattern of inventory.patterns) {
238120
- checks3.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [pattern.file]));
238121
- }
238122
- if (inventory.bindingSources.length > 0) {
238123
- checks3.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
238124
- checks3.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
238125
- }
238126
- for (const bindingSource of inventory.bindingSources) {
238127
- checks3.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
238128
- bindingSource.serverFile,
238129
- bindingSource.editorFile
238130
- ]));
238131
- const bindingTargetCheck = checkWorkspaceBindingTarget(workspace.projectDir, workspace, registeredBlockSlugs, bindingSource);
238132
- if (bindingTargetCheck) {
238133
- checks3.push(bindingTargetCheck);
238134
- }
238135
- }
238136
- if (inventory.restResources.length > 0) {
238137
- checks3.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238138
- }
238139
- for (const restResource of inventory.restResources) {
238140
- checks3.push(checkWorkspaceRestResourceConfig(restResource));
238141
- checks3.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
238142
- }
238143
- if (inventory.abilities.length > 0) {
238144
- checks3.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238145
- checks3.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
238146
- }
238147
- for (const ability of inventory.abilities) {
238148
- checks3.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
238149
- checks3.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
238150
- }
238151
- if (inventory.aiFeatures.length > 0) {
238152
- checks3.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238153
- }
238154
- for (const aiFeature of inventory.aiFeatures) {
238155
- checks3.push(checkWorkspaceAiFeatureConfig(aiFeature));
238156
- checks3.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
238157
- }
238158
- if (inventory.editorPlugins.length > 0) {
238159
- checks3.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238160
- checks3.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
238161
- }
238162
- for (const editorPlugin of inventory.editorPlugins) {
238163
- checks3.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
238164
- checks3.push(checkWorkspaceEditorPluginConfig(editorPlugin));
238165
- }
238166
- if (inventory.adminViews.length > 0) {
238167
- checks3.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
238168
- checks3.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
238169
- }
238170
- for (const adminView of inventory.adminViews) {
238171
- checks3.push(checkWorkspaceAdminViewConfig(adminView, inventory));
238172
- checks3.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
238173
- checks3.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
238174
- }
238175
- const migrationWorkspaceCheck = checkMigrationWorkspaceHint(workspace, workspacePackageJson);
238808
+ checks3.push(createDoctorCheck2("Workspace inventory", "pass", formatWorkspaceInventorySummary(inventory)));
238809
+ checks3.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
238810
+ checks3.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
238811
+ checks3.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
238812
+ const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspace, workspacePackageJson);
238176
238813
  if (migrationWorkspaceCheck) {
238177
238814
  checks3.push(migrationWorkspaceCheck);
238178
238815
  }
@@ -238181,55 +238818,14 @@ function getWorkspaceDoctorChecks(cwd) {
238181
238818
  }
238182
238819
  return checks3;
238183
238820
  }
238184
- var WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';", WORKSPACE_COLLECTION_IMPORT_PATTERN, WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php", WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js", WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php", WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php", WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php", WORKSPACE_ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", WORKSPACE_ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", WORKSPACE_AI_FEATURE_GLOB = "/inc/ai-features/*.php", WORKSPACE_ADMIN_VIEW_GLOB = "/inc/admin-views/*.php", WORKSPACE_ADMIN_VIEW_SCRIPT = "build/admin-views/index.js", WORKSPACE_ADMIN_VIEW_ASSET = "build/admin-views/index.asset.php", WORKSPACE_ADMIN_VIEW_STYLE = "build/admin-views/style-index.css", WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js", WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php", WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css", WORKSPACE_GENERATED_BLOCK_ARTIFACTS, WORKSPACE_FULL_BLOCK_NAME_PATTERN, WORKSPACE_VARIATIONS_IMPORT_PATTERN, WORKSPACE_VARIATIONS_CALL_PATTERN, WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN, WORKSPACE_BLOCK_STYLES_CALL_PATTERN, WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN, WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN, WORKSPACE_BLOCK_IFRAME_COMPATIBILITY_DOC_URL = "https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/block-migration-for-iframe-editor-compatibility/", WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES, WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN, WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES, WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES, WORKSPACE_BLOCK_LOCAL_STYLE_FILES, WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN, WORKSPACE_BLOCK_PROPS_PATTERN;
238185
238821
  var init_cli_doctor_workspace = __esm(() => {
238186
- init_cli_add_shared();
238187
- init_hooked_blocks();
238822
+ init_cli_doctor_workspace_bindings();
238823
+ init_cli_doctor_workspace_blocks();
238824
+ init_cli_doctor_workspace_features();
238825
+ init_cli_doctor_workspace_package();
238826
+ init_cli_doctor_workspace_shared();
238188
238827
  init_workspace_inventory();
238189
238828
  init_workspace_project();
238190
- WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
238191
- WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
238192
- "block.json",
238193
- "typia.manifest.json",
238194
- "typia.schema.json",
238195
- "typia-validator.php",
238196
- "typia.openapi.json"
238197
- ];
238198
- WORKSPACE_FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
238199
- WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
238200
- WORKSPACE_VARIATIONS_CALL_PATTERN = /registerWorkspaceVariations\s*\(\s*\)\s*;?/u;
238201
- WORKSPACE_BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
238202
- WORKSPACE_BLOCK_STYLES_CALL_PATTERN = /registerWorkspaceBlockStyles\s*\(\s*\)\s*;?/u;
238203
- WORKSPACE_BLOCK_TRANSFORMS_IMPORT_PATTERN = /^\s*import\s*\{\s*applyWorkspaceBlockTransforms\s*\}\s*from\s*["']\.\/transforms["']\s*;?\s*$/mu;
238204
- WORKSPACE_BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
238205
- WORKSPACE_BLOCK_IFRAME_DIAGNOSTIC_CODES = {
238206
- API_VERSION: "wp-typia.workspace.block.iframe.api-version",
238207
- BLOCK_PROPS: "wp-typia.workspace.block.iframe.block-props",
238208
- EDITOR_GLOBALS: "wp-typia.workspace.block.iframe.editor-globals",
238209
- EDITOR_STYLES: "wp-typia.workspace.block.iframe.editor-styles"
238210
- };
238211
- WORKSPACE_BLOCK_EDITOR_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/u;
238212
- WORKSPACE_BLOCK_EDITOR_SOURCE_BASENAMES = new Set([
238213
- "edit",
238214
- "editor",
238215
- "index",
238216
- "save"
238217
- ]);
238218
- WORKSPACE_BLOCK_EDITOR_SOURCE_DIRECTORIES = new Set([
238219
- "components",
238220
- "controls",
238221
- "editor",
238222
- "inspector"
238223
- ]);
238224
- WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
238225
- "editor.css",
238226
- "editor.scss",
238227
- "index.css",
238228
- "style.css",
238229
- "style.scss"
238230
- ];
238231
- WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
238232
- WORKSPACE_BLOCK_PROPS_PATTERN = /\buse(?:Block|InnerBlocks)Props(?:\.save)?\s*\(/u;
238233
238829
  });
238234
238830
 
238235
238831
  // ../wp-typia-project-tools/src/runtime/cli-doctor.ts
@@ -238278,19 +238874,19 @@ __export(exports_cli_init, {
238278
238874
  getInitPlan: () => getInitPlan,
238279
238875
  applyInitPlan: () => applyInitPlan
238280
238876
  });
238281
- import fs48 from "fs";
238877
+ import fs52 from "fs";
238282
238878
  import { promises as fsp25 } from "fs";
238283
- import path64 from "path";
238879
+ import path68 from "path";
238284
238880
  import { analyzeSourceTypes } from "@wp-typia/block-runtime/metadata-parser";
238285
238881
  function normalizeRelativePath2(value2) {
238286
238882
  return value2.replace(/\\/gu, "/");
238287
238883
  }
238288
238884
  function readProjectPackageJson(projectDir) {
238289
- const packageJsonPath = path64.join(projectDir, "package.json");
238290
- if (!fs48.existsSync(packageJsonPath)) {
238885
+ const packageJsonPath = path68.join(projectDir, "package.json");
238886
+ if (!fs52.existsSync(packageJsonPath)) {
238291
238887
  return null;
238292
238888
  }
238293
- const source = fs48.readFileSync(packageJsonPath, "utf8");
238889
+ const source = fs52.readFileSync(packageJsonPath, "utf8");
238294
238890
  try {
238295
238891
  return JSON.parse(source);
238296
238892
  } catch (error48) {
@@ -238302,13 +238898,13 @@ function inferInitPackageManager(projectDir, packageJson) {
238302
238898
  if (packageJson?.packageManager) {
238303
238899
  return parseWorkspacePackageManagerId(packageJson.packageManager);
238304
238900
  }
238305
- if (fs48.existsSync(path64.join(projectDir, "bun.lock")) || fs48.existsSync(path64.join(projectDir, "bun.lockb"))) {
238901
+ if (fs52.existsSync(path68.join(projectDir, "bun.lock")) || fs52.existsSync(path68.join(projectDir, "bun.lockb"))) {
238306
238902
  return "bun";
238307
238903
  }
238308
- if (fs48.existsSync(path64.join(projectDir, "pnpm-lock.yaml"))) {
238904
+ if (fs52.existsSync(path68.join(projectDir, "pnpm-lock.yaml"))) {
238309
238905
  return "pnpm";
238310
238906
  }
238311
- if (fs48.existsSync(path64.join(projectDir, "yarn.lock")) || fs48.existsSync(path64.join(projectDir, ".yarnrc.yml"))) {
238907
+ if (fs52.existsSync(path68.join(projectDir, "yarn.lock")) || fs52.existsSync(path68.join(projectDir, ".yarnrc.yml"))) {
238312
238908
  return "yarn";
238313
238909
  }
238314
238910
  return "npm";
@@ -238392,13 +238988,13 @@ function buildPackageManagerFieldChange(packageJson, packageManager, options = {
238392
238988
  };
238393
238989
  }
238394
238990
  function buildGeneratedArtifactPaths(blockJsonFile, manifestFile) {
238395
- const manifestDir = path64.dirname(manifestFile);
238991
+ const manifestDir = path68.dirname(manifestFile);
238396
238992
  const artifactPaths = [
238397
238993
  blockJsonFile,
238398
238994
  manifestFile,
238399
- path64.join(manifestDir, "typia.schema.json"),
238400
- path64.join(manifestDir, "typia-validator.php"),
238401
- path64.join(manifestDir, "typia.openapi.json")
238995
+ path68.join(manifestDir, "typia.schema.json"),
238996
+ path68.join(manifestDir, "typia-validator.php"),
238997
+ path68.join(manifestDir, "typia.openapi.json")
238402
238998
  ];
238403
238999
  return Array.from(new Set(artifactPaths.map((filePath) => normalizeRelativePath2(filePath))));
238404
239000
  }
@@ -238419,8 +239015,8 @@ function isObjectLikeSourceType(projectDir, typesFile, sourceTypeName) {
238419
239015
  return analyzedTypes[sourceTypeName]?.kind === "object";
238420
239016
  }
238421
239017
  function inferRetrofitAttributeTypeName(projectDir, block) {
238422
- const typesPath = path64.join(projectDir, block.typesFile);
238423
- const typesSource = fs48.readFileSync(typesPath, "utf8");
239018
+ const typesPath = path68.join(projectDir, block.typesFile);
239019
+ const typesSource = fs52.readFileSync(typesPath, "utf8");
238424
239020
  const blockNameSegments = block.blockName.split("/");
238425
239021
  const slug = blockNameSegments[blockNameSegments.length - 1] ?? block.key;
238426
239022
  const candidateNames = collectNamedSourceTypeCandidates(typesSource);
@@ -238725,10 +239321,10 @@ function hasExistingWpTypiaProjectSurface(projectDir, packageJson) {
238725
239321
  const scripts = packageJson?.scripts ?? {};
238726
239322
  const hasSyncSurface = typeof scripts.sync === "string" || typeof scripts["sync-types"] === "string";
238727
239323
  const hasHelperFiles = [
238728
- path64.join("scripts", "block-config.ts"),
238729
- path64.join("scripts", "sync-project.ts"),
238730
- path64.join("scripts", "sync-types-to-block-json.ts")
238731
- ].every((relativePath) => fs48.existsSync(path64.join(projectDir, relativePath)));
239324
+ path68.join("scripts", "block-config.ts"),
239325
+ path68.join("scripts", "sync-project.ts"),
239326
+ path68.join("scripts", "sync-types-to-block-json.ts")
239327
+ ].every((relativePath) => fs52.existsSync(path68.join(projectDir, relativePath)));
238732
239328
  const hasRuntimeDeps = typeof getExistingDependencyVersion(packageJson, "@wp-typia/block-runtime") === "string" && typeof getExistingDependencyVersion(packageJson, "@wp-typia/block-types") === "string";
238733
239329
  return hasSyncSurface && hasHelperFiles && hasRuntimeDeps;
238734
239330
  }
@@ -238738,17 +239334,17 @@ function buildPlannedFiles(projectDir, layoutKind) {
238738
239334
  }
238739
239335
  return [
238740
239336
  {
238741
- action: fs48.existsSync(path64.join(projectDir, "scripts", "block-config.ts")) ? "update" : "add",
239337
+ action: fs52.existsSync(path68.join(projectDir, "scripts", "block-config.ts")) ? "update" : "add",
238742
239338
  path: "scripts/block-config.ts",
238743
239339
  purpose: "Declare the current retrofit block targets so sync-types can regenerate metadata from the existing TypeScript source of truth."
238744
239340
  },
238745
239341
  {
238746
- action: fs48.existsSync(path64.join(projectDir, "scripts", "sync-types-to-block-json.ts")) ? "update" : "add",
239342
+ action: fs52.existsSync(path68.join(projectDir, "scripts", "sync-types-to-block-json.ts")) ? "update" : "add",
238747
239343
  path: "scripts/sync-types-to-block-json.ts",
238748
239344
  purpose: "Generate block.json and Typia metadata artifacts from the current TypeScript source of truth."
238749
239345
  },
238750
239346
  {
238751
- action: fs48.existsSync(path64.join(projectDir, "scripts", "sync-project.ts")) ? "update" : "add",
239347
+ action: fs52.existsSync(path68.join(projectDir, "scripts", "sync-project.ts")) ? "update" : "add",
238752
239348
  path: "scripts/sync-project.ts",
238753
239349
  purpose: "Provide one shared sync entrypoint that can grow into sync-rest or workspace-aware refresh steps later."
238754
239350
  }
@@ -238896,14 +239492,14 @@ function buildProjectPackageJsonSource(packageJson) {
238896
239492
  }
238897
239493
  function buildRetrofitHelperFiles(blockTargets) {
238898
239494
  return {
238899
- [path64.join("scripts", "block-config.ts")]: buildRetrofitBlockConfigSource(blockTargets),
238900
- [path64.join("scripts", "sync-project.ts")]: buildRetrofitSyncProjectScriptSource(),
238901
- [path64.join("scripts", "sync-types-to-block-json.ts")]: buildRetrofitSyncTypesScriptSource()
239495
+ [path68.join("scripts", "block-config.ts")]: buildRetrofitBlockConfigSource(blockTargets),
239496
+ [path68.join("scripts", "sync-project.ts")]: buildRetrofitSyncProjectScriptSource(),
239497
+ [path68.join("scripts", "sync-types-to-block-json.ts")]: buildRetrofitSyncTypesScriptSource()
238902
239498
  };
238903
239499
  }
238904
239500
  async function createRetrofitMutationSnapshot(projectDir, filePaths) {
238905
- const scriptsDir = path64.join(projectDir, "scripts");
238906
- const scriptsDirExisted = fs48.existsSync(scriptsDir);
239501
+ const scriptsDir = path68.join(projectDir, "scripts");
239502
+ const scriptsDirExisted = fs52.existsSync(scriptsDir);
238907
239503
  const fileSources = await snapshotWorkspaceFiles(filePaths);
238908
239504
  const targetPaths = fileSources.filter((entry) => entry.source === null).map((entry) => entry.filePath);
238909
239505
  if (!scriptsDirExisted) {
@@ -238917,11 +239513,11 @@ async function createRetrofitMutationSnapshot(projectDir, filePaths) {
238917
239513
  }
238918
239514
  async function writeRetrofitFiles(options) {
238919
239515
  const helperFiles = buildRetrofitHelperFiles(options.blockTargets);
238920
- const scriptsDir = path64.join(options.projectDir, "scripts");
239516
+ const scriptsDir = path68.join(options.projectDir, "scripts");
238921
239517
  await fsp25.mkdir(scriptsDir, { recursive: true });
238922
- await fsp25.writeFile(path64.join(options.projectDir, "package.json"), buildProjectPackageJsonSource(options.packageJson), "utf8");
239518
+ await fsp25.writeFile(path68.join(options.projectDir, "package.json"), buildProjectPackageJsonSource(options.packageJson), "utf8");
238923
239519
  for (const [relativePath, source] of Object.entries(helperFiles)) {
238924
- await fsp25.writeFile(path64.join(options.projectDir, relativePath), source, "utf8");
239520
+ await fsp25.writeFile(path68.join(options.projectDir, relativePath), source, "utf8");
238925
239521
  }
238926
239522
  }
238927
239523
  function buildApplyFailureError(error48) {
@@ -238929,7 +239525,7 @@ function buildApplyFailureError(error48) {
238929
239525
  return createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unable to apply the retrofit init plan safely. The command restored the previous package.json/helper-file snapshot. ${message}`, error48 instanceof Error ? { cause: error48 } : undefined);
238930
239526
  }
238931
239527
  function getInitPlan(projectDir, options = {}) {
238932
- const resolvedProjectDir = path64.resolve(projectDir);
239528
+ const resolvedProjectDir = path68.resolve(projectDir);
238933
239529
  const packageJson = readProjectPackageJson(resolvedProjectDir);
238934
239530
  const packageManager = resolveInitPackageManager(resolvedProjectDir, packageJson, options.packageManager);
238935
239531
  const workspace = tryResolveWorkspaceProject(resolvedProjectDir);
@@ -238965,7 +239561,7 @@ function getInitPlan(projectDir, options = {}) {
238965
239561
  status: "already-initialized"
238966
239562
  });
238967
239563
  }
238968
- const projectName = typeof packageJson?.name === "string" && packageJson.name.length > 0 ? packageJson.name : path64.basename(resolvedProjectDir);
239564
+ const projectName = typeof packageJson?.name === "string" && packageJson.name.length > 0 ? packageJson.name : path68.basename(resolvedProjectDir);
238969
239565
  const layout = buildLayoutDetails(resolvedProjectDir);
238970
239566
  const dependencyChanges = buildDependencyChanges(packageJson);
238971
239567
  const scriptChanges = buildScriptChanges(packageJson, packageManager);
@@ -239031,8 +239627,8 @@ async function applyInitPlan(projectDir, options = {}) {
239031
239627
  });
239032
239628
  const helperFiles = buildRetrofitHelperFiles(previewPlan.blockTargets);
239033
239629
  const filePaths = [
239034
- path64.join(previewPlan.projectDir, "package.json"),
239035
- ...Object.keys(helperFiles).map((relativePath) => path64.join(previewPlan.projectDir, relativePath))
239630
+ path68.join(previewPlan.projectDir, "package.json"),
239631
+ ...Object.keys(helperFiles).map((relativePath) => path68.join(previewPlan.projectDir, relativePath))
239036
239632
  ];
239037
239633
  const mutationSnapshot = await createRetrofitMutationSnapshot(previewPlan.projectDir, filePaths);
239038
239634
  try {
@@ -239094,27 +239690,27 @@ __export(exports_cli_scaffold, {
239094
239690
  getOptionalOnboarding: () => getOptionalOnboarding,
239095
239691
  getNextSteps: () => getNextSteps
239096
239692
  });
239097
- import fs49 from "fs";
239693
+ import fs53 from "fs";
239098
239694
  import { promises as fsp26 } from "fs";
239099
- import path65 from "path";
239695
+ import path69 from "path";
239100
239696
  async function listRelativeProjectFiles(rootDir) {
239101
239697
  const relativeFiles = [];
239102
239698
  async function visit2(currentDir) {
239103
239699
  const entries = await fsp26.readdir(currentDir, { withFileTypes: true });
239104
239700
  for (const entry of entries) {
239105
- const absolutePath = path65.join(currentDir, entry.name);
239701
+ const absolutePath = path69.join(currentDir, entry.name);
239106
239702
  if (entry.isDirectory()) {
239107
239703
  await visit2(absolutePath);
239108
239704
  continue;
239109
239705
  }
239110
- relativeFiles.push(path65.relative(rootDir, absolutePath).replace(path65.sep === "\\" ? /\\/gu : /\//gu, "/"));
239706
+ relativeFiles.push(path69.relative(rootDir, absolutePath).replace(path69.sep === "\\" ? /\\/gu : /\//gu, "/"));
239111
239707
  }
239112
239708
  }
239113
239709
  await visit2(rootDir);
239114
239710
  return relativeFiles.sort((left, right) => left.localeCompare(right));
239115
239711
  }
239116
239712
  async function assertDryRunTargetDirectoryReady(projectDir, allowExistingDir) {
239117
- if (!fs49.existsSync(projectDir) || allowExistingDir) {
239713
+ if (!fs53.existsSync(projectDir) || allowExistingDir) {
239118
239714
  return;
239119
239715
  }
239120
239716
  const entries = await fsp26.readdir(projectDir);
@@ -239145,7 +239741,7 @@ async function buildScaffoldDryRunPlan({
239145
239741
  }) {
239146
239742
  await assertDryRunTargetDirectoryReady(projectDir, allowExistingDir);
239147
239743
  const { path: tempRoot, cleanup } = await createManagedTempRoot("wp-typia-scaffold-plan-");
239148
- const previewProjectDir = path65.join(tempRoot, "preview-project");
239744
+ const previewProjectDir = path69.join(tempRoot, "preview-project");
239149
239745
  try {
239150
239746
  const result = await scaffoldProject({
239151
239747
  allowExistingDir: false,
@@ -239185,14 +239781,14 @@ function validateCreateProjectInput(projectInput) {
239185
239781
  if (normalizedProjectInput.length === 0) {
239186
239782
  throw new Error("Project directory is required. Usage: wp-typia create <project-dir> (or wp-typia <project-dir> when <project-dir> is the only positional argument).");
239187
239783
  }
239188
- const normalizedProjectPath = path65.normalize(normalizedProjectInput).replace(/[\\/]+$/u, "") || path65.normalize(normalizedProjectInput);
239784
+ const normalizedProjectPath = path69.normalize(normalizedProjectInput).replace(/[\\/]+$/u, "") || path69.normalize(normalizedProjectInput);
239189
239785
  if (normalizedProjectPath === "." || normalizedProjectPath === "..") {
239190
239786
  throw new Error("`wp-typia create` requires a new project directory. Use an explicit child directory instead of `.` or `..`.");
239191
239787
  }
239192
239788
  }
239193
239789
  function collectProjectDirectoryWarnings(projectDir) {
239194
239790
  const warnings = [];
239195
- const projectName = path65.basename(projectDir);
239791
+ const projectName = path69.basename(projectDir);
239196
239792
  if (/\s/u.test(projectName)) {
239197
239793
  warnings.push(`Project directory "${projectName}" contains spaces. The generated next-step commands will be quoted, but a simple kebab-case directory name is usually easier to use with shells and downstream tooling.`);
239198
239794
  }
@@ -239347,7 +239943,7 @@ function getNextSteps({
239347
239943
  noInstall,
239348
239944
  templateId
239349
239945
  }) {
239350
- const cdTarget = path65.isAbsolute(projectInput) ? projectDir : projectInput;
239946
+ const cdTarget = path69.isAbsolute(projectInput) ? projectDir : projectInput;
239351
239947
  const steps = [`cd ${quoteShellValue(cdTarget)}`];
239352
239948
  if (noInstall) {
239353
239949
  steps.push(formatInstallCommand(packageManager));
@@ -239495,8 +240091,8 @@ async function runScaffoldFlow({
239495
240091
  select: selectWithMigrationUi,
239496
240092
  yes
239497
240093
  });
239498
- const projectDir = path65.resolve(cwd, projectInput);
239499
- const projectName = path65.basename(projectDir);
240094
+ const projectDir = path69.resolve(cwd, projectInput);
240095
+ const projectName = path69.basename(projectDir);
239500
240096
  const answers = await collectScaffoldAnswers({
239501
240097
  dataStorageMode: resolvedDataStorage,
239502
240098
  namespace,
@@ -239559,7 +240155,7 @@ async function runScaffoldFlow({
239559
240155
  let availableScripts;
239560
240156
  if (!dryRun) {
239561
240157
  try {
239562
- const parsedPackageJson = JSON.parse(fs49.readFileSync(path65.join(projectDir, "package.json"), "utf8"));
240158
+ const parsedPackageJson = JSON.parse(fs53.readFileSync(path69.join(projectDir, "package.json"), "utf8"));
239563
240159
  const scripts = parsedPackageJson.scripts && typeof parsedPackageJson.scripts === "object" && !Array.isArray(parsedPackageJson.scripts) ? parsedPackageJson.scripts : {};
239564
240160
  availableScripts = Object.entries(scripts).filter(([, value2]) => typeof value2 === "string").map(([scriptName]) => scriptName);
239565
240161
  } catch {
@@ -292682,6 +293278,63 @@ var ADD_KIND_IDS = [
292682
293278
  "editor-plugin"
292683
293279
  ];
292684
293280
 
293281
+ // src/cli-string-flags.ts
293282
+ init_cli_diagnostics();
293283
+ function readOptionalCliStringFlagValue(flags2, name2, mode) {
293284
+ const value2 = flags2[name2];
293285
+ if (value2 === undefined || value2 === null) {
293286
+ return;
293287
+ }
293288
+ if (typeof value2 !== "string") {
293289
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name2}\` requires a value.`);
293290
+ }
293291
+ const trimmed = value2.trim();
293292
+ if (trimmed.length === 0) {
293293
+ if (mode === "strict") {
293294
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name2}\` requires a value.`);
293295
+ }
293296
+ return;
293297
+ }
293298
+ return mode === "strict" ? value2 : trimmed;
293299
+ }
293300
+ function readOptionalLooseStringFlag(flags2, name2) {
293301
+ return readOptionalCliStringFlagValue(flags2, name2, "loose");
293302
+ }
293303
+ function readOptionalStrictStringFlag(flags2, name2) {
293304
+ return readOptionalCliStringFlagValue(flags2, name2, "strict");
293305
+ }
293306
+ function requireStrictStringFlag(flags2, name2, message) {
293307
+ const value2 = readOptionalStrictStringFlag(flags2, name2);
293308
+ if (!value2) {
293309
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
293310
+ }
293311
+ return value2;
293312
+ }
293313
+ function readOptionalPairedStrictStringFlags(flags2, leftName, rightName, message) {
293314
+ const leftValue = readOptionalStrictStringFlag(flags2, leftName);
293315
+ const rightValue = readOptionalStrictStringFlag(flags2, rightName);
293316
+ if (Boolean(leftValue) !== Boolean(rightValue)) {
293317
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
293318
+ }
293319
+ return [leftValue, rightValue];
293320
+ }
293321
+
293322
+ // src/external-layer-prompt-options.ts
293323
+ function formatExternalLayerSelectHint(option3) {
293324
+ const details = [
293325
+ option3.description,
293326
+ option3.extends.length > 0 ? `extends ${option3.extends.join(", ")}` : undefined
293327
+ ].filter((value2) => typeof value2 === "string" && value2.length > 0);
293328
+ return details.length > 0 ? details.join(" \xB7 ") : undefined;
293329
+ }
293330
+ function toExternalLayerPromptOptions(options) {
293331
+ return options.map((option3) => ({
293332
+ hint: formatExternalLayerSelectHint(option3),
293333
+ label: option3.id,
293334
+ value: option3.id
293335
+ }));
293336
+ }
293337
+
292685
293338
  // src/add-kind-registry.ts
292686
293339
  var BLOCK_VISIBLE_FIELD_ORDER = [
292687
293340
  "kind",
@@ -292740,51 +293393,12 @@ var NAME_NAMESPACE_VISIBLE_FIELDS = [
292740
293393
  "name",
292741
293394
  "namespace"
292742
293395
  ];
292743
- function readOptionalStringFlag(flags2, name2) {
292744
- const value2 = flags2[name2];
292745
- if (value2 === undefined || value2 === null) {
292746
- return;
292747
- }
292748
- if (typeof value2 !== "string" || value2.trim().length === 0) {
292749
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name2}\` requires a value.`);
292750
- }
292751
- return value2;
292752
- }
292753
- function requireStringFlag(flags2, name2, message) {
292754
- const value2 = readOptionalStringFlag(flags2, name2);
292755
- if (!value2) {
292756
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
292757
- }
292758
- return value2;
292759
- }
292760
- function readOptionalPairedStringFlags(flags2, leftName, rightName, message) {
292761
- const leftValue = readOptionalStringFlag(flags2, leftName);
292762
- const rightValue = readOptionalStringFlag(flags2, rightName);
292763
- if (Boolean(leftValue) !== Boolean(rightValue)) {
292764
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
292765
- }
292766
- return [leftValue, rightValue];
292767
- }
292768
293396
  function requireAddKindName(context, message) {
292769
293397
  if (!context.name) {
292770
293398
  throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
292771
293399
  }
292772
293400
  return context.name;
292773
293401
  }
292774
- function formatExternalLayerSelectHint(option3) {
292775
- const details = [
292776
- option3.description,
292777
- option3.extends.length > 0 ? `extends ${option3.extends.join(", ")}` : undefined
292778
- ].filter((value2) => typeof value2 === "string" && value2.length > 0);
292779
- return details.length > 0 ? details.join(" \xB7 ") : undefined;
292780
- }
292781
- function toExternalLayerPromptOptions(options) {
292782
- return options.map((option3) => ({
292783
- hint: formatExternalLayerSelectHint(option3),
292784
- label: option3.id,
292785
- value: option3.id
292786
- }));
292787
- }
292788
293402
  function defineAddKindRegistryEntry(entry) {
292789
293403
  return entry;
292790
293404
  }
@@ -292818,7 +293432,7 @@ var ADD_KIND_REGISTRY = {
292818
293432
  nameLabel: "Admin view name",
292819
293433
  async prepareExecution(context) {
292820
293434
  const name2 = requireAddKindName(context, "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>].");
292821
- const source = readOptionalStringFlag(context.flags, "source");
293435
+ const source = readOptionalStrictStringFlag(context.flags, "source");
292822
293436
  return createNamedExecutionPlan(context, {
292823
293437
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddAdminViewCommand({
292824
293438
  adminViewName: name3,
@@ -292858,7 +293472,7 @@ var ADD_KIND_REGISTRY = {
292858
293472
  nameLabel: "Binding source name",
292859
293473
  async prepareExecution(context) {
292860
293474
  const name2 = requireAddKindName(context, "`wp-typia add binding-source` requires <name>. Usage: wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>].");
292861
- const [blockName, attributeName] = readOptionalPairedStringFlags(context.flags, "block", "attribute", "`wp-typia add binding-source` requires --block and --attribute to be provided together.");
293475
+ const [blockName, attributeName] = readOptionalPairedStrictStringFlags(context.flags, "block", "attribute", "`wp-typia add binding-source` requires --block and --attribute to be provided together.");
292862
293476
  return createNamedExecutionPlan(context, {
292863
293477
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddBindingSourceCommand({
292864
293478
  attributeName,
@@ -292898,15 +293512,15 @@ var ADD_KIND_REGISTRY = {
292898
293512
  nameLabel: "Block name",
292899
293513
  async prepareExecution(context) {
292900
293514
  const name2 = requireAddKindName(context, "`wp-typia add block` requires <name>. Usage: wp-typia add block <name> [--template <basic|interactivity|persistence|compound>]");
292901
- const externalLayerId = readOptionalStringFlag(context.flags, "external-layer-id");
292902
- const externalLayerSource = readOptionalStringFlag(context.flags, "external-layer-source");
293515
+ const externalLayerId = readOptionalStrictStringFlag(context.flags, "external-layer-id");
293516
+ const externalLayerSource = readOptionalStrictStringFlag(context.flags, "external-layer-source");
292903
293517
  const shouldPromptForLayerSelection = Boolean(externalLayerSource) && !Boolean(externalLayerId) && context.isInteractiveSession;
292904
293518
  const selectPrompt = shouldPromptForLayerSelection ? await context.getOrCreatePrompt() : undefined;
292905
- const alternateRenderTargets = readOptionalStringFlag(context.flags, "alternate-render-targets");
292906
- const dataStorageMode = readOptionalStringFlag(context.flags, "data-storage");
292907
- const innerBlocksPreset = readOptionalStringFlag(context.flags, "inner-blocks-preset");
292908
- const persistencePolicy = readOptionalStringFlag(context.flags, "persistence-policy");
292909
- let resolvedTemplateId = readOptionalStringFlag(context.flags, "template");
293519
+ const alternateRenderTargets = readOptionalStrictStringFlag(context.flags, "alternate-render-targets");
293520
+ const dataStorageMode = readOptionalStrictStringFlag(context.flags, "data-storage");
293521
+ const innerBlocksPreset = readOptionalStrictStringFlag(context.flags, "inner-blocks-preset");
293522
+ const persistencePolicy = readOptionalStrictStringFlag(context.flags, "persistence-policy");
293523
+ let resolvedTemplateId = readOptionalStrictStringFlag(context.flags, "template");
292910
293524
  if (!resolvedTemplateId && context.isInteractiveSession) {
292911
293525
  const templatePrompt = await context.getOrCreatePrompt();
292912
293526
  resolvedTemplateId = await templatePrompt.select("Select a block template", context.addRuntime.ADD_BLOCK_TEMPLATE_IDS.map((templateId) => ({
@@ -293003,7 +293617,7 @@ var ADD_KIND_REGISTRY = {
293003
293617
  nameLabel: "Editor plugin name",
293004
293618
  async prepareExecution(context) {
293005
293619
  const name2 = requireAddKindName(context, "`wp-typia add editor-plugin` requires <name>. Usage: wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>].");
293006
- const slot = readOptionalStringFlag(context.flags, "slot");
293620
+ const slot = readOptionalStrictStringFlag(context.flags, "slot");
293007
293621
  return createNamedExecutionPlan(context, {
293008
293622
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddEditorPluginCommand({
293009
293623
  cwd,
@@ -293041,8 +293655,8 @@ var ADD_KIND_REGISTRY = {
293041
293655
  nameLabel: "Target block",
293042
293656
  async prepareExecution(context) {
293043
293657
  const name2 = requireAddKindName(context, "`wp-typia add hooked-block` requires <block-slug>. Usage: wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <before|after|firstChild|lastChild>.");
293044
- const anchorBlockName = requireStringFlag(context.flags, "anchor", "`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
293045
- const position = requireStringFlag(context.flags, "position", "`wp-typia add hooked-block` requires --position <before|after|firstChild|lastChild>.");
293658
+ const anchorBlockName = requireStrictStringFlag(context.flags, "anchor", "`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
293659
+ const position = requireStrictStringFlag(context.flags, "position", "`wp-typia add hooked-block` requires --position <before|after|firstChild|lastChild>.");
293046
293660
  return createNamedExecutionPlan(context, {
293047
293661
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddHookedBlockCommand({
293048
293662
  anchorBlockName,
@@ -293112,7 +293726,7 @@ var ADD_KIND_REGISTRY = {
293112
293726
  nameLabel: "Style name",
293113
293727
  async prepareExecution(context) {
293114
293728
  const name2 = requireAddKindName(context, "`wp-typia add style` requires <name>. Usage: wp-typia add style <name> --block <block-slug>.");
293115
- const blockSlug = requireStringFlag(context.flags, "block", "`wp-typia add style` requires --block <block-slug>.");
293729
+ const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add style` requires --block <block-slug>.");
293116
293730
  return createNamedExecutionPlan(context, {
293117
293731
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddBlockStyleCommand({
293118
293732
  blockName: blockSlug,
@@ -293150,8 +293764,8 @@ var ADD_KIND_REGISTRY = {
293150
293764
  nameLabel: "Transform name",
293151
293765
  async prepareExecution(context) {
293152
293766
  const name2 = requireAddKindName(context, "`wp-typia add transform` requires <name>. Usage: wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug>.");
293153
- const fromBlockName = requireStringFlag(context.flags, "from", "`wp-typia add transform` requires --from <namespace/block>.");
293154
- const toBlockName = requireStringFlag(context.flags, "to", "`wp-typia add transform` requires --to <block-slug|namespace/block-slug>.");
293767
+ const fromBlockName = requireStrictStringFlag(context.flags, "from", "`wp-typia add transform` requires --from <namespace/block>.");
293768
+ const toBlockName = requireStrictStringFlag(context.flags, "to", "`wp-typia add transform` requires --to <block-slug|namespace/block-slug>.");
293155
293769
  return createNamedExecutionPlan(context, {
293156
293770
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddBlockTransformCommand({
293157
293771
  cwd,
@@ -293192,8 +293806,8 @@ var ADD_KIND_REGISTRY = {
293192
293806
  nameLabel: "REST resource name",
293193
293807
  async prepareExecution(context) {
293194
293808
  const name2 = requireAddKindName(context, "`wp-typia add rest-resource` requires <name>. Usage: wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create>].");
293195
- const methods = readOptionalStringFlag(context.flags, "methods");
293196
- const namespace = readOptionalStringFlag(context.flags, "namespace");
293809
+ const methods = readOptionalStrictStringFlag(context.flags, "methods");
293810
+ const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
293197
293811
  return createNamedExecutionPlan(context, {
293198
293812
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddRestResourceCommand({
293199
293813
  cwd,
@@ -293232,7 +293846,7 @@ var ADD_KIND_REGISTRY = {
293232
293846
  nameLabel: "AI feature name",
293233
293847
  async prepareExecution(context) {
293234
293848
  const name2 = requireAddKindName(context, "`wp-typia add ai-feature` requires <name>. Usage: wp-typia add ai-feature <name> [--namespace <vendor/v1>].");
293235
- const namespace = readOptionalStringFlag(context.flags, "namespace");
293849
+ const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
293236
293850
  return createNamedExecutionPlan(context, {
293237
293851
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddAiFeatureCommand({
293238
293852
  aiFeatureName: name3,
@@ -293271,7 +293885,7 @@ var ADD_KIND_REGISTRY = {
293271
293885
  nameLabel: "Variation name",
293272
293886
  async prepareExecution(context) {
293273
293887
  const name2 = requireAddKindName(context, "`wp-typia add variation` requires <name>. Usage: wp-typia add variation <name> --block <block-slug>");
293274
- const blockSlug = requireStringFlag(context.flags, "block", "`wp-typia add variation` requires --block <block-slug>.");
293888
+ const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add variation` requires --block <block-slug>.");
293275
293889
  return createNamedExecutionPlan(context, {
293276
293890
  execute: ({ cwd, name: name3 }) => context.addRuntime.runAddVariationCommand({
293277
293891
  blockName: blockSlug,
@@ -293449,7 +294063,7 @@ import path10 from "path";
293449
294063
  // package.json
293450
294064
  var package_default2 = {
293451
294065
  name: "wp-typia",
293452
- version: "0.22.1",
294066
+ version: "0.22.3",
293453
294067
  description: "Canonical CLI package for wp-typia scaffolding and project workflows",
293454
294068
  packageManager: "bun@1.3.11",
293455
294069
  type: "module",
@@ -293519,7 +294133,7 @@ var package_default2 = {
293519
294133
  "@bunli/tui": "0.6.0",
293520
294134
  "@bunli/utils": "0.6.0",
293521
294135
  "@wp-typia/api-client": "^0.4.5",
293522
- "@wp-typia/project-tools": "0.22.1",
294136
+ "@wp-typia/project-tools": "0.22.3",
293523
294137
  "better-result": "^2.7.0",
293524
294138
  react: "^19.2.5",
293525
294139
  "react-dom": "^19.2.5",
@@ -293874,20 +294488,6 @@ function printBlock(lines, printLine) {
293874
294488
  printLine(line);
293875
294489
  }
293876
294490
  }
293877
- function formatExternalLayerSelectHint2(option3) {
293878
- const details = [
293879
- option3.description,
293880
- option3.extends.length > 0 ? `extends ${option3.extends.join(", ")}` : undefined
293881
- ].filter((value2) => typeof value2 === "string" && value2.length > 0);
293882
- return details.length > 0 ? details.join(" \xB7 ") : undefined;
293883
- }
293884
- function toExternalLayerPromptOptions2(options) {
293885
- return options.map((option3) => ({
293886
- hint: formatExternalLayerSelectHint2(option3),
293887
- label: option3.id,
293888
- value: option3.id
293889
- }));
293890
- }
293891
294491
 
293892
294492
  // src/runtime-capabilities.ts
293893
294493
  function isInteractiveTerminal({
@@ -294171,17 +294771,6 @@ function shouldWrapCliCommandError(options) {
294171
294771
  }
294172
294772
  return true;
294173
294773
  }
294174
- function readOptionalLooseStringFlag(flags2, name2) {
294175
- const value2 = flags2[name2];
294176
- if (value2 === undefined || value2 === null) {
294177
- return;
294178
- }
294179
- if (typeof value2 !== "string") {
294180
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name2}\` requires a value.`);
294181
- }
294182
- const trimmed = value2.trim();
294183
- return trimmed.length > 0 ? trimmed : undefined;
294184
- }
294185
294774
  function pushFlag(argv, name2, value2) {
294186
294775
  if (value2 === undefined || value2 === null || value2 === false) {
294187
294776
  return;
@@ -294323,7 +294912,7 @@ async function executeCreateCommand({
294323
294912
  promptText: activePrompt ? (message, defaultValue, validate) => activePrompt.text(message, defaultValue, validate) : undefined,
294324
294913
  queryPostType: readOptionalLooseStringFlag(flags2, "query-post-type"),
294325
294914
  selectDataStorage: activePrompt ? () => activePrompt.select("Select a data storage mode", [...DATA_STORAGE_PROMPT_OPTIONS], 1) : undefined,
294326
- selectExternalLayerId: shouldPromptForExternalLayerSelection && activePrompt ? (options) => activePrompt.select("Select an external layer", toExternalLayerPromptOptions2(options), 1) : undefined,
294915
+ selectExternalLayerId: shouldPromptForExternalLayerSelection && activePrompt ? (options) => activePrompt.select("Select an external layer", toExternalLayerPromptOptions(options), 1) : undefined,
294327
294916
  selectPackageManager: activePrompt ? () => activePrompt.select("Select a package manager", [...PACKAGE_MANAGER_PROMPT_OPTIONS], 1) : undefined,
294328
294917
  selectPersistencePolicy: activePrompt ? () => activePrompt.select("Select a persistence policy", [...PERSISTENCE_POLICY_PROMPT_OPTIONS], 1) : undefined,
294329
294918
  selectTemplate: activePrompt ? () => activePrompt.select("Select a template", getTemplateSelectOptions2(), 1) : undefined,
@@ -295183,8 +295772,8 @@ var init_default = initCommand;
295183
295772
  init_cli_diagnostics();
295184
295773
 
295185
295774
  // src/mcp.ts
295186
- import fs50 from "fs/promises";
295187
- import path66 from "path";
295775
+ import fs54 from "fs/promises";
295776
+ import path70 from "path";
295188
295777
 
295189
295778
  // ../../node_modules/.bun/@bunli+plugin-mcp@0.2.5+ef72ce197b058209/node_modules/@bunli/plugin-mcp/src/errors.ts
295190
295779
  class SchemaConversionError extends TaggedError("SchemaConversionError")() {
@@ -295712,8 +296301,8 @@ function isToolGroup(value2) {
295712
296301
  return isObject3(value2) && typeof value2.namespace === "string" && Array.isArray(value2.tools) && value2.tools.every(isTool);
295713
296302
  }
295714
296303
  async function readSchemaSource(cwd, source) {
295715
- const schemaPath = path66.resolve(cwd, source.path);
295716
- const raw = await fs50.readFile(schemaPath, "utf8");
296304
+ const schemaPath = path70.resolve(cwd, source.path);
296305
+ const raw = await fs54.readFile(schemaPath, "utf8");
295717
296306
  const parsed = JSON.parse(raw);
295718
296307
  if (isToolGroup(parsed)) {
295719
296308
  return parsed;
@@ -295729,7 +296318,7 @@ async function readSchemaSource(cwd, source) {
295729
296318
  async function loadMcpToolGroups(cwd, schemaSources) {
295730
296319
  return Promise.all(schemaSources.map((source) => readSchemaSource(cwd, source)));
295731
296320
  }
295732
- async function syncMcpSchemas(cwd, schemaSources, outputDir = path66.join(cwd, ".bunli", "mcp")) {
296321
+ async function syncMcpSchemas(cwd, schemaSources, outputDir = path70.join(cwd, ".bunli", "mcp")) {
295733
296322
  const groups = await loadMcpToolGroups(cwd, schemaSources);
295734
296323
  const result = await generateMCPTypes({
295735
296324
  outputDir,
@@ -295751,8 +296340,8 @@ async function syncMcpSchemas(cwd, schemaSources, outputDir = path66.join(cwd, "
295751
296340
  throw convert.error;
295752
296341
  }
295753
296342
  }
295754
- await fs50.mkdir(outputDir, { recursive: true });
295755
- await fs50.writeFile(path66.join(outputDir, "registry.json"), `${JSON.stringify(registry2, null, 2)}
296343
+ await fs54.mkdir(outputDir, { recursive: true });
296344
+ await fs54.writeFile(path70.join(outputDir, "registry.json"), `${JSON.stringify(registry2, null, 2)}
295756
296345
  `, "utf8");
295757
296346
  return {
295758
296347
  commandCount: registry2.reduce((count, group) => count + group.tools.length, 0),
@@ -296071,4 +296660,4 @@ export {
296071
296660
  cli
296072
296661
  };
296073
296662
 
296074
- //# debugId=7FC90D52A694344264756E2164756E21
296663
+ //# debugId=EB85DB51484D012864756E2164756E21