@ankhorage/doctor 0.4.0 → 0.6.0

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.
@@ -1,57 +1,326 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { analyzeDoctorTarget, } from './analysis.js';
4
+ import { analyzeAppManifestTarget } from './manifestAnalysis.js';
4
5
  const LEGACY_ROOT_CLI_SOURCE = path.join('src', 'cli.ts');
5
6
  const CANONICAL_CLI_INDEX_SOURCE = path.join('src', 'cli', 'index.ts');
7
+ const ACTIVE_SOURCE_ROOTS = ['src', 'app', 'apps', 'packages', 'scripts'];
8
+ const ACTIVE_SOURCE_EXTENSIONS = new Set([
9
+ '.cjs',
10
+ '.cts',
11
+ '.js',
12
+ '.jsx',
13
+ '.mjs',
14
+ '.mts',
15
+ '.ts',
16
+ '.tsx',
17
+ ]);
18
+ const IGNORED_SOURCE_DIRECTORIES = new Set([
19
+ '.expo',
20
+ '.git',
21
+ '.next',
22
+ '__fixtures__',
23
+ '__tests__',
24
+ 'build',
25
+ 'coverage',
26
+ 'dist',
27
+ 'docs',
28
+ 'fixtures',
29
+ 'node_modules',
30
+ 'paradox',
31
+ 'test',
32
+ 'tests',
33
+ ]);
34
+ const COMPATIBILITY_PACKAGE_PREFIX = '@ankh/';
35
+ const STUDIO_PACKAGE_NAME = '@ankhorage/studio';
36
+ const STUDIO_DND_PACKAGE_NAME = '@ankhorage/react-native-reanimated-dnd-web';
37
+ const STUDIO_RUNTIME_PACKAGE_NAME = '@ankhorage/runtime';
38
+ const DEPENDENCY_FIELD_NAMES = [
39
+ 'dependencies',
40
+ 'devDependencies',
41
+ 'optionalDependencies',
42
+ 'peerDependencies',
43
+ ];
6
44
  export async function analyzeDoctorTargetWithCliLayout(request) {
45
+ const manifestResult = await analyzeAppManifestTarget(request);
46
+ if (manifestResult !== null) {
47
+ return manifestResult;
48
+ }
7
49
  const result = await analyzeDoctorTarget(request);
8
50
  if (!result.hasPackageJson) {
9
51
  return result;
10
52
  }
11
- const cliDiagnostics = await analyzeCliLayout(result.targetPath, result.profile);
12
- if (cliDiagnostics.length === 0) {
53
+ const packageJsonPath = path.join(result.targetPath, 'package.json');
54
+ const packageJson = await readPackageJson(packageJsonPath);
55
+ if (packageJson === null) {
56
+ return result;
57
+ }
58
+ const architectureDiagnostics = await analyzeTargetArchitecture({
59
+ packageJson,
60
+ packageJsonPath,
61
+ profile: result.profile,
62
+ targetPath: result.targetPath,
63
+ });
64
+ if (architectureDiagnostics.length === 0) {
13
65
  return result;
14
66
  }
15
- const diagnostics = [...result.diagnostics, ...cliDiagnostics];
67
+ const diagnostics = [...result.diagnostics, ...architectureDiagnostics];
16
68
  return {
17
69
  ...result,
18
70
  diagnostics,
19
71
  fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },
20
72
  };
21
73
  }
22
- async function analyzeCliLayout(targetPath, profile) {
74
+ async function analyzeTargetArchitecture(request) {
23
75
  const diagnostics = [];
24
- const legacyRootCliPath = path.join(targetPath, LEGACY_ROOT_CLI_SOURCE);
25
- const canonicalCliIndexPath = path.join(targetPath, CANONICAL_CLI_INDEX_SOURCE);
76
+ const legacyRootCliPath = path.join(request.targetPath, LEGACY_ROOT_CLI_SOURCE);
77
+ const canonicalCliIndexPath = path.join(request.targetPath, CANONICAL_CLI_INDEX_SOURCE);
78
+ const exportsField = isRecord(request.packageJson.exports) ? request.packageJson.exports : null;
79
+ const cliCapable = hasAnkhProvider(request.packageJson) ||
80
+ exportsField?.['./cli'] !== undefined ||
81
+ (await pathExists(canonicalCliIndexPath));
26
82
  if (await pathExists(legacyRootCliPath)) {
27
83
  diagnostics.push({
28
84
  code: 'field-invalid',
29
85
  message: 'Package CLI code must live under src/cli/; root src/cli.ts is not allowed.',
30
86
  path: legacyRootCliPath,
31
- profile,
87
+ profile: request.profile,
32
88
  ruleId: 'package.cli.root-file.disallowed',
33
89
  severity: 'error',
34
90
  });
35
91
  }
36
- const packageJson = await readPackageJson(path.join(targetPath, 'package.json'));
37
- if (packageJson !== null &&
38
- exposesCliProvider(packageJson) &&
39
- !(await pathExists(canonicalCliIndexPath))) {
92
+ if (cliCapable && !(await pathExists(canonicalCliIndexPath))) {
40
93
  diagnostics.push({
41
94
  code: 'missing-path',
42
95
  message: 'CLI-capable packages must expose their provider from src/cli/index.ts.',
43
96
  path: canonicalCliIndexPath,
44
- profile,
97
+ profile: request.profile,
45
98
  ruleId: 'package.cli.index.required',
46
99
  severity: 'error',
47
100
  });
48
101
  }
102
+ if (cliCapable && exportsField?.['./cli'] === undefined) {
103
+ diagnostics.push({
104
+ code: 'field-missing',
105
+ message: 'CLI-capable packages must export "./cli" from package.json and point it at the owning src/cli/index.ts build output.',
106
+ path: request.packageJsonPath,
107
+ profile: request.profile,
108
+ ruleId: 'package.cli.export.required',
109
+ severity: 'error',
110
+ });
111
+ }
112
+ const dependencyEntries = collectDependencyEntries(request.packageJson);
113
+ diagnostics.push(...validateDependencyArchitecture({
114
+ dependencyEntries,
115
+ packageJsonPath: request.packageJsonPath,
116
+ profile: request.profile,
117
+ }));
118
+ const activeSourceImports = await collectActiveSourceImports(request.targetPath);
119
+ diagnostics.push(...validateActiveSourceImports({
120
+ activeSourceImports,
121
+ profile: request.profile,
122
+ }));
123
+ if (request.packageJson.name === STUDIO_PACKAGE_NAME) {
124
+ diagnostics.push(...validateStudioOwnership({
125
+ activeSourceImports,
126
+ dependencyEntries,
127
+ packageJsonPath: request.packageJsonPath,
128
+ profile: request.profile,
129
+ }));
130
+ }
131
+ return diagnostics;
132
+ }
133
+ function validateDependencyArchitecture(request) {
134
+ const diagnostics = [];
135
+ for (const dependency of request.dependencyEntries) {
136
+ if (dependency.packageName.startsWith(COMPATIBILITY_PACKAGE_PREFIX)) {
137
+ diagnostics.push({
138
+ code: 'field-invalid',
139
+ message: `Dependency "${dependency.packageName}" in package.json.${dependency.fieldName} is an old ankhorage4 workspace alias. Depend on "${toOwningPackageSpecifier(dependency.packageName)}" directly.`,
140
+ path: request.packageJsonPath,
141
+ profile: request.profile,
142
+ ruleId: 'package.dependencies.ankh-workspace-alias.disallowed',
143
+ severity: 'error',
144
+ });
145
+ }
146
+ if (dependency.packageName.includes('ankhorage4') ||
147
+ dependency.version.includes('ankhorage4')) {
148
+ diagnostics.push({
149
+ code: 'field-invalid',
150
+ message: `Dependency "${dependency.packageName}" references ankhorage4 as active source. Depend on the extracted owning @ankhorage/* package instead.`,
151
+ path: request.packageJsonPath,
152
+ profile: request.profile,
153
+ ruleId: 'package.dependencies.ankhorage4-source.disallowed',
154
+ severity: 'error',
155
+ });
156
+ }
157
+ }
158
+ return diagnostics;
159
+ }
160
+ function validateActiveSourceImports(request) {
161
+ const diagnostics = [];
162
+ for (const sourceImport of request.activeSourceImports) {
163
+ if (sourceImport.specifier.startsWith(COMPATIBILITY_PACKAGE_PREFIX)) {
164
+ diagnostics.push({
165
+ code: 'field-invalid',
166
+ message: `Import "${sourceImport.specifier}" is an old ankhorage4 compatibility boundary. Import "${toOwningPackageSpecifier(sourceImport.specifier)}" directly from the owning package.`,
167
+ path: sourceImport.filePath,
168
+ profile: request.profile,
169
+ ruleId: 'package.imports.ankh-workspace-alias.disallowed',
170
+ severity: 'error',
171
+ });
172
+ }
173
+ if (sourceImport.specifier.includes('ankhorage4')) {
174
+ diagnostics.push({
175
+ code: 'field-invalid',
176
+ message: `Import "${sourceImport.specifier}" references ankhorage4 as active source. Import the extracted owning @ankhorage/* package instead.`,
177
+ path: sourceImport.filePath,
178
+ profile: request.profile,
179
+ ruleId: 'package.imports.ankhorage4-source.disallowed',
180
+ severity: 'error',
181
+ });
182
+ }
183
+ }
184
+ return diagnostics;
185
+ }
186
+ function validateStudioOwnership(request) {
187
+ const diagnostics = [];
188
+ const directDependencies = new Set(request.dependencyEntries
189
+ .filter((dependency) => dependency.fieldName === 'dependencies')
190
+ .map((dependency) => dependency.packageName));
191
+ const importedSpecifiers = request.activeSourceImports.map((sourceImport) => sourceImport.specifier);
192
+ if (!directDependencies.has(STUDIO_DND_PACKAGE_NAME)) {
193
+ diagnostics.push({
194
+ code: 'missing-dependency',
195
+ message: `@ankhorage/studio must depend directly on "${STUDIO_DND_PACKAGE_NAME}" for Studio drag-and-drop ownership.`,
196
+ path: request.packageJsonPath,
197
+ profile: request.profile,
198
+ ruleId: 'studio.dependencies.dnd.required',
199
+ severity: 'error',
200
+ });
201
+ }
202
+ if (!directDependencies.has(STUDIO_RUNTIME_PACKAGE_NAME)) {
203
+ diagnostics.push({
204
+ code: 'missing-dependency',
205
+ message: `@ankhorage/studio must depend directly on "${STUDIO_RUNTIME_PACKAGE_NAME}" for runtime ownership.`,
206
+ path: request.packageJsonPath,
207
+ profile: request.profile,
208
+ ruleId: 'studio.dependencies.runtime.required',
209
+ severity: 'error',
210
+ });
211
+ }
212
+ if (!importedSpecifiers.some((specifier) => isPackageImport(specifier, STUDIO_DND_PACKAGE_NAME))) {
213
+ diagnostics.push({
214
+ code: 'field-missing',
215
+ message: `@ankhorage/studio must import "${STUDIO_DND_PACKAGE_NAME}" directly from its Studio DnD boundary.`,
216
+ path: request.packageJsonPath,
217
+ profile: request.profile,
218
+ ruleId: 'studio.imports.dnd.required',
219
+ severity: 'error',
220
+ });
221
+ }
222
+ if (!importedSpecifiers.some((specifier) => isPackageImport(specifier, STUDIO_RUNTIME_PACKAGE_NAME))) {
223
+ diagnostics.push({
224
+ code: 'field-missing',
225
+ message: `@ankhorage/studio must import "${STUDIO_RUNTIME_PACKAGE_NAME}" directly from the owning runtime package.`,
226
+ path: request.packageJsonPath,
227
+ profile: request.profile,
228
+ ruleId: 'studio.imports.runtime.required',
229
+ severity: 'error',
230
+ });
231
+ }
49
232
  return diagnostics;
50
233
  }
51
- function exposesCliProvider(packageJson) {
234
+ async function collectActiveSourceImports(targetPath) {
235
+ const imports = [];
236
+ for (const sourceRoot of ACTIVE_SOURCE_ROOTS) {
237
+ const sourceRootPath = path.join(targetPath, sourceRoot);
238
+ if (!(await pathExists(sourceRootPath))) {
239
+ continue;
240
+ }
241
+ for (const filePath of await listActiveSourceFiles(sourceRootPath)) {
242
+ const source = await fs.readFile(filePath, 'utf8');
243
+ for (const specifier of extractImportSpecifiers(source)) {
244
+ imports.push({ filePath, specifier });
245
+ }
246
+ }
247
+ }
248
+ return imports;
249
+ }
250
+ async function listActiveSourceFiles(rootPath) {
251
+ const files = [];
252
+ await visit(rootPath);
253
+ return files.sort((left, right) => left.localeCompare(right));
254
+ async function visit(currentPath) {
255
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
256
+ for (const entry of entries) {
257
+ if (entry.isDirectory()) {
258
+ if (!IGNORED_SOURCE_DIRECTORIES.has(entry.name)) {
259
+ await visit(path.join(currentPath, entry.name));
260
+ }
261
+ continue;
262
+ }
263
+ if (!entry.isFile()) {
264
+ continue;
265
+ }
266
+ const filePath = path.join(currentPath, entry.name);
267
+ if (isActiveSourceFile(filePath)) {
268
+ files.push(filePath);
269
+ }
270
+ }
271
+ }
272
+ }
273
+ function isActiveSourceFile(filePath) {
274
+ if (!ACTIVE_SOURCE_EXTENSIONS.has(path.extname(filePath))) {
275
+ return false;
276
+ }
277
+ return !/(?:^|\.)(?:spec|test)\.[cm]?[jt]sx?$/.test(path.basename(filePath));
278
+ }
279
+ function extractImportSpecifiers(source) {
280
+ const specifiers = new Set();
281
+ const patterns = [
282
+ /\b(?:import|export)\s+(?:type\s+)?(?:[^;]*?\sfrom\s*)?['"]([^'"]+)['"]/g,
283
+ /\b(?:import|require)\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
284
+ ];
285
+ for (const pattern of patterns) {
286
+ for (const match of source.matchAll(pattern)) {
287
+ const [, specifier] = match;
288
+ if (specifier !== undefined) {
289
+ specifiers.add(specifier);
290
+ }
291
+ }
292
+ }
293
+ return [...specifiers].sort((left, right) => left.localeCompare(right));
294
+ }
295
+ function collectDependencyEntries(packageJson) {
296
+ const entries = [];
297
+ for (const fieldName of DEPENDENCY_FIELD_NAMES) {
298
+ const dependencies = isRecord(packageJson[fieldName]) ? packageJson[fieldName] : null;
299
+ if (dependencies === null) {
300
+ continue;
301
+ }
302
+ for (const [packageName, version] of Object.entries(dependencies)) {
303
+ if (isNonEmptyString(version)) {
304
+ entries.push({ fieldName, packageName, version });
305
+ }
306
+ }
307
+ }
308
+ return entries.sort((left, right) => {
309
+ const fieldComparison = left.fieldName.localeCompare(right.fieldName);
310
+ return fieldComparison !== 0
311
+ ? fieldComparison
312
+ : left.packageName.localeCompare(right.packageName);
313
+ });
314
+ }
315
+ function hasAnkhProvider(packageJson) {
52
316
  const ankh = isRecord(packageJson.ankh) ? packageJson.ankh : null;
53
- const exportsField = isRecord(packageJson.exports) ? packageJson.exports : null;
54
- return isNonEmptyString(ankh?.provider) || exportsField?.['./cli'] !== undefined;
317
+ return isNonEmptyString(ankh?.provider);
318
+ }
319
+ function isPackageImport(specifier, packageName) {
320
+ return specifier === packageName || specifier.startsWith(`${packageName}/`);
321
+ }
322
+ function toOwningPackageSpecifier(specifier) {
323
+ return `@ankhorage/${specifier.slice(COMPATIBILITY_PACKAGE_PREFIX.length)}`;
55
324
  }
56
325
  async function readPackageJson(packageJsonPath) {
57
326
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"cliLayoutAnalysis.js","sourceRoot":"","sources":["../src/cliLayoutAnalysis.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport {\n analyzeDoctorTarget,\n type DoctorAnalysisRequest,\n type DoctorAnalysisResult,\n} from './analysis.js';\nimport type { DoctorDiagnostic, DoctorPolicyProfile } from './diagnostics.js';\n\nconst LEGACY_ROOT_CLI_SOURCE = path.join('src', 'cli.ts');\nconst CANONICAL_CLI_INDEX_SOURCE = path.join('src', 'cli', 'index.ts');\n\nexport async function analyzeDoctorTargetWithCliLayout(\n request: DoctorAnalysisRequest,\n): Promise<DoctorAnalysisResult> {\n const result = await analyzeDoctorTarget(request);\n if (!result.hasPackageJson) {\n return result;\n }\n\n const cliDiagnostics = await analyzeCliLayout(result.targetPath, result.profile);\n if (cliDiagnostics.length === 0) {\n return result;\n }\n\n const diagnostics = [...result.diagnostics, ...cliDiagnostics];\n\n return {\n ...result,\n diagnostics,\n fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },\n };\n}\n\nasync function analyzeCliLayout(\n targetPath: string,\n profile: DoctorPolicyProfile,\n): Promise<DoctorDiagnostic[]> {\n const diagnostics: DoctorDiagnostic[] = [];\n const legacyRootCliPath = path.join(targetPath, LEGACY_ROOT_CLI_SOURCE);\n const canonicalCliIndexPath = path.join(targetPath, CANONICAL_CLI_INDEX_SOURCE);\n\n if (await pathExists(legacyRootCliPath)) {\n diagnostics.push({\n code: 'field-invalid',\n message: 'Package CLI code must live under src/cli/; root src/cli.ts is not allowed.',\n path: legacyRootCliPath,\n profile,\n ruleId: 'package.cli.root-file.disallowed',\n severity: 'error',\n });\n }\n\n const packageJson = await readPackageJson(path.join(targetPath, 'package.json'));\n if (\n packageJson !== null &&\n exposesCliProvider(packageJson) &&\n !(await pathExists(canonicalCliIndexPath))\n ) {\n diagnostics.push({\n code: 'missing-path',\n message: 'CLI-capable packages must expose their provider from src/cli/index.ts.',\n path: canonicalCliIndexPath,\n profile,\n ruleId: 'package.cli.index.required',\n severity: 'error',\n });\n }\n\n return diagnostics;\n}\n\nfunction exposesCliProvider(packageJson: Record<string, unknown>): boolean {\n const ankh = isRecord(packageJson.ankh) ? packageJson.ankh : null;\n const exportsField = isRecord(packageJson.exports) ? packageJson.exports : null;\n\n return isNonEmptyString(ankh?.provider) || exportsField?.['./cli'] !== undefined;\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed: unknown = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await fs.access(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
1
+ {"version":3,"file":"cliLayoutAnalysis.js","sourceRoot":"","sources":["../src/cliLayoutAnalysis.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport {\n analyzeDoctorTarget,\n type DoctorAnalysisRequest,\n type DoctorAnalysisResult,\n} from './analysis.js';\nimport type { DoctorDiagnostic, DoctorPolicyProfile } from './diagnostics.js';\nimport { analyzeAppManifestTarget } from './manifestAnalysis.js';\n\nconst LEGACY_ROOT_CLI_SOURCE = path.join('src', 'cli.ts');\nconst CANONICAL_CLI_INDEX_SOURCE = path.join('src', 'cli', 'index.ts');\nconst ACTIVE_SOURCE_ROOTS = ['src', 'app', 'apps', 'packages', 'scripts'] as const;\nconst ACTIVE_SOURCE_EXTENSIONS = new Set([\n '.cjs',\n '.cts',\n '.js',\n '.jsx',\n '.mjs',\n '.mts',\n '.ts',\n '.tsx',\n]);\nconst IGNORED_SOURCE_DIRECTORIES = new Set([\n '.expo',\n '.git',\n '.next',\n '__fixtures__',\n '__tests__',\n 'build',\n 'coverage',\n 'dist',\n 'docs',\n 'fixtures',\n 'node_modules',\n 'paradox',\n 'test',\n 'tests',\n]);\nconst COMPATIBILITY_PACKAGE_PREFIX = '@ankh/';\nconst STUDIO_PACKAGE_NAME = '@ankhorage/studio';\nconst STUDIO_DND_PACKAGE_NAME = '@ankhorage/react-native-reanimated-dnd-web';\nconst STUDIO_RUNTIME_PACKAGE_NAME = '@ankhorage/runtime';\nconst DEPENDENCY_FIELD_NAMES = [\n 'dependencies',\n 'devDependencies',\n 'optionalDependencies',\n 'peerDependencies',\n] as const;\n\ninterface ActiveSourceImport {\n readonly filePath: string;\n readonly specifier: string;\n}\n\ninterface DependencyEntry {\n readonly fieldName: (typeof DEPENDENCY_FIELD_NAMES)[number];\n readonly packageName: string;\n readonly version: string;\n}\n\nexport async function analyzeDoctorTargetWithCliLayout(\n request: DoctorAnalysisRequest,\n): Promise<DoctorAnalysisResult> {\n const manifestResult = await analyzeAppManifestTarget(request);\n if (manifestResult !== null) {\n return manifestResult;\n }\n\n const result = await analyzeDoctorTarget(request);\n if (!result.hasPackageJson) {\n return result;\n }\n\n const packageJsonPath = path.join(result.targetPath, 'package.json');\n const packageJson = await readPackageJson(packageJsonPath);\n if (packageJson === null) {\n return result;\n }\n\n const architectureDiagnostics = await analyzeTargetArchitecture({\n packageJson,\n packageJsonPath,\n profile: result.profile,\n targetPath: result.targetPath,\n });\n if (architectureDiagnostics.length === 0) {\n return result;\n }\n\n const diagnostics = [...result.diagnostics, ...architectureDiagnostics];\n\n return {\n ...result,\n diagnostics,\n fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },\n };\n}\n\nasync function analyzeTargetArchitecture(request: {\n readonly packageJson: Record<string, unknown>;\n readonly packageJsonPath: string;\n readonly profile: DoctorPolicyProfile;\n readonly targetPath: string;\n}): Promise<DoctorDiagnostic[]> {\n const diagnostics: DoctorDiagnostic[] = [];\n const legacyRootCliPath = path.join(request.targetPath, LEGACY_ROOT_CLI_SOURCE);\n const canonicalCliIndexPath = path.join(request.targetPath, CANONICAL_CLI_INDEX_SOURCE);\n const exportsField = isRecord(request.packageJson.exports) ? request.packageJson.exports : null;\n const cliCapable =\n hasAnkhProvider(request.packageJson) ||\n exportsField?.['./cli'] !== undefined ||\n (await pathExists(canonicalCliIndexPath));\n\n if (await pathExists(legacyRootCliPath)) {\n diagnostics.push({\n code: 'field-invalid',\n message: 'Package CLI code must live under src/cli/; root src/cli.ts is not allowed.',\n path: legacyRootCliPath,\n profile: request.profile,\n ruleId: 'package.cli.root-file.disallowed',\n severity: 'error',\n });\n }\n\n if (cliCapable && !(await pathExists(canonicalCliIndexPath))) {\n diagnostics.push({\n code: 'missing-path',\n message: 'CLI-capable packages must expose their provider from src/cli/index.ts.',\n path: canonicalCliIndexPath,\n profile: request.profile,\n ruleId: 'package.cli.index.required',\n severity: 'error',\n });\n }\n\n if (cliCapable && exportsField?.['./cli'] === undefined) {\n diagnostics.push({\n code: 'field-missing',\n message:\n 'CLI-capable packages must export \"./cli\" from package.json and point it at the owning src/cli/index.ts build output.',\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'package.cli.export.required',\n severity: 'error',\n });\n }\n\n const dependencyEntries = collectDependencyEntries(request.packageJson);\n diagnostics.push(\n ...validateDependencyArchitecture({\n dependencyEntries,\n packageJsonPath: request.packageJsonPath,\n profile: request.profile,\n }),\n );\n\n const activeSourceImports = await collectActiveSourceImports(request.targetPath);\n diagnostics.push(\n ...validateActiveSourceImports({\n activeSourceImports,\n profile: request.profile,\n }),\n );\n\n if (request.packageJson.name === STUDIO_PACKAGE_NAME) {\n diagnostics.push(\n ...validateStudioOwnership({\n activeSourceImports,\n dependencyEntries,\n packageJsonPath: request.packageJsonPath,\n profile: request.profile,\n }),\n );\n }\n\n return diagnostics;\n}\n\nfunction validateDependencyArchitecture(request: {\n readonly dependencyEntries: readonly DependencyEntry[];\n readonly packageJsonPath: string;\n readonly profile: DoctorPolicyProfile;\n}): DoctorDiagnostic[] {\n const diagnostics: DoctorDiagnostic[] = [];\n\n for (const dependency of request.dependencyEntries) {\n if (dependency.packageName.startsWith(COMPATIBILITY_PACKAGE_PREFIX)) {\n diagnostics.push({\n code: 'field-invalid',\n message: `Dependency \"${dependency.packageName}\" in package.json.${dependency.fieldName} is an old ankhorage4 workspace alias. Depend on \"${toOwningPackageSpecifier(dependency.packageName)}\" directly.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'package.dependencies.ankh-workspace-alias.disallowed',\n severity: 'error',\n });\n }\n\n if (\n dependency.packageName.includes('ankhorage4') ||\n dependency.version.includes('ankhorage4')\n ) {\n diagnostics.push({\n code: 'field-invalid',\n message: `Dependency \"${dependency.packageName}\" references ankhorage4 as active source. Depend on the extracted owning @ankhorage/* package instead.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'package.dependencies.ankhorage4-source.disallowed',\n severity: 'error',\n });\n }\n }\n\n return diagnostics;\n}\n\nfunction validateActiveSourceImports(request: {\n readonly activeSourceImports: readonly ActiveSourceImport[];\n readonly profile: DoctorPolicyProfile;\n}): DoctorDiagnostic[] {\n const diagnostics: DoctorDiagnostic[] = [];\n\n for (const sourceImport of request.activeSourceImports) {\n if (sourceImport.specifier.startsWith(COMPATIBILITY_PACKAGE_PREFIX)) {\n diagnostics.push({\n code: 'field-invalid',\n message: `Import \"${sourceImport.specifier}\" is an old ankhorage4 compatibility boundary. Import \"${toOwningPackageSpecifier(sourceImport.specifier)}\" directly from the owning package.`,\n path: sourceImport.filePath,\n profile: request.profile,\n ruleId: 'package.imports.ankh-workspace-alias.disallowed',\n severity: 'error',\n });\n }\n\n if (sourceImport.specifier.includes('ankhorage4')) {\n diagnostics.push({\n code: 'field-invalid',\n message: `Import \"${sourceImport.specifier}\" references ankhorage4 as active source. Import the extracted owning @ankhorage/* package instead.`,\n path: sourceImport.filePath,\n profile: request.profile,\n ruleId: 'package.imports.ankhorage4-source.disallowed',\n severity: 'error',\n });\n }\n }\n\n return diagnostics;\n}\n\nfunction validateStudioOwnership(request: {\n readonly activeSourceImports: readonly ActiveSourceImport[];\n readonly dependencyEntries: readonly DependencyEntry[];\n readonly packageJsonPath: string;\n readonly profile: DoctorPolicyProfile;\n}): DoctorDiagnostic[] {\n const diagnostics: DoctorDiagnostic[] = [];\n const directDependencies = new Set(\n request.dependencyEntries\n .filter((dependency) => dependency.fieldName === 'dependencies')\n .map((dependency) => dependency.packageName),\n );\n const importedSpecifiers = request.activeSourceImports.map(\n (sourceImport) => sourceImport.specifier,\n );\n\n if (!directDependencies.has(STUDIO_DND_PACKAGE_NAME)) {\n diagnostics.push({\n code: 'missing-dependency',\n message: `@ankhorage/studio must depend directly on \"${STUDIO_DND_PACKAGE_NAME}\" for Studio drag-and-drop ownership.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'studio.dependencies.dnd.required',\n severity: 'error',\n });\n }\n\n if (!directDependencies.has(STUDIO_RUNTIME_PACKAGE_NAME)) {\n diagnostics.push({\n code: 'missing-dependency',\n message: `@ankhorage/studio must depend directly on \"${STUDIO_RUNTIME_PACKAGE_NAME}\" for runtime ownership.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'studio.dependencies.runtime.required',\n severity: 'error',\n });\n }\n\n if (\n !importedSpecifiers.some((specifier) => isPackageImport(specifier, STUDIO_DND_PACKAGE_NAME))\n ) {\n diagnostics.push({\n code: 'field-missing',\n message: `@ankhorage/studio must import \"${STUDIO_DND_PACKAGE_NAME}\" directly from its Studio DnD boundary.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'studio.imports.dnd.required',\n severity: 'error',\n });\n }\n\n if (\n !importedSpecifiers.some((specifier) => isPackageImport(specifier, STUDIO_RUNTIME_PACKAGE_NAME))\n ) {\n diagnostics.push({\n code: 'field-missing',\n message: `@ankhorage/studio must import \"${STUDIO_RUNTIME_PACKAGE_NAME}\" directly from the owning runtime package.`,\n path: request.packageJsonPath,\n profile: request.profile,\n ruleId: 'studio.imports.runtime.required',\n severity: 'error',\n });\n }\n\n return diagnostics;\n}\n\nasync function collectActiveSourceImports(targetPath: string): Promise<ActiveSourceImport[]> {\n const imports: ActiveSourceImport[] = [];\n\n for (const sourceRoot of ACTIVE_SOURCE_ROOTS) {\n const sourceRootPath = path.join(targetPath, sourceRoot);\n if (!(await pathExists(sourceRootPath))) {\n continue;\n }\n\n for (const filePath of await listActiveSourceFiles(sourceRootPath)) {\n const source = await fs.readFile(filePath, 'utf8');\n for (const specifier of extractImportSpecifiers(source)) {\n imports.push({ filePath, specifier });\n }\n }\n }\n\n return imports;\n}\n\nasync function listActiveSourceFiles(rootPath: string): Promise<string[]> {\n const files: string[] = [];\n await visit(rootPath);\n return files.sort((left, right) => left.localeCompare(right));\n\n async function visit(currentPath: string): Promise<void> {\n const entries = await fs.readdir(currentPath, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (!IGNORED_SOURCE_DIRECTORIES.has(entry.name)) {\n await visit(path.join(currentPath, entry.name));\n }\n continue;\n }\n\n if (!entry.isFile()) {\n continue;\n }\n\n const filePath = path.join(currentPath, entry.name);\n if (isActiveSourceFile(filePath)) {\n files.push(filePath);\n }\n }\n }\n}\n\nfunction isActiveSourceFile(filePath: string): boolean {\n if (!ACTIVE_SOURCE_EXTENSIONS.has(path.extname(filePath))) {\n return false;\n }\n\n return !/(?:^|\\.)(?:spec|test)\\.[cm]?[jt]sx?$/.test(path.basename(filePath));\n}\n\nfunction extractImportSpecifiers(source: string): string[] {\n const specifiers = new Set<string>();\n const patterns = [\n /\\b(?:import|export)\\s+(?:type\\s+)?(?:[^;]*?\\sfrom\\s*)?['\"]([^'\"]+)['\"]/g,\n /\\b(?:import|require)\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g,\n ];\n\n for (const pattern of patterns) {\n for (const match of source.matchAll(pattern)) {\n const [, specifier] = match;\n if (specifier !== undefined) {\n specifiers.add(specifier);\n }\n }\n }\n\n return [...specifiers].sort((left, right) => left.localeCompare(right));\n}\n\nfunction collectDependencyEntries(packageJson: Record<string, unknown>): DependencyEntry[] {\n const entries: DependencyEntry[] = [];\n\n for (const fieldName of DEPENDENCY_FIELD_NAMES) {\n const dependencies = isRecord(packageJson[fieldName]) ? packageJson[fieldName] : null;\n if (dependencies === null) {\n continue;\n }\n\n for (const [packageName, version] of Object.entries(dependencies)) {\n if (isNonEmptyString(version)) {\n entries.push({ fieldName, packageName, version });\n }\n }\n }\n\n return entries.sort((left, right) => {\n const fieldComparison = left.fieldName.localeCompare(right.fieldName);\n return fieldComparison !== 0\n ? fieldComparison\n : left.packageName.localeCompare(right.packageName);\n });\n}\n\nfunction hasAnkhProvider(packageJson: Record<string, unknown>): boolean {\n const ankh = isRecord(packageJson.ankh) ? packageJson.ankh : null;\n return isNonEmptyString(ankh?.provider);\n}\n\nfunction isPackageImport(specifier: string, packageName: string): boolean {\n return specifier === packageName || specifier.startsWith(`${packageName}/`);\n}\n\nfunction toOwningPackageSpecifier(specifier: string): string {\n return `@ankhorage/${specifier.slice(COMPATIBILITY_PACKAGE_PREFIX.length)}`;\n}\n\nasync function readPackageJson(packageJsonPath: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed: unknown = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await fs.access(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { AnkhCapabilityId, AnkhCommandDescriptor } from '@ankhorage/contracts/cli';
2
2
  import type { DoctorTargetMode } from './analysis.js';
3
- import { analyzeDoctorTarget } from './analysis.js';
3
+ import { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';
4
4
  import type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
5
5
  type DoctorCommandName = 'fix' | 'package' | 'repo' | 'validate';
6
6
  interface DoctorCommandRunRequest {
@@ -22,7 +22,7 @@ export interface DoctorCommandInvocation {
22
22
  readonly context: DoctorCommandContext;
23
23
  }
24
24
  export interface DoctorCommandServices {
25
- readonly analyzeTarget: typeof analyzeDoctorTarget;
25
+ readonly analyzeTarget: typeof analyzeDoctorTargetWithCliLayout;
26
26
  }
27
27
  export interface RunDoctorCommandOptions {
28
28
  readonly runCommandImpl?: RunDoctorCommandImpl;
@@ -34,7 +34,7 @@ export declare const DOCTOR_COMMANDS: readonly [{
34
34
  readonly path: readonly ["validate"];
35
35
  readonly capability: "doctor.validate";
36
36
  readonly mode: "validate";
37
- readonly summary: "Auto-detect the applicable doctor policy profile and validate a local path.";
37
+ readonly summary: "Validate a repo, package, or app-manifest JSON path with the applicable Doctor profile.";
38
38
  readonly run: typeof runValidateCommand;
39
39
  }, {
40
40
  readonly standaloneName: "fix";
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,KAAK,EAA6C,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAQxF,KAAK,iBAAiB,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjE,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,KAAK,2BAA2B,GAAG,CACjC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,KAC5B,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAErC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,2BAA2B,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,mBAAmB,CAAC;CACpD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,uBAAuB,EAChC,OAAO,CAAC,EAAE,uBAAuB,KAC9B,OAAO,CAAC,sBAAsB,CAAC,CAAC;AASrC,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC2B,CAAC;AAExD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,EAChC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CAqBjC;AAED,wBAAgB,gCAAgC,IAAI,SAAS,qBAAqB,EAAE,CAMnF;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAE/F;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBtD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AA4CD,iBAAe,kBAAkB,CAC/B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,aAAa,CAC1B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,cAAc,CAC3B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,iBAAiB,CAC9B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,KAAK,EAA6C,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAQxF,KAAK,iBAAiB,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjE,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,KAAK,2BAA2B,GAAG,CACjC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,KAC5B,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAErC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,2BAA2B,CAAC;CAC3C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,OAAO,gCAAgC,CAAC;CACjE;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,OAAO,EAAE,uBAAuB,EAChC,OAAO,CAAC,EAAE,uBAAuB,KAC9B,OAAO,CAAC,sBAAsB,CAAC,CAAC;AASrC,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC2B,CAAC;AAExD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,EAChC,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CAqBjC;AAED,wBAAgB,gCAAgC,IAAI,SAAS,qBAAqB,EAAE,CAMnF;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAE/F;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBtD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AA4CD,iBAAe,kBAAkB,CAC/B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,aAAa,CAC1B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,cAAc,CAC3B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAED,iBAAe,iBAAiB,CAC9B,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC"}
package/dist/commands.js CHANGED
@@ -1,4 +1,4 @@
1
- import { analyzeDoctorTarget } from './analysis.js';
1
+ import { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';
2
2
  import { countErrorDiagnostics, countWarningDiagnostics, } from './diagnostics.js';
3
3
  import { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY } from './packageMetadata.js';
4
4
  const COMMAND_CAPABILITIES = {
@@ -13,7 +13,7 @@ export const DOCTOR_COMMANDS = [
13
13
  path: ['validate'],
14
14
  capability: COMMAND_CAPABILITIES.validate,
15
15
  mode: 'validate',
16
- summary: 'Auto-detect the applicable doctor policy profile and validate a local path.',
16
+ summary: 'Validate a repo, package, or app-manifest JSON path with the applicable Doctor profile.',
17
17
  run: runValidateCommand,
18
18
  },
19
19
  {
@@ -82,7 +82,7 @@ export function renderRootHelp(version) {
82
82
  commandLines,
83
83
  '',
84
84
  'Path resolution:',
85
- ' Pass [path], or omit it to validate the current working directory.',
85
+ ' Pass a repo/package directory or app-manifest JSON file, or omit [path] to inspect the current directory.',
86
86
  '',
87
87
  ].join('\n');
88
88
  }
@@ -98,13 +98,13 @@ function renderCommandHelp(command) {
98
98
  ` ankh ${DOCTOR_COMMAND_CATEGORY} ${command.path.join(' ')} [path]`,
99
99
  '',
100
100
  'Path resolution:',
101
- ' Pass [path], or omit it to validate the current working directory.',
101
+ ' Pass a repo/package directory or app-manifest JSON file, or omit [path] to inspect the current directory.',
102
102
  '',
103
103
  ].join('\n');
104
104
  }
105
105
  function createDoctorCommandServices(overrides = {}) {
106
106
  return {
107
- analyzeTarget: overrides.analyzeTarget ?? analyzeDoctorTarget,
107
+ analyzeTarget: overrides.analyzeTarget ?? analyzeDoctorTargetWithCliLayout,
108
108
  };
109
109
  }
110
110
  function parseCommandArguments(command, argv) {
@@ -1 +1 @@
1
- {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnkhCapabilityId, AnkhCommandDescriptor } from '@ankhorage/contracts/cli';\n\nimport type { DoctorAnalysisResult, DoctorPlannedChange, DoctorTargetMode } from './analysis.js';\nimport { analyzeDoctorTarget } from './analysis.js';\nimport type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';\nimport {\n countErrorDiagnostics,\n countWarningDiagnostics,\n type DoctorDiagnostic,\n} from './diagnostics.js';\nimport { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY } from './packageMetadata.js';\n\ntype DoctorCommandName = 'fix' | 'package' | 'repo' | 'validate';\n\ninterface DoctorCommandRunRequest {\n readonly context: DoctorCommandContext;\n readonly inputPath?: string;\n}\n\ntype DoctorCommandImplementation = (\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n) => Promise<DoctorCommandRunResult>;\n\nexport interface DoctorCommandDefinition {\n readonly capability: AnkhCapabilityId;\n readonly mode: DoctorTargetMode;\n readonly path: readonly [DoctorCommandName];\n readonly standaloneName: DoctorCommandName;\n readonly summary: string;\n readonly run: DoctorCommandImplementation;\n}\n\nexport interface DoctorCommandInvocation {\n readonly argv: readonly string[];\n readonly command: DoctorCommandDefinition;\n readonly context: DoctorCommandContext;\n}\n\nexport interface DoctorCommandServices {\n readonly analyzeTarget: typeof analyzeDoctorTarget;\n}\n\nexport interface RunDoctorCommandOptions {\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport type RunDoctorCommandImpl = (\n request: DoctorCommandInvocation,\n options?: RunDoctorCommandOptions,\n) => Promise<DoctorCommandRunResult>;\n\nconst COMMAND_CAPABILITIES = {\n validate: DOCTOR_CAPABILITIES[0],\n fix: DOCTOR_CAPABILITIES[1],\n repo: DOCTOR_CAPABILITIES[2],\n package: DOCTOR_CAPABILITIES[3],\n} as const satisfies Record<DoctorCommandName, AnkhCapabilityId>;\n\nexport const DOCTOR_COMMANDS = [\n {\n standaloneName: 'validate',\n path: ['validate'],\n capability: COMMAND_CAPABILITIES.validate,\n mode: 'validate',\n summary: 'Auto-detect the applicable doctor policy profile and validate a local path.',\n run: runValidateCommand,\n },\n {\n standaloneName: 'fix',\n path: ['fix'],\n capability: COMMAND_CAPABILITIES.fix,\n mode: 'fix',\n summary: 'Build a non-mutating fix plan for deterministic doctor policy violations.',\n run: runFixCommand,\n },\n {\n standaloneName: 'repo',\n path: ['repo'],\n capability: COMMAND_CAPABILITIES.repo,\n mode: 'repo',\n summary: 'Force repo-light diagnostics for a repo/workspace-root candidate path.',\n run: runRepoCommand,\n },\n {\n standaloneName: 'package',\n path: ['package'],\n capability: COMMAND_CAPABILITIES.package,\n mode: 'package',\n summary: 'Force package-light diagnostics for a directory containing package.json.',\n run: runPackageCommand,\n },\n] as const satisfies readonly DoctorCommandDefinition[];\n\nexport async function runDoctorCommand(\n request: DoctorCommandInvocation,\n options: RunDoctorCommandOptions = {},\n): Promise<DoctorCommandRunResult> {\n const services = createDoctorCommandServices(options.services);\n\n try {\n const parsedArgs = parseCommandArguments(request.command, request.argv);\n if (parsedArgs.kind === 'help') {\n request.context.writeStdout(renderCommandHelp(request.command));\n return { exitCode: 0 };\n }\n\n return await request.command.run(\n {\n context: request.context,\n inputPath: parsedArgs.inputPath,\n },\n services,\n );\n } catch (error) {\n request.context.writeStderr(renderCommandFailure(request.command.standaloneName, error));\n return { exitCode: 1 };\n }\n}\n\nexport function createProviderCommandDescriptors(): readonly AnkhCommandDescriptor[] {\n return DOCTOR_COMMANDS.map((command) => ({\n capability: command.capability,\n path: command.path,\n summary: command.summary,\n }));\n}\n\nexport function findDoctorCommandByStandaloneName(value: string): DoctorCommandDefinition | null {\n return DOCTOR_COMMANDS.find((command) => command.standaloneName === value) ?? null;\n}\n\nexport function renderRootHelp(version: string): string {\n const commandLines = DOCTOR_COMMANDS.map(\n (command) => ` ${command.standaloneName.padEnd(8, ' ')} ${command.summary}`,\n ).join('\\n');\n\n return [\n `@ankhorage/doctor v${version}`,\n '',\n 'Usage:',\n ' ankhorage-doctor <command> [path]',\n ` ankh ${DOCTOR_COMMAND_CATEGORY} <command> [path]`,\n '',\n 'Commands:',\n commandLines,\n '',\n 'Path resolution:',\n ' Pass [path], or omit it to validate the current working directory.',\n '',\n ].join('\\n');\n}\n\nexport function renderUnknownCommand(value: string): string {\n return [`Unknown doctor command: ${value}`, '', 'Run ankhorage-doctor --help', ''].join('\\n');\n}\n\nfunction renderCommandHelp(command: DoctorCommandDefinition): string {\n return [\n command.summary,\n '',\n 'Usage:',\n ` ankhorage-doctor ${command.standaloneName} [path]`,\n ` ankh ${DOCTOR_COMMAND_CATEGORY} ${command.path.join(' ')} [path]`,\n '',\n 'Path resolution:',\n ' Pass [path], or omit it to validate the current working directory.',\n '',\n ].join('\\n');\n}\n\nfunction createDoctorCommandServices(\n overrides: Partial<DoctorCommandServices> = {},\n): DoctorCommandServices {\n return {\n analyzeTarget: overrides.analyzeTarget ?? analyzeDoctorTarget,\n };\n}\n\nfunction parseCommandArguments(\n command: DoctorCommandDefinition,\n argv: readonly string[],\n): { readonly kind: 'help' } | { readonly kind: 'run'; readonly inputPath?: string } {\n const [firstArg] = argv;\n\n if (argv.length === 1 && firstArg !== undefined && isHelpToken(firstArg)) {\n return { kind: 'help' };\n }\n\n if (argv.length > 1) {\n throw new Error(`Doctor ${command.standaloneName} accepts at most one path argument.`);\n }\n\n return {\n kind: 'run',\n inputPath: firstArg,\n };\n}\n\nasync function runValidateCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'validate',\n });\n\n request.context.writeStdout(renderAnalysisReport('validate', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runFixCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'fix',\n });\n\n request.context.writeStdout(renderAnalysisReport('fix', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runRepoCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'repo',\n });\n\n request.context.writeStdout(renderAnalysisReport('repo', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runPackageCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'package',\n });\n\n request.context.writeStdout(renderAnalysisReport('package', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nfunction renderAnalysisReport(\n commandName: DoctorCommandName,\n result: DoctorAnalysisResult,\n): string {\n const lines = [\n `doctor ${commandName}`,\n `target: ${result.targetPath}`,\n `profile: ${result.profile}`,\n `checks: ${result.appliedChecks.length > 0 ? result.appliedChecks.join(', ') : 'none'}`,\n `repoMarkers: ${result.repoMarkers.length > 0 ? result.repoMarkers.join(', ') : 'none'}`,\n '',\n 'Diagnostics:',\n ];\n\n if (result.diagnostics.length === 0) {\n lines.push(' none');\n } else {\n for (const diagnostic of result.diagnostics) {\n lines.push(renderDiagnosticLine(diagnostic));\n }\n }\n\n if (commandName === 'fix') {\n lines.push('');\n lines.push('Planned changes:');\n\n if (result.plannedChanges.length === 0) {\n lines.push(' none');\n } else {\n for (const change of result.plannedChanges) {\n lines.push(renderPlannedChangeLine(change));\n }\n }\n }\n\n const errorCount = countErrorDiagnostics(result.diagnostics);\n const warningCount = countWarningDiagnostics(result.diagnostics);\n\n lines.push('');\n lines.push(`Summary: ${errorCount} error(s), ${warningCount} warning(s)`);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nfunction renderDiagnosticLine(diagnostic: DoctorDiagnostic): string {\n return ` - ${diagnostic.severity.toUpperCase()} ${diagnostic.ruleId} (${diagnostic.code}): ${diagnostic.message}`;\n}\n\nfunction renderPlannedChangeLine(change: DoctorPlannedChange): string {\n return ` - ${change.ruleId} [${change.kind}]: ${change.description}`;\n}\n\nfunction renderCommandFailure(commandName: DoctorCommandName, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return [`Failed to run doctor ${commandName}: ${message}`, ''].join('\\n');\n}\n\nfunction isHelpToken(value: string): boolean {\n return value === '--help' || value === '-h' || value === 'help';\n}\n"]}
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnkhCapabilityId, AnkhCommandDescriptor } from '@ankhorage/contracts/cli';\n\nimport type { DoctorAnalysisResult, DoctorPlannedChange, DoctorTargetMode } from './analysis.js';\nimport { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';\nimport type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';\nimport {\n countErrorDiagnostics,\n countWarningDiagnostics,\n type DoctorDiagnostic,\n} from './diagnostics.js';\nimport { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY } from './packageMetadata.js';\n\ntype DoctorCommandName = 'fix' | 'package' | 'repo' | 'validate';\n\ninterface DoctorCommandRunRequest {\n readonly context: DoctorCommandContext;\n readonly inputPath?: string;\n}\n\ntype DoctorCommandImplementation = (\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n) => Promise<DoctorCommandRunResult>;\n\nexport interface DoctorCommandDefinition {\n readonly capability: AnkhCapabilityId;\n readonly mode: DoctorTargetMode;\n readonly path: readonly [DoctorCommandName];\n readonly standaloneName: DoctorCommandName;\n readonly summary: string;\n readonly run: DoctorCommandImplementation;\n}\n\nexport interface DoctorCommandInvocation {\n readonly argv: readonly string[];\n readonly command: DoctorCommandDefinition;\n readonly context: DoctorCommandContext;\n}\n\nexport interface DoctorCommandServices {\n readonly analyzeTarget: typeof analyzeDoctorTargetWithCliLayout;\n}\n\nexport interface RunDoctorCommandOptions {\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport type RunDoctorCommandImpl = (\n request: DoctorCommandInvocation,\n options?: RunDoctorCommandOptions,\n) => Promise<DoctorCommandRunResult>;\n\nconst COMMAND_CAPABILITIES = {\n validate: DOCTOR_CAPABILITIES[0],\n fix: DOCTOR_CAPABILITIES[1],\n repo: DOCTOR_CAPABILITIES[2],\n package: DOCTOR_CAPABILITIES[3],\n} as const satisfies Record<DoctorCommandName, AnkhCapabilityId>;\n\nexport const DOCTOR_COMMANDS = [\n {\n standaloneName: 'validate',\n path: ['validate'],\n capability: COMMAND_CAPABILITIES.validate,\n mode: 'validate',\n summary:\n 'Validate a repo, package, or app-manifest JSON path with the applicable Doctor profile.',\n run: runValidateCommand,\n },\n {\n standaloneName: 'fix',\n path: ['fix'],\n capability: COMMAND_CAPABILITIES.fix,\n mode: 'fix',\n summary: 'Build a non-mutating fix plan for deterministic doctor policy violations.',\n run: runFixCommand,\n },\n {\n standaloneName: 'repo',\n path: ['repo'],\n capability: COMMAND_CAPABILITIES.repo,\n mode: 'repo',\n summary: 'Force repo-light diagnostics for a repo/workspace-root candidate path.',\n run: runRepoCommand,\n },\n {\n standaloneName: 'package',\n path: ['package'],\n capability: COMMAND_CAPABILITIES.package,\n mode: 'package',\n summary: 'Force package-light diagnostics for a directory containing package.json.',\n run: runPackageCommand,\n },\n] as const satisfies readonly DoctorCommandDefinition[];\n\nexport async function runDoctorCommand(\n request: DoctorCommandInvocation,\n options: RunDoctorCommandOptions = {},\n): Promise<DoctorCommandRunResult> {\n const services = createDoctorCommandServices(options.services);\n\n try {\n const parsedArgs = parseCommandArguments(request.command, request.argv);\n if (parsedArgs.kind === 'help') {\n request.context.writeStdout(renderCommandHelp(request.command));\n return { exitCode: 0 };\n }\n\n return await request.command.run(\n {\n context: request.context,\n inputPath: parsedArgs.inputPath,\n },\n services,\n );\n } catch (error) {\n request.context.writeStderr(renderCommandFailure(request.command.standaloneName, error));\n return { exitCode: 1 };\n }\n}\n\nexport function createProviderCommandDescriptors(): readonly AnkhCommandDescriptor[] {\n return DOCTOR_COMMANDS.map((command) => ({\n capability: command.capability,\n path: command.path,\n summary: command.summary,\n }));\n}\n\nexport function findDoctorCommandByStandaloneName(value: string): DoctorCommandDefinition | null {\n return DOCTOR_COMMANDS.find((command) => command.standaloneName === value) ?? null;\n}\n\nexport function renderRootHelp(version: string): string {\n const commandLines = DOCTOR_COMMANDS.map(\n (command) => ` ${command.standaloneName.padEnd(8, ' ')} ${command.summary}`,\n ).join('\\n');\n\n return [\n `@ankhorage/doctor v${version}`,\n '',\n 'Usage:',\n ' ankhorage-doctor <command> [path]',\n ` ankh ${DOCTOR_COMMAND_CATEGORY} <command> [path]`,\n '',\n 'Commands:',\n commandLines,\n '',\n 'Path resolution:',\n ' Pass a repo/package directory or app-manifest JSON file, or omit [path] to inspect the current directory.',\n '',\n ].join('\\n');\n}\n\nexport function renderUnknownCommand(value: string): string {\n return [`Unknown doctor command: ${value}`, '', 'Run ankhorage-doctor --help', ''].join('\\n');\n}\n\nfunction renderCommandHelp(command: DoctorCommandDefinition): string {\n return [\n command.summary,\n '',\n 'Usage:',\n ` ankhorage-doctor ${command.standaloneName} [path]`,\n ` ankh ${DOCTOR_COMMAND_CATEGORY} ${command.path.join(' ')} [path]`,\n '',\n 'Path resolution:',\n ' Pass a repo/package directory or app-manifest JSON file, or omit [path] to inspect the current directory.',\n '',\n ].join('\\n');\n}\n\nfunction createDoctorCommandServices(\n overrides: Partial<DoctorCommandServices> = {},\n): DoctorCommandServices {\n return {\n analyzeTarget: overrides.analyzeTarget ?? analyzeDoctorTargetWithCliLayout,\n };\n}\n\nfunction parseCommandArguments(\n command: DoctorCommandDefinition,\n argv: readonly string[],\n): { readonly kind: 'help' } | { readonly kind: 'run'; readonly inputPath?: string } {\n const [firstArg] = argv;\n\n if (argv.length === 1 && firstArg !== undefined && isHelpToken(firstArg)) {\n return { kind: 'help' };\n }\n\n if (argv.length > 1) {\n throw new Error(`Doctor ${command.standaloneName} accepts at most one path argument.`);\n }\n\n return {\n kind: 'run',\n inputPath: firstArg,\n };\n}\n\nasync function runValidateCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'validate',\n });\n\n request.context.writeStdout(renderAnalysisReport('validate', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runFixCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'fix',\n });\n\n request.context.writeStdout(renderAnalysisReport('fix', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runRepoCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'repo',\n });\n\n request.context.writeStdout(renderAnalysisReport('repo', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nasync function runPackageCommand(\n request: DoctorCommandRunRequest,\n services: DoctorCommandServices,\n): Promise<DoctorCommandRunResult> {\n const result = await services.analyzeTarget({\n cwd: request.context.cwd,\n inputPath: request.inputPath,\n mode: 'package',\n });\n\n request.context.writeStdout(renderAnalysisReport('package', result));\n\n return {\n exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,\n };\n}\n\nfunction renderAnalysisReport(\n commandName: DoctorCommandName,\n result: DoctorAnalysisResult,\n): string {\n const lines = [\n `doctor ${commandName}`,\n `target: ${result.targetPath}`,\n `profile: ${result.profile}`,\n `checks: ${result.appliedChecks.length > 0 ? result.appliedChecks.join(', ') : 'none'}`,\n `repoMarkers: ${result.repoMarkers.length > 0 ? result.repoMarkers.join(', ') : 'none'}`,\n '',\n 'Diagnostics:',\n ];\n\n if (result.diagnostics.length === 0) {\n lines.push(' none');\n } else {\n for (const diagnostic of result.diagnostics) {\n lines.push(renderDiagnosticLine(diagnostic));\n }\n }\n\n if (commandName === 'fix') {\n lines.push('');\n lines.push('Planned changes:');\n\n if (result.plannedChanges.length === 0) {\n lines.push(' none');\n } else {\n for (const change of result.plannedChanges) {\n lines.push(renderPlannedChangeLine(change));\n }\n }\n }\n\n const errorCount = countErrorDiagnostics(result.diagnostics);\n const warningCount = countWarningDiagnostics(result.diagnostics);\n\n lines.push('');\n lines.push(`Summary: ${errorCount} error(s), ${warningCount} warning(s)`);\n lines.push('');\n\n return lines.join('\\n');\n}\n\nfunction renderDiagnosticLine(diagnostic: DoctorDiagnostic): string {\n return ` - ${diagnostic.severity.toUpperCase()} ${diagnostic.ruleId} (${diagnostic.code}): ${diagnostic.message}`;\n}\n\nfunction renderPlannedChangeLine(change: DoctorPlannedChange): string {\n return ` - ${change.ruleId} [${change.kind}]: ${change.description}`;\n}\n\nfunction renderCommandFailure(commandName: DoctorCommandName, error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return [`Failed to run doctor ${commandName}: ${message}`, ''].join('\\n');\n}\n\nfunction isHelpToken(value: string): boolean {\n return value === '--help' || value === '-h' || value === 'help';\n}\n"]}
@@ -1,7 +1,7 @@
1
- export type DoctorDiagnosticCode = 'field-invalid' | 'field-missing' | 'invalid-ankh-metadata' | 'invalid-package-json' | 'missing-dependency' | 'missing-path' | 'missing-script' | 'provider-source-import-failed' | 'provider-source-missing' | 'target-not-directory' | 'target-not-found' | 'unsupported-target';
1
+ export type DoctorDiagnosticCode = 'field-invalid' | 'field-missing' | 'invalid-ankh-metadata' | 'invalid-app-manifest-json' | 'invalid-package-json' | 'missing-dependency' | 'missing-path' | 'missing-script' | 'provider-source-import-failed' | 'provider-source-missing' | 'target-not-directory' | 'target-not-found' | 'unsupported-target';
2
2
  export type DoctorDiagnosticSeverity = 'error' | 'warning';
3
- export type DoctorPolicyProfile = 'integration-monorepo' | 'public-package' | 'unknown';
4
- export type DoctorRuleId = 'integration.package.ankh.disallowed' | 'integration.package.private.required' | 'integration.package.workspaces.required' | 'package.ankh.capabilities.match-provider' | 'package.ankh.present.valid-shape' | 'package.ankh.provider-path.required' | 'package.ankh.required-for-provider' | 'package.cli.index.required' | 'package.cli.root-file.disallowed' | 'package.dependencies.changesets.required' | 'package.dependencies.devtools.required' | 'package.dependencies.paradox.required' | 'package.dependencies.types-bun.required' | 'package.dependencies.types-node.required' | 'package.dependencies.typescript.required' | 'package.json.bugs.required' | 'package.json.description.required' | 'package.json.exports.required' | 'package.json.files.required' | 'package.json.homepage.required' | 'package.json.keywords.required' | 'package.json.license.required' | 'package.json.name.required' | 'package.json.package-manager.bun' | 'package.json.package-manager.required' | 'package.json.private.public-package-disallowed' | 'package.json.publish-config.public' | 'package.json.publish-config.required' | 'package.json.repository.required' | 'package.json.type.module' | 'package.json.type.required' | 'package.json.version.required' | 'package.scripts.build.required' | 'package.scripts.changeset-status.required' | 'package.scripts.changeset.required' | 'package.scripts.docs.required' | 'package.scripts.format-check.required' | 'package.scripts.format.required' | 'package.scripts.knip.required' | 'package.scripts.lint-fix.required' | 'package.scripts.lint.required' | 'package.scripts.test.required' | 'package.scripts.typecheck.required' | 'package.scripts.version-packages.required' | 'provider.commands.match-capabilities' | 'provider.commands.match-handlers' | 'provider.source.importable' | 'provider.source.required' | 'repo.changelog.required' | 'repo.changeset.required' | 'repo.license.required' | 'repo.readme.required' | 'repo.workflows.required' | 'target.package-json.required' | 'target.path.directory' | 'target.path.exists' | 'target.profile.supported' | 'target.repo-markers.required';
3
+ export type DoctorPolicyProfile = 'app-manifest' | 'integration-monorepo' | 'public-package' | 'unknown';
4
+ export type DoctorRuleId = 'integration.package.ankh.disallowed' | 'integration.package.private.required' | 'integration.package.workspaces.required' | 'manifest.auth.authorization.engine.valid' | 'manifest.auth.authorization.kind.valid' | 'manifest.auth.authorization.valid-shape' | 'manifest.auth.flow.post-sign-in.distinct' | 'manifest.auth.flow.route.required' | 'manifest.auth.flow.route.unique' | 'manifest.auth.flow.route.valid' | 'manifest.auth.flow.unauthorized-route.valid' | 'manifest.auth.flow.valid-shape' | 'manifest.auth.valid-shape' | 'manifest.infra.valid-shape' | 'manifest.json.readable' | 'manifest.json.valid' | 'manifest.root.valid-shape' | 'manifest.settings.auth-flow.removed' | 'package.ankh.capabilities.match-provider' | 'package.ankh.present.valid-shape' | 'package.ankh.provider-path.required' | 'package.ankh.required-for-provider' | 'package.cli.export.required' | 'package.cli.index.required' | 'package.cli.root-file.disallowed' | 'package.dependencies.ankh-workspace-alias.disallowed' | 'package.dependencies.ankhorage4-source.disallowed' | 'package.dependencies.changesets.required' | 'package.dependencies.devtools.required' | 'package.dependencies.paradox.required' | 'package.dependencies.types-bun.required' | 'package.dependencies.types-node.required' | 'package.dependencies.typescript.required' | 'package.imports.ankh-workspace-alias.disallowed' | 'package.imports.ankhorage4-source.disallowed' | 'package.json.bugs.required' | 'package.json.description.required' | 'package.json.exports.required' | 'package.json.files.required' | 'package.json.homepage.required' | 'package.json.keywords.required' | 'package.json.license.required' | 'package.json.name.required' | 'package.json.package-manager.bun' | 'package.json.package-manager.required' | 'package.json.private.public-package-disallowed' | 'package.json.publish-config.public' | 'package.json.publish-config.required' | 'package.json.repository.required' | 'package.json.type.module' | 'package.json.type.required' | 'package.json.version.required' | 'package.scripts.build.required' | 'package.scripts.changeset-status.required' | 'package.scripts.changeset.required' | 'package.scripts.docs.required' | 'package.scripts.format-check.required' | 'package.scripts.format.required' | 'package.scripts.knip.required' | 'package.scripts.lint-fix.required' | 'package.scripts.lint.required' | 'package.scripts.test.required' | 'package.scripts.typecheck.required' | 'package.scripts.version-packages.required' | 'provider.commands.match-capabilities' | 'provider.commands.match-handlers' | 'provider.source.importable' | 'provider.source.required' | 'repo.changelog.required' | 'repo.changeset.required' | 'repo.license.required' | 'repo.readme.required' | 'repo.workflows.required' | 'studio.dependencies.dnd.required' | 'studio.dependencies.runtime.required' | 'studio.imports.dnd.required' | 'studio.imports.runtime.required' | 'target.package-json.required' | 'target.path.directory' | 'target.path.exists' | 'target.profile.supported' | 'target.repo-markers.required';
5
5
  export interface DoctorDiagnostic {
6
6
  readonly code: DoctorDiagnosticCode;
7
7
  readonly message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAC5B,eAAe,GACf,eAAe,GACf,uBAAuB,GACvB,sBAAsB,GACtB,oBAAoB,GACpB,cAAc,GACd,gBAAgB,GAChB,+BAA+B,GAC/B,yBAAyB,GACzB,sBAAsB,GACtB,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,mBAAmB,GAAG,sBAAsB,GAAG,gBAAgB,GAAG,SAAS,CAAC;AACxF,MAAM,MAAM,YAAY,GACpB,qCAAqC,GACrC,sCAAsC,GACtC,yCAAyC,GACzC,0CAA0C,GAC1C,kCAAkC,GAClC,qCAAqC,GACrC,oCAAoC,GACpC,4BAA4B,GAC5B,kCAAkC,GAClC,0CAA0C,GAC1C,wCAAwC,GACxC,uCAAuC,GACvC,yCAAyC,GACzC,0CAA0C,GAC1C,0CAA0C,GAC1C,4BAA4B,GAC5B,mCAAmC,GACnC,+BAA+B,GAC/B,6BAA6B,GAC7B,gCAAgC,GAChC,gCAAgC,GAChC,+BAA+B,GAC/B,4BAA4B,GAC5B,kCAAkC,GAClC,uCAAuC,GACvC,gDAAgD,GAChD,oCAAoC,GACpC,sCAAsC,GACtC,kCAAkC,GAClC,0BAA0B,GAC1B,4BAA4B,GAC5B,+BAA+B,GAC/B,gCAAgC,GAChC,2CAA2C,GAC3C,oCAAoC,GACpC,+BAA+B,GAC/B,uCAAuC,GACvC,iCAAiC,GACjC,+BAA+B,GAC/B,mCAAmC,GACnC,+BAA+B,GAC/B,+BAA+B,GAC/B,oCAAoC,GACpC,2CAA2C,GAC3C,sCAAsC,GACtC,kCAAkC,GAClC,4BAA4B,GAC5B,0BAA0B,GAC1B,yBAAyB,GACzB,yBAAyB,GACzB,uBAAuB,GACvB,sBAAsB,GACtB,yBAAyB,GACzB,8BAA8B,GAC9B,uBAAuB,GACvB,oBAAoB,GACpB,0BAA0B,GAC1B,8BAA8B,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;CAC7C;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAEtF;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAExF"}
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAC5B,eAAe,GACf,eAAe,GACf,uBAAuB,GACvB,2BAA2B,GAC3B,sBAAsB,GACtB,oBAAoB,GACpB,cAAc,GACd,gBAAgB,GAChB,+BAA+B,GAC/B,yBAAyB,GACzB,sBAAsB,GACtB,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,mBAAmB,GAC7B,cAAc,GAAG,sBAAsB,GAAG,gBAAgB,GAAG,SAAS,CAAC;AACzE,MAAM,MAAM,YAAY,GACpB,qCAAqC,GACrC,sCAAsC,GACtC,yCAAyC,GACzC,0CAA0C,GAC1C,wCAAwC,GACxC,yCAAyC,GACzC,0CAA0C,GAC1C,mCAAmC,GACnC,iCAAiC,GACjC,gCAAgC,GAChC,6CAA6C,GAC7C,gCAAgC,GAChC,2BAA2B,GAC3B,4BAA4B,GAC5B,wBAAwB,GACxB,qBAAqB,GACrB,2BAA2B,GAC3B,qCAAqC,GACrC,0CAA0C,GAC1C,kCAAkC,GAClC,qCAAqC,GACrC,oCAAoC,GACpC,6BAA6B,GAC7B,4BAA4B,GAC5B,kCAAkC,GAClC,sDAAsD,GACtD,mDAAmD,GACnD,0CAA0C,GAC1C,wCAAwC,GACxC,uCAAuC,GACvC,yCAAyC,GACzC,0CAA0C,GAC1C,0CAA0C,GAC1C,iDAAiD,GACjD,8CAA8C,GAC9C,4BAA4B,GAC5B,mCAAmC,GACnC,+BAA+B,GAC/B,6BAA6B,GAC7B,gCAAgC,GAChC,gCAAgC,GAChC,+BAA+B,GAC/B,4BAA4B,GAC5B,kCAAkC,GAClC,uCAAuC,GACvC,gDAAgD,GAChD,oCAAoC,GACpC,sCAAsC,GACtC,kCAAkC,GAClC,0BAA0B,GAC1B,4BAA4B,GAC5B,+BAA+B,GAC/B,gCAAgC,GAChC,2CAA2C,GAC3C,oCAAoC,GACpC,+BAA+B,GAC/B,uCAAuC,GACvC,iCAAiC,GACjC,+BAA+B,GAC/B,mCAAmC,GACnC,+BAA+B,GAC/B,+BAA+B,GAC/B,oCAAoC,GACpC,2CAA2C,GAC3C,sCAAsC,GACtC,kCAAkC,GAClC,4BAA4B,GAC5B,0BAA0B,GAC1B,yBAAyB,GACzB,yBAAyB,GACzB,uBAAuB,GACvB,sBAAsB,GACtB,yBAAyB,GACzB,kCAAkC,GAClC,sCAAsC,GACtC,6BAA6B,GAC7B,iCAAiC,GACjC,8BAA8B,GAC9B,uBAAuB,GACvB,oBAAoB,GACpB,0BAA0B,GAC1B,8BAA8B,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;CAC7C;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAEtF;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAExF"}