@wp-typia/project-tools 0.22.10 → 0.23.1

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 (155) hide show
  1. package/dist/runtime/ai-feature-artifacts.js +4 -1
  2. package/dist/runtime/block-generator-service-spec.js +2 -1
  3. package/dist/runtime/cli-add-block-json.js +5 -1
  4. package/dist/runtime/cli-add-collision.d.ts +25 -0
  5. package/dist/runtime/cli-add-collision.js +76 -0
  6. package/dist/runtime/cli-add-help.js +12 -2
  7. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  8. package/dist/runtime/cli-add-kind-ids.js +3 -0
  9. package/dist/runtime/cli-add-types.d.ts +129 -0
  10. package/dist/runtime/cli-add-types.js +26 -0
  11. package/dist/runtime/cli-add-validation.d.ts +97 -1
  12. package/dist/runtime/cli-add-validation.js +313 -1
  13. package/dist/runtime/cli-add-workspace-ability-scaffold.js +4 -1
  14. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +79 -20
  15. package/dist/runtime/cli-add-workspace-admin-view-source.js +11 -2
  16. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
  17. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
  18. package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
  19. package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
  20. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
  21. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
  22. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
  23. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
  24. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
  25. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
  26. package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +19 -10
  27. package/dist/runtime/cli-add-workspace-admin-view-templates.js +31 -971
  28. package/dist/runtime/cli-add-workspace-admin-view-types.d.ts +21 -0
  29. package/dist/runtime/cli-add-workspace-admin-view-types.js +22 -0
  30. package/dist/runtime/cli-add-workspace-ai-anchors.js +125 -32
  31. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +17 -1
  32. package/dist/runtime/cli-add-workspace-contract-source-emitters.d.ts +15 -0
  33. package/dist/runtime/cli-add-workspace-contract-source-emitters.js +42 -0
  34. package/dist/runtime/cli-add-workspace-contract.d.ts +15 -0
  35. package/dist/runtime/cli-add-workspace-contract.js +65 -0
  36. package/dist/runtime/cli-add-workspace-integration-env.d.ts +26 -0
  37. package/dist/runtime/cli-add-workspace-integration-env.js +428 -0
  38. package/dist/runtime/cli-add-workspace-post-meta-anchors.d.ts +23 -0
  39. package/dist/runtime/cli-add-workspace-post-meta-anchors.js +244 -0
  40. package/dist/runtime/cli-add-workspace-post-meta-source-emitters.d.ts +63 -0
  41. package/dist/runtime/cli-add-workspace-post-meta-source-emitters.js +179 -0
  42. package/dist/runtime/cli-add-workspace-post-meta.d.ts +15 -0
  43. package/dist/runtime/cli-add-workspace-post-meta.js +107 -0
  44. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +9 -0
  45. package/dist/runtime/cli-add-workspace-rest-anchors.js +326 -21
  46. package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
  47. package/dist/runtime/cli-add-workspace-rest-generated.js +158 -0
  48. package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
  49. package/dist/runtime/cli-add-workspace-rest-manual.js +279 -0
  50. package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +24 -0
  51. package/dist/runtime/cli-add-workspace-rest-php-templates.js +678 -0
  52. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +98 -2
  53. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +323 -29
  54. package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
  55. package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
  56. package/dist/runtime/cli-add-workspace-rest.d.ts +3 -7
  57. package/dist/runtime/cli-add-workspace-rest.js +34 -481
  58. package/dist/runtime/cli-add-workspace.d.ts +15 -0
  59. package/dist/runtime/cli-add-workspace.js +15 -0
  60. package/dist/runtime/cli-add.d.ts +1 -1
  61. package/dist/runtime/cli-add.js +1 -1
  62. package/dist/runtime/cli-core.d.ts +3 -2
  63. package/dist/runtime/cli-core.js +3 -2
  64. package/dist/runtime/cli-diagnostics.d.ts +3 -1
  65. package/dist/runtime/cli-diagnostics.js +17 -5
  66. package/dist/runtime/cli-doctor-environment.js +1 -3
  67. package/dist/runtime/cli-doctor-workspace-bindings.js +4 -1
  68. package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
  69. package/dist/runtime/cli-doctor-workspace-block-addons.js +134 -0
  70. package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
  71. package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
  72. package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
  73. package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
  74. package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
  75. package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
  76. package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
  77. package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
  78. package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
  79. package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
  80. package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
  81. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
  82. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
  83. package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
  84. package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
  85. package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
  86. package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
  87. package/dist/runtime/cli-doctor-workspace-features.js +14 -369
  88. package/dist/runtime/cli-doctor-workspace-package.d.ts +25 -3
  89. package/dist/runtime/cli-doctor-workspace-package.js +35 -13
  90. package/dist/runtime/cli-doctor-workspace-shared.d.ts +2 -0
  91. package/dist/runtime/cli-doctor-workspace-shared.js +2 -0
  92. package/dist/runtime/cli-doctor-workspace.js +8 -3
  93. package/dist/runtime/cli-doctor.d.ts +52 -3
  94. package/dist/runtime/cli-doctor.js +79 -8
  95. package/dist/runtime/cli-help.js +10 -0
  96. package/dist/runtime/cli-init-package-json.js +4 -2
  97. package/dist/runtime/cli-init-templates.js +11 -1
  98. package/dist/runtime/cli-prompt.d.ts +16 -2
  99. package/dist/runtime/cli-prompt.js +29 -12
  100. package/dist/runtime/cli-scaffold.d.ts +2 -1
  101. package/dist/runtime/cli-scaffold.js +19 -10
  102. package/dist/runtime/contract-artifacts.d.ts +14 -0
  103. package/dist/runtime/contract-artifacts.js +15 -0
  104. package/dist/runtime/external-template-guards.js +4 -6
  105. package/dist/runtime/index.d.ts +2 -2
  106. package/dist/runtime/index.js +1 -1
  107. package/dist/runtime/json-utils.d.ts +62 -4
  108. package/dist/runtime/json-utils.js +78 -4
  109. package/dist/runtime/local-dev-presets.js +4 -1
  110. package/dist/runtime/migration-ui-capability.js +4 -1
  111. package/dist/runtime/migration-utils.js +4 -1
  112. package/dist/runtime/package-managers.js +6 -1
  113. package/dist/runtime/package-versions.js +6 -1
  114. package/dist/runtime/rest-resource-artifacts.d.ts +57 -1
  115. package/dist/runtime/rest-resource-artifacts.js +97 -1
  116. package/dist/runtime/scaffold-bootstrap.js +7 -2
  117. package/dist/runtime/scaffold-package-manager-files.js +5 -1
  118. package/dist/runtime/scaffold-repository-reference.js +4 -2
  119. package/dist/runtime/scaffold-template-variables.js +2 -1
  120. package/dist/runtime/scaffold.d.ts +18 -1
  121. package/dist/runtime/scaffold.js +55 -2
  122. package/dist/runtime/temp-roots.js +4 -1
  123. package/dist/runtime/template-layers.js +4 -1
  124. package/dist/runtime/template-registry.js +9 -3
  125. package/dist/runtime/template-render.d.ts +1 -1
  126. package/dist/runtime/template-render.js +1 -1
  127. package/dist/runtime/template-source-cache-markers.d.ts +37 -0
  128. package/dist/runtime/template-source-cache-markers.js +125 -0
  129. package/dist/runtime/template-source-cache.d.ts +1 -4
  130. package/dist/runtime/template-source-cache.js +16 -122
  131. package/dist/runtime/template-source-contracts.d.ts +2 -0
  132. package/dist/runtime/template-source-external.d.ts +4 -2
  133. package/dist/runtime/template-source-external.js +4 -2
  134. package/dist/runtime/template-source-normalization.js +2 -1
  135. package/dist/runtime/template-source-remote.d.ts +8 -4
  136. package/dist/runtime/template-source-remote.js +26 -9
  137. package/dist/runtime/template-source-seeds.js +10 -3
  138. package/dist/runtime/workspace-inventory-mutations.js +54 -4
  139. package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
  140. package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
  141. package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
  142. package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
  143. package/dist/runtime/workspace-inventory-parser.d.ts +3 -44
  144. package/dist/runtime/workspace-inventory-parser.js +7 -464
  145. package/dist/runtime/workspace-inventory-read.d.ts +9 -2
  146. package/dist/runtime/workspace-inventory-read.js +9 -2
  147. package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
  148. package/dist/runtime/workspace-inventory-section-descriptors.js +435 -0
  149. package/dist/runtime/workspace-inventory-templates.d.ts +16 -1
  150. package/dist/runtime/workspace-inventory-templates.js +75 -4
  151. package/dist/runtime/workspace-inventory-types.d.ts +52 -2
  152. package/dist/runtime/workspace-inventory.d.ts +2 -2
  153. package/dist/runtime/workspace-inventory.js +1 -1
  154. package/dist/runtime/workspace-project.js +4 -6
  155. package/package.json +2 -2
@@ -1,331 +1,9 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { EDITOR_PLUGIN_SLOT_IDS, REST_RESOURCE_METHOD_IDS, REST_RESOURCE_NAMESPACE_PATTERN, resolveEditorPluginSlotAlias, } from "./cli-add-shared.js";
4
- import { checkExistingFiles, createDoctorCheck, resolveWorkspaceBootstrapPath, WORKSPACE_ABILITY_EDITOR_ASSET, WORKSPACE_ABILITY_EDITOR_SCRIPT, WORKSPACE_ABILITY_GLOB, WORKSPACE_ADMIN_VIEW_ASSET, WORKSPACE_ADMIN_VIEW_GLOB, WORKSPACE_ADMIN_VIEW_SCRIPT, WORKSPACE_ADMIN_VIEW_STYLE, WORKSPACE_AI_FEATURE_GLOB, WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET, WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT, WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE, WORKSPACE_REST_RESOURCE_GLOB, } from "./cli-doctor-workspace-shared.js";
5
- import { escapeRegex } from "./php-utils.js";
6
- function getWorkspaceRestResourceRequiredFiles(restResource) {
7
- const schemaNames = new Set();
8
- if (restResource.methods.includes("list")) {
9
- schemaNames.add("list-query");
10
- schemaNames.add("list-response");
11
- }
12
- if (restResource.methods.includes("read")) {
13
- schemaNames.add("read-query");
14
- schemaNames.add("read-response");
15
- }
16
- if (restResource.methods.includes("create")) {
17
- schemaNames.add("create-request");
18
- schemaNames.add("create-response");
19
- }
20
- if (restResource.methods.includes("update")) {
21
- schemaNames.add("update-query");
22
- schemaNames.add("update-request");
23
- schemaNames.add("update-response");
24
- }
25
- if (restResource.methods.includes("delete")) {
26
- schemaNames.add("delete-query");
27
- schemaNames.add("delete-response");
28
- }
29
- return Array.from(new Set([
30
- restResource.apiFile,
31
- ...Array.from(schemaNames, (schemaName) => path.join(path.dirname(restResource.typesFile), "api-schemas", `${schemaName}.schema.json`)),
32
- restResource.clientFile,
33
- restResource.dataFile,
34
- restResource.openApiFile,
35
- restResource.phpFile,
36
- restResource.typesFile,
37
- restResource.validatorsFile,
38
- ]));
39
- }
40
- function checkWorkspaceRestResourceConfig(restResource) {
41
- const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(restResource.namespace);
42
- const hasMethods = restResource.methods.length > 0 &&
43
- restResource.methods.every((method) => REST_RESOURCE_METHOD_IDS.includes(method));
44
- return createDoctorCheck(`REST resource config ${restResource.slug}`, hasNamespace && hasMethods ? "pass" : "fail", hasNamespace && hasMethods
45
- ? `REST resource namespace ${restResource.namespace} with methods ${restResource.methods.join(", ")}`
46
- : "REST resource namespace or methods are invalid");
47
- }
48
- function checkWorkspaceRestResourceBootstrap(projectDir, packageName, phpPrefix) {
49
- const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
50
- if (!fs.existsSync(bootstrapPath)) {
51
- return createDoctorCheck("REST resource bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
52
- }
53
- const source = fs.readFileSync(bootstrapPath, "utf8");
54
- const registerFunctionName = `${phpPrefix}_register_rest_resources`;
55
- const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
56
- const hasServerGlob = source.includes(WORKSPACE_REST_RESOURCE_GLOB);
57
- const hasRegisterHook = source.includes(registerHook);
58
- return createDoctorCheck("REST resource bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook
59
- ? "REST resource PHP loader hook is present"
60
- : "Missing REST resource PHP require glob or init hook");
61
- }
62
- function getWorkspaceAbilityRequiredFiles(ability) {
63
- return Array.from(new Set([
64
- ability.clientFile,
65
- ability.configFile,
66
- ability.dataFile,
67
- ability.inputSchemaFile,
68
- ability.outputSchemaFile,
69
- ability.phpFile,
70
- ability.typesFile,
71
- ]));
72
- }
73
- function checkWorkspaceAbilityConfig(projectDir, ability) {
74
- const configPath = path.join(projectDir, ability.configFile);
75
- if (!fs.existsSync(configPath)) {
76
- return createDoctorCheck(`Ability config ${ability.slug}`, "fail", `Missing ${ability.configFile}`);
77
- }
78
- try {
79
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
80
- const abilityId = typeof config.abilityId === "string" ? config.abilityId.trim() : "";
81
- const categorySlug = typeof config.category?.slug === "string"
82
- ? config.category.slug.trim()
83
- : "";
84
- const hasValidAbilityId = /^[a-z0-9-]+\/[a-z0-9-]+$/u.test(abilityId);
85
- const hasValidCategorySlug = /^[a-z0-9-]+$/u.test(categorySlug);
86
- return createDoctorCheck(`Ability config ${ability.slug}`, hasValidAbilityId && hasValidCategorySlug ? "pass" : "fail", hasValidAbilityId && hasValidCategorySlug
87
- ? `Ability id ${abilityId} in category ${categorySlug} is valid`
88
- : "Ability config must define a valid abilityId (`namespace/ability-name`) and category.slug.");
89
- }
90
- catch (error) {
91
- return createDoctorCheck(`Ability config ${ability.slug}`, "fail", error instanceof Error ? error.message : String(error));
92
- }
93
- }
94
- function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
95
- const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
96
- if (!fs.existsSync(bootstrapPath)) {
97
- return createDoctorCheck("Ability bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
98
- }
99
- const source = fs.readFileSync(bootstrapPath, "utf8");
100
- const loadFunctionName = `${phpPrefix}_load_workflow_abilities`;
101
- const enqueueFunctionName = `${phpPrefix}_enqueue_workflow_abilities`;
102
- const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
103
- const adminEnqueueHook = `add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );`;
104
- const editorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
105
- const hasLoaderHook = source.includes(loadHook);
106
- const hasAdminEnqueueHook = source.includes(adminEnqueueHook);
107
- const hasEditorEnqueueHook = source.includes(editorEnqueueHook);
108
- const hasServerGlob = source.includes(WORKSPACE_ABILITY_GLOB);
109
- const hasEditorScript = source.includes(WORKSPACE_ABILITY_EDITOR_SCRIPT);
110
- const hasEditorAsset = source.includes(WORKSPACE_ABILITY_EDITOR_ASSET);
111
- const hasScriptModuleEnqueue = source.includes("wp_enqueue_script_module");
112
- return createDoctorCheck("Ability bootstrap", hasLoaderHook &&
113
- hasAdminEnqueueHook &&
114
- hasEditorEnqueueHook &&
115
- hasServerGlob &&
116
- hasEditorScript &&
117
- hasEditorAsset &&
118
- hasScriptModuleEnqueue
119
- ? "pass"
120
- : "fail", hasLoaderHook &&
121
- hasAdminEnqueueHook &&
122
- hasEditorEnqueueHook &&
123
- hasServerGlob &&
124
- hasEditorScript &&
125
- hasEditorAsset &&
126
- hasScriptModuleEnqueue
127
- ? "Ability loader and admin/editor script-module bootstrap hooks are present"
128
- : "Missing ability loader hook, script-module enqueue, or build/abilities asset references");
129
- }
130
- function checkWorkspaceAbilityIndex(projectDir, abilities) {
131
- const indexRelativePath = [
132
- path.join("src", "abilities", "index.ts"),
133
- path.join("src", "abilities", "index.js"),
134
- ].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
135
- if (!indexRelativePath) {
136
- return createDoctorCheck("Abilities index", "fail", "Missing src/abilities/index.ts or src/abilities/index.js");
137
- }
138
- const indexPath = path.join(projectDir, indexRelativePath);
139
- const source = fs.readFileSync(indexPath, "utf8");
140
- const missingExports = abilities.filter((ability) => {
141
- const exportPattern = new RegExp(`^\\s*export\\s+(?:\\*\\s+from|\\{[^}]+\\}\\s+from)\\s+['"\`]\\./${escapeRegex(ability.slug)}\\/client['"\`]`, "mu");
142
- return !exportPattern.test(source);
143
- });
144
- return createDoctorCheck("Abilities index", missingExports.length === 0 ? "pass" : "fail", missingExports.length === 0
145
- ? "Ability client helpers are aggregated"
146
- : `Missing ability exports for: ${missingExports.map((entry) => entry.slug).join(", ")}`);
147
- }
148
- function getWorkspaceAiFeatureRequiredFiles(aiFeature) {
149
- return Array.from(new Set([
150
- aiFeature.aiSchemaFile,
151
- aiFeature.apiFile,
152
- path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-request.schema.json"),
153
- path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-response.schema.json"),
154
- path.join(path.dirname(aiFeature.typesFile), "api-schemas", "feature-result.schema.json"),
155
- aiFeature.clientFile,
156
- aiFeature.dataFile,
157
- aiFeature.openApiFile,
158
- aiFeature.phpFile,
159
- aiFeature.typesFile,
160
- aiFeature.validatorsFile,
161
- ]));
162
- }
163
- function checkWorkspaceAiFeatureConfig(aiFeature) {
164
- const hasNamespace = REST_RESOURCE_NAMESPACE_PATTERN.test(aiFeature.namespace);
165
- return createDoctorCheck(`AI feature config ${aiFeature.slug}`, hasNamespace ? "pass" : "fail", hasNamespace
166
- ? `AI feature namespace ${aiFeature.namespace} is valid`
167
- : "AI feature namespace is invalid");
168
- }
169
- function checkWorkspaceAiFeatureBootstrap(projectDir, packageName, phpPrefix) {
170
- const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
171
- if (!fs.existsSync(bootstrapPath)) {
172
- return createDoctorCheck("AI feature bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
173
- }
174
- const source = fs.readFileSync(bootstrapPath, "utf8");
175
- const registerFunctionName = `${phpPrefix}_register_ai_features`;
176
- const registerHook = `add_action( 'init', '${registerFunctionName}', 20 );`;
177
- const hasServerGlob = source.includes(WORKSPACE_AI_FEATURE_GLOB);
178
- const hasRegisterHook = source.includes(registerHook);
179
- return createDoctorCheck("AI feature bootstrap", hasServerGlob && hasRegisterHook ? "pass" : "fail", hasServerGlob && hasRegisterHook
180
- ? "AI feature PHP loader hook is present"
181
- : "Missing AI feature PHP require glob or init hook");
182
- }
183
- function getWorkspaceEditorPluginRequiredFiles(editorPlugin) {
184
- const editorPluginDir = path.join("src", "editor-plugins", editorPlugin.slug);
185
- const surfaceFile = editorPlugin.slot === "PluginSidebar"
186
- ? path.join(editorPluginDir, "Sidebar.tsx")
187
- : path.join(editorPluginDir, "Surface.tsx");
188
- return Array.from(new Set([
189
- editorPlugin.file,
190
- surfaceFile,
191
- path.join(editorPluginDir, "data.ts"),
192
- path.join(editorPluginDir, "types.ts"),
193
- path.join(editorPluginDir, "style.scss"),
194
- ]));
195
- }
196
- function checkWorkspaceEditorPluginConfig(editorPlugin) {
197
- const normalizedSlot = resolveEditorPluginSlotAlias(editorPlugin.slot);
198
- const isValidSlot = Boolean(normalizedSlot);
199
- return createDoctorCheck(`Editor plugin config ${editorPlugin.slug}`, isValidSlot ? "pass" : "fail", isValidSlot
200
- ? `Editor plugin slot ${editorPlugin.slot} is supported as ${normalizedSlot}`
201
- : `Unsupported editor plugin slot "${editorPlugin.slot}". Expected one of: ${EDITOR_PLUGIN_SLOT_IDS.join(", ")} or legacy aliases PluginSidebar, PluginDocumentSettingPanel.`);
202
- }
203
- function checkWorkspaceEditorPluginBootstrap(projectDir, packageName, phpPrefix) {
204
- const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
205
- if (!fs.existsSync(bootstrapPath)) {
206
- return createDoctorCheck("Editor plugin bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
207
- }
208
- const source = fs.readFileSync(bootstrapPath, "utf8");
209
- const enqueueFunctionName = `${phpPrefix}_enqueue_editor_plugins_editor`;
210
- const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
211
- const hasEditorEnqueueHook = source.includes(enqueueHook);
212
- const hasEditorScript = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_SCRIPT);
213
- const hasEditorAsset = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_ASSET);
214
- const hasEditorStyle = source.includes(WORKSPACE_EDITOR_PLUGIN_EDITOR_STYLE);
215
- return createDoctorCheck("Editor plugin bootstrap", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle ? "pass" : "fail", hasEditorEnqueueHook && hasEditorScript && hasEditorAsset && hasEditorStyle
216
- ? "Editor plugin enqueue hook is present"
217
- : "Missing editor plugin enqueue hook or build/editor-plugins script/style asset references");
218
- }
219
- function checkWorkspaceEditorPluginIndex(projectDir, editorPlugins) {
220
- const indexRelativePath = [
221
- path.join("src", "editor-plugins", "index.ts"),
222
- path.join("src", "editor-plugins", "index.js"),
223
- ].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
224
- if (!indexRelativePath) {
225
- return createDoctorCheck("Editor plugins index", "fail", "Missing src/editor-plugins/index.ts or src/editor-plugins/index.js");
226
- }
227
- const indexPath = path.join(projectDir, indexRelativePath);
228
- const source = fs.readFileSync(indexPath, "utf8");
229
- const missingImports = editorPlugins.filter((editorPlugin) => {
230
- const importPattern = new RegExp(`['"\`]\\./${escapeRegex(editorPlugin.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
231
- return !importPattern.test(source);
232
- });
233
- return createDoctorCheck("Editor plugins index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0
234
- ? "Editor plugin registrations are aggregated"
235
- : `Missing editor plugin imports for: ${missingImports
236
- .map((entry) => entry.slug)
237
- .join(", ")}`);
238
- }
239
- function getWorkspaceAdminViewRequiredFiles(adminView) {
240
- const adminViewDir = path.join("src", "admin-views", adminView.slug);
241
- return Array.from(new Set([
242
- adminView.file,
243
- adminView.phpFile,
244
- path.join(adminViewDir, "Screen.tsx"),
245
- path.join(adminViewDir, "config.ts"),
246
- path.join(adminViewDir, "data.ts"),
247
- path.join(adminViewDir, "style.scss"),
248
- path.join(adminViewDir, "types.ts"),
249
- ]));
250
- }
251
- function checkWorkspaceAdminViewConfig(adminView, inventory) {
252
- if (adminView.source === undefined) {
253
- return createDoctorCheck(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
254
- }
255
- const source = adminView.source.trim();
256
- const restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
257
- const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
258
- const restResourceSlug = restSourceMatch?.[1];
259
- const restResource = restResourceSlug
260
- ? inventory.restResources.find((entry) => entry.slug === restResourceSlug)
261
- : undefined;
262
- const isValid = Boolean(restResource?.methods.includes("list")) || Boolean(coreDataSourceMatch);
263
- return createDoctorCheck(`Admin view config ${adminView.slug}`, isValid ? "pass" : "fail", isValid
264
- ? `Admin view source ${source} is list-capable`
265
- : "Admin view source must use rest-resource:<slug> with a list-capable REST resource or core-data:<postType|taxonomy>/<name>");
266
- }
267
- function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
268
- const bootstrapPath = resolveWorkspaceBootstrapPath(projectDir, packageName);
269
- if (!fs.existsSync(bootstrapPath)) {
270
- return createDoctorCheck("Admin view bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
271
- }
272
- const source = fs.readFileSync(bootstrapPath, "utf8");
273
- const loadFunctionName = `${phpPrefix}_load_admin_views`;
274
- const loadHook = `add_action( 'plugins_loaded', '${loadFunctionName}' );`;
275
- const hasLoaderHook = source.includes(loadHook);
276
- const hasServerGlob = source.includes(WORKSPACE_ADMIN_VIEW_GLOB);
277
- return createDoctorCheck("Admin view bootstrap", hasLoaderHook && hasServerGlob ? "pass" : "fail", hasLoaderHook && hasServerGlob
278
- ? "Admin view PHP loader hook is present"
279
- : "Missing admin view PHP require glob or plugins_loaded hook");
280
- }
281
- function checkWorkspaceAdminViewIndex(projectDir, adminViews) {
282
- const indexRelativePath = [
283
- path.join("src", "admin-views", "index.ts"),
284
- path.join("src", "admin-views", "index.js"),
285
- ].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
286
- if (!indexRelativePath) {
287
- return createDoctorCheck("Admin views index", "fail", "Missing src/admin-views/index.ts or src/admin-views/index.js");
288
- }
289
- const indexPath = path.join(projectDir, indexRelativePath);
290
- const source = fs.readFileSync(indexPath, "utf8");
291
- const missingImports = adminViews.filter((adminView) => {
292
- const importPattern = new RegExp(`['"\`]\\./${escapeRegex(adminView.slug)}(?:/[^'"\`]*)?['"\`]`, "u");
293
- return !importPattern.test(source);
294
- });
295
- return createDoctorCheck("Admin views index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0
296
- ? "Admin view registrations are aggregated"
297
- : `Missing admin view imports for: ${missingImports
298
- .map((entry) => entry.slug)
299
- .join(", ")}`);
300
- }
301
- function checkWorkspaceAdminViewPhp(projectDir, adminView) {
302
- const phpPath = path.join(projectDir, adminView.phpFile);
303
- if (!fs.existsSync(phpPath)) {
304
- return createDoctorCheck(`Admin view PHP ${adminView.slug}`, "fail", `Missing ${adminView.phpFile}`);
305
- }
306
- const source = fs.readFileSync(phpPath, "utf8");
307
- const hasAdminMenu = source.includes("add_submenu_page");
308
- const hasAdminEnqueue = source.includes("admin_enqueue_scripts");
309
- const hasScript = source.includes(WORKSPACE_ADMIN_VIEW_SCRIPT);
310
- const hasAsset = source.includes(WORKSPACE_ADMIN_VIEW_ASSET);
311
- const hasStyle = source.includes(WORKSPACE_ADMIN_VIEW_STYLE);
312
- const hasComponentsStyleDependency = source.includes("'wp-components'");
313
- return createDoctorCheck(`Admin view PHP ${adminView.slug}`, hasAdminMenu &&
314
- hasAdminEnqueue &&
315
- hasScript &&
316
- hasAsset &&
317
- hasStyle &&
318
- hasComponentsStyleDependency
319
- ? "pass"
320
- : "fail", hasAdminMenu &&
321
- hasAdminEnqueue &&
322
- hasScript &&
323
- hasAsset &&
324
- hasStyle &&
325
- hasComponentsStyleDependency
326
- ? "Admin menu, script, style, and wp-components style dependency are wired"
327
- : "Missing admin menu, enqueue hook, build/admin-views asset reference, or wp-components style dependency");
328
- }
1
+ import { getWorkspaceAbilityDoctorChecks, } from "./cli-doctor-workspace-features-abilities.js";
2
+ import { getWorkspaceAdminViewDoctorChecks, } from "./cli-doctor-workspace-features-admin-views.js";
3
+ import { getWorkspaceAiFeatureDoctorChecks, } from "./cli-doctor-workspace-features-ai.js";
4
+ import { getWorkspaceEditorPluginDoctorChecks, } from "./cli-doctor-workspace-features-editor-plugins.js";
5
+ import { getWorkspacePostMetaDoctorChecks, } from "./cli-doctor-workspace-features-post-meta.js";
6
+ import { getWorkspaceRestResourceDoctorChecks, } from "./cli-doctor-workspace-features-rest.js";
329
7
  /**
330
8
  * Collect workspace doctor checks for REST resources, abilities, AI features, editor plugins, and admin views.
331
9
  *
@@ -334,45 +12,12 @@ function checkWorkspaceAdminViewPhp(projectDir, adminView) {
334
12
  * @returns Ordered `DoctorCheck[]` rows for extracted workspace feature diagnostics.
335
13
  */
336
14
  export function getWorkspaceFeatureDoctorChecks(workspace, inventory) {
337
- const checks = [];
338
- if (inventory.restResources.length > 0) {
339
- checks.push(checkWorkspaceRestResourceBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
340
- }
341
- for (const restResource of inventory.restResources) {
342
- checks.push(checkWorkspaceRestResourceConfig(restResource));
343
- checks.push(checkExistingFiles(workspace.projectDir, `REST resource ${restResource.slug}`, getWorkspaceRestResourceRequiredFiles(restResource)));
344
- }
345
- if (inventory.abilities.length > 0) {
346
- checks.push(checkWorkspaceAbilityBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
347
- checks.push(checkWorkspaceAbilityIndex(workspace.projectDir, inventory.abilities));
348
- }
349
- for (const ability of inventory.abilities) {
350
- checks.push(checkWorkspaceAbilityConfig(workspace.projectDir, ability));
351
- checks.push(checkExistingFiles(workspace.projectDir, `Ability ${ability.slug}`, getWorkspaceAbilityRequiredFiles(ability)));
352
- }
353
- if (inventory.aiFeatures.length > 0) {
354
- checks.push(checkWorkspaceAiFeatureBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
355
- }
356
- for (const aiFeature of inventory.aiFeatures) {
357
- checks.push(checkWorkspaceAiFeatureConfig(aiFeature));
358
- checks.push(checkExistingFiles(workspace.projectDir, `AI feature ${aiFeature.slug}`, getWorkspaceAiFeatureRequiredFiles(aiFeature)));
359
- }
360
- if (inventory.editorPlugins.length > 0) {
361
- checks.push(checkWorkspaceEditorPluginBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
362
- checks.push(checkWorkspaceEditorPluginIndex(workspace.projectDir, inventory.editorPlugins));
363
- }
364
- for (const editorPlugin of inventory.editorPlugins) {
365
- checks.push(checkExistingFiles(workspace.projectDir, `Editor plugin ${editorPlugin.slug}`, getWorkspaceEditorPluginRequiredFiles(editorPlugin)));
366
- checks.push(checkWorkspaceEditorPluginConfig(editorPlugin));
367
- }
368
- if (inventory.adminViews.length > 0) {
369
- checks.push(checkWorkspaceAdminViewBootstrap(workspace.projectDir, workspace.packageName, workspace.workspace.phpPrefix));
370
- checks.push(checkWorkspaceAdminViewIndex(workspace.projectDir, inventory.adminViews));
371
- }
372
- for (const adminView of inventory.adminViews) {
373
- checks.push(checkWorkspaceAdminViewConfig(adminView, inventory));
374
- checks.push(checkExistingFiles(workspace.projectDir, `Admin view ${adminView.slug}`, getWorkspaceAdminViewRequiredFiles(adminView)));
375
- checks.push(checkWorkspaceAdminViewPhp(workspace.projectDir, adminView));
376
- }
377
- return checks;
15
+ return [
16
+ ...getWorkspaceRestResourceDoctorChecks(workspace, inventory.restResources),
17
+ ...getWorkspacePostMetaDoctorChecks(workspace, inventory.postMeta),
18
+ ...getWorkspaceAbilityDoctorChecks(workspace, inventory.abilities),
19
+ ...getWorkspaceAiFeatureDoctorChecks(workspace, inventory.aiFeatures),
20
+ ...getWorkspaceEditorPluginDoctorChecks(workspace, inventory.editorPlugins),
21
+ ...getWorkspaceAdminViewDoctorChecks(workspace, inventory),
22
+ ];
378
23
  }
@@ -1,18 +1,40 @@
1
1
  import type { DoctorCheck } from "./cli-doctor.js";
2
2
  import type { WorkspacePackageJson, WorkspaceProject } from "./workspace-project.js";
3
+ /**
4
+ * Snapshot of package-level filesystem doctor inputs prepared asynchronously.
5
+ */
6
+ export interface WorkspacePackageDoctorSnapshot {
7
+ /** Whether the expected workspace bootstrap PHP file exists. */
8
+ bootstrapExists: boolean;
9
+ /** Relative path to the expected workspace bootstrap PHP file. */
10
+ bootstrapRelativePath: string;
11
+ /** Whether the migration config file exists. */
12
+ migrationConfigExists: boolean;
13
+ /** Relative path to the migration config file. */
14
+ migrationConfigRelativePath: string;
15
+ }
16
+ /**
17
+ * Prepare package-level workspace doctor inputs without blocking the event loop.
18
+ *
19
+ * @param workspace Resolved workspace metadata and filesystem paths.
20
+ * @param packageJson Parsed workspace package manifest.
21
+ * @returns Snapshot values consumed by synchronous doctor row mappers.
22
+ */
23
+ export declare function prepareWorkspacePackageDoctorSnapshot(workspace: WorkspaceProject, packageJson: WorkspacePackageJson): Promise<WorkspacePackageDoctorSnapshot>;
3
24
  /**
4
25
  * Validate the package metadata that makes a project an official workspace.
5
26
  *
6
27
  * @param workspace Resolved workspace metadata and filesystem paths.
7
28
  * @param packageJson Parsed workspace package manifest.
29
+ * @param snapshot Async filesystem snapshot for package-level doctor inputs.
8
30
  * @returns A `DoctorCheck` describing whether package metadata matches the workspace contract.
9
31
  */
10
- export declare function getWorkspacePackageMetadataCheck(workspace: WorkspaceProject, packageJson: WorkspacePackageJson): DoctorCheck;
32
+ export declare function getWorkspacePackageMetadataCheck(workspace: WorkspaceProject, packageJson: WorkspacePackageJson, snapshot: WorkspacePackageDoctorSnapshot): DoctorCheck;
11
33
  /**
12
34
  * Report whether a workspace configured for migrations exposes the expected doctor inputs.
13
35
  *
14
- * @param workspace Resolved workspace metadata and filesystem paths.
15
36
  * @param packageJson Parsed workspace package manifest.
37
+ * @param snapshot Async filesystem snapshot for package-level doctor inputs.
16
38
  * @returns A migration hint row when the workspace uses migrations, otherwise `null`.
17
39
  */
18
- export declare function getMigrationWorkspaceHintCheck(workspace: WorkspaceProject, packageJson: WorkspacePackageJson): DoctorCheck | null;
40
+ export declare function getMigrationWorkspaceHintCheck(packageJson: WorkspacePackageJson, snapshot: WorkspacePackageDoctorSnapshot): DoctorCheck | null;
@@ -1,18 +1,42 @@
1
- import fs from "node:fs";
2
1
  import path from "node:path";
3
2
  import { createDoctorCheck, getWorkspaceBootstrapRelativePath, } from "./cli-doctor-workspace-shared.js";
3
+ import { pathExists } from "./fs-async.js";
4
4
  import { WORKSPACE_TEMPLATE_PACKAGE } from "./workspace-project.js";
5
+ /**
6
+ * Prepare package-level workspace doctor inputs without blocking the event loop.
7
+ *
8
+ * @param workspace Resolved workspace metadata and filesystem paths.
9
+ * @param packageJson Parsed workspace package manifest.
10
+ * @returns Snapshot values consumed by synchronous doctor row mappers.
11
+ */
12
+ export async function prepareWorkspacePackageDoctorSnapshot(workspace, packageJson) {
13
+ const packageName = packageJson.name;
14
+ const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0
15
+ ? packageName
16
+ : workspace.packageName);
17
+ const migrationConfigRelativePath = path.join("src", "migrations", "config.ts");
18
+ const [bootstrapExists, migrationConfigExists] = await Promise.all([
19
+ pathExists(path.join(workspace.projectDir, bootstrapRelativePath)),
20
+ pathExists(path.join(workspace.projectDir, migrationConfigRelativePath)),
21
+ ]);
22
+ return {
23
+ bootstrapExists,
24
+ bootstrapRelativePath,
25
+ migrationConfigExists,
26
+ migrationConfigRelativePath,
27
+ };
28
+ }
5
29
  /**
6
30
  * Validate the package metadata that makes a project an official workspace.
7
31
  *
8
32
  * @param workspace Resolved workspace metadata and filesystem paths.
9
33
  * @param packageJson Parsed workspace package manifest.
34
+ * @param snapshot Async filesystem snapshot for package-level doctor inputs.
10
35
  * @returns A `DoctorCheck` describing whether package metadata matches the workspace contract.
11
36
  */
12
- export function getWorkspacePackageMetadataCheck(workspace, packageJson) {
37
+ export function getWorkspacePackageMetadataCheck(workspace, packageJson, snapshot) {
13
38
  const issues = [];
14
39
  const packageName = packageJson.name;
15
- const bootstrapRelativePath = getWorkspaceBootstrapRelativePath(typeof packageName === "string" && packageName.length > 0 ? packageName : workspace.packageName);
16
40
  const wpTypia = packageJson.wpTypia;
17
41
  if (typeof packageName !== "string" || packageName.length === 0) {
18
42
  issues.push("package.json must define a string name for workspace bootstrap resolution");
@@ -32,28 +56,26 @@ export function getWorkspacePackageMetadataCheck(workspace, packageJson) {
32
56
  if (wpTypia?.phpPrefix !== workspace.workspace.phpPrefix) {
33
57
  issues.push(`wpTypia.phpPrefix must equal "${workspace.workspace.phpPrefix}"`);
34
58
  }
35
- if (!fs.existsSync(path.join(workspace.projectDir, bootstrapRelativePath))) {
36
- issues.push(`Missing bootstrap file ${bootstrapRelativePath}`);
59
+ if (!snapshot.bootstrapExists) {
60
+ issues.push(`Missing bootstrap file ${snapshot.bootstrapRelativePath}`);
37
61
  }
38
62
  return createDoctorCheck("Workspace package metadata", issues.length === 0 ? "pass" : "fail", issues.length === 0
39
- ? `package.json metadata aligns with ${workspace.packageName} and ${bootstrapRelativePath}`
63
+ ? `package.json metadata aligns with ${workspace.packageName} and ${snapshot.bootstrapRelativePath}`
40
64
  : issues.join("; "));
41
65
  }
42
66
  /**
43
67
  * Report whether a workspace configured for migrations exposes the expected doctor inputs.
44
68
  *
45
- * @param workspace Resolved workspace metadata and filesystem paths.
46
69
  * @param packageJson Parsed workspace package manifest.
70
+ * @param snapshot Async filesystem snapshot for package-level doctor inputs.
47
71
  * @returns A migration hint row when the workspace uses migrations, otherwise `null`.
48
72
  */
49
- export function getMigrationWorkspaceHintCheck(workspace, packageJson) {
73
+ export function getMigrationWorkspaceHintCheck(packageJson, snapshot) {
50
74
  const hasMigrationScript = typeof packageJson.scripts?.["migration:doctor"] === "string";
51
- const migrationConfigRelativePath = path.join("src", "migrations", "config.ts");
52
- const hasMigrationConfig = fs.existsSync(path.join(workspace.projectDir, migrationConfigRelativePath));
53
- if (!hasMigrationScript && !hasMigrationConfig) {
75
+ if (!hasMigrationScript && !snapshot.migrationConfigExists) {
54
76
  return null;
55
77
  }
56
- return createDoctorCheck("Migration workspace", hasMigrationConfig ? "pass" : "fail", hasMigrationConfig
78
+ return createDoctorCheck("Migration workspace", snapshot.migrationConfigExists ? "pass" : "fail", snapshot.migrationConfigExists
57
79
  ? "Run `wp-typia migrate doctor --all` for migration target, snapshot, fixture, and generated artifact checks"
58
- : `Missing ${migrationConfigRelativePath} for the configured migration workspace`);
80
+ : `Missing ${snapshot.migrationConfigRelativePath} for the configured migration workspace`);
59
81
  }
@@ -7,6 +7,8 @@ export declare const WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js"
7
7
  export declare const WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
8
8
  /** Glob pattern for generated REST resource PHP entrypoints. */
9
9
  export declare const WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php";
10
+ /** Glob pattern for generated post-meta PHP entrypoints. */
11
+ export declare const WORKSPACE_POST_META_GLOB = "/inc/post-meta/*.php";
10
12
  /** Glob pattern for generated ability PHP entrypoints. */
11
13
  export declare const WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
12
14
  /** Relative path to the generated ability editor bundle. */
@@ -8,6 +8,8 @@ export const WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
8
8
  export const WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
9
9
  /** Glob pattern for generated REST resource PHP entrypoints. */
10
10
  export const WORKSPACE_REST_RESOURCE_GLOB = "/inc/rest/*.php";
11
+ /** Glob pattern for generated post-meta PHP entrypoints. */
12
+ export const WORKSPACE_POST_META_GLOB = "/inc/post-meta/*.php";
11
13
  /** Glob pattern for generated ability PHP entrypoints. */
12
14
  export const WORKSPACE_ABILITY_GLOB = "/inc/abilities/*.php";
13
15
  /** Relative path to the generated ability editor bundle. */
@@ -1,7 +1,7 @@
1
1
  import { getWorkspaceBindingDoctorChecks, } from "./cli-doctor-workspace-bindings.js";
2
2
  import { getWorkspaceBlockDoctorChecks, } from "./cli-doctor-workspace-blocks.js";
3
3
  import { getWorkspaceFeatureDoctorChecks, } from "./cli-doctor-workspace-features.js";
4
- import { getMigrationWorkspaceHintCheck, getWorkspacePackageMetadataCheck, } from "./cli-doctor-workspace-package.js";
4
+ import { getMigrationWorkspaceHintCheck, getWorkspacePackageMetadataCheck, prepareWorkspacePackageDoctorSnapshot, } from "./cli-doctor-workspace-package.js";
5
5
  import { createDoctorCheck, createDoctorScopeCheck, } from "./cli-doctor-workspace-shared.js";
6
6
  import { readWorkspaceInventoryAsync, } from "./workspace-inventory.js";
7
7
  import { getInvalidWorkspaceProjectReason, parseWorkspacePackageJson, tryResolveWorkspaceProject, } from "./workspace-project.js";
@@ -14,6 +14,7 @@ function formatWorkspaceInventorySummary(inventory) {
14
14
  `${inventory.patterns.length} pattern(s)`,
15
15
  `${inventory.bindingSources.length} binding source(s)`,
16
16
  `${inventory.restResources.length} REST resource(s)`,
17
+ `${inventory.postMeta.length} post meta contract(s)`,
17
18
  `${inventory.abilities.length} ability scaffold(s)`,
18
19
  `${inventory.aiFeatures.length} AI feature(s)`,
19
20
  `${inventory.editorPlugins.length} editor plugin(s)`,
@@ -73,14 +74,18 @@ export async function getWorkspaceDoctorChecks(cwd) {
73
74
  checks.push(createDoctorCheck("Workspace package metadata", "fail", error instanceof Error ? error.message : String(error)));
74
75
  return checks;
75
76
  }
76
- checks.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson));
77
+ const packageDoctorSnapshot = await prepareWorkspacePackageDoctorSnapshot(workspace, workspacePackageJson);
78
+ checks.push(getWorkspacePackageMetadataCheck(workspace, workspacePackageJson, packageDoctorSnapshot));
77
79
  try {
78
80
  const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
79
81
  checks.push(createDoctorCheck("Workspace inventory", "pass", formatWorkspaceInventorySummary(inventory)));
82
+ // The highest-impact remaining probes live in block, binding, and feature
83
+ // categories; keep them synchronous until broader path/content snapshots
84
+ // can preserve their current row ordering and diagnostics.
80
85
  checks.push(...getWorkspaceBlockDoctorChecks(workspace, inventory));
81
86
  checks.push(...getWorkspaceBindingDoctorChecks(workspace, inventory));
82
87
  checks.push(...getWorkspaceFeatureDoctorChecks(workspace, inventory));
83
- const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspace, workspacePackageJson);
88
+ const migrationWorkspaceCheck = getMigrationWorkspaceHintCheck(workspacePackageJson, packageDoctorSnapshot);
84
89
  if (migrationWorkspaceCheck) {
85
90
  checks.push(migrationWorkspaceCheck);
86
91
  }