@rahul05ranjan/dhruv-cli 1.4.6 → 1.5.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/.github/workflows/ci.yml +18 -238
- package/.github/workflows/contribution.yml +6 -141
- package/.github/workflows/dependabot-auto-merge.yml +1 -0
- package/.github/workflows/labeler.yml +1 -0
- package/.github/workflows/security.yml +3 -0
- package/CHANGELOG.md +9 -4
- package/README.md +145 -40
- package/__tests__/cli-contract.test.ts +104 -0
- package/__tests__/core.test.ts +121 -0
- package/__tests__/diagnostics.test.ts +155 -0
- package/__tests__/file-workflows.test.ts +195 -0
- package/__tests__/interactive.test.ts +119 -0
- package/__tests__/setup.ts +1 -0
- package/__tests__/workflows.test.ts +27 -4
- package/dist/commands/generate.d.ts +6 -1
- package/dist/commands/generate.js +18 -4
- package/dist/commands/health.d.ts +4 -1
- package/dist/commands/health.js +59 -16
- package/dist/commands/init.js +11 -2
- package/dist/commands/menu.js +125 -100
- package/dist/commands/metrics.d.ts +5 -1
- package/dist/commands/metrics.js +37 -8
- package/dist/commands/optimize.js +1 -1
- package/dist/commands/review.d.ts +4 -1
- package/dist/commands/review.js +48 -8
- package/dist/commands/security-check.d.ts +4 -1
- package/dist/commands/security-check.js +67 -6
- package/dist/commands/status.js +40 -2
- package/dist/config/config.d.ts +5 -1
- package/dist/config/config.js +24 -7
- package/dist/core/ai.d.ts +11 -0
- package/dist/core/ai.js +33 -9
- package/dist/core/command-catalog.d.ts +10 -0
- package/dist/core/command-catalog.js +27 -0
- package/dist/core/command-runner.js +100 -21
- package/dist/core/logger.js +1 -0
- package/dist/core/metrics.d.ts +28 -0
- package/dist/core/metrics.js +78 -0
- package/dist/index.js +46 -24
- package/dist/utils/projectType.d.ts +1 -1
- package/dist/utils/projectType.js +26 -7
- package/docs/api/assets/highlight.css +4 -4
- package/docs/api/index.html +161 -39
- package/docs/api/media/CONTRIBUTING.md +60 -0
- package/docs/api/media/SECURITY.md +8 -0
- package/docs/api/media/dhruv-cli-preview.svg +42 -0
- package/docs/api/media/publishing-fix.md +34 -0
- package/docs/dhruv-cli-preview.svg +42 -0
- package/docs/index.html +631 -533
- package/docs/publishing-fix.md +34 -0
- package/package.json +1 -1
- package/src/commands/generate.ts +23 -4
- package/src/commands/health.ts +62 -17
- package/src/commands/init.ts +11 -2
- package/src/commands/menu.ts +54 -30
- package/src/commands/metrics.ts +42 -7
- package/src/commands/optimize.ts +1 -1
- package/src/commands/review.ts +53 -8
- package/src/commands/security-check.ts +80 -6
- package/src/commands/status.ts +39 -3
- package/src/config/config.ts +26 -7
- package/src/core/ai.ts +36 -8
- package/src/core/command-catalog.ts +37 -0
- package/src/core/command-runner.ts +102 -22
- package/src/core/logger.ts +1 -0
- package/src/core/metrics.ts +103 -0
- package/src/index.ts +45 -24
- package/src/utils/projectType.ts +22 -7
- package/tsconfig.json +1 -1
- package/.github/workflows/auto-assign.yml +0 -14
- package/.github/workflows/build-publish.yml +0 -154
- package/.github/workflows/deploy.yml +0 -336
- package/.github/workflows/monitoring.yml +0 -270
- package/PUBLISHING_FIX.md +0 -92
- package/logs/.8a99b6cf655346317fdbf29f4fffcf91131432f3-audit.json +0 -15
- package/logs/.eee104bf8fff5ecd38a6a2842df260de6470a7c3-audit.json +0 -15
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { createRequire } from 'module';
|
|
|
20
20
|
import { logger, logCommand, logInfo, logError } from './core/logger.js';
|
|
21
21
|
import { metricsCollector } from './core/metrics.js';
|
|
22
22
|
import { securityManager } from './core/security.js';
|
|
23
|
+
import { commandDescription, completionCommands, completionOptions } from './core/command-catalog.js';
|
|
23
24
|
const require = createRequire(import.meta.url);
|
|
24
25
|
const pkg = require('../package.json');
|
|
25
26
|
|
|
@@ -32,65 +33,73 @@ program
|
|
|
32
33
|
|
|
33
34
|
program
|
|
34
35
|
.command('explain <query>')
|
|
35
|
-
.description('
|
|
36
|
+
.description(commandDescription('explain'))
|
|
36
37
|
.addHelpText('after', '\nExamples:\n $ dhruv explain "What is async/await?"\n $ dhruv explain "Docker containers vs VMs"')
|
|
37
38
|
.action(explain);
|
|
38
39
|
|
|
39
40
|
program
|
|
40
41
|
.command('suggest <query>')
|
|
41
|
-
.description('
|
|
42
|
+
.description(commandDescription('suggest'))
|
|
42
43
|
.addHelpText('after', '\nExamples:\n $ dhruv suggest "React performance optimization"\n $ dhruv suggest "Node.js project structure"')
|
|
43
44
|
.action(suggest);
|
|
44
45
|
|
|
45
46
|
program
|
|
46
47
|
.command('fix <query>')
|
|
47
|
-
.description('
|
|
48
|
+
.description(commandDescription('fix'))
|
|
48
49
|
.addHelpText('after', '\nExamples:\n $ dhruv fix "TypeError: Cannot read property of undefined"\n $ dhruv fix "CORS error in Express.js"')
|
|
49
50
|
.action(fix);
|
|
50
51
|
|
|
51
52
|
program
|
|
52
53
|
.command('review <fileOrDir>')
|
|
53
|
-
.description('
|
|
54
|
-
.
|
|
54
|
+
.description(commandDescription('review'))
|
|
55
|
+
.option('--diff', 'Review the current uncommitted git diff')
|
|
56
|
+
.action((fileOrDir: string, command: Command) => review(fileOrDir, command.opts()));
|
|
55
57
|
|
|
56
58
|
program
|
|
57
59
|
.command('optimize <file>')
|
|
58
|
-
.description(
|
|
60
|
+
.description(commandDescription('optimize'))
|
|
59
61
|
.action(optimize);
|
|
60
62
|
|
|
61
63
|
program
|
|
62
64
|
.command('security-check [fileOrDir]')
|
|
63
|
-
.description('
|
|
64
|
-
.
|
|
65
|
+
.description(commandDescription('security-check'))
|
|
66
|
+
.option('--strict', 'Exit with failure when high-confidence findings are detected')
|
|
67
|
+
.action((fileOrDir: string | undefined, command: Command) => securityCheck(fileOrDir, command.opts()));
|
|
65
68
|
|
|
66
69
|
program
|
|
67
70
|
.command('generate <type> <target>')
|
|
68
|
-
.description('
|
|
69
|
-
.
|
|
71
|
+
.description(commandDescription('generate'))
|
|
72
|
+
.option('--apply', 'Write generated tests to disk (preview is the default)')
|
|
73
|
+
.option('--output <path>', 'Write generated tests to this path')
|
|
74
|
+
.option('--overwrite', 'Allow replacing an existing output file')
|
|
75
|
+
.action((type: string, target: string, command: Command) => generate(type, target, command.opts()));
|
|
70
76
|
|
|
71
77
|
program
|
|
72
78
|
.command('init')
|
|
73
|
-
.description('
|
|
79
|
+
.description(commandDescription('init'))
|
|
74
80
|
.action(init);
|
|
75
81
|
|
|
76
82
|
program
|
|
77
83
|
.command('status')
|
|
78
|
-
.description('
|
|
84
|
+
.description(commandDescription('status'))
|
|
79
85
|
.action(status);
|
|
80
86
|
|
|
81
87
|
program
|
|
82
88
|
.command('health')
|
|
83
|
-
.description('
|
|
84
|
-
.
|
|
89
|
+
.description(commandDescription('health'))
|
|
90
|
+
.option('--details', 'Show every health check and diagnostic detail')
|
|
91
|
+
.action((command: Command) => health(command.opts()));
|
|
85
92
|
|
|
86
93
|
program
|
|
87
94
|
.command('metrics')
|
|
88
|
-
.description('
|
|
89
|
-
.
|
|
95
|
+
.description(commandDescription('metrics'))
|
|
96
|
+
.option('--raw', 'Export raw Prometheus metrics')
|
|
97
|
+
.option('--reset', 'Clear persisted local metrics')
|
|
98
|
+
.action((command: Command) => metrics(command.opts()));
|
|
90
99
|
|
|
91
100
|
program
|
|
92
101
|
.command('project-type')
|
|
93
|
-
.description('
|
|
102
|
+
.description(commandDescription('project-type'))
|
|
94
103
|
.action(() => {
|
|
95
104
|
const type = detectProjectType();
|
|
96
105
|
console.log(chalk.blue(`Detected project type: ${type}`));
|
|
@@ -98,20 +107,22 @@ program
|
|
|
98
107
|
|
|
99
108
|
program
|
|
100
109
|
.command('menu')
|
|
101
|
-
.description('
|
|
110
|
+
.description(commandDescription('menu'))
|
|
102
111
|
.action(menu);
|
|
103
112
|
|
|
104
113
|
program
|
|
105
114
|
.option('--model <model>', 'Set Ollama model')
|
|
106
115
|
.option('--verbose', 'Enable verbose output')
|
|
107
116
|
.option('--json', 'Output in JSON format')
|
|
117
|
+
.option('--timeout <milliseconds>', 'Set the AI request timeout')
|
|
108
118
|
.hook('preAction', async (thisCommand) => {
|
|
109
119
|
const opts = thisCommand.opts();
|
|
110
|
-
if (opts.model || opts.verbose || opts.json) {
|
|
120
|
+
if (opts.model || opts.verbose || opts.json || opts.timeout) {
|
|
111
121
|
const config: Record<string, unknown> = {};
|
|
112
122
|
if (opts.model) config.model = opts.model;
|
|
113
123
|
if (opts.verbose) config.verbose = true;
|
|
114
124
|
if (opts.json) config.responseFormat = 'json';
|
|
125
|
+
if (opts.timeout) config.timeoutMs = Number(opts.timeout);
|
|
115
126
|
// Save config for session
|
|
116
127
|
const configModule = await import('./config/config.js');
|
|
117
128
|
configModule.saveConfig(config);
|
|
@@ -165,23 +176,33 @@ async function loadPlugins(program: unknown) {
|
|
|
165
176
|
// Autocomplete: Generate shell completion scripts
|
|
166
177
|
program
|
|
167
178
|
.command('completion')
|
|
168
|
-
.description('
|
|
179
|
+
.description(commandDescription('completion'))
|
|
169
180
|
.argument('[shell]', 'shell type (bash|zsh|fish)', 'bash')
|
|
170
181
|
.action((shell: string) => {
|
|
182
|
+
const commands = completionCommands();
|
|
183
|
+
const options = completionOptions();
|
|
171
184
|
let script = '';
|
|
172
185
|
switch (shell) {
|
|
173
186
|
case 'zsh':
|
|
174
|
-
script = `#compdef dhruv\n_dhruv_completion() {\n
|
|
187
|
+
script = `#compdef dhruv\n_dhruv_completion() {\n _arguments '1:command:(${commands})' '*:option:(${options})'\n}\ncompdef _dhruv_completion dhruv`;
|
|
175
188
|
break;
|
|
176
189
|
case 'fish':
|
|
177
|
-
script = `
|
|
190
|
+
script = `complete -c dhruv -f -n '__fish_use_subcommand' -a '${commands}'\ncomplete -c dhruv -f -n 'not __fish_use_subcommand' -a '${options}'`;
|
|
178
191
|
break;
|
|
179
|
-
|
|
192
|
+
case 'bash':
|
|
180
193
|
script = String.raw`#!/bin/bash
|
|
181
194
|
_dhruv_completion() {
|
|
182
|
-
|
|
195
|
+
local commands="${commands}"
|
|
196
|
+
local options="${options}"
|
|
197
|
+
local choices="$commands $options"
|
|
198
|
+
COMPREPLY=( $(compgen -W "$choices" -- "\${COMP_WORDS[COMP_CWORD]}") )
|
|
183
199
|
}
|
|
184
200
|
complete -F _dhruv_completion dhruv`;
|
|
201
|
+
break;
|
|
202
|
+
default:
|
|
203
|
+
console.error(chalk.red(`Unsupported shell "${shell}". Choose bash, zsh, or fish.`));
|
|
204
|
+
process.exitCode = 2;
|
|
205
|
+
return;
|
|
185
206
|
}
|
|
186
207
|
console.log(script);
|
|
187
208
|
console.log(`\n# To enable tab completion, add the above to your shell profile or source it directly.`);
|
package/src/utils/projectType.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
// Use .js extension for ESM compatibility
|
|
2
2
|
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
|
|
4
|
-
export function detectProjectType(): string {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export function detectProjectType(directory: string = process.cwd()): string {
|
|
6
|
+
const file = (name: string) => path.join(directory, name);
|
|
7
|
+
|
|
8
|
+
if (fs.existsSync(file('package.json'))) {
|
|
9
|
+
let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };
|
|
10
|
+
try {
|
|
11
|
+
pkg = JSON.parse(fs.readFileSync(file('package.json'), 'utf-8'));
|
|
12
|
+
} catch {
|
|
13
|
+
return 'unknown';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const dependencies = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17
|
+
if (dependencies.react) return 'react';
|
|
18
|
+
if (dependencies.next) return 'nextjs';
|
|
19
|
+
if (dependencies.express) return 'node-express';
|
|
20
|
+
if (dependencies.typescript || fs.existsSync(file('tsconfig.json'))) return 'node-typescript';
|
|
9
21
|
return 'node';
|
|
10
22
|
}
|
|
11
|
-
if (fs.existsSync('requirements.txt')) return 'python';
|
|
12
|
-
if (fs.existsSync('pyproject.toml')) return 'python';
|
|
23
|
+
if (fs.existsSync(file('requirements.txt'))) return 'python';
|
|
24
|
+
if (fs.existsSync(file('pyproject.toml'))) return 'python';
|
|
25
|
+
if (fs.existsSync(file('go.mod'))) return 'go';
|
|
26
|
+
if (fs.existsSync(file('Cargo.toml'))) return 'rust';
|
|
27
|
+
if (fs.existsSync(file('pom.xml')) || fs.existsSync(file('build.gradle'))) return 'java';
|
|
13
28
|
return 'unknown';
|
|
14
29
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
name: Auto Assign
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
types: [opened, reopened]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
add-assignees:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- uses: kentaro-m/auto-assign-action@v1.2.4
|
|
12
|
-
with:
|
|
13
|
-
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
14
|
-
configuration-path: .github/auto_assign.yml
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
name: Build & Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
# Automatic main releases are owned by release.yml.
|
|
5
|
-
workflow_dispatch:
|
|
6
|
-
inputs:
|
|
7
|
-
version_type:
|
|
8
|
-
description: 'Version bump type'
|
|
9
|
-
required: true
|
|
10
|
-
default: 'patch'
|
|
11
|
-
type: choice
|
|
12
|
-
options:
|
|
13
|
-
- patch
|
|
14
|
-
- minor
|
|
15
|
-
- major
|
|
16
|
-
- prerelease
|
|
17
|
-
|
|
18
|
-
permissions:
|
|
19
|
-
contents: write
|
|
20
|
-
packages: write
|
|
21
|
-
id-token: write
|
|
22
|
-
|
|
23
|
-
jobs:
|
|
24
|
-
build-and-publish:
|
|
25
|
-
name: Build and Publish
|
|
26
|
-
runs-on: ubuntu-latest
|
|
27
|
-
timeout-minutes: 20
|
|
28
|
-
environment: npm-publish
|
|
29
|
-
steps:
|
|
30
|
-
- name: Harden Runner
|
|
31
|
-
uses: step-security/harden-runner@v2
|
|
32
|
-
with:
|
|
33
|
-
egress-policy: audit
|
|
34
|
-
|
|
35
|
-
- uses: actions/checkout@v4
|
|
36
|
-
with:
|
|
37
|
-
fetch-depth: 0
|
|
38
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
39
|
-
|
|
40
|
-
- name: Set up Node.js
|
|
41
|
-
uses: actions/setup-node@v4
|
|
42
|
-
with:
|
|
43
|
-
node-version: '22.14.0'
|
|
44
|
-
cache: 'npm'
|
|
45
|
-
registry-url: 'https://registry.npmjs.org'
|
|
46
|
-
|
|
47
|
-
- name: Install npm with trusted publishing support
|
|
48
|
-
run: npm install --global npm@11.17.0
|
|
49
|
-
|
|
50
|
-
- name: Install dependencies
|
|
51
|
-
run: npm ci --prefer-offline --no-audit
|
|
52
|
-
|
|
53
|
-
- name: Run tests
|
|
54
|
-
run: npm run test:ci
|
|
55
|
-
|
|
56
|
-
- name: Run linting
|
|
57
|
-
run: npm run lint
|
|
58
|
-
|
|
59
|
-
- name: Build project
|
|
60
|
-
run: npm run build
|
|
61
|
-
|
|
62
|
-
- name: Generate documentation
|
|
63
|
-
run: npm run docs
|
|
64
|
-
|
|
65
|
-
- name: Configure Git
|
|
66
|
-
run: |
|
|
67
|
-
git config --global user.name "GitHub Actions"
|
|
68
|
-
git config --global user.email "actions@github.com"
|
|
69
|
-
|
|
70
|
-
- name: Check if version needs update
|
|
71
|
-
id: check_version
|
|
72
|
-
run: |
|
|
73
|
-
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
74
|
-
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
75
|
-
|
|
76
|
-
# Check if this version exists on NPM
|
|
77
|
-
if npm view @rahul05ranjan/dhruv-cli@$CURRENT_VERSION version 2>/dev/null; then
|
|
78
|
-
echo "needs_version_bump=true" >> $GITHUB_OUTPUT
|
|
79
|
-
echo "Version $CURRENT_VERSION already exists on NPM, needs bump"
|
|
80
|
-
else
|
|
81
|
-
echo "needs_version_bump=false" >> $GITHUB_OUTPUT
|
|
82
|
-
echo "Version $CURRENT_VERSION is new, can publish"
|
|
83
|
-
fi
|
|
84
|
-
|
|
85
|
-
- name: Manual version bump
|
|
86
|
-
if: github.event_name == 'workflow_dispatch'
|
|
87
|
-
run: |
|
|
88
|
-
npm version ${{ github.event.inputs.version_type }} --no-git-tag-version
|
|
89
|
-
git add package.json package-lock.json
|
|
90
|
-
git commit -m "chore: bump version to $(node -p "require('./package.json').version") [skip ci]"
|
|
91
|
-
git push
|
|
92
|
-
|
|
93
|
-
- name: Get final version
|
|
94
|
-
id: final_version
|
|
95
|
-
run: |
|
|
96
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
97
|
-
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
98
|
-
echo "Final version to publish: $VERSION"
|
|
99
|
-
|
|
100
|
-
- name: Create Git tag
|
|
101
|
-
run: |
|
|
102
|
-
TAG="v${{ steps.final_version.outputs.version }}"
|
|
103
|
-
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
104
|
-
echo "Tag $TAG already exists, skipping tag creation"
|
|
105
|
-
else
|
|
106
|
-
git tag "$TAG"
|
|
107
|
-
git push origin "$TAG"
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
- name: Publish to NPM
|
|
111
|
-
# npm 11.5.1+ uses the workflow's OIDC identity without a stored token.
|
|
112
|
-
run: |
|
|
113
|
-
echo "Publishing version ${{ steps.final_version.outputs.version }}"
|
|
114
|
-
npm publish --access public --tag latest --provenance
|
|
115
|
-
|
|
116
|
-
- name: Create GitHub Release
|
|
117
|
-
uses: softprops/action-gh-release@v2
|
|
118
|
-
with:
|
|
119
|
-
tag_name: v${{ steps.final_version.outputs.version }}
|
|
120
|
-
name: Release v${{ steps.final_version.outputs.version }}
|
|
121
|
-
body: |
|
|
122
|
-
## What's Changed
|
|
123
|
-
|
|
124
|
-
Version ${{ steps.final_version.outputs.version }} of dhruv-cli
|
|
125
|
-
|
|
126
|
-
### Installation
|
|
127
|
-
```bash
|
|
128
|
-
npm install -g @rahul05ranjan/dhruv-cli@${{ steps.final_version.outputs.version }}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ steps.check_version.outputs.current_version }}...v${{ steps.final_version.outputs.version }}
|
|
132
|
-
files: |
|
|
133
|
-
dist/**
|
|
134
|
-
docs/api/**
|
|
135
|
-
draft: false
|
|
136
|
-
prerelease: false
|
|
137
|
-
env:
|
|
138
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
139
|
-
|
|
140
|
-
- name: Update documentation
|
|
141
|
-
uses: peaceiris/actions-gh-pages@v4
|
|
142
|
-
with:
|
|
143
|
-
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
144
|
-
publish_dir: ./docs/api
|
|
145
|
-
publish_branch: gh-pages
|
|
146
|
-
enable_jekyll: false
|
|
147
|
-
|
|
148
|
-
- name: Notify success
|
|
149
|
-
if: success()
|
|
150
|
-
run: |
|
|
151
|
-
echo "✅ Successfully published @rahul05ranjan/dhruv-cli@${{ steps.final_version.outputs.version }}"
|
|
152
|
-
echo "📦 NPM: https://www.npmjs.com/package/@rahul05ranjan/dhruv-cli"
|
|
153
|
-
echo "📖 Documentation: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}"
|
|
154
|
-
echo "🏷️ Release: https://github.com/${{ github.repository }}/releases/tag/v${{ steps.final_version.outputs.version }}"
|