@rahul05ranjan/dhruv-cli 1.8.1 → 1.8.2
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 +2 -2
- package/__tests__/file-workflows.test.ts +56 -0
- package/dist/commands/generate.js +1 -0
- package/dist/commands/optimize.js +3 -0
- package/dist/commands/review.js +3 -1
- package/dist/commands/security-check.js +3 -1
- package/package.json +1 -1
- package/src/commands/generate.ts +1 -0
- package/src/commands/optimize.ts +3 -0
- package/src/commands/review.ts +4 -1
- package/src/commands/security-check.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# [1.4.0](https://github.com/rahul05ranjan/dhruv-cli/compare/v1.8.
|
|
1
|
+
# [1.4.0](https://github.com/rahul05ranjan/dhruv-cli/compare/v1.8.1...v1.4.0) (2026-09-22)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
* **
|
|
6
|
+
* **cli:** exit with code 1 on missing or unreadable input (closes [#94](https://github.com/rahul05ranjan/dhruv-cli/issues/94)) ([90c19fa](https://github.com/rahul05ranjan/dhruv-cli/commit/90c19fa926f1ef781c4137dc1713626854b2ca08))
|
|
7
7
|
# Changelog
|
|
8
8
|
|
|
9
9
|
## [1.1.1](https://github.com/rahul05ranjan/dhruv-cli/compare/v1.1.0...v1.1.1) (2025-06-29)
|
|
@@ -231,4 +231,60 @@ describe('file analysis commands', () => {
|
|
|
231
231
|
expect(client.requests[0].prompt).toContain('expected impact');
|
|
232
232
|
expect(client.requests[0].prompt).toContain('trade-offs');
|
|
233
233
|
});
|
|
234
|
+
|
|
235
|
+
it('exits with code 1 and skips AI call when review target does not exist', async () => {
|
|
236
|
+
process.exitCode = 0;
|
|
237
|
+
const nonExistent = path.join(root, 'nonexistent.ts');
|
|
238
|
+
|
|
239
|
+
await review(nonExistent);
|
|
240
|
+
|
|
241
|
+
expect(process.exitCode).toBe(1);
|
|
242
|
+
expect(client.requests).toHaveLength(0);
|
|
243
|
+
process.exitCode = 0;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('exits with code 1 and skips AI call when review --diff has no uncommitted changes', async () => {
|
|
247
|
+
process.exitCode = 0;
|
|
248
|
+
const { execFileSync } = await import('child_process');
|
|
249
|
+
execFileSync('git', ['init'], { cwd: root });
|
|
250
|
+
|
|
251
|
+
await review(root, { diff: true });
|
|
252
|
+
|
|
253
|
+
expect(process.exitCode).toBe(1);
|
|
254
|
+
expect(client.requests).toHaveLength(0);
|
|
255
|
+
process.exitCode = 0;
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('exits with code 1 and skips AI call when security-check target does not exist', async () => {
|
|
259
|
+
process.exitCode = 0;
|
|
260
|
+
const nonExistent = path.join(root, 'nonexistent.ts');
|
|
261
|
+
|
|
262
|
+
await securityCheck(nonExistent);
|
|
263
|
+
|
|
264
|
+
expect(process.exitCode).toBe(1);
|
|
265
|
+
expect(client.requests).toHaveLength(0);
|
|
266
|
+
process.exitCode = 0;
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('exits with code 1 and skips AI call when generate target does not exist', async () => {
|
|
270
|
+
process.exitCode = 0;
|
|
271
|
+
const nonExistent = path.join(root, 'nonexistent.ts');
|
|
272
|
+
|
|
273
|
+
await generate('tests', nonExistent);
|
|
274
|
+
|
|
275
|
+
expect(process.exitCode).toBe(1);
|
|
276
|
+
expect(client.requests).toHaveLength(0);
|
|
277
|
+
process.exitCode = 0;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('exits with code 1 and skips AI call when optimize target does not exist', async () => {
|
|
281
|
+
process.exitCode = 0;
|
|
282
|
+
const nonExistent = path.join(root, 'nonexistent.ts');
|
|
283
|
+
|
|
284
|
+
await optimize(nonExistent);
|
|
285
|
+
|
|
286
|
+
expect(process.exitCode).toBe(1);
|
|
287
|
+
expect(client.requests).toHaveLength(0);
|
|
288
|
+
process.exitCode = 0;
|
|
289
|
+
});
|
|
234
290
|
});
|
|
@@ -45,6 +45,7 @@ function extractTestCode(response) {
|
|
|
45
45
|
export async function generate(type, target, options = {}) {
|
|
46
46
|
if (!fs.existsSync(target)) {
|
|
47
47
|
printError(`Target file "${target}" does not exist.`);
|
|
48
|
+
process.exitCode = 1;
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
const content = fs.readFileSync(target, 'utf-8');
|
|
@@ -21,10 +21,12 @@ function optimizationType(file) {
|
|
|
21
21
|
export async function optimize(file) {
|
|
22
22
|
if (!file || file.trim().length === 0) {
|
|
23
23
|
printError('Please provide a file path to optimize.');
|
|
24
|
+
process.exitCode = 1;
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
27
|
if (!fs.existsSync(file)) {
|
|
27
28
|
printError(`File "${file}" does not exist.`);
|
|
29
|
+
process.exitCode = 1;
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
let content;
|
|
@@ -33,6 +35,7 @@ export async function optimize(file) {
|
|
|
33
35
|
}
|
|
34
36
|
catch (err) {
|
|
35
37
|
printError(`Error reading file "${file}": ${err.message}`);
|
|
38
|
+
process.exitCode = 1;
|
|
36
39
|
return;
|
|
37
40
|
}
|
|
38
41
|
const type = optimizationType(file);
|
package/dist/commands/review.js
CHANGED
|
@@ -96,8 +96,10 @@ function readGitDiff(fileOrDir) {
|
|
|
96
96
|
}
|
|
97
97
|
export async function review(fileOrDir, options = {}) {
|
|
98
98
|
const code = options.diff ? readGitDiff(fileOrDir) : readCode(fileOrDir);
|
|
99
|
-
if (code === undefined)
|
|
99
|
+
if (code === undefined) {
|
|
100
|
+
process.exitCode = 1;
|
|
100
101
|
return;
|
|
102
|
+
}
|
|
101
103
|
const projectRoot = fs.existsSync(fileOrDir) && fs.statSync(fileOrDir).isDirectory() ? fileOrDir : path.dirname(fileOrDir);
|
|
102
104
|
const projectType = detectProjectType(projectRoot);
|
|
103
105
|
const scope = options.diff ? 'the current uncommitted git diff' : 'the supplied source files';
|
|
@@ -128,8 +128,10 @@ function readDirectory(dir) {
|
|
|
128
128
|
}
|
|
129
129
|
export async function securityCheck(fileOrDir = '.', options = {}) {
|
|
130
130
|
const code = readCode(fileOrDir);
|
|
131
|
-
if (code === undefined)
|
|
131
|
+
if (code === undefined) {
|
|
132
|
+
process.exitCode = 1;
|
|
132
133
|
return;
|
|
134
|
+
}
|
|
133
135
|
const findings = findHighConfidenceFindings(code);
|
|
134
136
|
const safeCode = redactSensitiveContent(code);
|
|
135
137
|
const findingSummary = findings.length === 0
|
package/package.json
CHANGED
package/src/commands/generate.ts
CHANGED
|
@@ -54,6 +54,7 @@ export interface GenerateOptions {
|
|
|
54
54
|
export async function generate(type: string, target: string, options: GenerateOptions = {}) {
|
|
55
55
|
if (!fs.existsSync(target)) {
|
|
56
56
|
printError(`Target file "${target}" does not exist.`);
|
|
57
|
+
process.exitCode = 1;
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
|
package/src/commands/optimize.ts
CHANGED
|
@@ -18,10 +18,12 @@ function optimizationType(file: string): string {
|
|
|
18
18
|
export async function optimize(file: string) {
|
|
19
19
|
if (!file || file.trim().length === 0) {
|
|
20
20
|
printError('Please provide a file path to optimize.');
|
|
21
|
+
process.exitCode = 1;
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
if (!fs.existsSync(file)) {
|
|
24
25
|
printError(`File "${file}" does not exist.`);
|
|
26
|
+
process.exitCode = 1;
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -30,6 +32,7 @@ export async function optimize(file: string) {
|
|
|
30
32
|
content = fs.readFileSync(file, 'utf-8');
|
|
31
33
|
} catch (err) {
|
|
32
34
|
printError(`Error reading file "${file}": ${(err as Error).message}`);
|
|
35
|
+
process.exitCode = 1;
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
|
package/src/commands/review.ts
CHANGED
|
@@ -105,7 +105,10 @@ export interface ReviewOptions {
|
|
|
105
105
|
|
|
106
106
|
export async function review(fileOrDir: string, options: ReviewOptions = {}) {
|
|
107
107
|
const code = options.diff ? readGitDiff(fileOrDir) : readCode(fileOrDir);
|
|
108
|
-
if (code === undefined)
|
|
108
|
+
if (code === undefined) {
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
109
112
|
const projectRoot = fs.existsSync(fileOrDir) && fs.statSync(fileOrDir).isDirectory() ? fileOrDir : path.dirname(fileOrDir);
|
|
110
113
|
const projectType = detectProjectType(projectRoot);
|
|
111
114
|
const scope = options.diff ? 'the current uncommitted git diff' : 'the supplied source files';
|
|
@@ -141,7 +141,10 @@ function readDirectory(dir: string): string | undefined {
|
|
|
141
141
|
|
|
142
142
|
export async function securityCheck(fileOrDir: string = '.', options: SecurityCheckOptions = {}) {
|
|
143
143
|
const code = readCode(fileOrDir);
|
|
144
|
-
if (code === undefined)
|
|
144
|
+
if (code === undefined) {
|
|
145
|
+
process.exitCode = 1;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
145
148
|
const findings = findHighConfidenceFindings(code);
|
|
146
149
|
const safeCode = redactSensitiveContent(code);
|
|
147
150
|
const findingSummary = findings.length === 0
|