sapper-iq 1.1.0 → 1.1.2
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 +1 -1
- package/sapper.mjs +72 -21
package/package.json
CHANGED
package/sapper.mjs
CHANGED
|
@@ -19,6 +19,18 @@ process.on('unhandledRejection', (reason) => {
|
|
|
19
19
|
console.error(chalk.red('\n❌ Unhandled rejection:'), reason);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
// Prevent Ctrl+C from killing the whole process
|
|
23
|
+
let ctrlCCount = 0;
|
|
24
|
+
process.on('SIGINT', () => {
|
|
25
|
+
ctrlCCount++;
|
|
26
|
+
if (ctrlCCount >= 2) {
|
|
27
|
+
console.log(chalk.red('\nForce quitting...'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
console.log(chalk.yellow('\n\nUse "exit" to close Sapper safely, or Ctrl+C again to force quit.'));
|
|
31
|
+
setTimeout(() => { ctrlCCount = 0; }, 2000); // Reset after 2 seconds
|
|
32
|
+
});
|
|
33
|
+
|
|
22
34
|
// Initialize versioning
|
|
23
35
|
let CURRENT_VERSION = "1.1.0";
|
|
24
36
|
try {
|
|
@@ -37,31 +49,27 @@ let rl = readline.createInterface({
|
|
|
37
49
|
historySize: 100
|
|
38
50
|
});
|
|
39
51
|
|
|
40
|
-
async function safeQuestion(query) {
|
|
41
|
-
return new Promise((resolve, reject) => {
|
|
42
|
-
process.stdout.write(query);
|
|
43
|
-
rl.once('line', (answer) => { resolve(answer.trim()); });
|
|
44
|
-
rl.once('close', () => {
|
|
45
|
-
// Readline was closed - recreate it and try again
|
|
46
|
-
recreateReadline();
|
|
47
|
-
resolve(''); // Return empty string to continue the loop
|
|
48
|
-
});
|
|
49
|
-
rl.once('error', (err) => {
|
|
50
|
-
console.error(chalk.red('Readline error:'), err.message);
|
|
51
|
-
recreateReadline();
|
|
52
|
-
resolve('');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
52
|
function recreateReadline() {
|
|
58
|
-
rl.close();
|
|
53
|
+
if (rl) rl.close();
|
|
59
54
|
rl = readline.createInterface({
|
|
60
55
|
input: process.stdin,
|
|
61
56
|
output: process.stdout,
|
|
62
57
|
terminal: true,
|
|
63
58
|
historySize: 100
|
|
64
59
|
});
|
|
60
|
+
// Force resume stdin to keep process alive
|
|
61
|
+
process.stdin.resume();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function safeQuestion(query) {
|
|
65
|
+
// Ensure we are ready to receive input
|
|
66
|
+
if (rl.closed) recreateReadline();
|
|
67
|
+
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
rl.question(query, (answer) => {
|
|
70
|
+
resolve(answer ? answer.trim() : '');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
// Directories to ignore when listing files
|
|
@@ -128,8 +136,11 @@ const tools = {
|
|
|
128
136
|
stdio: 'inherit', shell: useShell
|
|
129
137
|
});
|
|
130
138
|
proc.on('close', (code) => {
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
// Delay slightly to let terminal settle
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
recreateReadline();
|
|
142
|
+
resolve(`Command completed with code ${code}`);
|
|
143
|
+
}, 100);
|
|
133
144
|
});
|
|
134
145
|
});
|
|
135
146
|
}
|
|
@@ -148,6 +159,27 @@ const tools = {
|
|
|
148
159
|
});
|
|
149
160
|
return filtered.length > 0 ? filtered.join('\n') : '(empty or all files filtered)';
|
|
150
161
|
} catch (e) { return `Error: ${e.message}`; }
|
|
162
|
+
},
|
|
163
|
+
search: (pattern) => {
|
|
164
|
+
return new Promise((resolve) => {
|
|
165
|
+
const excludeDirs = Array.from(IGNORE_DIRS).join(',');
|
|
166
|
+
// Use grep to search for pattern, excluding ignored directories
|
|
167
|
+
const cmd = `grep -rEin "${pattern.replace(/"/g, '\\"')}" . --exclude-dir={${excludeDirs}} --include="*.{js,ts,jsx,tsx,py,java,go,rs,rb,php,c,cpp,h,css,scss,html,json,md,txt,yml,yaml,toml,sh}" 2>/dev/null | head -50`;
|
|
168
|
+
|
|
169
|
+
const proc = spawn('sh', ['-c', cmd], { cwd: process.cwd() });
|
|
170
|
+
let output = '';
|
|
171
|
+
|
|
172
|
+
proc.stdout.on('data', (data) => { output += data.toString(); });
|
|
173
|
+
proc.stderr.on('data', (data) => { output += data.toString(); });
|
|
174
|
+
|
|
175
|
+
proc.on('close', () => {
|
|
176
|
+
if (output.trim()) {
|
|
177
|
+
resolve(`Found matches:\n${output.trim()}`);
|
|
178
|
+
} else {
|
|
179
|
+
resolve(`No matches found for: ${pattern}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
151
183
|
}
|
|
152
184
|
};
|
|
153
185
|
|
|
@@ -221,16 +253,31 @@ READING GUIDELINES:
|
|
|
221
253
|
TOOL FORMAT (CRITICAL - FOLLOW EXACTLY):
|
|
222
254
|
✅ CORRECT: [TOOL:LIST].[/TOOL]
|
|
223
255
|
✅ CORRECT: [TOOL:READ]./file.js[/TOOL]
|
|
256
|
+
✅ CORRECT: [TOOL:SEARCH]functionName[/TOOL]
|
|
224
257
|
✅ CORRECT: [TOOL:WRITE]./file.js]full content here[/TOOL]
|
|
225
258
|
✅ CORRECT: [TOOL:PATCH]./file.js]old code|||new code[/TOOL]
|
|
226
259
|
❌ WRONG: [TOOL:LIST].[/] - missing TOOL at end!
|
|
227
260
|
|
|
261
|
+
AVAILABLE TOOLS:
|
|
262
|
+
- LIST: List directory contents
|
|
263
|
+
- READ: Read file contents
|
|
264
|
+
- SEARCH: Find text/code across all files (grep-like, returns file:line:match)
|
|
265
|
+
- WRITE: Create or overwrite entire file (requires confirmation)
|
|
266
|
+
- PATCH: Make small edits to existing file (requires confirmation)
|
|
267
|
+
- MKDIR: Create directory
|
|
268
|
+
- SHELL: Run terminal command (requires confirmation)
|
|
269
|
+
|
|
270
|
+
SMART WORKFLOW:
|
|
271
|
+
1. For unknown codebases: [TOOL:SEARCH]main|index|app[/TOOL] to find entry points
|
|
272
|
+
2. To find where something is defined: [TOOL:SEARCH]function myFunc[/TOOL]
|
|
273
|
+
3. SEARCH returns file paths + line numbers - then READ specific files
|
|
274
|
+
|
|
228
275
|
PATCH vs WRITE:
|
|
229
276
|
- Use PATCH for small changes (1-10 lines): [TOOL:PATCH]path]old|||new[/TOOL]
|
|
230
277
|
- Use WRITE only for new files or complete rewrites
|
|
231
278
|
|
|
232
279
|
WORKFLOW:
|
|
233
|
-
1. LIST
|
|
280
|
+
1. LIST or SEARCH → 2. READ relevant files → 3. ANALYZE and RESPOND`
|
|
234
281
|
}];
|
|
235
282
|
}
|
|
236
283
|
|
|
@@ -360,6 +407,7 @@ WORKFLOW:
|
|
|
360
407
|
result = 'Error: PATCH requires format [TOOL:PATCH]path]OLD_TEXT|||NEW_TEXT[/TOOL]';
|
|
361
408
|
}
|
|
362
409
|
}
|
|
410
|
+
else if (type.toLowerCase() === 'search') result = await tools.search(path);
|
|
363
411
|
else if (type.toLowerCase() === 'shell') result = await tools.shell(path);
|
|
364
412
|
|
|
365
413
|
messages.push({ role: 'user', content: `RESULT (${path}): ${result}` });
|
|
@@ -391,4 +439,7 @@ WORKFLOW:
|
|
|
391
439
|
}
|
|
392
440
|
}
|
|
393
441
|
|
|
442
|
+
// Keep-alive interval - prevents Node from exiting when event loop is empty
|
|
443
|
+
setInterval(() => {}, 1000);
|
|
444
|
+
|
|
394
445
|
runSapper();
|