scai 0.1.65 → 0.1.67

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.
@@ -7,7 +7,8 @@ import { generate } from '../lib/generate.js';
7
7
  import { buildContextualPrompt } from '../utils/buildContextualPrompt.js';
8
8
  import { generateFocusedFileTree } from '../utils/fileTree.js';
9
9
  import { log } from '../utils/log.js';
10
- import { PROMPT_LOG_PATH, SCAI_HOME, RELATED_FILES_LIMIT, MAX_SUMMARY_LINES, getIndexDir } from '../constants.js';
10
+ import { PROMPT_LOG_PATH, SCAI_HOME, RELATED_FILES_LIMIT, MAX_SUMMARY_LINES, getIndexDir, MAX_FUNCTION_LINES } from '../constants.js';
11
+ import chalk from 'chalk';
11
12
  export async function runAskCommand(query) {
12
13
  if (!query) {
13
14
  query = await promptOnce('šŸ’¬ Ask your question:\n');
@@ -33,7 +34,7 @@ export async function runAskCommand(query) {
33
34
  fallbackResults.forEach((file, i) => {
34
35
  console.log(` ${i + 1}. šŸ”Ž Fallback Match: ${file.path}`);
35
36
  });
36
- // 🟩 STEP 2: Merge results (de-duplicate by full resolved path)
37
+ // 🟩 STEP 2: Merge results
37
38
  const seen = new Set();
38
39
  const combinedResults = [];
39
40
  for (const file of semanticResults) {
@@ -71,33 +72,49 @@ export async function runAskCommand(query) {
71
72
  let code = '';
72
73
  let topSummary = topFile.summary || '(No summary available)';
73
74
  let topFunctions = [];
74
- // Truncate summary if needed
75
- if (topSummary) {
76
- topSummary = topSummary.split('\n').slice(0, MAX_SUMMARY_LINES).join('\n');
77
- }
75
+ const fileFunctions = {};
76
+ // Truncate summary
77
+ topSummary = topSummary.split('\n').slice(0, MAX_SUMMARY_LINES).join('\n');
78
78
  const allFileIds = combinedResults
79
79
  .map(file => file.id)
80
80
  .filter((id) => typeof id === 'number');
81
- const allFunctionsMap = getFunctionsForFiles(allFileIds);
81
+ const allFunctionsMap = getFunctionsForFiles(allFileIds); // Record<number, Function[]>
82
82
  try {
83
83
  code = fs.readFileSync(filepath, 'utf-8');
84
84
  const topFileId = topFile.id;
85
- topFunctions = allFunctionsMap[topFileId]?.map(fn => fn.name) || [];
85
+ topFunctions = allFunctionsMap[topFileId]?.map(fn => {
86
+ const content = fn.content
87
+ ? fn.content.split('\n').slice(0, MAX_FUNCTION_LINES).join('\n')
88
+ : '(No content available)';
89
+ return {
90
+ name: fn.name,
91
+ content,
92
+ };
93
+ }) || [];
86
94
  }
87
95
  catch (err) {
88
96
  console.warn(`āš ļø Failed to read or analyze top file (${filepath}):`, err);
89
97
  }
90
- // 🟩 STEP 5: Build relatedFiles with functions
98
+ // 🟩 STEP 5: Build relatedFiles with functions and fileFunctions
91
99
  const relatedFiles = combinedResults.slice(0, RELATED_FILES_LIMIT).map(file => {
92
100
  const fileId = file.id;
93
101
  let summary = file.summary || '(No summary available)';
94
102
  if (summary) {
95
103
  summary = summary.split('\n').slice(0, MAX_SUMMARY_LINES).join('\n');
96
104
  }
105
+ const functions = allFunctionsMap[fileId]?.map(fn => {
106
+ const content = fn.content
107
+ ? fn.content.split('\n').slice(0, MAX_FUNCTION_LINES).join('\n')
108
+ : '(No content available)';
109
+ return {
110
+ name: fn.name,
111
+ content,
112
+ };
113
+ }) || [];
97
114
  return {
98
115
  path: file.path,
99
116
  summary,
100
- functions: allFunctionsMap[fileId]?.map(fn => fn.name) || [],
117
+ functions,
101
118
  };
102
119
  });
103
120
  // 🟩 STEP 6: Generate file tree
@@ -109,6 +126,8 @@ export async function runAskCommand(query) {
109
126
  console.warn('āš ļø Could not generate file tree:', e);
110
127
  }
111
128
  // 🟩 STEP 7: Build prompt
129
+ console.log(chalk.blueBright('\nšŸ“¦ Building contextual prompt...'));
130
+ console.log(chalk.gray(`[runAskCommand] Calling buildContextualPrompt()`));
112
131
  const promptContent = buildContextualPrompt({
113
132
  baseInstruction: query,
114
133
  code,
@@ -116,8 +135,11 @@ export async function runAskCommand(query) {
116
135
  functions: topFunctions,
117
136
  relatedFiles,
118
137
  projectFileTree: fileTree || undefined,
138
+ fileFunctions,
119
139
  });
120
- // 🟩 STEP 8: Save prompt for trace/debug
140
+ console.log(chalk.greenBright('āœ… Prompt built successfully.'));
141
+ console.log(chalk.cyan(`[runAskCommand] Prompt token estimate: ~${Math.round(promptContent.length / 4)} tokens`));
142
+ // 🟩 STEP 8: Save prompt
121
143
  try {
122
144
  if (!fs.existsSync(SCAI_HOME))
123
145
  fs.mkdirSync(SCAI_HOME, { recursive: true });
@@ -144,7 +166,7 @@ export async function runAskCommand(query) {
144
166
  // 🟩 Helper: Prompt once
145
167
  function promptOnce(promptText) {
146
168
  return new Promise(resolve => {
147
- console.log(promptText); // Instead of putting it *in* rl.question
169
+ console.log(promptText);
148
170
  const rl = readline.createInterface({
149
171
  input: process.stdin,
150
172
  output: process.stdout,
package/dist/constants.js CHANGED
@@ -61,3 +61,7 @@ export const CANDIDATE_LIMIT = 100;
61
61
  * Limit number of summary lines
62
62
  */
63
63
  export const MAX_SUMMARY_LINES = 12;
64
+ /**
65
+ * Limit number of function content
66
+ */
67
+ export const MAX_FUNCTION_LINES = 12;
@@ -1,20 +1,56 @@
1
- export function buildContextualPrompt({ baseInstruction, code, summary, functions, relatedFiles, projectFileTree }) {
1
+ // File: src/utils/buildContextualPrompt.ts
2
+ import chalk from 'chalk';
3
+ function estimateTokenCount(text) {
4
+ return Math.round(text.length / 4); // simple heuristic approximation
5
+ }
6
+ export function buildContextualPrompt({ baseInstruction, code, summary, functions, relatedFiles, projectFileTree, }) {
2
7
  const parts = [baseInstruction];
3
8
  if (summary) {
4
9
  parts.push(`šŸ“„ File Summary:\n${summary}`);
5
10
  }
6
11
  if (functions?.length) {
7
- parts.push(`šŸ”§ Functions:\n${functions.join(', ')}`);
12
+ const formattedFunctions = functions
13
+ .map(fn => `• ${fn.name}:\n${fn.content}`)
14
+ .join('\n\n');
15
+ parts.push(`šŸ”§ Functions:\n${formattedFunctions}`);
16
+ }
17
+ else {
18
+ console.log(chalk.gray(`[buildContextualPrompt]`) +
19
+ chalk.yellow(` āš ļø No functions found in top file.`));
8
20
  }
9
21
  if (relatedFiles?.length) {
10
- const formatted = relatedFiles
11
- .map(f => `• ${f.path}: ${f.summary}`)
12
- .join('\n');
13
- parts.push(`šŸ“š Related Files:\n${formatted}`);
22
+ const formattedRelatedFiles = relatedFiles
23
+ .map(f => {
24
+ const relatedFunctions = f.functions
25
+ .map(fn => ` • ${fn.name}:\n ${fn.content}`)
26
+ .join('\n\n');
27
+ return `• ${f.path}: ${f.summary}\n${relatedFunctions}`;
28
+ })
29
+ .join('\n\n');
30
+ parts.push(`šŸ“š Related Files:\n${formattedRelatedFiles}`);
14
31
  }
15
32
  if (projectFileTree) {
16
33
  parts.push(`šŸ“ Project File Structure:\n\`\`\`\n${projectFileTree.trim()}\n\`\`\``);
17
34
  }
18
35
  parts.push(`\n--- CODE START ---\n${code}\n--- CODE END ---`);
19
- return parts.join('\n\n');
36
+ const prompt = parts.join('\n\n');
37
+ const tokenEstimate = estimateTokenCount(prompt);
38
+ // šŸ”µ Colorized diagnostic output
39
+ const header = chalk.bgBlue.white.bold(' [SCAI] Prompt Overview ');
40
+ const labelColor = chalk.cyan;
41
+ const contentColor = chalk.gray;
42
+ console.log('\n' + header);
43
+ console.log(labelColor('šŸ”¢ Token Estimate:'), contentColor(`${tokenEstimate.toLocaleString()} tokens`));
44
+ console.log(labelColor('🧩 Prompt Sections:'));
45
+ console.log(contentColor([
46
+ summary ? 'šŸ“„ Summary' : null,
47
+ functions?.length ? 'šŸ”§ Functions' : null,
48
+ relatedFiles?.length ? 'šŸ“š Related Files' : null,
49
+ projectFileTree ? 'šŸ“ File Tree' : null,
50
+ 'šŸ“¦ Code',
51
+ ]
52
+ .filter(Boolean)
53
+ .join(', ')));
54
+ console.log(labelColor('šŸ” Key:'), contentColor('[buildContextualPrompt]\n'));
55
+ return prompt;
20
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scai",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "scai": "./dist/index.js"