@wp-typia/project-tools 0.22.2 → 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.
Files changed (30) hide show
  1. package/dist/runtime/built-in-block-code-templates/interactivity.d.ts +1 -1
  2. package/dist/runtime/built-in-block-code-templates/interactivity.js +4 -2
  3. package/dist/runtime/cli-add-shared.d.ts +49 -0
  4. package/dist/runtime/cli-add-shared.js +204 -71
  5. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +5 -0
  6. package/dist/runtime/cli-add-workspace-ability-scaffold.js +392 -0
  7. package/dist/runtime/cli-add-workspace-ability-templates.d.ts +34 -0
  8. package/dist/runtime/cli-add-workspace-ability-templates.js +500 -0
  9. package/dist/runtime/cli-add-workspace-ability-types.d.ts +27 -0
  10. package/dist/runtime/cli-add-workspace-ability-types.js +14 -0
  11. package/dist/runtime/cli-add-workspace-ability.js +12 -852
  12. package/dist/runtime/cli-add-workspace-ai-scaffold.d.ts +21 -0
  13. package/dist/runtime/cli-add-workspace-ai-scaffold.js +91 -0
  14. package/dist/runtime/cli-add-workspace-ai-templates.d.ts +4 -0
  15. package/dist/runtime/cli-add-workspace-ai-templates.js +605 -0
  16. package/dist/runtime/cli-add-workspace-ai.js +15 -688
  17. package/dist/runtime/cli-add-workspace-assets.js +7 -4
  18. package/dist/runtime/cli-add-workspace.js +1 -19
  19. package/dist/runtime/cli-doctor-workspace-bindings.d.ts +11 -0
  20. package/dist/runtime/cli-doctor-workspace-bindings.js +134 -0
  21. package/dist/runtime/cli-doctor-workspace-blocks.d.ts +11 -0
  22. package/dist/runtime/cli-doctor-workspace-blocks.js +504 -0
  23. package/dist/runtime/cli-doctor-workspace-features.d.ts +11 -0
  24. package/dist/runtime/cli-doctor-workspace-features.js +383 -0
  25. package/dist/runtime/cli-doctor-workspace-package.d.ts +18 -0
  26. package/dist/runtime/cli-doctor-workspace-package.js +59 -0
  27. package/dist/runtime/cli-doctor-workspace-shared.d.ts +69 -0
  28. package/dist/runtime/cli-doctor-workspace-shared.js +87 -0
  29. package/dist/runtime/cli-doctor-workspace.js +25 -1062
  30. package/package.json +3 -3
@@ -0,0 +1,500 @@
1
+ import { renderScaffoldCompatibilityConfig } from "./scaffold-compatibility.js";
2
+ import { quoteTsString } from "./cli-add-shared.js";
3
+ import { ABILITY_REGISTRY_END_MARKER, ABILITY_REGISTRY_START_MARKER, } from "./cli-add-workspace-ability-types.js";
4
+ import { quotePhpString } from "./php-utils.js";
5
+ import { toPascalCase, toTitleCase } from "./string-case.js";
6
+ function toAbilityCategorySlug(workspaceNamespace) {
7
+ const normalizedNamespace = workspaceNamespace
8
+ .replace(/[^a-z0-9-]+/gu, "-")
9
+ .replace(/-{2,}/gu, "-")
10
+ .replace(/^-|-$/gu, "");
11
+ return `${normalizedNamespace || "workspace"}-workflows`;
12
+ }
13
+ /**
14
+ * Build the `ABILITIES` inventory entry for a generated workflow ability.
15
+ */
16
+ export function buildAbilityConfigEntry(abilitySlug, compatibilityPolicy) {
17
+ const pascalCase = toPascalCase(abilitySlug);
18
+ return [
19
+ "\t{",
20
+ `\t\tclientFile: ${quoteTsString(`src/abilities/${abilitySlug}/client.ts`)},`,
21
+ `\t\tcompatibility: ${renderScaffoldCompatibilityConfig(compatibilityPolicy)},`,
22
+ `\t\tconfigFile: ${quoteTsString(`src/abilities/${abilitySlug}/ability.config.json`)},`,
23
+ `\t\tdataFile: ${quoteTsString(`src/abilities/${abilitySlug}/data.ts`)},`,
24
+ `\t\tinputSchemaFile: ${quoteTsString(`src/abilities/${abilitySlug}/input.schema.json`)},`,
25
+ `\t\tinputTypeName: ${quoteTsString(`${pascalCase}AbilityInput`)},`,
26
+ `\t\toutputSchemaFile: ${quoteTsString(`src/abilities/${abilitySlug}/output.schema.json`)},`,
27
+ `\t\toutputTypeName: ${quoteTsString(`${pascalCase}AbilityOutput`)},`,
28
+ `\t\tphpFile: ${quoteTsString(`inc/abilities/${abilitySlug}.php`)},`,
29
+ `\t\tslug: ${quoteTsString(abilitySlug)},`,
30
+ `\t\ttypesFile: ${quoteTsString(`src/abilities/${abilitySlug}/types.ts`)},`,
31
+ "\t},",
32
+ ].join("\n");
33
+ }
34
+ /**
35
+ * Build the JSON config document that powers server-side ability registration.
36
+ */
37
+ export function buildAbilityConfigSource(abilitySlug, workspaceNamespace) {
38
+ const abilityTitle = toTitleCase(abilitySlug);
39
+ return `${JSON.stringify({
40
+ abilityId: `${workspaceNamespace}/${abilitySlug}`,
41
+ category: {
42
+ description: `Typed editor and admin workflows exposed by the ${workspaceNamespace} workspace.`,
43
+ label: `${toTitleCase(workspaceNamespace)} Workflows`,
44
+ slug: toAbilityCategorySlug(workspaceNamespace),
45
+ },
46
+ description: `Runs the ${abilityTitle} workflow using a typed server callback.`,
47
+ label: abilityTitle,
48
+ meta: {
49
+ annotations: {
50
+ destructive: false,
51
+ idempotent: true,
52
+ readonly: false,
53
+ },
54
+ mcp: {
55
+ public: false,
56
+ },
57
+ showInRest: true,
58
+ },
59
+ }, null, 2)}\n`;
60
+ }
61
+ /**
62
+ * Build the starter TypeScript input and output contracts for an ability.
63
+ */
64
+ export function buildAbilityTypesSource(abilitySlug) {
65
+ const pascalCase = toPascalCase(abilitySlug);
66
+ return `export interface ${pascalCase}AbilityInput {
67
+ \tcontextId: number;
68
+ \tnote?: string;
69
+ }
70
+
71
+ export interface ${pascalCase}AbilityOutput {
72
+ \tprocessedContextId: number;
73
+ \treceivedNote?: string;
74
+ \tstatus: 'ready';
75
+ \tsummary: string;
76
+ }
77
+ `;
78
+ }
79
+ /**
80
+ * Build the typed client helper module that wraps the WordPress Abilities API.
81
+ */
82
+ export function buildAbilityDataSource(abilitySlug) {
83
+ const pascalCase = toPascalCase(abilitySlug);
84
+ const abilityConstBase = abilitySlug
85
+ .toUpperCase()
86
+ .replace(/[^A-Z0-9]+/gu, "_")
87
+ .replace(/_{2,}/gu, "_")
88
+ .replace(/^_|_$/gu, "");
89
+ return `import {
90
+ \texecuteAbility,
91
+ \tgetAbilities,
92
+ \tgetAbility as getRegisteredAbility,
93
+ } from '@wordpress/abilities';
94
+ import '@wordpress/core-abilities';
95
+
96
+ import abilityConfig from './ability.config.json';
97
+
98
+ import type { ${pascalCase}AbilityInput, ${pascalCase}AbilityOutput } from './types';
99
+
100
+ interface WordPressAbilityDefinition {
101
+ \tcategory?: string;
102
+ \tdescription?: string;
103
+ \tlabel?: string;
104
+ \tmeta?: Record<string, unknown>;
105
+ \tname?: string;
106
+ }
107
+
108
+ export const ${abilityConstBase}_ABILITY = abilityConfig;
109
+ export const ${abilityConstBase}_ABILITY_CATEGORY = abilityConfig.category;
110
+ export const ${abilityConstBase}_ABILITY_ID = abilityConfig.abilityId;
111
+ export const ${abilityConstBase}_ABILITY_META = abilityConfig.meta;
112
+ const ABILITY_DISCOVERY_POLL_INTERVAL_MS = 50;
113
+ const ABILITY_DISCOVERY_TIMEOUT_MS = 5000;
114
+
115
+ export type {
116
+ \t${pascalCase}AbilityInput,
117
+ \t${pascalCase}AbilityOutput,
118
+ };
119
+
120
+ function sleep( milliseconds: number ): Promise< void > {
121
+ \treturn new Promise( ( resolve ) => {
122
+ \t\tsetTimeout( resolve, milliseconds );
123
+ \t} );
124
+ }
125
+
126
+ async function waitFor${pascalCase}AbilityRegistration(): Promise< void > {
127
+ \tconst deadline = Date.now() + ABILITY_DISCOVERY_TIMEOUT_MS;
128
+ \twhile ( ! getRegisteredAbility( ${abilityConstBase}_ABILITY_ID ) ) {
129
+ \t\tif ( Date.now() >= deadline ) {
130
+ \t\t\treturn;
131
+ \t\t}
132
+
133
+ \t\tawait sleep( ABILITY_DISCOVERY_POLL_INTERVAL_MS );
134
+ \t}
135
+ }
136
+
137
+ export async function list${pascalCase}CategoryAbilities(): Promise< WordPressAbilityDefinition[] > {
138
+ \tawait waitFor${pascalCase}AbilityRegistration();
139
+
140
+ \treturn getAbilities( {
141
+ \t\tcategory: ${abilityConstBase}_ABILITY_CATEGORY.slug,
142
+ \t} ) as WordPressAbilityDefinition[];
143
+ }
144
+
145
+ export async function get${pascalCase}Ability(): Promise<
146
+ \t| WordPressAbilityDefinition
147
+ \t| undefined
148
+ > {
149
+ \tawait waitFor${pascalCase}AbilityRegistration();
150
+
151
+ \treturn getRegisteredAbility( ${abilityConstBase}_ABILITY_ID ) as
152
+ \t\t| WordPressAbilityDefinition
153
+ \t\t| undefined;
154
+ }
155
+
156
+ export async function require${pascalCase}Ability(): Promise< WordPressAbilityDefinition > {
157
+ \tconst ability = await get${pascalCase}Ability();
158
+ \tif ( ability ) {
159
+ \t\treturn ability;
160
+ \t}
161
+
162
+ \tthrow new Error(
163
+ \t\t[
164
+ \t\t\t\`Ability "\${ ${abilityConstBase}_ABILITY_ID }" is not available yet.\`,
165
+ \t\t\t'Load the WordPress core abilities integration on this screen and confirm the server-side registration succeeded.',
166
+ \t\t].join( ' ' )
167
+ \t);
168
+ }
169
+
170
+ export async function run${pascalCase}Ability(
171
+ \tinput: ${pascalCase}AbilityInput
172
+ ): Promise< ${pascalCase}AbilityOutput > {
173
+ \tawait waitFor${pascalCase}AbilityRegistration();
174
+
175
+ \treturn ( await executeAbility(
176
+ \t\t${abilityConstBase}_ABILITY_ID,
177
+ \t\tinput
178
+ \t) ) as ${pascalCase}AbilityOutput;
179
+ }
180
+ `;
181
+ }
182
+ /**
183
+ * Build the re-export shim for the generated ability client helpers.
184
+ */
185
+ export function buildAbilityClientSource(abilitySlug) {
186
+ const pascalCase = toPascalCase(abilitySlug);
187
+ return `/**
188
+ * Re-export the typed ${pascalCase} ability client helpers.
189
+ *
190
+ * The helper methods load the WordPress core abilities integration and wait for
191
+ * this server-registered ability before reading or executing it.
192
+ */
193
+ export * from './data';
194
+ `;
195
+ }
196
+ /**
197
+ * Build the schema sync script that keeps generated ability JSON artifacts current.
198
+ */
199
+ export function buildAbilitySyncScriptSource() {
200
+ return `/* eslint-disable no-console */
201
+ import { syncTypeSchemas } from '@wp-typia/block-runtime/metadata-core';
202
+
203
+ import {
204
+ \tABILITIES,
205
+ \ttype WorkspaceAbilityConfig,
206
+ } from './block-config';
207
+
208
+ function parseCliOptions( argv: string[] ) {
209
+ \tconst options = {
210
+ \t\tcheck: false,
211
+ \t};
212
+
213
+ \tfor ( const argument of argv ) {
214
+ \t\tif ( argument === '--check' ) {
215
+ \t\t\toptions.check = true;
216
+ \t\t\tcontinue;
217
+ \t\t}
218
+
219
+ \t\tthrow new Error( \`Unknown sync-abilities flag: \${ argument }\` );
220
+ \t}
221
+
222
+ \treturn options;
223
+ }
224
+
225
+ function isWorkspaceAbility(
226
+ \tability: WorkspaceAbilityConfig
227
+ ): ability is WorkspaceAbilityConfig & {
228
+ \tclientFile: string;
229
+ \tconfigFile: string;
230
+ \tdataFile: string;
231
+ \tinputSchemaFile: string;
232
+ \tinputTypeName: string;
233
+ \toutputSchemaFile: string;
234
+ \toutputTypeName: string;
235
+ \tphpFile: string;
236
+ \ttypesFile: string;
237
+ } {
238
+ \treturn (
239
+ \t\ttypeof ability.clientFile === 'string' &&
240
+ \t\ttypeof ability.configFile === 'string' &&
241
+ \t\ttypeof ability.dataFile === 'string' &&
242
+ \t\ttypeof ability.inputSchemaFile === 'string' &&
243
+ \t\ttypeof ability.inputTypeName === 'string' &&
244
+ \t\ttypeof ability.outputSchemaFile === 'string' &&
245
+ \t\ttypeof ability.outputTypeName === 'string' &&
246
+ \t\ttypeof ability.phpFile === 'string' &&
247
+ \t\ttypeof ability.typesFile === 'string'
248
+ \t);
249
+ }
250
+
251
+ async function main() {
252
+ \tconst options = parseCliOptions( process.argv.slice( 2 ) );
253
+ \tconst abilities = ABILITIES.filter( isWorkspaceAbility );
254
+
255
+ \tif ( ABILITIES.length > 0 && abilities.length === 0 ) {
256
+ \t\tconsole.warn(
257
+ \t\t\t'⚠️ Ability inventory entries exist, but none include the required typed schema files. Check scripts/block-config.ts before relying on sync-abilities.'
258
+ \t\t);
259
+ \t}
260
+
261
+ \tif ( abilities.length === 0 ) {
262
+ \t\tconsole.log(
263
+ \t\t\toptions.check
264
+ \t\t\t\t? 'ℹ️ No typed workflow abilities are registered yet. "sync-abilities --check" is already clean.'
265
+ \t\t\t\t: 'ℹ️ No typed workflow abilities are registered yet.'
266
+ \t\t);
267
+ \t\treturn;
268
+ \t}
269
+
270
+ \tfor ( const ability of abilities ) {
271
+ \t\tawait syncTypeSchemas(
272
+ \t\t\t{
273
+ \t\t\t\tjsonSchemaFile: ability.inputSchemaFile,
274
+ \t\t\t\tprojectRoot: process.cwd(),
275
+ \t\t\t\tsourceTypeName: ability.inputTypeName,
276
+ \t\t\t\ttypesFile: ability.typesFile,
277
+ \t\t\t},
278
+ \t\t\t{
279
+ \t\t\t\tcheck: options.check,
280
+ \t\t\t}
281
+ \t\t);
282
+
283
+ \t\tawait syncTypeSchemas(
284
+ \t\t\t{
285
+ \t\t\t\tjsonSchemaFile: ability.outputSchemaFile,
286
+ \t\t\t\tprojectRoot: process.cwd(),
287
+ \t\t\t\tsourceTypeName: ability.outputTypeName,
288
+ \t\t\t\ttypesFile: ability.typesFile,
289
+ \t\t\t},
290
+ \t\t\t{
291
+ \t\t\t\tcheck: options.check,
292
+ \t\t\t}
293
+ \t\t);
294
+ \t}
295
+
296
+ \tconsole.log(
297
+ \t\toptions.check
298
+ \t\t\t? '✅ Ability input and output schemas are already up to date for all registered workflow abilities!'
299
+ \t\t\t: '✅ Ability input and output schemas generated for all registered workflow abilities!'
300
+ \t);
301
+ }
302
+
303
+ main().catch( ( error ) => {
304
+ \tconsole.error( '❌ Ability schema sync failed:', error );
305
+ \tprocess.exit( 1 );
306
+ } );
307
+ `;
308
+ }
309
+ /**
310
+ * Build the PHP ability registration module for a generated workflow ability.
311
+ */
312
+ export function buildAbilityPhpSource(abilitySlug, workspace) {
313
+ const abilityTitle = toTitleCase(abilitySlug);
314
+ const abilityPhpId = abilitySlug.replace(/-/g, "_");
315
+ const categoryRegisterFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_register_ability_category`;
316
+ const abilityRegisterFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_register_ability`;
317
+ const configLoaderFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_load_ability_config`;
318
+ const schemaLoaderFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_load_ability_schema`;
319
+ const permissionFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_can_execute_ability`;
320
+ const executeFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_execute_ability`;
321
+ const metaFactoryFunctionName = `${workspace.workspace.phpPrefix}_${abilityPhpId}_build_ability_meta`;
322
+ return `<?php
323
+ if ( ! defined( 'ABSPATH' ) ) {
324
+ \treturn;
325
+ }
326
+
327
+ if ( ! function_exists( '${configLoaderFunctionName}' ) ) {
328
+ \tfunction ${configLoaderFunctionName}() {
329
+ \t\t$project_root = dirname( __DIR__, 2 );
330
+ \t\t$config_path = $project_root . '/src/abilities/${abilitySlug}/ability.config.json';
331
+ \t\tif ( ! file_exists( $config_path ) ) {
332
+ \t\t\treturn null;
333
+ \t\t}
334
+
335
+ \t\t$decoded = json_decode( file_get_contents( $config_path ), true );
336
+ \t\treturn is_array( $decoded ) ? $decoded : null;
337
+ \t}
338
+ }
339
+
340
+ if ( ! function_exists( '${schemaLoaderFunctionName}' ) ) {
341
+ \tfunction ${schemaLoaderFunctionName}( $schema_name ) {
342
+ \t\t$project_root = dirname( __DIR__, 2 );
343
+ \t\t$schema_path = $project_root . '/src/abilities/${abilitySlug}/' . $schema_name;
344
+ \t\tif ( ! file_exists( $schema_path ) ) {
345
+ \t\t\treturn null;
346
+ \t\t}
347
+
348
+ \t\t$decoded = json_decode( file_get_contents( $schema_path ), true );
349
+ \t\treturn is_array( $decoded ) ? $decoded : null;
350
+ \t}
351
+ }
352
+
353
+ if ( ! function_exists( '${metaFactoryFunctionName}' ) ) {
354
+ \tfunction ${metaFactoryFunctionName}( array $config ) {
355
+ \t\t$meta = array(
356
+ \t\t\t'annotations' => isset( $config['meta']['annotations'] ) && is_array( $config['meta']['annotations'] )
357
+ \t\t\t\t? $config['meta']['annotations']
358
+ \t\t\t\t: array(
359
+ \t\t\t\t\t'destructive' => false,
360
+ \t\t\t\t\t'idempotent' => true,
361
+ \t\t\t\t\t'readonly' => false,
362
+ \t\t\t\t),
363
+ \t\t\t'show_in_rest' => ! empty( $config['meta']['showInRest'] ),
364
+ \t\t);
365
+
366
+ \t\tif ( ! empty( $config['meta']['mcp']['public'] ) ) {
367
+ \t\t\t$meta['mcp'] = array(
368
+ \t\t\t\t'public' => true,
369
+ \t\t\t);
370
+ \t\t}
371
+
372
+ \t\treturn $meta;
373
+ \t}
374
+ }
375
+
376
+ if ( ! function_exists( '${permissionFunctionName}' ) ) {
377
+ \tfunction ${permissionFunctionName}( $input = array() ) {
378
+ \t\tunset( $input );
379
+
380
+ \t\treturn current_user_can( 'edit_posts' );
381
+ \t}
382
+ }
383
+
384
+ if ( ! function_exists( '${executeFunctionName}' ) ) {
385
+ \tfunction ${executeFunctionName}( $input = array() ) {
386
+ \t\t$payload = is_array( $input ) ? $input : array();
387
+ \t\t$context_id = isset( $payload['contextId'] ) ? (int) $payload['contextId'] : 0;
388
+ \t\t$note = isset( $payload['note'] ) && is_string( $payload['note'] )
389
+ \t\t\t? trim( $payload['note'] )
390
+ \t\t\t: '';
391
+ \t\t$result = array(
392
+ \t\t\t'processedContextId' => $context_id,
393
+ \t\t\t'status' => 'ready',
394
+ \t\t\t'summary' => sprintf(
395
+ \t\t\t\t/* translators: 1: workflow title, 2: context id */
396
+ \t\t\t\t__( '%1$s processed context %2$d.', ${quotePhpString(workspace.workspace.textDomain)} ),
397
+ \t\t\t\t${quotePhpString(abilityTitle)},
398
+ \t\t\t\t$context_id
399
+ \t\t\t),
400
+ \t\t);
401
+
402
+ \t\tif ( '' !== $note ) {
403
+ \t\t\t$result['receivedNote'] = $note;
404
+ \t\t}
405
+
406
+ \t\treturn $result;
407
+ \t}
408
+ }
409
+
410
+ if ( ! function_exists( '${categoryRegisterFunctionName}' ) ) {
411
+ \tfunction ${categoryRegisterFunctionName}() {
412
+ \t\tif ( ! function_exists( 'wp_register_ability_category' ) ) {
413
+ \t\t\treturn;
414
+ \t\t}
415
+
416
+ \t\t$config = ${configLoaderFunctionName}();
417
+ \t\tif (
418
+ \t\t\t! is_array( $config ) ||
419
+ \t\t\tempty( $config['category']['slug'] ) ||
420
+ \t\t\tempty( $config['category']['label'] )
421
+ \t\t) {
422
+ \t\t\treturn;
423
+ \t\t}
424
+
425
+ \t\twp_register_ability_category(
426
+ \t\t\t(string) $config['category']['slug'],
427
+ \t\t\tarray(
428
+ \t\t\t\t'description' => isset( $config['category']['description'] ) && is_string( $config['category']['description'] )
429
+ \t\t\t\t\t? $config['category']['description']
430
+ \t\t\t\t\t: '',
431
+ \t\t\t\t'label' => (string) $config['category']['label'],
432
+ \t\t\t)
433
+ \t\t);
434
+ \t}
435
+ }
436
+
437
+ if ( ! function_exists( '${abilityRegisterFunctionName}' ) ) {
438
+ \tfunction ${abilityRegisterFunctionName}() {
439
+ \t\tif ( ! function_exists( 'wp_register_ability' ) ) {
440
+ \t\t\treturn;
441
+ \t\t}
442
+
443
+ \t\t$config = ${configLoaderFunctionName}();
444
+ \t\tif (
445
+ \t\t\t! is_array( $config ) ||
446
+ \t\t\tempty( $config['abilityId'] ) ||
447
+ \t\t\tempty( $config['category']['slug'] ) ||
448
+ \t\t\tempty( $config['label'] ) ||
449
+ \t\t\tempty( $config['description'] )
450
+ \t\t) {
451
+ \t\t\treturn;
452
+ \t\t}
453
+
454
+ \t\t$input_schema = ${schemaLoaderFunctionName}( 'input.schema.json' );
455
+ \t\t$output_schema = ${schemaLoaderFunctionName}( 'output.schema.json' );
456
+ \t\tif ( ! is_array( $output_schema ) ) {
457
+ \t\t\treturn;
458
+ \t\t}
459
+
460
+ \t\t$args = array(
461
+ \t\t\t'category' => (string) $config['category']['slug'],
462
+ \t\t\t'description' => (string) $config['description'],
463
+ \t\t\t'execute_callback' => ${quotePhpString(executeFunctionName)},
464
+ \t\t\t'label' => (string) $config['label'],
465
+ \t\t\t'meta' => ${metaFactoryFunctionName}( $config ),
466
+ \t\t\t'output_schema' => $output_schema,
467
+ \t\t\t'permission_callback' => ${quotePhpString(permissionFunctionName)},
468
+ \t\t);
469
+
470
+ \t\tif ( is_array( $input_schema ) ) {
471
+ \t\t\t$args['input_schema'] = $input_schema;
472
+ \t\t}
473
+
474
+ \t\twp_register_ability(
475
+ \t\t\t(string) $config['abilityId'],
476
+ \t\t\t$args
477
+ \t\t);
478
+ \t}
479
+ }
480
+
481
+ add_action( 'wp_abilities_api_categories_init', '${categoryRegisterFunctionName}' );
482
+ add_action( 'wp_abilities_api_init', '${abilityRegisterFunctionName}' );
483
+ `;
484
+ }
485
+ /**
486
+ * Build the generated abilities index section managed by `wp-typia add ability`.
487
+ */
488
+ export function buildAbilityRegistrySource(abilitySlugs) {
489
+ const exportLines = abilitySlugs
490
+ .map((abilitySlug) => `export * from './${abilitySlug}/client';`)
491
+ .join("\n");
492
+ return [
493
+ ABILITY_REGISTRY_START_MARKER,
494
+ exportLines,
495
+ ABILITY_REGISTRY_END_MARKER,
496
+ ]
497
+ .filter((line) => line.length > 0)
498
+ .join("\n")
499
+ .concat("\n");
500
+ }
@@ -0,0 +1,27 @@
1
+ import type { ScaffoldCompatibilityPolicy } from "./scaffold-compatibility.js";
2
+ import type { WorkspaceProject } from "./workspace-project.js";
3
+ /** Glob used to load generated ability PHP modules from the workspace bootstrap. */
4
+ export declare const ABILITY_SERVER_GLOB = "/inc/abilities/*.php";
5
+ /** Relative path to the generated ability editor script bundle. */
6
+ export declare const ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
7
+ /** Relative path to the generated asset metadata for the ability bundle. */
8
+ export declare const ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
9
+ /** End marker for the generated ability client registry section. */
10
+ export declare const ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end";
11
+ /** Start marker for the generated ability client registry section. */
12
+ export declare const ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start";
13
+ /** Script module id for the public WordPress abilities package. */
14
+ export declare const WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities";
15
+ /** Script module id for the WordPress core abilities bootstrap package. */
16
+ export declare const WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
17
+ /**
18
+ * Inputs required to scaffold a typed workflow ability into a generated workspace.
19
+ */
20
+ export interface ScaffoldAbilityWorkspaceOptions {
21
+ /** Kebab-case ability slug used for directory names and registry ids. */
22
+ abilitySlug: string;
23
+ /** Compatibility metadata applied to the generated workspace bootstrap. */
24
+ compatibilityPolicy: ScaffoldCompatibilityPolicy;
25
+ /** Resolved workspace metadata and filesystem paths for the target project. */
26
+ workspace: WorkspaceProject;
27
+ }
@@ -0,0 +1,14 @@
1
+ /** Glob used to load generated ability PHP modules from the workspace bootstrap. */
2
+ export const ABILITY_SERVER_GLOB = "/inc/abilities/*.php";
3
+ /** Relative path to the generated ability editor script bundle. */
4
+ export const ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
5
+ /** Relative path to the generated asset metadata for the ability bundle. */
6
+ export const ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
7
+ /** End marker for the generated ability client registry section. */
8
+ export const ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end";
9
+ /** Start marker for the generated ability client registry section. */
10
+ export const ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start";
11
+ /** Script module id for the public WordPress abilities package. */
12
+ export const WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities";
13
+ /** Script module id for the WordPress core abilities bootstrap package. */
14
+ export const WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";