@rahul05ranjan/dhruv-cli 1.3.0 โ 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/ENTERPRISE.md +275 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +45 -17
- package/.github/ISSUE_TEMPLATE/documentation_issue.md +61 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +61 -9
- package/.github/ISSUE_TEMPLATE/security_vulnerability.md +74 -0
- package/.github/dependabot.yml +42 -2
- package/.github/pull_request_template.md +13 -0
- package/.github/workflows/ci.yml +51 -38
- package/.github/workflows/contribution.yml +41 -34
- package/.github/workflows/dependabot-auto-merge.yml +62 -2
- package/.github/workflows/labeler.yml +1 -0
- package/.github/workflows/release.yml +229 -0
- package/.github/workflows/security.yml +201 -0
- package/.releaserc.json +50 -0
- package/AGENTS.md +13 -0
- package/CHANGELOG.md +13 -0
- package/README.md +145 -40
- package/__tests__/cli-contract.test.ts +104 -0
- package/__tests__/core.test.ts +439 -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 +62 -0
- package/__tests__/workflows.test.ts +118 -0
- package/dist/commands/explain.js +13 -44
- package/dist/commands/fix.js +13 -38
- package/dist/commands/generate.d.ts +6 -1
- package/dist/commands/generate.js +60 -55
- package/dist/commands/health.d.ts +4 -0
- package/dist/commands/health.js +419 -0
- package/dist/commands/init.js +56 -42
- package/dist/commands/menu.js +137 -24
- package/dist/commands/metrics.d.ts +5 -0
- package/dist/commands/metrics.js +80 -0
- package/dist/commands/optimize.js +42 -34
- package/dist/commands/review.d.ts +4 -1
- package/dist/commands/review.js +87 -43
- package/dist/commands/security-check.d.ts +4 -1
- package/dist/commands/security-check.js +109 -38
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +83 -0
- package/dist/commands/suggest.js +13 -39
- package/dist/config/config.d.ts +5 -1
- package/dist/config/config.js +53 -8
- package/dist/core/ai.d.ts +88 -2
- package/dist/core/ai.js +231 -30
- package/dist/core/command-catalog.d.ts +10 -0
- package/dist/core/command-catalog.js +27 -0
- package/dist/core/command-runner.d.ts +17 -0
- package/dist/core/command-runner.js +157 -0
- package/dist/core/logger.d.ts +40 -0
- package/dist/core/logger.js +139 -0
- package/dist/core/metrics.d.ts +62 -0
- package/dist/core/metrics.js +284 -0
- package/dist/core/prompts.d.ts +1 -0
- package/dist/core/prompts.js +121 -0
- package/dist/core/security.d.ts +34 -0
- package/dist/core/security.js +197 -0
- package/dist/index.js +84 -22
- package/dist/utils/projectType.d.ts +1 -1
- package/dist/utils/projectType.js +26 -7
- package/dist/utils/ux.d.ts +3 -0
- package/dist/utils/ux.js +15 -0
- package/docs/agents/domain.md +51 -0
- package/docs/agents/issue-tracker.md +45 -0
- package/docs/agents/triage-labels.md +15 -0
- package/docs/api/.nojekyll +1 -0
- package/docs/api/assets/hierarchy.js +1 -0
- package/docs/api/assets/highlight.css +71 -0
- package/docs/api/assets/icons.js +18 -0
- package/docs/api/assets/icons.svg +1 -0
- package/docs/api/assets/main.js +60 -0
- package/docs/api/assets/navigation.js +1 -0
- package/docs/api/assets/search.js +1 -0
- package/docs/api/assets/style.css +1633 -0
- package/docs/api/hierarchy.html +1 -0
- package/docs/api/index.html +161 -0
- 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/api/modules.html +1 -0
- package/docs/dhruv-cli-preview.svg +42 -0
- package/docs/index.html +631 -533
- package/docs/publishing-fix.md +34 -0
- package/eslint.config.js +170 -0
- package/jest.config.json +37 -0
- package/lighthouserc.json +22 -0
- package/package.json +62 -8
- package/src/commands/explain.ts +13 -42
- package/src/commands/fix.ts +13 -31
- package/src/commands/generate.ts +68 -48
- package/src/commands/health.ts +485 -0
- package/src/commands/init.ts +57 -42
- package/src/commands/menu.ts +132 -24
- package/src/commands/metrics.ts +100 -0
- package/src/commands/optimize.ts +40 -28
- package/src/commands/review.ts +96 -37
- package/src/commands/security-check.ts +127 -33
- package/src/commands/status.ts +83 -0
- package/src/commands/suggest.ts +13 -32
- package/src/config/config.ts +60 -8
- package/src/core/ai.ts +265 -26
- package/src/core/command-catalog.ts +37 -0
- package/src/core/command-runner.ts +185 -0
- package/src/core/logger.ts +195 -0
- package/src/core/metrics.ts +335 -0
- package/src/core/prompts.ts +128 -0
- package/src/core/security.ts +243 -0
- package/src/index.ts +90 -22
- package/src/utils/projectType.ts +22 -7
- package/src/utils/ux.ts +18 -0
- package/test-suite.sh +147 -0
- package/tsconfig.json +4 -3
- package/typedoc.json +44 -0
- package/types/global.d.ts +13 -0
- package/validate-workflows.sh +270 -0
- package/.eslintignore +0 -1
- package/.eslintrc.cjs +0 -43
- package/.github/workflows/auto-assign.yml +0 -14
- package/src/core/ai.test.js +0 -40
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# npm publishing issue resolution
|
|
2
|
+
|
|
3
|
+
## Issue
|
|
4
|
+
|
|
5
|
+
GitHub Actions was failing with:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/@rahul05ranjan%2fdhruv-cli - You cannot publish over the previously published versions: 0.0.0-development.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Resolution
|
|
12
|
+
|
|
13
|
+
- Updated the package version from `0.0.0-development` to `1.4.0`.
|
|
14
|
+
- Added semantic-release configuration and plugins.
|
|
15
|
+
- Removed direct npm publishing from the CI workflow.
|
|
16
|
+
- Added a dedicated publishing workflow with version-conflict checks.
|
|
17
|
+
- Enabled trusted publishing with npm provenance.
|
|
18
|
+
|
|
19
|
+
## Release conventions
|
|
20
|
+
|
|
21
|
+
Use conventional commit messages so semantic-release can determine the next version:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Patch
|
|
25
|
+
git commit -m "fix: resolve a connection issue"
|
|
26
|
+
|
|
27
|
+
# Minor
|
|
28
|
+
git commit -m "feat: add a new command"
|
|
29
|
+
|
|
30
|
+
# Major
|
|
31
|
+
git commit -m "feat!: change the command output contract"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The authoritative release configuration lives in [`.releaserc.json`](../.releaserc.json) and the workflows live in [`.github/workflows/`](../.github/workflows/).
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
// Base configuration
|
|
6
|
+
js.configs.recommended,
|
|
7
|
+
|
|
8
|
+
// Global ignores (migrated from .eslintignore)
|
|
9
|
+
{
|
|
10
|
+
ignores: [
|
|
11
|
+
'dist/',
|
|
12
|
+
'node_modules/',
|
|
13
|
+
'node-fetch.d.ts',
|
|
14
|
+
'coverage/',
|
|
15
|
+
'.dhruv-cache/',
|
|
16
|
+
'logs/',
|
|
17
|
+
'docs/'
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
// TypeScript files configuration (excluding test files)
|
|
22
|
+
{
|
|
23
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
24
|
+
ignores: ['__tests__/**/*', '**/*.test.ts', '**/*.spec.ts', 'src/core/logger.ts', 'src/core/security.ts'],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
parser: tseslint.parser,
|
|
27
|
+
parserOptions: {
|
|
28
|
+
project: './tsconfig.json',
|
|
29
|
+
sourceType: 'module',
|
|
30
|
+
ecmaVersion: 2020,
|
|
31
|
+
},
|
|
32
|
+
globals: {
|
|
33
|
+
console: 'readonly',
|
|
34
|
+
process: 'readonly',
|
|
35
|
+
Buffer: 'readonly',
|
|
36
|
+
setTimeout: 'readonly',
|
|
37
|
+
__dirname: 'readonly',
|
|
38
|
+
__filename: 'readonly',
|
|
39
|
+
global: 'readonly',
|
|
40
|
+
module: 'readonly',
|
|
41
|
+
require: 'readonly',
|
|
42
|
+
exports: 'readonly',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
plugins: {
|
|
46
|
+
'@typescript-eslint': tseslint.plugin,
|
|
47
|
+
},
|
|
48
|
+
rules: {
|
|
49
|
+
...tseslint.configs.recommended.rules,
|
|
50
|
+
'no-console': 'off',
|
|
51
|
+
'@typescript-eslint/no-unused-vars': ['warn', {
|
|
52
|
+
'argsIgnorePattern': '^_|error|e',
|
|
53
|
+
'varsIgnorePattern': '^_|response|error|e|Command|printSuccess|printInfo|printWarning|detectProjectType',
|
|
54
|
+
'ignoreRestSiblings': true
|
|
55
|
+
}],
|
|
56
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
57
|
+
'@typescript-eslint/no-explicit-any': ['warn', {
|
|
58
|
+
'ignoreRestArgs': true
|
|
59
|
+
}],
|
|
60
|
+
'no-var': 'error',
|
|
61
|
+
'prefer-const': 'error',
|
|
62
|
+
'eqeqeq': ['error', 'always'],
|
|
63
|
+
'no-undef': 'off', // Turn off because we're using globals
|
|
64
|
+
'no-redeclare': 'off', // Allow redeclaration of globals
|
|
65
|
+
'no-unused-vars': 'off', // Turn off base rule, use @typescript-eslint/no-unused-vars
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Lenient configuration for files with external library interfaces
|
|
70
|
+
{
|
|
71
|
+
files: ['src/core/logger.ts', 'src/core/security.ts'],
|
|
72
|
+
languageOptions: {
|
|
73
|
+
parser: tseslint.parser,
|
|
74
|
+
parserOptions: {
|
|
75
|
+
project: './tsconfig.json',
|
|
76
|
+
sourceType: 'module',
|
|
77
|
+
ecmaVersion: 2020,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
plugins: {
|
|
81
|
+
'@typescript-eslint': tseslint.plugin,
|
|
82
|
+
},
|
|
83
|
+
rules: {
|
|
84
|
+
...tseslint.configs.recommended.rules,
|
|
85
|
+
'no-console': 'off',
|
|
86
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
87
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
88
|
+
'@typescript-eslint/no-explicit-any': 'off', // Allow any in these files due to Winston/security libraries
|
|
89
|
+
'no-var': 'error',
|
|
90
|
+
'prefer-const': 'error',
|
|
91
|
+
'eqeqeq': ['error', 'always'],
|
|
92
|
+
'no-undef': 'off',
|
|
93
|
+
'no-redeclare': 'off',
|
|
94
|
+
'no-unused-vars': 'off',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// JavaScript files configuration
|
|
99
|
+
{
|
|
100
|
+
files: ['**/*.js'],
|
|
101
|
+
languageOptions: {
|
|
102
|
+
sourceType: 'module',
|
|
103
|
+
ecmaVersion: 2020,
|
|
104
|
+
globals: {
|
|
105
|
+
console: 'readonly',
|
|
106
|
+
process: 'readonly',
|
|
107
|
+
Buffer: 'readonly',
|
|
108
|
+
setTimeout: 'readonly',
|
|
109
|
+
__dirname: 'readonly',
|
|
110
|
+
__filename: 'readonly',
|
|
111
|
+
global: 'readonly',
|
|
112
|
+
module: 'readonly',
|
|
113
|
+
require: 'readonly',
|
|
114
|
+
exports: 'readonly',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
rules: {
|
|
118
|
+
'no-console': 'off',
|
|
119
|
+
'no-var': 'error',
|
|
120
|
+
'prefer-const': 'error',
|
|
121
|
+
'eqeqeq': ['error', 'always'],
|
|
122
|
+
'no-undef': 'off', // Turn off because we're using globals
|
|
123
|
+
'no-redeclare': 'off', // Allow redeclaration of globals
|
|
124
|
+
'no-unused-vars': 'off', // Allow unused vars in JS files for flexibility
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
// Test files configuration (separate project config)
|
|
129
|
+
{
|
|
130
|
+
files: ['__tests__/**/*.{ts,js}', '**/*.test.{ts,js}', '**/*.spec.{ts,js}'],
|
|
131
|
+
languageOptions: {
|
|
132
|
+
parser: tseslint.parser,
|
|
133
|
+
parserOptions: {
|
|
134
|
+
sourceType: 'module',
|
|
135
|
+
ecmaVersion: 2020,
|
|
136
|
+
// Don't use project for test files since they're not in tsconfig.json
|
|
137
|
+
},
|
|
138
|
+
globals: {
|
|
139
|
+
console: 'readonly',
|
|
140
|
+
process: 'readonly',
|
|
141
|
+
Buffer: 'readonly',
|
|
142
|
+
setTimeout: 'readonly',
|
|
143
|
+
describe: 'readonly',
|
|
144
|
+
it: 'readonly',
|
|
145
|
+
test: 'readonly',
|
|
146
|
+
expect: 'readonly',
|
|
147
|
+
beforeEach: 'readonly',
|
|
148
|
+
afterEach: 'readonly',
|
|
149
|
+
beforeAll: 'readonly',
|
|
150
|
+
afterAll: 'readonly',
|
|
151
|
+
jest: 'readonly',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
plugins: {
|
|
155
|
+
'@typescript-eslint': tseslint.plugin,
|
|
156
|
+
},
|
|
157
|
+
rules: {
|
|
158
|
+
'@typescript-eslint/no-unused-vars': ['warn', {
|
|
159
|
+
'argsIgnorePattern': '^_|error|e',
|
|
160
|
+
'varsIgnorePattern': '^_|response|error|e|Command|printSuccess|printInfo|printWarning|detectProjectType',
|
|
161
|
+
'ignoreRestSiblings': true
|
|
162
|
+
}],
|
|
163
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
164
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
165
|
+
'no-undef': 'off', // Turn off because we're using globals
|
|
166
|
+
'no-redeclare': 'off', // Allow redeclaration of globals
|
|
167
|
+
'no-unused-vars': 'off', // Turn off base rule, use @typescript-eslint/no-unused-vars
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
];
|
package/jest.config.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"preset": "ts-jest",
|
|
3
|
+
"testEnvironment": "node",
|
|
4
|
+
"roots": ["<rootDir>/src", "<rootDir>/__tests__"],
|
|
5
|
+
"testMatch": ["**/__tests__/**/*.test.ts", "**/*.test.ts", "**/*.spec.ts"],
|
|
6
|
+
"testPathIgnorePatterns": ["/node_modules/", "/dist/", "/coverage/", "\\.test\\.js$", "\\.spec\\.js$"],
|
|
7
|
+
"transform": {
|
|
8
|
+
"^.+\\.ts$": "ts-jest"
|
|
9
|
+
},
|
|
10
|
+
"moduleNameMapper": {
|
|
11
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
12
|
+
},
|
|
13
|
+
"collectCoverageFrom": [
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"!src/**/*.d.ts",
|
|
16
|
+
"!src/index.ts"
|
|
17
|
+
],
|
|
18
|
+
"coverageDirectory": "coverage",
|
|
19
|
+
"coverageReporters": ["text", "lcov", "html"],
|
|
20
|
+
"reporters": [
|
|
21
|
+
"default",
|
|
22
|
+
["jest-junit", { "outputDirectory": "coverage", "outputName": "junit.xml" }]
|
|
23
|
+
],
|
|
24
|
+
"coverageThreshold": {
|
|
25
|
+
"global": {
|
|
26
|
+
"branches": 7,
|
|
27
|
+
"functions": 5,
|
|
28
|
+
"lines": 6,
|
|
29
|
+
"statements": 6
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"setupFilesAfterEnv": ["<rootDir>/__tests__/setup.ts"],
|
|
33
|
+
"testTimeout": 10000,
|
|
34
|
+
"verbose": true,
|
|
35
|
+
"forceExit": true,
|
|
36
|
+
"detectOpenHandles": true
|
|
37
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ci": {
|
|
3
|
+
"collect": {
|
|
4
|
+
"numberOfRuns": 3,
|
|
5
|
+
"startServerCommand": "npm run start",
|
|
6
|
+
"startServerReadyPattern": "Dhruv CLI is running",
|
|
7
|
+
"url": ["http://localhost:3000"]
|
|
8
|
+
},
|
|
9
|
+
"assert": {
|
|
10
|
+
"assertions": {
|
|
11
|
+
"categories:performance": ["error", {"minScore": 0.8}],
|
|
12
|
+
"categories:accessibility": ["error", {"minScore": 0.9}],
|
|
13
|
+
"categories:best-practices": ["error", {"minScore": 0.9}],
|
|
14
|
+
"categories:seo": ["error", {"minScore": 0.9}],
|
|
15
|
+
"categories:pwa": "off"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"upload": {
|
|
19
|
+
"target": "temporary-public-storage"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rahul05ranjan/dhruv-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "AI-powered CLI assistant for developers using Ollama",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -21,7 +21,30 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc",
|
|
23
23
|
"start": "node ./dist/index.js",
|
|
24
|
-
"dev": "ts-node src/index.ts"
|
|
24
|
+
"dev": "ts-node src/index.ts",
|
|
25
|
+
"test": "jest",
|
|
26
|
+
"test:watch": "jest --watch",
|
|
27
|
+
"test:coverage": "jest --coverage",
|
|
28
|
+
"test:ci": "jest --coverage --watchAll=false --passWithNoTests",
|
|
29
|
+
"test:e2e": "jest --config jest.e2e.config.js",
|
|
30
|
+
"lint": "eslint . --ext .ts,.js",
|
|
31
|
+
"lint:fix": "eslint . --ext .ts,.js --fix",
|
|
32
|
+
"type-check": "tsc --noEmit",
|
|
33
|
+
"docs": "typedoc --out docs/api src",
|
|
34
|
+
"docs:serve": "npx serve docs",
|
|
35
|
+
"docs:publish": "npm run docs && gh-pages -d docs",
|
|
36
|
+
"benchmark": "autocannon -c 100 -d 10 http://localhost:3000",
|
|
37
|
+
"performance": "lighthouse http://localhost:3000 --output=json --output-path=./reports/lighthouse.json",
|
|
38
|
+
"security": "npm audit --audit-level=moderate",
|
|
39
|
+
"security:full": "npm audit --audit-level=info",
|
|
40
|
+
"clean": "rm -rf dist coverage .dhruv-cache logs/*.log",
|
|
41
|
+
"prepublishOnly": "npm run clean && npm run lint && npm run test:ci && npm run build",
|
|
42
|
+
"release": "semantic-release",
|
|
43
|
+
"release:beta": "semantic-release --tag beta",
|
|
44
|
+
"docker:build": "docker build -t dhruv-cli .",
|
|
45
|
+
"docker:run": "docker run -it dhruv-cli",
|
|
46
|
+
"health": "node dist/index.js health",
|
|
47
|
+
"metrics": "node dist/index.js metrics"
|
|
25
48
|
},
|
|
26
49
|
"dependencies": {
|
|
27
50
|
"chalk": "^5.3.0",
|
|
@@ -29,21 +52,52 @@
|
|
|
29
52
|
"cli-progress": "^3.12.0",
|
|
30
53
|
"commander": "^14.0.0",
|
|
31
54
|
"inquirer": "^12.6.3",
|
|
32
|
-
"
|
|
55
|
+
"joi": "^18.2.9",
|
|
56
|
+
"node-fetch": "^3.3.2",
|
|
33
57
|
"ollama": "^0.5.16",
|
|
34
|
-
"ora": "^8.2.0"
|
|
58
|
+
"ora": "^8.2.0",
|
|
59
|
+
"prom-client": "^15.1.3",
|
|
60
|
+
"validator": "^13.15.35",
|
|
61
|
+
"winston": "^3.17.0",
|
|
62
|
+
"winston-daily-rotate-file": "^5.0.0"
|
|
35
63
|
},
|
|
36
64
|
"devDependencies": {
|
|
37
|
-
"@eslint/js": "^
|
|
65
|
+
"@eslint/js": "^9.30.1",
|
|
66
|
+
"@lhci/cli": "^0.15.1",
|
|
67
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
68
|
+
"@semantic-release/commit-analyzer": "^12.0.0",
|
|
69
|
+
"@semantic-release/git": "^10.0.1",
|
|
70
|
+
"@semantic-release/github": "^10.3.5",
|
|
71
|
+
"@semantic-release/npm": "^13.1.5",
|
|
72
|
+
"@semantic-release/release-notes-generator": "^12.1.0",
|
|
38
73
|
"@types/inquirer": "^9.0.8",
|
|
74
|
+
"@types/jest": "^30.0.0",
|
|
75
|
+
"@types/nock": "^10.0.3",
|
|
39
76
|
"@types/node": "^24.0.7",
|
|
77
|
+
"@types/supertest": "^6.0.3",
|
|
78
|
+
"@types/validator": "^13.15.2",
|
|
40
79
|
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
|
41
80
|
"@typescript-eslint/parser": "^8.35.0",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
81
|
+
"autocannon": "^8.0.0",
|
|
82
|
+
"benchmark": "^2.1.4",
|
|
83
|
+
"eslint": "^9.30.0",
|
|
84
|
+
"istanbul-lib-coverage": "^3.2.2",
|
|
85
|
+
"istanbul-lib-report": "^3.0.1",
|
|
86
|
+
"istanbul-reports": "^3.2.0",
|
|
87
|
+
"jest": "^30.1.0",
|
|
88
|
+
"jest-junit": "^17.0.0",
|
|
89
|
+
"jsdoc-to-markdown": "^9.1.2",
|
|
90
|
+
"lighthouse": "^12.8.1",
|
|
91
|
+
"nock": "^14.0.10",
|
|
92
|
+
"semantic-release": "^25.0.1",
|
|
93
|
+
"supertest": "^7.1.4",
|
|
94
|
+
"ts-jest": "^29.4.1",
|
|
44
95
|
"ts-node": "^10.9.1",
|
|
96
|
+
"typedoc": "^0.28.11",
|
|
97
|
+
"typedoc-plugin-markdown": "^4.8.1",
|
|
45
98
|
"typescript": "^5.8.3",
|
|
46
|
-
"typescript-eslint": "^8.35.0"
|
|
99
|
+
"typescript-eslint": "^8.35.0",
|
|
100
|
+
"yaml": "^2.9.1"
|
|
47
101
|
},
|
|
48
102
|
"repository": {
|
|
49
103
|
"type": "git",
|
package/src/commands/explain.ts
CHANGED
|
@@ -1,45 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { loadConfig } from '../config/config.js';
|
|
5
|
-
import { highlightCode, printError } from '../utils/ux.js';
|
|
1
|
+
import { runCommand } from '../core/command-runner.js';
|
|
2
|
+
import { getSystemMessage } from '../core/prompts.js';
|
|
6
3
|
|
|
7
4
|
export async function explain(query: string) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
onToken: (token: string) => {
|
|
20
|
-
streamed += token;
|
|
21
|
-
process.stdout.write(chalk.cyan(token));
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
process.stdout.write('\n');
|
|
25
|
-
if (typeof highlightCode === 'function' && streamed.match(/```[a-z]*[\s\S]*?```/)) {
|
|
26
|
-
const codeBlocks = streamed.match(/```([a-z]*)\n([\s\S]*?)```/g) || [];
|
|
27
|
-
for (const block of codeBlocks) {
|
|
28
|
-
const [, lang, code] = block.match(/```([a-z]*)\n([\s\S]*?)```/) || [];
|
|
29
|
-
if (code) {
|
|
30
|
-
try {
|
|
31
|
-
console.log(highlightCode(code, lang || 'js'));
|
|
32
|
-
} catch (err) {
|
|
33
|
-
// Only log highlight errors in development
|
|
34
|
-
if (process.env.NODE_ENV === 'development') {
|
|
35
|
-
console.error('Highlight error:', err);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
} catch (err) {
|
|
42
|
-
printError('Failed to get explanation.');
|
|
43
|
-
console.error(chalk.red((err as Error).message));
|
|
44
|
-
}
|
|
5
|
+
await runCommand({
|
|
6
|
+
name: 'explain',
|
|
7
|
+
input: { query },
|
|
8
|
+
header: '๐ Explanation: ',
|
|
9
|
+
buildRequest: (input, model) => ({
|
|
10
|
+
prompt: input.query,
|
|
11
|
+
systemMessage: getSystemMessage('explain'),
|
|
12
|
+
model,
|
|
13
|
+
}),
|
|
14
|
+
footer: `๐ก Need more help? Try: dhruv suggest "${query}"`,
|
|
15
|
+
});
|
|
45
16
|
}
|
package/src/commands/fix.ts
CHANGED
|
@@ -1,34 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { loadConfig } from '../config/config.js';
|
|
5
|
-
import { highlightCode, printError } from '../utils/ux.js';
|
|
1
|
+
import { runCommand } from '../core/command-runner.js';
|
|
2
|
+
import { getSystemMessage } from '../core/prompts.js';
|
|
6
3
|
|
|
7
4
|
export async function fix(query: string) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
process.stdout.write(chalk.cyan(token));
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
process.stdout.write('\n');
|
|
23
|
-
if (typeof highlightCode === 'function' && streamed.match(/```[a-z]*[\s\S]*?```/)) {
|
|
24
|
-
const codeBlocks = streamed.match(/```([a-z]*)\n([\s\S]*?)```/g) || [];
|
|
25
|
-
for (const block of codeBlocks) {
|
|
26
|
-
const [, lang, code] = block.match(/```([a-z]*)\n([\s\S]*?)```/) || [];
|
|
27
|
-
if (code) try { console.log(highlightCode(code, lang || 'js')); } catch (err) { console.error('Highlight error:', err); }
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} catch (err) {
|
|
31
|
-
printError('Failed to get fix suggestion.');
|
|
32
|
-
console.error(chalk.red((err as Error).message));
|
|
33
|
-
}
|
|
5
|
+
await runCommand({
|
|
6
|
+
name: 'fix',
|
|
7
|
+
input: { query },
|
|
8
|
+
header: '๐ง Fix Analysis: ',
|
|
9
|
+
buildRequest: (input, model) => ({
|
|
10
|
+
prompt: input.query,
|
|
11
|
+
systemMessage: getSystemMessage('fix'),
|
|
12
|
+
model,
|
|
13
|
+
}),
|
|
14
|
+
footer: `๐งช Want to test this? Try: dhruv generate tests <your-file>`,
|
|
15
|
+
});
|
|
34
16
|
}
|
package/src/commands/generate.ts
CHANGED
|
@@ -1,55 +1,75 @@
|
|
|
1
|
-
import { askOllama } from '../core/ai.js';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { loadConfig } from '../config/config.js';
|
|
4
1
|
import fs from 'fs';
|
|
5
|
-
import
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { runCommand } from '../core/command-runner.js';
|
|
4
|
+
import { getSystemMessage } from '../core/prompts.js';
|
|
5
|
+
import { printError, printSuccess, printInfo } from '../utils/ux.js';
|
|
6
|
+
import { loadConfig } from '../config/config.js';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (fs.existsSync(target)) {
|
|
11
|
-
content = fs.readFileSync(target, 'utf-8');
|
|
8
|
+
function buildPrompt(type: string, content: string): string {
|
|
9
|
+
if (type === 'tests' || type === 'test') {
|
|
10
|
+
return `Generate comprehensive unit tests for the following JavaScript code. Use Jest or Mocha syntax. Only return the test code without explanations:\n\n${content}`;
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
if (type === 'documentation' || type === 'docs') {
|
|
13
|
+
return `Generate JSDoc documentation for the following code:\n\n${content}`;
|
|
14
|
+
}
|
|
15
|
+
return `Generate ${type} for this code:\n\n${content}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Extracts test code from the response: a fenced block if present, else the raw response. */
|
|
19
|
+
function extractTestCode(response: string): string {
|
|
20
|
+
const fenced = response.match(/```(?:javascript|js)?\s*\n([\s\S]*?)```/);
|
|
21
|
+
if (fenced?.[1]) return fenced[1].trim();
|
|
22
|
+
return response
|
|
23
|
+
.replace(/^.*?(?=const|describe|test|it\s*\()/s, '')
|
|
24
|
+
.replace(/```[a-z]*\n?/g, '')
|
|
25
|
+
.trim();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GenerateOptions {
|
|
29
|
+
apply?: boolean;
|
|
30
|
+
output?: string;
|
|
31
|
+
overwrite?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function generate(type: string, target: string, options: GenerateOptions = {}) {
|
|
35
|
+
if (!fs.existsSync(target)) {
|
|
36
|
+
printError(`Target file "${target}" does not exist.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const content = fs.readFileSync(target, 'utf-8');
|
|
41
|
+
|
|
42
|
+
await runCommand({
|
|
43
|
+
name: 'generate',
|
|
44
|
+
input: { type, target },
|
|
45
|
+
header: `๐จ Generating ${type}: `,
|
|
46
|
+
buildRequest: (input, model) => ({
|
|
47
|
+
prompt: buildPrompt(input.type, content),
|
|
48
|
+
systemMessage: getSystemMessage('generate'),
|
|
49
|
+
model,
|
|
50
|
+
}),
|
|
51
|
+
onComplete: (response) => {
|
|
52
|
+
if (type !== 'tests' && type !== 'test') return;
|
|
53
|
+
const codeToSave = extractTestCode(response);
|
|
54
|
+
if (!codeToSave) {
|
|
55
|
+
printError('No valid test code generated.');
|
|
56
|
+
return;
|
|
22
57
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
codeToSave = codeBlockMatch[1].trim();
|
|
31
|
-
} else {
|
|
32
|
-
// Remove Markdown, explanations, and keep only lines that look like code
|
|
33
|
-
codeToSave = streamed
|
|
34
|
-
.replace(/```[a-z]*\n|```/g, '') // remove code block markers
|
|
35
|
-
.split('\n')
|
|
36
|
-
.filter(line => line.trim() && !/^\s*#|^\s*\/\//.test(line) && /[;{}()=]/.test(line))
|
|
37
|
-
.join('\n')
|
|
38
|
-
.trim();
|
|
58
|
+
const extension = path.extname(target) || '.js';
|
|
59
|
+
const testFile = options.output ?? target.replace(/\.[^.]+$/, `.test${extension}`);
|
|
60
|
+
if (!options.apply && !options.output) {
|
|
61
|
+
if (loadConfig().responseFormat !== 'json') {
|
|
62
|
+
printInfo(`Preview only. Use --apply to write ${testFile}, or --output <path> to choose a destination.`);
|
|
63
|
+
}
|
|
64
|
+
return;
|
|
39
65
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
if (typeof highlightCode === 'function' && streamed.match(/```[a-z]*[\s\S]*?```/)) {
|
|
45
|
-
const codeBlocks = streamed.match(/```([a-z]*)\n([\s\S]*?)```/g) || [];
|
|
46
|
-
for (const block of codeBlocks) {
|
|
47
|
-
const [, lang, code] = block.match(/```([a-z]*)\n([\s\S]*?)```/) || [];
|
|
48
|
-
if (code) try { console.log(highlightCode(code, lang || 'js')); } catch (err) { console.error('Highlight error:', err); }
|
|
66
|
+
if (fs.existsSync(testFile) && !options.overwrite) {
|
|
67
|
+
printError(`Test file "${testFile}" already exists. Use --overwrite to replace it.`);
|
|
68
|
+
return;
|
|
49
69
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
70
|
+
fs.writeFileSync(testFile, codeToSave);
|
|
71
|
+
if (loadConfig().responseFormat !== 'json') printSuccess(`Test file saved: ${testFile}`);
|
|
72
|
+
},
|
|
73
|
+
footer: `๐ Want a review? Try: dhruv review ${target}`,
|
|
74
|
+
});
|
|
55
75
|
}
|