scai 0.1.58 โ 0.1.60
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.
|
@@ -3,7 +3,6 @@ import { ancestor as walkAncestor } from 'acorn-walk';
|
|
|
3
3
|
import { generateEmbedding } from '../../lib/generateEmbedding.js';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { log } from '../../utils/log.js';
|
|
6
|
-
import fs from 'fs';
|
|
7
6
|
import { markFileAsSkippedTemplate, markFileAsExtractedTemplate, markFileAsFailedTemplate } from '../sqlTemplates.js';
|
|
8
7
|
import { getDbForRepo } from '../client.js';
|
|
9
8
|
function getFunctionName(node, parent, fileName) {
|
|
@@ -22,9 +21,8 @@ function getFunctionName(node, parent, fileName) {
|
|
|
22
21
|
export async function extractFromJS(filePath, content, fileId) {
|
|
23
22
|
const db = getDbForRepo();
|
|
24
23
|
try {
|
|
25
|
-
const code = fs.readFileSync(filePath, 'utf-8');
|
|
26
24
|
console.log(`[Debug] Attempting to parse: ${filePath}`);
|
|
27
|
-
console.log(`[Debug] First 3 lines:\n${
|
|
25
|
+
console.log(`[Debug] First 3 lines:\n${content.split('\n').slice(0, 3).join('\n')}`);
|
|
28
26
|
const ast = parse(content, {
|
|
29
27
|
ecmaVersion: 'latest',
|
|
30
28
|
sourceType: 'module',
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,9 @@ import { promptForToken } from "./github/token.js";
|
|
|
26
26
|
import { validateGitHubTokenAgainstRepo } from "./github/githubAuthCheck.js";
|
|
27
27
|
import { checkGit } from "./commands/GitCmd.js";
|
|
28
28
|
import { runSwitchCommand, runInteractiveSwitch } from "./commands/SwitchCmd.js";
|
|
29
|
+
import { execSync } from "child_process";
|
|
30
|
+
import { dirname, resolve } from "path";
|
|
31
|
+
import { fileURLToPath } from "url";
|
|
29
32
|
// ๐๏ธ CLI Setup
|
|
30
33
|
const cmd = new Command('scai')
|
|
31
34
|
.version(version)
|
|
@@ -174,6 +177,23 @@ index
|
|
|
174
177
|
runInteractiveSwitch();
|
|
175
178
|
}
|
|
176
179
|
});
|
|
180
|
+
// This will help resolve the current directory in an ES Module
|
|
181
|
+
cmd
|
|
182
|
+
.command('check-db')
|
|
183
|
+
.description('Run the dbcheck script to check the database status')
|
|
184
|
+
.action(() => {
|
|
185
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
186
|
+
const __dirname = dirname(__filename);
|
|
187
|
+
// Go up two levels from dist/commands โ dist โ then into dist/scripts/dbcheck.js
|
|
188
|
+
const scriptPath = resolve(__dirname, '..', 'dist/scripts', 'dbcheck.js');
|
|
189
|
+
console.log(`๐ Running database check script: ${scriptPath}`);
|
|
190
|
+
try {
|
|
191
|
+
execSync(`node "${scriptPath}"`, { stdio: 'inherit' });
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
console.error('โ Error running dbcheck script:', err instanceof Error ? err.message : err);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
177
197
|
cmd
|
|
178
198
|
.command('backup')
|
|
179
199
|
.description('Backup the current .scai folder')
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { Config } from "../config.js";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
const cfg = Config.getRaw();
|
|
7
|
+
const repoKey = cfg.activeRepo;
|
|
8
|
+
if (!repoKey) {
|
|
9
|
+
console.error("โ No active repo found. Use `scai set-index` to set one.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
// Get the basename (repo name) from the full repoKey (which is the path)
|
|
13
|
+
const repoName = path.basename(repoKey);
|
|
14
|
+
const scaiRepoRoot = path.join(os.homedir(), ".scai", "repos", repoName);
|
|
15
|
+
const dbPath = path.join(scaiRepoRoot, "db.sqlite");
|
|
16
|
+
if (!fs.existsSync(dbPath)) {
|
|
17
|
+
console.error(`โ No database found at ${dbPath}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const db = new Database(dbPath);
|
|
21
|
+
// === Basic Stats ===
|
|
22
|
+
const stats = {
|
|
23
|
+
total: db.prepare('SELECT COUNT(*) as count FROM files').get().count,
|
|
24
|
+
withSummary: db.prepare(`SELECT COUNT(*) as count FROM files WHERE summary IS NOT NULL AND summary != ''`).get().count,
|
|
25
|
+
withoutSummary: db.prepare(`SELECT COUNT(*) as count FROM files WHERE summary IS NULL OR summary = ''`).get().count,
|
|
26
|
+
withEmbedding: db.prepare(`SELECT COUNT(*) as count FROM files WHERE embedding IS NOT NULL AND embedding != ''`).get().count,
|
|
27
|
+
withoutEmbedding: db.prepare(`SELECT COUNT(*) as count FROM files WHERE embedding IS NULL OR embedding = ''`).get().count,
|
|
28
|
+
withProcessingStatusExtracted: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'extracted'`).get().count,
|
|
29
|
+
withoutProcessingStatusExtracted: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status IS NULL OR processing_status != 'extracted'`).get().count,
|
|
30
|
+
withProcessingStatusSkipped: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'skipped'`).get().count,
|
|
31
|
+
withProcessingStatusFailed: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'failed'`).get().count,
|
|
32
|
+
withProcessingStatusUnprocessed: db.prepare(`SELECT COUNT(*) as count FROM files WHERE processing_status = 'unprocessed'`).get().count,
|
|
33
|
+
};
|
|
34
|
+
console.log("๐ SQLite Stats for Table: files");
|
|
35
|
+
console.log("-------------------------------------------");
|
|
36
|
+
console.log(`๐ข Total rows: ${stats.total}`);
|
|
37
|
+
console.log(`โ
With summary: ${stats.withSummary}`);
|
|
38
|
+
console.log(`โ Without summary: ${stats.withoutSummary}`);
|
|
39
|
+
console.log(`โ
With embedding: ${stats.withEmbedding}`);
|
|
40
|
+
console.log(`โ Without embedding: ${stats.withoutEmbedding}`);
|
|
41
|
+
console.log(`โ
With processing_status = 'extracted': ${stats.withProcessingStatusExtracted}`);
|
|
42
|
+
console.log(`โ Without processing_status = 'extracted': ${stats.withoutProcessingStatusExtracted}`);
|
|
43
|
+
console.log(`โ
With processing_status = 'skipped': ${stats.withProcessingStatusSkipped}`);
|
|
44
|
+
console.log(`โ
With processing_status = 'failed': ${stats.withProcessingStatusFailed}`);
|
|
45
|
+
console.log(`โ
With processing_status = 'unprocessed': ${stats.withProcessingStatusUnprocessed}`);
|
|
46
|
+
// === Example Summaries ===
|
|
47
|
+
console.log("\n๐งพ Example summaries and embeddings:\n--------------------------");
|
|
48
|
+
console.log("Example summaries (first 50 characters):");
|
|
49
|
+
const summaries = db.prepare(`
|
|
50
|
+
SELECT id, substr(summary, 1, 50) || '...' AS short_summary
|
|
51
|
+
FROM files
|
|
52
|
+
WHERE summary IS NOT NULL AND summary != ''
|
|
53
|
+
LIMIT 10
|
|
54
|
+
`).all();
|
|
55
|
+
summaries.forEach(row => {
|
|
56
|
+
console.log(`${row.id.toString().padEnd(4)} ${row.short_summary}`);
|
|
57
|
+
});
|
|
58
|
+
console.log("\nExample embeddings (first 50 characters):");
|
|
59
|
+
const embeddings = db.prepare(`
|
|
60
|
+
SELECT id, substr(embedding, 1, 50) || '...' AS short_embedding
|
|
61
|
+
FROM files
|
|
62
|
+
WHERE embedding IS NOT NULL AND embedding != ''
|
|
63
|
+
LIMIT 10
|
|
64
|
+
`).all();
|
|
65
|
+
embeddings.forEach(row => {
|
|
66
|
+
console.log(`${row.id.toString().padEnd(4)} ${row.short_embedding}`);
|
|
67
|
+
});
|
|
68
|
+
// === FTS5 Check ===
|
|
69
|
+
console.log("\n๐ FTS5 Check");
|
|
70
|
+
console.log("--------------------------");
|
|
71
|
+
try {
|
|
72
|
+
const ftsExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='files_fts'`).get();
|
|
73
|
+
if (!ftsExists) {
|
|
74
|
+
console.log("โ No FTS5 table `files_fts` found in database.");
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const ftsRowCount = db.prepare(`SELECT COUNT(*) AS count FROM files_fts`).get().count;
|
|
78
|
+
console.log(`โ
files_fts table exists. Rows: ${ftsRowCount}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.error("โ Error while accessing files_fts:", err.message);
|
|
83
|
+
}
|
|
84
|
+
// === Rebuild FTS Index ===
|
|
85
|
+
console.log("\n๐ง Rebuilding FTS5 index...");
|
|
86
|
+
try {
|
|
87
|
+
db.prepare(`INSERT INTO files_fts(files_fts) VALUES ('rebuild')`).run();
|
|
88
|
+
console.log(`โ
Rebuild completed.`);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.error("โ FTS5 rebuild failed:", err.message);
|
|
92
|
+
}
|
|
93
|
+
// === FTS Search Test ===
|
|
94
|
+
console.log('\n๐ Test MATCH query for "minimap":');
|
|
95
|
+
try {
|
|
96
|
+
const minimapMatches = db.prepare(`
|
|
97
|
+
SELECT f.id, f.path
|
|
98
|
+
FROM files f
|
|
99
|
+
JOIN files_fts fts ON f.id = fts.rowid
|
|
100
|
+
WHERE fts.files_fts MATCH 'minimap'
|
|
101
|
+
LIMIT 10
|
|
102
|
+
`).all();
|
|
103
|
+
if (minimapMatches.length === 0) {
|
|
104
|
+
console.warn('โ ๏ธ No matches for "minimap" in FTS index');
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
minimapMatches.forEach(row => {
|
|
108
|
+
console.log(`๐ ${row.path}`);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
console.error('โ Error running MATCH query:', err.message);
|
|
114
|
+
}
|
|
115
|
+
// === Direct LIKE Fallback ===
|
|
116
|
+
console.log('\n๐ Direct LIKE query on path for "minimap":');
|
|
117
|
+
const likeMatches = db.prepare(`
|
|
118
|
+
SELECT id, path
|
|
119
|
+
FROM files
|
|
120
|
+
WHERE path LIKE '%minimap%'
|
|
121
|
+
LIMIT 10
|
|
122
|
+
`).all();
|
|
123
|
+
if (likeMatches.length === 0) {
|
|
124
|
+
console.warn('โ ๏ธ No file paths contain "minimap"');
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
likeMatches.forEach(row => {
|
|
128
|
+
console.log(`๐ ${row.path}`);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// === Function Table Stats ===
|
|
132
|
+
console.log('\n๐ Stats for Table: functions');
|
|
133
|
+
console.log('-------------------------------------------');
|
|
134
|
+
try {
|
|
135
|
+
const funcCount = db.prepare(`SELECT COUNT(*) AS count FROM functions`).get().count;
|
|
136
|
+
const distinctFiles = db.prepare(`SELECT COUNT(DISTINCT file_id) AS count FROM functions`).get().count;
|
|
137
|
+
console.log(`๐ข Total functions: ${funcCount}`);
|
|
138
|
+
console.log(`๐ Distinct files: ${distinctFiles}`);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error('โ Error accessing functions table:', err.message);
|
|
142
|
+
}
|
|
143
|
+
// === Example Functions ===
|
|
144
|
+
console.log('\n๐งช Example extracted functions:');
|
|
145
|
+
try {
|
|
146
|
+
const sampleFunctions = db.prepare(`
|
|
147
|
+
SELECT id, name, start_line, end_line, substr(content, 1, 100) || '...' AS short_body
|
|
148
|
+
FROM functions
|
|
149
|
+
ORDER BY id DESC
|
|
150
|
+
LIMIT 5
|
|
151
|
+
`).all();
|
|
152
|
+
sampleFunctions.forEach(fn => {
|
|
153
|
+
console.log(`๐น ID: ${fn.id}`);
|
|
154
|
+
console.log(` Name: ${fn.name}`);
|
|
155
|
+
console.log(` Lines: ${fn.start_line}-${fn.end_line}`);
|
|
156
|
+
console.log(` Body: ${fn.short_body}\n`);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
console.error('โ Error printing function examples:', err.message);
|
|
161
|
+
}
|
|
162
|
+
// === Function Calls Table Stats ===
|
|
163
|
+
console.log('\n๐ Stats for Table: function_calls');
|
|
164
|
+
console.log('-------------------------------------------');
|
|
165
|
+
try {
|
|
166
|
+
const callCount = db.prepare(`SELECT COUNT(*) AS count FROM function_calls`).get().count;
|
|
167
|
+
const topCallers = db.prepare(`
|
|
168
|
+
SELECT caller_id, COUNT(*) AS num_calls
|
|
169
|
+
FROM function_calls
|
|
170
|
+
GROUP BY caller_id
|
|
171
|
+
ORDER BY num_calls DESC
|
|
172
|
+
LIMIT 5
|
|
173
|
+
`).all();
|
|
174
|
+
console.log(`๐ Total function calls: ${callCount}`);
|
|
175
|
+
console.log('๐ Top callers:');
|
|
176
|
+
topCallers.forEach(row => {
|
|
177
|
+
console.log(` - Caller ${row.caller_id} made ${row.num_calls} calls`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
console.error('โ Error accessing function_calls table:', err.message);
|
|
182
|
+
}
|
|
183
|
+
// === Random Summary Samples ===
|
|
184
|
+
console.log('\n๐งพ 10 Random Summaries (ID + Preview):');
|
|
185
|
+
console.log('-------------------------------------------');
|
|
186
|
+
const randomSummaries = db.prepare(`
|
|
187
|
+
SELECT id, filename, substr(summary, 1, 1000) || '...' AS preview
|
|
188
|
+
FROM files
|
|
189
|
+
WHERE summary IS NOT NULL AND summary != ''
|
|
190
|
+
ORDER BY RANDOM()
|
|
191
|
+
LIMIT 10
|
|
192
|
+
`).all();
|
|
193
|
+
randomSummaries.forEach(row => {
|
|
194
|
+
console.log(`๐ [${row.id}] ${row.filename}: ${row.preview}`);
|
|
195
|
+
});
|
|
196
|
+
// === Random Functions Samples ===
|
|
197
|
+
console.log('\n๐งโ๐ป 20 Random Functions (ID, name, body):');
|
|
198
|
+
console.log('-------------------------------------------');
|
|
199
|
+
const randomFunctions = db.prepare(`
|
|
200
|
+
SELECT id, name, file_id, substr(content, 1, 100) || '...' AS preview
|
|
201
|
+
FROM functions
|
|
202
|
+
ORDER BY RANDOM()
|
|
203
|
+
LIMIT 20
|
|
204
|
+
`).all();
|
|
205
|
+
randomFunctions.forEach(row => {
|
|
206
|
+
console.log(`๐น [${row.id}] ${row.name} (file_id: ${row.file_id})`);
|
|
207
|
+
console.log(` ${row.preview}\n`);
|
|
208
|
+
});
|
|
209
|
+
// === Column View of 100 Files ===
|
|
210
|
+
console.log('\n๐ Table View: First 100 Files');
|
|
211
|
+
console.log('-------------------------------------------');
|
|
212
|
+
const fileRows = db.prepare(`
|
|
213
|
+
SELECT id, filename, type, processing_status, functions_extracted_at, length(summary) AS summary_len
|
|
214
|
+
FROM files
|
|
215
|
+
LIMIT 1000
|
|
216
|
+
`).all();
|
|
217
|
+
console.table(fileRows);
|
|
218
|
+
// === Column View of 100 Functions ===
|
|
219
|
+
console.log('\n๐ Table View: First 100 Functions');
|
|
220
|
+
console.log('-------------------------------------------');
|
|
221
|
+
const functionRows = db.prepare(`
|
|
222
|
+
SELECT id, file_id, name, start_line, end_line, length(content) AS length
|
|
223
|
+
FROM functions
|
|
224
|
+
LIMIT 1000
|
|
225
|
+
`).all();
|
|
226
|
+
console.table(functionRows);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.60",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"scai": "./dist/index.js"
|
|
@@ -50,10 +50,11 @@
|
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/better-sqlite3": "^7.6.13",
|
|
52
52
|
"@types/jest": "^30.0.0",
|
|
53
|
-
"@types/node": "^24.0
|
|
53
|
+
"@types/node": "^24.1.0",
|
|
54
54
|
"@types/proper-lockfile": "^4.1.4",
|
|
55
55
|
"jest": "^30.0.2",
|
|
56
56
|
"ts-jest": "^29.4.0",
|
|
57
|
+
"ts-node": "^10.9.2",
|
|
57
58
|
"typescript": "^5.8.3"
|
|
58
59
|
},
|
|
59
60
|
"files": [
|