@wp-typia/project-tools 0.22.1 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/runtime/built-in-block-code-templates/interactivity.d.ts +1 -1
  2. package/dist/runtime/built-in-block-code-templates/interactivity.js +4 -2
  3. package/dist/runtime/cli-add-shared.d.ts +49 -0
  4. package/dist/runtime/cli-add-shared.js +204 -71
  5. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +5 -0
  6. package/dist/runtime/cli-add-workspace-ability-scaffold.js +392 -0
  7. package/dist/runtime/cli-add-workspace-ability-templates.d.ts +34 -0
  8. package/dist/runtime/cli-add-workspace-ability-templates.js +500 -0
  9. package/dist/runtime/cli-add-workspace-ability-types.d.ts +27 -0
  10. package/dist/runtime/cli-add-workspace-ability-types.js +14 -0
  11. package/dist/runtime/cli-add-workspace-ability.js +12 -852
  12. package/dist/runtime/cli-add-workspace-ai-scaffold.d.ts +21 -0
  13. package/dist/runtime/cli-add-workspace-ai-scaffold.js +91 -0
  14. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +119 -1
  15. package/dist/runtime/cli-add-workspace-ai-templates.d.ts +4 -0
  16. package/dist/runtime/cli-add-workspace-ai-templates.js +605 -0
  17. package/dist/runtime/cli-add-workspace-ai.js +15 -465
  18. package/dist/runtime/cli-add-workspace-assets.js +7 -4
  19. package/dist/runtime/cli-add-workspace.js +1 -19
  20. package/dist/runtime/cli-doctor-workspace-bindings.d.ts +11 -0
  21. package/dist/runtime/cli-doctor-workspace-bindings.js +134 -0
  22. package/dist/runtime/cli-doctor-workspace-blocks.d.ts +11 -0
  23. package/dist/runtime/cli-doctor-workspace-blocks.js +504 -0
  24. package/dist/runtime/cli-doctor-workspace-features.d.ts +11 -0
  25. package/dist/runtime/cli-doctor-workspace-features.js +383 -0
  26. package/dist/runtime/cli-doctor-workspace-package.d.ts +18 -0
  27. package/dist/runtime/cli-doctor-workspace-package.js +59 -0
  28. package/dist/runtime/cli-doctor-workspace-shared.d.ts +69 -0
  29. package/dist/runtime/cli-doctor-workspace-shared.js +87 -0
  30. package/dist/runtime/cli-doctor-workspace.js +25 -1062
  31. package/dist/runtime/scaffold-compatibility.d.ts +2 -0
  32. package/dist/runtime/scaffold-compatibility.js +2 -0
  33. package/dist/runtime/typia-llm.d.ts +37 -2
  34. package/dist/runtime/typia-llm.js +240 -3
  35. package/dist/runtime/workspace-inventory.js +24 -0
  36. package/package.json +3 -3
@@ -0,0 +1,21 @@
1
+ import type { ScaffoldCompatibilityPolicy } from "./scaffold-compatibility.js";
2
+ import type { WorkspaceProject } from "./workspace-project.js";
3
+ /**
4
+ * Inputs required to scaffold a generated AI feature into a workspace.
5
+ */
6
+ export interface ScaffoldAiFeatureWorkspaceOptions {
7
+ /** Kebab-case feature slug used for file paths and route ids. */
8
+ aiFeatureSlug: string;
9
+ /** Compatibility metadata applied to the generated workspace bootstrap. */
10
+ compatibilityPolicy: ScaffoldCompatibilityPolicy;
11
+ /** WordPress REST namespace used for generated feature routes. */
12
+ namespace: string;
13
+ /** Resolved workspace metadata and filesystem paths for the target project. */
14
+ workspace: WorkspaceProject;
15
+ }
16
+ /**
17
+ * Write generated AI feature sources and patch shared workspace anchors.
18
+ */
19
+ export declare function scaffoldAiFeatureWorkspace({ aiFeatureSlug, compatibilityPolicy, namespace, workspace, }: ScaffoldAiFeatureWorkspaceOptions): Promise<{
20
+ warnings: string[];
21
+ }>;
@@ -0,0 +1,91 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import { ensureBlockConfigCanAddRestManifests } from "./cli-add-block-legacy-validator.js";
4
+ import { buildAiFeatureConfigEntry, buildAiFeatureDataSource, buildAiFeatureSyncScriptSource, buildAiFeatureTypesSource, buildAiFeatureValidatorsSource, buildAiFeatureApiSource, } from "./cli-add-workspace-ai-source-emitters.js";
5
+ import { ensureAiFeatureBootstrapAnchors, ensureAiFeaturePackageScripts, ensureAiFeatureSyncProjectAnchors, ensureAiFeatureSyncRestAnchors, } from "./cli-add-workspace-ai-anchors.js";
6
+ import { buildAiFeaturePhpSource } from "./cli-add-workspace-ai-templates.js";
7
+ import { appendWorkspaceInventoryEntries } from "./workspace-inventory.js";
8
+ import { getWorkspaceBootstrapPath, patchFile, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
9
+ import { updatePluginHeaderCompatibility } from "./scaffold-compatibility.js";
10
+ import { toPascalCase, toTitleCase } from "./string-case.js";
11
+ import { syncAiFeatureRestArtifacts, syncAiFeatureSchemaArtifact, } from "./ai-feature-artifacts.js";
12
+ /**
13
+ * Write generated AI feature sources and patch shared workspace anchors.
14
+ */
15
+ export async function scaffoldAiFeatureWorkspace({ aiFeatureSlug, compatibilityPolicy, namespace, workspace, }) {
16
+ const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
17
+ const bootstrapPath = getWorkspaceBootstrapPath(workspace);
18
+ const packageJsonPath = path.join(workspace.projectDir, "package.json");
19
+ const syncAiScriptPath = path.join(workspace.projectDir, "scripts", "sync-ai-features.ts");
20
+ const syncProjectScriptPath = path.join(workspace.projectDir, "scripts", "sync-project.ts");
21
+ const syncRestScriptPath = path.join(workspace.projectDir, "scripts", "sync-rest-contracts.ts");
22
+ const aiFeatureDir = path.join(workspace.projectDir, "src", "ai-features", aiFeatureSlug);
23
+ const typesFilePath = path.join(aiFeatureDir, "api-types.ts");
24
+ const validatorsFilePath = path.join(aiFeatureDir, "api-validators.ts");
25
+ const apiFilePath = path.join(aiFeatureDir, "api.ts");
26
+ const dataFilePath = path.join(aiFeatureDir, "data.ts");
27
+ const phpFilePath = path.join(workspace.projectDir, "inc", "ai-features", `${aiFeatureSlug}.php`);
28
+ const mutationSnapshot = {
29
+ fileSources: await snapshotWorkspaceFiles([
30
+ blockConfigPath,
31
+ bootstrapPath,
32
+ packageJsonPath,
33
+ syncAiScriptPath,
34
+ syncProjectScriptPath,
35
+ syncRestScriptPath,
36
+ ]),
37
+ snapshotDirs: [],
38
+ targetPaths: [aiFeatureDir, phpFilePath, syncAiScriptPath],
39
+ };
40
+ try {
41
+ await fsp.mkdir(aiFeatureDir, { recursive: true });
42
+ await fsp.mkdir(path.dirname(phpFilePath), { recursive: true });
43
+ await ensureAiFeatureBootstrapAnchors(workspace);
44
+ await patchFile(bootstrapPath, (source) => updatePluginHeaderCompatibility(source, compatibilityPolicy));
45
+ const packageScriptChanges = await ensureAiFeaturePackageScripts(workspace);
46
+ await ensureAiFeatureSyncProjectAnchors(workspace);
47
+ await ensureAiFeatureSyncRestAnchors(workspace);
48
+ await fsp.writeFile(syncAiScriptPath, buildAiFeatureSyncScriptSource(), "utf8");
49
+ await fsp.writeFile(typesFilePath, buildAiFeatureTypesSource(aiFeatureSlug), "utf8");
50
+ await fsp.writeFile(validatorsFilePath, buildAiFeatureValidatorsSource(aiFeatureSlug), "utf8");
51
+ await fsp.writeFile(apiFilePath, buildAiFeatureApiSource(aiFeatureSlug), "utf8");
52
+ await fsp.writeFile(dataFilePath, buildAiFeatureDataSource(aiFeatureSlug), "utf8");
53
+ await fsp.writeFile(phpFilePath, buildAiFeaturePhpSource(aiFeatureSlug, namespace, workspace.workspace.phpPrefix, workspace.workspace.textDomain), "utf8");
54
+ const pascalCase = toPascalCase(aiFeatureSlug);
55
+ await syncAiFeatureRestArtifacts({
56
+ clientFile: `src/ai-features/${aiFeatureSlug}/api-client.ts`,
57
+ outputDir: path.join("src", "ai-features", aiFeatureSlug),
58
+ projectDir: workspace.projectDir,
59
+ typesFile: `src/ai-features/${aiFeatureSlug}/api-types.ts`,
60
+ validatorsFile: `src/ai-features/${aiFeatureSlug}/api-validators.ts`,
61
+ variables: {
62
+ namespace,
63
+ pascalCase,
64
+ slugKebabCase: aiFeatureSlug,
65
+ title: toTitleCase(aiFeatureSlug),
66
+ },
67
+ });
68
+ await syncAiFeatureSchemaArtifact({
69
+ aiSchemaFile: `src/ai-features/${aiFeatureSlug}/ai-schemas/feature-result.ai.schema.json`,
70
+ outputDir: path.join("src", "ai-features", aiFeatureSlug),
71
+ projectDir: workspace.projectDir,
72
+ });
73
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
74
+ aiFeatureEntries: [
75
+ buildAiFeatureConfigEntry(aiFeatureSlug, namespace),
76
+ ],
77
+ transformSource: ensureBlockConfigCanAddRestManifests,
78
+ });
79
+ return {
80
+ warnings: packageScriptChanges.addedProjectToolsDependency
81
+ ? [
82
+ "Added `@wp-typia/project-tools` to devDependencies for `sync-ai`. If this workspace was already installed, rerun your package manager install command before the first `wp-typia sync ai`.",
83
+ ]
84
+ : [],
85
+ };
86
+ }
87
+ catch (error) {
88
+ await rollbackWorkspaceMutation(mutationSnapshot);
89
+ throw error;
90
+ }
91
+ }
@@ -1,6 +1,6 @@
1
1
  import { quoteTsString } from "./cli-add-shared.js";
2
2
  import { buildAiFeatureEndpointManifest } from "./ai-feature-artifacts.js";
3
- import { OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY, renderScaffoldCompatibilityConfig, resolveScaffoldCompatibilityPolicy, } from "./scaffold-compatibility.js";
3
+ import { OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY, createScaffoldCompatibilityConfig, renderScaffoldCompatibilityConfig, resolveScaffoldCompatibilityPolicy, } from "./scaffold-compatibility.js";
4
4
  import { toPascalCase, toTitleCase } from "./string-case.js";
5
5
  function indentMultiline(source, prefix) {
6
6
  return source
@@ -79,6 +79,45 @@ export interface ${pascalCase}AiFeatureResponse {
79
79
  \tresult: ${pascalCase}AiFeatureResult;
80
80
  \ttelemetry: ${pascalCase}AiFeatureTelemetry;
81
81
  }
82
+
83
+ export type ${pascalCase}AiFeatureSupportProbeMode = 'request-time';
84
+
85
+ export type ${pascalCase}AiFeatureUnavailableErrorCode =
86
+ \t'ai_client_unavailable';
87
+
88
+ export type ${pascalCase}AiFeatureUnavailableReasonCode =
89
+ \t| 'missing-wordpress-ai-client'
90
+ \t| 'request-time-support-probe';
91
+
92
+ export interface ${pascalCase}AiFeatureSupportReason {
93
+ \tcode: ${pascalCase}AiFeatureUnavailableReasonCode;
94
+ \tlabel: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
95
+ \tmessage: string & tags.MinLength< 1 > & tags.MaxLength< 4000 >;
96
+ }
97
+
98
+ export interface ${pascalCase}AiFeatureSupportMetadata {
99
+ \tfeatureLabel: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
100
+ \tfeatureSlug: string & tags.MinLength< 1 > & tags.MaxLength< 160 >;
101
+ \tcompatibility: {
102
+ \t\thardMinimums: {
103
+ \t\t\tphp?: string;
104
+ \t\t\twordpress?: string;
105
+ \t\t};
106
+ \t\tmode: 'baseline' | 'optional' | 'required';
107
+ \t\toptionalFeatureIds: string[];
108
+ \t\toptionalFeatures: string[];
109
+ \t\trequiredFeatureIds: string[];
110
+ \t\trequiredFeatures: string[];
111
+ \t\truntimeGates: string[];
112
+ \t};
113
+ \tsupportProbe: {
114
+ \t\tendpointMethod: 'POST';
115
+ \t\tendpointPath: string & tags.MinLength< 1 > & tags.MaxLength< 200 >;
116
+ \t\tmode: ${pascalCase}AiFeatureSupportProbeMode;
117
+ \t\tunavailableErrorCode: ${pascalCase}AiFeatureUnavailableErrorCode;
118
+ \t};
119
+ \tunavailableReasons: ${pascalCase}AiFeatureSupportReason[];
120
+ }
82
121
  `;
83
122
  }
84
123
  /**
@@ -120,6 +159,8 @@ export const apiValidators = {
120
159
  */
121
160
  export function buildAiFeatureApiSource(aiFeatureSlug) {
122
161
  const pascalCase = toPascalCase(aiFeatureSlug);
162
+ const compatibility = createScaffoldCompatibilityConfig(resolveScaffoldCompatibilityPolicy(OPTIONAL_WORDPRESS_AI_CLIENT_COMPATIBILITY));
163
+ const title = toTitleCase(aiFeatureSlug);
123
164
  return `import {
124
165
  \tcallEndpoint,
125
166
  \tresolveRestRouteUrl,
@@ -127,6 +168,7 @@ export function buildAiFeatureApiSource(aiFeatureSlug) {
127
168
 
128
169
  import type {
129
170
  \t${pascalCase}AiFeatureRequest,
171
+ \t${pascalCase}AiFeatureSupportMetadata,
130
172
  } from './api-types';
131
173
  import {
132
174
  \trun${pascalCase}AiFeatureEndpoint,
@@ -153,6 +195,14 @@ function resolveRestNonce( fallback?: string ): string | undefined {
153
195
  \t\t: undefined;
154
196
  }
155
197
 
198
+ function isPlainObject( value: unknown ): value is Record< string, unknown > {
199
+ \treturn (
200
+ \t\t!! value &&
201
+ \t\ttypeof value === 'object' &&
202
+ \t\t! Array.isArray( value )
203
+ \t);
204
+ }
205
+
156
206
  export const aiFeatureRunEndpoint = {
157
207
  \t...run${pascalCase}AiFeatureEndpoint,
158
208
  \tbuildRequestOptions: () => {
@@ -168,6 +218,63 @@ export const aiFeatureRunEndpoint = {
168
218
  \t},
169
219
  };
170
220
 
221
+ export const aiFeatureSupportMetadata = {
222
+ \tcompatibility: ${JSON.stringify(compatibility, null, "\t")},
223
+ \tfeatureLabel: ${quoteTsString(title)},
224
+ \tfeatureSlug: ${quoteTsString(aiFeatureSlug)},
225
+ \tsupportProbe: {
226
+ \t\tendpointMethod: 'POST',
227
+ \t\tendpointPath: aiFeatureRunEndpoint.path,
228
+ \t\tmode: 'request-time',
229
+ \t\tunavailableErrorCode: 'ai_client_unavailable',
230
+ \t},
231
+ \tunavailableReasons: [
232
+ \t\t{
233
+ \t\t\tcode: 'missing-wordpress-ai-client',
234
+ \t\t\tlabel: 'WordPress AI Client unavailable',
235
+ \t\t\tmessage:
236
+ \t\t\t\t'This AI feature stays disabled until the WordPress AI Client is available on the site.',
237
+ \t\t},
238
+ \t\t{
239
+ \t\t\tcode: 'request-time-support-probe',
240
+ \t\t\tlabel: 'Support is checked at request time',
241
+ \t\t\tmessage:
242
+ \t\t\t\t'Support is verified when the feature runs, so editor and admin UIs should degrade gracefully when the site rejects the request.',
243
+ \t\t},
244
+ \t],
245
+ } satisfies ${pascalCase}AiFeatureSupportMetadata;
246
+
247
+ export function getAiFeatureSupportHintLines() {
248
+ \treturn aiFeatureSupportMetadata.unavailableReasons.map(
249
+ \t\t( reason ) => reason.message
250
+ \t);
251
+ }
252
+
253
+ export function isAiFeatureSupportUnavailableError( error: unknown ) {
254
+ \tif ( ! isPlainObject( error ) ) {
255
+ \t\treturn false;
256
+ \t}
257
+
258
+ \tconst data = isPlainObject( error.data ) ? error.data : undefined;
259
+ \treturn (
260
+ \t\terror.code === aiFeatureSupportMetadata.supportProbe.unavailableErrorCode ||
261
+ \t\tdata?.status === 501
262
+ \t);
263
+ }
264
+
265
+ export function resolveAiFeatureUnavailableMessage( error: unknown ) {
266
+ \tif (
267
+ \t\tisPlainObject( error ) &&
268
+ \t\ttypeof error.message === 'string' &&
269
+ \t\terror.message.length > 0
270
+ \t) {
271
+ \t\treturn error.message;
272
+ \t}
273
+
274
+ \treturn aiFeatureSupportMetadata.unavailableReasons[ 0 ]?.message ??
275
+ \t\t'This AI feature is currently unavailable.';
276
+ }
277
+
171
278
  export function runAiFeature( request: ${pascalCase}AiFeatureRequest ) {
172
279
  \treturn callEndpoint( aiFeatureRunEndpoint, request );
173
280
  }
@@ -189,6 +296,10 @@ import type {
189
296
  } from './api-types';
190
297
  import {
191
298
  \taiFeatureRunEndpoint,
299
+ \taiFeatureSupportMetadata,
300
+ \tgetAiFeatureSupportHintLines,
301
+ \tisAiFeatureSupportUnavailableError,
302
+ \tresolveAiFeatureUnavailableMessage,
192
303
  } from './api';
193
304
 
194
305
  export type UseRun${pascalCase}AiFeatureMutationOptions =
@@ -203,6 +314,13 @@ export function useRun${pascalCase}AiFeatureMutation(
203
314
  ) {
204
315
  \treturn useEndpointMutation( aiFeatureRunEndpoint, options );
205
316
  }
317
+
318
+ export {
319
+ \taiFeatureSupportMetadata,
320
+ \tgetAiFeatureSupportHintLines,
321
+ \tisAiFeatureSupportUnavailableError,
322
+ \tresolveAiFeatureUnavailableMessage,
323
+ };
206
324
  `;
207
325
  }
208
326
  /**
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Build the generated PHP controller and hook surface for a workspace AI feature.
3
+ */
4
+ export declare function buildAiFeaturePhpSource(aiFeatureSlug: string, namespace: string, phpPrefix: string, textDomain: string): string;