cadr-cli 0.0.1 ā 1.9.1
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/dist/adr.d.ts +50 -0
- package/dist/adr.d.ts.map +1 -0
- package/dist/adr.js +156 -0
- package/dist/adr.js.map +1 -0
- package/dist/adr.test.d.ts +8 -0
- package/dist/adr.test.d.ts.map +1 -0
- package/dist/adr.test.js +256 -0
- package/dist/adr.test.js.map +1 -0
- package/dist/analysis.d.ts +24 -0
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +281 -0
- package/dist/analysis.js.map +1 -0
- package/dist/analysis.test.d.ts +8 -0
- package/dist/analysis.test.d.ts.map +1 -0
- package/dist/analysis.test.js +351 -0
- package/dist/analysis.test.js.map +1 -0
- package/dist/commands/analyze.d.ts +14 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +56 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +93 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +56 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +208 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +97 -0
- package/dist/config.test.js.map +1 -0
- package/dist/git.d.ts +42 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +157 -0
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +78 -62
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +51 -0
- package/dist/index.test.js.map +1 -0
- package/dist/llm.d.ts +73 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +264 -0
- package/dist/llm.js.map +1 -0
- package/dist/llm.test.d.ts +2 -0
- package/dist/llm.test.d.ts.map +1 -0
- package/dist/llm.test.js +592 -0
- package/dist/llm.test.js.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +5 -3
- package/dist/logger.js.map +1 -1
- package/dist/logger.test.d.ts +2 -0
- package/dist/logger.test.d.ts.map +1 -0
- package/dist/logger.test.js +78 -0
- package/dist/logger.test.js.map +1 -0
- package/dist/prompts.d.ts +49 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +195 -0
- package/dist/prompts.js.map +1 -0
- package/dist/prompts.test.d.ts +2 -0
- package/dist/prompts.test.d.ts.map +1 -0
- package/dist/prompts.test.js +427 -0
- package/dist/prompts.test.js.map +1 -0
- package/dist/providers/gemini.d.ts +3 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +38 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +6 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +3 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +24 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/registry.d.ts +4 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +16 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +11 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/version.test.d.ts +3 -0
- package/dist/version.test.d.ts.map +1 -0
- package/dist/version.test.js +25 -0
- package/dist/version.test.js.map +1 -0
- package/package.json +14 -5
- package/src/adr.test.ts +278 -0
- package/src/adr.ts +136 -0
- package/src/analysis.test.ts +396 -0
- package/src/analysis.ts +262 -0
- package/src/commands/analyze.ts +56 -0
- package/src/commands/init.test.ts +27 -0
- package/src/commands/init.ts +99 -0
- package/src/config.test.ts +79 -0
- package/src/config.ts +214 -0
- package/src/git.ts +240 -0
- package/src/index.test.ts +59 -0
- package/src/index.ts +80 -60
- package/src/llm.test.ts +701 -0
- package/src/llm.ts +345 -0
- package/src/logger.test.ts +90 -0
- package/src/logger.ts +6 -3
- package/src/prompts.test.ts +515 -0
- package/src/prompts.ts +174 -0
- package/src/providers/gemini.ts +41 -0
- package/src/providers/index.ts +1 -0
- package/src/providers/openai.ts +22 -0
- package/src/providers/registry.ts +16 -0
- package/src/providers/types.ts +12 -0
- package/src/version.test.ts +29 -0
- package/bin/cadr.js +0 -16
package/src/git.ts
CHANGED
|
@@ -14,6 +14,15 @@ export class GitError extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Options for specifying what diff to analyze
|
|
19
|
+
*/
|
|
20
|
+
export interface DiffOptions {
|
|
21
|
+
mode: 'staged' | 'all' | 'branch-diff';
|
|
22
|
+
base?: string; // For branch-diff: base git reference (e.g., 'origin/main')
|
|
23
|
+
head?: string; // For branch-diff: head git reference (e.g., 'HEAD')
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
/**
|
|
18
27
|
* Retrieves the list of staged files in the current Git repository
|
|
19
28
|
* @returns Promise<string[]> Array of staged file paths
|
|
@@ -58,3 +67,234 @@ export async function getStagedFiles(): Promise<string[]> {
|
|
|
58
67
|
);
|
|
59
68
|
}
|
|
60
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves the full diff content for staged files
|
|
73
|
+
* Uses minimal context to reduce token usage
|
|
74
|
+
* @returns Promise<string> Full diff content of staged changes
|
|
75
|
+
* @throws GitError When Git is not available or repository is invalid
|
|
76
|
+
*/
|
|
77
|
+
export async function getStagedDiff(): Promise<string> {
|
|
78
|
+
try {
|
|
79
|
+
// Use --unified=1 for minimal context (1 line before/after instead of 3)
|
|
80
|
+
// This significantly reduces token usage while maintaining readability
|
|
81
|
+
const { stdout } = await execAsync('git diff --cached --unified=1');
|
|
82
|
+
return stdout;
|
|
83
|
+
} catch (error: unknown) {
|
|
84
|
+
// Handle different Git error scenarios (same as getStagedFiles)
|
|
85
|
+
const errorWithCode = error as { code?: number };
|
|
86
|
+
|
|
87
|
+
if (errorWithCode.code === 128) {
|
|
88
|
+
throw new GitError(
|
|
89
|
+
'Not in a Git repository. Please run \'cadr\' from within a Git repository.',
|
|
90
|
+
'NOT_GIT_REPO',
|
|
91
|
+
error instanceof Error ? error : new Error(String(error))
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (errorWithCode.code === 127) {
|
|
96
|
+
throw new GitError(
|
|
97
|
+
'Git is not installed. Please install Git and try again.',
|
|
98
|
+
'GIT_NOT_FOUND',
|
|
99
|
+
error instanceof Error ? error : new Error(String(error))
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Handle other Git errors (permissions, corruption, etc.)
|
|
104
|
+
throw new GitError(
|
|
105
|
+
'Unable to read Git repository. Please check repository permissions.',
|
|
106
|
+
'GIT_ERROR',
|
|
107
|
+
error instanceof Error ? error : new Error(String(error))
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Retrieves the list of all uncommitted files (staged + unstaged) in the current Git repository
|
|
114
|
+
* @returns Promise<string[]> Array of uncommitted file paths
|
|
115
|
+
* @throws GitError When Git is not available or repository is invalid
|
|
116
|
+
*/
|
|
117
|
+
export async function getUncommittedFiles(): Promise<string[]> {
|
|
118
|
+
try {
|
|
119
|
+
const { stdout } = await execAsync('git diff HEAD --name-only');
|
|
120
|
+
|
|
121
|
+
// Split by newlines and filter out empty strings
|
|
122
|
+
const uncommittedFiles = stdout
|
|
123
|
+
.split('\n')
|
|
124
|
+
.map(file => file.trim())
|
|
125
|
+
.filter(file => file.length > 0);
|
|
126
|
+
|
|
127
|
+
return uncommittedFiles;
|
|
128
|
+
} catch (error: unknown) {
|
|
129
|
+
// Handle different Git error scenarios
|
|
130
|
+
const errorWithCode = error as { code?: number };
|
|
131
|
+
|
|
132
|
+
if (errorWithCode.code === 128) {
|
|
133
|
+
throw new GitError(
|
|
134
|
+
'Not in a Git repository. Please run \'cadr\' from within a Git repository.',
|
|
135
|
+
'NOT_GIT_REPO',
|
|
136
|
+
error instanceof Error ? error : new Error(String(error))
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (errorWithCode.code === 127) {
|
|
141
|
+
throw new GitError(
|
|
142
|
+
'Git is not installed. Please install Git and try again.',
|
|
143
|
+
'GIT_NOT_FOUND',
|
|
144
|
+
error instanceof Error ? error : new Error(String(error))
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Handle other Git errors (permissions, corruption, etc.)
|
|
149
|
+
throw new GitError(
|
|
150
|
+
'Unable to read Git repository. Please check repository permissions.',
|
|
151
|
+
'GIT_ERROR',
|
|
152
|
+
error instanceof Error ? error : new Error(String(error))
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Retrieves the full diff content for all uncommitted files (staged + unstaged)
|
|
159
|
+
* Uses minimal context to reduce token usage
|
|
160
|
+
* @returns Promise<string> Full diff content of uncommitted changes
|
|
161
|
+
* @throws GitError When Git is not available or repository is invalid
|
|
162
|
+
*/
|
|
163
|
+
export async function getUncommittedDiff(): Promise<string> {
|
|
164
|
+
try {
|
|
165
|
+
// Use --unified=1 for minimal context (1 line before/after instead of 3)
|
|
166
|
+
// This significantly reduces token usage while maintaining readability
|
|
167
|
+
const { stdout } = await execAsync('git diff HEAD --unified=1');
|
|
168
|
+
return stdout;
|
|
169
|
+
} catch (error: unknown) {
|
|
170
|
+
// Handle different Git error scenarios (same as getUncommittedFiles)
|
|
171
|
+
const errorWithCode = error as { code?: number };
|
|
172
|
+
|
|
173
|
+
if (errorWithCode.code === 128) {
|
|
174
|
+
throw new GitError(
|
|
175
|
+
'Not in a Git repository. Please run \'cadr\' from within a Git repository.',
|
|
176
|
+
'NOT_GIT_REPO',
|
|
177
|
+
error instanceof Error ? error : new Error(String(error))
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (errorWithCode.code === 127) {
|
|
182
|
+
throw new GitError(
|
|
183
|
+
'Git is not installed. Please install Git and try again.',
|
|
184
|
+
'GIT_NOT_FOUND',
|
|
185
|
+
error instanceof Error ? error : new Error(String(error))
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Handle other Git errors (permissions, corruption, etc.)
|
|
190
|
+
throw new GitError(
|
|
191
|
+
'Unable to read Git repository. Please check repository permissions.',
|
|
192
|
+
'GIT_ERROR',
|
|
193
|
+
error instanceof Error ? error : new Error(String(error))
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Generic function to get changed files based on diff options
|
|
200
|
+
* @param options - Diff options specifying which changes to analyze
|
|
201
|
+
* @returns Promise<string[]> Array of changed file paths
|
|
202
|
+
* @throws GitError When Git is not available or repository is invalid
|
|
203
|
+
*/
|
|
204
|
+
export async function getChangedFiles(options: DiffOptions = { mode: 'all' }): Promise<string[]> {
|
|
205
|
+
switch (options.mode) {
|
|
206
|
+
case 'staged':
|
|
207
|
+
return getStagedFiles();
|
|
208
|
+
case 'all':
|
|
209
|
+
return getUncommittedFiles();
|
|
210
|
+
case 'branch-diff': {
|
|
211
|
+
const base = options.base || 'origin/main';
|
|
212
|
+
const head = options.head || 'HEAD';
|
|
213
|
+
try {
|
|
214
|
+
// Use triple-dot syntax for merge-base diff (standard in CI/CD)
|
|
215
|
+
const { stdout } = await execAsync(`git diff ${base}...${head} --name-only`);
|
|
216
|
+
|
|
217
|
+
const files = stdout
|
|
218
|
+
.split('\n')
|
|
219
|
+
.map(file => file.trim())
|
|
220
|
+
.filter(file => file.length > 0);
|
|
221
|
+
|
|
222
|
+
return files;
|
|
223
|
+
} catch (error: unknown) {
|
|
224
|
+
// Handle different Git error scenarios
|
|
225
|
+
const errorWithCode = error as { code?: number };
|
|
226
|
+
|
|
227
|
+
if (errorWithCode.code === 128) {
|
|
228
|
+
throw new GitError(
|
|
229
|
+
`Invalid git references: ${base}...${head}. Please ensure both references exist.`,
|
|
230
|
+
'GIT_ERROR',
|
|
231
|
+
error instanceof Error ? error : new Error(String(error))
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (errorWithCode.code === 127) {
|
|
236
|
+
throw new GitError(
|
|
237
|
+
'Git is not installed. Please install Git and try again.',
|
|
238
|
+
'GIT_NOT_FOUND',
|
|
239
|
+
error instanceof Error ? error : new Error(String(error))
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
throw new GitError(
|
|
244
|
+
'Unable to read Git repository. Please check repository permissions.',
|
|
245
|
+
'GIT_ERROR',
|
|
246
|
+
error instanceof Error ? error : new Error(String(error))
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Generic function to get diff content based on diff options
|
|
255
|
+
* @param options - Diff options specifying which changes to analyze
|
|
256
|
+
* @returns Promise<string> Full diff content
|
|
257
|
+
* @throws GitError When Git is not available or repository is invalid
|
|
258
|
+
*/
|
|
259
|
+
export async function getDiff(options: DiffOptions = { mode: 'all' }): Promise<string> {
|
|
260
|
+
switch (options.mode) {
|
|
261
|
+
case 'staged':
|
|
262
|
+
return getStagedDiff();
|
|
263
|
+
case 'all':
|
|
264
|
+
return getUncommittedDiff();
|
|
265
|
+
case 'branch-diff': {
|
|
266
|
+
const base = options.base || 'origin/main';
|
|
267
|
+
const head = options.head || 'HEAD';
|
|
268
|
+
try {
|
|
269
|
+
// Use triple-dot syntax for merge-base diff with minimal context
|
|
270
|
+
const { stdout } = await execAsync(`git diff ${base}...${head} --unified=1`);
|
|
271
|
+
return stdout;
|
|
272
|
+
} catch (error: unknown) {
|
|
273
|
+
// Handle different Git error scenarios
|
|
274
|
+
const errorWithCode = error as { code?: number };
|
|
275
|
+
|
|
276
|
+
if (errorWithCode.code === 128) {
|
|
277
|
+
throw new GitError(
|
|
278
|
+
`Invalid git references: ${base}...${head}. Please ensure both references exist.`,
|
|
279
|
+
'GIT_ERROR',
|
|
280
|
+
error instanceof Error ? error : new Error(String(error))
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (errorWithCode.code === 127) {
|
|
285
|
+
throw new GitError(
|
|
286
|
+
'Git is not installed. Please install Git and try again.',
|
|
287
|
+
'GIT_NOT_FOUND',
|
|
288
|
+
error instanceof Error ? error : new Error(String(error))
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
throw new GitError(
|
|
293
|
+
'Unable to read Git repository. Please check repository permissions.',
|
|
294
|
+
'GIT_ERROR',
|
|
295
|
+
error instanceof Error ? error : new Error(String(error))
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { showHelp, showVersion } from './index';
|
|
2
|
+
|
|
3
|
+
describe('CLI Help', () => {
|
|
4
|
+
let stdoutSpy: jest.SpyInstance;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
stdoutSpy.mockRestore();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('showHelp displays product name', () => {
|
|
15
|
+
showHelp();
|
|
16
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining('cADR'));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('showHelp displays available commands', () => {
|
|
20
|
+
showHelp();
|
|
21
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
22
|
+
expect(output).toContain('init');
|
|
23
|
+
expect(output).toContain('analyze');
|
|
24
|
+
expect(output).toContain('help');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('showHelp displays usage examples', () => {
|
|
28
|
+
showHelp();
|
|
29
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
30
|
+
expect(output).toContain('USAGE');
|
|
31
|
+
expect(output).toContain('COMMANDS');
|
|
32
|
+
expect(output).toContain('OPTIONS');
|
|
33
|
+
expect(output).toContain('EXAMPLES');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('showHelp displays version info', () => {
|
|
37
|
+
showHelp();
|
|
38
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
39
|
+
expect(output).toContain('0.0.1');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('CLI Version', () => {
|
|
44
|
+
let stdoutSpy: jest.SpyInstance;
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
afterEach(() => {
|
|
51
|
+
stdoutSpy.mockRestore();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('showVersion displays version information', () => {
|
|
55
|
+
showVersion();
|
|
56
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining('cADR version'));
|
|
57
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining('0.0.1'));
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,80 +1,100 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { initCommand } from './commands/init';
|
|
2
|
+
import { analyzeCommand } from './commands/analyze';
|
|
3
3
|
|
|
4
4
|
// Version constants
|
|
5
5
|
const CORE_VERSION = '0.0.1';
|
|
6
6
|
const CLI_VERSION = '0.0.1';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
8
|
+
export function showHelp(): void {
|
|
9
|
+
const help = `
|
|
10
|
+
cADR - Continuous Architectural Decision Records
|
|
11
|
+
Version: ${CLI_VERSION}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
USAGE
|
|
14
|
+
cadr [command] [options]
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
COMMANDS
|
|
17
|
+
init Create a cadr.yaml configuration file
|
|
18
|
+
analyze Analyze code changes and generate ADRs (default)
|
|
19
|
+
help Show this help message
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
ANALYZE OPTIONS
|
|
22
|
+
--all Analyze all uncommitted changes (staged + unstaged) [default]
|
|
23
|
+
--staged Analyze only staged changes
|
|
24
|
+
--base <ref> Base git reference for CI/CD (e.g., origin/main)
|
|
25
|
+
--head <ref> Head git reference for CI/CD (default: HEAD)
|
|
26
|
+
|
|
27
|
+
GLOBAL OPTIONS
|
|
28
|
+
-h, --help Show help message
|
|
29
|
+
-v, --version Show version information
|
|
30
|
+
--verbose Enable verbose logging
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
EXAMPLES
|
|
33
|
+
# Local development
|
|
34
|
+
cadr # Analyze all uncommitted files (default)
|
|
35
|
+
cadr analyze # Analyze all uncommitted files
|
|
36
|
+
cadr analyze --staged # Analyze only staged files
|
|
37
|
+
cadr analyze --all # Analyze all uncommitted files (explicit)
|
|
38
|
+
|
|
39
|
+
# CI/CD (Pull Requests)
|
|
40
|
+
cadr analyze --base origin/main # Compare current HEAD to main
|
|
41
|
+
cadr analyze --base origin/main --head feature-branch
|
|
42
|
+
cadr analyze --base HEAD~1 # Compare to previous commit
|
|
43
|
+
|
|
44
|
+
# Other commands
|
|
45
|
+
cadr init # Initialize configuration
|
|
46
|
+
cadr --verbose analyze # Analyze with debug logs
|
|
47
|
+
|
|
48
|
+
LEARN MORE
|
|
49
|
+
GitHub: https://github.com/YotpoLtd/cADR
|
|
50
|
+
Docs: https://github.com/YotpoLtd/cADR#readme
|
|
23
51
|
`;
|
|
52
|
+
process.stdout.write(help);
|
|
24
53
|
}
|
|
25
54
|
|
|
26
|
-
export function
|
|
27
|
-
|
|
28
|
-
process.stdout.write(getWelcomeMessage());
|
|
55
|
+
export function showVersion(): void {
|
|
56
|
+
process.stdout.write(`cADR version ${CLI_VERSION} (core: ${CORE_VERSION})\n`);
|
|
29
57
|
}
|
|
30
58
|
|
|
31
|
-
export async function processStagedFiles(): Promise<void> {
|
|
32
|
-
try {
|
|
33
|
-
const stagedFiles = await getStagedFiles();
|
|
34
|
-
|
|
35
|
-
// Display staged files to user
|
|
36
|
-
if (stagedFiles.length > 0) {
|
|
37
|
-
process.stdout.write(`\nš Found ${stagedFiles.length} staged file${stagedFiles.length === 1 ? '' : 's'}:\n`);
|
|
38
|
-
stagedFiles.forEach((file: string) => {
|
|
39
|
-
process.stdout.write(` ⢠${file}\n`);
|
|
40
|
-
});
|
|
41
|
-
} else {
|
|
42
|
-
process.stdout.write(`\nš No staged files found.\n`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Only log for debugging when verbose mode is enabled
|
|
46
|
-
if (isVerbose) {
|
|
47
|
-
loggerInstance.info('Retrieved staged files', {
|
|
48
|
-
staged_files: stagedFiles,
|
|
49
|
-
count: stagedFiles.length
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
} catch (error: unknown) {
|
|
53
|
-
if (error instanceof GitError) {
|
|
54
|
-
// Display helpful error message to stdout
|
|
55
|
-
process.stdout.write(`\nā ${error.message}\n`);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
} else {
|
|
58
|
-
// Log unexpected errors (always show errors)
|
|
59
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
60
|
-
loggerInstance.error('Unexpected error occurred', {
|
|
61
|
-
error: errorMessage
|
|
62
|
-
});
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
59
|
|
|
68
60
|
// Main execution block - run when module is executed directly
|
|
69
61
|
if (require.main === module) {
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
const args = process.argv.slice(2);
|
|
63
|
+
const command = args[0];
|
|
72
64
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
// Handle commands
|
|
66
|
+
(async () => {
|
|
67
|
+
// Help flags
|
|
68
|
+
if (!command || command === 'help' || args.includes('--help') || args.includes('-h')) {
|
|
69
|
+
showHelp();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Version flag
|
|
74
|
+
if (args.includes('--version')) {
|
|
75
|
+
showVersion();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Commands
|
|
80
|
+
switch (command) {
|
|
81
|
+
case 'init':
|
|
82
|
+
await initCommand();
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case 'analyze':
|
|
86
|
+
await analyzeCommand(args);
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
default:
|
|
90
|
+
// Unknown command - show error and help
|
|
91
|
+
process.stdout.write(`\nā Unknown command: ${command}\n`);
|
|
92
|
+
showHelp();
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
})().catch((error) => {
|
|
96
|
+
// eslint-disable-next-line no-console
|
|
97
|
+
console.error('Error:', error.message || error);
|
|
78
98
|
process.exit(1);
|
|
79
99
|
});
|
|
80
|
-
}
|
|
100
|
+
}
|