scai 0.1.17 โ 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/dist/commands/IndexCmd.js +45 -0
- package/dist/commands/ResetDbCmd.js +27 -0
- 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 -7
- package/dist/utils/getSummary.js +31 -0
- package/dist/utils/languageConfig.js +7 -0
- package/package.json +3 -1
- package/dist/context/generateProjectContext.js +0 -104
- package/dist/context/loadProjectContext.js +0 -1
|
@@ -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
|
+
}
|
|
@@ -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,7 +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 {
|
|
18
|
+
import { runIndexCommand } from './commands/IndexCmd.js';
|
|
19
|
+
import { resetDatabase } from './commands/ResetDbCmd.js';
|
|
19
20
|
// Create the CLI instance
|
|
20
21
|
const cmd = new Command('scai')
|
|
21
22
|
.version(version)
|
|
@@ -29,12 +30,6 @@ cmd
|
|
|
29
30
|
await bootstrap();
|
|
30
31
|
console.log('โ
Model initialization completed!');
|
|
31
32
|
});
|
|
32
|
-
cmd
|
|
33
|
-
.command('context')
|
|
34
|
-
.description('Generate a summary-based context map of your project')
|
|
35
|
-
.action(async () => {
|
|
36
|
-
await generateProjectContext(); // Your new scanner module
|
|
37
|
-
});
|
|
38
33
|
cmd
|
|
39
34
|
.command('sugg')
|
|
40
35
|
.description('Suggest a commit message from staged changes')
|
|
@@ -73,6 +68,16 @@ cmd
|
|
|
73
68
|
.action(() => {
|
|
74
69
|
ModelConfig.logCurrentConfig();
|
|
75
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());
|
|
76
81
|
cmd
|
|
77
82
|
.arguments('<file>')
|
|
78
83
|
.option('-m, --modules <modules>', 'Comma-separated list of modules to run (e.g., comments,cleanup,summary)')
|
|
@@ -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,11 +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",
|
|
28
29
|
"fast-glob": "^3.3.3",
|
|
29
30
|
"ora": "^8.2.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
33
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
32
34
|
"@types/jest": "^30.0.0",
|
|
33
35
|
"@types/node": "^24.0.1",
|
|
34
36
|
"jest": "^30.0.2",
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import fg from 'fast-glob';
|
|
4
|
-
import { posix as pathPosix } from 'path';
|
|
5
|
-
import { ModelConfig } from '../config/ModelConfig.js';
|
|
6
|
-
const IGNORE = ['node_modules', 'dist', 'build', 'coverage', '.git', '**/*.test.*'];
|
|
7
|
-
const EXTENSIONS_BY_LANG = {
|
|
8
|
-
ts: ['.ts', '.tsx'],
|
|
9
|
-
js: ['.js', '.jsx'],
|
|
10
|
-
java: ['.java'],
|
|
11
|
-
rust: ['.rs'],
|
|
12
|
-
python: ['.py'],
|
|
13
|
-
};
|
|
14
|
-
function getSummary(filename, lang) {
|
|
15
|
-
const base = path.basename(filename).toLowerCase();
|
|
16
|
-
const ext = path.extname(base);
|
|
17
|
-
if (base === 'package.json')
|
|
18
|
-
return 'Defines project metadata and dependencies.';
|
|
19
|
-
if (base === 'tsconfig.json')
|
|
20
|
-
return 'TypeScript compiler settings.';
|
|
21
|
-
if (base === 'pyproject.toml')
|
|
22
|
-
return 'Python build and dependency configuration.';
|
|
23
|
-
if (base === 'Cargo.toml')
|
|
24
|
-
return 'Rust project configuration.';
|
|
25
|
-
if (base === 'pom.xml')
|
|
26
|
-
return 'Maven config for a Java project.';
|
|
27
|
-
if (base === 'README.md')
|
|
28
|
-
return 'Project documentation.';
|
|
29
|
-
if (base.startsWith('index'))
|
|
30
|
-
return 'Entry point module.';
|
|
31
|
-
if (lang === 'ts' || lang === 'js') {
|
|
32
|
-
if (base.includes('service'))
|
|
33
|
-
return 'Service logic module.';
|
|
34
|
-
if (base.includes('util'))
|
|
35
|
-
return 'Utility/helper module.';
|
|
36
|
-
if (base.includes('controller'))
|
|
37
|
-
return 'Handles request/response logic.';
|
|
38
|
-
if (base.includes('router'))
|
|
39
|
-
return 'Routing definitions.';
|
|
40
|
-
}
|
|
41
|
-
if (lang === 'java') {
|
|
42
|
-
if (base.includes('controller'))
|
|
43
|
-
return 'Java controller class.';
|
|
44
|
-
if (base.includes('service'))
|
|
45
|
-
return 'Business logic in Java.';
|
|
46
|
-
}
|
|
47
|
-
if (lang === 'python') {
|
|
48
|
-
if (base.includes('main'))
|
|
49
|
-
return 'Main execution script.';
|
|
50
|
-
if (base.includes('config'))
|
|
51
|
-
return 'Configuration or settings.';
|
|
52
|
-
}
|
|
53
|
-
if (lang === 'rust') {
|
|
54
|
-
if (base === 'main.rs')
|
|
55
|
-
return 'Main Rust binary entry point.';
|
|
56
|
-
if (base === 'lib.rs')
|
|
57
|
-
return 'Rust library root module.';
|
|
58
|
-
}
|
|
59
|
-
return `Generic ${ext.replace('.', '')} file.`;
|
|
60
|
-
}
|
|
61
|
-
function insertNested(tree, parts, summary) {
|
|
62
|
-
const name = parts.pop();
|
|
63
|
-
let curr = tree;
|
|
64
|
-
for (const dir of parts) {
|
|
65
|
-
if (!curr[dir])
|
|
66
|
-
curr[dir] = {};
|
|
67
|
-
curr = curr[dir];
|
|
68
|
-
}
|
|
69
|
-
curr[name] = summary;
|
|
70
|
-
}
|
|
71
|
-
export async function generateProjectContext(root = process.cwd()) {
|
|
72
|
-
const lang = ModelConfig.getLanguage();
|
|
73
|
-
const extensions = EXTENSIONS_BY_LANG[lang];
|
|
74
|
-
const patterns = extensions.map((ext) => `**/*${ext}`);
|
|
75
|
-
// Add language-relevant config files
|
|
76
|
-
if (lang === 'ts')
|
|
77
|
-
patterns.push('tsconfig.json', 'package.json');
|
|
78
|
-
if (lang === 'js')
|
|
79
|
-
patterns.push('package.json');
|
|
80
|
-
if (lang === 'java')
|
|
81
|
-
patterns.push('pom.xml');
|
|
82
|
-
if (lang === 'python')
|
|
83
|
-
patterns.push('pyproject.toml', '*.py');
|
|
84
|
-
if (lang === 'rust')
|
|
85
|
-
patterns.push('Cargo.toml', '*.rs');
|
|
86
|
-
const files = await fg(patterns, {
|
|
87
|
-
cwd: root,
|
|
88
|
-
ignore: IGNORE,
|
|
89
|
-
});
|
|
90
|
-
const flat = {};
|
|
91
|
-
const tree = {};
|
|
92
|
-
for (const file of files) {
|
|
93
|
-
const summary = getSummary(file, lang);
|
|
94
|
-
flat[file] = summary;
|
|
95
|
-
insertNested(tree, pathPosix.normalize(file).split('/'), summary);
|
|
96
|
-
}
|
|
97
|
-
await fs.mkdir('.scai', { recursive: true });
|
|
98
|
-
await fs.writeFile('.scai/context.flat.json', JSON.stringify(flat, null, 2));
|
|
99
|
-
await fs.writeFile('.scai/context.tree.json', JSON.stringify(tree, null, 2));
|
|
100
|
-
console.log(`โ
Context generated:
|
|
101
|
-
- .scai/context.flat.json
|
|
102
|
-
- .scai/context.tree.json
|
|
103
|
-
- Language used: ${lang}`);
|
|
104
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|