scai 0.1.105 → 0.1.107
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 +86 -33
- package/dist/CHANGELOG.md +6 -1
- package/dist/agent/agentManager.js +12 -13
- package/dist/agent/workflowManager.js +1 -0
- package/dist/context.js +1 -26
- package/dist/index.js +26 -27
- package/dist/lib/generate.js +24 -19
- package/dist/lib/spinner.js +11 -5
- package/dist/pipeline/modules/commentModule.js +3 -7
- package/dist/pipeline/registry/moduleRegistry.js +74 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
# ⚙️ scai — Smart Commit AI ✨
|
|
2
2
|
|
|
3
|
-
> AI-powered CLI tool for commit messages
|
|
3
|
+
> AI-powered CLI tool for commit messages, pull request reviews, **and agent-driven workflows** — using local models.
|
|
4
4
|
|
|
5
5
|
**scai** is your AI pair‑programmer in the terminal. Focus on coding while scai:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
|
|
7
|
+
* 💬 **Suggests intelligent Git commit messages** based on your staged diff
|
|
8
|
+
* 🤖 **Reviews open pull requests** and provides AI‑driven feedback (BETA)
|
|
9
|
+
* 📝 **Generates comments for multiple files** while you keep coding
|
|
10
|
+
* 🤖 **Runs agent workflows** to automate repetitive tasks like summarizing, commenting, or running tests — run agents on single files or entire folders with custom goals
|
|
11
|
+
* 📜 Auto‑updates your changelog
|
|
12
|
+
* 🔍 (ALPHA) Search & ask questions across your codebase
|
|
13
|
+
* 🔐 100% local — no API keys, no cloud, no telemetry
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
### 🧩 Agent Mode Examples
|
|
18
|
+
|
|
19
|
+
Run an agent workflow with goals:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Run comments and tests on a single file
|
|
23
|
+
$ scai agent run comments tests -f path/to/myfile
|
|
24
|
+
|
|
25
|
+
# Run summary on all files in a folder
|
|
26
|
+
$ scai agent run summary -f path/to/myfolder
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The agent mode allows you to chain goals (`summary → comments → tests`) while processing files or directories automatically, keeping your workflow fast and focused.
|
|
30
|
+
|
|
13
31
|
|
|
14
32
|
---
|
|
15
33
|
|
|
@@ -52,6 +70,42 @@ scai runs entirely on your machine and doesn't require cloud APIs or API keys. T
|
|
|
52
70
|
scai init
|
|
53
71
|
```
|
|
54
72
|
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🤖 Agent Workflow Command
|
|
76
|
+
|
|
77
|
+
The `agent` command allows you to run a sequence of AI-powered workflows (goals) on one or multiple files or even an entire folder. This is useful for tasks like generating comments, summaries, or tests, while letting the AI work in the background as you continue coding.
|
|
78
|
+
|
|
79
|
+
### Usage
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Run agent with comments and tests on a single file
|
|
83
|
+
scai agent run comments tests -f path/to/file.ts
|
|
84
|
+
|
|
85
|
+
# Run agent on an entire folder
|
|
86
|
+
scai agent run comments tests -f path/to/folder
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You can provide multiple goals, which will be executed in the order specified. Currently supported example goals:
|
|
90
|
+
|
|
91
|
+
* `summary` – Summarize a file
|
|
92
|
+
* `comments` – Add inline comments to code
|
|
93
|
+
* `tests` – Generate test stubs (ALPHA)
|
|
94
|
+
|
|
95
|
+
#### Features
|
|
96
|
+
|
|
97
|
+
* ✅ Works on single files or entire folders recursively
|
|
98
|
+
* ✅ Processes multiple files in the background, so you can continue coding
|
|
99
|
+
* ✅ Modular design allows you to chain goals (e.g., `comments → tests → summary`)
|
|
100
|
+
|
|
101
|
+
#### Notes
|
|
102
|
+
|
|
103
|
+
* Only `summary`, `comments`, and `tests` are currently fully supported. Other modules are experimental.
|
|
104
|
+
* The agent resolves folders into all supported files (`.ts`, `.js`, etc.) automatically.
|
|
105
|
+
* Background processing allows you to queue multiple files without waiting for each one to finish interactively.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
55
109
|
## ✨ AI Code Review, Powered by Your Terminal
|
|
56
110
|
|
|
57
111
|
No more struggling to write pull request descriptions by hand. `scai git review` automatically generates a rich summary of your changes, complete with context, suggestions, and rationale.
|
|
@@ -95,6 +149,30 @@ To interact with GitHub and create pull requests, `scai` needs a personal access
|
|
|
95
149
|
|
|
96
150
|
---
|
|
97
151
|
## ⚒️ Usage Overview
|
|
152
|
+
|
|
153
|
+
### 🔧 How to Use `scai git commit`
|
|
154
|
+
|
|
155
|
+
Use AI to suggest a meaningful commit message based on your staged code:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
git add .
|
|
159
|
+
scai git commit
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
You can also include a changelog entry along with the commit:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
scai git commit --changelog
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This will:
|
|
169
|
+
1. Suggest a commit message based on your `git diff --cached`
|
|
170
|
+
2. Propose a changelog entry (if relevant)
|
|
171
|
+
3. Allow you to approve, regenerate, or skip the changelog
|
|
172
|
+
4. Automatically stage and commit the changes
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
98
176
|
### 🧠 How to Use `scai git review`
|
|
99
177
|
|
|
100
178
|
```bash
|
|
@@ -182,31 +260,6 @@ You might consider renaming `sessionManager` to better reflect its dual role in
|
|
|
182
260
|
5) 🚪 Cancel
|
|
183
261
|
```
|
|
184
262
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
### 🔧 How to Use `scai git commit`
|
|
188
|
-
|
|
189
|
-
Use AI to suggest a meaningful commit message based on your staged code:
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
git add .
|
|
193
|
-
scai git commit
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
You can also include a changelog entry along with the commit:
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
scai git commit --changelog
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
This will:
|
|
203
|
-
1. Suggest a commit message based on your `git diff --cached`
|
|
204
|
-
2. Propose a changelog entry (if relevant)
|
|
205
|
-
3. Allow you to approve, regenerate, or skip the changelog
|
|
206
|
-
4. Automatically stage and commit the changes
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
263
|
### 📝 Generate a Standalone Changelog Entry
|
|
211
264
|
|
|
212
265
|
If you want to generate a changelog entry without committing:
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -157,4 +157,9 @@ Type handling with the module pipeline
|
|
|
157
157
|
• Introduce Agent class with minimal implementation
|
|
158
158
|
• Improve test-module's filepath handling and variable naming
|
|
159
159
|
• Rename workflowManager.ts to agent/workflowManager.ts
|
|
160
|
-
• Improved formatting of agent run summary output
|
|
160
|
+
• Improved formatting of agent run summary output
|
|
161
|
+
|
|
162
|
+
## 2025-08-31
|
|
163
|
+
|
|
164
|
+
• Update Spinner class to correctly display text and frames
|
|
165
|
+
• Update CLI help to reflect new agent workflow examples.
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
// src/agent/agentManager.ts
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveModuleOrder } from "../pipeline/registry/moduleRegistry.js";
|
|
5
5
|
import { handleAgentRun } from "./workflowManager.js";
|
|
6
|
-
// Minimal agent:
|
|
6
|
+
// Minimal agent: resolves modules (with before/after dependencies) and delegates to handleAgentRun
|
|
7
7
|
export class Agent {
|
|
8
8
|
constructor(goals) {
|
|
9
9
|
// Trim goal names to avoid whitespace issues
|
|
10
|
-
this.goals = goals.map(g => g.trim());
|
|
10
|
+
this.goals = goals.map((g) => g.trim());
|
|
11
|
+
}
|
|
12
|
+
resolveModules(goals) {
|
|
13
|
+
// Use the registry helper to get the correct order
|
|
14
|
+
return resolveModuleOrder(goals);
|
|
11
15
|
}
|
|
12
16
|
async execute(filepath) {
|
|
13
17
|
console.log(chalk.cyan(`🤖 Agent starting on: ${filepath}`));
|
|
14
|
-
//
|
|
15
|
-
const modules = this.goals
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return mod;
|
|
20
|
-
});
|
|
21
|
-
console.log(chalk.green("📋 Modules to run:"), modules.map(m => m.name).join(" → "));
|
|
22
|
-
// Read file content
|
|
23
|
-
const content = await fs.readFile(filepath, "utf-8");
|
|
18
|
+
// Resolve modules (with before/after dependencies)
|
|
19
|
+
const modules = this.resolveModules(this.goals);
|
|
20
|
+
console.log(chalk.green("📋 Modules to run:"), modules.map((m) => m.name).join(" → "));
|
|
21
|
+
// Read file content (optional, could be used by modules in workflow)
|
|
22
|
+
await fs.readFile(filepath, "utf-8");
|
|
24
23
|
// Delegate everything to handleAgentRun (like CLI commands do)
|
|
25
24
|
await handleAgentRun(filepath, modules);
|
|
26
25
|
console.log(chalk.green("✅ Agent finished!"));
|
|
@@ -4,6 +4,7 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { runModulePipeline } from '../pipeline/runModulePipeline.js';
|
|
5
5
|
import { countTokens, splitCodeIntoChunks } from '../utils/splitCodeIntoChunk.js';
|
|
6
6
|
import { normalizePath } from '../utils/contentUtils.js';
|
|
7
|
+
// basically handles all input (chunk if large), and writing of output (overwrite, append, new file)
|
|
7
8
|
export async function handleAgentRun(filepath, modules) {
|
|
8
9
|
try {
|
|
9
10
|
filepath = normalizePath(filepath);
|
package/dist/context.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// context.ts
|
|
2
|
-
import { readConfig, writeConfig
|
|
2
|
+
import { readConfig, writeConfig } from "./config.js";
|
|
3
3
|
import { normalizePath } from "./utils/contentUtils.js";
|
|
4
4
|
import { getHashedRepoKey } from "./utils/repoKey.js";
|
|
5
5
|
import { getDbForRepo, getDbPathForRepo } from "./db/client.js";
|
|
6
6
|
import fs from "fs";
|
|
7
7
|
import chalk from "chalk";
|
|
8
|
-
import { generate } from "./lib/generate.js"; // 👈 use your existing generate wrapper
|
|
9
|
-
import { startModelProcess } from "./utils/checkModel.js";
|
|
10
8
|
export async function updateContext() {
|
|
11
9
|
const cwd = normalizePath(process.cwd());
|
|
12
10
|
const cfg = readConfig();
|
|
@@ -56,17 +54,6 @@ export async function updateContext() {
|
|
|
56
54
|
else if (isNewRepo || activeRepoChanged) {
|
|
57
55
|
console.log(chalk.green("✅ Database present"));
|
|
58
56
|
}
|
|
59
|
-
// ✅ NEW: Ensure model is available
|
|
60
|
-
if (ok) {
|
|
61
|
-
const modelReady = await ensureModelReady();
|
|
62
|
-
if (modelReady) {
|
|
63
|
-
console.log(chalk.green("✅ Model ready"));
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
console.log(chalk.red("❌ Model not available"));
|
|
67
|
-
ok = false;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
57
|
// Final context status
|
|
71
58
|
if (ok) {
|
|
72
59
|
console.log(chalk.bold.green("\n✅ Context OK\n"));
|
|
@@ -76,15 +63,3 @@ export async function updateContext() {
|
|
|
76
63
|
}
|
|
77
64
|
return ok;
|
|
78
65
|
}
|
|
79
|
-
async function ensureModelReady() {
|
|
80
|
-
try {
|
|
81
|
-
// simple "ping" prompt that costs almost nothing
|
|
82
|
-
const res = await generate({ content: "ping" }, Config.getModel());
|
|
83
|
-
return Boolean(res?.content);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
console.log(chalk.yellow("⚡ Model not responding. Attempting to start..."));
|
|
87
|
-
await startModelProcess();
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -25,16 +25,10 @@ import { runInteractiveSwitch } from "./commands/SwitchCmd.js";
|
|
|
25
25
|
import { execSync } from "child_process";
|
|
26
26
|
import { fileURLToPath } from "url";
|
|
27
27
|
import { dirname, resolve } from "path";
|
|
28
|
-
import { handleAgentRun } from './agent/workflowManager.js';
|
|
29
|
-
import { addCommentsModule } from './pipeline/modules/commentModule.js';
|
|
30
|
-
import { generateTestsModule } from './pipeline/modules/generateTestsModule.js';
|
|
31
|
-
import { preserveCodeModule } from './pipeline/modules/preserveCodeModule.js';
|
|
32
28
|
import { runInteractiveDelete } from './commands/DeleteIndex.js';
|
|
33
29
|
import { resolveTargetsToFiles } from './utils/resolveTargetsToFiles.js';
|
|
34
30
|
import { updateContext } from './context.js';
|
|
35
|
-
import { cleanGeneratedTestsModule } from './pipeline/modules/cleanGeneratedTestsModule.js';
|
|
36
31
|
import { Agent } from './agent/agentManager.js';
|
|
37
|
-
import { builtInModules } from './pipeline/registry/moduleRegistry.js';
|
|
38
32
|
// 🎛️ CLI Setup
|
|
39
33
|
const cmd = new Command('scai')
|
|
40
34
|
.version(version)
|
|
@@ -51,11 +45,13 @@ cmd
|
|
|
51
45
|
// 🔧 Group: Agent-related commands
|
|
52
46
|
const agent = cmd
|
|
53
47
|
.command('agent')
|
|
54
|
-
.description(`Run an agent workflow.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
`
|
|
58
|
-
`
|
|
48
|
+
.description(`Run an agent workflow. Example available tools:\n` +
|
|
49
|
+
` - summary\n` +
|
|
50
|
+
` - comments\n` +
|
|
51
|
+
` - tests\n\n` +
|
|
52
|
+
`Example usage:\n` +
|
|
53
|
+
` $ scai agent run comments tests -f path/to/myfile\n` +
|
|
54
|
+
` This will run the agent with the goals: comments → tests\n`);
|
|
59
55
|
// Run workflow subcommand
|
|
60
56
|
const runCmd = agent
|
|
61
57
|
.command('run <goals...>')
|
|
@@ -71,10 +67,12 @@ const runCmd = agent
|
|
|
71
67
|
await agentInstance.execute(file);
|
|
72
68
|
});
|
|
73
69
|
});
|
|
74
|
-
//
|
|
70
|
+
// Optional: show example modules on --help
|
|
75
71
|
runCmd.on('--help', () => {
|
|
76
|
-
console.log('\
|
|
77
|
-
|
|
72
|
+
console.log('\nExample tools:');
|
|
73
|
+
console.log(' - summary');
|
|
74
|
+
console.log(' - comments');
|
|
75
|
+
console.log(' - tests');
|
|
78
76
|
});
|
|
79
77
|
// 🔧 Group: Git-related commands
|
|
80
78
|
const git = cmd.command('git').description('Git utilities');
|
|
@@ -155,10 +153,22 @@ gen
|
|
|
155
153
|
.description("Write comments for the given file(s) or folder(s)")
|
|
156
154
|
.action(async (targets) => {
|
|
157
155
|
await withContext(async () => {
|
|
158
|
-
// Remove the file type filter to allow any file
|
|
159
156
|
const files = await resolveTargetsToFiles(targets);
|
|
160
157
|
for (const file of files) {
|
|
161
|
-
|
|
158
|
+
const agent = new Agent(["comments"]); // goals: "comments"
|
|
159
|
+
await agent.execute(file); // run on the file
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
gen
|
|
164
|
+
.command("test <targets...>")
|
|
165
|
+
.description("Generate tests for the given file(s) or folder(s)")
|
|
166
|
+
.action(async (targets) => {
|
|
167
|
+
await withContext(async () => {
|
|
168
|
+
const files = await resolveTargetsToFiles(targets);
|
|
169
|
+
for (const file of files) {
|
|
170
|
+
const agent = new Agent(["tests"]); // goals: "tests"
|
|
171
|
+
await agent.execute(file);
|
|
162
172
|
}
|
|
163
173
|
});
|
|
164
174
|
});
|
|
@@ -178,17 +188,6 @@ gen
|
|
|
178
188
|
summarizeFile(file);
|
|
179
189
|
});
|
|
180
190
|
});
|
|
181
|
-
gen
|
|
182
|
-
.command("test <targets...>")
|
|
183
|
-
.description("Generate tests for the given file(s) or folder(s)")
|
|
184
|
-
.action(async (targets, options) => {
|
|
185
|
-
await withContext(async () => {
|
|
186
|
-
const files = await resolveTargetsToFiles(targets);
|
|
187
|
-
for (const file of files) {
|
|
188
|
-
await handleAgentRun(file, [generateTestsModule, cleanGeneratedTestsModule]);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
191
|
// ⚙️ Group: Configuration settings
|
|
193
192
|
const config = cmd.command('config').description('Manage SCAI configuration');
|
|
194
193
|
config
|
package/dist/lib/generate.js
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
// File: lib/generate.ts
|
|
2
2
|
import { Spinner } from './spinner.js';
|
|
3
3
|
import { readConfig } from '../config.js';
|
|
4
|
+
import { startModelProcess } from '../utils/checkModel.js';
|
|
4
5
|
export async function generate(input, model) {
|
|
5
6
|
const contextLength = readConfig().contextLength ?? 8192;
|
|
6
7
|
let prompt = input.content;
|
|
7
8
|
if (prompt.length > contextLength) {
|
|
8
|
-
console.warn(`⚠️ Warning: Input prompt length (${prompt.length}) exceeds model context length (${contextLength})
|
|
9
|
+
console.warn(`⚠️ Warning: Input prompt length (${prompt.length}) exceeds model context length (${contextLength}).`);
|
|
9
10
|
}
|
|
10
11
|
const spinner = new Spinner(`🧠 Thinking with ${model}...`);
|
|
11
12
|
spinner.start();
|
|
12
13
|
try {
|
|
13
|
-
|
|
14
|
-
method: 'POST',
|
|
15
|
-
headers: { 'Content-Type': 'application/json' },
|
|
16
|
-
body: JSON.stringify({
|
|
17
|
-
model,
|
|
18
|
-
prompt, // use truncated prompt here
|
|
19
|
-
stream: false,
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
const data = await res.json();
|
|
23
|
-
spinner.succeed('Model response received.');
|
|
24
|
-
process.stdout.write('\n');
|
|
25
|
-
return {
|
|
26
|
-
content: data.response?.trim() ?? '',
|
|
27
|
-
filepath: input.filepath,
|
|
28
|
-
};
|
|
14
|
+
return await doGenerate(prompt, model, spinner, false);
|
|
29
15
|
}
|
|
30
16
|
catch (err) {
|
|
31
|
-
spinner.fail('Model request failed.');
|
|
17
|
+
spinner.fail('Model request failed. Attempting to start model...');
|
|
32
18
|
process.stdout.write('\n');
|
|
33
|
-
|
|
19
|
+
await startModelProcess();
|
|
20
|
+
spinner.update(`🧠 Retrying with ${model}...`);
|
|
21
|
+
return await doGenerate(prompt, model, spinner, true); // retry once
|
|
34
22
|
}
|
|
35
23
|
}
|
|
24
|
+
async function doGenerate(prompt, model, spinner, retrying) {
|
|
25
|
+
const res = await fetch('http://localhost:11434/api/generate', {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: { 'Content-Type': 'application/json' },
|
|
28
|
+
body: JSON.stringify({
|
|
29
|
+
model,
|
|
30
|
+
prompt,
|
|
31
|
+
stream: false,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
const data = await res.json();
|
|
35
|
+
spinner.succeed(retrying ? 'Model response received after restart.' : 'Model response received.');
|
|
36
|
+
process.stdout.write('\n');
|
|
37
|
+
return {
|
|
38
|
+
content: data.response?.trim() ?? '',
|
|
39
|
+
};
|
|
40
|
+
}
|
package/dist/lib/spinner.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// lib/spinner.ts
|
|
2
1
|
export class Spinner {
|
|
3
2
|
constructor(message) {
|
|
4
3
|
this.frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
@@ -8,18 +7,25 @@ export class Spinner {
|
|
|
8
7
|
}
|
|
9
8
|
start() {
|
|
10
9
|
process.stdout.write('\x1b[?25l'); // hide cursor
|
|
10
|
+
process.stdout.write(` ${this.text}`); // print text once
|
|
11
11
|
this.interval = setInterval(() => {
|
|
12
|
-
|
|
13
|
-
process.stdout.write(
|
|
12
|
+
process.stdout.write('\r'); // return to start of line
|
|
13
|
+
process.stdout.write(`${this.frames[this.i]} ${this.text}`);
|
|
14
|
+
this.i = (this.i + 1) % this.frames.length;
|
|
14
15
|
}, 80);
|
|
15
16
|
}
|
|
17
|
+
update(text) {
|
|
18
|
+
this.text = text;
|
|
19
|
+
}
|
|
16
20
|
succeed(msg) {
|
|
17
21
|
this.stop();
|
|
18
|
-
process.stdout.write(
|
|
22
|
+
process.stdout.write('\r'); // go to start
|
|
23
|
+
console.log(`✅ ${msg}`);
|
|
19
24
|
}
|
|
20
25
|
fail(msg) {
|
|
21
26
|
this.stop();
|
|
22
|
-
process.stdout.write(
|
|
27
|
+
process.stdout.write('\r'); // go to start
|
|
28
|
+
console.log(`❌ ${msg}`);
|
|
23
29
|
}
|
|
24
30
|
stop() {
|
|
25
31
|
if (this.interval) {
|
|
@@ -43,16 +43,12 @@ You are a senior engineer reviewing a ${fileType} file.
|
|
|
43
43
|
Please:
|
|
44
44
|
|
|
45
45
|
- Add summary comments (2-3 lines) at relevant points for greater class insights
|
|
46
|
-
- Add clear, helpful inline
|
|
46
|
+
- Add clear, helpful inline-comments to explain non-obvious logic inside functions.
|
|
47
47
|
- Use "${commentSyntax}" as the comment syntax appropriate for ${fileType}.
|
|
48
|
-
- Preserve all original formatting, whitespace, and code exactly.
|
|
49
48
|
|
|
50
49
|
Rules:
|
|
51
|
-
- Return the full original chunk of code with added comments
|
|
52
|
-
-
|
|
53
|
-
- Summaries should be brief but meaningful.
|
|
54
|
-
- Inline comments should clarify complex or tricky parts only.
|
|
55
|
-
- Do NOT add any “chunk” start/end markers, numbering, or metadata to the output.
|
|
50
|
+
- Return the full original chunk of code with added comments.
|
|
51
|
+
- Inline comments should clarify complex or tricky parts.
|
|
56
52
|
|
|
57
53
|
${input.content}
|
|
58
54
|
|
|
@@ -6,24 +6,88 @@ import { commitSuggesterModule } from '../modules/commitSuggesterModule.js';
|
|
|
6
6
|
import { changelogModule } from '../modules/changeLogModule.js';
|
|
7
7
|
import { cleanGeneratedTestsModule } from '../modules/cleanGeneratedTestsModule.js';
|
|
8
8
|
import { preserveCodeModule } from '../modules/preserveCodeModule.js';
|
|
9
|
-
//
|
|
9
|
+
// Built-in modules with metadata
|
|
10
10
|
export const builtInModules = {
|
|
11
|
-
comments:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
cleanComments:
|
|
11
|
+
comments: {
|
|
12
|
+
...addCommentsModule,
|
|
13
|
+
group: 'documentation',
|
|
14
|
+
dependencies: {
|
|
15
|
+
after: ['cleanComments'], // run cleanComments after comments
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
cleanComments: {
|
|
19
|
+
...preserveCodeModule,
|
|
20
|
+
group: 'documentation',
|
|
21
|
+
},
|
|
22
|
+
cleanup: {
|
|
23
|
+
...cleanupModule,
|
|
24
|
+
group: 'maintenance',
|
|
25
|
+
},
|
|
26
|
+
summary: {
|
|
27
|
+
...summaryModule,
|
|
28
|
+
group: 'documentation',
|
|
29
|
+
},
|
|
30
|
+
tests: {
|
|
31
|
+
...generateTestsModule,
|
|
32
|
+
group: 'testing',
|
|
33
|
+
dependencies: {
|
|
34
|
+
after: ['cleanTests'], // run cleanTests after tests
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
cleanTests: {
|
|
38
|
+
...cleanGeneratedTestsModule,
|
|
39
|
+
group: 'testing',
|
|
40
|
+
},
|
|
41
|
+
suggest: {
|
|
42
|
+
...commitSuggesterModule,
|
|
43
|
+
group: 'git',
|
|
44
|
+
},
|
|
45
|
+
changelog: {
|
|
46
|
+
...changelogModule,
|
|
47
|
+
group: 'git',
|
|
48
|
+
},
|
|
19
49
|
};
|
|
50
|
+
// Get module by name
|
|
20
51
|
export function getModuleByName(name) {
|
|
21
52
|
return builtInModules[name];
|
|
22
53
|
}
|
|
23
54
|
// Return module metadata for CLI or UI
|
|
24
55
|
export function listAvailableModules() {
|
|
25
|
-
return Object.values(builtInModules).map(({ name, description }) => ({
|
|
56
|
+
return Object.values(builtInModules).map(({ name, description, group, dependencies }) => ({
|
|
26
57
|
name,
|
|
27
58
|
description: description || 'No description available',
|
|
59
|
+
group,
|
|
60
|
+
dependencies,
|
|
28
61
|
}));
|
|
29
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve module execution order including before/after dependencies.
|
|
65
|
+
* Returns a unique ordered array of PromptModuleMeta.
|
|
66
|
+
*/
|
|
67
|
+
export function resolveModuleOrder(moduleNames) {
|
|
68
|
+
const resolved = [];
|
|
69
|
+
const visited = new Set();
|
|
70
|
+
function visit(name) {
|
|
71
|
+
if (visited.has(name))
|
|
72
|
+
return;
|
|
73
|
+
const mod = getModuleByName(name);
|
|
74
|
+
if (!mod)
|
|
75
|
+
return;
|
|
76
|
+
// Handle before dependencies first
|
|
77
|
+
if (mod.dependencies?.before) {
|
|
78
|
+
for (const dep of mod.dependencies.before)
|
|
79
|
+
visit(dep);
|
|
80
|
+
}
|
|
81
|
+
// Add the module itself
|
|
82
|
+
resolved.push(mod);
|
|
83
|
+
visited.add(name);
|
|
84
|
+
// Handle after dependencies
|
|
85
|
+
if (mod.dependencies?.after) {
|
|
86
|
+
for (const dep of mod.dependencies.after)
|
|
87
|
+
visit(dep);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const name of moduleNames)
|
|
91
|
+
visit(name);
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|