sapper-iq 1.1.20 → 1.1.22
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/package.json +4 -2
- package/sapper.mjs +48 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sapper-iq",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.22",
|
|
4
4
|
"description": "AI-powered development assistant that executes commands and builds projects",
|
|
5
5
|
"main": "sapper.mjs",
|
|
6
6
|
"bin": {
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
"start": "node sapper.mjs"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"ollama": "^0.5.0",
|
|
15
14
|
"chalk": "^5.3.0",
|
|
15
|
+
"marked": "^15.0.12",
|
|
16
|
+
"marked-terminal": "^7.3.0",
|
|
17
|
+
"ollama": "^0.5.0",
|
|
16
18
|
"ora": "^8.0.1"
|
|
17
19
|
},
|
|
18
20
|
"engines": {
|
package/sapper.mjs
CHANGED
|
@@ -7,6 +7,8 @@ import ora from 'ora';
|
|
|
7
7
|
import readline from 'readline';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { dirname, join } from 'path';
|
|
10
|
+
import { marked } from 'marked';
|
|
11
|
+
import TerminalRenderer from 'marked-terminal';
|
|
10
12
|
|
|
11
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
14
|
const __dirname = dirname(__filename);
|
|
@@ -178,6 +180,36 @@ function statusBadge(text, type = 'info') {
|
|
|
178
180
|
return badges[type] || badges.info;
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
// Configure marked with terminal renderer
|
|
184
|
+
marked.setOptions({
|
|
185
|
+
renderer: new TerminalRenderer({
|
|
186
|
+
code: chalk.cyan,
|
|
187
|
+
blockquote: chalk.gray.italic,
|
|
188
|
+
html: chalk.gray,
|
|
189
|
+
heading: chalk.bold.cyan,
|
|
190
|
+
firstHeading: chalk.bold.cyan,
|
|
191
|
+
hr: chalk.gray('─'.repeat(40)),
|
|
192
|
+
listitem: chalk.yellow('• ') + '%s',
|
|
193
|
+
table: chalk.white,
|
|
194
|
+
paragraph: chalk.white,
|
|
195
|
+
strong: chalk.bold.white,
|
|
196
|
+
em: chalk.italic,
|
|
197
|
+
codespan: chalk.cyan,
|
|
198
|
+
del: chalk.strikethrough,
|
|
199
|
+
link: chalk.underline.blue,
|
|
200
|
+
href: chalk.gray
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Render markdown to terminal
|
|
205
|
+
function renderMarkdown(text) {
|
|
206
|
+
try {
|
|
207
|
+
return marked(text).trim();
|
|
208
|
+
} catch (e) {
|
|
209
|
+
return text; // Fallback to raw text
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
181
213
|
let stepMode = false;
|
|
182
214
|
let debugMode = false; // Toggle with /debug command
|
|
183
215
|
let abortStream = false; // Flag to interrupt AI response
|
|
@@ -403,7 +435,9 @@ const tools = {
|
|
|
403
435
|
},
|
|
404
436
|
list: (path) => {
|
|
405
437
|
try {
|
|
406
|
-
|
|
438
|
+
let dir = path.trim() || '.';
|
|
439
|
+
// If AI sends "/" (root), treat as current directory "."
|
|
440
|
+
if (dir === '/') dir = '.';
|
|
407
441
|
const entries = fs.readdirSync(dir);
|
|
408
442
|
// Filter out ignored directories
|
|
409
443
|
const filtered = entries.filter(entry => {
|
|
@@ -765,6 +799,19 @@ async function runSapper() {
|
|
|
765
799
|
}
|
|
766
800
|
}
|
|
767
801
|
console.log();
|
|
802
|
+
|
|
803
|
+
// If response has markdown, show rendered version
|
|
804
|
+
const hasMarkdown = /\*\*|__|`|^#|^[-*] /m.test(msg);
|
|
805
|
+
if (hasMarkdown && !msg.includes('[TOOL:')) {
|
|
806
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
807
|
+
const rendered = renderMarkdown(msg);
|
|
808
|
+
const lines = rendered.split('\n');
|
|
809
|
+
for (const line of lines) {
|
|
810
|
+
console.log(chalk.magenta('│ ') + line);
|
|
811
|
+
}
|
|
812
|
+
console.log();
|
|
813
|
+
}
|
|
814
|
+
|
|
768
815
|
messages.push({ role: 'assistant', content: msg });
|
|
769
816
|
|
|
770
817
|
// Fixed regex: [^\]]+ stops at first ] to correctly separate path from content
|