scai 0.1.20 → 0.1.22
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/README.md +82 -87
- package/dist/commands/IndexCmd.js +26 -4
- package/dist/config.js +68 -0
- package/dist/constants.js +19 -0
- package/dist/db/client.js +2 -4
- package/dist/db/fileIndex.js +1 -1
- package/dist/index.js +71 -39
- package/dist/pipeline/modules/changeLogModule.js +2 -2
- package/dist/pipeline/modules/commentModule.js +3 -3
- package/dist/pipeline/modules/commitSuggesterModule.js +2 -2
- package/dist/pipeline/modules/generateTestsModule.js +3 -3
- package/dist/pipeline/modules/refactorModule.js +3 -3
- package/dist/pipeline/modules/summaryModule.js +2 -3
- package/package.json +1 -1
- package/dist/config/ModelConfig.js +0 -23
- /package/dist/{pipeline/types.js → types.js} +0 -0
package/README.md
CHANGED
|
@@ -1,150 +1,145 @@
|
|
|
1
1
|
# ⚙️ scai — Smart Commit AI ✨
|
|
2
2
|
|
|
3
|
-
> AI-powered CLI
|
|
3
|
+
> AI-powered CLI tool for smart commit messages, code comments, summaries, test generation, and changelogs — all powered by local models.
|
|
4
4
|
|
|
5
|
-
**scai** (Smart Commit AI) is a lightweight, privacy-focused CLI tool that
|
|
5
|
+
**scai** (Smart Commit AI) is a lightweight, privacy-focused CLI tool that helps developers work faster and cleaner:
|
|
6
6
|
|
|
7
7
|
- 💬 Suggest high-quality Git commit messages
|
|
8
8
|
- ✨ Automatically comment your code
|
|
9
9
|
- 🧠 Summarize code files instantly in the terminal
|
|
10
|
+
- 🧪 Generate test files for your code (JavaScript/TypeScript)
|
|
10
11
|
- 📝 Generate changelog entries based on Git diffs
|
|
11
|
-
- 🔒 100% local — no API keys, no cloud, no telemetry
|
|
12
|
+
- 🔒 100% local — no API keys, no cloud, no telemetry
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
## 🚀 Features
|
|
16
17
|
|
|
17
|
-
- ⚡️ Powered by local
|
|
18
|
-
- 🛠️
|
|
19
|
-
- 🔒 No external services
|
|
20
|
-
- ✅ Global options
|
|
18
|
+
- ⚡️ Powered by local AI models (e.g., `llama3`, `codellama`)
|
|
19
|
+
- 🛠️ Built with Node.js and TypeScript
|
|
20
|
+
- 🔒 No external services or APIs required
|
|
21
|
+
- ✅ Global options to select model and programming language
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
24
25
|
## ❤️ Why Local AI?
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
At scai, we believe your code — and your workflow — should stay **yours**. That's why we prioritize **local models** and **privacy-first** development:
|
|
27
28
|
|
|
28
|
-
✅
|
|
29
|
-
✅
|
|
30
|
-
✅
|
|
31
|
-
|
|
29
|
+
- ✅ **Local models**: scai runs entirely on your machine, with no need for cloud-based processing. We use open-source models like `llama3` and `codellama`, ensuring that your code stays private and secure.
|
|
30
|
+
- ✅ **Privacy by design**: We do not send your code to the cloud, store your data, or require API keys. Your data remains 100% local, ensuring full control over your project.
|
|
31
|
+
- ✅ **EU & Danish friendly**: As a Danish company, we are deeply committed to respecting European privacy regulations (GDPR). This means no data collection, no tracking, and full compliance with the strictest data protection laws.
|
|
32
|
+
|
|
33
|
+
By running everything locally, you can be sure that your sensitive code and workflows stay safe, private, and within your control.
|
|
34
|
+
|
|
35
|
+
---
|
|
32
36
|
|
|
33
37
|
## 📦 Installation
|
|
34
38
|
|
|
35
|
-
1. **Install
|
|
39
|
+
1. **Install Ollama:**
|
|
36
40
|
- On **Windows**: [Download Ollama](https://ollama.com/download)
|
|
37
|
-
- On **macOS**:
|
|
38
|
-
- Via Homebrew:
|
|
39
|
-
```bash
|
|
40
|
-
brew install ollama
|
|
41
|
-
```
|
|
42
|
-
- Or download directly from the website
|
|
41
|
+
- On **macOS**: via Homebrew (`brew install ollama`) or [download from Ollama](https://ollama.com)
|
|
43
42
|
|
|
44
|
-
2. **Install scai globally:**
|
|
43
|
+
2. **Install scai globally:**
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g scai
|
|
46
|
+
```
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
3. **Initialize the tool and models:**
|
|
49
|
+
```bash
|
|
50
|
+
scai init
|
|
51
|
+
```
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
This will download required models and set up scai.
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
scai init
|
|
54
|
-
```
|
|
55
|
+
---
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
- Start the Ollama background server
|
|
58
|
-
- Download required models (`llama3`, etc.)
|
|
57
|
+
## ⚒️ Usage Examples
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
### 🔧 Git Commands
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
- **Suggest a commit message:**
|
|
62
|
+
```bash
|
|
63
|
+
git add .
|
|
64
|
+
scai git sugg
|
|
65
|
+
```
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```
|
|
67
|
+
*Example output:*
|
|
68
|
+
```
|
|
69
|
+
feat(api): add error handling to user service
|
|
70
|
+
```
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
```
|
|
72
|
+
To commit automatically with the suggestion:
|
|
73
|
+
```bash
|
|
74
|
+
scai git sugg --commit
|
|
75
|
+
```
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
### 🛠️ Generate Code-Related Output (`gen` commands)
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
- **Summarize a code file:**
|
|
80
|
+
```bash
|
|
81
|
+
scai gen summ <file>
|
|
82
|
+
```
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
Prints a summary of what the code does directly in the terminal. You can also pipe file content:
|
|
85
|
+
```bash
|
|
86
|
+
cat <file> | scai gen summ
|
|
87
|
+
```
|
|
81
88
|
|
|
82
|
-
|
|
89
|
+
- **Generate tests for a code file:**
|
|
90
|
+
```bash
|
|
91
|
+
scai gen tests <file>
|
|
92
|
+
```
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
scai comm <file>
|
|
86
|
-
```
|
|
94
|
+
Creates a Jest test file for the specified JavaScript/TypeScript module.
|
|
87
95
|
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
- **Update the changelog:**
|
|
97
|
+
```bash
|
|
98
|
+
scai gen changelog
|
|
99
|
+
```
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
### 🔍 Summarize a code file
|
|
101
|
+
Analyzes the current Git diff and updates (or creates) a `CHANGELOG.md` file with relevant changes.
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
scai summ <file>
|
|
97
|
-
```
|
|
103
|
+
## ⚙️ Configuration
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
scai stores your configuration locally in the `~/.scai/config.json` file. You can configure the model and programming language settings as follows:
|
|
100
106
|
|
|
101
|
-
|
|
107
|
+
- **Set the model:**
|
|
108
|
+
```bash
|
|
109
|
+
scai set model <model>
|
|
110
|
+
```
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
cat <file> | scai summ
|
|
105
|
-
```
|
|
112
|
+
e.g., `scai set model codellama:7b`
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
- **Set the programming language:**
|
|
115
|
+
```bash
|
|
116
|
+
scai set lang <lang>
|
|
117
|
+
```
|
|
108
118
|
|
|
109
|
-
|
|
119
|
+
e.g., `scai set lang rust`
|
|
110
120
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
- **Show current configuration:**
|
|
122
|
+
```bash
|
|
123
|
+
scai config
|
|
124
|
+
```
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
You can also use global options `--model` and `--lang` with any command to override the settings:
|
|
127
|
+
```bash
|
|
128
|
+
scai --model codellama:34b --lang ts git sugg
|
|
129
|
+
```
|
|
116
130
|
|
|
117
131
|
---
|
|
118
132
|
|
|
119
|
-
### 📦 Module Pipeline (Advanced Usage)
|
|
120
|
-
|
|
121
|
-
For more advanced functionality, scai allows you to run custom pipelines with multiple modules to process code. You can specify multiple modules to be run, such as comment, summary, cleanup, and more.
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
scai <file> --modules comment,summary,cleanup
|
|
125
|
-
```
|
|
126
|
-
Like with regular Unix commands you can pipe this to a file
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
scai <file> --modules comment,summary > test.txt
|
|
130
|
-
```
|
|
131
|
-
Or to both stdout and a file with tee fx.
|
|
132
|
-
```bash
|
|
133
|
-
scai <file> --modules comment,summary | tee test.txt
|
|
134
|
-
```
|
|
135
|
-
|
|
136
133
|
## 🔐 License & Fair Use
|
|
137
134
|
|
|
138
135
|
**scai is free to use** for individuals, teams, and companies — including in commercial work.
|
|
139
136
|
|
|
140
137
|
You may:
|
|
141
|
-
|
|
142
138
|
- ✅ Use it internally in your projects
|
|
143
139
|
- ✅ Use it at work or in commercial development
|
|
144
140
|
- ✅ Share and recommend it
|
|
145
141
|
|
|
146
142
|
But you may not:
|
|
147
|
-
|
|
148
143
|
- ❌ Repackage or resell **scai** as a product or SaaS
|
|
149
144
|
- ❌ Claim ownership of the tool
|
|
150
145
|
|
|
@@ -6,15 +6,37 @@ import { shouldIgnoreFile } from '../utils/shouldIgnoreFiles.js';
|
|
|
6
6
|
import { detectFileType } from '../utils/detectFileType.js';
|
|
7
7
|
import { runDaemonScheduler } from './DaemonCmd.js';
|
|
8
8
|
import { IGNORED_FOLDER_GLOBS } from '../config/IgnoredPaths.js';
|
|
9
|
+
import { db } from '../db/client.js';
|
|
9
10
|
const IGNORE = [
|
|
10
11
|
'**/node_modules/**', '**/dist/**', '**/build/**',
|
|
11
12
|
'**/coverage/**', '**/.git/**', '**/*.test.*'
|
|
12
13
|
];
|
|
13
14
|
export async function runIndexCommand(targetDir = process.cwd(), options = {}) {
|
|
14
|
-
|
|
15
|
+
const resolvedDir = path.resolve(targetDir);
|
|
16
|
+
console.log(`📂 Indexing files in: ${resolvedDir}`);
|
|
15
17
|
initSchema();
|
|
18
|
+
// 🧠 Check if another directory has already been indexed
|
|
19
|
+
const indexedPaths = db.prepare(`
|
|
20
|
+
SELECT DISTINCT path FROM files LIMIT 100
|
|
21
|
+
`).all();
|
|
22
|
+
const knownRoot = indexedPaths.length > 0
|
|
23
|
+
? path.dirname(indexedPaths[0].path)
|
|
24
|
+
: null;
|
|
25
|
+
if (knownRoot && !resolvedDir.startsWith(knownRoot) && !options.force) {
|
|
26
|
+
console.warn(`⚠️ You're indexing a different folder than before:
|
|
27
|
+
- Previously: ${knownRoot}
|
|
28
|
+
- Now: ${resolvedDir}
|
|
29
|
+
|
|
30
|
+
This will add more files into the existing index and may reduce accuracy or performance.
|
|
31
|
+
|
|
32
|
+
Use --force to continue, or consider clearing the index:
|
|
33
|
+
scai reset-db
|
|
34
|
+
|
|
35
|
+
Aborting.`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
16
38
|
const files = await fg('**/*.*', {
|
|
17
|
-
cwd:
|
|
39
|
+
cwd: resolvedDir,
|
|
18
40
|
ignore: IGNORED_FOLDER_GLOBS,
|
|
19
41
|
absolute: true,
|
|
20
42
|
});
|
|
@@ -28,7 +50,7 @@ export async function runIndexCommand(targetDir = process.cwd(), options = {}) {
|
|
|
28
50
|
indexFile(file, null, type); // empty summary for now
|
|
29
51
|
const ext = path.extname(file);
|
|
30
52
|
countByExt[ext] = (countByExt[ext] || 0) + 1;
|
|
31
|
-
console.log(`📄 Indexed: ${path.relative(
|
|
53
|
+
console.log(`📄 Indexed: ${path.relative(resolvedDir, file)}`);
|
|
32
54
|
count++;
|
|
33
55
|
}
|
|
34
56
|
catch (err) {
|
|
@@ -39,6 +61,6 @@ export async function runIndexCommand(targetDir = process.cwd(), options = {}) {
|
|
|
39
61
|
console.log(`✅ Done. Indexed ${count} files.`);
|
|
40
62
|
if (options.detached) {
|
|
41
63
|
console.log('🚀 Starting summarizer daemon in background mode...');
|
|
42
|
-
runDaemonScheduler();
|
|
64
|
+
runDaemonScheduler();
|
|
43
65
|
}
|
|
44
66
|
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { CONFIG_PATH, SCAI_HOME, INDEX_DIR } from './constants.js'; // Correctly import INDEX_DIR from constants
|
|
3
|
+
// Default configuration values
|
|
4
|
+
const defaultConfig = {
|
|
5
|
+
model: 'llama3',
|
|
6
|
+
language: 'ts',
|
|
7
|
+
indexDir: INDEX_DIR, // Default index directory from constants
|
|
8
|
+
};
|
|
9
|
+
// Function to ensure the configuration directory exists
|
|
10
|
+
function ensureConfigDir() {
|
|
11
|
+
if (!fs.existsSync(SCAI_HOME)) {
|
|
12
|
+
fs.mkdirSync(SCAI_HOME, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Function to read the configuration file
|
|
16
|
+
function readConfig() {
|
|
17
|
+
try {
|
|
18
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
19
|
+
return { ...defaultConfig, ...JSON.parse(content) };
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return defaultConfig; // Return default config if read fails
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Function to write the configuration to the config file
|
|
26
|
+
function writeConfig(newConfig) {
|
|
27
|
+
ensureConfigDir();
|
|
28
|
+
const current = readConfig();
|
|
29
|
+
const merged = { ...current, ...newConfig };
|
|
30
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2));
|
|
31
|
+
}
|
|
32
|
+
export const Config = {
|
|
33
|
+
// Get the current model from the config
|
|
34
|
+
getModel() {
|
|
35
|
+
return readConfig().model;
|
|
36
|
+
},
|
|
37
|
+
// Set a new model in the config
|
|
38
|
+
setModel(model) {
|
|
39
|
+
writeConfig({ model });
|
|
40
|
+
console.log(`📦 Model set to: ${model}`);
|
|
41
|
+
},
|
|
42
|
+
// Get the current language from the config
|
|
43
|
+
getLanguage() {
|
|
44
|
+
return readConfig().language;
|
|
45
|
+
},
|
|
46
|
+
// Set a new language in the config
|
|
47
|
+
setLanguage(language) {
|
|
48
|
+
writeConfig({ language });
|
|
49
|
+
console.log(`🗣️ Language set to: ${language}`);
|
|
50
|
+
},
|
|
51
|
+
// Get the index directory from the config
|
|
52
|
+
getIndexDir() {
|
|
53
|
+
return readConfig().indexDir;
|
|
54
|
+
},
|
|
55
|
+
// Set a new index directory in the config
|
|
56
|
+
setIndexDir(indexDir) {
|
|
57
|
+
writeConfig({ indexDir });
|
|
58
|
+
console.log(`📁 Index directory set to: ${indexDir}`);
|
|
59
|
+
},
|
|
60
|
+
// Show the current configuration
|
|
61
|
+
show() {
|
|
62
|
+
const cfg = readConfig();
|
|
63
|
+
console.log(`🔧 Current configuration:`);
|
|
64
|
+
console.log(` Model : ${cfg.model}`);
|
|
65
|
+
console.log(` Language : ${cfg.language}`);
|
|
66
|
+
console.log(` Index dir : ${cfg.indexDir}`);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
export const SCAI_HOME = path.join(os.homedir(), '.scai');
|
|
5
|
+
export const DB_PATH = path.join(SCAI_HOME, 'db.sqlite');
|
|
6
|
+
export const PID_PATH = path.join(SCAI_HOME, 'daemon.pid');
|
|
7
|
+
export const CONFIG_PATH = path.join(SCAI_HOME, 'config.json');
|
|
8
|
+
// Function to read config and get the indexDir on-demand
|
|
9
|
+
export function getIndexDir() {
|
|
10
|
+
try {
|
|
11
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
12
|
+
return config.indexDir || path.join(os.homedir(), 'defaultIndex'); // Default if not set
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
return path.join(os.homedir(), 'defaultIndex'); // Fallback if no config file
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// On-demand index directory retrieval
|
|
19
|
+
export const INDEX_DIR = getIndexDir();
|
package/dist/db/client.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
-
import path from 'path';
|
|
3
2
|
import fs from 'fs';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
3
|
+
import { DB_PATH, SCAI_HOME } from '../constants.js';
|
|
4
|
+
fs.mkdirSync(SCAI_HOME, { recursive: true });
|
|
7
5
|
export const db = new Database(DB_PATH);
|
package/dist/db/fileIndex.js
CHANGED
|
@@ -17,7 +17,7 @@ export function indexFile(filePath, summary, type) {
|
|
|
17
17
|
// Step 2: Insert into FTS with the same id
|
|
18
18
|
db.prepare(sqlTemplates.insertIntoFtsTemplate).run({ path: filePath, summary });
|
|
19
19
|
}
|
|
20
|
-
export function queryFiles(query, limit =
|
|
20
|
+
export function queryFiles(query, limit = 10) {
|
|
21
21
|
// Sanitize the query by removing or escaping special characters
|
|
22
22
|
const safeQuery = query
|
|
23
23
|
.trim()
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { Config } from './config.js';
|
|
4
5
|
import { createRequire } from 'module';
|
|
5
6
|
const require = createRequire(import.meta.url);
|
|
6
7
|
const { version } = require('../package.json');
|
|
7
|
-
//
|
|
8
|
+
// 🧠 Commands
|
|
8
9
|
import { checkEnv } from "./commands/EnvCmd.js";
|
|
9
10
|
import { checkGit } from "./commands/GitCmd.js";
|
|
10
11
|
import { suggestCommitMessage } from "./commands/CommitSuggesterCmd.js";
|
|
11
12
|
import { handleRefactor } from "./commands/RefactorCmd.js";
|
|
12
13
|
import { generateTests } from "./commands/TestGenCmd.js";
|
|
13
14
|
import { bootstrap } from './modelSetup.js';
|
|
14
|
-
import { ModelConfig } from './config/ModelConfig.js';
|
|
15
15
|
import { summarizeFile } from "./commands/SummaryCmd.js";
|
|
16
16
|
import { handleChangelogUpdate } from './commands/ChangeLogUpdateCmd.js';
|
|
17
17
|
import { runModulePipelineFromCLI } from './commands/ModulePipelineCmd.js';
|
|
@@ -21,12 +21,12 @@ import { runQueryCommand } from './commands/QueryCmd.js';
|
|
|
21
21
|
import { runDaemonBatch } from './commands/DaemonCmd.js';
|
|
22
22
|
import { runStopDaemonCommand } from "./commands/StopDaemonCmd.js";
|
|
23
23
|
import { runAskCommand } from './commands/AskCmd.js';
|
|
24
|
-
//
|
|
24
|
+
// 🎛️ CLI Setup
|
|
25
25
|
const cmd = new Command('scai')
|
|
26
26
|
.version(version)
|
|
27
27
|
.option('--model <model>', 'Set the model to use (e.g., codellama:34b)')
|
|
28
28
|
.option('--lang <lang>', 'Set the target language (ts, java, rust)');
|
|
29
|
-
//
|
|
29
|
+
// 🚀 Init command
|
|
30
30
|
cmd
|
|
31
31
|
.command('init')
|
|
32
32
|
.description('Initialize the model and download required models')
|
|
@@ -34,77 +34,109 @@ cmd
|
|
|
34
34
|
await bootstrap();
|
|
35
35
|
console.log('✅ Model initialization completed!');
|
|
36
36
|
});
|
|
37
|
-
|
|
37
|
+
// 🔧 Group: Git-related commands
|
|
38
|
+
const git = cmd.command('git').description('Git utilities');
|
|
39
|
+
git
|
|
40
|
+
.command('status')
|
|
41
|
+
.description('Check Git status')
|
|
42
|
+
.action(checkGit);
|
|
43
|
+
git
|
|
38
44
|
.command('sugg')
|
|
39
45
|
.description('Suggest a commit message from staged changes')
|
|
40
46
|
.option('-c, --commit', 'Automatically commit with suggested message')
|
|
41
47
|
.action(suggestCommitMessage);
|
|
42
|
-
|
|
48
|
+
// 🛠️ Group: `gen` commands for content generation
|
|
49
|
+
const gen = cmd.command('gen').description('Generate code-related output');
|
|
50
|
+
gen
|
|
43
51
|
.command('comm <file>')
|
|
44
52
|
.description('Write comments for the given file')
|
|
45
53
|
.option('-a, --apply', 'Apply the refactored version to the original file')
|
|
46
54
|
.action((file, options) => handleRefactor(file, options));
|
|
47
|
-
|
|
55
|
+
gen
|
|
48
56
|
.command('changelog')
|
|
49
57
|
.description('Update or create the CHANGELOG.md based on current Git diff')
|
|
50
58
|
.action(async () => {
|
|
51
59
|
await handleChangelogUpdate();
|
|
52
60
|
});
|
|
53
|
-
|
|
61
|
+
gen
|
|
54
62
|
.command('summ [file]')
|
|
55
63
|
.description('Print a summary of the given file to the terminal')
|
|
56
64
|
.action((file) => summarizeFile(file));
|
|
65
|
+
gen
|
|
66
|
+
.command('tests <file>')
|
|
67
|
+
.description('Generate a Jest test file for the specified JS/TS module')
|
|
68
|
+
.action((file) => generateTests(file));
|
|
69
|
+
// 🔍 Indexing
|
|
57
70
|
cmd
|
|
58
|
-
.command('
|
|
59
|
-
.description('
|
|
60
|
-
.
|
|
71
|
+
.command('index [targetDir]')
|
|
72
|
+
.description('Index supported files in the given directory (or current folder if none)')
|
|
73
|
+
.option('-d, --detached', 'Run summarizer daemon after indexing')
|
|
74
|
+
.option('--force', 'Force indexing even if another folder has already been indexed')
|
|
75
|
+
.action((targetDir, options) => {
|
|
76
|
+
const resolvedDir = targetDir ? path.resolve(targetDir) : process.cwd();
|
|
77
|
+
runIndexCommand(resolvedDir, { detached: options.detached, force: options.force });
|
|
78
|
+
});
|
|
79
|
+
// ⚙️ Group: Configuration settings
|
|
80
|
+
const set = cmd.command('set').description('Set configuration values');
|
|
81
|
+
set
|
|
82
|
+
.command('model <model>')
|
|
83
|
+
.description('Set the model to use')
|
|
84
|
+
.action((model) => {
|
|
85
|
+
Config.setModel(model);
|
|
86
|
+
Config.show();
|
|
87
|
+
});
|
|
88
|
+
set
|
|
89
|
+
.command('lang <lang>')
|
|
90
|
+
.description('Set the programming language')
|
|
91
|
+
.action((lang) => {
|
|
92
|
+
Config.setLanguage(lang);
|
|
93
|
+
Config.show();
|
|
94
|
+
});
|
|
95
|
+
set
|
|
96
|
+
.command('index-dir <dir>')
|
|
97
|
+
.description('Set the path to the indexed directory')
|
|
98
|
+
.action((dir) => {
|
|
99
|
+
Config.setIndexDir(path.resolve(dir));
|
|
100
|
+
Config.show();
|
|
101
|
+
});
|
|
102
|
+
// 🧪 Diagnostics and info
|
|
61
103
|
cmd
|
|
62
104
|
.command('env')
|
|
63
105
|
.description('Check environment variables')
|
|
64
106
|
.action(checkEnv);
|
|
65
|
-
cmd
|
|
66
|
-
.command('gen-tests <file>')
|
|
67
|
-
.description('Generate a Jest test file for the specified JS/TS module')
|
|
68
|
-
.action((file) => generateTests(file));
|
|
69
107
|
cmd
|
|
70
108
|
.command('config')
|
|
71
109
|
.description('Show the currently active model and language settings')
|
|
72
110
|
.action(() => {
|
|
73
|
-
|
|
74
|
-
});
|
|
75
|
-
cmd
|
|
76
|
-
.command('daemon')
|
|
77
|
-
.description('Run background summarization of indexed files')
|
|
78
|
-
.action(runDaemonBatch);
|
|
79
|
-
cmd
|
|
80
|
-
.command('stop-daemon')
|
|
81
|
-
.description('Stop the background summarizer daemon')
|
|
82
|
-
.action(runStopDaemonCommand);
|
|
83
|
-
cmd
|
|
84
|
-
.command('index [targetDir]')
|
|
85
|
-
.description('Index supported files in the given directory (or current folder if none)')
|
|
86
|
-
.option('-d, --detached', 'Run summarizer daemon after indexing')
|
|
87
|
-
.action((targetDir, options) => {
|
|
88
|
-
runIndexCommand(targetDir, { detached: options.detached });
|
|
111
|
+
Config.show();
|
|
89
112
|
});
|
|
113
|
+
// 🧠 Query and assistant
|
|
90
114
|
cmd
|
|
91
115
|
.command('query <query>')
|
|
92
116
|
.description('Search indexed files by keyword')
|
|
93
117
|
.action(runQueryCommand);
|
|
94
|
-
// Command structure using Commander
|
|
95
118
|
cmd
|
|
96
119
|
.command('ask')
|
|
97
120
|
.description('Ask a question using file summaries and a local model')
|
|
98
121
|
.argument('<question...>', 'The question to ask')
|
|
99
122
|
.action((question) => {
|
|
100
123
|
const q = question.join(' ');
|
|
101
|
-
runAskCommand(q);
|
|
124
|
+
runAskCommand(q);
|
|
102
125
|
});
|
|
126
|
+
// 🛠️ Background tasks and maintenance
|
|
127
|
+
cmd
|
|
128
|
+
.command('daemon')
|
|
129
|
+
.description('Run background summarization of indexed files')
|
|
130
|
+
.action(runDaemonBatch);
|
|
131
|
+
cmd
|
|
132
|
+
.command('stop-daemon')
|
|
133
|
+
.description('Stop the background summarizer daemon')
|
|
134
|
+
.action(runStopDaemonCommand);
|
|
103
135
|
cmd
|
|
104
136
|
.command('reset-db')
|
|
105
137
|
.description('Delete and reset the SQLite database')
|
|
106
138
|
.action(() => resetDatabase());
|
|
107
|
-
//
|
|
139
|
+
// 🧬 Fallback: Pipeline mode
|
|
108
140
|
cmd
|
|
109
141
|
.arguments('<file>')
|
|
110
142
|
.option('-m, --modules <modules>', 'Comma-separated list of modules to run (e.g., comments,cleanup,summary)')
|
|
@@ -115,11 +147,11 @@ cmd
|
|
|
115
147
|
}
|
|
116
148
|
runModulePipelineFromCLI(file, options);
|
|
117
149
|
});
|
|
118
|
-
// ✅
|
|
150
|
+
// ✅ Parse CLI args
|
|
119
151
|
cmd.parse(process.argv);
|
|
120
|
-
//
|
|
152
|
+
// 🔁 Apply global options post-parse
|
|
121
153
|
const opts = cmd.opts();
|
|
122
154
|
if (opts.model)
|
|
123
|
-
|
|
155
|
+
Config.setModel(opts.model);
|
|
124
156
|
if (opts.lang)
|
|
125
|
-
|
|
157
|
+
Config.setLanguage(opts.lang);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from '../../config.js';
|
|
2
2
|
import { generate } from '../../lib/generate.js';
|
|
3
3
|
export const changelogModule = {
|
|
4
4
|
name: 'changelogModule',
|
|
5
5
|
description: 'Generates changelog entry based on Git diff',
|
|
6
6
|
async run(input) {
|
|
7
|
-
const model =
|
|
7
|
+
const model = Config.getModel();
|
|
8
8
|
const prompt = `
|
|
9
9
|
You're an experienced changelog writer. Based on this Git diff, write a markdown bullet-point entry suitable for CHANGELOG.md:
|
|
10
10
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from '../../config.js';
|
|
2
2
|
import { generate } from '../../lib/generate.js';
|
|
3
3
|
export const addCommentsModule = {
|
|
4
4
|
name: 'addComments',
|
|
5
5
|
description: 'Adds meaningful // comments to each block of code',
|
|
6
6
|
async run(input) {
|
|
7
|
-
const model =
|
|
8
|
-
const lang =
|
|
7
|
+
const model = Config.getModel();
|
|
8
|
+
const lang = Config.getLanguage();
|
|
9
9
|
const prompt = `
|
|
10
10
|
You are a senior ${lang.toUpperCase()} engineer reviewing source code.
|
|
11
11
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { generate } from '../../lib/generate.js';
|
|
2
|
-
import {
|
|
2
|
+
import { Config } from '../../config.js';
|
|
3
3
|
export const commitSuggesterModule = {
|
|
4
4
|
name: 'commitSuggester',
|
|
5
5
|
description: 'Suggests conventional commit messages from Git diff',
|
|
6
6
|
async run({ content }) {
|
|
7
|
-
const model =
|
|
7
|
+
const model = Config.getModel();
|
|
8
8
|
const prompt = `
|
|
9
9
|
Suggest ALWAYS 3 concise, conventional Git commit messages based on the input code diff.
|
|
10
10
|
Use this format ONLY:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// src/pipeline/modules/generateTestsModule.ts
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import { Config } from '../../config.js';
|
|
5
5
|
import { generate } from '../../lib/generate.js';
|
|
6
6
|
export const generateTestsModule = {
|
|
7
7
|
name: 'generateTests',
|
|
8
8
|
description: 'Generate a Jest test file for the class/module',
|
|
9
9
|
async run({ content, filepath }) {
|
|
10
|
-
const model =
|
|
11
|
-
const lang =
|
|
10
|
+
const model = Config.getModel();
|
|
11
|
+
const lang = Config.getLanguage();
|
|
12
12
|
if (!filepath)
|
|
13
13
|
throw new Error('Missing filepath in pipeline context');
|
|
14
14
|
const prompt = `
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from '../../config.js';
|
|
2
2
|
import { generate } from '../../lib/generate.js';
|
|
3
3
|
export const refactorModule = {
|
|
4
4
|
name: 'refactor',
|
|
5
5
|
description: 'Break code into small, clean functions',
|
|
6
6
|
async run(input) {
|
|
7
|
-
const model =
|
|
8
|
-
const lang =
|
|
7
|
+
const model = Config.getModel();
|
|
8
|
+
const lang = Config.getLanguage();
|
|
9
9
|
const prompt = `
|
|
10
10
|
You are a senior ${lang.toUpperCase()} engineer.
|
|
11
11
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Config } from '../../config.js';
|
|
2
2
|
import { generate } from '../../lib/generate.js';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
export const summaryModule = {
|
|
5
5
|
name: 'summary',
|
|
6
6
|
description: 'Generates a general summary of any file content.',
|
|
7
7
|
run: async ({ content, filepath }) => {
|
|
8
|
-
const model =
|
|
8
|
+
const model = Config.getModel();
|
|
9
9
|
const ext = filepath ? path.extname(filepath).toLowerCase() : '';
|
|
10
10
|
const filename = filepath ? path.basename(filepath) : '';
|
|
11
11
|
// More neutral prompt for general-purpose content
|
|
@@ -36,7 +36,6 @@ ${content}
|
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
38
|
console.warn('⚠️ No summary generated.');
|
|
39
|
-
response.summary = '⚠️ No summary generated.';
|
|
40
39
|
}
|
|
41
40
|
return response;
|
|
42
41
|
}
|
package/package.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export class ModelConfig {
|
|
2
|
-
static setModel(model) {
|
|
3
|
-
this.model = model;
|
|
4
|
-
console.log(`📦 Model set to: ${model}`);
|
|
5
|
-
}
|
|
6
|
-
static getModel() {
|
|
7
|
-
return this.model;
|
|
8
|
-
}
|
|
9
|
-
static setLanguage(lang) {
|
|
10
|
-
this.language = lang;
|
|
11
|
-
console.log(`🗣️ Language set to: ${lang}`);
|
|
12
|
-
}
|
|
13
|
-
static getLanguage() {
|
|
14
|
-
return this.language;
|
|
15
|
-
}
|
|
16
|
-
static logCurrentConfig() {
|
|
17
|
-
console.log(`🔧 Current configuration:`);
|
|
18
|
-
console.log(` Model : ${this.model}`);
|
|
19
|
-
console.log(` Language: ${this.language}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
ModelConfig.model = 'llama3';
|
|
23
|
-
ModelConfig.language = 'ts';
|
|
File without changes
|