jawere 1.0.13 → 1.5.0
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/dist/index.js +156 -58
- package/package.json +2 -2
- package/dist/agent.d.ts +0 -15
- package/dist/agent.js +0 -321
- package/dist/config.d.ts +0 -19
- package/dist/config.js +0 -53
- package/dist/convex-client.d.ts +0 -41
- package/dist/convex-client.js +0 -99
- package/dist/crypto.d.ts +0 -12
- package/dist/crypto.js +0 -79
- package/dist/index.d.ts +0 -1
- package/dist/prompt.d.ts +0 -9
- package/dist/prompt.js +0 -325
- package/dist/scanner.d.ts +0 -29
- package/dist/scanner.js +0 -520
- package/dist/spinner.d.ts +0 -23
- package/dist/spinner.js +0 -83
- package/dist/system-prompt.d.ts +0 -1
- package/dist/system-prompt.js +0 -115
- package/dist/tools.d.ts +0 -22
- package/dist/tools.js +0 -551
package/dist/prompt.js
DELETED
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
// src/prompt.ts — Multiline prompt with Shift+Enter & paste support
|
|
2
|
-
// Extracted from index.ts to isolate complex terminal handling for testability.
|
|
3
|
-
import * as readline from 'readline';
|
|
4
|
-
// Gruvbox colors
|
|
5
|
-
const G_GRAY = '\x1b[38;2;146;131;116m';
|
|
6
|
-
const R = '\x1b[0m';
|
|
7
|
-
const PROMPT = `${G_GRAY}>${R} `;
|
|
8
|
-
const CONT = ' ';
|
|
9
|
-
// ── Long paste threshold ────────────────────────────────────────────
|
|
10
|
-
// Pastes exceeding this many lines or characters are stored and
|
|
11
|
-
// replaced with a [paste #N] placeholder to keep the prompt responsive.
|
|
12
|
-
const PASTE_LINE_LIMIT = 20;
|
|
13
|
-
const PASTE_CHAR_LIMIT = 500;
|
|
14
|
-
/**
|
|
15
|
-
* Simple fallback prompt for piped/non-TTY input.
|
|
16
|
-
*/
|
|
17
|
-
function simplePrompt() {
|
|
18
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
-
return new Promise((resolve) => {
|
|
20
|
-
rl.question('> ', (answer) => { rl.close(); resolve(answer); });
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Full-featured multiline prompt with:
|
|
25
|
-
* - Shift+Enter for newlines (kitty: CSI 13;2u / xterm: CSI 13;2~)
|
|
26
|
-
* - Bracketed paste mode (multi-line paste support)
|
|
27
|
-
* - Long pastes stored as [paste #N] placeholders to avoid UI churn
|
|
28
|
-
* - Arrow keys, Home, End, Delete, Backspace
|
|
29
|
-
* - Ctrl+C to cancel, Ctrl+D to exit on empty line
|
|
30
|
-
*
|
|
31
|
-
* This is raw-mode terminal handling — fragile but necessary for a good UX.
|
|
32
|
-
* Isolating it here makes it easier to test, debug, and replace.
|
|
33
|
-
*/
|
|
34
|
-
function multilinePrompt() {
|
|
35
|
-
return new Promise((resolve) => {
|
|
36
|
-
const lines = [''];
|
|
37
|
-
let row = 0;
|
|
38
|
-
let col = 0;
|
|
39
|
-
// ── Paste state ──────────────────────────────────────────────
|
|
40
|
-
let pasteMode = false;
|
|
41
|
-
let pasteBuf = '';
|
|
42
|
-
// Map of placeholder -> actual content for long pastes
|
|
43
|
-
const storedPastes = [];
|
|
44
|
-
let pasteCounter = 0;
|
|
45
|
-
process.stdout.write('\n');
|
|
46
|
-
process.stdout.write(PROMPT);
|
|
47
|
-
const rawOn = () => {
|
|
48
|
-
if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') {
|
|
49
|
-
process.stdin.setRawMode(true);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
const rawOff = () => {
|
|
53
|
-
if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') {
|
|
54
|
-
process.stdin.setRawMode(false);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
rawOn();
|
|
58
|
-
// ── Redraw helper ────────────────────────────────────────────
|
|
59
|
-
// Repaints the entire prompt and all continuation lines, then
|
|
60
|
-
// repositions the cursor at (row, col).
|
|
61
|
-
const redraw = () => {
|
|
62
|
-
// Move cursor up to the first prompt line
|
|
63
|
-
process.stdout.write(`\x1b[${row}A\r`);
|
|
64
|
-
// Clear from cursor to end of screen
|
|
65
|
-
process.stdout.write('\x1b[0J');
|
|
66
|
-
// Print first line with prompt prefix
|
|
67
|
-
process.stdout.write(PROMPT + lines[0]);
|
|
68
|
-
// Print continuation lines
|
|
69
|
-
for (let i = 1; i < lines.length; i++) {
|
|
70
|
-
process.stdout.write('\r\n' + CONT + lines[i]);
|
|
71
|
-
}
|
|
72
|
-
// Reposition cursor
|
|
73
|
-
const moveUp = lines.length - 1 - row;
|
|
74
|
-
if (moveUp > 0)
|
|
75
|
-
process.stdout.write(`\x1b[${moveUp}A`);
|
|
76
|
-
process.stdout.write('\r');
|
|
77
|
-
const prefixLen = row === 0 ? PROMPT.length : CONT.length;
|
|
78
|
-
if (col > 0)
|
|
79
|
-
process.stdout.write(`\x1b[${prefixLen + col}C`);
|
|
80
|
-
};
|
|
81
|
-
const cleanup = () => {
|
|
82
|
-
process.stdin.removeListener('data', onData);
|
|
83
|
-
rawOff();
|
|
84
|
-
};
|
|
85
|
-
// ── Expand paste placeholders ────────────────────────────────
|
|
86
|
-
// Replace [paste #N] markers with actual stored paste content.
|
|
87
|
-
const expandPastes = (text) => {
|
|
88
|
-
let result = text;
|
|
89
|
-
for (let i = 0; i < storedPastes.length; i++) {
|
|
90
|
-
const placeholder = `[paste #${i + 1}]`;
|
|
91
|
-
// Use split/join for simple replacement (handles multiple occurrences)
|
|
92
|
-
result = result.split(placeholder).join(storedPastes[i]);
|
|
93
|
-
}
|
|
94
|
-
return result;
|
|
95
|
-
};
|
|
96
|
-
// ── Process a completed paste ────────────────────────────────
|
|
97
|
-
const processPaste = (content) => {
|
|
98
|
-
const lineCount = content.split('\n').length;
|
|
99
|
-
const charCount = content.length;
|
|
100
|
-
// Decide: render inline or store as placeholder?
|
|
101
|
-
if (lineCount > PASTE_LINE_LIMIT || charCount > PASTE_CHAR_LIMIT) {
|
|
102
|
-
// ── Long paste → placeholder ──
|
|
103
|
-
pasteCounter++;
|
|
104
|
-
storedPastes.push(content);
|
|
105
|
-
const placeholder = `[paste #${pasteCounter}]`;
|
|
106
|
-
const before = lines[row].slice(0, col);
|
|
107
|
-
const after = lines[row].slice(col);
|
|
108
|
-
lines[row] = before + placeholder + after;
|
|
109
|
-
col += placeholder.length;
|
|
110
|
-
process.stdout.write(placeholder);
|
|
111
|
-
if (after.length > 0)
|
|
112
|
-
redraw();
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// ── Short paste → render inline ──
|
|
116
|
-
const before = lines[row].slice(0, col);
|
|
117
|
-
const after = lines[row].slice(col);
|
|
118
|
-
const pasteLines = content.split('\n');
|
|
119
|
-
if (pasteLines.length === 1) {
|
|
120
|
-
// Single-line paste
|
|
121
|
-
lines[row] = before + pasteLines[0] + after;
|
|
122
|
-
col += pasteLines[0].length;
|
|
123
|
-
process.stdout.write(pasteLines[0]);
|
|
124
|
-
if (after.length > 0)
|
|
125
|
-
redraw();
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
// Multi-line paste
|
|
129
|
-
lines[row] = before + pasteLines[0];
|
|
130
|
-
for (let i = 1; i < pasteLines.length; i++) {
|
|
131
|
-
lines.splice(row + i, 0, pasteLines[i]);
|
|
132
|
-
}
|
|
133
|
-
lines[row + pasteLines.length - 1] += after;
|
|
134
|
-
row += pasteLines.length - 1;
|
|
135
|
-
col = pasteLines[pasteLines.length - 1].length;
|
|
136
|
-
redraw();
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
// ── Data handler ─────────────────────────────────────────────
|
|
141
|
-
const onData = (buf) => {
|
|
142
|
-
const s = buf.toString();
|
|
143
|
-
// ── Bracketed paste start ─────────────────────────────────
|
|
144
|
-
if (!pasteMode && s.startsWith('\x1b[200~')) {
|
|
145
|
-
pasteMode = true;
|
|
146
|
-
// Everything after the 6-char start marker goes into pasteBuf
|
|
147
|
-
pasteBuf = s.slice(6);
|
|
148
|
-
// Check if the entire paste (including end marker) is in this chunk.
|
|
149
|
-
// This is the critical fix: we must search pasteBuf, not just s.
|
|
150
|
-
const endIdx = pasteBuf.indexOf('\x1b[201~');
|
|
151
|
-
if (endIdx !== -1) {
|
|
152
|
-
const content = pasteBuf.slice(0, endIdx);
|
|
153
|
-
const rest = pasteBuf.slice(endIdx + 6);
|
|
154
|
-
pasteBuf = '';
|
|
155
|
-
pasteMode = false;
|
|
156
|
-
processPaste(content);
|
|
157
|
-
if (rest)
|
|
158
|
-
onData(Buffer.from(rest));
|
|
159
|
-
}
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
// ── Accumulating paste data ───────────────────────────────
|
|
163
|
-
if (pasteMode) {
|
|
164
|
-
pasteBuf += s;
|
|
165
|
-
// Search pasteBuf for the end marker (not just s — this is the fix)
|
|
166
|
-
const endIdx = pasteBuf.indexOf('\x1b[201~');
|
|
167
|
-
if (endIdx !== -1) {
|
|
168
|
-
const content = pasteBuf.slice(0, endIdx);
|
|
169
|
-
const rest = pasteBuf.slice(endIdx + 6);
|
|
170
|
-
pasteBuf = '';
|
|
171
|
-
pasteMode = false;
|
|
172
|
-
processPaste(content);
|
|
173
|
-
if (rest)
|
|
174
|
-
onData(Buffer.from(rest));
|
|
175
|
-
}
|
|
176
|
-
// If end marker not found, keep accumulating — no action needed
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
// ── Shift+Enter (kitty: CSI 13;2u, xterm: CSI 13;2~) ─────
|
|
180
|
-
if (s === '\x1b[13;2u' || s === '\x1b[13;2~') {
|
|
181
|
-
const before = lines[row].slice(0, col);
|
|
182
|
-
const after = lines[row].slice(col);
|
|
183
|
-
lines[row] = before;
|
|
184
|
-
lines.splice(row + 1, 0, after);
|
|
185
|
-
row++;
|
|
186
|
-
col = 0;
|
|
187
|
-
process.stdout.write('\r\n' + CONT);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
// ── Enter ─────────────────────────────────────────────────
|
|
191
|
-
if (s === '\r' || s === '\n') {
|
|
192
|
-
cleanup();
|
|
193
|
-
process.stdout.write('\r\n');
|
|
194
|
-
const raw = lines.join('\n');
|
|
195
|
-
const expanded = expandPastes(raw);
|
|
196
|
-
resolve(expanded);
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
// ── Ctrl+C ────────────────────────────────────────────────
|
|
200
|
-
if (s === '\x03') {
|
|
201
|
-
cleanup();
|
|
202
|
-
process.stdout.write('^C\r\n');
|
|
203
|
-
resolve('');
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
// ── Ctrl+D on empty line ──────────────────────────────────
|
|
207
|
-
if (s === '\x04' && lines.length === 1 && lines[0].length === 0) {
|
|
208
|
-
cleanup();
|
|
209
|
-
process.stdout.write('\r\n');
|
|
210
|
-
resolve('/exit');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
// ── Backspace ─────────────────────────────────────────────
|
|
214
|
-
if (s === '\x7f' || s === '\b') {
|
|
215
|
-
if (col > 0) {
|
|
216
|
-
const line = lines[row];
|
|
217
|
-
lines[row] = line.slice(0, col - 1) + line.slice(col);
|
|
218
|
-
col--;
|
|
219
|
-
process.stdout.write('\b \b');
|
|
220
|
-
if (col < lines[row].length)
|
|
221
|
-
redraw();
|
|
222
|
-
}
|
|
223
|
-
else if (row > 0) {
|
|
224
|
-
// Join with previous line
|
|
225
|
-
const prevLen = lines[row - 1].length;
|
|
226
|
-
lines[row - 1] += lines[row];
|
|
227
|
-
lines.splice(row, 1);
|
|
228
|
-
row--;
|
|
229
|
-
col = prevLen;
|
|
230
|
-
redraw();
|
|
231
|
-
}
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
// ── Escape sequences (arrows, home, end, delete) ──────────
|
|
235
|
-
if (s.startsWith('\x1b[')) {
|
|
236
|
-
// Arrow keys: CSI n A/B/C/D
|
|
237
|
-
const m = s.match(/^\x1b\[(\d*)([ABCD])/);
|
|
238
|
-
if (m) {
|
|
239
|
-
const n = m[1] ? parseInt(m[1], 10) : 1;
|
|
240
|
-
const dir = m[2];
|
|
241
|
-
if (dir === 'D' && col > 0) {
|
|
242
|
-
col = Math.max(0, col - n);
|
|
243
|
-
process.stdout.write(`\x1b[${n}D`);
|
|
244
|
-
}
|
|
245
|
-
else if (dir === 'C' && col < lines[row].length) {
|
|
246
|
-
col = Math.min(lines[row].length, col + n);
|
|
247
|
-
process.stdout.write(`\x1b[${n}C`);
|
|
248
|
-
}
|
|
249
|
-
else if (dir === 'A' && row > 0) {
|
|
250
|
-
row = Math.max(0, row - n);
|
|
251
|
-
col = Math.min(col, lines[row].length);
|
|
252
|
-
process.stdout.write(`\x1b[${n}A`);
|
|
253
|
-
}
|
|
254
|
-
else if (dir === 'B' && row < lines.length - 1) {
|
|
255
|
-
row = Math.min(lines.length - 1, row + n);
|
|
256
|
-
col = Math.min(col, lines[row].length);
|
|
257
|
-
process.stdout.write(`\x1b[${n}B`);
|
|
258
|
-
}
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
// Home
|
|
262
|
-
if (s === '\x1b[H' || s === '\x1b[1~') {
|
|
263
|
-
const diff = col;
|
|
264
|
-
col = 0;
|
|
265
|
-
process.stdout.write(`\x1b[${diff}D`);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
// End
|
|
269
|
-
if (s === '\x1b[F' || s === '\x1b[4~') {
|
|
270
|
-
const diff = lines[row].length - col;
|
|
271
|
-
col = lines[row].length;
|
|
272
|
-
process.stdout.write(`\x1b[${diff}C`);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
// Delete
|
|
276
|
-
if (s === '\x1b[3~') {
|
|
277
|
-
if (col < lines[row].length) {
|
|
278
|
-
lines[row] = lines[row].slice(0, col) + lines[row].slice(col + 1);
|
|
279
|
-
redraw();
|
|
280
|
-
}
|
|
281
|
-
else if (row < lines.length - 1) {
|
|
282
|
-
// Join with next line
|
|
283
|
-
lines[row] += lines[row + 1];
|
|
284
|
-
lines.splice(row + 1, 1);
|
|
285
|
-
redraw();
|
|
286
|
-
}
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
// Unknown escape — ignore
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
// ── Regular character ─────────────────────────────────────
|
|
293
|
-
const before = lines[row];
|
|
294
|
-
lines[row] = before.slice(0, col) + s + before.slice(col);
|
|
295
|
-
col += s.length;
|
|
296
|
-
if (col < lines[row].length) {
|
|
297
|
-
// Cursor is now in the middle of the line — need to repaint
|
|
298
|
-
redraw();
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
// Cursor at end — simple echo suffices
|
|
302
|
-
process.stdout.write(s);
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
process.stdin.on('data', onData);
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Create a prompt function appropriate for the current terminal.
|
|
310
|
-
* Returns multilinePrompt for TTYs, simplePrompt for pipes/files.
|
|
311
|
-
*/
|
|
312
|
-
export function createPrompt() {
|
|
313
|
-
const isTTY = process.stdin.isTTY && typeof process.stdin.setRawMode === 'function';
|
|
314
|
-
return {
|
|
315
|
-
prompt: isTTY ? multilinePrompt : simplePrompt,
|
|
316
|
-
enableBracketedPaste: () => {
|
|
317
|
-
if (isTTY)
|
|
318
|
-
process.stdout.write('\x1b[?2004h');
|
|
319
|
-
},
|
|
320
|
-
disableBracketedPaste: () => {
|
|
321
|
-
if (isTTY)
|
|
322
|
-
process.stdout.write('\x1b[?2004l');
|
|
323
|
-
},
|
|
324
|
-
};
|
|
325
|
-
}
|
package/dist/scanner.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
interface ChecksumEntry {
|
|
2
|
-
hash: string;
|
|
3
|
-
size: number;
|
|
4
|
-
scannedAt: number;
|
|
5
|
-
}
|
|
6
|
-
interface Checksums {
|
|
7
|
-
scannedAt: number;
|
|
8
|
-
gitHash: string | null;
|
|
9
|
-
files: Record<string, ChecksumEntry>;
|
|
10
|
-
}
|
|
11
|
-
export declare function cacheIsStale(workDir: string): Promise<boolean>;
|
|
12
|
-
/**
|
|
13
|
-
* Load stored checksums for quick file-change detection.
|
|
14
|
-
* The agent can use this to skip re-reading files that haven't changed.
|
|
15
|
-
*/
|
|
16
|
-
export declare function loadChecksums(workDir: string): Promise<Checksums | null>;
|
|
17
|
-
/**
|
|
18
|
-
* Run the background scanner.
|
|
19
|
-
* Checks cache validity first; if stale, re-scans the codebase.
|
|
20
|
-
*
|
|
21
|
-
* @param workDir Working directory to scan
|
|
22
|
-
* @param force Force rescan even if cache is fresh
|
|
23
|
-
* @returns Scan result with file count
|
|
24
|
-
*/
|
|
25
|
-
export declare function runScanner(workDir: string, force?: boolean): Promise<{
|
|
26
|
-
fileCount: number;
|
|
27
|
-
cached: boolean;
|
|
28
|
-
}>;
|
|
29
|
-
export {};
|