scai 0.1.111 → 0.1.113
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/index.js +1 -3
- package/dist/utils/buildContextualPrompt.js +25 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,9 +31,7 @@ import { updateContext } from './context.js';
|
|
|
31
31
|
import { Agent } from './agent/agentManager.js';
|
|
32
32
|
// 🎛️ CLI Setup
|
|
33
33
|
const cmd = new Command('scai')
|
|
34
|
-
.version(version)
|
|
35
|
-
.option('--model <model>', 'Set the model to use (e.g., codellama:34b)')
|
|
36
|
-
.option('--lang <lang>', 'Set the target language (ts, java, rust)');
|
|
34
|
+
.version(version, '-v, --version', 'output the current version');
|
|
37
35
|
// 🔧 Main command group
|
|
38
36
|
cmd
|
|
39
37
|
.command('init')
|
|
@@ -6,13 +6,14 @@ export async function buildContextualPrompt({ topFile, query, kgDepth = 3, }) {
|
|
|
6
6
|
const log = (...args) => console.log("[buildContextualPrompt]", ...args);
|
|
7
7
|
const promptSections = [];
|
|
8
8
|
const seenPaths = new Set();
|
|
9
|
-
|
|
9
|
+
// ✂️ Word-based summarizer with progressive shortening
|
|
10
|
+
function summarizeForPrompt(summary, maxWords = 30) {
|
|
10
11
|
if (!summary)
|
|
11
12
|
return undefined;
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
15
|
-
return
|
|
13
|
+
const words = summary.split(/\s+/);
|
|
14
|
+
if (words.length <= maxWords)
|
|
15
|
+
return summary.trim();
|
|
16
|
+
return words.slice(0, maxWords).join(" ") + " …";
|
|
16
17
|
}
|
|
17
18
|
// --- Step 1: Top file summary ---
|
|
18
19
|
if (topFile.summary) {
|
|
@@ -62,21 +63,27 @@ export async function buildContextualPrompt({ topFile, query, kgDepth = 3, }) {
|
|
|
62
63
|
}
|
|
63
64
|
function buildFileTree(file, depth, visited = new Set()) {
|
|
64
65
|
log(`buildFileTree - file=${file.path}, depth=${depth}`);
|
|
65
|
-
if (
|
|
66
|
-
return { id: file.id.toString(), path: file.path
|
|
66
|
+
if (visited.has(file.id)) {
|
|
67
|
+
return { id: file.id.toString(), path: file.path };
|
|
67
68
|
}
|
|
68
69
|
visited.add(file.id);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
log(`File ${file.path} has ${relatedFiles.length} related files`);
|
|
73
|
-
const relatedNodes = relatedFiles.map(f => buildFileTree(f, depth - 1, visited));
|
|
74
|
-
return {
|
|
70
|
+
// progressively shorten summaries, drop at depth <= 1
|
|
71
|
+
const maxWordsByDepth = depth >= 3 ? 30 : depth === 2 ? 15 : 0;
|
|
72
|
+
const node = {
|
|
75
73
|
id: file.id.toString(),
|
|
76
74
|
path: file.path,
|
|
77
|
-
summary: summarizeForPrompt(file.summary),
|
|
78
|
-
related: relatedNodes.length ? relatedNodes : undefined,
|
|
75
|
+
summary: maxWordsByDepth > 0 ? summarizeForPrompt(file.summary, maxWordsByDepth) : undefined,
|
|
79
76
|
};
|
|
77
|
+
if (depth > 1) {
|
|
78
|
+
const relatedFiles = getRelatedKGFiles(file.id, visited)
|
|
79
|
+
.map(f => ({ id: f.id, path: f.path, summary: f.summary }))
|
|
80
|
+
.slice(0, 5); // cap children
|
|
81
|
+
log(`File ${file.path} has ${relatedFiles.length} related files`);
|
|
82
|
+
const relatedNodes = relatedFiles.map(f => buildFileTree(f, depth - 1, visited));
|
|
83
|
+
if (relatedNodes.length)
|
|
84
|
+
node.related = relatedNodes;
|
|
85
|
+
}
|
|
86
|
+
return node;
|
|
80
87
|
}
|
|
81
88
|
const kgTree = buildFileTree({ id: topFile.id, path: topFile.path, summary: topFile.summary }, kgDepth);
|
|
82
89
|
const kgJson = JSON.stringify(kgTree, null, 2);
|
|
@@ -93,8 +100,10 @@ export async function buildContextualPrompt({ topFile, query, kgDepth = 3, }) {
|
|
|
93
100
|
console.warn("⚠️ Could not generate file tree:", e);
|
|
94
101
|
}
|
|
95
102
|
// --- Step 5: Code snippet ---
|
|
103
|
+
// Only include raw code if no summary exists, or if the query explicitly asks for it
|
|
96
104
|
const MAX_LINES = 50;
|
|
97
|
-
|
|
105
|
+
const queryNeedsCode = /\b(code|implementation|function|snippet)\b/i.test(query);
|
|
106
|
+
if ((!topFile.summary || queryNeedsCode) && topFile.code) {
|
|
98
107
|
const lines = topFile.code.split("\n").slice(0, MAX_LINES);
|
|
99
108
|
let snippet = lines.join("\n");
|
|
100
109
|
if (topFile.code.split("\n").length > MAX_LINES) {
|