@ankhorage/doctor 0.3.1 → 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.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +6 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/{cli.d.ts → cli/standalone.d.ts} +3 -3
- package/dist/cli/standalone.d.ts.map +1 -0
- package/dist/{cli.js → cli/standalone.js} +8 -4
- package/dist/cli/standalone.js.map +1 -0
- package/dist/cliLayoutAnalysis.d.ts +3 -0
- package/dist/cliLayoutAnalysis.d.ts.map +1 -0
- package/dist/cliLayoutAnalysis.js +80 -0
- package/dist/cliLayoutAnalysis.js.map +1 -0
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/readme-usage.js +1 -1
- package/dist/readme-usage.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/index.ts +6 -1
- package/src/{cli.ts → cli/standalone.ts} +8 -4
- package/src/cliLayoutAnalysis.ts +105 -0
- package/src/diagnostics.ts +2 -0
- package/src/index.ts +2 -1
- package/src/readme-usage.ts +1 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
        
|
|
7
7
|
|
|
8
|
-
Executable doctor provider and standalone CLI for lightweight
|
|
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
|
```
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { analyzeDoctorTargetWithCliLayout } from '../cliLayoutAnalysis.js';
|
|
1
2
|
import { createProviderCommandDescriptors, DOCTOR_COMMANDS, runDoctorCommand, } from '../commands.js';
|
|
2
3
|
import { DOCTOR_CAPABILITIES, DOCTOR_COMMAND_CATEGORY, DOCTOR_PACKAGE_NAME, DOCTOR_PACKAGE_VERSION, } from '../packageMetadata.js';
|
|
3
4
|
export function createDoctorRuntimeProvider(options = {}) {
|
|
4
5
|
const runCommandImpl = options.runCommandImpl ?? runDoctorCommand;
|
|
6
|
+
const services = {
|
|
7
|
+
analyzeTarget: analyzeDoctorTargetWithCliLayout,
|
|
8
|
+
...options.services,
|
|
9
|
+
};
|
|
5
10
|
return {
|
|
6
11
|
id: DOCTOR_PACKAGE_NAME,
|
|
7
12
|
category: DOCTOR_COMMAND_CATEGORY,
|
|
@@ -14,7 +19,7 @@ export function createDoctorRuntimeProvider(options = {}) {
|
|
|
14
19
|
command,
|
|
15
20
|
context: request.context,
|
|
16
21
|
}, {
|
|
17
|
-
services
|
|
22
|
+
services,
|
|
18
23
|
});
|
|
19
24
|
return {
|
|
20
25
|
path: command.path,
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAEA,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;
|
|
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 '
|
|
3
|
-
import { type DoctorCommandServices, type RunDoctorCommandImpl } from '
|
|
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=
|
|
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 {
|
|
3
|
-
import {
|
|
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:
|
|
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=
|
|
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 @@
|
|
|
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":"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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"]}
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -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"}
|
package/dist/diagnostics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"
|
|
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 { runCli } from './cli.js';
|
|
4
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,EAAE,MAAM,EAAE,MAAM,
|
|
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 { runCli } from './cli.js';
|
|
3
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,EAAE,MAAM,EAAE,MAAM,
|
|
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"]}
|
package/dist/readme-usage.js
CHANGED
package/dist/readme-usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readme-usage.js","sourceRoot":"","sources":["../src/readme-usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,
|
|
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
|
+
"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": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"LICENSE"
|
|
48
48
|
],
|
|
49
49
|
"bin": {
|
|
50
|
-
"ankhorage-doctor": "./dist/cli.js"
|
|
50
|
+
"ankhorage-doctor": "./dist/cli/standalone.js"
|
|
51
51
|
},
|
|
52
52
|
"ankh": {
|
|
53
53
|
"category": "doctor",
|
package/src/cli/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
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,
|
|
@@ -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,
|
|
@@ -39,7 +44,7 @@ export function createDoctorRuntimeProvider(
|
|
|
39
44
|
context: request.context,
|
|
40
45
|
},
|
|
41
46
|
{
|
|
42
|
-
services
|
|
47
|
+
services,
|
|
43
48
|
},
|
|
44
49
|
);
|
|
45
50
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
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 '
|
|
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:
|
|
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
|
+
}
|
package/src/diagnostics.ts
CHANGED
|
@@ -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
|
@@ -8,11 +8,12 @@ export type {
|
|
|
8
8
|
DoctorTargetMode,
|
|
9
9
|
} from './analysis.js';
|
|
10
10
|
export { analyzeDoctorTarget } from './analysis.js';
|
|
11
|
-
export { runCli } from './cli.js';
|
|
12
11
|
export {
|
|
13
12
|
createDoctorRuntimeProvider,
|
|
14
13
|
type CreateDoctorRuntimeProviderOptions,
|
|
15
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 {
|
package/src/readme-usage.ts
CHANGED
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"]}
|