@ankhorage/doctor 0.3.0 → 0.4.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -3
  3. package/dist/{ankh.provider.d.ts → cli/index.d.ts} +2 -2
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +33 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/{cli.d.ts → cli/standalone.d.ts} +3 -3
  8. package/dist/cli/standalone.d.ts.map +1 -0
  9. package/dist/{cli.js → cli/standalone.js} +8 -4
  10. package/dist/cli/standalone.js.map +1 -0
  11. package/dist/cliLayoutAnalysis.d.ts +3 -0
  12. package/dist/cliLayoutAnalysis.d.ts.map +1 -0
  13. package/dist/cliLayoutAnalysis.js +80 -0
  14. package/dist/cliLayoutAnalysis.js.map +1 -0
  15. package/dist/diagnostics.d.ts +1 -1
  16. package/dist/diagnostics.d.ts.map +1 -1
  17. package/dist/diagnostics.js.map +1 -1
  18. package/dist/index.d.ts +3 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/packageMetadata.d.ts +1 -1
  23. package/dist/packageMetadata.js +1 -1
  24. package/dist/packageMetadata.js.map +1 -1
  25. package/dist/readme-usage.js +1 -1
  26. package/dist/readme-usage.js.map +1 -1
  27. package/package.json +8 -3
  28. package/src/{ankh.provider.ts → cli/index.ts} +18 -10
  29. package/src/{cli.ts → cli/standalone.ts} +8 -4
  30. package/src/cliLayoutAnalysis.ts +105 -0
  31. package/src/diagnostics.ts +2 -0
  32. package/src/index.ts +3 -2
  33. package/src/packageMetadata.ts +1 -1
  34. package/src/readme-usage.ts +1 -1
  35. package/dist/ankh.provider.d.ts.map +0 -1
  36. package/dist/ankh.provider.js +0 -27
  37. package/dist/ankh.provider.js.map +0 -1
  38. package/dist/cli.d.ts.map +0 -1
  39. package/dist/cli.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1d1a8fd: Enforce the canonical `src/cli/index.ts` provider layout, reject root `src/cli.ts` files, and move the Doctor standalone executable under `src/cli/`.
8
+
9
+ ## 0.3.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 0c1f5c2: Expose the package command provider.
14
+
3
15
  ## 0.3.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -3,9 +3,9 @@
3
3
 
4
4
  # DOCTOR
5
5
 
6
- ![license: MIT](././paradox/badges/license.svg) ![npm: v0.2.1](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg)
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v0.3.0](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg)
7
7
 
8
- Executable doctor provider and standalone CLI for lightweight Ankhorage repo and package compliance diagnostics.
8
+ Executable doctor provider and standalone CLI for lightweight repo and package compliance diagnostics.
9
9
 
10
10
  ## Usage
11
11
 
@@ -46,7 +46,7 @@ Path handling:
46
46
  Source: `src/readme-usage.ts`
47
47
 
48
48
  ```ts
49
- import { runCli } from './cli.js';
49
+ import { runCli } from './cli/standalone.js';
50
50
 
51
51
  await runCli(['--help']);
52
52
  ```
@@ -1,5 +1,5 @@
1
1
  import type { AnkhRuntimeCommandProvider } from '@ankhorage/ankh';
2
- import { type DoctorCommandServices, type RunDoctorCommandImpl } from './commands.js';
2
+ import { type DoctorCommandServices, type RunDoctorCommandImpl } from '../commands.js';
3
3
  export interface CreateDoctorRuntimeProviderOptions {
4
4
  readonly runCommandImpl?: RunDoctorCommandImpl;
5
5
  readonly services?: Partial<DoctorCommandServices>;
@@ -7,4 +7,4 @@ export interface CreateDoctorRuntimeProviderOptions {
7
7
  export declare function createDoctorRuntimeProvider(options?: CreateDoctorRuntimeProviderOptions): AnkhRuntimeCommandProvider;
8
8
  declare const provider: AnkhRuntimeCommandProvider;
9
9
  export default provider;
10
- //# sourceMappingURL=ankh.provider.d.ts.map
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAGtF,OAAO,EAGL,KAAK,qBAAqB,EAE1B,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AAQxB,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kCAAuC,GAC/C,0BAA0B,CAgC5B;AAED,QAAA,MAAM,QAAQ,4BAAgC,CAAC;AAE/C,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';
2
+ import { createProviderCommandDescriptors, DOCTOR_COMMANDS, runDoctorCommand, } from '../commands.js';
3
+ import { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY, DOCTOR_PACKAGE_NAME, DOCTOR_PACKAGE_VERSION, } from '../packageMetadata.js';
4
+ export function createDoctorRuntimeProvider(options = {}) {
5
+ const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;
6
+ const services = {
7
+ analyzeTarget: analyzeDoctorTargetWithCliLayout,
8
+ ...options.services,
9
+ };
10
+ return {
11
+ id: DOCTOR_PACKAGE_NAME,
12
+ category: DOCTOR_COMMAND_CATEGORY,
13
+ version: DOCTOR_PACKAGE_VERSION,
14
+ capabilities: [...DOCTOR_CAPABILITIES],
15
+ commands: createProviderCommandDescriptors(),
16
+ handlers: DOCTOR_COMMANDS.map((command) => {
17
+ const handler = (request) => runCommandImpl({
18
+ argv: request.argv,
19
+ command,
20
+ context: request.context,
21
+ }, {
22
+ services,
23
+ });
24
+ return {
25
+ path: command.path,
26
+ handler,
27
+ };
28
+ }),
29
+ };
30
+ }
31
+ const provider = createDoctorRuntimeProvider();
32
+ export default provider;
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gCAAgC,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EACL,gCAAgC,EAChC,eAAe,EAEf,gBAAgB,GAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,UAAU,2BAA2B,CACzC,UAA8C,EAAE;IAEhD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAClE,MAAM,QAAQ,GAAG;QACf,aAAa,EAAE,gCAAgC;QAC/C,GAAG,OAAO,CAAC,QAAQ;KACY,CAAC;IAElC,OAAO;QACL,EAAE,EAAE,mBAAmB;QACvB,QAAQ,EAAE,uBAAuB;QACjC,OAAO,EAAE,sBAAsB;QAC/B,YAAY,EAAE,CAAC,GAAG,mBAAmB,CAAC;QACtC,QAAQ,EAAE,gCAAgC,EAAE;QAC5C,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACxC,MAAM,OAAO,GAAuB,CAAC,OAAO,EAAE,EAAE,CAC9C,cAAc,CACZ;gBACE,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,EACD;gBACE,QAAQ;aACT,CACF,CAAC;YAEJ,OAAO;gBACL,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO;aACR,CAAC;QACJ,CAAC,CAAC;KACkC,CAAC;AACzC,CAAC;AAED,MAAM,QAAQ,GAAG,2BAA2B,EAAE,CAAC;AAE/C,eAAe,QAAQ,CAAC","sourcesContent":["import type { AnkhCommandHandler, AnkhRuntimeCommandProvider } from '@ankhorage/ankh';\n\nimport { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';\nimport {\n createProviderCommandDescriptors,\n DOCTOR_COMMANDS,\n type DoctorCommandServices,\n runDoctorCommand,\n type RunDoctorCommandImpl,\n} from '../commands.js';\nimport {\n DOCTOR_CAPABILITIES,\n DOCTOR_COMMAND_CATEGORY,\n DOCTOR_PACKAGE_NAME,\n DOCTOR_PACKAGE_VERSION,\n} from '../packageMetadata.js';\n\nexport interface CreateDoctorRuntimeProviderOptions {\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport function createDoctorRuntimeProvider(\n options: CreateDoctorRuntimeProviderOptions = {},\n): AnkhRuntimeCommandProvider {\n const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;\n const services = {\n analyzeTarget: analyzeDoctorTargetWithCliLayout,\n ...options.services,\n } satisfies DoctorCommandServices;\n\n return {\n id: DOCTOR_PACKAGE_NAME,\n category: DOCTOR_COMMAND_CATEGORY,\n version: DOCTOR_PACKAGE_VERSION,\n capabilities: [...DOCTOR_CAPABILITIES],\n commands: createProviderCommandDescriptors(),\n handlers: DOCTOR_COMMANDS.map((command) => {\n const handler: AnkhCommandHandler = (request) =>\n runCommandImpl(\n {\n argv: request.argv,\n command,\n context: request.context,\n },\n {\n services,\n },\n );\n\n return {\n path: command.path,\n handler,\n };\n }),\n } satisfies AnkhRuntimeCommandProvider;\n}\n\nconst provider = createDoctorRuntimeProvider();\n\nexport default provider;\n"]}
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env bun
2
- import type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
3
- import { type DoctorCommandServices, type RunDoctorCommandImpl } from './commands.js';
2
+ import type { DoctorCommandContext, DoctorCommandRunResult } from '../commandContext.js';
3
+ import { type DoctorCommandServices, type RunDoctorCommandImpl } from '../commands.js';
4
4
  export interface DoctorCliOptions {
5
5
  readonly context?: DoctorCommandContext;
6
6
  readonly runCommandImpl?: RunDoctorCommandImpl;
7
7
  readonly services?: Partial<DoctorCommandServices>;
8
8
  }
9
9
  export declare function runCli(argv: readonly string[], options?: DoctorCliOptions): Promise<DoctorCommandRunResult>;
10
- //# sourceMappingURL=cli.d.ts.map
10
+ //# sourceMappingURL=standalone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone.d.ts","sourceRoot":"","sources":["../../src/cli/standalone.ts"],"names":[],"mappings":";AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,EACL,KAAK,qBAAqB,EAK1B,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC,CAkCjC"}
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bun
2
- import { createDefaultCommandContext } from './commandContext.js';
3
- import { findDoctorCommandByStandaloneName, renderRootHelp, renderUnknownCommand, runDoctorCommand, } from './commands.js';
2
+ import { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';
3
+ import { createDefaultCommandContext } from '../commandContext.js';
4
+ import { findDoctorCommandByStandaloneName, renderRootHelp, renderUnknownCommand, runDoctorCommand, } from '../commands.js';
4
5
  export async function runCli(argv, options = {}) {
5
6
  const context = options.context ?? createDefaultCommandContext();
6
7
  const runCommand = options.runCommandImpl ?? runDoctorCommand;
@@ -23,7 +24,10 @@ export async function runCli(argv, options = {}) {
23
24
  command,
24
25
  context,
25
26
  }, {
26
- services: options.services,
27
+ services: {
28
+ analyzeTarget: analyzeDoctorTargetWithCliLayout,
29
+ ...options.services,
30
+ },
27
31
  });
28
32
  }
29
33
  function isHelpToken(value) {
@@ -36,4 +40,4 @@ if (import.meta.main) {
36
40
  const result = await runCli(process.argv.slice(2));
37
41
  process.exit(result.exitCode);
38
42
  }
39
- //# sourceMappingURL=cli.js.map
43
+ //# sourceMappingURL=standalone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standalone.js","sourceRoot":"","sources":["../../src/cli/standalone.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,gCAAgC,EAAE,MAAM,yBAAyB,CAAC;AAE3E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAEL,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,gBAAgB,CAAC;AAQxB,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,IAAuB,EACvB,UAA4B,EAAE;IAE9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,2BAA2B,EAAE,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC9D,MAAM,CAAC,UAAU,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC;IAEzC,IAAI,UAAU,KAAK,SAAS,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACrD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5C,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,OAAO,GAAG,iCAAiC,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,UAAU,CACf;QACE,IAAI,EAAE,UAAU;QAChB,OAAO;QACP,OAAO;KACR,EACD;QACE,QAAQ,EAAE;YACR,aAAa,EAAE,gCAAgC;YAC/C,GAAG,OAAO,CAAC,QAAQ;SACpB;KACF,CACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,CAAC;AAClE,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;AACxE,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC","sourcesContent":["#!/usr/bin/env bun\n\nimport { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';\nimport type { DoctorCommandContext, DoctorCommandRunResult } from '../commandContext.js';\nimport { createDefaultCommandContext } from '../commandContext.js';\nimport {\n type DoctorCommandServices,\n findDoctorCommandByStandaloneName,\n renderRootHelp,\n renderUnknownCommand,\n runDoctorCommand,\n type RunDoctorCommandImpl,\n} from '../commands.js';\n\nexport interface DoctorCliOptions {\n readonly context?: DoctorCommandContext;\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport async function runCli(\n argv: readonly string[],\n options: DoctorCliOptions = {},\n): Promise<DoctorCommandRunResult> {\n const context = options.context ?? createDefaultCommandContext();\n const runCommand = options.runCommandImpl ?? runDoctorCommand;\n const [firstToken, ...restTokens] = argv;\n\n if (firstToken === undefined || isHelpToken(firstToken)) {\n context.writeStdout(renderRootHelp(context.version));\n return { exitCode: 0 };\n }\n\n if (isVersionToken(firstToken)) {\n context.writeStdout(`${context.version}\\n`);\n return { exitCode: 0 };\n }\n\n const command = findDoctorCommandByStandaloneName(firstToken);\n if (command === null) {\n context.writeStderr(renderUnknownCommand(firstToken));\n return { exitCode: 1 };\n }\n\n return runCommand(\n {\n argv: restTokens,\n command,\n context,\n },\n {\n services: {\n analyzeTarget: analyzeDoctorTargetWithCliLayout,\n ...options.services,\n },\n },\n );\n}\n\nfunction isHelpToken(value: string): boolean {\n return value === '--help' || value === '-h' || value === 'help';\n}\n\nfunction isVersionToken(value: string): boolean {\n return value === '--version' || value === '-v' || value === 'version';\n}\n\nif (import.meta.main) {\n const result = await runCli(process.argv.slice(2));\n process.exit(result.exitCode);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { type DoctorAnalysisRequest, type DoctorAnalysisResult } from './analysis.js';
2
+ export declare function analyzeDoctorTargetWithCliLayout(request: DoctorAnalysisRequest): Promise<DoctorAnalysisResult>;
3
+ //# sourceMappingURL=cliLayoutAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliLayoutAnalysis.d.ts","sourceRoot":"","sources":["../src/cliLayoutAnalysis.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAMvB,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAkB/B"}
@@ -0,0 +1,80 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { analyzeDoctorTarget, } from './analysis.js';
4
+ const LEGACY_ROOT_CLI_SOURCE = path.join('src', 'cli.ts');
5
+ const CANONICAL_CLI_INDEX_SOURCE = path.join('src', 'cli', 'index.ts');
6
+ export async function analyzeDoctorTargetWithCliLayout(request) {
7
+ const result = await analyzeDoctorTarget(request);
8
+ if (!result.hasPackageJson) {
9
+ return result;
10
+ }
11
+ const cliDiagnostics = await analyzeCliLayout(result.targetPath, result.profile);
12
+ if (cliDiagnostics.length === 0) {
13
+ return result;
14
+ }
15
+ const diagnostics = [...result.diagnostics, ...cliDiagnostics];
16
+ return {
17
+ ...result,
18
+ diagnostics,
19
+ fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },
20
+ };
21
+ }
22
+ async function analyzeCliLayout(targetPath, profile) {
23
+ const diagnostics = [];
24
+ const legacyRootCliPath = path.join(targetPath, LEGACY_ROOT_CLI_SOURCE);
25
+ const canonicalCliIndexPath = path.join(targetPath, CANONICAL_CLI_INDEX_SOURCE);
26
+ if (await pathExists(legacyRootCliPath)) {
27
+ diagnostics.push({
28
+ code: 'field-invalid',
29
+ message: 'Package CLI code must live under src/cli/; root src/cli.ts is not allowed.',
30
+ path: legacyRootCliPath,
31
+ profile,
32
+ ruleId: 'package.cli.root-file.disallowed',
33
+ severity: 'error',
34
+ });
35
+ }
36
+ const packageJson = await readPackageJson(path.join(targetPath, 'package.json'));
37
+ if (packageJson !== null &&
38
+ exposesCliProvider(packageJson) &&
39
+ !(await pathExists(canonicalCliIndexPath))) {
40
+ diagnostics.push({
41
+ code: 'missing-path',
42
+ message: 'CLI-capable packages must expose their provider from src/cli/index.ts.',
43
+ path: canonicalCliIndexPath,
44
+ profile,
45
+ ruleId: 'package.cli.index.required',
46
+ severity: 'error',
47
+ });
48
+ }
49
+ return diagnostics;
50
+ }
51
+ function exposesCliProvider(packageJson) {
52
+ 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;
55
+ }
56
+ async function readPackageJson(packageJsonPath) {
57
+ try {
58
+ const parsed = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
59
+ return isRecord(parsed) ? parsed : null;
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ async function pathExists(targetPath) {
66
+ try {
67
+ await fs.access(targetPath);
68
+ return true;
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ function isNonEmptyString(value) {
75
+ return typeof value === 'string' && value.trim().length > 0;
76
+ }
77
+ function isRecord(value) {
78
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
79
+ }
80
+ //# sourceMappingURL=cliLayoutAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliLayoutAnalysis.js","sourceRoot":"","sources":["../src/cliLayoutAnalysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,mBAAmB,GAGpB,MAAM,eAAe,CAAC;AAGvB,MAAM,sBAAsB,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC1D,MAAM,0BAA0B,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,OAA8B;IAE9B,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjF,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,GAAG,cAAc,CAAC,CAAC;IAE/D,OAAO;QACL,GAAG,MAAM;QACT,WAAW;QACX,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE;KAC7E,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,UAAkB,EAClB,OAA4B;IAE5B,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAC;IACxE,MAAM,qBAAqB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,0BAA0B,CAAC,CAAC;IAEhF,IAAI,MAAM,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,4EAA4E;YACrF,IAAI,EAAE,iBAAiB;YACvB,OAAO;YACP,MAAM,EAAE,kCAAkC;YAC1C,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IACjF,IACE,WAAW,KAAK,IAAI;QACpB,kBAAkB,CAAC,WAAW,CAAC;QAC/B,CAAC,CAAC,MAAM,UAAU,CAAC,qBAAqB,CAAC,CAAC,EAC1C,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,wEAAwE;YACjF,IAAI,EAAE,qBAAqB;YAC3B,OAAO;YACP,MAAM,EAAE,4BAA4B;YACpC,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAoC;IAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhF,OAAO,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,YAAY,EAAE,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC;AACnF,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,eAAuB;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/E,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC","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,7 +1,7 @@
1
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';
2
2
  export type DoctorDiagnosticSeverity = 'error' | 'warning';
3
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.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';
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';
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,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,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 +1 @@
1
- {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAmFA,MAAM,UAAU,qBAAqB,CAAC,WAAwC;IAC5E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,WAAwC;IAC9E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;AACtF,CAAC","sourcesContent":["export type DoctorDiagnosticCode =\n | 'field-invalid'\n | 'field-missing'\n | 'invalid-ankh-metadata'\n | 'invalid-package-json'\n | 'missing-dependency'\n | 'missing-path'\n | 'missing-script'\n | 'provider-source-import-failed'\n | 'provider-source-missing'\n | 'target-not-directory'\n | 'target-not-found'\n | 'unsupported-target';\n\nexport type DoctorDiagnosticSeverity = 'error' | 'warning';\nexport type DoctorPolicyProfile = 'integration-monorepo' | 'public-package' | 'unknown';\nexport type DoctorRuleId =\n | 'integration.package.ankh.disallowed'\n | 'integration.package.private.required'\n | 'integration.package.workspaces.required'\n | 'package.ankh.capabilities.match-provider'\n | 'package.ankh.present.valid-shape'\n | 'package.ankh.provider-path.required'\n | 'package.ankh.required-for-provider'\n | 'package.dependencies.changesets.required'\n | 'package.dependencies.devtools.required'\n | 'package.dependencies.paradox.required'\n | 'package.dependencies.types-bun.required'\n | 'package.dependencies.types-node.required'\n | 'package.dependencies.typescript.required'\n | 'package.json.bugs.required'\n | 'package.json.description.required'\n | 'package.json.exports.required'\n | 'package.json.files.required'\n | 'package.json.homepage.required'\n | 'package.json.keywords.required'\n | 'package.json.license.required'\n | 'package.json.name.required'\n | 'package.json.package-manager.bun'\n | 'package.json.package-manager.required'\n | 'package.json.private.public-package-disallowed'\n | 'package.json.publish-config.public'\n | 'package.json.publish-config.required'\n | 'package.json.repository.required'\n | 'package.json.type.module'\n | 'package.json.type.required'\n | 'package.json.version.required'\n | 'package.scripts.build.required'\n | 'package.scripts.changeset-status.required'\n | 'package.scripts.changeset.required'\n | 'package.scripts.docs.required'\n | 'package.scripts.format-check.required'\n | 'package.scripts.format.required'\n | 'package.scripts.knip.required'\n | 'package.scripts.lint-fix.required'\n | 'package.scripts.lint.required'\n | 'package.scripts.test.required'\n | 'package.scripts.typecheck.required'\n | 'package.scripts.version-packages.required'\n | 'provider.commands.match-capabilities'\n | 'provider.commands.match-handlers'\n | 'provider.source.importable'\n | 'provider.source.required'\n | 'repo.changelog.required'\n | 'repo.changeset.required'\n | 'repo.license.required'\n | 'repo.readme.required'\n | 'repo.workflows.required'\n | 'target.package-json.required'\n | 'target.path.directory'\n | 'target.path.exists'\n | 'target.profile.supported'\n | 'target.repo-markers.required';\n\nexport interface DoctorDiagnostic {\n readonly code: DoctorDiagnosticCode;\n readonly message: string;\n readonly path: string;\n readonly profile: DoctorPolicyProfile;\n readonly ruleId: DoctorRuleId;\n readonly severity: DoctorDiagnosticSeverity;\n}\n\nexport function countErrorDiagnostics(diagnostics: readonly DoctorDiagnostic[]): number {\n return diagnostics.filter((diagnostic) => diagnostic.severity === 'error').length;\n}\n\nexport function countWarningDiagnostics(diagnostics: readonly DoctorDiagnostic[]): number {\n return diagnostics.filter((diagnostic) => diagnostic.severity === 'warning').length;\n}\n"]}
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAqFA,MAAM,UAAU,qBAAqB,CAAC,WAAwC;IAC5E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,WAAwC;IAC9E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;AACtF,CAAC","sourcesContent":["export type DoctorDiagnosticCode =\n | 'field-invalid'\n | 'field-missing'\n | 'invalid-ankh-metadata'\n | 'invalid-package-json'\n | 'missing-dependency'\n | 'missing-path'\n | 'missing-script'\n | 'provider-source-import-failed'\n | 'provider-source-missing'\n | 'target-not-directory'\n | 'target-not-found'\n | 'unsupported-target';\n\nexport type DoctorDiagnosticSeverity = 'error' | 'warning';\nexport type DoctorPolicyProfile = 'integration-monorepo' | 'public-package' | 'unknown';\nexport type DoctorRuleId =\n | 'integration.package.ankh.disallowed'\n | 'integration.package.private.required'\n | 'integration.package.workspaces.required'\n | 'package.ankh.capabilities.match-provider'\n | 'package.ankh.present.valid-shape'\n | 'package.ankh.provider-path.required'\n | 'package.ankh.required-for-provider'\n | 'package.cli.index.required'\n | 'package.cli.root-file.disallowed'\n | 'package.dependencies.changesets.required'\n | 'package.dependencies.devtools.required'\n | 'package.dependencies.paradox.required'\n | 'package.dependencies.types-bun.required'\n | 'package.dependencies.types-node.required'\n | 'package.dependencies.typescript.required'\n | 'package.json.bugs.required'\n | 'package.json.description.required'\n | 'package.json.exports.required'\n | 'package.json.files.required'\n | 'package.json.homepage.required'\n | 'package.json.keywords.required'\n | 'package.json.license.required'\n | 'package.json.name.required'\n | 'package.json.package-manager.bun'\n | 'package.json.package-manager.required'\n | 'package.json.private.public-package-disallowed'\n | 'package.json.publish-config.public'\n | 'package.json.publish-config.required'\n | 'package.json.repository.required'\n | 'package.json.type.module'\n | 'package.json.type.required'\n | 'package.json.version.required'\n | 'package.scripts.build.required'\n | 'package.scripts.changeset-status.required'\n | 'package.scripts.changeset.required'\n | 'package.scripts.docs.required'\n | 'package.scripts.format-check.required'\n | 'package.scripts.format.required'\n | 'package.scripts.knip.required'\n | 'package.scripts.lint-fix.required'\n | 'package.scripts.lint.required'\n | 'package.scripts.test.required'\n | 'package.scripts.typecheck.required'\n | 'package.scripts.version-packages.required'\n | 'provider.commands.match-capabilities'\n | 'provider.commands.match-handlers'\n | 'provider.source.importable'\n | 'provider.source.required'\n | 'repo.changelog.required'\n | 'repo.changeset.required'\n | 'repo.license.required'\n | 'repo.readme.required'\n | 'repo.workflows.required'\n | 'target.package-json.required'\n | 'target.path.directory'\n | 'target.path.exists'\n | 'target.profile.supported'\n | 'target.repo-markers.required';\n\nexport interface DoctorDiagnostic {\n readonly code: DoctorDiagnosticCode;\n readonly message: string;\n readonly path: string;\n readonly profile: DoctorPolicyProfile;\n readonly ruleId: DoctorRuleId;\n readonly severity: DoctorDiagnosticSeverity;\n}\n\nexport function countErrorDiagnostics(diagnostics: readonly DoctorDiagnostic[]): number {\n return diagnostics.filter((diagnostic) => diagnostic.severity === 'error').length;\n}\n\nexport function countWarningDiagnostics(diagnostics: readonly DoctorDiagnostic[]): number {\n return diagnostics.filter((diagnostic) => diagnostic.severity === 'warning').length;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export type { DoctorAnalysisRequest, DoctorAnalysisResult, DoctorFixPlan, DoctorPlannedChange, DoctorPlannedChangeKind, DoctorTargetCheck, DoctorTargetMode, } from './analysis.js';
2
2
  export { analyzeDoctorTarget } from './analysis.js';
3
- export { createDoctorRuntimeProvider, type CreateDoctorRuntimeProviderOptions, } from './ankh.provider.js';
4
- export { runCli } from './cli.js';
3
+ export { createDoctorRuntimeProvider, type CreateDoctorRuntimeProviderOptions, } from './cli/index.js';
4
+ export { runCli } from './cli/standalone.js';
5
+ export { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';
5
6
  export type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
6
7
  export { createDefaultCommandContext } from './commandContext.js';
7
8
  export type { DoctorDiagnostic, DoctorDiagnosticCode, DoctorDiagnosticSeverity, DoctorPolicyProfile, DoctorRuleId, } from './diagnostics.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { analyzeDoctorTarget } from './analysis.js';
2
- export { createDoctorRuntimeProvider, } from './ankh.provider.js';
3
- export { runCli } from './cli.js';
2
+ export { createDoctorRuntimeProvider, } from './cli/index.js';
3
+ export { runCli } from './cli/standalone.js';
4
+ export { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';
4
5
  export { createDefaultCommandContext } from './commandContext.js';
5
6
  export { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY, DOCTOR_PACKAGE_METADATA, DOCTOR_PACKAGE_NAME, DOCTOR_PACKAGE_VERSION, } from './packageMetadata.js';
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,2BAA2B,GAE5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAQlE,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC","sourcesContent":["export type {\n DoctorAnalysisRequest,\n DoctorAnalysisResult,\n DoctorFixPlan,\n DoctorPlannedChange,\n DoctorPlannedChangeKind,\n DoctorTargetCheck,\n DoctorTargetMode,\n} from './analysis.js';\nexport { analyzeDoctorTarget } from './analysis.js';\nexport {\n createDoctorRuntimeProvider,\n type CreateDoctorRuntimeProviderOptions,\n} from './ankh.provider.js';\nexport { runCli } from './cli.js';\nexport type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';\nexport { createDefaultCommandContext } from './commandContext.js';\nexport type {\n DoctorDiagnostic,\n DoctorDiagnosticCode,\n DoctorDiagnosticSeverity,\n DoctorPolicyProfile,\n DoctorRuleId,\n} from './diagnostics.js';\nexport {\n DOCTOR_CAPABILITIES,\n DOCTOR_COMMAND_CATEGORY,\n DOCTOR_PACKAGE_METADATA,\n DOCTOR_PACKAGE_NAME,\n DOCTOR_PACKAGE_VERSION,\n} from './packageMetadata.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,2BAA2B,GAE5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAC;AAE1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAQlE,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC","sourcesContent":["export type {\n DoctorAnalysisRequest,\n DoctorAnalysisResult,\n DoctorFixPlan,\n DoctorPlannedChange,\n DoctorPlannedChangeKind,\n DoctorTargetCheck,\n DoctorTargetMode,\n} from './analysis.js';\nexport { analyzeDoctorTarget } from './analysis.js';\nexport {\n createDoctorRuntimeProvider,\n type CreateDoctorRuntimeProviderOptions,\n} from './cli/index.js';\nexport { runCli } from './cli/standalone.js';\nexport { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';\nexport type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';\nexport { createDefaultCommandContext } from './commandContext.js';\nexport type {\n DoctorDiagnostic,\n DoctorDiagnosticCode,\n DoctorDiagnosticSeverity,\n DoctorPolicyProfile,\n DoctorRuleId,\n} from './diagnostics.js';\nexport {\n DOCTOR_CAPABILITIES,\n DOCTOR_COMMAND_CATEGORY,\n DOCTOR_PACKAGE_METADATA,\n DOCTOR_PACKAGE_NAME,\n DOCTOR_PACKAGE_VERSION,\n} from './packageMetadata.js';\n"]}
@@ -4,7 +4,7 @@ export declare const DOCTOR_COMMAND_CATEGORY: "doctor";
4
4
  export declare const DOCTOR_CAPABILITIES: readonly ["doctor.validate", "doctor.fix", "doctor.repo", "doctor.package"];
5
5
  export declare const DOCTOR_PACKAGE_METADATA: {
6
6
  readonly category: "doctor";
7
- readonly provider: "./dist/ankh.provider.js";
7
+ readonly provider: "./dist/cli/index.js";
8
8
  readonly capabilities: readonly ["doctor.validate", "doctor.fix", "doctor.repo", "doctor.package"];
9
9
  };
10
10
  //# sourceMappingURL=packageMetadata.d.ts.map
@@ -10,7 +10,7 @@ export const DOCTOR_CAPABILITIES = [
10
10
  ];
11
11
  export const DOCTOR_PACKAGE_METADATA = {
12
12
  category: DOCTOR_COMMAND_CATEGORY,
13
- provider: './dist/ankh.provider.js',
13
+ provider: './dist/cli/index.js',
14
14
  capabilities: DOCTOR_CAPABILITIES,
15
15
  };
16
16
  //# sourceMappingURL=packageMetadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageMetadata.js","sourceRoot":"","sources":["../src/packageMetadata.ts"],"names":[],"mappings":"AAMA,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC,IAAI,CAAC;AACpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAC,OAAO,CAAC;AAC1D,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAA+C,CAAC;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,iBAAiB;IACjB,YAAY;IACZ,aAAa;IACb,gBAAgB;CAC8B,CAAC;AAEjD,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,QAAQ,EAAE,uBAAuB;IACjC,QAAQ,EAAE,yBAAyB;IACnC,YAAY,EAAE,mBAAmB;CACK,CAAC","sourcesContent":["import type {\n AnkhCapabilityId,\n AnkhCommandCategory,\n AnkhPackageMetadata,\n} from '@ankhorage/contracts/cli';\n\nimport packageJson from '../package.json';\n\nexport const DOCTOR_PACKAGE_NAME = packageJson.name;\nexport const DOCTOR_PACKAGE_VERSION = packageJson.version;\nexport const DOCTOR_COMMAND_CATEGORY = 'doctor' as const satisfies AnkhCommandCategory;\nexport const DOCTOR_CAPABILITIES = [\n 'doctor.validate',\n 'doctor.fix',\n 'doctor.repo',\n 'doctor.package',\n] as const satisfies readonly AnkhCapabilityId[];\n\nexport const DOCTOR_PACKAGE_METADATA = {\n category: DOCTOR_COMMAND_CATEGORY,\n provider: './dist/ankh.provider.js',\n capabilities: DOCTOR_CAPABILITIES,\n} as const satisfies AnkhPackageMetadata;\n"]}
1
+ {"version":3,"file":"packageMetadata.js","sourceRoot":"","sources":["../src/packageMetadata.ts"],"names":[],"mappings":"AAMA,OAAO,WAAW,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC,IAAI,CAAC;AACpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAC,OAAO,CAAC;AAC1D,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAA+C,CAAC;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,iBAAiB;IACjB,YAAY;IACZ,aAAa;IACb,gBAAgB;CAC8B,CAAC;AAEjD,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,QAAQ,EAAE,uBAAuB;IACjC,QAAQ,EAAE,qBAAqB;IAC/B,YAAY,EAAE,mBAAmB;CACK,CAAC","sourcesContent":["import type {\n AnkhCapabilityId,\n AnkhCommandCategory,\n AnkhPackageMetadata,\n} from '@ankhorage/contracts/cli';\n\nimport packageJson from '../package.json';\n\nexport const DOCTOR_PACKAGE_NAME = packageJson.name;\nexport const DOCTOR_PACKAGE_VERSION = packageJson.version;\nexport const DOCTOR_COMMAND_CATEGORY = 'doctor' as const satisfies AnkhCommandCategory;\nexport const DOCTOR_CAPABILITIES = [\n 'doctor.validate',\n 'doctor.fix',\n 'doctor.repo',\n 'doctor.package',\n] as const satisfies readonly AnkhCapabilityId[];\n\nexport const DOCTOR_PACKAGE_METADATA = {\n category: DOCTOR_COMMAND_CATEGORY,\n provider: './dist/cli/index.js',\n capabilities: DOCTOR_CAPABILITIES,\n} as const satisfies AnkhPackageMetadata;\n"]}
@@ -1,4 +1,4 @@
1
- import { runCli } from './cli.js';
1
+ import { runCli } from './cli/standalone.js';
2
2
  /***
3
3
  * Provider and CLI surface
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"readme-usage.js","sourceRoot":"","sources":["../src/readme-usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC","sourcesContent":["import { runCli } from './cli.js';\n\n/***\n * Provider and CLI surface\n *\n * `@ankhorage/doctor` is the repo/package compliance provider for Ankhorage.\n *\n * The same shared command implementation backs both:\n *\n * - `ankh doctor ...`\n * - `bunx @ankhorage/doctor ...`\n *\n * Current command surface:\n *\n * - `validate`\n * - `fix`\n * - `repo`\n * - `package`\n *\n * `doctor#2` adds a profile-based policy engine:\n *\n * - strict `public-package` validation for extracted public package repos\n * - light recognized `integration-monorepo` validation for `ankhorage4`\n * - non-mutating `fix` plans for deterministic mechanical changes only\n *\n * Still deferred:\n *\n * - GitHub checks\n * - CI checks\n * - on-disk `fix --apply`\n * - deeper cross-repo policy enforcement\n *\n * Path handling:\n *\n * - pass `[path]`, or\n * - omit it to inspect the current working directory\n *\n * @usage\n */\nawait runCli(['--help']);\n"]}
1
+ {"version":3,"file":"readme-usage.js","sourceRoot":"","sources":["../src/readme-usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC","sourcesContent":["import { runCli } from './cli/standalone.js';\n\n/***\n * Provider and CLI surface\n *\n * `@ankhorage/doctor` is the repo/package compliance provider for Ankhorage.\n *\n * The same shared command implementation backs both:\n *\n * - `ankh doctor ...`\n * - `bunx @ankhorage/doctor ...`\n *\n * Current command surface:\n *\n * - `validate`\n * - `fix`\n * - `repo`\n * - `package`\n *\n * `doctor#2` adds a profile-based policy engine:\n *\n * - strict `public-package` validation for extracted public package repos\n * - light recognized `integration-monorepo` validation for `ankhorage4`\n * - non-mutating `fix` plans for deterministic mechanical changes only\n *\n * Still deferred:\n *\n * - GitHub checks\n * - CI checks\n * - on-disk `fix --apply`\n * - deeper cross-repo policy enforcement\n *\n * Path handling:\n *\n * - pass `[path]`, or\n * - omit it to inspect the current working directory\n *\n * @usage\n */\nawait runCli(['--help']);\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/doctor",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Executable Ankh provider and standalone CLI for lightweight repo and package compliance diagnostics.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -31,6 +31,11 @@
31
31
  "import": "./dist/index.js",
32
32
  "default": "./dist/index.js"
33
33
  },
34
+ "./cli": {
35
+ "types": "./dist/cli/index.d.ts",
36
+ "import": "./dist/cli/index.js",
37
+ "default": "./dist/cli/index.js"
38
+ },
34
39
  "./package.json": "./package.json"
35
40
  },
36
41
  "files": [
@@ -42,11 +47,11 @@
42
47
  "LICENSE"
43
48
  ],
44
49
  "bin": {
45
- "ankhorage-doctor": "./dist/cli.js"
50
+ "ankhorage-doctor": "./dist/cli/standalone.js"
46
51
  },
47
52
  "ankh": {
48
53
  "category": "doctor",
49
- "provider": "./dist/ankh.provider.js",
54
+ "provider": "./dist/cli/index.js",
50
55
  "capabilities": [
51
56
  "doctor.validate",
52
57
  "doctor.fix",
@@ -1,18 +1,19 @@
1
- import type { AnkhRuntimeCommandProvider } from '@ankhorage/ankh';
1
+ import type { AnkhCommandHandler, AnkhRuntimeCommandProvider } from '@ankhorage/ankh';
2
2
 
3
+ import { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';
3
4
  import {
4
5
  createProviderCommandDescriptors,
5
6
  DOCTOR_COMMANDS,
6
7
  type DoctorCommandServices,
7
8
  runDoctorCommand,
8
9
  type RunDoctorCommandImpl,
9
- } from './commands.js';
10
+ } from '../commands.js';
10
11
  import {
11
12
  DOCTOR_CAPABILITIES,
12
13
  DOCTOR_COMMAND_CATEGORY,
13
14
  DOCTOR_PACKAGE_NAME,
14
15
  DOCTOR_PACKAGE_VERSION,
15
- } from './packageMetadata.js';
16
+ } from '../packageMetadata.js';
16
17
 
17
18
  export interface CreateDoctorRuntimeProviderOptions {
18
19
  readonly runCommandImpl?: RunDoctorCommandImpl;
@@ -23,6 +24,10 @@ export function createDoctorRuntimeProvider(
23
24
  options: CreateDoctorRuntimeProviderOptions = {},
24
25
  ): AnkhRuntimeCommandProvider {
25
26
  const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;
27
+ const services = {
28
+ analyzeTarget: analyzeDoctorTargetWithCliLayout,
29
+ ...options.services,
30
+ } satisfies DoctorCommandServices;
26
31
 
27
32
  return {
28
33
  id: DOCTOR_PACKAGE_NAME,
@@ -30,21 +35,24 @@ export function createDoctorRuntimeProvider(
30
35
  version: DOCTOR_PACKAGE_VERSION,
31
36
  capabilities: [...DOCTOR_CAPABILITIES],
32
37
  commands: createProviderCommandDescriptors(),
33
- handlers: DOCTOR_COMMANDS.map((command) => ({
34
- path: command.path,
35
- handler(request) {
36
- return runCommandImpl(
38
+ handlers: DOCTOR_COMMANDS.map((command) => {
39
+ const handler: AnkhCommandHandler = (request) =>
40
+ runCommandImpl(
37
41
  {
38
42
  argv: request.argv,
39
43
  command,
40
44
  context: request.context,
41
45
  },
42
46
  {
43
- services: options.services,
47
+ services,
44
48
  },
45
49
  );
46
- },
47
- })),
50
+
51
+ return {
52
+ path: command.path,
53
+ handler,
54
+ };
55
+ }),
48
56
  } satisfies AnkhRuntimeCommandProvider;
49
57
  }
50
58
 
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
4
- import { createDefaultCommandContext } from './commandContext.js';
3
+ import { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';
4
+ import type { DoctorCommandContext, DoctorCommandRunResult } from '../commandContext.js';
5
+ import { createDefaultCommandContext } from '../commandContext.js';
5
6
  import {
6
7
  type DoctorCommandServices,
7
8
  findDoctorCommandByStandaloneName,
@@ -9,7 +10,7 @@ import {
9
10
  renderUnknownCommand,
10
11
  runDoctorCommand,
11
12
  type RunDoctorCommandImpl,
12
- } from './commands.js';
13
+ } from '../commands.js';
13
14
 
14
15
  export interface DoctorCliOptions {
15
16
  readonly context?: DoctorCommandContext;
@@ -48,7 +49,10 @@ export async function runCli(
48
49
  context,
49
50
  },
50
51
  {
51
- services: options.services,
52
+ services: {
53
+ analyzeTarget: analyzeDoctorTargetWithCliLayout,
54
+ ...options.services,
55
+ },
52
56
  },
53
57
  );
54
58
  }
@@ -0,0 +1,105 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import {
5
+ analyzeDoctorTarget,
6
+ type DoctorAnalysisRequest,
7
+ type DoctorAnalysisResult,
8
+ } from './analysis.js';
9
+ import type { DoctorDiagnostic, DoctorPolicyProfile } from './diagnostics.js';
10
+
11
+ const LEGACY_ROOT_CLI_SOURCE = path.join('src', 'cli.ts');
12
+ const CANONICAL_CLI_INDEX_SOURCE = path.join('src', 'cli', 'index.ts');
13
+
14
+ export async function analyzeDoctorTargetWithCliLayout(
15
+ request: DoctorAnalysisRequest,
16
+ ): Promise<DoctorAnalysisResult> {
17
+ const result = await analyzeDoctorTarget(request);
18
+ if (!result.hasPackageJson) {
19
+ return result;
20
+ }
21
+
22
+ const cliDiagnostics = await analyzeCliLayout(result.targetPath, result.profile);
23
+ if (cliDiagnostics.length === 0) {
24
+ return result;
25
+ }
26
+
27
+ const diagnostics = [...result.diagnostics, ...cliDiagnostics];
28
+
29
+ return {
30
+ ...result,
31
+ diagnostics,
32
+ fixPlan: result.fixPlan === null ? null : { ...result.fixPlan, diagnostics },
33
+ };
34
+ }
35
+
36
+ async function analyzeCliLayout(
37
+ targetPath: string,
38
+ profile: DoctorPolicyProfile,
39
+ ): Promise<DoctorDiagnostic[]> {
40
+ const diagnostics: DoctorDiagnostic[] = [];
41
+ const legacyRootCliPath = path.join(targetPath, LEGACY_ROOT_CLI_SOURCE);
42
+ const canonicalCliIndexPath = path.join(targetPath, CANONICAL_CLI_INDEX_SOURCE);
43
+
44
+ if (await pathExists(legacyRootCliPath)) {
45
+ diagnostics.push({
46
+ code: 'field-invalid',
47
+ message: 'Package CLI code must live under src/cli/; root src/cli.ts is not allowed.',
48
+ path: legacyRootCliPath,
49
+ profile,
50
+ ruleId: 'package.cli.root-file.disallowed',
51
+ severity: 'error',
52
+ });
53
+ }
54
+
55
+ const packageJson = await readPackageJson(path.join(targetPath, 'package.json'));
56
+ if (
57
+ packageJson !== null &&
58
+ exposesCliProvider(packageJson) &&
59
+ !(await pathExists(canonicalCliIndexPath))
60
+ ) {
61
+ diagnostics.push({
62
+ code: 'missing-path',
63
+ message: 'CLI-capable packages must expose their provider from src/cli/index.ts.',
64
+ path: canonicalCliIndexPath,
65
+ profile,
66
+ ruleId: 'package.cli.index.required',
67
+ severity: 'error',
68
+ });
69
+ }
70
+
71
+ return diagnostics;
72
+ }
73
+
74
+ function exposesCliProvider(packageJson: Record<string, unknown>): boolean {
75
+ const ankh = isRecord(packageJson.ankh) ? packageJson.ankh : null;
76
+ const exportsField = isRecord(packageJson.exports) ? packageJson.exports : null;
77
+
78
+ return isNonEmptyString(ankh?.provider) || exportsField?.['./cli'] !== undefined;
79
+ }
80
+
81
+ async function readPackageJson(packageJsonPath: string): Promise<Record<string, unknown> | null> {
82
+ try {
83
+ const parsed: unknown = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
84
+ return isRecord(parsed) ? parsed : null;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ async function pathExists(targetPath: string): Promise<boolean> {
91
+ try {
92
+ await fs.access(targetPath);
93
+ return true;
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ function isNonEmptyString(value: unknown): value is string {
100
+ return typeof value === 'string' && value.trim().length > 0;
101
+ }
102
+
103
+ function isRecord(value: unknown): value is Record<string, unknown> {
104
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
105
+ }
@@ -22,6 +22,8 @@ export type DoctorRuleId =
22
22
  | 'package.ankh.present.valid-shape'
23
23
  | 'package.ankh.provider-path.required'
24
24
  | 'package.ankh.required-for-provider'
25
+ | 'package.cli.index.required'
26
+ | 'package.cli.root-file.disallowed'
25
27
  | 'package.dependencies.changesets.required'
26
28
  | 'package.dependencies.devtools.required'
27
29
  | 'package.dependencies.paradox.required'
package/src/index.ts CHANGED
@@ -11,8 +11,9 @@ export { analyzeDoctorTarget } from './analysis.js';
11
11
  export {
12
12
  createDoctorRuntimeProvider,
13
13
  type CreateDoctorRuntimeProviderOptions,
14
- } from './ankh.provider.js';
15
- export { runCli } from './cli.js';
14
+ } from './cli/index.js';
15
+ export { runCli } from './cli/standalone.js';
16
+ export { analyzeDoctorTargetWithCliLayout } from './cliLayoutAnalysis.js';
16
17
  export type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
17
18
  export { createDefaultCommandContext } from './commandContext.js';
18
19
  export type {
@@ -18,6 +18,6 @@ export const DOCTOR_CAPABILITIES = [
18
18
 
19
19
  export const DOCTOR_PACKAGE_METADATA = {
20
20
  category: DOCTOR_COMMAND_CATEGORY,
21
- provider: './dist/ankh.provider.js',
21
+ provider: './dist/cli/index.js',
22
22
  capabilities: DOCTOR_CAPABILITIES,
23
23
  } as const satisfies AnkhPackageMetadata;
@@ -1,4 +1,4 @@
1
- import { runCli } from './cli.js';
1
+ import { runCli } from './cli/standalone.js';
2
2
 
3
3
  /***
4
4
  * Provider and CLI surface
@@ -1 +0,0 @@
1
- {"version":3,"file":"ankh.provider.d.ts","sourceRoot":"","sources":["../src/ankh.provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAGL,KAAK,qBAAqB,EAE1B,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAQvB,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kCAAuC,GAC/C,0BAA0B,CAyB5B;AAED,QAAA,MAAM,QAAQ,4BAAgC,CAAC;AAE/C,eAAe,QAAQ,CAAC"}
@@ -1,27 +0,0 @@
1
- import { createProviderCommandDescriptors, DOCTOR_COMMANDS, runDoctorCommand, } from './commands.js';
2
- import { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY, DOCTOR_PACKAGE_NAME, DOCTOR_PACKAGE_VERSION, } from './packageMetadata.js';
3
- export function createDoctorRuntimeProvider(options = {}) {
4
- const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;
5
- return {
6
- id: DOCTOR_PACKAGE_NAME,
7
- category: DOCTOR_COMMAND_CATEGORY,
8
- version: DOCTOR_PACKAGE_VERSION,
9
- capabilities: [...DOCTOR_CAPABILITIES],
10
- commands: createProviderCommandDescriptors(),
11
- handlers: DOCTOR_COMMANDS.map((command) => ({
12
- path: command.path,
13
- handler(request) {
14
- return runCommandImpl({
15
- argv: request.argv,
16
- command,
17
- context: request.context,
18
- }, {
19
- services: options.services,
20
- });
21
- },
22
- })),
23
- };
24
- }
25
- const provider = createDoctorRuntimeProvider();
26
- export default provider;
27
- //# sourceMappingURL=ankh.provider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ankh.provider.js","sourceRoot":"","sources":["../src/ankh.provider.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gCAAgC,EAChC,eAAe,EAEf,gBAAgB,GAEjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAO9B,MAAM,UAAU,2BAA2B,CACzC,UAA8C,EAAE;IAEhD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAElE,OAAO;QACL,EAAE,EAAE,mBAAmB;QACvB,QAAQ,EAAE,uBAAuB;QACjC,OAAO,EAAE,sBAAsB;QAC/B,YAAY,EAAE,CAAC,GAAG,mBAAmB,CAAC;QACtC,QAAQ,EAAE,gCAAgC,EAAE;QAC5C,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,CAAC,OAAO;gBACb,OAAO,cAAc,CACnB;oBACE,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,OAAO;oBACP,OAAO,EAAE,OAAO,CAAC,OAAO;iBACzB,EACD;oBACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;iBAC3B,CACF,CAAC;YACJ,CAAC;SACF,CAAC,CAAC;KACiC,CAAC;AACzC,CAAC;AAED,MAAM,QAAQ,GAAG,2BAA2B,EAAE,CAAC;AAE/C,eAAe,QAAQ,CAAC","sourcesContent":["import type { AnkhRuntimeCommandProvider } from '@ankhorage/ankh';\n\nimport {\n createProviderCommandDescriptors,\n DOCTOR_COMMANDS,\n type DoctorCommandServices,\n runDoctorCommand,\n type RunDoctorCommandImpl,\n} from './commands.js';\nimport {\n DOCTOR_CAPABILITIES,\n DOCTOR_COMMAND_CATEGORY,\n DOCTOR_PACKAGE_NAME,\n DOCTOR_PACKAGE_VERSION,\n} from './packageMetadata.js';\n\nexport interface CreateDoctorRuntimeProviderOptions {\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport function createDoctorRuntimeProvider(\n options: CreateDoctorRuntimeProviderOptions = {},\n): AnkhRuntimeCommandProvider {\n const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;\n\n return {\n id: DOCTOR_PACKAGE_NAME,\n category: DOCTOR_COMMAND_CATEGORY,\n version: DOCTOR_PACKAGE_VERSION,\n capabilities: [...DOCTOR_CAPABILITIES],\n commands: createProviderCommandDescriptors(),\n handlers: DOCTOR_COMMANDS.map((command) => ({\n path: command.path,\n handler(request) {\n return runCommandImpl(\n {\n argv: request.argv,\n command,\n context: request.context,\n },\n {\n services: options.services,\n },\n );\n },\n })),\n } satisfies AnkhRuntimeCommandProvider;\n}\n\nconst provider = createDoctorRuntimeProvider();\n\nexport default provider;\n"]}
package/dist/cli.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAExF,OAAO,EACL,KAAK,qBAAqB,EAK1B,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACpD;AAED,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,sBAAsB,CAAC,CA+BjC"}
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAEL,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,eAAe,CAAC;AAQvB,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,IAAuB,EACvB,UAA4B,EAAE;IAE9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,2BAA2B,EAAE,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAC9D,MAAM,CAAC,UAAU,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC;IAEzC,IAAI,UAAU,KAAK,SAAS,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACrD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5C,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,OAAO,GAAG,iCAAiC,CAAC,UAAU,CAAC,CAAC;IAC9D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,UAAU,CACf;QACE,IAAI,EAAE,UAAU;QAChB,OAAO;QACP,OAAO;KACR,EACD;QACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,CAAC;AAClE,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;AACxE,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC","sourcesContent":["#!/usr/bin/env bun\n\nimport type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';\nimport { createDefaultCommandContext } from './commandContext.js';\nimport {\n type DoctorCommandServices,\n findDoctorCommandByStandaloneName,\n renderRootHelp,\n renderUnknownCommand,\n runDoctorCommand,\n type RunDoctorCommandImpl,\n} from './commands.js';\n\nexport interface DoctorCliOptions {\n readonly context?: DoctorCommandContext;\n readonly runCommandImpl?: RunDoctorCommandImpl;\n readonly services?: Partial<DoctorCommandServices>;\n}\n\nexport async function runCli(\n argv: readonly string[],\n options: DoctorCliOptions = {},\n): Promise<DoctorCommandRunResult> {\n const context = options.context ?? createDefaultCommandContext();\n const runCommand = options.runCommandImpl ?? runDoctorCommand;\n const [firstToken, ...restTokens] = argv;\n\n if (firstToken === undefined || isHelpToken(firstToken)) {\n context.writeStdout(renderRootHelp(context.version));\n return { exitCode: 0 };\n }\n\n if (isVersionToken(firstToken)) {\n context.writeStdout(`${context.version}\\n`);\n return { exitCode: 0 };\n }\n\n const command = findDoctorCommandByStandaloneName(firstToken);\n if (command === null) {\n context.writeStderr(renderUnknownCommand(firstToken));\n return { exitCode: 1 };\n }\n\n return runCommand(\n {\n argv: restTokens,\n command,\n context,\n },\n {\n services: options.services,\n },\n );\n}\n\nfunction isHelpToken(value: string): boolean {\n return value === '--help' || value === '-h' || value === 'help';\n}\n\nfunction isVersionToken(value: string): boolean {\n return value === '--version' || value === '-v' || value === 'version';\n}\n\nif (import.meta.main) {\n const result = await runCli(process.argv.slice(2));\n process.exit(result.exitCode);\n}\n"]}