wp-typia 0.22.8 → 0.22.10

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.
@@ -11,13 +11,15 @@ import {
11
11
  WP_TYPIA_TOP_LEVEL_COMMAND_NAMES,
12
12
  buildCommandOptions,
13
13
  emitCliDiagnosticFailure,
14
+ formatAddKindList,
15
+ formatAddKindUsagePlaceholder,
14
16
  getAddBlockDefaults,
15
17
  getCreateDefaults,
16
18
  getMcpSchemaSources,
17
19
  package_default,
18
20
  prefersStructuredCliOutput,
19
21
  resolveCommandOptionValues
20
- } from "./cli-e7n7hbvr.js";
22
+ } from "./cli-spdrcg8k.js";
21
23
  import {
22
24
  Result,
23
25
  TaggedError,
@@ -42,10 +44,12 @@ import {
42
44
  createCliDiagnosticCodeError
43
45
  } from "./cli-p95wr1q8.js";
44
46
  import {
47
+ PACKAGE_MANAGER_IDS,
45
48
  formatInstallCommand,
46
49
  formatPackageExecCommand,
47
50
  formatRunScript,
48
- inferPackageManagerId
51
+ inferPackageManagerId,
52
+ parsePackageManagerField
49
53
  } from "./cli-52ke0ptp.js";
50
54
  import {
51
55
  __require,
@@ -67,7 +71,7 @@ function resolveBundledModuleHref(baseUrl, candidates, options = {}) {
67
71
  }
68
72
  const missingCandidates = candidates.map((candidate) => fileURLToPath(new URL(candidate, baseUrl)));
69
73
  const label = options.moduleLabel ?? "bundled wp-typia runtime module";
70
- throw new Error([
74
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_BUILD_ARTIFACT, [
71
75
  `Missing bundled build artifacts for ${label}.`,
72
76
  "None of the expected files were found:",
73
77
  ...missingCandidates.map((candidatePath) => `- ${candidatePath}`),
@@ -76,63 +80,7 @@ function resolveBundledModuleHref(baseUrl, candidates, options = {}) {
76
80
  `));
77
81
  }
78
82
 
79
- // src/cli-string-flags.ts
80
- function readOptionalCliStringFlagValue(flags, name, mode) {
81
- const value = flags[name];
82
- if (value === undefined || value === null) {
83
- return;
84
- }
85
- if (typeof value !== "string") {
86
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name}\` requires a value.`);
87
- }
88
- const trimmed = value.trim();
89
- if (trimmed.length === 0) {
90
- if (mode === "strict") {
91
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name}\` requires a value.`);
92
- }
93
- return;
94
- }
95
- return mode === "strict" ? value : trimmed;
96
- }
97
- function readOptionalLooseStringFlag(flags, name) {
98
- return readOptionalCliStringFlagValue(flags, name, "loose");
99
- }
100
- function readOptionalStrictStringFlag(flags, name) {
101
- return readOptionalCliStringFlagValue(flags, name, "strict");
102
- }
103
- function requireStrictStringFlag(flags, name, message) {
104
- const value = readOptionalStrictStringFlag(flags, name);
105
- if (!value) {
106
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
107
- }
108
- return value;
109
- }
110
- function readOptionalPairedStrictStringFlags(flags, leftName, rightName, message) {
111
- const leftValue = readOptionalStrictStringFlag(flags, leftName);
112
- const rightValue = readOptionalStrictStringFlag(flags, rightName);
113
- if (Boolean(leftValue) !== Boolean(rightValue)) {
114
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
115
- }
116
- return [leftValue, rightValue];
117
- }
118
-
119
- // src/external-layer-prompt-options.ts
120
- function formatExternalLayerSelectHint(option2) {
121
- const details = [
122
- option2.description,
123
- option2.extends.length > 0 ? `extends ${option2.extends.join(", ")}` : undefined
124
- ].filter((value) => typeof value === "string" && value.length > 0);
125
- return details.length > 0 ? details.join(" \xB7 ") : undefined;
126
- }
127
- function toExternalLayerPromptOptions(options) {
128
- return options.map((option2) => ({
129
- hint: formatExternalLayerSelectHint(option2),
130
- label: option2.id,
131
- value: option2.id
132
- }));
133
- }
134
-
135
- // src/add-kind-registry.ts
83
+ // src/add-kind-registry-shared.ts
136
84
  var BLOCK_VISIBLE_FIELD_ORDER = [
137
85
  "kind",
138
86
  "name",
@@ -214,509 +162,627 @@ function isAddPersistenceTemplate(template) {
214
162
  function formatAddBlockTemplateIds(addRuntime) {
215
163
  return addRuntime.ADD_BLOCK_TEMPLATE_IDS.join(", ");
216
164
  }
165
+ function getMistypedAddBlockTemplateMessage(addRuntime, templateId) {
166
+ const suggestion = addRuntime.suggestAddBlockTemplateId(templateId);
167
+ if (!suggestion) {
168
+ return null;
169
+ }
170
+ return `Unknown add-block template "${templateId}". Did you mean "${suggestion}"? Use \`--template ${suggestion}\`, or run \`wp-typia templates list\` to inspect available templates.`;
171
+ }
217
172
  function assertAddBlockTemplateId(context, templateId) {
173
+ if (templateId === "query-loop") {
174
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, "`wp-typia add block --template query-loop` is not supported. Query Loop is a create-time `core/query` variation scaffold, so use `wp-typia create <project-dir> --template query-loop` instead.");
175
+ }
218
176
  if (context.addRuntime.isAddBlockTemplateId(templateId)) {
219
177
  return templateId;
220
178
  }
221
- if (templateId === "query-loop") {
222
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, "`wp-typia add block --template query-loop` is not supported. Query Loop is a create-time `core/query` variation scaffold, so use `wp-typia create <project-dir> --template query-loop` instead.");
179
+ const mistypedAddBlockTemplateMessage = getMistypedAddBlockTemplateMessage(context.addRuntime, templateId);
180
+ if (mistypedAddBlockTemplateMessage) {
181
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.UNKNOWN_TEMPLATE, mistypedAddBlockTemplateMessage);
223
182
  }
224
183
  throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.UNKNOWN_TEMPLATE, `Unknown add-block template "${templateId}". Expected one of: ${formatAddBlockTemplateIds(context.addRuntime)}. Run \`wp-typia templates list\` to inspect available templates.`);
225
184
  }
226
- var ADD_KIND_REGISTRY = {
227
- "admin-view": defineAddKindRegistryEntry({
228
- completion: {
229
- nextSteps: (values) => [
230
- `Review src/admin-views/${values.adminViewSlug}/ and inc/admin-views/${values.adminViewSlug}.php.`,
231
- "Run your workspace build or dev command to verify the generated DataViews admin screen."
232
- ],
233
- summaryLines: (values, projectDir) => [
234
- `Admin view: ${values.adminViewSlug}`,
235
- ...values.source ? [`Source: ${values.source}`] : [],
236
- `Project directory: ${projectDir}`
237
- ],
238
- title: "Added DataViews admin screen"
239
- },
240
- description: "Add an opt-in DataViews-powered admin screen",
241
- nameLabel: "Admin view name",
242
- async prepareExecution(context) {
243
- const name = requireAddKindName(context, "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>].");
244
- const source = readOptionalStrictStringFlag(context.flags, "source");
245
- return createNamedExecutionPlan(context, {
246
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddAdminViewCommand({
247
- adminViewName: name2,
248
- cwd,
249
- source
250
- }),
251
- getValues: (result) => ({
252
- adminViewSlug: result.adminViewSlug,
253
- ...result.source ? { source: result.source } : {}
254
- }),
255
- missingNameMessage: "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>].",
256
- name
257
- });
258
- },
259
- sortOrder: 10,
260
- supportsDryRun: true,
261
- usage: "wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>] [--dry-run]",
262
- visibleFieldNames: () => NAME_SOURCE_VISIBLE_FIELDS
263
- }),
264
- "binding-source": defineAddKindRegistryEntry({
265
- completion: {
266
- nextSteps: (values) => [
267
- `Review src/bindings/${values.bindingSourceSlug}/server.php and src/bindings/${values.bindingSourceSlug}/editor.ts.`,
268
- ...values.blockSlug && values.attributeName ? [
269
- `Review src/blocks/${values.blockSlug}/block.json for the ${values.attributeName} bindable attribute.`
270
- ] : [],
271
- "Run your workspace build or dev command to verify the binding source hooks and editor registration."
272
- ],
273
- summaryLines: (values, projectDir) => [
274
- `Binding source: ${values.bindingSourceSlug}`,
275
- ...values.blockSlug && values.attributeName ? [`Target: ${values.blockSlug}.${values.attributeName}`] : [],
276
- `Project directory: ${projectDir}`
277
- ],
278
- title: "Added binding source"
279
- },
280
- description: "Add a shared block bindings source",
281
- nameLabel: "Binding source name",
282
- async prepareExecution(context) {
283
- const name = requireAddKindName(context, "`wp-typia add binding-source` requires <name>. Usage: wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>].");
284
- const [blockName, attributeName] = readOptionalPairedStrictStringFlags(context.flags, "block", "attribute", "`wp-typia add binding-source` requires --block and --attribute to be provided together.");
285
- return createNamedExecutionPlan(context, {
286
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBindingSourceCommand({
287
- attributeName,
288
- bindingSourceName: name2,
289
- blockName,
290
- cwd
291
- }),
292
- getValues: (result) => ({
293
- ...result.attributeName ? { attributeName: result.attributeName } : {},
294
- ...result.blockSlug ? { blockSlug: result.blockSlug } : {},
295
- bindingSourceSlug: result.bindingSourceSlug
296
- }),
297
- missingNameMessage: "`wp-typia add binding-source` requires <name>. Usage: wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>].",
298
- name
299
- });
300
- },
301
- sortOrder: 70,
302
- supportsDryRun: true,
303
- usage: "wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--dry-run]",
304
- visibleFieldNames: () => NAME_BLOCK_ATTRIBUTE_VISIBLE_FIELDS
305
- }),
306
- block: defineAddKindRegistryEntry({
307
- completion: {
308
- nextSteps: () => [
309
- "Review the generated sources under src/blocks/ and the updated scripts/block-config.ts entry.",
310
- "Run your workspace build or dev command to verify the new scaffolded block family."
311
- ],
312
- summaryLines: (values, projectDir) => [
313
- `Blocks: ${values.blockSlugs}`,
314
- `Template family: ${values.templateId}`,
315
- `Project directory: ${projectDir}`
316
- ],
317
- title: "Added workspace block"
318
- },
319
- description: "Add a real block slice",
320
- hiddenStringSubmitFields: ["external-layer-id", "external-layer-source"],
321
- nameLabel: "Block name",
322
- async prepareExecution(context) {
323
- const name = requireAddKindName(context, "`wp-typia add block` requires <name>. Usage: wp-typia add block <name> [--template <basic|interactivity|persistence|compound>]");
324
- const externalLayerId = readOptionalStrictStringFlag(context.flags, "external-layer-id");
325
- const externalLayerSource = readOptionalStrictStringFlag(context.flags, "external-layer-source");
326
- const shouldPromptForLayerSelection = Boolean(externalLayerSource) && !Boolean(externalLayerId) && context.isInteractiveSession;
327
- const selectPrompt = shouldPromptForLayerSelection ? await context.getOrCreatePrompt() : undefined;
328
- const alternateRenderTargets = readOptionalStrictStringFlag(context.flags, "alternate-render-targets");
329
- const dataStorageMode = readOptionalStrictStringFlag(context.flags, "data-storage");
330
- const innerBlocksPreset = readOptionalStrictStringFlag(context.flags, "inner-blocks-preset");
331
- const persistencePolicy = readOptionalStrictStringFlag(context.flags, "persistence-policy");
332
- const requestedTemplateId = readOptionalStrictStringFlag(context.flags, "template");
333
- let resolvedTemplateId = requestedTemplateId ? assertAddBlockTemplateId(context, requestedTemplateId) : undefined;
334
- if (!resolvedTemplateId && context.isInteractiveSession) {
335
- const templatePrompt = await context.getOrCreatePrompt();
336
- resolvedTemplateId = await templatePrompt.select("Select a block template", context.addRuntime.ADD_BLOCK_TEMPLATE_IDS.map((templateId) => ({
337
- hint: `Scaffold the ${templateId} block family`,
338
- label: templateId,
339
- value: templateId
340
- })), 1);
341
- }
342
- resolvedTemplateId ??= "basic";
343
- return createNamedExecutionPlan(context, {
344
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockCommand({
345
- alternateRenderTargets,
346
- blockName: name2,
347
- cwd,
348
- dataStorageMode,
349
- externalLayerId,
350
- externalLayerSource,
351
- innerBlocksPreset,
352
- persistencePolicy,
353
- selectExternalLayerId: selectPrompt ? (options) => selectPrompt.select("Select an external layer", toExternalLayerPromptOptions(options), 1) : undefined,
354
- templateId: resolvedTemplateId
355
- }),
356
- getValues: (result) => ({
357
- blockSlugs: result.blockSlugs.join(", "),
358
- templateId: result.templateId
359
- }),
360
- getWarnings: (result) => result.warnings,
361
- missingNameMessage: "`wp-typia add block` requires <name>. Usage: wp-typia add block <name> [--template <basic|interactivity|persistence|compound>]",
362
- name,
363
- warnLine: context.warnLine
364
- });
365
- },
366
- sortOrder: 20,
367
- supportsDryRun: true,
368
- usage: "wp-typia add block <name> [--template <basic|interactivity|persistence|compound>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--dry-run]",
369
- visibleFieldNames: ({ template }) => BLOCK_VISIBLE_FIELD_ORDER.filter((fieldName) => {
370
- if (fieldName === "alternate-render-targets") {
371
- return isAddPersistenceTemplate(template);
372
- }
373
- if (fieldName === "inner-blocks-preset") {
374
- return template === "compound";
375
- }
376
- if (fieldName === "data-storage" || fieldName === "persistence-policy") {
377
- return isAddPersistenceTemplate(template);
378
- }
379
- return true;
380
- })
381
- }),
382
- ability: defineAddKindRegistryEntry({
383
- completion: {
384
- nextSteps: (values) => [
385
- `Review src/abilities/${values.abilitySlug}/ and inc/abilities/${values.abilitySlug}.php.`,
386
- "Run `wp-typia sync` or `npm run sync-abilities -- --check` and then your workspace build/dev command to verify the generated workflow ability."
387
- ],
388
- summaryLines: (values, projectDir) => [
389
- `Ability: ${values.abilitySlug}`,
390
- `Project directory: ${projectDir}`
391
- ],
392
- title: "Added workflow ability"
393
- },
394
- description: "Add a typed server/client workflow ability scaffold",
395
- nameLabel: "Ability name",
396
- async prepareExecution(context) {
397
- return createNamedExecutionPlan(context, {
398
- execute: ({ cwd, name }) => context.addRuntime.runAddAbilityCommand({
399
- abilityName: name,
400
- cwd
401
- }),
402
- getValues: (result) => ({
403
- abilitySlug: result.abilitySlug
404
- }),
405
- getWarnings: (result) => result.warnings,
406
- missingNameMessage: "`wp-typia add ability` requires <name>. Usage: wp-typia add ability <name>.",
407
- warnLine: context.warnLine
408
- });
409
- },
410
- sortOrder: 90,
411
- supportsDryRun: true,
412
- usage: "wp-typia add ability <name> [--dry-run]",
413
- visibleFieldNames: () => NAME_ONLY_VISIBLE_FIELDS
414
- }),
415
- "editor-plugin": defineAddKindRegistryEntry({
416
- completion: {
417
- nextSteps: (values) => [
418
- `Review src/editor-plugins/${values.editorPluginSlug}/.`,
419
- "Run your workspace build or dev command to verify the new editor plugin registration."
420
- ],
421
- summaryLines: (values, projectDir) => [
422
- `Editor plugin: ${values.editorPluginSlug}`,
423
- `Slot: ${values.slot}`,
424
- `Project directory: ${projectDir}`
425
- ],
426
- title: "Added editor plugin"
427
- },
428
- description: "Add a slot-aware document editor extension shell",
429
- nameLabel: "Editor plugin name",
430
- async prepareExecution(context) {
431
- const name = requireAddKindName(context, "`wp-typia add editor-plugin` requires <name>. Usage: wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>].");
432
- const slot = readOptionalStrictStringFlag(context.flags, "slot");
433
- return createNamedExecutionPlan(context, {
434
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddEditorPluginCommand({
435
- cwd,
436
- editorPluginName: name2,
437
- slot
438
- }),
439
- getValues: (result) => ({
440
- editorPluginSlug: result.editorPluginSlug,
441
- slot: result.slot
442
- }),
443
- missingNameMessage: "`wp-typia add editor-plugin` requires <name>. Usage: wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>].",
444
- name
445
- });
446
- },
447
- sortOrder: 120,
448
- supportsDryRun: true,
449
- usage: "wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>] [--dry-run]",
450
- visibleFieldNames: () => NAME_SLOT_VISIBLE_FIELDS
451
- }),
452
- "hooked-block": defineAddKindRegistryEntry({
453
- completion: {
454
- nextSteps: (values) => [
455
- `Review src/blocks/${values.blockSlug}/block.json for the new blockHooks entry.`,
456
- "Run your workspace build or dev command to verify the updated hooked-block metadata."
457
- ],
458
- summaryLines: (values, projectDir) => [
459
- `Block: ${values.blockSlug}`,
460
- `Anchor: ${values.anchorBlockName}`,
461
- `Position: ${values.position}`,
462
- `Project directory: ${projectDir}`
463
- ],
464
- title: "Added blockHooks metadata"
465
- },
466
- description: "Add block.json hook metadata to an existing block",
467
- nameLabel: "Target block",
468
- async prepareExecution(context) {
469
- const name = 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>.");
470
- const anchorBlockName = requireStrictStringFlag(context.flags, "anchor", "`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
471
- const position = requireStrictStringFlag(context.flags, "position", "`wp-typia add hooked-block` requires --position <before|after|firstChild|lastChild>.");
472
- return createNamedExecutionPlan(context, {
473
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddHookedBlockCommand({
474
- anchorBlockName,
475
- blockName: name2,
476
- cwd,
477
- position
478
- }),
479
- getValues: (result) => ({
480
- anchorBlockName: result.anchorBlockName,
481
- blockSlug: result.blockSlug,
482
- position: result.position
483
- }),
484
- missingNameMessage: "`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>.",
485
- name
486
- });
487
- },
488
- sortOrder: 110,
489
- supportsDryRun: true,
490
- usage: "wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <before|after|firstChild|lastChild> [--dry-run]",
491
- visibleFieldNames: () => NAME_ANCHOR_POSITION_VISIBLE_FIELDS
492
- }),
493
- pattern: defineAddKindRegistryEntry({
494
- completion: {
495
- nextSteps: (values) => [
496
- `Review src/patterns/${values.patternSlug}.php.`,
497
- "Run your workspace build or dev command to verify the new pattern registration."
498
- ],
499
- summaryLines: (values, projectDir) => [
500
- `Pattern: ${values.patternSlug}`,
501
- `Project directory: ${projectDir}`
502
- ],
503
- title: "Added workspace pattern"
504
- },
505
- description: "Add a PHP block pattern shell",
506
- nameLabel: "Pattern name",
507
- async prepareExecution(context) {
508
- return createNamedExecutionPlan(context, {
509
- execute: ({ cwd, name }) => context.addRuntime.runAddPatternCommand({
510
- cwd,
511
- patternName: name
512
- }),
513
- getValues: (result) => ({
514
- patternSlug: result.patternSlug
515
- }),
516
- missingNameMessage: "`wp-typia add pattern` requires <name>. Usage: wp-typia add pattern <name>."
517
- });
518
- },
519
- sortOrder: 60,
520
- supportsDryRun: true,
521
- usage: "wp-typia add pattern <name> [--dry-run]",
522
- visibleFieldNames: () => NAME_ONLY_VISIBLE_FIELDS
523
- }),
524
- style: defineAddKindRegistryEntry({
525
- completion: {
526
- nextSteps: (values) => [
527
- `Review src/blocks/${values.blockSlug}/styles/${values.styleSlug}.ts.`,
528
- "Run your workspace build or dev command to verify the new block style registration."
529
- ],
530
- summaryLines: (values, projectDir) => [
531
- `Block style: ${values.styleSlug}`,
532
- `Target block: ${values.blockSlug}`,
533
- `Project directory: ${projectDir}`
534
- ],
535
- title: "Added block style"
536
- },
537
- description: "Add a Block Styles registration to an existing block",
538
- nameLabel: "Style name",
539
- async prepareExecution(context) {
540
- const name = requireAddKindName(context, "`wp-typia add style` requires <name>. Usage: wp-typia add style <name> --block <block-slug>.");
541
- const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add style` requires --block <block-slug>.");
542
- return createNamedExecutionPlan(context, {
543
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockStyleCommand({
544
- blockName: blockSlug,
545
- cwd,
546
- styleName: name2
547
- }),
548
- getValues: (result) => ({
549
- blockSlug: result.blockSlug,
550
- styleSlug: result.styleSlug
551
- }),
552
- missingNameMessage: "`wp-typia add style` requires <name>. Usage: wp-typia add style <name> --block <block-slug>.",
553
- name
554
- });
555
- },
556
- sortOrder: 40,
557
- supportsDryRun: true,
558
- usage: "wp-typia add style <name> --block <block-slug> [--dry-run]",
559
- visibleFieldNames: () => NAME_BLOCK_VISIBLE_FIELDS
560
- }),
561
- transform: defineAddKindRegistryEntry({
562
- completion: {
563
- nextSteps: (values) => [
564
- `Review src/blocks/${values.blockSlug}/transforms/${values.transformSlug}.ts.`,
565
- "Run your workspace build or dev command to verify the new block transform registration."
566
- ],
567
- summaryLines: (values, projectDir) => [
568
- `Block transform: ${values.transformSlug}`,
569
- `From: ${values.fromBlockName}`,
570
- `To: ${values.toBlockName}`,
571
- `Project directory: ${projectDir}`
572
- ],
573
- title: "Added block transform"
574
- },
575
- description: "Add a block-to-block transform into a workspace block",
576
- nameLabel: "Transform name",
577
- async prepareExecution(context) {
578
- const name = requireAddKindName(context, "`wp-typia add transform` requires <name>. Usage: wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug>.");
579
- const fromBlockName = requireStrictStringFlag(context.flags, "from", "`wp-typia add transform` requires --from <namespace/block>.");
580
- const toBlockName = requireStrictStringFlag(context.flags, "to", "`wp-typia add transform` requires --to <block-slug|namespace/block-slug>.");
581
- return createNamedExecutionPlan(context, {
582
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockTransformCommand({
583
- cwd,
584
- fromBlockName,
585
- toBlockName,
586
- transformName: name2
587
- }),
588
- getValues: (result) => ({
589
- blockSlug: result.blockSlug,
590
- fromBlockName: result.fromBlockName,
591
- toBlockName: result.toBlockName,
592
- transformSlug: result.transformSlug
593
- }),
594
- missingNameMessage: "`wp-typia add transform` requires <name>. Usage: wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug>.",
595
- name
596
- });
597
- },
598
- sortOrder: 50,
599
- supportsDryRun: true,
600
- usage: "wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug> [--dry-run]",
601
- visibleFieldNames: () => NAME_FROM_TO_VISIBLE_FIELDS
602
- }),
603
- "rest-resource": defineAddKindRegistryEntry({
604
- completion: {
605
- nextSteps: (values) => [
606
- `Review src/rest/${values.restResourceSlug}/ and inc/rest/${values.restResourceSlug}.php.`,
607
- "Run your workspace build or dev command to verify the generated REST resource contract."
608
- ],
609
- summaryLines: (values, projectDir) => [
610
- `REST resource: ${values.restResourceSlug}`,
611
- `Namespace: ${values.namespace}`,
612
- `Methods: ${values.methods}`,
613
- `Project directory: ${projectDir}`
614
- ],
615
- title: "Added plugin-level REST resource"
616
- },
617
- description: "Add a plugin-level typed REST resource",
618
- nameLabel: "REST resource name",
619
- async prepareExecution(context) {
620
- const name = requireAddKindName(context, "`wp-typia add rest-resource` requires <name>. Usage: wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create>].");
621
- const methods = readOptionalStrictStringFlag(context.flags, "methods");
622
- const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
623
- return createNamedExecutionPlan(context, {
624
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddRestResourceCommand({
625
- cwd,
626
- methods,
627
- namespace,
628
- restResourceName: name2
629
- }),
630
- getValues: (result) => ({
631
- methods: result.methods.join(", "),
632
- namespace: result.namespace,
633
- restResourceSlug: result.restResourceSlug
634
- }),
635
- missingNameMessage: "`wp-typia add rest-resource` requires <name>. Usage: wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create>].",
636
- name
637
- });
638
- },
639
- sortOrder: 80,
640
- supportsDryRun: true,
641
- usage: "wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create,update,delete>] [--dry-run]",
642
- visibleFieldNames: () => NAME_NAMESPACE_METHODS_VISIBLE_FIELDS
643
- }),
644
- "ai-feature": defineAddKindRegistryEntry({
645
- completion: {
646
- nextSteps: (values) => [
647
- `Review src/ai-features/${values.aiFeatureSlug}/ and inc/ai-features/${values.aiFeatureSlug}.php.`,
648
- "Run `wp-typia sync-rest` and `wp-typia sync ai` or your workspace build/dev command to verify the generated REST artifacts and AI schema."
649
- ],
650
- summaryLines: (values, projectDir) => [
651
- `AI feature: ${values.aiFeatureSlug}`,
652
- `Namespace: ${values.namespace}`,
653
- `Project directory: ${projectDir}`
654
- ],
655
- title: "Added server-only AI feature"
656
- },
657
- description: "Add a server-owned WordPress AI feature endpoint",
658
- nameLabel: "AI feature name",
659
- async prepareExecution(context) {
660
- const name = requireAddKindName(context, "`wp-typia add ai-feature` requires <name>. Usage: wp-typia add ai-feature <name> [--namespace <vendor/v1>].");
661
- const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
662
- return createNamedExecutionPlan(context, {
663
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddAiFeatureCommand({
664
- aiFeatureName: name2,
665
- cwd,
666
- namespace
667
- }),
668
- getValues: (result) => ({
669
- aiFeatureSlug: result.aiFeatureSlug,
670
- namespace: result.namespace
671
- }),
672
- getWarnings: (result) => result.warnings,
673
- missingNameMessage: "`wp-typia add ai-feature` requires <name>. Usage: wp-typia add ai-feature <name> [--namespace <vendor/v1>].",
674
- name,
675
- warnLine: context.warnLine
676
- });
677
- },
678
- sortOrder: 100,
679
- supportsDryRun: true,
680
- usage: "wp-typia add ai-feature <name> [--namespace <vendor/v1>] [--dry-run]",
681
- visibleFieldNames: () => NAME_NAMESPACE_VISIBLE_FIELDS
682
- }),
683
- variation: defineAddKindRegistryEntry({
684
- completion: {
685
- nextSteps: (values) => [
686
- `Review src/blocks/${values.blockSlug}/variations/${values.variationSlug}.ts.`,
687
- "Run your workspace build or dev command to pick up the new variation."
688
- ],
689
- summaryLines: (values, projectDir) => [
690
- `Variation: ${values.variationSlug}`,
691
- `Target block: ${values.blockSlug}`,
692
- `Project directory: ${projectDir}`
693
- ],
694
- title: "Added workspace variation"
695
- },
696
- description: "Add a variation to an existing block",
697
- nameLabel: "Variation name",
698
- async prepareExecution(context) {
699
- const name = requireAddKindName(context, "`wp-typia add variation` requires <name>. Usage: wp-typia add variation <name> --block <block-slug>");
700
- const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add variation` requires --block <block-slug>.");
701
- return createNamedExecutionPlan(context, {
702
- execute: ({ cwd, name: name2 }) => context.addRuntime.runAddVariationCommand({
703
- blockName: blockSlug,
704
- cwd,
705
- variationName: name2
706
- }),
707
- getValues: (result) => ({
708
- blockSlug: result.blockSlug,
709
- variationSlug: result.variationSlug
710
- }),
711
- missingNameMessage: "`wp-typia add variation` requires <name>. Usage: wp-typia add variation <name> --block <block-slug>",
712
- name
713
- });
714
- },
715
- sortOrder: 30,
716
- supportsDryRun: true,
717
- usage: "wp-typia add variation <name> --block <block-slug> [--dry-run]",
718
- visibleFieldNames: () => NAME_BLOCK_VISIBLE_FIELDS
185
+
186
+ // src/add-kinds/ability.ts
187
+ var ABILITY_MISSING_NAME_MESSAGE = "`wp-typia add ability` requires <name>. Usage: wp-typia add ability <name>.";
188
+ var abilityAddKindEntry = defineAddKindRegistryEntry({
189
+ completion: {
190
+ nextSteps: (values) => [
191
+ `Review src/abilities/${values.abilitySlug}/ and inc/abilities/${values.abilitySlug}.php.`,
192
+ "Run `wp-typia sync` or `npm run sync-abilities -- --check` and then your workspace build/dev command to verify the generated workflow ability."
193
+ ],
194
+ summaryLines: (values, projectDir) => [
195
+ `Ability: ${values.abilitySlug}`,
196
+ `Project directory: ${projectDir}`
197
+ ],
198
+ title: "Added workflow ability"
199
+ },
200
+ description: "Add a typed server/client workflow ability scaffold",
201
+ nameLabel: "Ability name",
202
+ async prepareExecution(context) {
203
+ return createNamedExecutionPlan(context, {
204
+ execute: ({ cwd, name }) => context.addRuntime.runAddAbilityCommand({
205
+ abilityName: name,
206
+ cwd
207
+ }),
208
+ getValues: (result) => ({
209
+ abilitySlug: result.abilitySlug
210
+ }),
211
+ getWarnings: (result) => result.warnings,
212
+ missingNameMessage: ABILITY_MISSING_NAME_MESSAGE,
213
+ warnLine: context.warnLine
214
+ });
215
+ },
216
+ sortOrder: 90,
217
+ supportsDryRun: true,
218
+ usage: "wp-typia add ability <name> [--dry-run]",
219
+ visibleFieldNames: () => NAME_ONLY_VISIBLE_FIELDS
220
+ });
221
+
222
+ // src/cli-string-flags.ts
223
+ function readOptionalCliStringFlagValue(flags, name, mode) {
224
+ const value = flags[name];
225
+ if (value === undefined || value === null) {
226
+ return;
227
+ }
228
+ if (typeof value !== "string") {
229
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name}\` requires a value.`);
230
+ }
231
+ const trimmed = value.trim();
232
+ if (trimmed.length === 0) {
233
+ if (mode === "strict") {
234
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`--${name}\` requires a value.`);
235
+ }
236
+ return;
237
+ }
238
+ return mode === "strict" ? value : trimmed;
239
+ }
240
+ function readOptionalLooseStringFlag(flags, name) {
241
+ return readOptionalCliStringFlagValue(flags, name, "loose");
242
+ }
243
+ function readOptionalStrictStringFlag(flags, name) {
244
+ return readOptionalCliStringFlagValue(flags, name, "strict");
245
+ }
246
+ function requireStrictStringFlag(flags, name, message) {
247
+ const value = readOptionalStrictStringFlag(flags, name);
248
+ if (!value) {
249
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
250
+ }
251
+ return value;
252
+ }
253
+ function readOptionalPairedStrictStringFlags(flags, leftName, rightName, message) {
254
+ const leftValue = readOptionalStrictStringFlag(flags, leftName);
255
+ const rightValue = readOptionalStrictStringFlag(flags, rightName);
256
+ if (Boolean(leftValue) !== Boolean(rightValue)) {
257
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, message);
258
+ }
259
+ return [leftValue, rightValue];
260
+ }
261
+
262
+ // src/add-kinds/admin-view.ts
263
+ var ADMIN_VIEW_MISSING_NAME_MESSAGE = "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>].";
264
+ var adminViewAddKindEntry = defineAddKindRegistryEntry({
265
+ completion: {
266
+ nextSteps: (values) => [
267
+ `Review src/admin-views/${values.adminViewSlug}/ and inc/admin-views/${values.adminViewSlug}.php.`,
268
+ "Run your workspace build or dev command to verify the generated DataViews admin screen."
269
+ ],
270
+ summaryLines: (values, projectDir) => [
271
+ `Admin view: ${values.adminViewSlug}`,
272
+ ...values.source ? [`Source: ${values.source}`] : [],
273
+ `Project directory: ${projectDir}`
274
+ ],
275
+ title: "Added DataViews admin screen"
276
+ },
277
+ description: "Add an opt-in DataViews-powered admin screen",
278
+ nameLabel: "Admin view name",
279
+ async prepareExecution(context) {
280
+ const name = requireAddKindName(context, ADMIN_VIEW_MISSING_NAME_MESSAGE);
281
+ const source = readOptionalStrictStringFlag(context.flags, "source");
282
+ return createNamedExecutionPlan(context, {
283
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddAdminViewCommand({
284
+ adminViewName: name2,
285
+ cwd,
286
+ source
287
+ }),
288
+ getValues: (result) => ({
289
+ adminViewSlug: result.adminViewSlug,
290
+ ...result.source ? { source: result.source } : {}
291
+ }),
292
+ missingNameMessage: ADMIN_VIEW_MISSING_NAME_MESSAGE,
293
+ name
294
+ });
295
+ },
296
+ sortOrder: 10,
297
+ supportsDryRun: true,
298
+ usage: "wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>] [--dry-run]",
299
+ visibleFieldNames: () => NAME_SOURCE_VISIBLE_FIELDS
300
+ });
301
+
302
+ // src/add-kinds/ai-feature.ts
303
+ var AI_FEATURE_MISSING_NAME_MESSAGE = "`wp-typia add ai-feature` requires <name>. Usage: wp-typia add ai-feature <name> [--namespace <vendor/v1>].";
304
+ var aiFeatureAddKindEntry = defineAddKindRegistryEntry({
305
+ completion: {
306
+ nextSteps: (values) => [
307
+ `Review src/ai-features/${values.aiFeatureSlug}/ and inc/ai-features/${values.aiFeatureSlug}.php.`,
308
+ "Run `wp-typia sync-rest` and `wp-typia sync ai` or your workspace build/dev command to verify the generated REST artifacts and AI schema."
309
+ ],
310
+ summaryLines: (values, projectDir) => [
311
+ `AI feature: ${values.aiFeatureSlug}`,
312
+ `Namespace: ${values.namespace}`,
313
+ `Project directory: ${projectDir}`
314
+ ],
315
+ title: "Added server-only AI feature"
316
+ },
317
+ description: "Add a server-owned WordPress AI feature endpoint",
318
+ nameLabel: "AI feature name",
319
+ async prepareExecution(context) {
320
+ const name = requireAddKindName(context, AI_FEATURE_MISSING_NAME_MESSAGE);
321
+ const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
322
+ return createNamedExecutionPlan(context, {
323
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddAiFeatureCommand({
324
+ aiFeatureName: name2,
325
+ cwd,
326
+ namespace
327
+ }),
328
+ getValues: (result) => ({
329
+ aiFeatureSlug: result.aiFeatureSlug,
330
+ namespace: result.namespace
331
+ }),
332
+ getWarnings: (result) => result.warnings,
333
+ missingNameMessage: AI_FEATURE_MISSING_NAME_MESSAGE,
334
+ name,
335
+ warnLine: context.warnLine
336
+ });
337
+ },
338
+ sortOrder: 100,
339
+ supportsDryRun: true,
340
+ usage: "wp-typia add ai-feature <name> [--namespace <vendor/v1>] [--dry-run]",
341
+ visibleFieldNames: () => NAME_NAMESPACE_VISIBLE_FIELDS
342
+ });
343
+
344
+ // src/add-kinds/binding-source.ts
345
+ var BINDING_SOURCE_MISSING_NAME_MESSAGE = "`wp-typia add binding-source` requires <name>. Usage: wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>].";
346
+ var bindingSourceAddKindEntry = defineAddKindRegistryEntry({
347
+ completion: {
348
+ nextSteps: (values) => [
349
+ `Review src/bindings/${values.bindingSourceSlug}/server.php and src/bindings/${values.bindingSourceSlug}/editor.ts.`,
350
+ ...values.blockSlug && values.attributeName ? [
351
+ `Review src/blocks/${values.blockSlug}/block.json for the ${values.attributeName} bindable attribute.`
352
+ ] : [],
353
+ "Run your workspace build or dev command to verify the binding source hooks and editor registration."
354
+ ],
355
+ summaryLines: (values, projectDir) => [
356
+ `Binding source: ${values.bindingSourceSlug}`,
357
+ ...values.blockSlug && values.attributeName ? [`Target: ${values.blockSlug}.${values.attributeName}`] : [],
358
+ `Project directory: ${projectDir}`
359
+ ],
360
+ title: "Added binding source"
361
+ },
362
+ description: "Add a shared block bindings source",
363
+ nameLabel: "Binding source name",
364
+ async prepareExecution(context) {
365
+ const name = requireAddKindName(context, BINDING_SOURCE_MISSING_NAME_MESSAGE);
366
+ const [blockName, attributeName] = readOptionalPairedStrictStringFlags(context.flags, "block", "attribute", "`wp-typia add binding-source` requires --block and --attribute to be provided together.");
367
+ return createNamedExecutionPlan(context, {
368
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBindingSourceCommand({
369
+ attributeName,
370
+ bindingSourceName: name2,
371
+ blockName,
372
+ cwd
373
+ }),
374
+ getValues: (result) => ({
375
+ ...result.attributeName ? { attributeName: result.attributeName } : {},
376
+ ...result.blockSlug ? { blockSlug: result.blockSlug } : {},
377
+ bindingSourceSlug: result.bindingSourceSlug
378
+ }),
379
+ missingNameMessage: BINDING_SOURCE_MISSING_NAME_MESSAGE,
380
+ name
381
+ });
382
+ },
383
+ sortOrder: 70,
384
+ supportsDryRun: true,
385
+ usage: "wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--dry-run]",
386
+ visibleFieldNames: () => NAME_BLOCK_ATTRIBUTE_VISIBLE_FIELDS
387
+ });
388
+
389
+ // src/external-layer-prompt-options.ts
390
+ function formatExternalLayerSelectHint(option2) {
391
+ const details = [
392
+ option2.description,
393
+ option2.extends.length > 0 ? `extends ${option2.extends.join(", ")}` : undefined
394
+ ].filter((value) => typeof value === "string" && value.length > 0);
395
+ return details.length > 0 ? details.join(" \xB7 ") : undefined;
396
+ }
397
+ function toExternalLayerPromptOptions(options) {
398
+ return options.map((option2) => ({
399
+ hint: formatExternalLayerSelectHint(option2),
400
+ label: option2.id,
401
+ value: option2.id
402
+ }));
403
+ }
404
+
405
+ // src/add-kinds/block.ts
406
+ var BLOCK_MISSING_NAME_MESSAGE = "`wp-typia add block` requires <name>. Usage: wp-typia add block <name> [--template <basic|interactivity|persistence|compound>]";
407
+ var blockAddKindEntry = defineAddKindRegistryEntry({
408
+ completion: {
409
+ nextSteps: () => [
410
+ "Review the generated sources under src/blocks/ and the updated scripts/block-config.ts entry.",
411
+ "Run your workspace build or dev command to verify the new scaffolded block family."
412
+ ],
413
+ summaryLines: (values, projectDir) => [
414
+ `Blocks: ${values.blockSlugs}`,
415
+ `Template family: ${values.templateId}`,
416
+ `Project directory: ${projectDir}`
417
+ ],
418
+ title: "Added workspace block"
419
+ },
420
+ description: "Add a real block slice",
421
+ hiddenStringSubmitFields: ["external-layer-id", "external-layer-source"],
422
+ nameLabel: "Block name",
423
+ async prepareExecution(context) {
424
+ const name = requireAddKindName(context, BLOCK_MISSING_NAME_MESSAGE);
425
+ const externalLayerId = readOptionalStrictStringFlag(context.flags, "external-layer-id");
426
+ const externalLayerSource = readOptionalStrictStringFlag(context.flags, "external-layer-source");
427
+ const shouldPromptForLayerSelection = Boolean(externalLayerSource) && !Boolean(externalLayerId) && context.isInteractiveSession;
428
+ const selectPrompt = shouldPromptForLayerSelection ? await context.getOrCreatePrompt() : undefined;
429
+ const alternateRenderTargets = readOptionalStrictStringFlag(context.flags, "alternate-render-targets");
430
+ const dataStorageMode = readOptionalStrictStringFlag(context.flags, "data-storage");
431
+ const innerBlocksPreset = readOptionalStrictStringFlag(context.flags, "inner-blocks-preset");
432
+ const persistencePolicy = readOptionalStrictStringFlag(context.flags, "persistence-policy");
433
+ const requestedTemplateId = readOptionalStrictStringFlag(context.flags, "template");
434
+ let resolvedTemplateId = requestedTemplateId ? assertAddBlockTemplateId(context, requestedTemplateId) : undefined;
435
+ if (!resolvedTemplateId && context.isInteractiveSession) {
436
+ const templatePrompt = await context.getOrCreatePrompt();
437
+ resolvedTemplateId = await templatePrompt.select("Select a block template", context.addRuntime.ADD_BLOCK_TEMPLATE_IDS.map((templateId) => ({
438
+ hint: `Scaffold the ${templateId} block family`,
439
+ label: templateId,
440
+ value: templateId
441
+ })), 1);
442
+ }
443
+ resolvedTemplateId ??= "basic";
444
+ return createNamedExecutionPlan(context, {
445
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockCommand({
446
+ alternateRenderTargets,
447
+ blockName: name2,
448
+ cwd,
449
+ dataStorageMode,
450
+ externalLayerId,
451
+ externalLayerSource,
452
+ innerBlocksPreset,
453
+ persistencePolicy,
454
+ selectExternalLayerId: selectPrompt ? (options) => selectPrompt.select("Select an external layer", toExternalLayerPromptOptions(options), 1) : undefined,
455
+ templateId: resolvedTemplateId
456
+ }),
457
+ getValues: (result) => ({
458
+ blockSlugs: result.blockSlugs.join(", "),
459
+ templateId: result.templateId
460
+ }),
461
+ getWarnings: (result) => result.warnings,
462
+ missingNameMessage: BLOCK_MISSING_NAME_MESSAGE,
463
+ name,
464
+ warnLine: context.warnLine
465
+ });
466
+ },
467
+ sortOrder: 20,
468
+ supportsDryRun: true,
469
+ usage: "wp-typia add block <name> [--template <basic|interactivity|persistence|compound>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--dry-run]",
470
+ visibleFieldNames: ({ template }) => BLOCK_VISIBLE_FIELD_ORDER.filter((fieldName) => {
471
+ if (fieldName === "alternate-render-targets") {
472
+ return isAddPersistenceTemplate(template);
473
+ }
474
+ if (fieldName === "inner-blocks-preset") {
475
+ return template === "compound";
476
+ }
477
+ if (fieldName === "data-storage" || fieldName === "persistence-policy") {
478
+ return isAddPersistenceTemplate(template);
479
+ }
480
+ return true;
719
481
  })
482
+ });
483
+
484
+ // src/add-kinds/editor-plugin.ts
485
+ var EDITOR_PLUGIN_MISSING_NAME_MESSAGE = "`wp-typia add editor-plugin` requires <name>. Usage: wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>].";
486
+ var editorPluginAddKindEntry = defineAddKindRegistryEntry({
487
+ completion: {
488
+ nextSteps: (values) => [
489
+ `Review src/editor-plugins/${values.editorPluginSlug}/.`,
490
+ "Run your workspace build or dev command to verify the new editor plugin registration."
491
+ ],
492
+ summaryLines: (values, projectDir) => [
493
+ `Editor plugin: ${values.editorPluginSlug}`,
494
+ `Slot: ${values.slot}`,
495
+ `Project directory: ${projectDir}`
496
+ ],
497
+ title: "Added editor plugin"
498
+ },
499
+ description: "Add a slot-aware document editor extension shell",
500
+ nameLabel: "Editor plugin name",
501
+ async prepareExecution(context) {
502
+ const name = requireAddKindName(context, EDITOR_PLUGIN_MISSING_NAME_MESSAGE);
503
+ const slot = readOptionalStrictStringFlag(context.flags, "slot");
504
+ return createNamedExecutionPlan(context, {
505
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddEditorPluginCommand({
506
+ cwd,
507
+ editorPluginName: name2,
508
+ slot
509
+ }),
510
+ getValues: (result) => ({
511
+ editorPluginSlug: result.editorPluginSlug,
512
+ slot: result.slot
513
+ }),
514
+ missingNameMessage: EDITOR_PLUGIN_MISSING_NAME_MESSAGE,
515
+ name
516
+ });
517
+ },
518
+ sortOrder: 120,
519
+ supportsDryRun: true,
520
+ usage: "wp-typia add editor-plugin <name> [--slot <sidebar|document-setting-panel>] [--dry-run]",
521
+ visibleFieldNames: () => NAME_SLOT_VISIBLE_FIELDS
522
+ });
523
+
524
+ // src/add-kinds/hooked-block.ts
525
+ var HOOKED_BLOCK_MISSING_NAME_MESSAGE = "`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>.";
526
+ var hookedBlockAddKindEntry = defineAddKindRegistryEntry({
527
+ completion: {
528
+ nextSteps: (values) => [
529
+ `Review src/blocks/${values.blockSlug}/block.json for the new blockHooks entry.`,
530
+ "Run your workspace build or dev command to verify the updated hooked-block metadata."
531
+ ],
532
+ summaryLines: (values, projectDir) => [
533
+ `Block: ${values.blockSlug}`,
534
+ `Anchor: ${values.anchorBlockName}`,
535
+ `Position: ${values.position}`,
536
+ `Project directory: ${projectDir}`
537
+ ],
538
+ title: "Added blockHooks metadata"
539
+ },
540
+ description: "Add block.json hook metadata to an existing block",
541
+ nameLabel: "Target block",
542
+ async prepareExecution(context) {
543
+ const name = requireAddKindName(context, HOOKED_BLOCK_MISSING_NAME_MESSAGE);
544
+ const anchorBlockName = requireStrictStringFlag(context.flags, "anchor", "`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
545
+ const position = requireStrictStringFlag(context.flags, "position", "`wp-typia add hooked-block` requires --position <before|after|firstChild|lastChild>.");
546
+ return createNamedExecutionPlan(context, {
547
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddHookedBlockCommand({
548
+ anchorBlockName,
549
+ blockName: name2,
550
+ cwd,
551
+ position
552
+ }),
553
+ getValues: (result) => ({
554
+ anchorBlockName: result.anchorBlockName,
555
+ blockSlug: result.blockSlug,
556
+ position: result.position
557
+ }),
558
+ missingNameMessage: HOOKED_BLOCK_MISSING_NAME_MESSAGE,
559
+ name
560
+ });
561
+ },
562
+ sortOrder: 110,
563
+ supportsDryRun: true,
564
+ usage: "wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <before|after|firstChild|lastChild> [--dry-run]",
565
+ visibleFieldNames: () => NAME_ANCHOR_POSITION_VISIBLE_FIELDS
566
+ });
567
+
568
+ // src/add-kinds/pattern.ts
569
+ var PATTERN_MISSING_NAME_MESSAGE = "`wp-typia add pattern` requires <name>. Usage: wp-typia add pattern <name>.";
570
+ var patternAddKindEntry = defineAddKindRegistryEntry({
571
+ completion: {
572
+ nextSteps: (values) => [
573
+ `Review src/patterns/${values.patternSlug}.php.`,
574
+ "Run your workspace build or dev command to verify the new pattern registration."
575
+ ],
576
+ summaryLines: (values, projectDir) => [
577
+ `Pattern: ${values.patternSlug}`,
578
+ `Project directory: ${projectDir}`
579
+ ],
580
+ title: "Added workspace pattern"
581
+ },
582
+ description: "Add a PHP block pattern shell",
583
+ nameLabel: "Pattern name",
584
+ async prepareExecution(context) {
585
+ return createNamedExecutionPlan(context, {
586
+ execute: ({ cwd, name }) => context.addRuntime.runAddPatternCommand({
587
+ cwd,
588
+ patternName: name
589
+ }),
590
+ getValues: (result) => ({
591
+ patternSlug: result.patternSlug
592
+ }),
593
+ missingNameMessage: PATTERN_MISSING_NAME_MESSAGE,
594
+ warnLine: context.warnLine
595
+ });
596
+ },
597
+ sortOrder: 60,
598
+ supportsDryRun: true,
599
+ usage: "wp-typia add pattern <name> [--dry-run]",
600
+ visibleFieldNames: () => NAME_ONLY_VISIBLE_FIELDS
601
+ });
602
+
603
+ // src/add-kinds/rest-resource.ts
604
+ var REST_RESOURCE_MISSING_NAME_MESSAGE = "`wp-typia add rest-resource` requires <name>. Usage: wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create,update,delete>].";
605
+ var restResourceAddKindEntry = defineAddKindRegistryEntry({
606
+ completion: {
607
+ nextSteps: (values) => [
608
+ `Review src/rest/${values.restResourceSlug}/ and inc/rest/${values.restResourceSlug}.php.`,
609
+ "Run your workspace build or dev command to verify the generated REST resource contract."
610
+ ],
611
+ summaryLines: (values, projectDir) => [
612
+ `REST resource: ${values.restResourceSlug}`,
613
+ `Namespace: ${values.namespace}`,
614
+ `Methods: ${values.methods}`,
615
+ `Project directory: ${projectDir}`
616
+ ],
617
+ title: "Added plugin-level REST resource"
618
+ },
619
+ description: "Add a plugin-level typed REST resource",
620
+ nameLabel: "REST resource name",
621
+ async prepareExecution(context) {
622
+ const name = requireAddKindName(context, REST_RESOURCE_MISSING_NAME_MESSAGE);
623
+ const methods = readOptionalStrictStringFlag(context.flags, "methods");
624
+ const namespace = readOptionalStrictStringFlag(context.flags, "namespace");
625
+ return createNamedExecutionPlan(context, {
626
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddRestResourceCommand({
627
+ cwd,
628
+ methods,
629
+ namespace,
630
+ restResourceName: name2
631
+ }),
632
+ getValues: (result) => ({
633
+ methods: result.methods.join(", "),
634
+ namespace: result.namespace,
635
+ restResourceSlug: result.restResourceSlug
636
+ }),
637
+ missingNameMessage: REST_RESOURCE_MISSING_NAME_MESSAGE,
638
+ name
639
+ });
640
+ },
641
+ sortOrder: 80,
642
+ supportsDryRun: true,
643
+ usage: "wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <list,read,create,update,delete>] [--dry-run]",
644
+ visibleFieldNames: () => NAME_NAMESPACE_METHODS_VISIBLE_FIELDS
645
+ });
646
+
647
+ // src/add-kinds/style.ts
648
+ var STYLE_MISSING_NAME_MESSAGE = "`wp-typia add style` requires <name>. Usage: wp-typia add style <name> --block <block-slug>.";
649
+ var styleAddKindEntry = defineAddKindRegistryEntry({
650
+ completion: {
651
+ nextSteps: (values) => [
652
+ `Review src/blocks/${values.blockSlug}/styles/${values.styleSlug}.ts.`,
653
+ "Run your workspace build or dev command to verify the new block style registration."
654
+ ],
655
+ summaryLines: (values, projectDir) => [
656
+ `Block style: ${values.styleSlug}`,
657
+ `Target block: ${values.blockSlug}`,
658
+ `Project directory: ${projectDir}`
659
+ ],
660
+ title: "Added block style"
661
+ },
662
+ description: "Add a Block Styles registration to an existing block",
663
+ nameLabel: "Style name",
664
+ async prepareExecution(context) {
665
+ const name = requireAddKindName(context, STYLE_MISSING_NAME_MESSAGE);
666
+ const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add style` requires --block <block-slug>.");
667
+ return createNamedExecutionPlan(context, {
668
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockStyleCommand({
669
+ blockName: blockSlug,
670
+ cwd,
671
+ styleName: name2
672
+ }),
673
+ getValues: (result) => ({
674
+ blockSlug: result.blockSlug,
675
+ styleSlug: result.styleSlug
676
+ }),
677
+ missingNameMessage: STYLE_MISSING_NAME_MESSAGE,
678
+ name
679
+ });
680
+ },
681
+ sortOrder: 40,
682
+ supportsDryRun: true,
683
+ usage: "wp-typia add style <name> --block <block-slug> [--dry-run]",
684
+ visibleFieldNames: () => NAME_BLOCK_VISIBLE_FIELDS
685
+ });
686
+
687
+ // src/add-kinds/transform.ts
688
+ var TRANSFORM_MISSING_NAME_MESSAGE = "`wp-typia add transform` requires <name>. Usage: wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug>.";
689
+ var transformAddKindEntry = defineAddKindRegistryEntry({
690
+ completion: {
691
+ nextSteps: (values) => [
692
+ `Review src/blocks/${values.blockSlug}/transforms/${values.transformSlug}.ts.`,
693
+ "Run your workspace build or dev command to verify the new block transform registration."
694
+ ],
695
+ summaryLines: (values, projectDir) => [
696
+ `Block transform: ${values.transformSlug}`,
697
+ `From: ${values.fromBlockName}`,
698
+ `To: ${values.toBlockName}`,
699
+ `Project directory: ${projectDir}`
700
+ ],
701
+ title: "Added block transform"
702
+ },
703
+ description: "Add a block-to-block transform into a workspace block",
704
+ nameLabel: "Transform name",
705
+ async prepareExecution(context) {
706
+ const name = requireAddKindName(context, TRANSFORM_MISSING_NAME_MESSAGE);
707
+ const fromBlockName = requireStrictStringFlag(context.flags, "from", "`wp-typia add transform` requires --from <namespace/block>.");
708
+ const toBlockName = requireStrictStringFlag(context.flags, "to", "`wp-typia add transform` requires --to <block-slug|namespace/block-slug>.");
709
+ return createNamedExecutionPlan(context, {
710
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddBlockTransformCommand({
711
+ cwd,
712
+ fromBlockName,
713
+ toBlockName,
714
+ transformName: name2
715
+ }),
716
+ getValues: (result) => ({
717
+ blockSlug: result.blockSlug,
718
+ fromBlockName: result.fromBlockName,
719
+ toBlockName: result.toBlockName,
720
+ transformSlug: result.transformSlug
721
+ }),
722
+ missingNameMessage: TRANSFORM_MISSING_NAME_MESSAGE,
723
+ name
724
+ });
725
+ },
726
+ sortOrder: 50,
727
+ supportsDryRun: true,
728
+ usage: "wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug> [--dry-run]",
729
+ visibleFieldNames: () => NAME_FROM_TO_VISIBLE_FIELDS
730
+ });
731
+
732
+ // src/add-kinds/variation.ts
733
+ var VARIATION_MISSING_NAME_MESSAGE = "`wp-typia add variation` requires <name>. Usage: wp-typia add variation <name> --block <block-slug>";
734
+ var variationAddKindEntry = defineAddKindRegistryEntry({
735
+ completion: {
736
+ nextSteps: (values) => [
737
+ `Review src/blocks/${values.blockSlug}/variations/${values.variationSlug}.ts.`,
738
+ "Run your workspace build or dev command to pick up the new variation."
739
+ ],
740
+ summaryLines: (values, projectDir) => [
741
+ `Variation: ${values.variationSlug}`,
742
+ `Target block: ${values.blockSlug}`,
743
+ `Project directory: ${projectDir}`
744
+ ],
745
+ title: "Added workspace variation"
746
+ },
747
+ description: "Add a variation to an existing block",
748
+ nameLabel: "Variation name",
749
+ async prepareExecution(context) {
750
+ const name = requireAddKindName(context, VARIATION_MISSING_NAME_MESSAGE);
751
+ const blockSlug = requireStrictStringFlag(context.flags, "block", "`wp-typia add variation` requires --block <block-slug>.");
752
+ return createNamedExecutionPlan(context, {
753
+ execute: ({ cwd, name: name2 }) => context.addRuntime.runAddVariationCommand({
754
+ blockName: blockSlug,
755
+ cwd,
756
+ variationName: name2
757
+ }),
758
+ getValues: (result) => ({
759
+ blockSlug: result.blockSlug,
760
+ variationSlug: result.variationSlug
761
+ }),
762
+ missingNameMessage: VARIATION_MISSING_NAME_MESSAGE,
763
+ name
764
+ });
765
+ },
766
+ sortOrder: 30,
767
+ supportsDryRun: true,
768
+ usage: "wp-typia add variation <name> --block <block-slug> [--dry-run]",
769
+ visibleFieldNames: () => NAME_BLOCK_VISIBLE_FIELDS
770
+ });
771
+
772
+ // src/add-kind-registry.ts
773
+ var ADD_KIND_REGISTRY = {
774
+ "admin-view": adminViewAddKindEntry,
775
+ block: blockAddKindEntry,
776
+ variation: variationAddKindEntry,
777
+ style: styleAddKindEntry,
778
+ transform: transformAddKindEntry,
779
+ pattern: patternAddKindEntry,
780
+ "binding-source": bindingSourceAddKindEntry,
781
+ "rest-resource": restResourceAddKindEntry,
782
+ ability: abilityAddKindEntry,
783
+ "ai-feature": aiFeatureAddKindEntry,
784
+ "hooked-block": hookedBlockAddKindEntry,
785
+ "editor-plugin": editorPluginAddKindEntry
720
786
  };
721
787
  function isAddKindId(value) {
722
788
  return typeof value === "string" && ADD_KIND_IDS.includes(value);
@@ -732,16 +798,28 @@ function buildAddKindCompletionDetails(kind, options) {
732
798
  title: descriptor.title
733
799
  };
734
800
  }
735
- function formatAddKindList() {
736
- return ADD_KIND_IDS.join(", ");
737
- }
738
- function formatAddKindUsagePlaceholder() {
739
- return `<${ADD_KIND_IDS.join("|")}>`;
740
- }
741
801
  function supportsAddKindDryRun(kind) {
742
802
  return ADD_KIND_REGISTRY[kind].supportsDryRun;
743
803
  }
744
804
 
805
+ // src/cli-error-messages.ts
806
+ var MISSING_CREATE_PROJECT_DIR_DETAIL_LINES = [
807
+ "`wp-typia create` requires <project-dir>.",
808
+ "`--dry-run` still needs a logical project directory name because wp-typia derives slugs, package names, and planned file paths from it."
809
+ ];
810
+ function formatMissingAddKindDetailLine() {
811
+ return `\`wp-typia add\` requires <kind>. Usage: wp-typia add ${formatAddKindUsagePlaceholder()} ...`;
812
+ }
813
+ function shouldPrintMissingAddKindHelp(options) {
814
+ if (typeof options.emitOutput === "boolean") {
815
+ return options.emitOutput;
816
+ }
817
+ return options.format !== "json";
818
+ }
819
+ function buildMissingCreateProjectDirDetailLines() {
820
+ return [...MISSING_CREATE_PROJECT_DIR_DETAIL_LINES];
821
+ }
822
+
745
823
  // src/runtime-bridge-add-dry-run.ts
746
824
  import fs2 from "fs";
747
825
  import { promises as fsp } from "fs";
@@ -766,6 +844,55 @@ async function copyWorkspaceProject(sourceDir, targetDir) {
766
844
  recursive: true
767
845
  });
768
846
  }
847
+ function formatInstallMarkerError(error) {
848
+ if (error instanceof Error) {
849
+ return error.message;
850
+ }
851
+ return String(error);
852
+ }
853
+ function formatInstallMarkerFailures(failures) {
854
+ return failures.map((failure) => `${failure.operation}: ${failure.reason}`).join("; ");
855
+ }
856
+ function ensureWorkspaceInstallMarker({
857
+ fsAdapter = fs2,
858
+ sourceMarker,
859
+ targetMarker
860
+ }) {
861
+ const failures = [];
862
+ try {
863
+ fsAdapter.symlinkSync(sourceMarker, targetMarker);
864
+ return;
865
+ } catch (error) {
866
+ failures.push({
867
+ operation: "symlink",
868
+ reason: formatInstallMarkerError(error)
869
+ });
870
+ }
871
+ try {
872
+ fsAdapter.linkSync(sourceMarker, targetMarker);
873
+ return;
874
+ } catch (error) {
875
+ failures.push({
876
+ operation: "hard link",
877
+ reason: formatInstallMarkerError(error)
878
+ });
879
+ }
880
+ try {
881
+ fsAdapter.copyFileSync(sourceMarker, targetMarker);
882
+ return;
883
+ } catch (error) {
884
+ failures.push({
885
+ operation: "copy",
886
+ reason: formatInstallMarkerError(error)
887
+ });
888
+ }
889
+ throw new Error([
890
+ "Failed to prepare dry-run install marker.",
891
+ `Source: ${sourceMarker}`,
892
+ `Target: ${targetMarker}`,
893
+ `Fallback failures: ${formatInstallMarkerFailures(failures)}`
894
+ ].join(" "));
895
+ }
769
896
  function ensureWorkspaceInstallMarkers(sourceDir, targetDir) {
770
897
  const sourceNodeModules = path.join(sourceDir, "node_modules");
771
898
  if (fs2.existsSync(sourceNodeModules)) {
@@ -777,15 +904,7 @@ function ensureWorkspaceInstallMarkers(sourceDir, targetDir) {
777
904
  continue;
778
905
  }
779
906
  const targetMarker = path.join(targetDir, marker);
780
- try {
781
- fs2.symlinkSync(sourceMarker, targetMarker);
782
- } catch {
783
- try {
784
- fs2.linkSync(sourceMarker, targetMarker);
785
- } catch {
786
- fs2.copyFileSync(sourceMarker, targetMarker);
787
- }
788
- }
907
+ ensureWorkspaceInstallMarker({ sourceMarker, targetMarker });
789
908
  }
790
909
  }
791
910
  async function listWorkspaceFiles(rootDir) {
@@ -946,40 +1065,38 @@ function stripLeadingOutputMarker(text, kind) {
946
1065
  return text.replace(new RegExp(`^(?:${markerPattern})\\s*`, "u"), "");
947
1066
  }
948
1067
 
949
- // src/runtime-bridge-output.ts
950
- function printCompletionPayload(payload, options = {}) {
951
- const printLine = options.printLine ?? console.log;
952
- const warnLine = options.warnLine ?? printLine;
953
- for (const line of payload.preambleLines ?? []) {
954
- printLine(line);
955
- }
956
- for (const warning of payload.warningLines ?? []) {
957
- warnLine(formatOutputMarker("warning", warning, options.markerOptions));
958
- }
959
- const hasDetails = (payload.summaryLines?.length ?? 0) > 0 || (payload.nextSteps?.length ?? 0) > 0 || (payload.optionalLines?.length ?? 0) > 0 || Boolean(payload.optionalNote);
960
- const hasLeadingContext = (payload.preambleLines?.length ?? 0) > 0 || (payload.warningLines?.length ?? 0) > 0;
961
- printLine(hasLeadingContext && hasDetails ? `
962
- ${payload.title}` : payload.title);
963
- for (const line of payload.summaryLines ?? []) {
964
- printLine(line);
965
- }
966
- if ((payload.nextSteps?.length ?? 0) > 0) {
967
- printLine("Next steps:");
968
- for (const step of payload.nextSteps ?? []) {
969
- printLine(` ${step}`);
970
- }
971
- }
972
- if ((payload.optionalLines?.length ?? 0) > 0) {
973
- printLine(`
974
- ${payload.optionalTitle ?? "Optional:"}`);
975
- for (const step of payload.optionalLines ?? []) {
976
- printLine(` ${step}`);
977
- }
978
- }
979
- if (payload.optionalNote) {
980
- printLine(`Note: ${payload.optionalNote}`);
981
- }
1068
+ // src/runtime-output/init.ts
1069
+ function buildInitCompletionPayload(plan, markerOptions) {
1070
+ const changeLines = [
1071
+ ...plan.packageChanges.addDevDependencies.map((dependency) => `devDependency ${dependency.action} ${dependency.name} -> ${dependency.requiredValue}`),
1072
+ ...plan.packageChanges.packageManagerField ? [
1073
+ `packageManager ${plan.packageChanges.packageManagerField.action} -> ${plan.packageChanges.packageManagerField.requiredValue}`
1074
+ ] : [],
1075
+ ...plan.packageChanges.scripts.map((script) => `script ${script.action} ${script.name} -> ${script.requiredValue}`),
1076
+ ...plan.plannedFiles.map((filePlan) => `file ${filePlan.action} ${filePlan.path} (${filePlan.purpose})`),
1077
+ ...plan.commandMode === "preview-only" ? plan.generatedArtifacts.map((artifactPath) => `generated artifact ${artifactPath}`) : []
1078
+ ];
1079
+ const modeLine = plan.commandMode === "apply" ? plan.status === "already-initialized" ? "Mode: apply requested; no files were written because the retrofit surface already existed." : "Mode: apply; package.json and retrofit helper files were written." : "Mode: preview only; no files were written.";
1080
+ const optionalTitle = plan.commandMode === "apply" ? `Applied adoption changes (${changeLines.length}):` : `Planned adoption changes (${changeLines.length}):`;
1081
+ const title = plan.status === "already-initialized" ? formatOutputMarker("success", `wp-typia init: ${plan.projectName} is already initialized`, markerOptions) : plan.commandMode === "apply" ? formatOutputMarker("success", `Applied retrofit init for ${plan.projectName}`, markerOptions) : formatOutputMarker("dryRun", `Retrofit init plan for ${plan.projectName}`, markerOptions);
1082
+ return {
1083
+ nextSteps: plan.nextSteps,
1084
+ optionalLines: changeLines,
1085
+ optionalNote: plan.summary,
1086
+ optionalTitle,
1087
+ summaryLines: [
1088
+ `Project directory: ${plan.projectDir}`,
1089
+ `Detected layout: ${plan.detectedLayout.description}`,
1090
+ ...plan.detectedLayout.blockNames.length > 0 ? [`Block targets: ${plan.detectedLayout.blockNames.join(", ")}`] : [],
1091
+ `Package manager: ${plan.packageManager}`,
1092
+ modeLine
1093
+ ],
1094
+ title,
1095
+ warningLines: plan.notes
1096
+ };
982
1097
  }
1098
+
1099
+ // src/runtime-output/structured.ts
983
1100
  function toNonEmptyArray(values) {
984
1101
  return values && values.length > 0 ? values : undefined;
985
1102
  }
@@ -1040,12 +1157,35 @@ function buildStructuredInitSuccessPayload(plan) {
1040
1157
  }
1041
1158
  };
1042
1159
  }
1160
+ // src/runtime-output/create.ts
1161
+ function escapeRegExp2(source) {
1162
+ return source.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
1163
+ }
1164
+ var LOOSE_CREATE_COMPLETION_PACKAGE_MANAGER_PATTERN = new RegExp(`^(?:corepack\\s+)?(${PACKAGE_MANAGER_IDS.map(escapeRegExp2).join("|")})(?=$|[@:/+\\s])`, "iu");
1165
+ function parseCreateCompletionPackageManager(packageManager) {
1166
+ const normalizedPackageManager = packageManager.trim();
1167
+ const parsedPackageManager = parsePackageManagerField(normalizedPackageManager);
1168
+ if (parsedPackageManager) {
1169
+ return parsedPackageManager;
1170
+ }
1171
+ const looseMatch = LOOSE_CREATE_COMPLETION_PACKAGE_MANAGER_PATTERN.exec(normalizedPackageManager);
1172
+ const loosePackageManager = looseMatch?.[1]?.toLowerCase();
1173
+ return PACKAGE_MANAGER_IDS.includes(loosePackageManager) ? loosePackageManager : null;
1174
+ }
1175
+ function resolveCreateCompletionPackageManager(packageManager) {
1176
+ const parsedPackageManager = parseCreateCompletionPackageManager(packageManager);
1177
+ if (parsedPackageManager) {
1178
+ return parsedPackageManager;
1179
+ }
1180
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unsupported package manager "${packageManager}" in create completion payload. Expected one of: ${PACKAGE_MANAGER_IDS.join(", ")}.`);
1181
+ }
1043
1182
  function formatCreateProgressLine(payload, markerOptions) {
1044
1183
  return formatOutputMarker("progress", `${payload.title}: ${payload.detail}`, markerOptions);
1045
1184
  }
1046
1185
  function buildCreateCompletionPayload(flow, markerOptions) {
1186
+ const packageManager = resolveCreateCompletionPackageManager(flow.packageManager);
1047
1187
  const verificationSteps = [
1048
- formatPackageExecCommand(flow.packageManager, `wp-typia@${package_default.version}`, "doctor"),
1188
+ formatPackageExecCommand(packageManager, `wp-typia@${package_default.version}`, "doctor"),
1049
1189
  ...flow.optionalOnboarding.steps
1050
1190
  ];
1051
1191
  return {
@@ -1084,42 +1224,7 @@ function buildCreateDryRunPayload(flow, markerOptions) {
1084
1224
  warningLines: flow.result.warnings
1085
1225
  };
1086
1226
  }
1087
- function buildInitCompletionPayload(plan, markerOptions) {
1088
- const changeLines = [
1089
- ...plan.packageChanges.addDevDependencies.map((dependency) => `devDependency ${dependency.action} ${dependency.name} -> ${dependency.requiredValue}`),
1090
- ...plan.packageChanges.packageManagerField ? [
1091
- `packageManager ${plan.packageChanges.packageManagerField.action} -> ${plan.packageChanges.packageManagerField.requiredValue}`
1092
- ] : [],
1093
- ...plan.packageChanges.scripts.map((script) => `script ${script.action} ${script.name} -> ${script.requiredValue}`),
1094
- ...plan.plannedFiles.map((filePlan) => `file ${filePlan.action} ${filePlan.path} (${filePlan.purpose})`),
1095
- ...plan.commandMode === "preview-only" ? plan.generatedArtifacts.map((artifactPath) => `generated artifact ${artifactPath}`) : []
1096
- ];
1097
- const modeLine = plan.commandMode === "apply" ? plan.status === "already-initialized" ? "Mode: apply requested; no files were written because the retrofit surface already existed." : "Mode: apply; package.json and retrofit helper files were written." : "Mode: preview only; no files were written.";
1098
- const optionalTitle = plan.commandMode === "apply" ? `Applied adoption changes (${changeLines.length}):` : `Planned adoption changes (${changeLines.length}):`;
1099
- const title = plan.status === "already-initialized" ? formatOutputMarker("success", `wp-typia init: ${plan.projectName} is already initialized`, markerOptions) : plan.commandMode === "apply" ? formatOutputMarker("success", `Applied retrofit init for ${plan.projectName}`, markerOptions) : formatOutputMarker("dryRun", `Retrofit init plan for ${plan.projectName}`, markerOptions);
1100
- return {
1101
- nextSteps: plan.nextSteps,
1102
- optionalLines: changeLines,
1103
- optionalNote: plan.summary,
1104
- optionalTitle,
1105
- summaryLines: [
1106
- `Project directory: ${plan.projectDir}`,
1107
- `Detected layout: ${plan.detectedLayout.description}`,
1108
- ...plan.detectedLayout.blockNames.length > 0 ? [`Block targets: ${plan.detectedLayout.blockNames.join(", ")}`] : [],
1109
- `Package manager: ${plan.packageManager}`,
1110
- modeLine
1111
- ],
1112
- title,
1113
- warningLines: plan.notes
1114
- };
1115
- }
1116
- function buildMigrationCompletionPayload(options, markerOptions) {
1117
- const summaryLines = options.lines.filter((line) => line.trim().length > 0);
1118
- return {
1119
- summaryLines,
1120
- title: formatOutputMarker("success", `Completed wp-typia migrate ${options.command}`, markerOptions)
1121
- };
1122
- }
1227
+ // src/runtime-output/add.ts
1123
1228
  function buildAddCompletionPayload(options, markerOptions) {
1124
1229
  const verificationLines = [
1125
1230
  formatPackageExecCommand(options.packageManager ?? inferPackageManagerId(options.projectDir), `wp-typia@${package_default.version}`, "doctor")
@@ -1151,6 +1256,15 @@ function buildAddDryRunPayload(options, markerOptions) {
1151
1256
  warningLines: options.completion.warningLines
1152
1257
  };
1153
1258
  }
1259
+ // src/runtime-output/migrate.ts
1260
+ function buildMigrationCompletionPayload(options, markerOptions) {
1261
+ const summaryLines = options.lines.filter((line) => line.trim().length > 0);
1262
+ return {
1263
+ summaryLines,
1264
+ title: formatOutputMarker("success", `Completed wp-typia migrate ${options.command}`, markerOptions)
1265
+ };
1266
+ }
1267
+ // src/runtime-output/sync.ts
1154
1268
  function buildSyncDryRunPayload(options, markerOptions) {
1155
1269
  const targetSuffix = options.target === "ai" ? " ai" : "";
1156
1270
  const targetSummary = options.target === "ai" ? "Sync target: AI artifacts only." : options.target === "default" ? "Sync target: generated project defaults." : undefined;
@@ -1167,232 +1281,62 @@ function buildSyncDryRunPayload(options, markerOptions) {
1167
1281
  title: formatOutputMarker("dryRun", `Dry run for wp-typia sync${targetSuffix}`, markerOptions)
1168
1282
  };
1169
1283
  }
1170
- function printBlock(lines, printLine) {
1284
+ // src/print-block.ts
1285
+ function printBlock(printLine, lines) {
1171
1286
  for (const line of lines) {
1172
1287
  printLine(line);
1173
1288
  }
1174
1289
  }
1175
1290
 
1176
- // src/runtime-capabilities.ts
1177
- function isInteractiveTerminal({
1178
- stdin = process.stdin,
1179
- stdout = process.stdout,
1180
- term = process.env.TERM
1181
- } = {}) {
1182
- return Boolean(stdin?.isTTY) && Boolean(stdout?.isTTY) && term !== "dumb";
1183
- }
1184
- function supportsInteractiveTui(options = {}) {
1185
- const hasBunRuntime = options.hasBunRuntime ?? typeof Bun !== "undefined";
1186
- return hasBunRuntime && isInteractiveTerminal(options);
1187
- }
1188
- // src/runtime-bridge-sync.ts
1189
- import { spawnSync } from "child_process";
1190
- import fs3 from "fs";
1191
- import path2 from "path";
1192
- var SYNC_INSTALL_MARKERS = [
1193
- "node_modules",
1194
- ".pnp.cjs",
1195
- ".pnp.loader.mjs"
1196
- ];
1197
- var LOCAL_SYNC_TOOL_PATTERN = /(^|[\s;&|()])(?:tsx|wp-scripts)(?=($|[\s;&|()]))/u;
1198
- var CAPTURED_SYNC_OUTPUT_MAX_BUFFER = 16 * 1024 * 1024;
1199
- function resolveSyncExecutionTarget(subcommand) {
1200
- if (!subcommand) {
1201
- return "default";
1202
- }
1203
- if (subcommand === "ai") {
1204
- return "ai";
1205
- }
1206
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown sync subcommand "${subcommand}". Expected one of: "ai".`);
1207
- }
1208
- function getSyncRootError(cwd) {
1209
- return createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.OUTSIDE_PROJECT_ROOT, `No generated wp-typia project root was found at ${cwd}. Run \`wp-typia sync\` from a scaffolded project or official workspace root that already contains generated sync scripts. If you expected this directory to work, cd into the scaffold root first or rerun the scaffold before syncing.`);
1210
- }
1211
- function resolveSyncProjectContext(cwd) {
1212
- const packageJsonPath = path2.join(cwd, "package.json");
1213
- if (!fs3.existsSync(packageJsonPath)) {
1214
- throw getSyncRootError(cwd);
1215
- }
1216
- const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
1217
- const scripts = packageJson.scripts ?? {};
1218
- const syncScripts = {
1219
- sync: typeof scripts.sync === "string" ? {
1220
- command: scripts.sync,
1221
- scriptName: "sync"
1222
- } : undefined,
1223
- "sync-ai": typeof scripts["sync-ai"] === "string" ? {
1224
- command: scripts["sync-ai"],
1225
- scriptName: "sync-ai"
1226
- } : typeof scripts["sync-wordpress-ai"] === "string" ? {
1227
- command: scripts["sync-wordpress-ai"],
1228
- scriptName: "sync-wordpress-ai"
1229
- } : undefined,
1230
- "sync-rest": typeof scripts["sync-rest"] === "string" ? {
1231
- command: scripts["sync-rest"],
1232
- scriptName: "sync-rest"
1233
- } : undefined,
1234
- "sync-types": typeof scripts["sync-types"] === "string" ? {
1235
- command: scripts["sync-types"],
1236
- scriptName: "sync-types"
1237
- } : undefined
1238
- };
1239
- return {
1240
- cwd,
1241
- packageJsonPath,
1242
- packageManager: inferPackageManagerId(cwd, packageJson.packageManager),
1243
- scripts: syncScripts
1244
- };
1245
- }
1246
- function findInstalledDependencyMarkerDir(projectDir) {
1247
- let currentDir = path2.resolve(projectDir);
1248
- while (true) {
1249
- if (SYNC_INSTALL_MARKERS.some((marker) => fs3.existsSync(path2.join(currentDir, marker)))) {
1250
- return currentDir;
1251
- }
1252
- const parentDir = path2.dirname(currentDir);
1253
- if (parentDir === currentDir) {
1254
- return null;
1255
- }
1256
- currentDir = parentDir;
1257
- }
1258
- }
1259
- function scriptsLikelyNeedInstalledDependencies(project, target) {
1260
- const candidateScripts = target === "ai" ? [project.scripts["sync-ai"]] : project.scripts.sync ? [project.scripts.sync] : [
1261
- project.scripts["sync-types"],
1262
- project.scripts["sync-rest"],
1263
- project.scripts["sync-ai"]
1264
- ];
1265
- return candidateScripts.some((script) => script !== undefined && LOCAL_SYNC_TOOL_PATTERN.test(script.command));
1266
- }
1267
- function assertSyncDependenciesInstalled(project, target) {
1268
- if (!scriptsLikelyNeedInstalledDependencies(project, target)) {
1269
- return;
1270
- }
1271
- const markerDir = findInstalledDependencyMarkerDir(project.cwd);
1272
- if (markerDir) {
1273
- return;
1274
- }
1275
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.DEPENDENCIES_NOT_INSTALLED, `Project dependencies have not been installed yet. Run \`${formatInstallCommand(project.packageManager)}\` from the project root before \`wp-typia sync\`. The generated sync scripts rely on local tools such as \`tsx\`.`);
1276
- }
1277
- function getPackageManagerRunInvocation(packageManager, scriptName, extraArgs) {
1278
- switch (packageManager) {
1279
- case "bun":
1280
- return { args: ["run", scriptName, ...extraArgs], command: "bun" };
1281
- case "npm":
1282
- return {
1283
- args: [
1284
- "run",
1285
- scriptName,
1286
- ...extraArgs.length > 0 ? ["--", ...extraArgs] : []
1287
- ],
1288
- command: "npm"
1289
- };
1290
- case "pnpm":
1291
- return { args: ["run", scriptName, ...extraArgs], command: "pnpm" };
1292
- case "yarn":
1293
- return { args: ["run", scriptName, ...extraArgs], command: "yarn" };
1294
- }
1295
- }
1296
- function createSyncPlannedCommand(project, scriptName, extraArgs) {
1297
- const script = project.scripts[scriptName];
1298
- if (!script) {
1299
- return null;
1300
- }
1301
- const invocation = getPackageManagerRunInvocation(project.packageManager, script.scriptName, extraArgs);
1302
- return {
1303
- args: invocation.args,
1304
- command: invocation.command,
1305
- displayCommand: formatRunScript(project.packageManager, script.scriptName, extraArgs.join(" ")),
1306
- scriptName: script.scriptName
1307
- };
1308
- }
1309
- function buildSyncPlannedCommands(project, extraArgs, target) {
1310
- if (target === "ai") {
1311
- const syncAiCommand2 = createSyncPlannedCommand(project, "sync-ai", extraArgs);
1312
- if (!syncAiCommand2) {
1313
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.CONFIGURATION_MISSING, `Expected ${project.packageJsonPath} to define a \`sync-ai\` script for \`wp-typia sync ai\`.`);
1314
- }
1315
- return [syncAiCommand2];
1291
+ // src/runtime-output/print.ts
1292
+ function printCompletionPayload(payload, options = {}) {
1293
+ const printLine = options.printLine ?? console.log;
1294
+ const warnLine = options.warnLine ?? printLine;
1295
+ for (const line of payload.preambleLines ?? []) {
1296
+ printLine(line);
1316
1297
  }
1317
- if (project.scripts.sync) {
1318
- return [createSyncPlannedCommand(project, "sync", extraArgs)];
1298
+ for (const warning of payload.warningLines ?? []) {
1299
+ warnLine(formatOutputMarker("warning", warning, options.markerOptions));
1319
1300
  }
1320
- const syncTypesCommand = createSyncPlannedCommand(project, "sync-types", extraArgs);
1321
- if (!syncTypesCommand) {
1322
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.CONFIGURATION_MISSING, `Expected ${project.packageJsonPath} to define either a \`sync\` or \`sync-types\` script.`);
1301
+ const hasDetails = (payload.summaryLines?.length ?? 0) > 0 || (payload.nextSteps?.length ?? 0) > 0 || (payload.optionalLines?.length ?? 0) > 0 || Boolean(payload.optionalNote);
1302
+ const hasLeadingContext = (payload.preambleLines?.length ?? 0) > 0 || (payload.warningLines?.length ?? 0) > 0;
1303
+ printLine(hasLeadingContext && hasDetails ? `
1304
+ ${payload.title}` : payload.title);
1305
+ for (const line of payload.summaryLines ?? []) {
1306
+ printLine(line);
1323
1307
  }
1324
- const plannedCommands = [syncTypesCommand];
1325
- const syncRestCommand = createSyncPlannedCommand(project, "sync-rest", extraArgs);
1326
- if (syncRestCommand) {
1327
- plannedCommands.push(syncRestCommand);
1308
+ if ((payload.nextSteps?.length ?? 0) > 0) {
1309
+ printLine("Next steps:");
1310
+ for (const step of payload.nextSteps ?? []) {
1311
+ printLine(` ${step}`);
1312
+ }
1328
1313
  }
1329
- const syncAiCommand = createSyncPlannedCommand(project, "sync-ai", extraArgs);
1330
- if (syncAiCommand) {
1331
- plannedCommands.push(syncAiCommand);
1314
+ if ((payload.optionalLines?.length ?? 0) > 0) {
1315
+ printLine(`
1316
+ ${payload.optionalTitle ?? "Optional:"}`);
1317
+ for (const step of payload.optionalLines ?? []) {
1318
+ printLine(` ${step}`);
1319
+ }
1332
1320
  }
1333
- return plannedCommands;
1334
- }
1335
- function runProjectScript(project, plannedCommand, options) {
1336
- const result = spawnSync(plannedCommand.command, plannedCommand.args, {
1337
- cwd: project.cwd,
1338
- encoding: options.captureOutput ? "utf8" : undefined,
1339
- ...options.captureOutput ? { maxBuffer: CAPTURED_SYNC_OUTPUT_MAX_BUFFER } : {},
1340
- shell: process.platform === "win32",
1341
- stdio: options.captureOutput ? "pipe" : "inherit"
1342
- });
1343
- const stderr = options.captureOutput && typeof result.stderr === "string" ? result.stderr : undefined;
1344
- const stdout = options.captureOutput && typeof result.stdout === "string" ? result.stdout : undefined;
1345
- if (result.error || result.status !== 0) {
1346
- throw new Error(`\`${plannedCommand.displayCommand}\` failed.`, {
1347
- cause: result.error ?? (stderr ? new Error(stderr.trim()) : undefined)
1348
- });
1321
+ if (payload.optionalNote) {
1322
+ printLine(`Note: ${payload.optionalNote}`);
1349
1323
  }
1350
- return {
1351
- ...plannedCommand,
1352
- exitCode: result.status ?? 0,
1353
- ...stderr !== undefined ? { stderr } : {},
1354
- ...stdout !== undefined ? { stdout } : {}
1355
- };
1356
1324
  }
1357
- async function executeSyncCommand({
1358
- captureOutput = false,
1359
- check = false,
1360
- cwd,
1361
- dryRun = false,
1362
- target = "default"
1363
- }) {
1364
- const project = resolveSyncProjectContext(cwd);
1365
- const extraArgs = check ? ["--check"] : [];
1366
- const plannedCommands = buildSyncPlannedCommands(project, extraArgs, target);
1367
- const result = {
1368
- check,
1369
- dryRun,
1370
- packageJsonPath: project.packageJsonPath,
1371
- packageManager: project.packageManager,
1372
- plannedCommands,
1373
- projectDir: project.cwd,
1374
- target
1375
- };
1376
- if (dryRun) {
1377
- return result;
1378
- }
1379
- assertSyncDependenciesInstalled(project, target);
1380
- result.executedCommands = plannedCommands.map((plannedCommand) => runProjectScript(project, plannedCommand, {
1381
- captureOutput
1382
- }));
1383
- return result;
1325
+ // src/runtime-capabilities.ts
1326
+ function isInteractiveTerminal({
1327
+ stdin = process.stdin,
1328
+ stdout = process.stdout,
1329
+ term = process.env.TERM
1330
+ } = {}) {
1331
+ return Boolean(stdin?.isTTY) && Boolean(stdout?.isTTY) && term !== "dumb";
1332
+ }
1333
+ function supportsInteractiveTui(options = {}) {
1334
+ const hasBunRuntime = options.hasBunRuntime ?? typeof Bun !== "undefined";
1335
+ return hasBunRuntime && isInteractiveTerminal(options);
1384
1336
  }
1385
1337
 
1386
- // src/runtime-bridge.ts
1387
- var loadCliAddRuntime = () => import("./cli-add-1xvw17yg.js");
1338
+ // src/runtime-bridge-shared.ts
1388
1339
  var loadCliDiagnosticsRuntime = () => import("./cli-diagnostics-5dvztm7q.js");
1389
- var loadCliDoctorRuntime = () => import("./cli-doctor-bjv6z74k.js");
1390
- var loadCliInitRuntime = () => import("./cli-init-zdfrmp3y.js");
1391
- var loadCliPromptRuntime = () => import("./cli-prompt-614tq57c.js");
1392
- var loadCliScaffoldRuntime = () => import("./cli-scaffold-pbb67zxg.js");
1393
- var loadCliTemplatesRuntime = () => import("./cli-templates-hc71dfc2.js");
1394
- var loadCreateTemplateValidationRuntime = () => import("./create-template-validation-7k2752mz.js");
1395
- var loadMigrationsRuntime = () => import("./migrations-ads3j14z.js");
1396
1340
  async function wrapCliCommandError(command, error) {
1397
1341
  const { createCliCommandError } = await loadCliDiagnosticsRuntime();
1398
1342
  return createCliCommandError({ command, error });
@@ -1406,6 +1350,15 @@ function shouldWrapCliCommandError(options) {
1406
1350
  }
1407
1351
  return true;
1408
1352
  }
1353
+ function emitCompletion(payload, options) {
1354
+ if (options.emitOutput) {
1355
+ printCompletionPayload(payload, {
1356
+ printLine: options.printLine,
1357
+ warnLine: options.warnLine
1358
+ });
1359
+ }
1360
+ return payload;
1361
+ }
1409
1362
  function pushFlag(argv, name, value) {
1410
1363
  if (value === undefined || value === null || value === false) {
1411
1364
  return;
@@ -1416,6 +1369,10 @@ function pushFlag(argv, name, value) {
1416
1369
  }
1417
1370
  argv.push(`--${name}`, String(value));
1418
1371
  }
1372
+
1373
+ // src/runtime-bridge-add.ts
1374
+ var loadCliAddRuntime = () => import("./cli-add-8rvmezy0.js");
1375
+ var loadCliPromptRuntime = () => import("./cli-prompt-614tq57c.js");
1419
1376
  async function executeWorkspaceAddWithOptionalDryRun(options) {
1420
1377
  const simulated = options.dryRun ? await simulateWorkspaceAddDryRun({
1421
1378
  cwd: options.cwd,
@@ -1459,6 +1416,72 @@ async function executePlannedAddKind(kind, executionContext, context) {
1459
1416
  const plan = await getAddKindExecutionPlan(kind, executionContext);
1460
1417
  return executePreparedAddKind(kind, context, plan);
1461
1418
  }
1419
+ async function executeAddCommand({
1420
+ cwd,
1421
+ emitOutput = true,
1422
+ flags,
1423
+ interactive,
1424
+ kind,
1425
+ name,
1426
+ printLine = console.log,
1427
+ prompt,
1428
+ warnLine = console.warn
1429
+ }) {
1430
+ let activePrompt;
1431
+ const dryRun = Boolean(flags["dry-run"]);
1432
+ try {
1433
+ const addRuntime = await loadCliAddRuntime();
1434
+ const isInteractiveSession = interactive ?? isInteractiveTerminal();
1435
+ if (!kind) {
1436
+ if (shouldPrintMissingAddKindHelp({ emitOutput })) {
1437
+ printLine(addRuntime.formatAddHelpText());
1438
+ }
1439
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, formatMissingAddKindDetailLine());
1440
+ }
1441
+ if (!isAddKindId(kind)) {
1442
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown add kind "${kind}". Expected one of: ${formatAddKindList()}.`);
1443
+ }
1444
+ if (dryRun && !supportsAddKindDryRun(kind)) {
1445
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `\`wp-typia add ${kind}\` does not support \`--dry-run\` yet.`);
1446
+ }
1447
+ const executionContext = {
1448
+ addRuntime,
1449
+ cwd,
1450
+ flags,
1451
+ getOrCreatePrompt: async () => {
1452
+ if (activePrompt) {
1453
+ return activePrompt;
1454
+ }
1455
+ const { createReadlinePrompt } = await loadCliPromptRuntime();
1456
+ activePrompt = prompt ?? createReadlinePrompt();
1457
+ return activePrompt;
1458
+ },
1459
+ isInteractiveSession,
1460
+ name,
1461
+ warnLine
1462
+ };
1463
+ return await executePlannedAddKind(kind, executionContext, {
1464
+ cwd,
1465
+ dryRun,
1466
+ emitOutput,
1467
+ printLine
1468
+ });
1469
+ } catch (error) {
1470
+ if (!shouldWrapCliCommandError({ emitOutput })) {
1471
+ throw error;
1472
+ }
1473
+ throw await wrapCliCommandError("add", error);
1474
+ } finally {
1475
+ if (activePrompt && activePrompt !== prompt) {
1476
+ activePrompt.close();
1477
+ }
1478
+ }
1479
+ }
1480
+ // src/runtime-bridge-create.ts
1481
+ var loadCliPromptRuntime2 = () => import("./cli-prompt-614tq57c.js");
1482
+ var loadCliScaffoldRuntime = () => import("./cli-scaffold-b1ex2y80.js");
1483
+ var loadCliTemplatesRuntime = () => import("./cli-templates-hc71dfc2.js");
1484
+ var loadCreateTemplateValidationRuntime = () => import("./create-template-validation-rtec5sng.js");
1462
1485
  var PACKAGE_MANAGER_PROMPT_OPTIONS = [
1463
1486
  { label: "npm", value: "npm", hint: "Use npm" },
1464
1487
  { label: "pnpm", value: "pnpm", hint: "Use pnpm" },
@@ -1485,15 +1508,6 @@ var BOOLEAN_PROMPT_OPTIONS = [
1485
1508
  { label: "Yes", value: "yes", hint: "Enable this option" },
1486
1509
  { label: "No", value: "no", hint: "Keep the default disabled state" }
1487
1510
  ];
1488
- function emitCompletion(payload, options) {
1489
- if (options.emitOutput) {
1490
- printCompletionPayload(payload, {
1491
- printLine: options.printLine,
1492
- warnLine: options.warnLine
1493
- });
1494
- }
1495
- return payload;
1496
- }
1497
1511
  async function executeCreateCommand({
1498
1512
  projectDir,
1499
1513
  cwd,
@@ -1514,7 +1528,7 @@ async function executeCreateCommand({
1514
1528
  { runScaffoldFlow },
1515
1529
  { getTemplateSelectOptions }
1516
1530
  ] = await Promise.all([
1517
- loadCliPromptRuntime(),
1531
+ loadCliPromptRuntime2(),
1518
1532
  loadCliScaffoldRuntime(),
1519
1533
  loadCliTemplatesRuntime()
1520
1534
  ]);
@@ -1583,100 +1597,24 @@ async function executeCreateCommand({
1583
1597
  activePrompt.close();
1584
1598
  }
1585
1599
  }
1586
- }
1587
- async function executeAddCommand({
1588
- cwd,
1589
- emitOutput = true,
1590
- flags,
1591
- interactive,
1592
- kind,
1593
- name,
1594
- printLine = console.log,
1595
- prompt,
1596
- warnLine = console.warn
1597
- }) {
1598
- let activePrompt;
1599
- const dryRun = Boolean(flags["dry-run"]);
1600
- try {
1601
- const addRuntime = await loadCliAddRuntime();
1602
- const isInteractiveSession = interactive ?? isInteractiveTerminal();
1603
- if (!kind) {
1604
- if (emitOutput) {
1605
- printLine(addRuntime.formatAddHelpText());
1606
- }
1607
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, `\`wp-typia add\` requires <kind>. Usage: wp-typia add ${formatAddKindUsagePlaceholder()} ...`);
1608
- }
1609
- if (!isAddKindId(kind)) {
1610
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown add kind "${kind}". Expected one of: ${formatAddKindList()}.`);
1611
- }
1612
- if (dryRun && !supportsAddKindDryRun(kind)) {
1613
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `\`wp-typia add ${kind}\` does not support \`--dry-run\` yet.`);
1614
- }
1615
- const executionContext = {
1616
- addRuntime,
1617
- cwd,
1618
- flags,
1619
- getOrCreatePrompt: async () => {
1620
- if (activePrompt) {
1621
- return activePrompt;
1622
- }
1623
- const { createReadlinePrompt } = await loadCliPromptRuntime();
1624
- activePrompt = prompt ?? createReadlinePrompt();
1625
- return activePrompt;
1626
- },
1627
- isInteractiveSession,
1628
- name,
1629
- warnLine
1630
- };
1631
- return await executePlannedAddKind(kind, executionContext, {
1632
- cwd,
1633
- dryRun,
1634
- emitOutput,
1635
- printLine
1636
- });
1637
- } catch (error) {
1638
- if (!shouldWrapCliCommandError({ emitOutput })) {
1639
- throw error;
1640
- }
1641
- throw await wrapCliCommandError("add", error);
1642
- } finally {
1643
- if (activePrompt && activePrompt !== prompt) {
1644
- activePrompt.close();
1645
- }
1646
- }
1647
- }
1648
- async function executeTemplatesCommand({ flags }, printLine = console.log) {
1649
- const {
1650
- formatTemplateDetails,
1651
- formatTemplateFeatures,
1652
- formatTemplateSummary,
1653
- getTemplateById,
1654
- listTemplates
1655
- } = await loadCliTemplatesRuntime();
1656
- const subcommand = flags.subcommand ?? "list";
1657
- if (subcommand === "list") {
1658
- for (const template of listTemplates()) {
1659
- printBlock([formatTemplateSummary(template), formatTemplateFeatures(template)], printLine);
1660
- }
1661
- return;
1662
- }
1663
- if (subcommand === "inspect") {
1664
- if (!flags.id) {
1665
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, "`wp-typia templates inspect` requires <template-id>.");
1666
- }
1667
- const template = getTemplateById(flags.id);
1668
- if (!template) {
1669
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unknown template "${flags.id}".`);
1670
- }
1671
- printBlock([formatTemplateDetails(template)], printLine);
1672
- return;
1600
+ }
1601
+ // src/runtime-bridge-doctor.ts
1602
+ var loadCliDoctorRuntime = () => import("./cli-doctor-5m6xyx9q.js");
1603
+ async function executeDoctorCommand(cwd) {
1604
+ try {
1605
+ const { runDoctor } = await loadCliDoctorRuntime();
1606
+ await runDoctor(cwd);
1607
+ } catch (error) {
1608
+ throw await wrapCliCommandError("doctor", error);
1673
1609
  }
1674
- throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown templates subcommand "${subcommand}". Expected list or inspect.`);
1675
1610
  }
1611
+ // src/runtime-bridge-init.ts
1612
+ import path2 from "path";
1613
+ var loadCliInitRuntime = () => import("./cli-init-qv3zxmvc.js");
1676
1614
  async function executeInitCommand({ apply, cwd, packageManager, projectDir }, options = {}) {
1677
1615
  try {
1678
1616
  const { runInitCommand } = await loadCliInitRuntime();
1679
- const resolvedProjectDir = projectDir ? (await import("path")).resolve(cwd, projectDir) : cwd;
1617
+ const resolvedProjectDir = projectDir ? path2.resolve(cwd, projectDir) : cwd;
1680
1618
  const plan = await runInitCommand({
1681
1619
  apply,
1682
1620
  packageManager,
@@ -1697,14 +1635,8 @@ async function executeInitCommand({ apply, cwd, packageManager, projectDir }, op
1697
1635
  throw await wrapCliCommandError("init", error);
1698
1636
  }
1699
1637
  }
1700
- async function executeDoctorCommand(cwd) {
1701
- try {
1702
- const { runDoctor } = await loadCliDoctorRuntime();
1703
- await runDoctor(cwd);
1704
- } catch (error) {
1705
- throw await wrapCliCommandError("doctor", error);
1706
- }
1707
- }
1638
+ // src/runtime-bridge-migrate.ts
1639
+ var loadMigrationsRuntime = () => import("./migrations-7g9rag5d.js");
1708
1640
  async function executeMigrateCommand({
1709
1641
  command,
1710
1642
  cwd,
@@ -1712,12 +1644,17 @@ async function executeMigrateCommand({
1712
1644
  prompt,
1713
1645
  renderLine
1714
1646
  }) {
1715
- const { formatMigrationHelpText, parseMigrationArgs, runMigrationCommand } = await loadMigrationsRuntime();
1716
- if (!command) {
1717
- console.log(formatMigrationHelpText());
1718
- return;
1719
- }
1720
1647
  try {
1648
+ const { formatMigrationHelpText, parseMigrationArgs, runMigrationCommand } = await loadMigrationsRuntime();
1649
+ if (!command) {
1650
+ const helpText = formatMigrationHelpText();
1651
+ if (renderLine) {
1652
+ renderLine(helpText);
1653
+ } else {
1654
+ console.log(helpText);
1655
+ }
1656
+ return;
1657
+ }
1721
1658
  const argv = [command];
1722
1659
  pushFlag(argv, "all", flags.all);
1723
1660
  pushFlag(argv, "force", flags.force);
@@ -1757,11 +1694,246 @@ async function executeMigrateCommand({
1757
1694
  throw await wrapCliCommandError("migrate", error);
1758
1695
  }
1759
1696
  }
1697
+ // src/runtime-bridge-templates.ts
1698
+ var loadCliTemplatesRuntime2 = () => import("./cli-templates-hc71dfc2.js");
1699
+ async function executeTemplatesCommand({ flags }, printLine = console.log) {
1700
+ const {
1701
+ formatTemplateDetails,
1702
+ formatTemplateFeatures,
1703
+ formatTemplateSummary,
1704
+ getTemplateById,
1705
+ listTemplates
1706
+ } = await loadCliTemplatesRuntime2();
1707
+ const subcommand = flags.subcommand ?? "list";
1708
+ if (subcommand === "list") {
1709
+ for (const template of listTemplates()) {
1710
+ printBlock(printLine, [formatTemplateSummary(template), formatTemplateFeatures(template)]);
1711
+ }
1712
+ return;
1713
+ }
1714
+ if (subcommand === "inspect") {
1715
+ if (!flags.id) {
1716
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT, "`wp-typia templates inspect` requires <template-id>.");
1717
+ }
1718
+ const template = getTemplateById(flags.id);
1719
+ if (!template) {
1720
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unknown template "${flags.id}".`);
1721
+ }
1722
+ printBlock(printLine, [formatTemplateDetails(template)]);
1723
+ return;
1724
+ }
1725
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown templates subcommand "${subcommand}". Expected list or inspect.`);
1726
+ }
1760
1727
  async function listTemplatesForRuntime() {
1761
- const { listTemplates } = await loadCliTemplatesRuntime();
1728
+ const { listTemplates } = await loadCliTemplatesRuntime2();
1762
1729
  return listTemplates();
1763
1730
  }
1764
-
1731
+ // src/runtime-bridge-sync.ts
1732
+ import { spawnSync } from "child_process";
1733
+ import fs3 from "fs";
1734
+ import path3 from "path";
1735
+ var SYNC_INSTALL_MARKERS = [
1736
+ "node_modules",
1737
+ ".pnp.cjs",
1738
+ ".pnp.loader.mjs"
1739
+ ];
1740
+ var LOCAL_SYNC_TOOL_PATTERN = /(^|[\s;&|()])(?:tsx|wp-scripts)(?=($|[\s;&|()]))/u;
1741
+ var CAPTURED_SYNC_OUTPUT_MAX_BUFFER = 16 * 1024 * 1024;
1742
+ function resolveSyncExecutionTarget(subcommand) {
1743
+ if (!subcommand) {
1744
+ return "default";
1745
+ }
1746
+ if (subcommand === "ai") {
1747
+ return "ai";
1748
+ }
1749
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_COMMAND, `Unknown sync subcommand "${subcommand}". Expected one of: "ai".`);
1750
+ }
1751
+ function getSyncRootError(cwd) {
1752
+ return createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.OUTSIDE_PROJECT_ROOT, `No generated wp-typia project root was found at ${cwd}. Run \`wp-typia sync\` from a scaffolded project or official workspace root that already contains generated sync scripts. If you expected this directory to work, cd into the scaffold root first or rerun the scaffold before syncing.`);
1753
+ }
1754
+ function readSyncPackageJson(packageJsonPath) {
1755
+ const source = fs3.readFileSync(packageJsonPath, "utf8");
1756
+ try {
1757
+ return JSON.parse(source);
1758
+ } catch (error) {
1759
+ const message = error instanceof Error ? error.message : String(error);
1760
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, `Unable to parse ${packageJsonPath}: ${message}`, error instanceof Error ? { cause: error } : undefined);
1761
+ }
1762
+ }
1763
+ function resolveSyncProjectContext(cwd) {
1764
+ const packageJsonPath = path3.join(cwd, "package.json");
1765
+ if (!fs3.existsSync(packageJsonPath)) {
1766
+ throw getSyncRootError(cwd);
1767
+ }
1768
+ const packageJson = readSyncPackageJson(packageJsonPath);
1769
+ const scripts = packageJson.scripts ?? {};
1770
+ const syncScripts = {
1771
+ sync: typeof scripts.sync === "string" ? {
1772
+ command: scripts.sync,
1773
+ scriptName: "sync"
1774
+ } : undefined,
1775
+ "sync-ai": typeof scripts["sync-ai"] === "string" ? {
1776
+ command: scripts["sync-ai"],
1777
+ scriptName: "sync-ai"
1778
+ } : typeof scripts["sync-wordpress-ai"] === "string" ? {
1779
+ command: scripts["sync-wordpress-ai"],
1780
+ scriptName: "sync-wordpress-ai"
1781
+ } : undefined,
1782
+ "sync-rest": typeof scripts["sync-rest"] === "string" ? {
1783
+ command: scripts["sync-rest"],
1784
+ scriptName: "sync-rest"
1785
+ } : undefined,
1786
+ "sync-types": typeof scripts["sync-types"] === "string" ? {
1787
+ command: scripts["sync-types"],
1788
+ scriptName: "sync-types"
1789
+ } : undefined
1790
+ };
1791
+ return {
1792
+ cwd,
1793
+ packageJsonPath,
1794
+ packageManager: inferPackageManagerId(cwd, packageJson.packageManager),
1795
+ scripts: syncScripts
1796
+ };
1797
+ }
1798
+ function findInstalledDependencyMarkerDir(projectDir) {
1799
+ let currentDir = path3.resolve(projectDir);
1800
+ while (true) {
1801
+ if (SYNC_INSTALL_MARKERS.some((marker) => fs3.existsSync(path3.join(currentDir, marker)))) {
1802
+ return currentDir;
1803
+ }
1804
+ const parentDir = path3.dirname(currentDir);
1805
+ if (parentDir === currentDir) {
1806
+ return null;
1807
+ }
1808
+ currentDir = parentDir;
1809
+ }
1810
+ }
1811
+ function scriptsLikelyNeedInstalledDependencies(project, target) {
1812
+ const candidateScripts = target === "ai" ? [project.scripts["sync-ai"]] : project.scripts.sync ? [project.scripts.sync] : [
1813
+ project.scripts["sync-types"],
1814
+ project.scripts["sync-rest"],
1815
+ project.scripts["sync-ai"]
1816
+ ];
1817
+ return candidateScripts.some((script) => script !== undefined && LOCAL_SYNC_TOOL_PATTERN.test(script.command));
1818
+ }
1819
+ function assertSyncDependenciesInstalled(project, target) {
1820
+ if (!scriptsLikelyNeedInstalledDependencies(project, target)) {
1821
+ return;
1822
+ }
1823
+ const markerDir = findInstalledDependencyMarkerDir(project.cwd);
1824
+ if (markerDir) {
1825
+ return;
1826
+ }
1827
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.DEPENDENCIES_NOT_INSTALLED, `Project dependencies have not been installed yet. Run \`${formatInstallCommand(project.packageManager)}\` from the project root before \`wp-typia sync\`. The generated sync scripts rely on local tools such as \`tsx\`.`);
1828
+ }
1829
+ function getPackageManagerRunInvocation(packageManager, scriptName, extraArgs) {
1830
+ switch (packageManager) {
1831
+ case "bun":
1832
+ return { args: ["run", scriptName, ...extraArgs], command: "bun" };
1833
+ case "npm":
1834
+ return {
1835
+ args: [
1836
+ "run",
1837
+ scriptName,
1838
+ ...extraArgs.length > 0 ? ["--", ...extraArgs] : []
1839
+ ],
1840
+ command: "npm"
1841
+ };
1842
+ case "pnpm":
1843
+ return { args: ["run", scriptName, ...extraArgs], command: "pnpm" };
1844
+ case "yarn":
1845
+ return { args: ["run", scriptName, ...extraArgs], command: "yarn" };
1846
+ }
1847
+ }
1848
+ function createSyncPlannedCommand(project, scriptName, extraArgs) {
1849
+ const script = project.scripts[scriptName];
1850
+ if (!script) {
1851
+ return null;
1852
+ }
1853
+ const invocation = getPackageManagerRunInvocation(project.packageManager, script.scriptName, extraArgs);
1854
+ return {
1855
+ args: invocation.args,
1856
+ command: invocation.command,
1857
+ displayCommand: formatRunScript(project.packageManager, script.scriptName, extraArgs.join(" ")),
1858
+ scriptName: script.scriptName
1859
+ };
1860
+ }
1861
+ function buildSyncPlannedCommands(project, extraArgs, target) {
1862
+ if (target === "ai") {
1863
+ const syncAiCommand2 = createSyncPlannedCommand(project, "sync-ai", extraArgs);
1864
+ if (!syncAiCommand2) {
1865
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.CONFIGURATION_MISSING, `Expected ${project.packageJsonPath} to define a \`sync-ai\` script for \`wp-typia sync ai\`.`);
1866
+ }
1867
+ return [syncAiCommand2];
1868
+ }
1869
+ if (project.scripts.sync) {
1870
+ return [createSyncPlannedCommand(project, "sync", extraArgs)];
1871
+ }
1872
+ const syncTypesCommand = createSyncPlannedCommand(project, "sync-types", extraArgs);
1873
+ if (!syncTypesCommand) {
1874
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.CONFIGURATION_MISSING, `Expected ${project.packageJsonPath} to define either a \`sync\` or \`sync-types\` script.`);
1875
+ }
1876
+ const plannedCommands = [syncTypesCommand];
1877
+ const syncRestCommand = createSyncPlannedCommand(project, "sync-rest", extraArgs);
1878
+ if (syncRestCommand) {
1879
+ plannedCommands.push(syncRestCommand);
1880
+ }
1881
+ const syncAiCommand = createSyncPlannedCommand(project, "sync-ai", extraArgs);
1882
+ if (syncAiCommand) {
1883
+ plannedCommands.push(syncAiCommand);
1884
+ }
1885
+ return plannedCommands;
1886
+ }
1887
+ function runProjectScript(project, plannedCommand, options) {
1888
+ const result = spawnSync(plannedCommand.command, plannedCommand.args, {
1889
+ cwd: project.cwd,
1890
+ encoding: options.captureOutput ? "utf8" : undefined,
1891
+ ...options.captureOutput ? { maxBuffer: CAPTURED_SYNC_OUTPUT_MAX_BUFFER } : {},
1892
+ shell: process.platform === "win32",
1893
+ stdio: options.captureOutput ? "pipe" : "inherit"
1894
+ });
1895
+ const stderr = options.captureOutput && typeof result.stderr === "string" ? result.stderr : undefined;
1896
+ const stdout = options.captureOutput && typeof result.stdout === "string" ? result.stdout : undefined;
1897
+ if (result.error || result.status !== 0) {
1898
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.COMMAND_EXECUTION, `\`${plannedCommand.displayCommand}\` failed.`, {
1899
+ cause: result.error ?? (stderr ? new Error(stderr.trim()) : undefined)
1900
+ });
1901
+ }
1902
+ return {
1903
+ ...plannedCommand,
1904
+ exitCode: result.status ?? 0,
1905
+ ...stderr !== undefined ? { stderr } : {},
1906
+ ...stdout !== undefined ? { stdout } : {}
1907
+ };
1908
+ }
1909
+ async function executeSyncCommand({
1910
+ captureOutput = false,
1911
+ check = false,
1912
+ cwd,
1913
+ dryRun = false,
1914
+ target = "default"
1915
+ }) {
1916
+ const project = resolveSyncProjectContext(cwd);
1917
+ const extraArgs = check ? ["--check"] : [];
1918
+ const plannedCommands = buildSyncPlannedCommands(project, extraArgs, target);
1919
+ const result = {
1920
+ check,
1921
+ dryRun,
1922
+ packageJsonPath: project.packageJsonPath,
1923
+ packageManager: project.packageManager,
1924
+ plannedCommands,
1925
+ projectDir: project.cwd,
1926
+ target
1927
+ };
1928
+ if (dryRun) {
1929
+ return result;
1930
+ }
1931
+ assertSyncDependenciesInstalled(project, target);
1932
+ result.executedCommands = plannedCommands.map((plannedCommand) => runProjectScript(project, plannedCommand, {
1933
+ captureOutput
1934
+ }));
1935
+ return result;
1936
+ }
1765
1937
  // src/ui/lazy-flow.tsx
1766
1938
  var import_react33 = __toESM(require_react(), 1);
1767
1939
 
@@ -2279,10 +2451,7 @@ var createCommand = defineCommand({
2279
2451
  emitCliDiagnosticFailure(args, {
2280
2452
  code: CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT,
2281
2453
  command: "create",
2282
- detailLines: [
2283
- "`wp-typia create` requires <project-dir>.",
2284
- "`--dry-run` still needs a logical project directory name because wp-typia derives slugs, package names, and planned file paths from it."
2285
- ]
2454
+ detailLines: buildMissingCreateProjectDirDetailLines()
2286
2455
  });
2287
2456
  return;
2288
2457
  }
@@ -2344,7 +2513,7 @@ var doctorCommand = defineCommand({
2344
2513
  const prefersStructuredOutput = prefersStructuredCliOutput(args);
2345
2514
  if (prefersStructuredOutput) {
2346
2515
  const [{ getDoctorChecks }, { getDoctorFailureDetailLines }] = await Promise.all([
2347
- import("./cli-doctor-bjv6z74k.js"),
2516
+ import("./cli-doctor-5m6xyx9q.js"),
2348
2517
  import("./cli-diagnostics-5dvztm7q.js")
2349
2518
  ]);
2350
2519
  const checks = await getDoctorChecks(args.cwd);
@@ -2403,7 +2572,7 @@ var initCommand = defineCommand({
2403
2572
 
2404
2573
  // src/mcp.ts
2405
2574
  import fs4 from "fs/promises";
2406
- import path3 from "path";
2575
+ import path4 from "path";
2407
2576
 
2408
2577
  // ../../node_modules/.bun/@bunli+plugin-mcp@0.2.5+ef72ce197b058209/node_modules/@bunli/plugin-mcp/src/errors.ts
2409
2578
  class SchemaConversionError extends TaggedError("SchemaConversionError")() {
@@ -2422,7 +2591,7 @@ class McpToolsProviderError extends TaggedError("McpToolsProviderError")() {
2422
2591
  function jsonSchemaToZodSchema(schema, options = {}) {
2423
2592
  return convertSchema(schema, options, "$");
2424
2593
  }
2425
- function convertSchema(schema, options, path3) {
2594
+ function convertSchema(schema, options, path4) {
2426
2595
  const { coerce = true } = options;
2427
2596
  if (!schema || typeof schema !== "object") {
2428
2597
  return Result.ok(exports_external.unknown());
@@ -2437,49 +2606,49 @@ function convertSchema(schema, options, path3) {
2437
2606
  return Result.ok(exports_external.enum(enumValues));
2438
2607
  }
2439
2608
  const literals = enumValues.map((v) => exports_external.literal(v));
2440
- return unionFromSchemas(literals, path3);
2609
+ return unionFromSchemas(literals, path4);
2441
2610
  }
2442
2611
  }
2443
2612
  if (schema.anyOf && schema.anyOf.length > 0) {
2444
- const schemas = mapSchemas(schema.anyOf, options, `${path3}.anyOf`);
2613
+ const schemas = mapSchemas(schema.anyOf, options, `${path4}.anyOf`);
2445
2614
  if (Result.isError(schemas)) {
2446
2615
  return schemas;
2447
2616
  }
2448
- return unionFromSchemas(schemas.value, `${path3}.anyOf`);
2617
+ return unionFromSchemas(schemas.value, `${path4}.anyOf`);
2449
2618
  }
2450
2619
  if (schema.oneOf && schema.oneOf.length > 0) {
2451
- const schemas = mapSchemas(schema.oneOf, options, `${path3}.oneOf`);
2620
+ const schemas = mapSchemas(schema.oneOf, options, `${path4}.oneOf`);
2452
2621
  if (Result.isError(schemas)) {
2453
2622
  return schemas;
2454
2623
  }
2455
- return unionFromSchemas(schemas.value, `${path3}.oneOf`);
2624
+ return unionFromSchemas(schemas.value, `${path4}.oneOf`);
2456
2625
  }
2457
2626
  const schemaType = Array.isArray(schema.type) ? schema.type[0] : schema.type;
2458
2627
  switch (schemaType) {
2459
2628
  case "string":
2460
- return buildStringSchema(schema, path3);
2629
+ return buildStringSchema(schema, path4);
2461
2630
  case "number":
2462
2631
  case "integer":
2463
2632
  return Result.ok(buildNumberSchema(schema, coerce));
2464
2633
  case "boolean":
2465
2634
  return Result.ok(buildBooleanSchema());
2466
2635
  case "array":
2467
- return buildArraySchema(schema, options, path3);
2636
+ return buildArraySchema(schema, options, path4);
2468
2637
  case "object":
2469
- return buildObjectSchema(schema, options, path3);
2638
+ return buildObjectSchema(schema, options, path4);
2470
2639
  case "null":
2471
2640
  return Result.ok(exports_external.null());
2472
2641
  default:
2473
2642
  if (schema.properties) {
2474
- return buildObjectSchema(schema, options, path3);
2643
+ return buildObjectSchema(schema, options, path4);
2475
2644
  }
2476
2645
  if (schema.items) {
2477
- return buildArraySchema(schema, options, path3);
2646
+ return buildArraySchema(schema, options, path4);
2478
2647
  }
2479
2648
  return Result.ok(exports_external.unknown());
2480
2649
  }
2481
2650
  }
2482
- function buildStringSchema(schema, path3) {
2651
+ function buildStringSchema(schema, path4) {
2483
2652
  let zodSchema = exports_external.string();
2484
2653
  if (schema.minLength !== undefined) {
2485
2654
  zodSchema = zodSchema.min(schema.minLength);
@@ -2492,7 +2661,7 @@ function buildStringSchema(schema, path3) {
2492
2661
  const regexResult = Result.try({
2493
2662
  try: () => new RegExp(pattern),
2494
2663
  catch: (cause) => new SchemaConversionError({
2495
- path: path3,
2664
+ path: path4,
2496
2665
  message: `Invalid regex pattern "${pattern}"`,
2497
2666
  cause
2498
2667
  })
@@ -2549,19 +2718,19 @@ function buildNumberSchema(schema, coerce) {
2549
2718
  function buildBooleanSchema() {
2550
2719
  return exports_external.boolean();
2551
2720
  }
2552
- function buildArraySchema(schema, options, path3) {
2721
+ function buildArraySchema(schema, options, path4) {
2553
2722
  let itemSchema = exports_external.unknown();
2554
2723
  if (schema.items) {
2555
2724
  if (Array.isArray(schema.items)) {
2556
2725
  if (schema.items.length > 0) {
2557
- const itemResult = convertSchema(schema.items[0], options, `${path3}.items[0]`);
2726
+ const itemResult = convertSchema(schema.items[0], options, `${path4}.items[0]`);
2558
2727
  if (Result.isError(itemResult)) {
2559
2728
  return itemResult;
2560
2729
  }
2561
2730
  itemSchema = itemResult.value;
2562
2731
  }
2563
2732
  } else {
2564
- const itemResult = convertSchema(schema.items, options, `${path3}.items`);
2733
+ const itemResult = convertSchema(schema.items, options, `${path4}.items`);
2565
2734
  if (Result.isError(itemResult)) {
2566
2735
  return itemResult;
2567
2736
  }
@@ -2577,14 +2746,14 @@ function buildArraySchema(schema, options, path3) {
2577
2746
  }
2578
2747
  return Result.ok(zodSchema);
2579
2748
  }
2580
- function buildObjectSchema(schema, options, path3) {
2749
+ function buildObjectSchema(schema, options, path4) {
2581
2750
  if (!schema.properties) {
2582
2751
  return Result.ok(exports_external.record(exports_external.string(), exports_external.unknown()));
2583
2752
  }
2584
2753
  const shape = {};
2585
2754
  const requiredFields = new Set(schema.required || []);
2586
2755
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
2587
- const propResult = convertSchema(propSchema, options, `${path3}.properties.${propName}`);
2756
+ const propResult = convertSchema(propSchema, options, `${path4}.properties.${propName}`);
2588
2757
  if (Result.isError(propResult)) {
2589
2758
  return propResult;
2590
2759
  }
@@ -2599,10 +2768,10 @@ function buildObjectSchema(schema, options, path3) {
2599
2768
  }
2600
2769
  return Result.ok(exports_external.object(shape));
2601
2770
  }
2602
- function mapSchemas(schemas, options, path3) {
2771
+ function mapSchemas(schemas, options, path4) {
2603
2772
  const zodSchemas = [];
2604
2773
  for (let index = 0;index < schemas.length; index += 1) {
2605
- const converted = convertSchema(schemas[index], options, `${path3}[${index}]`);
2774
+ const converted = convertSchema(schemas[index], options, `${path4}[${index}]`);
2606
2775
  if (Result.isError(converted)) {
2607
2776
  return converted;
2608
2777
  }
@@ -2610,11 +2779,11 @@ function mapSchemas(schemas, options, path3) {
2610
2779
  }
2611
2780
  return Result.ok(zodSchemas);
2612
2781
  }
2613
- function unionFromSchemas(schemas, path3) {
2782
+ function unionFromSchemas(schemas, path4) {
2614
2783
  if (schemas.length === 0) {
2615
2784
  return Result.err(new SchemaConversionError({
2616
- path: path3,
2617
- message: `Cannot create union from an empty schema set at ${path3}`,
2785
+ path: path4,
2786
+ message: `Cannot create union from an empty schema set at ${path4}`,
2618
2787
  cause: new Error("Empty schema union")
2619
2788
  }));
2620
2789
  }
@@ -2937,7 +3106,7 @@ function getErrorCauseOptions(error) {
2937
3106
  return error instanceof Error ? { cause: error } : undefined;
2938
3107
  }
2939
3108
  async function readSchemaSource(cwd, source) {
2940
- const schemaPath = path3.resolve(cwd, source.path);
3109
+ const schemaPath = path4.resolve(cwd, source.path);
2941
3110
  const raw = await fs4.readFile(schemaPath, "utf8");
2942
3111
  let parsed;
2943
3112
  try {
@@ -2959,7 +3128,7 @@ async function readSchemaSource(cwd, source) {
2959
3128
  async function loadMcpToolGroups(cwd, schemaSources) {
2960
3129
  return Promise.all(schemaSources.map((source) => readSchemaSource(cwd, source)));
2961
3130
  }
2962
- async function syncMcpSchemas(cwd, schemaSources, outputDir = path3.join(cwd, ".bunli", "mcp")) {
3131
+ async function syncMcpSchemas(cwd, schemaSources, outputDir = path4.join(cwd, ".bunli", "mcp")) {
2963
3132
  const groups = await loadMcpToolGroups(cwd, schemaSources);
2964
3133
  const result = await generateMCPTypes({
2965
3134
  outputDir,
@@ -2982,7 +3151,7 @@ async function syncMcpSchemas(cwd, schemaSources, outputDir = path3.join(cwd, ".
2982
3151
  }
2983
3152
  }
2984
3153
  await fs4.mkdir(outputDir, { recursive: true });
2985
- await fs4.writeFile(path3.join(outputDir, "registry.json"), `${JSON.stringify(registry, null, 2)}
3154
+ await fs4.writeFile(path4.join(outputDir, "registry.json"), `${JSON.stringify(registry, null, 2)}
2986
3155
  `, "utf8");
2987
3156
  return {
2988
3157
  commandCount: registry.reduce((count, group) => count + group.tools.length, 0),
@@ -2992,12 +3161,31 @@ async function syncMcpSchemas(cwd, schemaSources, outputDir = path3.join(cwd, ".
2992
3161
  }
2993
3162
 
2994
3163
  // src/commands/mcp.ts
3164
+ var defaultPrintLine = (line) => {
3165
+ process.stdout.write(`${line}
3166
+ `);
3167
+ };
3168
+ function resolveMcpPrintLine(args) {
3169
+ return args.printLine ?? defaultPrintLine;
3170
+ }
3171
+ function printMcpToolGroupSummary(summary, printLine) {
3172
+ for (const group of summary) {
3173
+ printLine(`${group.namespace} (${group.toolCount})`);
3174
+ for (const tool of group.tools) {
3175
+ printLine(` - ${tool}`);
3176
+ }
3177
+ }
3178
+ }
3179
+ function printMcpSyncSummary(result, printLine) {
3180
+ printLine(`Synced ${result.commandCount} MCP tools across ${result.groups.length} namespaces into ${result.outputDir}.`);
3181
+ }
2995
3182
  var mcpCommand = defineCommand({
2996
3183
  defaultFormat: "json",
2997
3184
  description: "Inspect or sync schema-driven MCP metadata for wp-typia.",
2998
3185
  handler: async (args) => {
2999
3186
  const subcommand = args.positional[0] ?? "list";
3000
3187
  const prefersStructuredOutput = prefersStructuredCliOutput(args);
3188
+ const printLine = resolveMcpPrintLine(args);
3001
3189
  const userConfig = args.context?.store?.wpTypiaUserConfig && typeof args.context.store.wpTypiaUserConfig === "object" ? args.context.store.wpTypiaUserConfig : {};
3002
3190
  const schemaSources = getMcpSchemaSources(userConfig);
3003
3191
  if (schemaSources.length === 0) {
@@ -3022,12 +3210,7 @@ var mcpCommand = defineCommand({
3022
3210
  args.output({ groups: summary });
3023
3211
  return;
3024
3212
  }
3025
- for (const group of summary) {
3026
- console.log(`${group.namespace} (${group.toolCount})`);
3027
- for (const tool of group.tools) {
3028
- console.log(` - ${tool}`);
3029
- }
3030
- }
3213
+ printMcpToolGroupSummary(summary, printLine);
3031
3214
  return;
3032
3215
  }
3033
3216
  if (subcommand === "sync") {
@@ -3037,7 +3220,7 @@ var mcpCommand = defineCommand({
3037
3220
  args.output({ sync: result });
3038
3221
  return;
3039
3222
  }
3040
- console.log(`Synced ${result.commandCount} MCP tools across ${result.groups.length} namespaces into ${result.outputDir}.`);
3223
+ printMcpSyncSummary(result, printLine);
3041
3224
  return;
3042
3225
  }
3043
3226
  emitCliDiagnosticFailure(args, {
@@ -3221,4 +3404,4 @@ export {
3221
3404
  wpTypiaCommands
3222
3405
  };
3223
3406
 
3224
- //# debugId=C86915DD4AD0BB9C64756E2164756E21
3407
+ //# debugId=8B3272B9527B417864756E2164756E21