scai 0.1.11 → 0.1.12

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
@@ -1,25 +1,26 @@
1
1
  # ⚙️ scai — Smart Commit AI ✨
2
2
 
3
- > AI-powered CLI tools for smart commit messages, automated refactoring, and developer insight — all powered by local models.
3
+ > AI-powered CLI tools for smart commit messages, auto generated comments, and readme files — all powered by local models.
4
4
 
5
5
  **scai** (Smart Commit AI) is a lightweight, privacy-focused CLI tool that uses local AI models (via [Ollama](https://ollama.com)) to help developers work faster and cleaner:
6
6
 
7
7
  - 🤖 Suggest high-quality Git commit messages
8
8
  - ✨ Comments your code automatically
9
- - 🧠 Generate README updates based on your diff
9
+ - 🧠 Get a summary of any code file directly to the terminal
10
10
  - 🔒 100% local — no API keys, no cloud, no telemetry
11
11
 
12
12
  ---
13
13
 
14
- **scai** follows the Unix philosophy — small, composable tools with powerful output.
15
-
16
14
  ## 🚀 Features
17
15
 
18
- - 💬 Generate commit messages from staged Git changes
19
- - Add comments to your code
20
- - ⚡️ Powered by open local Ollama models like `mistral`
21
- - 🛠️ CLI built with Node.js + TypeScript
16
+ - ⚡️ Powered by open local Ollama models like `mistral` and new `commentModule`
17
+ - 🛠️ CLI built with Node.js + TypeScript
22
18
  - 🔒 No external services, full privacy by design
19
+ - ✅ Now supports global options for model and language settings
20
+
21
+ ### 📦 Recent Additions
22
+
23
+ * **Summary Command**: Print a summary of the given file to the terminal (e.g., `scai summ <file>`)
23
24
 
24
25
  ---
25
26
 
@@ -34,6 +35,8 @@ No internet connection. No vendor lock-in. Just local, private, AI-enhanced deve
34
35
  ✅ Backed by open-source models
35
36
  ✅ Designed for CLI-first devs and scriptable workflows
36
37
 
38
+ **scai** follows the Unix philosophy — small, composable tools with powerful output.
39
+
37
40
  ---
38
41
 
39
42
  ## 📦 Installation
@@ -75,7 +78,7 @@ This will:
75
78
  git add .
76
79
 
77
80
  # Let scai suggest a commit message
78
- scai suggest
81
+ scai sugg
79
82
  ```
80
83
 
81
84
  > Example output:
@@ -86,42 +89,29 @@ feat(api): add error handling to user service
86
89
  To automatically commit with the suggested message:
87
90
 
88
91
  ```bash
89
- scai suggest --commit
92
+ scai sugg --commit
90
93
  ```
91
94
 
92
95
  ---
93
96
 
94
- ### 🛠 Refactor a JavaScript file
97
+ ### 🛠 Comment a code file
95
98
 
96
99
  ```bash
97
- scai refac path/to/file.js
100
+ scai comment <file>
98
101
  ```
99
102
 
100
- A cleaned-up version will be written to:
101
-
102
- ```
103
- path/to/refactored/file.refactored.js
104
- ```
103
+ Write comments for the given file. Optional flags:
104
+ - `-a, --apply` - Apply the refactored version to the original file
105
105
 
106
106
  ---
107
107
 
108
- ### 🧩 Generate Tests
108
+ ### 🔍 Code summary
109
109
 
110
110
  ```bash
111
- scai generate-tests <file>
111
+ scai summ <file>
112
112
  ```
113
113
 
114
- Automatically generates Jest test files for specified JavaScript/TypeScript modules.
115
-
116
- ---
117
-
118
- ### 🔍 Check Git status
119
-
120
- ```bash
121
- scai git
122
- ```
123
-
124
- Useful overview of current branch, commits, and uncommitted changes.
114
+ Create a quick summary of the file your working on to gain fast insights.
125
115
 
126
116
  ---
127
117
 
@@ -141,4 +131,4 @@ However:
141
131
 
142
132
  For full terms, see the [LICENSE](./LICENSE) file.
143
133
 
144
- ---
134
+ ---
@@ -1,41 +1,35 @@
1
- // Import required modules
2
1
  import { execSync } from 'child_process';
3
2
  import readline from 'readline';
4
- // Function to ask the user to choose a commit message suggestion
5
3
  async function askUserToChoose(suggestions) {
6
- // Create an interface for reading and writing to the console
7
- const rl = readline.createInterface({
8
- input: process.stdin,
9
- output: process.stdout,
10
- });
11
- // Show AI-suggested commit messages to the user and ask for their choice
12
4
  return new Promise((resolve) => {
13
- console.log('\n💡 AI-suggested commit messages:\n');
5
+ console.log('\n💡 AI-suggested commit messages:\n'); // Display all suggestions to the user
14
6
  suggestions.forEach((msg, i) => {
15
7
  console.log(`${i + 1}) ${msg}`);
16
8
  });
17
- console.log(`${suggestions.length + 1}) 🔁 Regenerate suggestions`);
18
- console.log(`${suggestions.length + 2}) ✍️ Write your own commit message`);
19
- rl.question(`\n👉 Choose a commit message [1-${suggestions.length + 2}]: `, (answer) => {
20
- // Close the readline interface and resolve the promise with user choice
9
+ console.log(`${suggestions.length + 1}) 🔁 Regenerate suggestions`); // Allow the user to regenerate suggestions if they want
10
+ console.log(`${suggestions.length + 2}) ✍️ Write your own commit message`); // Allow the user to write their own commit message
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+ rl.question(`\n👉 Choose a commit message [1-${suggestions.length + 2}]: `, // Ask the user to choose from the suggestions or write their own
16
+ (answer) => {
21
17
  rl.close();
22
- const choice = parseInt(answer, 10);
23
- if (isNaN(choice) || choice < 1 || choice > suggestions.length + 2) {
24
- console.log('⚠️ Invalid selection. Using the first suggestion by default.');
25
- resolve(0);
18
+ const choice = parseInt(answer, 10); // Parse the user's input as a number
19
+ if (isNaN(choice) || choice < 1 || choice > suggestions.length + 2) { // Check that the user has entered a valid number
20
+ console.log('⚠️ Invalid selection. Using the first suggestion by default.'); // Default to the first suggestion if the input is invalid
21
+ resolve(0); // Resolve the promise with the 0-based index (0 to 3)
26
22
  }
27
- else if (choice === suggestions.length + 2) {
28
- resolve('custom');
23
+ else if (choice === suggestions.length + 2) { // If the user has chosen "Write your own commit message"
24
+ resolve('custom'); // Return 'custom' to indicate that the user wants to write their own commit message
29
25
  }
30
26
  else {
31
- resolve(choice - 1); // Return 0-based index (0 to 3)
27
+ resolve(choice - 1); // Return the 0-based index (0 to 3) of the selected suggestion
32
28
  }
33
29
  });
34
30
  });
35
31
  }
36
- // Async function to generate commit message suggestions using an API call
37
32
  async function generateSuggestions(prompt) {
38
- // Fetch the suggestions from an API and return them as an array of strings
39
33
  const res = await fetch("http://localhost:11434/api/generate", {
40
34
  method: "POST",
41
35
  headers: { "Content-Type": "application/json" },
@@ -45,17 +39,19 @@ async function generateSuggestions(prompt) {
45
39
  stream: false,
46
40
  }),
47
41
  });
48
- const { response } = await res.json();
49
- // Check for validity of the LLM response and return an array of commit messages
50
- if (!response || typeof response !== 'string') {
51
- throw new Error('Invalid LLM response');
42
+ const { response } = await res.json(); // Parse the response from the API as JSON
43
+ if (!response || typeof response !== 'string') { // Check that the response is valid
44
+ throw new Error('Invalid LLM response'); // Throw an error if the response is invalid
45
+ }
46
+ const lines = response.trim().split('\n').filter(line => /^\d+\.\s+/.test(line)); // Split the response into individual lines and filter out any lines that don't start with a number followed by a period
47
+ const messages = lines.map(line => // Map each line to its commit message suggestion
48
+ line.replace(/^\d+\.\s+/, '').replace(/^"(.*)"$/, '$1').trim());
49
+ if (messages.length === 0) { // Check that there are any commit message suggestions
50
+ throw new Error('No valid commit messages found in LLM response.'); // Throw an error if there are no valid commit message suggestions
52
51
  }
53
- const lines = response.trim().split('\n').filter(line => /^\d+\.\s+/.test(line));
54
- return lines.map(line => line.replace(/^\d+\.\s+/, '').replace(/^"(.*)"$/, '$1').trim());
52
+ return messages; // Return the array of commit message suggestions
55
53
  }
56
- // Function to prompt the user for a custom commit message
57
- async function promptCustomMessage() {
58
- // Read the user's input for their custom commit message
54
+ function promptCustomMessage() {
59
55
  return new Promise((resolve) => {
60
56
  const rl = readline.createInterface({
61
57
  input: process.stdin,
@@ -63,18 +59,17 @@ async function promptCustomMessage() {
63
59
  });
64
60
  rl.question('\n📝 Enter your custom commit message:\n> ', (input) => {
65
61
  rl.close();
66
- resolve(input.trim());
62
+ resolve(input.trim()); // Resolve the promise with the trimmed input string
67
63
  });
68
64
  });
69
65
  }
70
- // Export the main function to suggest a commit message based on user input and generated suggestions
71
66
  export async function suggestCommitMessage(options) {
72
67
  try {
73
- let diff = execSync("git diff", { encoding: "utf-8" }).trim();
74
- if (!diff) {
75
- diff = execSync("git diff --cached", { encoding: "utf-8" }).trim();
68
+ let diff = execSync("git diff", { encoding: "utf-8" }).trim(); // Get the current Git diff
69
+ if (!diff) { // Check that there are any changes to stage
70
+ diff = execSync("git diff --cached", { encoding: "utf-8" }).trim(); // If there are no staged changes, check for unstaged changes
76
71
  }
77
- if (!diff) {
72
+ if (!diff) { // If there are still no changes, display a message and return early
78
73
  console.log('⚠️ No staged changes to suggest a message for.');
79
74
  return;
80
75
  }
@@ -84,33 +79,28 @@ export async function suggestCommitMessage(options) {
84
79
  3. ...
85
80
 
86
81
  Here is the diff:
87
- ${diff}`;
82
+ ${diff}`; // Create a prompt string for the user to enter their own commit message suggestions
88
83
  let message = null;
89
- while (message === null) {
90
- const suggestions = await generateSuggestions(prompt);
91
- const choice = await askUserToChoose(suggestions);
92
- if (choice === suggestions.length) {
93
- // User chose "Regenerate"
94
- console.log('\n🔄 Regenerating suggestions...\n');
95
- continue;
96
- }
97
- if (choice === 'custom') {
98
- message = await promptCustomMessage();
99
- break;
84
+ while (message === null) { // Loop until the user has entered a valid commit message or chosen to write their own
85
+ const suggestions = await generateSuggestions(prompt); // Generate commit message suggestions based on the diff output from Git
86
+ const choice = await askUserToChoose(suggestions); // Ask the user to choose from the suggestions or write their own
87
+ if (choice === 'custom') { // If the user has chosen "Write your own commit message"
88
+ message = await promptCustomMessage(); // Prompt the user for their custom commit message
89
+ break; // Break out of the loop and use the custom commit message
100
90
  }
101
- message = suggestions[choice];
91
+ message = suggestions[choice]; // Use the selected suggestion as the commit message
102
92
  }
103
- console.log(`\n✅ Selected commit message:\n${message}\n`);
104
- if (options.commit) {
105
- const commitDiff = execSync("git diff", { encoding: "utf-8" }).trim();
106
- if (commitDiff) {
107
- execSync("git add .", { encoding: "utf-8" });
93
+ console.log(`\n✅ Selected commit message:\n${message}\n`); // Display the selected commit message to the user
94
+ if (options.commit) { // If the user has specified that they want to commit the changes
95
+ const commitDiff = execSync("git diff", { encoding: "utf-8" }).trim(); // Get the current Git diff again, in case anything has changed since the last call to `generateSuggestions`
96
+ if (commitDiff) { // Check that there are any staged changes
97
+ execSync("git add .", { encoding: "utf-8" }); // Stage all changes before committing
108
98
  }
109
- execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
110
- console.log('✅ Committed with selected message.');
99
+ execSync(`git commit -m "${message.replace(/"/g, '\\"')}"`, { stdio: 'inherit' }); // Commit the changes with the selected commit message
100
+ console.log('✅ Committed with selected message.'); // Display a success message to the user
111
101
  }
112
102
  }
113
- catch (err) {
114
- console.error('❌ Error in commit message suggestion:', err.message);
103
+ catch (err) { // If there is an error in the code
104
+ console.error('❌ Error in commit message suggestion:', err); // Log the error to the console
115
105
  }
116
106
  }
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Here;
3
+ 's a Jest test file for the `checkEnv` function: `` `typescript
4
+ import { checkEnv } from "../src/utils";
5
+
6
+ describe("checkEnv", () => {
7
+ it("should warn when missing required env vars", () => {
8
+ const processEnv = Object.assign({}, process.env);
9
+ delete processEnv.DB_HOST;
10
+ delete processEnv.API_KEY;
11
+ const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
12
+ checkEnv();
13
+ expect(consoleWarnSpy).toHaveBeenCalledWith("❌ Missing env vars: DB_HOST, API_KEY");
14
+ consoleWarnSpy.mockRestore();
15
+ });
16
+
17
+ it("should log a message when all required env vars are set", () => {
18
+ const processEnv = Object.assign({}, process.env);
19
+ checkEnv();
20
+ expect(console.log).toHaveBeenCalledWith("✅ All env vars are set");
21
+ });
22
+ });
23
+ ` ``;
24
+ In;
25
+ this;
26
+ test;
27
+ file, we;
28
+ first;
29
+ var the = ;
30
+ `checkEnv`;
31
+ function from() { }
32
+ the;
33
+ contains;
34
+ it.We;
35
+ then;
36
+ define;
37
+ two;
38
+ test;
39
+ cases: one;
40
+ for (when; required; environment)
41
+ variables;
42
+ are;
43
+ missing;
44
+ and;
45
+ another;
46
+ for (when; all; required)
47
+ environment;
48
+ variables;
49
+ are;
50
+ set.
51
+ ;
52
+ In;
53
+ the;
54
+ first;
55
+ test;
56
+ we;
57
+ use `jest.spyOn()`;
58
+ to;
59
+ mock;
60
+ the `console.warn()`;
61
+ method;
62
+ and;
63
+ replace;
64
+ it;
65
+ with (a)
66
+ spy;
67
+ function () { }
68
+ We;
69
+ then;
70
+ delete the `DB_HOST`;
71
+ and `API_KEY`;
72
+ environment;
73
+ variables;
74
+ and;
75
+ call;
76
+ the `checkEnv()`;
77
+ function () { }
78
+ Finally, we;
79
+ check;
80
+ that;
81
+ the `console.warn()`;
82
+ method;
83
+ was;
84
+ called;
85
+ with (the)
86
+ expected;
87
+ message.
88
+ ;
89
+ In;
90
+ the;
91
+ second;
92
+ test;
93
+ we;
94
+ simply;
95
+ call;
96
+ the `checkEnv()`;
97
+ function without() { }
98
+ deleting;
99
+ any;
100
+ environment;
101
+ variables;
102
+ and;
103
+ check;
104
+ that;
105
+ the `console.log()`;
106
+ method;
107
+ was;
108
+ called;
109
+ with (the)
110
+ expected;
111
+ message.
112
+ ;
113
+ Note;
114
+ that;
115
+ we;
116
+ use;
117
+ the `mockImplementation()`;
118
+ method;
119
+ to;
120
+ mock;
121
+ the `console.warn()`;
122
+ method;
123
+ and;
124
+ the `mockRestore()`;
125
+ method;
126
+ to;
127
+ restore;
128
+ it;
129
+ after;
130
+ the;
131
+ test;
132
+ is;
133
+ done.This;
134
+ is;
135
+ necessary;
136
+ because;
137
+ Jest;
138
+ does;
139
+ not;
140
+ allow;
141
+ us;
142
+ to;
143
+ modify;
144
+ the;
145
+ original `console.warn()`;
146
+ method.;
@@ -0,0 +1,12 @@
1
+ // File: src/commands/SummaryCmd.ts
2
+ import fs from 'fs/promises';
3
+ import { summaryModule } from '../pipeline/modules/summaryModule.js';
4
+ export async function summarizeFile(filepath) {
5
+ try {
6
+ const code = await fs.readFile(filepath, 'utf-8');
7
+ await summaryModule.run({ code });
8
+ }
9
+ catch (err) {
10
+ console.error(`❌ Could not read or summarize ${filepath}:`, err.message);
11
+ }
12
+ }
@@ -0,0 +1,16 @@
1
+ export class ModelConfig {
2
+ static setModel(model) {
3
+ this.model = model;
4
+ }
5
+ static getModel() {
6
+ return this.model;
7
+ }
8
+ static setLanguage(lang) {
9
+ this.language = lang;
10
+ }
11
+ static getLanguage() {
12
+ return this.language;
13
+ }
14
+ }
15
+ ModelConfig.model = 'codellama:7b';
16
+ ModelConfig.language = 'ts';
package/dist/index.js CHANGED
@@ -1,16 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
+ import { createRequire } from 'module';
4
+ const require = createRequire(import.meta.url);
5
+ const { version } = require('../package.json');
3
6
  import { checkEnv } from "./commands/EnvCmd.js";
4
7
  import { checkGit } from "./commands/GitCmd.js";
5
8
  import { suggestCommitMessage } from "./commands/CommitSuggesterCmd.js";
6
9
  import { handleRefactor } from "./commands/RefactorCmd.js";
7
10
  import { updateReadmeIfNeeded } from "./commands/ReadmeCmd.js";
8
11
  import { generateTests } from "./commands/TestGenCmd.js";
9
- // Import the model check and initialization logic
10
12
  import { bootstrap } from './modelSetup.js';
13
+ import { ModelConfig } from './config/ModelConfig.js';
14
+ import { summarizeFile } from "./commands/SummaryCmd.js";
11
15
  // Create the CLI instance
12
16
  const cmd = new Command('scai')
13
- .version('0.1.0');
17
+ .version(version)
18
+ .option('--model <model>', 'Set the model to use (e.g., codellama:34b)')
19
+ .option('--lang <lang>', 'Set the target language (ts, java, rust)');
14
20
  // Define CLI commands
15
21
  cmd
16
22
  .command('init')
@@ -20,21 +26,13 @@ cmd
20
26
  console.log('✅ Model initialization completed!');
21
27
  });
22
28
  cmd
23
- .command('env')
24
- .description('Check environment variables')
25
- .action(checkEnv);
26
- cmd
27
- .command('git')
28
- .description('Check Git status')
29
- .action(checkGit);
30
- cmd
31
- .command('suggest')
29
+ .command('sugg')
32
30
  .description('Suggest a commit message from staged changes')
33
31
  .option('-c, --commit', 'Automatically commit with suggested message')
34
32
  .action(suggestCommitMessage);
35
33
  cmd
36
- .command('refac <file>')
37
- .description('Suggest a refactor for the given JS/TS file')
34
+ .command('comm <file>')
35
+ .description('Write comments for the given file')
38
36
  .option('-a, --apply', 'Apply the refactored version to the original file')
39
37
  .action((file, options) => handleRefactor(file, options));
40
38
  cmd
@@ -42,8 +40,26 @@ cmd
42
40
  .description('Update README.md if relevant changes were made')
43
41
  .action(updateReadmeIfNeeded);
44
42
  cmd
45
- .command('generate-tests <file>')
43
+ .command('summ <file>')
44
+ .description('Print a summary of the given file to the terminal')
45
+ .action((file) => summarizeFile(file));
46
+ cmd
47
+ .command('git')
48
+ .description('Check Git status')
49
+ .action(checkGit);
50
+ cmd
51
+ .command('env')
52
+ .description('Check environment variables')
53
+ .action(checkEnv);
54
+ cmd
55
+ .command('gen-tests <file>')
46
56
  .description('Generate a Jest test file for the specified JS/TS module')
47
57
  .action((file) => generateTests(file));
48
- // Parse CLI arguments
58
+ // Now that commands are defined, parse args
49
59
  cmd.parse(process.argv);
60
+ // ✅ Apply global options after parsing
61
+ const opts = cmd.opts();
62
+ if (opts.model)
63
+ ModelConfig.setModel(opts.model);
64
+ if (opts.lang)
65
+ ModelConfig.setLanguage(opts.lang);
@@ -1,9 +1,12 @@
1
+ import { ModelConfig } from '../../config/ModelConfig.js';
1
2
  export const addCommentsModule = {
2
3
  name: 'addComments',
3
4
  description: 'Adds meaningful // comments to each block of code',
4
5
  async run(input) {
6
+ const model = ModelConfig.getModel();
7
+ const lang = ModelConfig.getLanguage();
5
8
  const prompt = `
6
- You are a senior JavaScript engineer.
9
+ You are a senior ${lang.toUpperCase()} engineer.
7
10
 
8
11
  Add clear and helpful single-line // comments to complex parts of the code.
9
12
  - Do NOT remove or change in ANY way any parts of the code!
@@ -17,8 +20,8 @@ ${input.code}
17
20
  method: 'POST',
18
21
  headers: { 'Content-Type': 'application/json' },
19
22
  body: JSON.stringify({
20
- model: 'mistral',
21
- prompt: prompt,
23
+ model,
24
+ prompt,
22
25
  stream: false,
23
26
  }),
24
27
  });
@@ -1,11 +1,14 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
+ import { ModelConfig } from '../../config/ModelConfig.js';
3
4
  export const generateTestsModule = {
4
5
  name: 'generateTests',
5
6
  description: 'Generate a Jest test file for the class/module',
6
7
  async run({ code, filepath }) {
8
+ const model = ModelConfig.getModel();
9
+ const lang = ModelConfig.getLanguage();
7
10
  const prompt = `
8
- You're a senior TypeScript developer. Given the following class or module, generate a Jest test file.
11
+ You are a senior ${lang.toUpperCase()} engineer. Given the following class or module, generate a Jest test file.
9
12
 
10
13
  Guidelines:
11
14
  - Use the 'jest' test framework
@@ -21,7 +24,7 @@ ${code}
21
24
  method: 'POST',
22
25
  headers: { 'Content-Type': 'application/json' },
23
26
  body: JSON.stringify({
24
- model: 'mistral',
27
+ model,
25
28
  prompt,
26
29
  stream: false
27
30
  })
@@ -1,25 +1,45 @@
1
+ import { ModelConfig } from '../../config/ModelConfig.js';
1
2
  export const refactorModule = {
2
3
  name: 'refactor',
3
4
  description: 'Break code into small, clean functions',
4
- async run({ code }) {
5
+ async run(input) {
6
+ const model = ModelConfig.getModel();
7
+ const lang = ModelConfig.getLanguage();
5
8
  const prompt = `
6
- You are a senior JavaScript/TypeScript engineer.
9
+ You are a senior ${lang.toUpperCase()} engineer.
7
10
 
8
11
  Refactor the following code:
9
- - Refactor only long and complex functions
12
+ - Refactor only long and complex functions
10
13
  - Keep original names and semantics.
11
14
  - Do NOT insert comments
12
15
 
13
16
  --- CODE START ---
14
- ${code}
17
+ ${input.code}
15
18
  --- CODE END ---
16
19
  `.trim();
17
- const res = await fetch('http://localhost:11434/api/generate', {
18
- method: 'POST',
19
- headers: { 'Content-Type': 'application/json' },
20
- body: JSON.stringify({ model: 'mistral', prompt: prompt, stream: false })
21
- });
22
- const data = await res.json();
23
- return { code: data.response?.trim() ?? '' };
20
+ try {
21
+ const res = await fetch('http://localhost:11434/api/generate', {
22
+ method: 'POST',
23
+ headers: { 'Content-Type': 'application/json' },
24
+ body: JSON.stringify({
25
+ model,
26
+ prompt,
27
+ stream: false
28
+ })
29
+ });
30
+ if (!res.ok) {
31
+ const errBody = await res.text();
32
+ throw new Error(`❌ Refactor failed: ${res.status} ${res.statusText} - ${errBody}`);
33
+ }
34
+ const data = await res.json();
35
+ if (!data.response) {
36
+ throw new Error('❌ No response field returned from model.');
37
+ }
38
+ return { code: data.response.trim() };
39
+ }
40
+ catch (err) {
41
+ console.error('🔥 Error in refactorModule:', err);
42
+ throw new Error('❌ Error in refactor module: ' + err.message);
43
+ }
24
44
  }
25
45
  };
@@ -1,20 +1,22 @@
1
+ import { ModelConfig } from '../../config/ModelConfig.js';
1
2
  export const summaryModule = {
2
3
  name: 'summary',
3
- description: 'Append // Summary of changes at the end',
4
+ description: 'Prints a summary of changes to the terminal',
4
5
  async run({ code }) {
6
+ const model = ModelConfig.getModel();
7
+ const lang = ModelConfig.getLanguage();
5
8
  const prompt = `
6
- You are a senior developer assistant.
9
+ You are a senior ${lang.toUpperCase()} engineer.
7
10
 
8
- Take the following code and return it exactly as-is,
9
- but add a summary at the very end in this format:
11
+ Analyze the code below and return a concise summary of its functionality or structure.
12
+ Only return the summary in this format:
10
13
 
11
- // Summary of refactor:
12
- // - Did X
13
- // - Did Y
14
+ // Summary of code:
15
+ // - [Bullet 1]
16
+ // - [Bullet 2]
14
17
  // - etc.
15
18
 
16
- DO NOT modify or omit any existing code.
17
- Just append the summary.
19
+ Return the original code after the summary.
18
20
 
19
21
  --- CODE START ---
20
22
  ${code}
@@ -23,9 +25,18 @@ ${code}
23
25
  const res = await fetch('http://localhost:11434/api/generate', {
24
26
  method: 'POST',
25
27
  headers: { 'Content-Type': 'application/json' },
26
- body: JSON.stringify({ model: 'llama3', prompt: prompt, stream: false })
28
+ body: JSON.stringify({ model, prompt, stream: false })
27
29
  });
28
30
  const data = await res.json();
29
- return { code: data.response?.trim() ?? '' };
31
+ const summary = data.response?.trim();
32
+ if (summary) {
33
+ console.log('\n📝 Code Summary:\n');
34
+ console.log(summary);
35
+ }
36
+ else {
37
+ console.warn('⚠️ No summary generated.');
38
+ }
39
+ // Return unchanged input so it’s pipe-safe, if reused in pipelines
40
+ return { code };
30
41
  }
31
42
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scai",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "scai": "./dist/index.js"