sapper-iq 1.1.38 → 1.1.39
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 +401 -88
- package/package.json +2 -1
- package/sapper-ui.mjs +66 -19
- package/sapper.mjs +1456 -211
package/sapper-ui.mjs
CHANGED
|
@@ -116,13 +116,17 @@ function getSapperIgnorePatterns() {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
function ignorePatternToRegex(pattern) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
try {
|
|
120
|
+
let p = pattern.replace(/\/+$/, '');
|
|
121
|
+
p = p.replace(/([.+^${}()|[\]\\])/g, '\\$1');
|
|
122
|
+
p = p.replace(/\*\*/g, '<<<GLOBSTAR>>>');
|
|
123
|
+
p = p.replace(/\*/g, '[^/]*');
|
|
124
|
+
p = p.replace(/<<<GLOBSTAR>>>/g, '.*');
|
|
125
|
+
p = p.replace(/\?/g, '[^/]');
|
|
126
|
+
return new RegExp(`(^|/)${p}($|/)`, 'i');
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return /^$/; // Return a regex that never matches on error
|
|
129
|
+
}
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
function shouldIgnore(nameOrPath) {
|
|
@@ -262,12 +266,30 @@ const tools = {
|
|
|
262
266
|
for (const { pattern: p, negate } of getSapperIgnorePatterns()) {
|
|
263
267
|
if (!negate && p.endsWith('/')) allIgnoreDirs.add(p.replace(/\/+$/, ''));
|
|
264
268
|
}
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
const
|
|
269
|
+
// Use args array to avoid command injection
|
|
270
|
+
const args = ['-rEin', pattern, '.'];
|
|
271
|
+
for (const dir of allIgnoreDirs) {
|
|
272
|
+
args.push(`--exclude-dir=${dir}`);
|
|
273
|
+
}
|
|
274
|
+
args.push('--include=*.js', '--include=*.ts', '--include=*.jsx', '--include=*.tsx',
|
|
275
|
+
'--include=*.py', '--include=*.java', '--include=*.go', '--include=*.rs',
|
|
276
|
+
'--include=*.rb', '--include=*.php', '--include=*.c', '--include=*.cpp',
|
|
277
|
+
'--include=*.h', '--include=*.css', '--include=*.scss', '--include=*.html',
|
|
278
|
+
'--include=*.json', '--include=*.md', '--include=*.txt', '--include=*.yml',
|
|
279
|
+
'--include=*.yaml', '--include=*.toml', '--include=*.sh');
|
|
280
|
+
const proc = spawn('grep', args, { cwd: workingDir });
|
|
268
281
|
let out = '';
|
|
269
|
-
|
|
270
|
-
proc.
|
|
282
|
+
let lineCount = 0;
|
|
283
|
+
proc.stdout.on('data', d => {
|
|
284
|
+
const text = d.toString();
|
|
285
|
+
const lines = text.split('\n');
|
|
286
|
+
for (const line of lines) {
|
|
287
|
+
if (lineCount >= 50) { proc.kill(); return; }
|
|
288
|
+
if (line) { out += line + '\n'; lineCount++; }
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
proc.stderr.on('data', () => {});
|
|
292
|
+
proc.on('error', (err) => res(`Error searching: ${err.message}`));
|
|
271
293
|
proc.on('close', () => res(out.trim() || `No matches for: ${pattern}`));
|
|
272
294
|
});
|
|
273
295
|
},
|
|
@@ -277,6 +299,9 @@ const tools = {
|
|
|
277
299
|
let out = '';
|
|
278
300
|
proc.stdout.on('data', d => out += d);
|
|
279
301
|
proc.stderr.on('data', d => out += d);
|
|
302
|
+
proc.on('error', (err) => {
|
|
303
|
+
res(`Shell error: ${err.message}`);
|
|
304
|
+
});
|
|
280
305
|
proc.on('close', code => {
|
|
281
306
|
let result = out.trim();
|
|
282
307
|
if (result.length > 10000) result = result.substring(0, 10000) + '\n...(truncated)';
|
|
@@ -297,7 +322,12 @@ async function executeTool(type, path, content, agentTools) {
|
|
|
297
322
|
else if (t === 'mkdir') result = tools.mkdir(path);
|
|
298
323
|
else if (t === 'write') result = tools.write(path, content || '');
|
|
299
324
|
else if (t === 'patch') {
|
|
300
|
-
|
|
325
|
+
// Use indexOf to split into exactly 2 parts, preserving ||| in content
|
|
326
|
+
const sepIdx = content?.indexOf('|||');
|
|
327
|
+
let parts = null;
|
|
328
|
+
if (sepIdx > -1) {
|
|
329
|
+
parts = [content.substring(0, sepIdx), content.substring(sepIdx + 3)];
|
|
330
|
+
}
|
|
301
331
|
if (parts && parts.length === 2) result = tools.patch(path, parts[0], parts[1]);
|
|
302
332
|
else result = 'Error: PATCH needs OLD_TEXT|||NEW_TEXT';
|
|
303
333
|
}
|
|
@@ -501,9 +531,20 @@ function json(res, data, status = 200) {
|
|
|
501
531
|
}
|
|
502
532
|
|
|
503
533
|
function readBody(req) {
|
|
504
|
-
|
|
534
|
+
const MAX_BODY_SIZE = 5 * 1024 * 1024; // 5MB limit
|
|
535
|
+
return new Promise((resolve, reject) => {
|
|
505
536
|
let body = '';
|
|
506
|
-
|
|
537
|
+
let size = 0;
|
|
538
|
+
req.on('data', c => {
|
|
539
|
+
size += c.length;
|
|
540
|
+
if (size > MAX_BODY_SIZE) {
|
|
541
|
+
req.destroy();
|
|
542
|
+
resolve({ _error: 'Request body too large' });
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
body += c;
|
|
546
|
+
});
|
|
547
|
+
req.on('error', () => resolve({}));
|
|
507
548
|
req.on('end', () => { try { resolve(JSON.parse(body)); } catch { resolve({}); } });
|
|
508
549
|
});
|
|
509
550
|
}
|
|
@@ -1566,7 +1607,7 @@ function replacePairs(text, marker, open, close) {
|
|
|
1566
1607
|
|
|
1567
1608
|
function esc(s) {
|
|
1568
1609
|
if (!s) return '';
|
|
1569
|
-
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
1610
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
1570
1611
|
}
|
|
1571
1612
|
|
|
1572
1613
|
// ─── File Panel ────────────────────────────────────────────
|
|
@@ -1943,12 +1984,18 @@ const server = http.createServer(async (req, res) => {
|
|
|
1943
1984
|
|
|
1944
1985
|
try {
|
|
1945
1986
|
const stream = chatStream(serverMessages, serverModel, serverAgentTools);
|
|
1987
|
+
let clientClosed = false;
|
|
1988
|
+
res.on('close', () => { clientClosed = true; });
|
|
1946
1989
|
for await (const evt of stream) {
|
|
1990
|
+
if (clientClosed) break;
|
|
1947
1991
|
const ok = res.write(`data: ${JSON.stringify(evt)}\n\n`);
|
|
1948
|
-
if (!ok) await new Promise(r =>
|
|
1992
|
+
if (!ok && !clientClosed) await new Promise(r => {
|
|
1993
|
+
res.once('drain', r);
|
|
1994
|
+
res.once('close', r);
|
|
1995
|
+
});
|
|
1949
1996
|
}
|
|
1950
1997
|
} catch (e) {
|
|
1951
|
-
res.write(`data: ${JSON.stringify({ type: 'system', data: 'Error: ' + e.message })}\n\n`);
|
|
1998
|
+
try { res.write(`data: ${JSON.stringify({ type: 'system', data: 'Error: ' + e.message })}\n\n`); } catch {}
|
|
1952
1999
|
}
|
|
1953
2000
|
res.write('data: [DONE]\n\n');
|
|
1954
2001
|
res.end();
|
|
@@ -1956,7 +2003,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1956
2003
|
}
|
|
1957
2004
|
|
|
1958
2005
|
// ── 404 ──
|
|
1959
|
-
res.writeHead(404);
|
|
2006
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
1960
2007
|
res.end('Not found');
|
|
1961
2008
|
});
|
|
1962
2009
|
|