@ankhorage/doctor 0.2.0 → 0.3.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/src/commands.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { AnkhCapabilityId, AnkhCommandDescriptor } from '@ankhorage/contracts/cli';
2
2
 
3
- import type { DoctorAnalysisResult, DoctorTargetMode } from './analysis.js';
3
+ import type { DoctorAnalysisResult, DoctorPlannedChange, DoctorTargetMode } from './analysis.js';
4
4
  import { analyzeDoctorTarget } from './analysis.js';
5
5
  import type { DoctorCommandContext, DoctorCommandRunResult } from './commandContext.js';
6
6
  import {
@@ -64,7 +64,7 @@ export const DOCTOR_COMMANDS = [
64
64
  path: ['validate'],
65
65
  capability: COMMAND_CAPABILITIES.validate,
66
66
  mode: 'validate',
67
- summary: 'Auto-detect lightweight repo and package diagnostics for a local path.',
67
+ summary: 'Auto-detect the applicable doctor policy profile and validate a local path.',
68
68
  run: runValidateCommand,
69
69
  },
70
70
  {
@@ -72,7 +72,7 @@ export const DOCTOR_COMMANDS = [
72
72
  path: ['fix'],
73
73
  capability: COMMAND_CAPABILITIES.fix,
74
74
  mode: 'fix',
75
- summary: 'Run the same lightweight checks and report that no automatic fixes exist yet.',
75
+ summary: 'Build a non-mutating fix plan for deterministic doctor policy violations.',
76
76
  run: runFixCommand,
77
77
  },
78
78
  {
@@ -226,7 +226,6 @@ async function runFixCommand(
226
226
  });
227
227
 
228
228
  request.context.writeStdout(renderAnalysisReport('fix', result));
229
- request.context.writeStdout('No automatic fixes available.\n');
230
229
 
231
230
  return {
232
231
  exitCode: countErrorDiagnostics(result.diagnostics) > 0 ? 1 : 0,
@@ -274,6 +273,7 @@ function renderAnalysisReport(
274
273
  const lines = [
275
274
  `doctor ${commandName}`,
276
275
  `target: ${result.targetPath}`,
276
+ `profile: ${result.profile}`,
277
277
  `checks: ${result.appliedChecks.length > 0 ? result.appliedChecks.join(', ') : 'none'}`,
278
278
  `repoMarkers: ${result.repoMarkers.length > 0 ? result.repoMarkers.join(', ') : 'none'}`,
279
279
  '',
@@ -288,6 +288,19 @@ function renderAnalysisReport(
288
288
  }
289
289
  }
290
290
 
291
+ if (commandName === 'fix') {
292
+ lines.push('');
293
+ lines.push('Planned changes:');
294
+
295
+ if (result.plannedChanges.length === 0) {
296
+ lines.push(' none');
297
+ } else {
298
+ for (const change of result.plannedChanges) {
299
+ lines.push(renderPlannedChangeLine(change));
300
+ }
301
+ }
302
+ }
303
+
291
304
  const errorCount = countErrorDiagnostics(result.diagnostics);
292
305
  const warningCount = countWarningDiagnostics(result.diagnostics);
293
306
 
@@ -299,7 +312,11 @@ function renderAnalysisReport(
299
312
  }
300
313
 
301
314
  function renderDiagnosticLine(diagnostic: DoctorDiagnostic): string {
302
- return ` - ${diagnostic.severity.toUpperCase()} ${diagnostic.code}: ${diagnostic.message}`;
315
+ return ` - ${diagnostic.severity.toUpperCase()} ${diagnostic.ruleId} (${diagnostic.code}): ${diagnostic.message}`;
316
+ }
317
+
318
+ function renderPlannedChangeLine(change: DoctorPlannedChange): string {
319
+ return ` - ${change.ruleId} [${change.kind}]: ${change.description}`;
303
320
  }
304
321
 
305
322
  function renderCommandFailure(commandName: DoctorCommandName, error: unknown): string {
@@ -1,26 +1,83 @@
1
1
  export type DoctorDiagnosticCode =
2
+ | 'field-invalid'
3
+ | 'field-missing'
2
4
  | 'invalid-ankh-metadata'
3
5
  | 'invalid-package-json'
4
- | 'missing-changelog'
5
- | 'missing-changeset-directory'
6
- | 'missing-license'
7
- | 'missing-readme'
8
- | 'missing-workflows-directory'
9
- | 'package-json-missing'
10
- | 'package-name-missing'
11
- | 'package-type-missing'
12
- | 'package-version-missing'
13
- | 'repo-markers-missing'
6
+ | 'missing-dependency'
7
+ | 'missing-path'
8
+ | 'missing-script'
9
+ | 'provider-source-import-failed'
10
+ | 'provider-source-missing'
14
11
  | 'target-not-directory'
15
12
  | 'target-not-found'
16
13
  | 'unsupported-target';
17
14
 
18
15
  export type DoctorDiagnosticSeverity = 'error' | 'warning';
16
+ export type DoctorPolicyProfile = 'integration-monorepo' | 'public-package' | 'unknown';
17
+ export type DoctorRuleId =
18
+ | 'integration.package.ankh.disallowed'
19
+ | 'integration.package.private.required'
20
+ | 'integration.package.workspaces.required'
21
+ | 'package.ankh.capabilities.match-provider'
22
+ | 'package.ankh.present.valid-shape'
23
+ | 'package.ankh.provider-path.required'
24
+ | 'package.ankh.required-for-provider'
25
+ | 'package.dependencies.changesets.required'
26
+ | 'package.dependencies.devtools.required'
27
+ | 'package.dependencies.paradox.required'
28
+ | 'package.dependencies.types-bun.required'
29
+ | 'package.dependencies.types-node.required'
30
+ | 'package.dependencies.typescript.required'
31
+ | 'package.json.bugs.required'
32
+ | 'package.json.description.required'
33
+ | 'package.json.exports.required'
34
+ | 'package.json.files.required'
35
+ | 'package.json.homepage.required'
36
+ | 'package.json.keywords.required'
37
+ | 'package.json.license.required'
38
+ | 'package.json.name.required'
39
+ | 'package.json.package-manager.bun'
40
+ | 'package.json.package-manager.required'
41
+ | 'package.json.private.public-package-disallowed'
42
+ | 'package.json.publish-config.public'
43
+ | 'package.json.publish-config.required'
44
+ | 'package.json.repository.required'
45
+ | 'package.json.type.module'
46
+ | 'package.json.type.required'
47
+ | 'package.json.version.required'
48
+ | 'package.scripts.build.required'
49
+ | 'package.scripts.changeset-status.required'
50
+ | 'package.scripts.changeset.required'
51
+ | 'package.scripts.docs.required'
52
+ | 'package.scripts.format-check.required'
53
+ | 'package.scripts.format.required'
54
+ | 'package.scripts.knip.required'
55
+ | 'package.scripts.lint-fix.required'
56
+ | 'package.scripts.lint.required'
57
+ | 'package.scripts.test.required'
58
+ | 'package.scripts.typecheck.required'
59
+ | 'package.scripts.version-packages.required'
60
+ | 'provider.commands.match-capabilities'
61
+ | 'provider.commands.match-handlers'
62
+ | 'provider.source.importable'
63
+ | 'provider.source.required'
64
+ | 'repo.changelog.required'
65
+ | 'repo.changeset.required'
66
+ | 'repo.license.required'
67
+ | 'repo.readme.required'
68
+ | 'repo.workflows.required'
69
+ | 'target.package-json.required'
70
+ | 'target.path.directory'
71
+ | 'target.path.exists'
72
+ | 'target.profile.supported'
73
+ | 'target.repo-markers.required';
19
74
 
20
75
  export interface DoctorDiagnostic {
21
76
  readonly code: DoctorDiagnosticCode;
22
77
  readonly message: string;
23
78
  readonly path: string;
79
+ readonly profile: DoctorPolicyProfile;
80
+ readonly ruleId: DoctorRuleId;
24
81
  readonly severity: DoctorDiagnosticSeverity;
25
82
  }
26
83
 
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export type {
2
2
  DoctorAnalysisRequest,
3
3
  DoctorAnalysisResult,
4
+ DoctorFixPlan,
5
+ DoctorPlannedChange,
6
+ DoctorPlannedChangeKind,
4
7
  DoctorTargetCheck,
5
8
  DoctorTargetMode,
6
9
  } from './analysis.js';
@@ -16,6 +19,8 @@ export type {
16
19
  DoctorDiagnostic,
17
20
  DoctorDiagnosticCode,
18
21
  DoctorDiagnosticSeverity,
22
+ DoctorPolicyProfile,
23
+ DoctorRuleId,
19
24
  } from './diagnostics.js';
20
25
  export {
21
26
  DOCTOR_CAPABILITIES,
@@ -17,10 +17,18 @@ import { runCli } from './cli.js';
17
17
  * - `repo`
18
18
  * - `package`
19
19
  *
20
- * `doctor#1` intentionally stays lightweight:
20
+ * `doctor#2` adds a profile-based policy engine:
21
21
  *
22
- * - path-aware local repo/package diagnostics are implemented now
23
- * - GitHub checks, CI checks, full policy enforcement, and autofix rules are deferred
22
+ * - strict `public-package` validation for extracted public package repos
23
+ * - light recognized `integration-monorepo` validation for `ankhorage4`
24
+ * - non-mutating `fix` plans for deterministic mechanical changes only
25
+ *
26
+ * Still deferred:
27
+ *
28
+ * - GitHub checks
29
+ * - CI checks
30
+ * - on-disk `fix --apply`
31
+ * - deeper cross-repo policy enforcement
24
32
  *
25
33
  * Path handling:
26
34
  *