@openpkg-ts/cli 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.
@@ -0,0 +1,20 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ export { __toESM, __require };
@@ -1,3 +1,5 @@
1
+ import"../shared/chunk-1dqs11h6.js";
2
+
1
3
  // src/index.ts
2
4
  import { getExport, listExports } from "@openpkg-ts/sdk";
3
5
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for OpenPkg TypeScript API extraction and documentation generation",
5
5
  "homepage": "https://github.com/ryanwaits/openpkg-ts#readme",
6
6
  "repository": {
@@ -9,17 +9,22 @@
9
9
  "directory": "packages/cli"
10
10
  },
11
11
  "type": "module",
12
+ "main": "./dist/src/index.js",
13
+ "types": "./dist/src/index.d.ts",
12
14
  "bin": {
13
- "openpkg": "./bin/openpkg.ts"
15
+ "openpkg": "./dist/bin/openpkg.js"
14
16
  },
17
+ "files": [
18
+ "dist"
19
+ ],
15
20
  "scripts": {
16
21
  "build": "bunup",
17
22
  "dev": "bunup --watch",
18
23
  "test": "bun test"
19
24
  },
20
25
  "dependencies": {
21
- "@openpkg-ts/adapters": "^0.3.0",
22
- "@openpkg-ts/sdk": "^0.31.0",
26
+ "@openpkg-ts/adapters": "^0.3.1",
27
+ "@openpkg-ts/sdk": "^0.32.0",
23
28
  "commander": "^14.0.0"
24
29
  },
25
30
  "devDependencies": {
package/CHANGELOG.md DELETED
@@ -1,44 +0,0 @@
1
- # @openpkg-ts/cli
2
-
3
- ## 0.3.0
4
-
5
- ### Minor Changes
6
-
7
- - bd70dc7: add diagnostics, filter primitives, new CLI commands (breaking, changelog, diagnostics, filter, semver, validate), registry system, render enhancements
8
-
9
- ### Patch Changes
10
-
11
- - Updated dependencies [bd70dc7]
12
- - @openpkg-ts/sdk@0.31.0
13
- - @openpkg-ts/adapters@0.3.0
14
-
15
- ## 0.2.3
16
-
17
- ### Patch Changes
18
-
19
- - update @openpkg-ts/sdk dependency to ^0.30.2
20
-
21
- ## 0.2.2
22
-
23
- ### Patch Changes
24
-
25
- - pull version from package.json instead of hardcoding
26
-
27
- ## 0.2.1
28
-
29
- ### Patch Changes
30
-
31
- - fix workspace:\* deps to use published versions for npm compatibility
32
- - Updated dependencies
33
- - @openpkg-ts/sdk@0.30.1
34
-
35
- ## 0.2.0
36
-
37
- ### Minor Changes
38
-
39
- - Major monorepo restructure: extract → sdk, doc-generator split into sdk/react/adapters, fumadocs-adapter deleted (use @openpkg-ts/adapters/fumadocs)
40
-
41
- ### Patch Changes
42
-
43
- - Updated dependencies
44
- - @openpkg-ts/sdk@0.30.0
package/bin/openpkg.ts DELETED
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env bun
2
- import * as path from 'node:path';
3
- import { getExport, listExports } from '@openpkg-ts/sdk';
4
- import { Command } from 'commander';
5
- import pkg from '../package.json';
6
- import { createBreakingCommand } from '../src/commands/breaking';
7
- import { createChangelogCommand } from '../src/commands/changelog';
8
- import { createDiagnosticsCommand } from '../src/commands/diagnostics';
9
- import { createDiffCommand } from '../src/commands/diff';
10
- import { createFilterCommand } from '../src/commands/filter';
11
- import { createDocsCommand } from '../src/commands/docs';
12
- import { createSemverCommand } from '../src/commands/semver';
13
- import { createSnapshotCommand } from '../src/commands/snapshot';
14
- import { createValidateCommand } from '../src/commands/validate';
15
-
16
- const program = new Command();
17
-
18
- program
19
- .name('openpkg')
20
- .description('OpenPkg CLI - TypeScript API extraction primitives')
21
- .version(pkg.version);
22
-
23
- program
24
- .command('list')
25
- .description('List exports from a TypeScript entry point')
26
- .argument('<entry>', 'Entry point file path')
27
- .action(async (entry: string) => {
28
- const entryFile = path.resolve(entry);
29
- const result = await listExports({ entryFile });
30
-
31
- if (result.errors.length > 0) {
32
- console.error(JSON.stringify({ errors: result.errors }, null, 2));
33
- process.exit(1);
34
- }
35
-
36
- console.log(JSON.stringify(result.exports, null, 2));
37
- });
38
-
39
- program
40
- .command('get')
41
- .description('Get detailed spec for a single export')
42
- .argument('<entry>', 'Entry point file path')
43
- .argument('<name>', 'Export name')
44
- .action(async (entry: string, name: string) => {
45
- const entryFile = path.resolve(entry);
46
- const result = await getExport({ entryFile, exportName: name });
47
-
48
- if (!result.export) {
49
- const errorMsg =
50
- result.errors.length > 0 ? result.errors.join('; ') : `Export '${name}' not found`;
51
- console.error(JSON.stringify({ error: errorMsg }, null, 2));
52
- process.exit(1);
53
- }
54
-
55
- // Output export with related types if any
56
- const output: Record<string, unknown> = { export: result.export };
57
- if (result.types.length > 0) {
58
- output.types = result.types;
59
- }
60
- console.log(JSON.stringify(output, null, 2));
61
- });
62
-
63
- program.addCommand(createSnapshotCommand());
64
- program.addCommand(createDiffCommand());
65
- program.addCommand(createDocsCommand());
66
- program.addCommand(createBreakingCommand());
67
- program.addCommand(createChangelogCommand());
68
- program.addCommand(createSemverCommand());
69
- program.addCommand(createValidateCommand());
70
- program.addCommand(createDiagnosticsCommand());
71
- program.addCommand(createFilterCommand());
72
-
73
- program.parse();
@@ -1,46 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { type CategorizedBreaking, categorizeBreakingChanges, diffSpec, type OpenPkg } from '@openpkg-ts/spec';
4
- import { Command } from 'commander';
5
-
6
- export type BreakingResult = {
7
- breaking: CategorizedBreaking[];
8
- count: number;
9
- };
10
-
11
- function loadSpec(filePath: string): OpenPkg {
12
- const resolved = path.resolve(filePath);
13
- const content = fs.readFileSync(resolved, 'utf-8');
14
- return JSON.parse(content) as OpenPkg;
15
- }
16
-
17
- export function createBreakingCommand(): Command {
18
- return new Command('breaking')
19
- .description('Check for breaking changes between two specs')
20
- .argument('<old>', 'Path to old spec file (JSON)')
21
- .argument('<new>', 'Path to new spec file (JSON)')
22
- .action(async (oldPath: string, newPath: string) => {
23
- try {
24
- const oldSpec = loadSpec(oldPath);
25
- const newSpec = loadSpec(newPath);
26
-
27
- const diff = diffSpec(oldSpec, newSpec);
28
- const categorized = categorizeBreakingChanges(diff.breaking, oldSpec, newSpec);
29
-
30
- const result: BreakingResult = {
31
- breaking: categorized,
32
- count: categorized.length,
33
- };
34
-
35
- console.log(JSON.stringify(result, null, 2));
36
-
37
- if (categorized.length > 0) {
38
- process.exit(1);
39
- }
40
- } catch (err) {
41
- const error = err instanceof Error ? err : new Error(String(err));
42
- console.error(JSON.stringify({ error: error.message }, null, 2));
43
- process.exit(1);
44
- }
45
- });
46
- }
@@ -1,78 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import * as fs from 'node:fs';
3
- import * as os from 'node:os';
4
- import * as path from 'node:path';
5
- import type { OpenPkg } from '@openpkg-ts/spec';
6
- import { $ } from 'bun';
7
-
8
- const oldSpec: OpenPkg = {
9
- meta: { name: 'test-pkg', version: '1.0.0' },
10
- exports: [
11
- { id: 'fn-greet', name: 'greet', kind: 'function', signatures: [] },
12
- { id: 'fn-removed', name: 'removed', kind: 'function', signatures: [] },
13
- ],
14
- types: [],
15
- };
16
-
17
- const newSpec: OpenPkg = {
18
- meta: { name: 'test-pkg', version: '2.0.0' },
19
- exports: [
20
- { id: 'fn-greet', name: 'greet', kind: 'function', signatures: [] },
21
- { id: 'fn-added', name: 'added', kind: 'function', signatures: [] },
22
- ],
23
- types: [],
24
- };
25
-
26
- describe('changelog command', () => {
27
- test('outputs JSON format', async () => {
28
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'changelog-test-'));
29
- const oldPath = path.join(tmpDir, 'old.json');
30
- const newPath = path.join(tmpDir, 'new.json');
31
-
32
- fs.writeFileSync(oldPath, JSON.stringify(oldSpec));
33
- fs.writeFileSync(newPath, JSON.stringify(newSpec));
34
-
35
- const result = await $`bun packages/cli/bin/openpkg.ts changelog ${oldPath} ${newPath} --format json`.text();
36
- const parsed = JSON.parse(result);
37
-
38
- expect(parsed).toHaveProperty('breaking');
39
- expect(parsed).toHaveProperty('added');
40
- expect(parsed).toHaveProperty('removed');
41
- expect(parsed).toHaveProperty('summary');
42
-
43
- fs.rmSync(tmpDir, { recursive: true });
44
- });
45
-
46
- test('outputs markdown format', async () => {
47
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'changelog-test-'));
48
- const oldPath = path.join(tmpDir, 'old.json');
49
- const newPath = path.join(tmpDir, 'new.json');
50
-
51
- fs.writeFileSync(oldPath, JSON.stringify(oldSpec));
52
- fs.writeFileSync(newPath, JSON.stringify(newSpec));
53
-
54
- const result = await $`bun packages/cli/bin/openpkg.ts changelog ${oldPath} ${newPath}`.text();
55
-
56
- expect(result).toContain('## Breaking Changes');
57
- expect(result).toContain('removed');
58
- expect(result).toContain('## Added');
59
- expect(result).toContain('added');
60
-
61
- fs.rmSync(tmpDir, { recursive: true });
62
- });
63
-
64
- test('empty diff shows no changes', async () => {
65
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'changelog-test-'));
66
- const oldPath = path.join(tmpDir, 'old.json');
67
- const newPath = path.join(tmpDir, 'new.json');
68
-
69
- fs.writeFileSync(oldPath, JSON.stringify(oldSpec));
70
- fs.writeFileSync(newPath, JSON.stringify(oldSpec));
71
-
72
- const result = await $`bun packages/cli/bin/openpkg.ts changelog ${oldPath} ${newPath}`.text();
73
-
74
- expect(result.trim()).toBe('No changes detected.');
75
-
76
- fs.rmSync(tmpDir, { recursive: true });
77
- });
78
- });
@@ -1,79 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import type { OpenPkg } from '@openpkg-ts/spec';
4
- import { Command } from 'commander';
5
- import { type DiffResult, enrichDiff } from './diff.js';
6
-
7
- function loadSpec(filePath: string): OpenPkg {
8
- const resolved = path.resolve(filePath);
9
- const content = fs.readFileSync(resolved, 'utf-8');
10
- return JSON.parse(content) as OpenPkg;
11
- }
12
-
13
- /**
14
- * Format diff result as markdown changelog
15
- */
16
- function formatMarkdown(diff: DiffResult): string {
17
- const lines: string[] = [];
18
-
19
- // Breaking Changes
20
- if (diff.removed.length > 0 || diff.changed.length > 0) {
21
- lines.push('## Breaking Changes');
22
- lines.push('');
23
- for (const r of diff.removed) {
24
- lines.push(`- **Removed** \`${r.name}\` (${r.kind})`);
25
- }
26
- for (const c of diff.changed) {
27
- lines.push(`- **${c.name}** (${c.kind}): ${c.description}`);
28
- }
29
- lines.push('');
30
- }
31
-
32
- // Added
33
- if (diff.added.length > 0) {
34
- lines.push('## Added');
35
- lines.push('');
36
- for (const id of diff.added) {
37
- lines.push(`- \`${id}\``);
38
- }
39
- lines.push('');
40
- }
41
-
42
- // Changed (docs only)
43
- if (diff.docsOnly.length > 0) {
44
- lines.push('## Changed');
45
- lines.push('');
46
- for (const id of diff.docsOnly) {
47
- lines.push(`- \`${id}\` (docs)`);
48
- }
49
- lines.push('');
50
- }
51
-
52
- return lines.join('\n').trim() || 'No changes detected.';
53
- }
54
-
55
- export function createChangelogCommand(): Command {
56
- return new Command('changelog')
57
- .description('Generate changelog from diff between two specs')
58
- .argument('<old>', 'Path to old spec file (JSON)')
59
- .argument('<new>', 'Path to new spec file (JSON)')
60
- .option('--format <format>', 'Output format: md or json', 'md')
61
- .action(async (oldPath: string, newPath: string, options: { format?: string }) => {
62
- try {
63
- const oldSpec = loadSpec(oldPath);
64
- const newSpec = loadSpec(newPath);
65
-
66
- const diff = enrichDiff(oldSpec, newSpec);
67
-
68
- if (options.format === 'json') {
69
- console.log(JSON.stringify(diff, null, 2));
70
- } else {
71
- console.log(formatMarkdown(diff));
72
- }
73
- } catch (err) {
74
- const error = err instanceof Error ? err : new Error(String(err));
75
- console.error(JSON.stringify({ error: error.message }, null, 2));
76
- process.exit(1);
77
- }
78
- });
79
- }
@@ -1,55 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, it } from 'bun:test';
2
- import * as fs from 'node:fs';
3
- import * as os from 'node:os';
4
- import * as path from 'node:path';
5
- import { $ } from 'bun';
6
-
7
- describe('openpkg diagnostics', () => {
8
- let tmpDir: string;
9
-
10
- beforeAll(() => {
11
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'diagnostics-test-'));
12
- });
13
-
14
- afterAll(() => {
15
- fs.rmSync(tmpDir, { recursive: true });
16
- });
17
-
18
- it('outputs JSON with diagnostics', async () => {
19
- const specPath = path.join(tmpDir, 'spec.json');
20
- const spec = {
21
- openpkg: '0.4.0',
22
- meta: { name: 'test-pkg' },
23
- exports: [
24
- { id: 'a', name: 'noDesc', kind: 'function' },
25
- { id: 'b', name: 'withDesc', kind: 'function', description: 'Has desc' },
26
- {
27
- id: 'c',
28
- name: 'depNoReason',
29
- kind: 'function',
30
- description: 'Something',
31
- deprecated: true,
32
- },
33
- ],
34
- };
35
- fs.writeFileSync(specPath, JSON.stringify(spec));
36
-
37
- const output = await $`bun packages/cli/bin/openpkg.ts diagnostics ${specPath}`.text();
38
- const result = JSON.parse(output);
39
-
40
- expect(result.summary.total).toBe(2);
41
- expect(result.summary.missingDescriptions).toBe(1);
42
- expect(result.summary.deprecatedNoReason).toBe(1);
43
- expect(result.diagnostics.missingDescriptions[0].exportName).toBe('noDesc');
44
- });
45
-
46
- it('handles malformed spec gracefully', async () => {
47
- const specPath = path.join(tmpDir, 'bad.json');
48
- fs.writeFileSync(specPath, '{ invalid json');
49
-
50
- const output = await $`bun packages/cli/bin/openpkg.ts diagnostics ${specPath}`.text();
51
- const result = JSON.parse(output);
52
-
53
- expect(result.error).toBeDefined();
54
- });
55
- });
@@ -1,55 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { analyzeSpec, type SpecDiagnostics } from '@openpkg-ts/sdk';
4
- import type { OpenPkg } from '@openpkg-ts/spec';
5
- import { Command } from 'commander';
6
-
7
- export interface DiagnosticsResult {
8
- summary: {
9
- total: number;
10
- missingDescriptions: number;
11
- deprecatedNoReason: number;
12
- missingParamDocs: number;
13
- };
14
- diagnostics: SpecDiagnostics;
15
- }
16
-
17
- function loadJSON(filePath: string): unknown {
18
- const resolved = path.resolve(filePath);
19
- const content = fs.readFileSync(resolved, 'utf-8');
20
- return JSON.parse(content);
21
- }
22
-
23
- export function createDiagnosticsCommand(): Command {
24
- return new Command('diagnostics')
25
- .description('Analyze spec for quality issues (missing docs, deprecated without reason)')
26
- .argument('<spec>', 'Path to spec file (JSON)')
27
- .action(async (specPath: string) => {
28
- try {
29
- const spec = loadJSON(specPath) as OpenPkg;
30
-
31
- const diagnostics = analyzeSpec(spec);
32
-
33
- const result: DiagnosticsResult = {
34
- summary: {
35
- total:
36
- diagnostics.missingDescriptions.length +
37
- diagnostics.deprecatedNoReason.length +
38
- diagnostics.missingParamDocs.length,
39
- missingDescriptions: diagnostics.missingDescriptions.length,
40
- deprecatedNoReason: diagnostics.deprecatedNoReason.length,
41
- missingParamDocs: diagnostics.missingParamDocs.length,
42
- },
43
- diagnostics,
44
- };
45
-
46
- console.log(JSON.stringify(result, null, 2));
47
- // Always exit 0 - informational only
48
- process.exit(0);
49
- } catch (err) {
50
- const error = err instanceof Error ? err : new Error(String(err));
51
- console.log(JSON.stringify({ error: error.message }, null, 2));
52
- process.exit(0);
53
- }
54
- });
55
- }
@@ -1,174 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import {
4
- type CategorizedBreaking,
5
- categorizeBreakingChanges,
6
- diffSpec,
7
- type OpenPkg,
8
- recommendSemverBump,
9
- type SemverBump,
10
- type SpecExportKind,
11
- } from '@openpkg-ts/spec';
12
- import { Command } from 'commander';
13
-
14
- /**
15
- * A changed export with details about what changed
16
- */
17
- export interface ChangedExport {
18
- id: string;
19
- name: string;
20
- kind: SpecExportKind;
21
- description: string;
22
- }
23
-
24
- /**
25
- * Enriched diff result with categorized changes
26
- */
27
- export interface DiffResult {
28
- breaking: CategorizedBreaking[];
29
- added: string[];
30
- removed: RemovedExport[];
31
- changed: ChangedExport[];
32
- docsOnly: string[];
33
- summary: {
34
- breakingCount: number;
35
- addedCount: number;
36
- removedCount: number;
37
- changedCount: number;
38
- docsOnlyCount: number;
39
- semverBump: SemverBump;
40
- semverReason: string;
41
- };
42
- }
43
-
44
- export interface RemovedExport {
45
- id: string;
46
- name: string;
47
- kind: SpecExportKind;
48
- }
49
-
50
- function loadSpec(filePath: string): OpenPkg {
51
- const resolved = path.resolve(filePath);
52
- const content = fs.readFileSync(resolved, 'utf-8');
53
- return JSON.parse(content) as OpenPkg;
54
- }
55
-
56
- function toExportMap(spec: OpenPkg): Map<string, { name: string; kind: SpecExportKind }> {
57
- const map = new Map<string, { name: string; kind: SpecExportKind }>();
58
- for (const exp of spec.exports) {
59
- map.set(exp.id, { name: exp.name, kind: exp.kind });
60
- }
61
- if (spec.types) {
62
- for (const t of spec.types) {
63
- map.set(t.id, { name: t.name, kind: t.kind as SpecExportKind });
64
- }
65
- }
66
- return map;
67
- }
68
-
69
- /**
70
- * Enriches basic diffSpec output with categorization
71
- */
72
- export function enrichDiff(oldSpec: OpenPkg, newSpec: OpenPkg): DiffResult {
73
- const rawDiff = diffSpec(oldSpec, newSpec);
74
- const categorized = categorizeBreakingChanges(rawDiff.breaking, oldSpec, newSpec);
75
- const semver = recommendSemverBump(rawDiff);
76
-
77
- const oldExports = toExportMap(oldSpec);
78
-
79
- // Separate removed from changed
80
- const removed: RemovedExport[] = [];
81
- const changed: ChangedExport[] = [];
82
- const breaking: CategorizedBreaking[] = [];
83
-
84
- for (const cat of categorized) {
85
- if (cat.reason === 'removed') {
86
- const info = oldExports.get(cat.id);
87
- removed.push({
88
- id: cat.id,
89
- name: cat.name,
90
- kind: info?.kind ?? cat.kind,
91
- });
92
- } else {
93
- // It's a change, not a removal
94
- changed.push({
95
- id: cat.id,
96
- name: cat.name,
97
- kind: cat.kind,
98
- description: describeChange(cat),
99
- });
100
- breaking.push(cat);
101
- }
102
- }
103
-
104
- // Added exports
105
- const added = rawDiff.nonBreaking;
106
-
107
- return {
108
- breaking,
109
- added,
110
- removed,
111
- changed,
112
- docsOnly: rawDiff.docsOnly,
113
- summary: {
114
- breakingCount: breaking.length,
115
- addedCount: added.length,
116
- removedCount: removed.length,
117
- changedCount: changed.length,
118
- docsOnlyCount: rawDiff.docsOnly.length,
119
- semverBump: semver.bump,
120
- semverReason: semver.reason,
121
- },
122
- };
123
- }
124
-
125
- /**
126
- * Generate human-readable description for a change
127
- */
128
- function describeChange(cat: CategorizedBreaking): string {
129
- switch (cat.reason) {
130
- case 'signature changed':
131
- return `Function signature changed`;
132
- case 'type definition changed':
133
- return `Type definition changed`;
134
- case 'constructor changed':
135
- return `Class constructor signature changed`;
136
- case 'methods removed':
137
- return `Class methods removed`;
138
- case 'methods changed':
139
- return `Class methods changed`;
140
- case 'changed':
141
- return `${cat.kind} changed`;
142
- default:
143
- return cat.reason;
144
- }
145
- }
146
-
147
- export function createDiffCommand(): Command {
148
- return new Command('diff')
149
- .description('Compare two OpenPkg specs and show differences')
150
- .argument('<old>', 'Path to old spec file (JSON)')
151
- .argument('<new>', 'Path to new spec file (JSON)')
152
- .option('--json', 'Output as JSON (default)')
153
- .option('--summary', 'Only show summary')
154
- .action(
155
- async (oldPath: string, newPath: string, options: { json?: boolean; summary?: boolean }) => {
156
- try {
157
- const oldSpec = loadSpec(oldPath);
158
- const newSpec = loadSpec(newPath);
159
-
160
- const result = enrichDiff(oldSpec, newSpec);
161
-
162
- if (options.summary) {
163
- console.log(JSON.stringify(result.summary, null, 2));
164
- } else {
165
- console.log(JSON.stringify(result, null, 2));
166
- }
167
- } catch (err) {
168
- const error = err instanceof Error ? err : new Error(String(err));
169
- console.error(JSON.stringify({ error: error.message }, null, 2));
170
- process.exit(1);
171
- }
172
- },
173
- );
174
- }