scai 0.1.16 → 0.1.17

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/README.md CHANGED
@@ -123,6 +123,15 @@ For more advanced functionality, scai allows you to run custom pipelines with mu
123
123
  ```bash
124
124
  scai <file> --modules comment,summary,cleanup
125
125
  ```
126
+ Like with regular Unix commands you can pipe this to a file
127
+
128
+ ```bash
129
+ scai <file> --modules comment,summary > test.txt
130
+ ```
131
+ Or to both stdout and a file with tee fx.
132
+ ```bash
133
+ scai <file> --modules comment,summary | tee test.txt
134
+ ```
126
135
 
127
136
  ## 🔐 License & Fair Use
128
137
 
@@ -29,7 +29,7 @@ export async function summarizeFile(filepath) {
29
29
  }
30
30
  if (code.trim()) {
31
31
  // Call the summary module to get the raw summary
32
- const summary = await summaryModule.run({ code });
32
+ const summary = await summaryModule.run({ code, filepath });
33
33
  // Pass the summary text to the utility function for formatting
34
34
  const formattedSummary = summarizeCode(summary.code);
35
35
  console.log(formattedSummary);
@@ -0,0 +1,104 @@
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
+ }
@@ -0,0 +1 @@
1
+ "use strict";
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ 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 { generateProjectContext } from './context/generateProjectContext.js';
18
19
  // Create the CLI instance
19
20
  const cmd = new Command('scai')
20
21
  .version(version)
@@ -28,6 +29,12 @@ cmd
28
29
  await bootstrap();
29
30
  console.log('✅ Model initialization completed!');
30
31
  });
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
+ });
31
38
  cmd
32
39
  .command('sugg')
33
40
  .description('Suggest a commit message from staged changes')
@@ -9,12 +9,12 @@ export const addCommentsModule = {
9
9
  const prompt = `
10
10
  You are a senior ${lang.toUpperCase()} engineer reviewing source code.
11
11
 
12
- Your task is to add clear and helpful single-line // comments to complex or non-obvious parts of the code.
12
+ Your task is to add clear and insightful single-line comments to the code.
13
13
 
14
14
  ⚠️ VERY IMPORTANT RULES:
15
15
  - You MUST return the ENTIRE original code.
16
16
  - You MUST NOT remove, replace, reformat, or alter ANY code.
17
- - Only add single-line // comments in appropriate places.
17
+ - Only add single-line // comments to complex or non-obvious parts of the code.
18
18
  - Do NOT wrap the code in markdown or code blocks.
19
19
  - The code should be valid ${lang.toUpperCase()} after your changes.
20
20
 
@@ -6,7 +6,7 @@ export const commitSuggesterModule = {
6
6
  async run({ code }) {
7
7
  const model = ModelConfig.getModel();
8
8
  const prompt = `
9
- Suggest ALWAYS 3 concise, conventional Git commit messages based on this diff.
9
+ Suggest ALWAYS 3 concise, conventional Git commit messages based on the input code diff.
10
10
  Use this format ONLY:
11
11
 
12
12
  1. feat: ...
@@ -1,18 +1,42 @@
1
1
  import { ModelConfig } from '../../config/ModelConfig.js';
2
2
  import { generate } from '../../lib/generate.js';
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
3
5
  export const summaryModule = {
4
6
  name: 'summary',
5
7
  description: 'Prints a summary of changes to the terminal',
6
- async run({ code }) {
8
+ async run({ code, filepath }) {
7
9
  const model = ModelConfig.getModel();
8
10
  const lang = ModelConfig.getLanguage();
11
+ let contextString = '';
12
+ // Try to load and filter the flat context
13
+ try {
14
+ const raw = await fs.readFile('./.scai/context.flat.json', 'utf-8');
15
+ const flatContext = JSON.parse(raw);
16
+ if (filepath) {
17
+ const dir = path.dirname(filepath).replace(/\\/g, '/'); // Normalize slashes
18
+ console.log("Dir: ", dir);
19
+ const contextSubset = Object.entries(flatContext)
20
+ .filter(([file]) => file.startsWith(dir))
21
+ .slice(0, 10); // limit if needed
22
+ if (contextSubset.length) {
23
+ contextString = '📁 Local Context:\n' + contextSubset
24
+ .map(([file, summary]) => `- ${file}: ${summary}`)
25
+ .join('\n');
26
+ console.log("Context string input to prompt: ", contextString);
27
+ }
28
+ }
29
+ }
30
+ catch (err) {
31
+ console.warn('⚠️ Context file not found or failed to parse.');
32
+ }
9
33
  const prompt = `
10
34
  You are a senior ${lang.toUpperCase()} engineer.
11
35
 
12
- Take the following source code and do NOT modify it in any way. Your task is:
36
+ Project Overview:
37
+ ${contextString ? contextString + '\n\n' : ''}
13
38
 
14
- 1. Output the original code exactly as it is.
15
- 2. After the code, append a short summary in this format:
39
+ Take the following source code and do NOT modify it in any way. Your task is:
16
40
 
17
41
  // Summary of code:
18
42
  // - [What the code does at a high level]
@@ -20,9 +44,8 @@ Take the following source code and do NOT modify it in any way. Your task is:
20
44
  // - [Any interesting logic or patterns]
21
45
 
22
46
  ⚠️ IMPORTANT:
23
- - Do NOT omit or alter any part of the original code.
24
- - Do NOT insert comments inside the code.
25
- - Only append the summary AFTER the full code.
47
+ - Do NOT include the original code in your summary
48
+ - Remove the original code from you output
26
49
 
27
50
  --- CODE START ---
28
51
  ${code}
@@ -36,7 +59,6 @@ ${code}
36
59
  else {
37
60
  console.warn('⚠️ No summary generated.');
38
61
  }
39
- // Return unchanged input for composability
40
- return { code };
62
+ return { code }; // passthrough
41
63
  }
42
64
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scai",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "scai": "./dist/index.js"
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "commander": "^11.0.0",
28
+ "fast-glob": "^3.3.3",
28
29
  "ora": "^8.2.0"
29
30
  },
30
31
  "devDependencies": {