scai 0.1.16 โ 0.1.18
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 +9 -0
- package/dist/commands/IndexCmd.js +45 -0
- package/dist/commands/ResetDbCmd.js +27 -0
- package/dist/commands/SummaryCmd.js +1 -1
- package/dist/db/client.js +7 -0
- package/dist/db/fileIndex.js +18 -0
- package/dist/db/schema.js +13 -0
- package/dist/index.js +12 -0
- package/dist/pipeline/modules/commentModule.js +2 -2
- package/dist/pipeline/modules/commitSuggesterModule.js +1 -1
- package/dist/pipeline/modules/summaryModule.js +31 -9
- package/dist/utils/getSummary.js +31 -0
- package/dist/utils/languageConfig.js +7 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -123,6 +123,15 @@ For more advanced functionality, scai allows you to run custom pipelines with mu
|
|
|
123
123
|
```bash
|
|
124
124
|
scai <file> --modules comment,summary,cleanup
|
|
125
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
|
+
```
|
|
126
135
|
|
|
127
136
|
## ๐ License & Fair Use
|
|
128
137
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { ModelConfig } from '../config/ModelConfig.js';
|
|
4
|
+
import { initSchema } from '../db/schema.js';
|
|
5
|
+
import { indexFile } from '../db/fileIndex.js';
|
|
6
|
+
import { getSummary } from '../utils/getSummary.js';
|
|
7
|
+
import { EXTENSIONS_BY_LANG } from '../utils/languageConfig.js';
|
|
8
|
+
const IGNORE = [
|
|
9
|
+
'**/node_modules/**',
|
|
10
|
+
'**/dist/**',
|
|
11
|
+
'**/build/**',
|
|
12
|
+
'**/coverage/**',
|
|
13
|
+
'**/.git/**',
|
|
14
|
+
'**/*.test.*'
|
|
15
|
+
];
|
|
16
|
+
export async function runIndexCommand(targetDir = process.cwd()) {
|
|
17
|
+
console.log(`๐ Indexing files in: ${targetDir}`);
|
|
18
|
+
initSchema();
|
|
19
|
+
const lang = ModelConfig.getLanguage();
|
|
20
|
+
const exts = EXTENSIONS_BY_LANG[lang] || ['.txt'];
|
|
21
|
+
const patterns = exts.map(ext => `**/*${ext}`);
|
|
22
|
+
const files = await fg(patterns, {
|
|
23
|
+
cwd: targetDir,
|
|
24
|
+
ignore: IGNORE,
|
|
25
|
+
absolute: true,
|
|
26
|
+
});
|
|
27
|
+
// Count file extensions (diagnostic)
|
|
28
|
+
const countByExt = {};
|
|
29
|
+
files.forEach(file => {
|
|
30
|
+
const ext = path.extname(file);
|
|
31
|
+
countByExt[ext] = (countByExt[ext] || 0) + 1;
|
|
32
|
+
});
|
|
33
|
+
console.log('๐ Indexed files by extension:', countByExt);
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
try {
|
|
36
|
+
const summary = getSummary(file, lang);
|
|
37
|
+
indexFile(file, summary, lang);
|
|
38
|
+
console.log(`๐ Indexed: ${path.relative(targetDir, file)}`);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.warn(`โ ๏ธ Skipped ${file}:`, err instanceof Error ? err.message : err);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
console.log(`โ
Done. Indexed ${files.length} files.`);
|
|
45
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { db } from '../db/client.js';
|
|
4
|
+
export function resetDatabase() {
|
|
5
|
+
const dbPath = path.resolve(process.cwd(), '.scai/db.sqlite');
|
|
6
|
+
try {
|
|
7
|
+
db.close(); // ๐ Make sure the DB is closed
|
|
8
|
+
console.log('๐ Closed SQLite database connection.');
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
console.warn('โ ๏ธ Could not close database:', err);
|
|
12
|
+
}
|
|
13
|
+
if (fs.existsSync(dbPath)) {
|
|
14
|
+
try {
|
|
15
|
+
fs.unlinkSync(dbPath);
|
|
16
|
+
console.log('๐งน Deleted existing database.');
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
console.error('โ Failed to delete DB file:', err instanceof Error ? err.message : err);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log('โน๏ธ No existing database found.');
|
|
25
|
+
}
|
|
26
|
+
console.log('โ
Database has been reset. You can now re-run: scai index');
|
|
27
|
+
}
|
|
@@ -29,7 +29,7 @@ export async function summarizeFile(filepath) {
|
|
|
29
29
|
}
|
|
30
30
|
if (code.trim()) {
|
|
31
31
|
// Call the summary module to get the raw summary
|
|
32
|
-
const summary = await summaryModule.run({ code });
|
|
32
|
+
const summary = await summaryModule.run({ code, filepath });
|
|
33
33
|
// Pass the summary text to the utility function for formatting
|
|
34
34
|
const formattedSummary = summarizeCode(summary.code);
|
|
35
35
|
console.log(formattedSummary);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
const DB_PATH = path.resolve(process.cwd(), '.scai/db.sqlite');
|
|
5
|
+
// Ensure directory exists
|
|
6
|
+
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
7
|
+
export const db = new Database(DB_PATH);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { db } from './client.js';
|
|
2
|
+
export function indexFile(filePath, summary, lang) {
|
|
3
|
+
const insertStmt = db.prepare(`
|
|
4
|
+
INSERT OR REPLACE INTO files (path, summary, lang, indexed_at)
|
|
5
|
+
VALUES (?, ?, ?, datetime('now'))
|
|
6
|
+
`);
|
|
7
|
+
insertStmt.run(filePath, summary, lang);
|
|
8
|
+
}
|
|
9
|
+
export function searchFiles(query, limit = 10) {
|
|
10
|
+
const stmt = db.prepare(`
|
|
11
|
+
SELECT path, summary FROM files
|
|
12
|
+
WHERE path LIKE ? OR summary LIKE ?
|
|
13
|
+
ORDER BY indexed_at DESC
|
|
14
|
+
LIMIT ?
|
|
15
|
+
`);
|
|
16
|
+
const wildcard = `%${query}%`;
|
|
17
|
+
return stmt.all(wildcard, wildcard, limit);
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { db } from './client.js';
|
|
2
|
+
export function initSchema() {
|
|
3
|
+
db.exec(`
|
|
4
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
5
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
6
|
+
path TEXT UNIQUE,
|
|
7
|
+
summary TEXT,
|
|
8
|
+
lang TEXT,
|
|
9
|
+
indexed_at TEXT
|
|
10
|
+
);
|
|
11
|
+
`);
|
|
12
|
+
console.log('โ
SQLite schema initialized');
|
|
13
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@ 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';
|
|
18
|
+
import { runIndexCommand } from './commands/IndexCmd.js';
|
|
19
|
+
import { resetDatabase } from './commands/ResetDbCmd.js';
|
|
18
20
|
// Create the CLI instance
|
|
19
21
|
const cmd = new Command('scai')
|
|
20
22
|
.version(version)
|
|
@@ -66,6 +68,16 @@ cmd
|
|
|
66
68
|
.action(() => {
|
|
67
69
|
ModelConfig.logCurrentConfig();
|
|
68
70
|
});
|
|
71
|
+
cmd
|
|
72
|
+
.command('index [targetDir]')
|
|
73
|
+
.description('Index supported files in the given directory (or current folder if none)')
|
|
74
|
+
.action((targetDir) => {
|
|
75
|
+
runIndexCommand(targetDir);
|
|
76
|
+
});
|
|
77
|
+
cmd
|
|
78
|
+
.command('reset-db')
|
|
79
|
+
.description('Delete and reset the SQLite database')
|
|
80
|
+
.action(() => resetDatabase());
|
|
69
81
|
cmd
|
|
70
82
|
.arguments('<file>')
|
|
71
83
|
.option('-m, --modules <modules>', 'Comma-separated list of modules to run (e.g., comments,cleanup,summary)')
|
|
@@ -9,12 +9,12 @@ export const addCommentsModule = {
|
|
|
9
9
|
const prompt = `
|
|
10
10
|
You are a senior ${lang.toUpperCase()} engineer reviewing source code.
|
|
11
11
|
|
|
12
|
-
Your task is to add clear and
|
|
12
|
+
Your task is to add clear and insightful single-line comments to the code.
|
|
13
13
|
|
|
14
14
|
โ ๏ธ VERY IMPORTANT RULES:
|
|
15
15
|
- You MUST return the ENTIRE original code.
|
|
16
16
|
- You MUST NOT remove, replace, reformat, or alter ANY code.
|
|
17
|
-
- Only add single-line // comments
|
|
17
|
+
- Only add single-line // comments to complex or non-obvious parts of the code.
|
|
18
18
|
- Do NOT wrap the code in markdown or code blocks.
|
|
19
19
|
- The code should be valid ${lang.toUpperCase()} after your changes.
|
|
20
20
|
|
|
@@ -6,7 +6,7 @@ export const commitSuggesterModule = {
|
|
|
6
6
|
async run({ code }) {
|
|
7
7
|
const model = ModelConfig.getModel();
|
|
8
8
|
const prompt = `
|
|
9
|
-
Suggest ALWAYS 3 concise, conventional Git commit messages based on
|
|
9
|
+
Suggest ALWAYS 3 concise, conventional Git commit messages based on the input code diff.
|
|
10
10
|
Use this format ONLY:
|
|
11
11
|
|
|
12
12
|
1. feat: ...
|
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
import { ModelConfig } from '../../config/ModelConfig.js';
|
|
2
2
|
import { generate } from '../../lib/generate.js';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
3
5
|
export const summaryModule = {
|
|
4
6
|
name: 'summary',
|
|
5
7
|
description: 'Prints a summary of changes to the terminal',
|
|
6
|
-
async run({ code }) {
|
|
8
|
+
async run({ code, filepath }) {
|
|
7
9
|
const model = ModelConfig.getModel();
|
|
8
10
|
const lang = ModelConfig.getLanguage();
|
|
11
|
+
let contextString = '';
|
|
12
|
+
// Try to load and filter the flat context
|
|
13
|
+
try {
|
|
14
|
+
const raw = await fs.readFile('./.scai/context.flat.json', 'utf-8');
|
|
15
|
+
const flatContext = JSON.parse(raw);
|
|
16
|
+
if (filepath) {
|
|
17
|
+
const dir = path.dirname(filepath).replace(/\\/g, '/'); // Normalize slashes
|
|
18
|
+
console.log("Dir: ", dir);
|
|
19
|
+
const contextSubset = Object.entries(flatContext)
|
|
20
|
+
.filter(([file]) => file.startsWith(dir))
|
|
21
|
+
.slice(0, 10); // limit if needed
|
|
22
|
+
if (contextSubset.length) {
|
|
23
|
+
contextString = '๐ Local Context:\n' + contextSubset
|
|
24
|
+
.map(([file, summary]) => `- ${file}: ${summary}`)
|
|
25
|
+
.join('\n');
|
|
26
|
+
console.log("Context string input to prompt: ", contextString);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
console.warn('โ ๏ธ Context file not found or failed to parse.');
|
|
32
|
+
}
|
|
9
33
|
const prompt = `
|
|
10
34
|
You are a senior ${lang.toUpperCase()} engineer.
|
|
11
35
|
|
|
12
|
-
|
|
36
|
+
Project Overview:
|
|
37
|
+
${contextString ? contextString + '\n\n' : ''}
|
|
13
38
|
|
|
14
|
-
|
|
15
|
-
2. After the code, append a short summary in this format:
|
|
39
|
+
Take the following source code and do NOT modify it in any way. Your task is:
|
|
16
40
|
|
|
17
41
|
// Summary of code:
|
|
18
42
|
// - [What the code does at a high level]
|
|
@@ -20,9 +44,8 @@ Take the following source code and do NOT modify it in any way. Your task is:
|
|
|
20
44
|
// - [Any interesting logic or patterns]
|
|
21
45
|
|
|
22
46
|
โ ๏ธ IMPORTANT:
|
|
23
|
-
- Do NOT
|
|
24
|
-
-
|
|
25
|
-
- Only append the summary AFTER the full code.
|
|
47
|
+
- Do NOT include the original code in your summary
|
|
48
|
+
- Remove the original code from you output
|
|
26
49
|
|
|
27
50
|
--- CODE START ---
|
|
28
51
|
${code}
|
|
@@ -36,7 +59,6 @@ ${code}
|
|
|
36
59
|
else {
|
|
37
60
|
console.warn('โ ๏ธ No summary generated.');
|
|
38
61
|
}
|
|
39
|
-
|
|
40
|
-
return { code };
|
|
62
|
+
return { code }; // passthrough
|
|
41
63
|
}
|
|
42
64
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/utils/getSummary.ts
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export function getSummary(filename, lang) {
|
|
4
|
+
const base = path.basename(filename).toLowerCase();
|
|
5
|
+
const ext = path.extname(base);
|
|
6
|
+
if (base === 'package.json')
|
|
7
|
+
return 'Defines project metadata and dependencies.';
|
|
8
|
+
if (base === 'tsconfig.json')
|
|
9
|
+
return 'TypeScript compiler settings.';
|
|
10
|
+
if (base === 'pyproject.toml')
|
|
11
|
+
return 'Python build and dependency configuration.';
|
|
12
|
+
if (base === 'Cargo.toml')
|
|
13
|
+
return 'Rust project configuration.';
|
|
14
|
+
if (base === 'pom.xml')
|
|
15
|
+
return 'Maven config for a Java project.';
|
|
16
|
+
if (base === 'README.md')
|
|
17
|
+
return 'Project documentation.';
|
|
18
|
+
if (base.startsWith('index'))
|
|
19
|
+
return 'Entry point module.';
|
|
20
|
+
if (lang === 'ts' || lang === 'js') {
|
|
21
|
+
if (base.includes('service'))
|
|
22
|
+
return 'Service logic module.';
|
|
23
|
+
if (base.includes('util'))
|
|
24
|
+
return 'Utility/helper module.';
|
|
25
|
+
if (base.includes('controller'))
|
|
26
|
+
return 'Handles request/response logic.';
|
|
27
|
+
if (base.includes('router'))
|
|
28
|
+
return 'Routing definitions.';
|
|
29
|
+
}
|
|
30
|
+
return `Generic ${ext.replace('.', '')} file.`;
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"scai": "./dist/index.js"
|
|
@@ -24,10 +24,13 @@
|
|
|
24
24
|
"start": "node dist/index.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"better-sqlite3": "^12.1.1",
|
|
27
28
|
"commander": "^11.0.0",
|
|
29
|
+
"fast-glob": "^3.3.3",
|
|
28
30
|
"ora": "^8.2.0"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
33
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
31
34
|
"@types/jest": "^30.0.0",
|
|
32
35
|
"@types/node": "^24.0.1",
|
|
33
36
|
"jest": "^30.0.2",
|