cloving 0.3.18 → 0.3.19
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/.DS_Store +0 -0
- package/.aider.chat.history.md +16978 -0
- package/.aider.input.history +15 -0
- package/.aider.tags.cache.v3/cache.db +0 -0
- package/.aider.tags.cache.v3/cache.db-shm +0 -0
- package/.aider.tags.cache.v3/cache.db-wal +0 -0
- package/.cursorrules +77 -0
- package/.github/workflows/auto-release.yml +83 -0
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/npm-publish.yml +34 -0
- package/.gitignore +67 -0
- package/.husky/_/.gitignore +1 -0
- package/.husky/_/applypatch-msg +2 -0
- package/.husky/_/commit-msg +2 -0
- package/.husky/_/h +22 -0
- package/.husky/_/husky.sh +9 -0
- package/.husky/_/post-applypatch +2 -0
- package/.husky/_/post-checkout +2 -0
- package/.husky/_/post-commit +2 -0
- package/.husky/_/post-merge +2 -0
- package/.husky/_/post-rewrite +2 -0
- package/.husky/_/pre-applypatch +2 -0
- package/.husky/_/pre-auto-gc +2 -0
- package/.husky/_/pre-commit +2 -0
- package/.husky/_/pre-merge-commit +2 -0
- package/.husky/_/pre-push +2 -0
- package/.husky/_/pre-rebase +2 -0
- package/.husky/_/prepare-commit-msg +2 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +1 -0
- package/.prettierrc.json +7 -0
- package/.tool-versions +2 -0
- package/SECURITY.md +15 -0
- package/cloving.json +67 -0
- package/dist/managers/CommitManager.js +8 -2
- package/dist/package.json +1 -1
- package/jest.config.js +11 -0
- package/package.json +1 -1
- package/src/cloving_gpt/adapters/azureopenai.ts +83 -0
- package/src/cloving_gpt/adapters/claude.ts +140 -0
- package/src/cloving_gpt/adapters/gemini.ts +146 -0
- package/src/cloving_gpt/adapters/index.ts +43 -0
- package/src/cloving_gpt/adapters/mistral.ts +142 -0
- package/src/cloving_gpt/adapters/ollama.ts +136 -0
- package/src/cloving_gpt/adapters/openai.ts +113 -0
- package/src/cloving_gpt/index.ts +229 -0
- package/src/commands/chat.ts +12 -0
- package/src/commands/config.ts +192 -0
- package/src/commands/generate/code.ts +18 -0
- package/src/commands/generate/commit.ts +9 -0
- package/src/commands/generate/context.ts +93 -0
- package/src/commands/generate/docs.ts +9 -0
- package/src/commands/generate/review.ts +9 -0
- package/src/commands/generate/shell.ts +9 -0
- package/src/commands/generate/unit_tests.ts +9 -0
- package/src/commands/init.ts +9 -0
- package/src/commands/models.ts +21 -0
- package/src/commands/proxy.ts +9 -0
- package/src/commands/tokens.ts +82 -0
- package/src/index.ts +197 -0
- package/src/managers/BlockManager.ts +126 -0
- package/src/managers/ChatManager.ts +755 -0
- package/src/managers/ChunkManager.ts +31 -0
- package/src/managers/CodeManager.ts +226 -0
- package/src/managers/CommitManager.ts +71 -0
- package/src/managers/DocsManager.ts +101 -0
- package/src/managers/InitManager.ts +263 -0
- package/src/managers/ProxyManager.ts +240 -0
- package/src/managers/ReviewManager.ts +154 -0
- package/src/managers/ShellManager.ts +172 -0
- package/src/managers/StreamManager.ts +353 -0
- package/src/managers/UnitTestManager.ts +293 -0
- package/src/utils/config_utils.ts +271 -0
- package/src/utils/git_utils.ts +230 -0
- package/src/utils/model_utils.ts +3 -0
- package/src/utils/prompt_utils.ts +375 -0
- package/src/utils/prompts/CODEGEN_COULDNT_APPLY.md +5 -0
- package/src/utils/prompts/CODEGEN_EXAMPLES.md +82 -0
- package/src/utils/prompts/CODEGEN_INSTRUCTIONS.md +43 -0
- package/src/utils/prompts/DOCS_INSTRUCTIONS.md +9 -0
- package/src/utils/prompts/INIT_INSTRUCTIONS.md +132 -0
- package/src/utils/prompts/REVIEW_INSTRUCTIONS.md +49 -0
- package/src/utils/prompts/SHELL_INSTRUCTIONS.md +15 -0
- package/src/utils/prompts/SPECIAL_FILES.md +66 -0
- package/src/utils/prompts/index.ts +37 -0
- package/src/utils/string_utils.ts +552 -0
- package/src/utils/types.ts +127 -0
- package/tests/commands/generate/unit_tests.test.ts +27 -0
- package/tests/utils/git_utils.test.ts +116 -0
- package/tests/utils/model_utils.test.ts +27 -0
- package/tests/utils/prompt_utils.test.ts +33 -0
- package/tests/utils/string_utils.test.ts +560 -0
- package/tsconfig.json +14 -0
- package/yarn.lock +5823 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export type GPTProvider = 'openai' | 'claude' | 'ollama' | 'gemini'
|
|
2
|
+
|
|
3
|
+
export interface BlockIndices {
|
|
4
|
+
start: number
|
|
5
|
+
current: number
|
|
6
|
+
filePathEnd: number
|
|
7
|
+
divider: number
|
|
8
|
+
end: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface OpenAIStreamChunk {
|
|
12
|
+
output: string
|
|
13
|
+
lastChar: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CurrentNewBlock {
|
|
17
|
+
language: string
|
|
18
|
+
filePath: string
|
|
19
|
+
currentContent: string
|
|
20
|
+
newContent: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ChatMessage {
|
|
24
|
+
role: 'user' | 'assistant' | 'system'
|
|
25
|
+
content: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GPTRequest {
|
|
29
|
+
messages?: ChatMessage[]
|
|
30
|
+
prompt: string
|
|
31
|
+
maxTokens?: number
|
|
32
|
+
temperature?: number
|
|
33
|
+
stream?: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ClovingGPTOptions {
|
|
37
|
+
model?: string
|
|
38
|
+
silent?: boolean
|
|
39
|
+
files?: string[]
|
|
40
|
+
prompt?: string
|
|
41
|
+
save?: boolean
|
|
42
|
+
exec?: boolean
|
|
43
|
+
interactive?: boolean
|
|
44
|
+
temperature?: number
|
|
45
|
+
port?: number
|
|
46
|
+
stream?: boolean
|
|
47
|
+
timeout?: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ClovingModelConfig {
|
|
51
|
+
apiKey: string
|
|
52
|
+
primary: boolean
|
|
53
|
+
priority: number
|
|
54
|
+
silent: boolean
|
|
55
|
+
trust: boolean
|
|
56
|
+
temperature: number
|
|
57
|
+
endpoint?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type ProjectConfig = {
|
|
61
|
+
name: string
|
|
62
|
+
task: string
|
|
63
|
+
files?: string[]
|
|
64
|
+
plan?: Record<string, any>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ClovingConfig = {
|
|
68
|
+
models: {
|
|
69
|
+
[provider: string]: {
|
|
70
|
+
[model: string]: ClovingModelConfig
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
globalSilent: boolean
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface LanguageConfig {
|
|
77
|
+
name: string
|
|
78
|
+
version?: string
|
|
79
|
+
primary?: boolean
|
|
80
|
+
directory: string
|
|
81
|
+
extension: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface FrameworkConfig {
|
|
85
|
+
name: string
|
|
86
|
+
type: string
|
|
87
|
+
version?: string
|
|
88
|
+
primary?: boolean
|
|
89
|
+
directory?: string
|
|
90
|
+
extension?: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface TestingFrameworkConfig {
|
|
94
|
+
name: string
|
|
95
|
+
type: string
|
|
96
|
+
version?: string
|
|
97
|
+
directory?: string
|
|
98
|
+
runCommand?: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface BuildToolConfig {
|
|
102
|
+
name: string
|
|
103
|
+
type: string
|
|
104
|
+
version?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface LinterConfig {
|
|
108
|
+
name: string
|
|
109
|
+
version?: string
|
|
110
|
+
type?: string
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface DatabaseConfig {
|
|
114
|
+
name: string
|
|
115
|
+
primary?: boolean
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface ClovingfileConfig {
|
|
119
|
+
languages: LanguageConfig[]
|
|
120
|
+
frameworks: FrameworkConfig[]
|
|
121
|
+
testingFrameworks?: TestingFrameworkConfig[]
|
|
122
|
+
buildTools: BuildToolConfig[]
|
|
123
|
+
packageManager: string
|
|
124
|
+
linters: LinterConfig[]
|
|
125
|
+
databases?: DatabaseConfig[]
|
|
126
|
+
projectType: string
|
|
127
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import unitTests from '../../../src/commands/generate/unit_tests';
|
|
2
|
+
import ClovingGPT from '../../../src/cloving_gpt';
|
|
3
|
+
|
|
4
|
+
jest.mock('../../../src/utils/git_utils', () => ({
|
|
5
|
+
getGitDiff: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
jest.mock('../../../src/cloving_gpt');
|
|
9
|
+
|
|
10
|
+
describe('unitTests', () => {
|
|
11
|
+
const mockOptions = { files: ['src/cloving_gpt/adapters/ollama.ts'], silent: true, save: true };
|
|
12
|
+
const mockGenerateText = jest.fn();
|
|
13
|
+
const gpt = new ClovingGPT(mockOptions);
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
(ClovingGPT as jest.Mock).mockImplementation(() => ({
|
|
17
|
+
generateText: mockGenerateText,
|
|
18
|
+
}));
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('should generate unit tests for provided files', async () => {
|
|
23
|
+
mockGenerateText.mockResolvedValueOnce('Generated unit tests content');
|
|
24
|
+
await unitTests(mockOptions);
|
|
25
|
+
expect(mockGenerateText).toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getGitDiff,
|
|
3
|
+
getDefaultBranchName,
|
|
4
|
+
getCurrentBranchName,
|
|
5
|
+
findCommitlintConfig,
|
|
6
|
+
generateCommitMessagePrompt,
|
|
7
|
+
readCommitlintConfig,
|
|
8
|
+
} from '../../src/utils/git_utils'
|
|
9
|
+
import { execSync } from 'child_process'
|
|
10
|
+
import fs from 'fs'
|
|
11
|
+
import path from 'path'
|
|
12
|
+
|
|
13
|
+
jest.mock('child_process', () => ({
|
|
14
|
+
execSync: jest.fn(),
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
jest.mock('fs', () => ({
|
|
18
|
+
existsSync: jest.fn(),
|
|
19
|
+
readFileSync: jest.fn(),
|
|
20
|
+
}))
|
|
21
|
+
|
|
22
|
+
describe('gitUtils', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('getDefaultBranchName should return the default branch name', async () => {
|
|
28
|
+
;(execSync as jest.Mock).mockReturnValueOnce('main\n')
|
|
29
|
+
const result = await getDefaultBranchName()
|
|
30
|
+
expect(result).toBe('main')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('getCurrentBranchName should return the current branch name', () => {
|
|
34
|
+
;(execSync as jest.Mock).mockReturnValueOnce('feature-branch\n')
|
|
35
|
+
const result = getCurrentBranchName()
|
|
36
|
+
expect(result).toBe('feature-branch')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('commitlint integration', () => {
|
|
40
|
+
test('findCommitlintConfig should return null when no config file exists', () => {
|
|
41
|
+
;(fs.existsSync as jest.Mock).mockReturnValue(false)
|
|
42
|
+
const result = findCommitlintConfig()
|
|
43
|
+
expect(result).toBeNull()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('findCommitlintConfig should return the path when a config file exists', () => {
|
|
47
|
+
;(fs.existsSync as jest.Mock).mockImplementation(
|
|
48
|
+
(path: string) => path === '.commitlintrc.json',
|
|
49
|
+
)
|
|
50
|
+
const result = findCommitlintConfig()
|
|
51
|
+
expect(result).toBe('.commitlintrc.json')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('readCommitlintConfig should parse JSON config files', () => {
|
|
55
|
+
const mockConfig = {
|
|
56
|
+
extends: ['@commitlint/config-conventional'],
|
|
57
|
+
rules: {
|
|
58
|
+
'type-enum': [2, 'always', ['feat', 'fix']],
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
;(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockConfig))
|
|
62
|
+
const result = readCommitlintConfig('.commitlintrc.json')
|
|
63
|
+
expect(result).toEqual(mockConfig)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('readCommitlintConfig should handle YAML config files', () => {
|
|
67
|
+
const mockYamlConfig = `
|
|
68
|
+
extends: ['@commitlint/config-conventional']
|
|
69
|
+
rules:
|
|
70
|
+
type-enum: [2, 'always', ['feat', 'fix']]
|
|
71
|
+
`
|
|
72
|
+
;(fs.readFileSync as jest.Mock).mockReturnValue(mockYamlConfig)
|
|
73
|
+
const result = readCommitlintConfig('.commitlintrc.yml')
|
|
74
|
+
expect(result).toEqual({ config: mockYamlConfig })
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('readCommitlintConfig should return null for JS/TS config files', () => {
|
|
78
|
+
const result = readCommitlintConfig('commitlint.config.js')
|
|
79
|
+
expect(result).toBeNull()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe('generateCommitMessagePrompt', () => {
|
|
83
|
+
test('should always include conventional commit format instructions', () => {
|
|
84
|
+
;(fs.existsSync as jest.Mock).mockReturnValue(false)
|
|
85
|
+
const diff = 'sample diff'
|
|
86
|
+
const result = generateCommitMessagePrompt(diff)
|
|
87
|
+
|
|
88
|
+
expect(result).toContain('<type>[optional scope]: <description>')
|
|
89
|
+
expect(result).toContain('Types must be one of:')
|
|
90
|
+
expect(result).toContain('feat: A new feature')
|
|
91
|
+
expect(result).toContain('fix: A bug fix')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('should include commitlint config when available', () => {
|
|
95
|
+
const mockConfig = {
|
|
96
|
+
extends: ['@commitlint/config-conventional'],
|
|
97
|
+
rules: {
|
|
98
|
+
'type-enum': [2, 'always', ['feat', 'fix']],
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
;(fs.existsSync as jest.Mock).mockImplementation(
|
|
102
|
+
(path: string) => path === '.commitlintrc.json',
|
|
103
|
+
)
|
|
104
|
+
;(fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(mockConfig))
|
|
105
|
+
|
|
106
|
+
const diff = 'sample diff'
|
|
107
|
+
const result = generateCommitMessagePrompt(diff)
|
|
108
|
+
|
|
109
|
+
expect(result).toContain('Found commitlint configuration at .commitlintrc.json')
|
|
110
|
+
expect(result).toContain('"extends":')
|
|
111
|
+
expect(result).toContain('"rules":')
|
|
112
|
+
expect(result).toContain('<type>[optional scope]: <description>')
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
import { getModel } from '../../src/utils/model_utils'
|
|
3
|
+
|
|
4
|
+
describe('modelUtils', () => {
|
|
5
|
+
const originalEnv = process.env
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.resetModules()
|
|
9
|
+
process.env = { ...originalEnv }
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterAll(() => {
|
|
13
|
+
process.env = originalEnv
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('getModel should return default model when CLOVING_MODEL is not set', () => {
|
|
17
|
+
delete process.env.CLOVING_MODEL
|
|
18
|
+
const result = getModel()
|
|
19
|
+
expect(result).toBe('claude:claude-3-5-sonnet-20240620')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('getModel should return CLOVING_MODEL when it is set', () => {
|
|
23
|
+
process.env.CLOVING_MODEL = 'openai:gpt-4'
|
|
24
|
+
const result = getModel()
|
|
25
|
+
expect(result).toBe('openai:gpt-4')
|
|
26
|
+
})
|
|
27
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { generateCodegenPrompt } from '../../src/utils/prompt_utils'
|
|
2
|
+
import { CODEGEN_INSTRUCTIONS } from '../../src/utils/prompts'
|
|
3
|
+
|
|
4
|
+
jest.mock('../../src/utils/config_utils', () => ({
|
|
5
|
+
getClovingConfig: jest.fn().mockReturnValue({}),
|
|
6
|
+
getNearestClovingConfig: jest.fn().mockReturnValue({ config: {}, path: '' }),
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
describe('prompt_utils', () => {
|
|
10
|
+
describe('CODEGEN_INSTRUCTIONS', () => {
|
|
11
|
+
it('should contain the correct instructions', () => {
|
|
12
|
+
expect(CODEGEN_INSTRUCTIONS).toContain('AI Code Generation Instructions')
|
|
13
|
+
expect(CODEGEN_INSTRUCTIONS).toContain('General Guidelines')
|
|
14
|
+
expect(CODEGEN_INSTRUCTIONS).toContain('Request Handling')
|
|
15
|
+
expect(CODEGEN_INSTRUCTIONS).toContain('*CURRENT/NEW* Block Format')
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('generateCodegenPrompt', () => {
|
|
20
|
+
it('should include CODEGEN_INSTRUCTIONS in the generated prompt', () => {
|
|
21
|
+
const contextFilesContent = { 'test.ts': 'console.log("test");' }
|
|
22
|
+
const result = generateCodegenPrompt(contextFilesContent)
|
|
23
|
+
expect(result).toContain(CODEGEN_INSTRUCTIONS)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should include context files content in the generated prompt', () => {
|
|
27
|
+
const contextFilesContent = { 'test.ts': 'console.log("test");' }
|
|
28
|
+
const result = generateCodegenPrompt(contextFilesContent)
|
|
29
|
+
expect(result).toContain('test.ts')
|
|
30
|
+
expect(result).toContain('console.log("test");')
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
})
|