scai 0.1.43 ā 0.1.44
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.
|
@@ -1,27 +1,45 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { db } from '../db/client.js';
|
|
2
|
+
import { runDaemonBatch } from './daemonBatch.js'; // assuming this function is already defined
|
|
3
3
|
import { log } from '../utils/log.js';
|
|
4
|
-
|
|
5
|
-
const SLEEP_MS =
|
|
6
|
-
const IDLE_SLEEP_MS =
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
// Time between each batch in milliseconds
|
|
5
|
+
const SLEEP_MS = 2000; // Adjust as needed
|
|
6
|
+
const IDLE_SLEEP_MS = 5000; // Adjust as needed
|
|
7
|
+
// Check if there are any files left to process
|
|
8
|
+
async function isQueueEmpty() {
|
|
9
|
+
// Query the database for the count of files with certain processing statuses
|
|
10
|
+
const row = db.prepare(`
|
|
11
|
+
SELECT COUNT(*) AS count
|
|
12
|
+
FROM files
|
|
13
|
+
WHERE processing_status IN ('unprocessed')
|
|
14
|
+
`).get();
|
|
15
|
+
// Cast the row to an object that has a `count` property of type number
|
|
16
|
+
const castRow = row;
|
|
17
|
+
// Check if the casted `row` has a valid `count` property (number)
|
|
18
|
+
if (typeof castRow.count !== 'number') {
|
|
19
|
+
console.error('Error: Invalid count value in the database query result.');
|
|
20
|
+
return true; // Assume queue is empty if the count is invalid
|
|
21
|
+
}
|
|
22
|
+
// Return true if count is 0, otherwise false
|
|
23
|
+
return castRow.count === 0;
|
|
9
24
|
}
|
|
10
|
-
async function
|
|
11
|
-
fsSync.mkdirSync(SCAI_HOME, { recursive: true });
|
|
12
|
-
fsSync.writeFileSync(PID_PATH, process.pid.toString(), 'utf-8');
|
|
13
|
-
fsSync.appendFileSync(LOG_PATH, `\n\nš§ Daemon started at ${new Date().toISOString()} ā PID ${process.pid}\n`);
|
|
14
|
-
let cycles = 0;
|
|
25
|
+
export async function daemonWorker() {
|
|
15
26
|
while (true) {
|
|
27
|
+
// Execute a batch job
|
|
16
28
|
const didWork = await runDaemonBatch();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
if (!didWork) {
|
|
30
|
+
// Check if the queue is empty after a batch job
|
|
31
|
+
const queueEmpty = await isQueueEmpty();
|
|
32
|
+
if (queueEmpty) {
|
|
33
|
+
// If no files are left to process, stop the daemon
|
|
34
|
+
log("ā
No more work left. Stopping daemon.");
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
20
37
|
}
|
|
38
|
+
// Sleep for a set amount of time before checking again
|
|
21
39
|
await sleep(didWork ? SLEEP_MS : IDLE_SLEEP_MS);
|
|
22
40
|
}
|
|
23
41
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
42
|
+
// Sleep function to control how often the worker checks
|
|
43
|
+
function sleep(ms) {
|
|
44
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
45
|
+
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { parse } from 'acorn';
|
|
2
|
-
import {
|
|
2
|
+
import { ancestor as walkAncestor } from 'acorn-walk';
|
|
3
3
|
import { generateEmbedding } from '../../lib/generateEmbedding.js';
|
|
4
4
|
import { db } from '../client.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { log } from '../../utils/log.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
function getFunctionName(node, parent, fileName) {
|
|
8
|
+
if (node.id?.name)
|
|
9
|
+
return node.id.name;
|
|
10
|
+
if (parent?.type === 'VariableDeclarator' && parent.id?.name)
|
|
11
|
+
return parent.id.name;
|
|
12
|
+
if (parent?.type === 'Property' && parent.key?.name)
|
|
13
|
+
return parent.key.name;
|
|
14
|
+
if (parent?.type === 'AssignmentExpression' && parent.left?.name)
|
|
15
|
+
return parent.left.name;
|
|
16
|
+
if (parent?.type === 'MethodDefinition' && parent.key?.name)
|
|
17
|
+
return parent.key.name;
|
|
18
|
+
return `${fileName}:<anon>`;
|
|
19
|
+
}
|
|
12
20
|
export async function extractFromJS(filePath, content, fileId) {
|
|
13
21
|
const ast = parse(content, {
|
|
14
22
|
ecmaVersion: 'latest',
|
|
@@ -16,27 +24,36 @@ export async function extractFromJS(filePath, content, fileId) {
|
|
|
16
24
|
locations: true,
|
|
17
25
|
});
|
|
18
26
|
const functions = [];
|
|
19
|
-
|
|
20
|
-
FunctionDeclaration(node) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
walkAncestor(ast, {
|
|
28
|
+
FunctionDeclaration(node, ancestors) {
|
|
29
|
+
const parent = ancestors[ancestors.length - 2];
|
|
30
|
+
const name = getFunctionName(node, parent, path.basename(filePath));
|
|
31
|
+
functions.push({
|
|
32
|
+
name,
|
|
33
|
+
start_line: node.loc?.start.line ?? -1,
|
|
34
|
+
end_line: node.loc?.end.line ?? -1,
|
|
35
|
+
body: content.slice(node.start, node.end),
|
|
36
|
+
});
|
|
26
37
|
},
|
|
27
|
-
FunctionExpression(node) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
FunctionExpression(node, ancestors) {
|
|
39
|
+
const parent = ancestors[ancestors.length - 2];
|
|
40
|
+
const name = getFunctionName(node, parent, path.basename(filePath));
|
|
41
|
+
functions.push({
|
|
42
|
+
name,
|
|
43
|
+
start_line: node.loc?.start.line ?? -1,
|
|
44
|
+
end_line: node.loc?.end.line ?? -1,
|
|
45
|
+
body: content.slice(node.start, node.end),
|
|
46
|
+
});
|
|
33
47
|
},
|
|
34
|
-
ArrowFunctionExpression(node) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
ArrowFunctionExpression(node, ancestors) {
|
|
49
|
+
const parent = ancestors[ancestors.length - 2];
|
|
50
|
+
const name = getFunctionName(node, parent, path.basename(filePath));
|
|
51
|
+
functions.push({
|
|
52
|
+
name,
|
|
53
|
+
start_line: node.loc?.start.line ?? -1,
|
|
54
|
+
end_line: node.loc?.end.line ?? -1,
|
|
55
|
+
body: content.slice(node.start, node.end),
|
|
56
|
+
});
|
|
40
57
|
},
|
|
41
58
|
});
|
|
42
59
|
if (functions.length === 0) {
|
|
@@ -62,15 +79,15 @@ export async function extractFromJS(filePath, content, fileId) {
|
|
|
62
79
|
lang: 'js'
|
|
63
80
|
});
|
|
64
81
|
const callerId = result.lastInsertRowid;
|
|
65
|
-
const fnAst = parse(
|
|
82
|
+
const fnAst = parse(fn.body, {
|
|
66
83
|
ecmaVersion: 'latest',
|
|
67
84
|
sourceType: 'module',
|
|
68
85
|
locations: true,
|
|
69
86
|
});
|
|
70
87
|
const calls = [];
|
|
71
|
-
|
|
88
|
+
walkAncestor(fnAst, {
|
|
72
89
|
CallExpression(node) {
|
|
73
|
-
if (node.callee
|
|
90
|
+
if (node.callee?.type === 'Identifier' && node.callee.name) {
|
|
74
91
|
calls.push({ calleeName: node.callee.name });
|
|
75
92
|
}
|
|
76
93
|
}
|
|
@@ -86,7 +103,6 @@ export async function extractFromJS(filePath, content, fileId) {
|
|
|
86
103
|
}
|
|
87
104
|
log(`š Indexed function: ${fn.name} with ${calls.length} calls`);
|
|
88
105
|
}
|
|
89
|
-
// ā
Mark as extracted using new processing_status column
|
|
90
106
|
db.prepare(`
|
|
91
107
|
UPDATE files
|
|
92
108
|
SET processing_status = 'extracted'
|