@cnrai/pave 0.3.35 → 0.3.51

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -218
  3. package/package.json +32 -35
  4. package/pave.js +3 -0
  5. package/sandbox/SandboxRunner.js +1 -0
  6. package/sandbox/pave-run.js +2 -0
  7. package/sandbox/permission.js +1 -0
  8. package/sandbox/utils/yaml.js +1 -0
  9. package/MARKETPLACE.md +0 -406
  10. package/build-binary.js +0 -591
  11. package/build-npm.js +0 -537
  12. package/build.js +0 -230
  13. package/check-binary.js +0 -26
  14. package/deploy.sh +0 -95
  15. package/index.js +0 -5776
  16. package/lib/agent-registry.js +0 -1037
  17. package/lib/args-parser.js +0 -837
  18. package/lib/blessed-widget-patched.js +0 -93
  19. package/lib/cli-markdown.js +0 -590
  20. package/lib/compaction.js +0 -153
  21. package/lib/duration.js +0 -94
  22. package/lib/hash.js +0 -22
  23. package/lib/marketplace.js +0 -866
  24. package/lib/memory-config.js +0 -166
  25. package/lib/skill-manager.js +0 -891
  26. package/lib/soul.js +0 -31
  27. package/lib/tool-output-formatter.js +0 -180
  28. package/start-pave.sh +0 -149
  29. package/status.js +0 -271
  30. package/test/abort-stream.test.js +0 -445
  31. package/test/agent-auto-compaction.test.js +0 -552
  32. package/test/agent-comm-abort.test.js +0 -95
  33. package/test/agent-comm.test.js +0 -598
  34. package/test/agent-inbox.test.js +0 -576
  35. package/test/agent-init.test.js +0 -264
  36. package/test/agent-interrupt.test.js +0 -314
  37. package/test/agent-lifecycle.test.js +0 -520
  38. package/test/agent-log-files.test.js +0 -349
  39. package/test/agent-mode.manual-test.js +0 -392
  40. package/test/agent-parsing.test.js +0 -228
  41. package/test/agent-post-stream-idle.test.js +0 -762
  42. package/test/agent-registry.test.js +0 -359
  43. package/test/agent-rm.test.js +0 -442
  44. package/test/agent-spawn.test.js +0 -933
  45. package/test/agent-status-api.test.js +0 -624
  46. package/test/agent-update.test.js +0 -435
  47. package/test/args-parser.test.js +0 -391
  48. package/test/auto-compaction-chat.manual-test.js +0 -227
  49. package/test/auto-compaction.test.js +0 -941
  50. package/test/build-config.test.js +0 -120
  51. package/test/build-npm.test.js +0 -388
  52. package/test/chat-command.test.js +0 -137
  53. package/test/chat-leading-lines.test.js +0 -159
  54. package/test/config-flag.test.js +0 -272
  55. package/test/cursor-drift.test.js +0 -135
  56. package/test/debug-require.js +0 -23
  57. package/test/dir-migration.test.js +0 -323
  58. package/test/duration.test.js +0 -229
  59. package/test/ghostty-term.test.js +0 -202
  60. package/test/http500-backoff.test.js +0 -854
  61. package/test/integration.test.js +0 -86
  62. package/test/memory-guard-env.test.js +0 -220
  63. package/test/pr233-fixes.test.js +0 -259
  64. package/test/run-agent-init.js +0 -297
  65. package/test/run-all.js +0 -64
  66. package/test/run-config-flag.js +0 -159
  67. package/test/run-cursor-drift.js +0 -82
  68. package/test/run-session-path.js +0 -154
  69. package/test/run-tests.js +0 -643
  70. package/test/sandbox-redirect.test.js +0 -202
  71. package/test/session-path.test.js +0 -132
  72. package/test/shebang-strip.test.js +0 -241
  73. package/test/soul-reinject.test.js +0 -1027
  74. package/test/soul-reread.test.js +0 -281
  75. package/test/tool-output-formatter.test.js +0 -486
  76. package/test/tool-output-gating.test.js +0 -143
  77. package/test/tool-states.test.js +0 -167
  78. package/test/tools-flag.test.js +0 -65
  79. package/test/tui-attach.test.js +0 -1255
  80. package/test/tui-compaction.test.js +0 -354
  81. package/test/tui-wrap.test.js +0 -568
  82. package/test-binary.js +0 -52
  83. package/test-binary2.js +0 -36
@@ -1,568 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- // Test TUI word-wrap helper functions
6
- // Verifies fixes for issues #147 (tui wrap algorithms) and #150 (wrap width mismatch)
7
- //
8
- // NOTE: The TUI helpers are attached to blessed input widgets at runtime
9
- // and cannot be directly imported without a full blessed/screen setup.
10
- // We replicate the helper logic here with a mock input to test the
11
- // algorithms in isolation. If the production implementations diverge,
12
- // integration tests with a real TUI instance should be added.
13
-
14
- function runTest(name, fn) {
15
- try {
16
- fn();
17
- console.log('\u2705 ' + name);
18
- } catch (e) {
19
- console.log('\u274C ' + name + ': ' + e.message);
20
- process.exitCode = 1;
21
- }
22
- }
23
-
24
- function assertEqual(actual, expected, msg) {
25
- if (actual !== expected) {
26
- throw new Error((msg || '') + ' expected ' + JSON.stringify(expected) + ', got ' + JSON.stringify(actual));
27
- }
28
- }
29
-
30
- // Helper: detect valid surrogate pair at index i
31
- function isSurrogatePair(str, i) {
32
- const code = str.charCodeAt(i);
33
- if (code >= 0xD800 && code <= 0xDBFF && i + 1 < str.length) {
34
- const next = str.charCodeAt(i + 1);
35
- return next >= 0xDC00 && next <= 0xDFFF;
36
- }
37
- return false;
38
- }
39
-
40
- // ---- Helper functions replicated from tui/index.js ----
41
- // These match the production implementations after the #147 fixes.
42
-
43
- function createMockInput(strWidthFn, lposWidth) {
44
- const input = {
45
- value: '',
46
- strWidth: strWidthFn || function (s) { return s ? s.length : 0; },
47
- iwidth: 0,
48
- };
49
-
50
- // Mock lpos for _getWrapWidth. lposWidth is the raw widget width
51
- // (xl - xi). If not provided, _getWrapWidth uses the fallback of 79.
52
- if (lposWidth !== undefined) {
53
- input.lpos = { xl: lposWidth, xi: 0 };
54
- }
55
-
56
- // Blessed subtracts 1 from textarea width in _wrapContent (the "textarea
57
- // margin" for the cursor column). See #112, #150.
58
- input._getWrapWidth = function (lpos) {
59
- if (!lpos) lpos = input.lpos;
60
- const w = lpos ? (lpos.xl - lpos.xi) - input.iwidth - 1 : 79;
61
- return w < 1 ? 1 : w;
62
- };
63
-
64
- input._wordWrapLine = function (line, widgetWidth) {
65
- if (widgetWidth < 1) widgetWidth = 1;
66
- const segs = [];
67
- let offset = 0;
68
- while (line.length > 0) {
69
- if (input.strWidth(line) <= widgetWidth) {
70
- segs.push({ text: line, startIdx: offset });
71
- break;
72
- }
73
- let i = 0;
74
- let w = 0;
75
- while (i < line.length) {
76
- let step = 1;
77
- if (isSurrogatePair(line, i)) {
78
- step = 2;
79
- }
80
- const cw = input.strWidth(line.substring(i, i + step));
81
- if (w + cw > widgetWidth) break;
82
- w += cw;
83
- i += step;
84
- }
85
- if (i < 1) {
86
- // Always advance at least one full codepoint
87
- let minStep = 1;
88
- if (isSurrogatePair(line, 0)) {
89
- minStep = 2;
90
- }
91
- i = minStep;
92
- }
93
- let j = i;
94
- while (j > i - 10 && j > 0 && line[--j] !== ' ');
95
- if (line[j] === ' ') i = j + 1;
96
- const part = line.substring(0, i);
97
- segs.push({ text: part, startIdx: offset });
98
- offset += part.length;
99
- line = line.substring(i);
100
- if (line === '') break;
101
- }
102
- if (segs.length === 0) {
103
- segs.push({ text: '', startIdx: 0 });
104
- }
105
- return segs;
106
- };
107
-
108
- input._getVisualPos = function (charPos, widgetWidth) {
109
- const value = input.value || '';
110
- const logicalLines = value.split('\n');
111
- let visualRow = 0;
112
- let consumed = 0;
113
- for (let li = 0; li < logicalLines.length; li++) {
114
- const logLine = logicalLines[li];
115
- const segs = input._wordWrapLine(logLine, widgetWidth);
116
- for (let si = 0; si < segs.length; si++) {
117
- const segStart = consumed + segs[si].startIdx;
118
- const segLen = segs[si].text.length;
119
- const segEnd = segStart + segLen;
120
- if (charPos >= segStart && (charPos < segEnd || (si === segs.length - 1 && charPos === segEnd))) {
121
- const col = input.strWidth(value.substring(segStart, charPos));
122
- return { row: visualRow, col };
123
- }
124
- visualRow++;
125
- }
126
- consumed += logLine.length + 1;
127
- }
128
- return { row: Math.max(0, visualRow - 1), col: 0 };
129
- };
130
-
131
- input._countVisualLines = function (widgetWidth) {
132
- const value = input.value || '';
133
- if (!value) return 1;
134
- const logicalLines = value.split('\n');
135
- let total = 0;
136
- for (let li = 0; li < logicalLines.length; li++) {
137
- total += input._wordWrapLine(logicalLines[li], widgetWidth).length;
138
- }
139
- return total;
140
- };
141
-
142
- input._buildCharToVisual = function (widgetWidth) {
143
- const value = input.value || '';
144
- const map = [];
145
- const logicalLines = value.split('\n');
146
- let visualRow = 0;
147
- for (let li = 0; li < logicalLines.length; li++) {
148
- const logLine = logicalLines[li];
149
- const segs = input._wordWrapLine(logLine, widgetWidth);
150
- for (let si = 0; si < segs.length; si++) {
151
- const seg = segs[si];
152
- let runCol = 0;
153
- for (let ci = 0; ci < seg.text.length; ci++) {
154
- map.push({ row: visualRow, col: runCol });
155
- let step = 1;
156
- if (isSurrogatePair(seg.text, ci)) {
157
- step = 2;
158
- }
159
- const charWidth = input.strWidth(seg.text.substring(ci, ci + step));
160
- runCol += charWidth;
161
- if (step === 2) {
162
- map.push({ row: visualRow, col: runCol - charWidth });
163
- ci++;
164
- }
165
- }
166
- if (si < segs.length - 1) {
167
- visualRow++;
168
- }
169
- }
170
- if (li < logicalLines.length - 1) {
171
- map.push({ row: visualRow, col: map.length > 0 ? input.strWidth(segs[segs.length - 1].text) : 0 });
172
- visualRow++;
173
- }
174
- }
175
- const lastSeg = input._wordWrapLine(logicalLines[logicalLines.length - 1], widgetWidth);
176
- const lastSegText = lastSeg[lastSeg.length - 1].text;
177
- let endCol = input.strWidth(lastSegText);
178
- if (endCol > widgetWidth) {
179
- visualRow++;
180
- endCol = 0;
181
- }
182
- map.push({ row: visualRow, col: endCol });
183
- return map;
184
- };
185
-
186
- input._charPosFromVisualRow = function (targetRow, targetCol, widgetWidth) {
187
- const value = input.value || '';
188
- const logicalLines = value.split('\n');
189
- let visualRow = 0;
190
- let consumed = 0;
191
- for (let li = 0; li < logicalLines.length; li++) {
192
- const logLine = logicalLines[li];
193
- const segs = input._wordWrapLine(logLine, widgetWidth);
194
- for (let si = 0; si < segs.length; si++) {
195
- if (visualRow === targetRow) {
196
- const segStart = consumed + segs[si].startIdx;
197
- const segText = segs[si].text;
198
- let runW = 0;
199
- for (let ci = 0; ci < segText.length; ci++) {
200
- let step = 1;
201
- if (isSurrogatePair(segText, ci)) {
202
- step = 2;
203
- }
204
- const cw = input.strWidth(segText.substring(ci, ci + step));
205
- if (runW + cw > targetCol) {
206
- return segStart + ci;
207
- }
208
- runW += cw;
209
- if (step === 2) ci++;
210
- }
211
- return segStart + segText.length;
212
- }
213
- visualRow++;
214
- }
215
- consumed += logLine.length + 1;
216
- }
217
- return value.length;
218
- };
219
-
220
- return input;
221
- }
222
-
223
- // Surrogate-pair-aware strWidth for tests
224
- function surrogateStrWidth(s) {
225
- if (!s) return 0;
226
- let w = 0;
227
- for (let i = 0; i < s.length; i++) {
228
- const code = s.charCodeAt(i);
229
- if (code >= 0xD800 && code <= 0xDBFF) {
230
- w += 2; // surrogate pair = 2 visual width
231
- i++; // skip low surrogate
232
- } else if (code >= 0xDC00 && code <= 0xDFFF) {
233
- w += 1; // lone low surrogate
234
- } else {
235
- w += 1;
236
- }
237
- }
238
- return w;
239
- }
240
-
241
- // ========== _wordWrapLine tests ==========
242
-
243
- runTest('wordWrap: short line fits without wrapping', () => {
244
- const input = createMockInput();
245
- const segs = input._wordWrapLine('hello', 10);
246
- assertEqual(segs.length, 1);
247
- assertEqual(segs[0].text, 'hello');
248
- assertEqual(segs[0].startIdx, 0);
249
- });
250
-
251
- runTest('wordWrap: exact width line does not wrap', () => {
252
- const input = createMockInput();
253
- const segs = input._wordWrapLine('1234567890', 10);
254
- assertEqual(segs.length, 1);
255
- assertEqual(segs[0].text, '1234567890');
256
- });
257
-
258
- runTest('wordWrap: wraps at word boundary within 10 chars of width', () => {
259
- const input = createMockInput();
260
- const segs = input._wordWrapLine('hello world', 10);
261
- assertEqual(segs.length, 2);
262
- assertEqual(segs[0].text, 'hello ');
263
- assertEqual(segs[1].text, 'world');
264
- assertEqual(segs[1].startIdx, 6);
265
- });
266
-
267
- runTest('wordWrap: wraps long word without spaces at width', () => {
268
- const input = createMockInput();
269
- const segs = input._wordWrapLine('abcdefghijklmnop', 10);
270
- assertEqual(segs.length, 2);
271
- assertEqual(segs[0].text, 'abcdefghij');
272
- assertEqual(segs[1].text, 'klmnop');
273
- });
274
-
275
- runTest('wordWrap: empty line returns single empty segment', () => {
276
- const input = createMockInput();
277
- const segs = input._wordWrapLine('', 10);
278
- assertEqual(segs.length, 1);
279
- assertEqual(segs[0].text, '');
280
- });
281
-
282
- runTest('wordWrap: widgetWidth < 1 treated as 1', () => {
283
- const input = createMockInput();
284
- const segs = input._wordWrapLine('abc', 0);
285
- if (segs.length < 1) throw new Error('Expected at least 1 segment');
286
- });
287
-
288
- runTest('wordWrap: multiple wraps', () => {
289
- const input = createMockInput();
290
- const segs = input._wordWrapLine('aaa bbb ccc ddd eee fff ggg h', 10);
291
- if (segs.length < 3) throw new Error('Expected at least 3 segments, got ' + segs.length);
292
- });
293
-
294
- runTest('wordWrap: does not split surrogate pairs', () => {
295
- const input = createMockInput(surrogateStrWidth);
296
- // 'aaa' + U+1F600 (😀) + 'bbb' = visual 3+2+3 = 8
297
- const line = 'aaa\uD83D\uDE00bbb';
298
- const segs = input._wordWrapLine(line, 5);
299
- assertEqual(segs.length, 2);
300
- assertEqual(segs[0].text, 'aaa\uD83D\uDE00');
301
- assertEqual(segs[1].text, 'bbb');
302
- });
303
-
304
- runTest('wordWrap: widgetWidth=1 with wide surrogate pair does not split pair', () => {
305
- const input = createMockInput(surrogateStrWidth);
306
- // Emoji (😀) has visual width 2, but widgetWidth is 1.
307
- // Must keep the surrogate pair intact, not split mid-pair.
308
- const line = '\uD83D\uDE00b';
309
- const segs = input._wordWrapLine(line, 1);
310
- if (segs.length < 1) throw new Error('Expected at least 1 segment');
311
- // The first segment should be the full emoji (never a lone high surrogate)
312
- assertEqual(segs[0].text, '\uD83D\uDE00');
313
- if (segs.length > 1) {
314
- assertEqual(segs[1].text.charAt(0), 'b');
315
- }
316
- });
317
-
318
- // ========== _getVisualPos tests ==========
319
-
320
- runTest('visualPos: cursor at start of single line', () => {
321
- const input = createMockInput();
322
- input.value = 'hello';
323
- const pos = input._getVisualPos(0, 10);
324
- assertEqual(pos.row, 0);
325
- assertEqual(pos.col, 0);
326
- });
327
-
328
- runTest('visualPos: cursor at end of single line', () => {
329
- const input = createMockInput();
330
- input.value = 'hello';
331
- const pos = input._getVisualPos(5, 10);
332
- assertEqual(pos.row, 0);
333
- assertEqual(pos.col, 5);
334
- });
335
-
336
- runTest('visualPos: cursor on second visual line after wrap', () => {
337
- const input = createMockInput();
338
- input.value = 'hello world';
339
- const pos = input._getVisualPos(6, 10);
340
- assertEqual(pos.row, 1);
341
- assertEqual(pos.col, 0);
342
- });
343
-
344
- runTest('visualPos: cursor with newline', () => {
345
- const input = createMockInput();
346
- input.value = 'abc\ndef';
347
- const pos = input._getVisualPos(4, 10);
348
- assertEqual(pos.row, 1);
349
- assertEqual(pos.col, 0);
350
- });
351
-
352
- // ========== _countVisualLines tests ==========
353
-
354
- runTest('countLines: empty value returns 1', () => {
355
- const input = createMockInput();
356
- input.value = '';
357
- assertEqual(input._countVisualLines(10), 1);
358
- });
359
-
360
- runTest('countLines: single short line returns 1', () => {
361
- const input = createMockInput();
362
- input.value = 'hello';
363
- assertEqual(input._countVisualLines(10), 1);
364
- });
365
-
366
- runTest('countLines: wrapping line adds visual lines', () => {
367
- const input = createMockInput();
368
- input.value = 'hello world';
369
- assertEqual(input._countVisualLines(10), 2);
370
- });
371
-
372
- runTest('countLines: newline adds visual line', () => {
373
- const input = createMockInput();
374
- input.value = 'abc\ndef';
375
- assertEqual(input._countVisualLines(10), 2);
376
- });
377
-
378
- // ========== _buildCharToVisual tests ==========
379
-
380
- runTest('charMap: simple line maps correctly', () => {
381
- const input = createMockInput();
382
- input.value = 'abc';
383
- const map = input._buildCharToVisual(10);
384
- assertEqual(map.length, 4);
385
- assertEqual(map[0].row, 0);
386
- assertEqual(map[0].col, 0);
387
- assertEqual(map[1].col, 1);
388
- assertEqual(map[2].col, 2);
389
- assertEqual(map[3].col, 3);
390
- });
391
-
392
- runTest('charMap: exact width line end stays on same row', () => {
393
- const input = createMockInput();
394
- input.value = '1234567890';
395
- const map = input._buildCharToVisual(10);
396
- assertEqual(map[10].row, 0);
397
- assertEqual(map[10].col, 10);
398
- });
399
-
400
- runTest('charMap: line exceeding width wraps end to next row', () => {
401
- const input = createMockInput();
402
- input.value = '12345678901';
403
- const map = input._buildCharToVisual(10);
404
- assertEqual(map[10].row, 1);
405
- assertEqual(map[10].col, 0);
406
- });
407
-
408
- runTest('charMap: newline maps to end of visual row', () => {
409
- const input = createMockInput();
410
- input.value = 'ab\ncd';
411
- const map = input._buildCharToVisual(10);
412
- assertEqual(map.length, 6);
413
- assertEqual(map[2].row, 0);
414
- assertEqual(map[3].row, 1);
415
- assertEqual(map[3].col, 0);
416
- });
417
-
418
- runTest('charMap: uses input.value not fullValue (no ReferenceError)', () => {
419
- const input = createMockInput();
420
- input.value = 'hello\nworld';
421
- const map = input._buildCharToVisual(10);
422
- assertEqual(map.length, 12);
423
- assertEqual((input.value || '')[5], '\n');
424
- });
425
-
426
- // ========== _charPosFromVisualRow tests ==========
427
-
428
- runTest('charFromRow: row 0 col 0 returns 0', () => {
429
- const input = createMockInput();
430
- input.value = 'hello';
431
- assertEqual(input._charPosFromVisualRow(0, 0, 10), 0);
432
- });
433
-
434
- runTest('charFromRow: row 0 col 3 returns 3', () => {
435
- const input = createMockInput();
436
- input.value = 'hello';
437
- assertEqual(input._charPosFromVisualRow(0, 3, 10), 3);
438
- });
439
-
440
- runTest('charFromRow: col beyond line length clamps to end', () => {
441
- const input = createMockInput();
442
- input.value = 'hello';
443
- assertEqual(input._charPosFromVisualRow(0, 999, 10), 5);
444
- });
445
-
446
- runTest('charFromRow: navigates to second visual line after wrap', () => {
447
- const input = createMockInput();
448
- input.value = 'hello world';
449
- const pos = input._charPosFromVisualRow(1, 0, 10);
450
- assertEqual(pos, 6);
451
- });
452
-
453
- runTest('charFromRow: past last row returns value length', () => {
454
- const input = createMockInput();
455
- input.value = 'hello';
456
- assertEqual(input._charPosFromVisualRow(99, 0, 10), 5);
457
- });
458
-
459
- // ========== Double-width character tests ==========
460
-
461
- runTest('double-width: _wordWrapLine handles double-width chars', () => {
462
- const input = createMockInput((s) => { return s ? s.length * 2 : 0; });
463
- let segs = input._wordWrapLine('abcde', 10);
464
- assertEqual(segs.length, 1);
465
- segs = input._wordWrapLine('abcdef', 10);
466
- assertEqual(segs.length, 2);
467
- assertEqual(segs[0].text, 'abcde');
468
- assertEqual(segs[1].text, 'f');
469
- });
470
-
471
- runTest('double-width: _getVisualPos with double-width chars', () => {
472
- const input = createMockInput((s) => { return s ? s.length * 2 : 0; });
473
- input.value = 'abcdef';
474
- const pos = input._getVisualPos(5, 10);
475
- assertEqual(pos.row, 1);
476
- assertEqual(pos.col, 0);
477
- });
478
-
479
- runTest('double-width: _buildCharToVisual maps columns correctly', () => {
480
- const input = createMockInput((s) => { return s ? s.length * 2 : 0; });
481
- input.value = 'abc';
482
- const map = input._buildCharToVisual(10);
483
- assertEqual(map[0].col, 0);
484
- assertEqual(map[1].col, 2);
485
- assertEqual(map[2].col, 4);
486
- });
487
-
488
- runTest('double-width: _charPosFromVisualRow with double-width', () => {
489
- const input = createMockInput((s) => { return s ? s.length * 2 : 0; });
490
- input.value = 'abcdef';
491
- const pos = input._charPosFromVisualRow(0, 4, 10);
492
- assertEqual(pos, 2);
493
- });
494
-
495
- // ========== _getWrapWidth tests (issue #150) ==========
496
-
497
- runTest('wrapWidth: subtracts 1 from raw widget width (textarea margin)', () => {
498
- // Widget width = 50 (xl=50, xi=0), iwidth=0 => wrapWidth = 50 - 0 - 1 = 49
499
- const input = createMockInput(undefined, 50);
500
- assertEqual(input._getWrapWidth(), 49);
501
- });
502
-
503
- runTest('wrapWidth: accounts for iwidth', () => {
504
- const input = createMockInput(undefined, 50);
505
- input.iwidth = 2;
506
- // 50 - 2 - 1 = 47
507
- assertEqual(input._getWrapWidth(), 47);
508
- });
509
-
510
- runTest('wrapWidth: returns 79 when no lpos available', () => {
511
- const input = createMockInput();
512
- // No lpos set, so fallback to 79
513
- assertEqual(input._getWrapWidth(), 79);
514
- });
515
-
516
- runTest('wrapWidth: clamps to 1 for very narrow widget', () => {
517
- const input = createMockInput(undefined, 2);
518
- // 2 - 0 - 1 = 1
519
- assertEqual(input._getWrapWidth(), 1);
520
- input.lpos = { xl: 1, xi: 0 };
521
- // 1 - 0 - 1 = 0 => clamped to 1
522
- assertEqual(input._getWrapWidth(), 1);
523
- });
524
-
525
- runTest('wrapWidth: accepts optional lpos parameter to avoid redundant _getCoords', () => {
526
- const input = createMockInput(undefined, 20);
527
- // Default: uses input.lpos (xl=20, xi=0) => 20 - 0 - 1 = 19
528
- assertEqual(input._getWrapWidth(), 19);
529
- // Passing a different lpos overrides the default
530
- const customLpos = { xl: 15, xi: 0 };
531
- assertEqual(input._getWrapWidth(customLpos), 14);
532
- // Passing lpos avoids using input.lpos
533
- input.lpos = null;
534
- assertEqual(input._getWrapWidth(customLpos), 14);
535
- // Without lpos param and no input.lpos, falls back to 79
536
- assertEqual(input._getWrapWidth(), 79);
537
- });
538
-
539
- runTest('wrapWidth: word wrap uses correct width with textarea margin', () => {
540
- // Simulate a widget that is 11 chars wide. Blessed's effective wrap
541
- // width is 11 - 1 = 10. "hello world" (11 chars) should wrap.
542
- const input = createMockInput(undefined, 11);
543
- input.value = 'hello world';
544
- const ww = input._getWrapWidth(); // 10
545
- assertEqual(ww, 10);
546
- const segs = input._wordWrapLine('hello world', ww);
547
- assertEqual(segs.length, 2);
548
- assertEqual(segs[0].text, 'hello ');
549
- assertEqual(segs[1].text, 'world');
550
- });
551
-
552
- runTest('wrapWidth: cursor position matches blessed wrap at boundary', () => {
553
- // Widget width 11, effective wrap width 10.
554
- // "hello worl" = 10 chars, fits on line 1.
555
- // Adding "d" makes "hello world" = 11 chars, wraps "world" to line 2.
556
- const input = createMockInput(undefined, 11);
557
- input.value = 'hello world';
558
- const ww = input._getWrapWidth(); // 10
559
- // Insertion position 10 (just before 'd') should be on row 1
560
- let vpos = input._getVisualPos(10, ww);
561
- assertEqual(vpos.row, 1);
562
- // Insertion position 6 (just before the 'w' of 'world') should also be on row 1
563
- vpos = input._getVisualPos(6, ww);
564
- assertEqual(vpos.row, 1);
565
- assertEqual(vpos.col, 0);
566
- });
567
-
568
- console.log('\nAll tui-wrap tests complete.');
package/test-binary.js DELETED
@@ -1,52 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
-
4
- const binaryPath = '/Users/raymond/pave-apps/openpave/src/packages/pave/dist/bin/pave-darwin-arm64';
5
- const binary = fs.readFileSync(binaryPath);
6
- const str = binary.toString('utf8');
7
-
8
- console.log('='.repeat(60));
9
- console.log('PAVE Binary Analysis');
10
- console.log('='.repeat(60));
11
- console.log('Binary size:', (binary.length / 1024 / 1024).toFixed(1), 'MB');
12
- console.log('');
13
- console.log('Searching for sensitive sandbox strings...');
14
- console.log('');
15
-
16
- const sensitivePatterns = [
17
- 'newGlobal',
18
- 'os.system',
19
- 'SandboxRunner',
20
- '__ipc__',
21
- 'OPENCODE_TOKENS',
22
- 'deleteModule',
23
- 'newCompartment',
24
- 'drainJobQueue',
25
- ];
26
-
27
- sensitivePatterns.forEach((pattern) => {
28
- const found = str.includes(pattern);
29
- const status = found ? '⚠️ FOUND' : '✅ NOT FOUND';
30
- console.log(` ${pattern}: ${status}`);
31
- });
32
-
33
- console.log('');
34
- console.log('='.repeat(60));
35
-
36
- // Compare with original JS bundle
37
- const jsPath = '/Users/raymond/pave-apps/openpave/src/packages/pave/dist/pave.js';
38
- const js = fs.readFileSync(jsPath, 'utf8');
39
-
40
- console.log('Comparison with original pave.js:');
41
- console.log('');
42
-
43
- sensitivePatterns.forEach((pattern) => {
44
- const inBinary = str.includes(pattern);
45
- const inJS = js.includes(pattern);
46
- console.log(` ${pattern}:`);
47
- console.log(` In JS bundle: ${inJS ? 'YES' : 'NO'}`);
48
- console.log(` In binary: ${inBinary ? 'YES' : 'NO'}`);
49
- });
50
-
51
- console.log('');
52
- console.log('='.repeat(60));
package/test-binary2.js DELETED
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env node
2
- const fs = require('fs');
3
-
4
- const binaryPath = '/Users/raymond/pave-apps/openpave/src/packages/pave/dist/bin/pave-darwin-arm64';
5
- const binary = fs.readFileSync(binaryPath);
6
- const str = binary.toString('utf8');
7
-
8
- // Try to find and extract readable code chunks
9
- console.log('='.repeat(60));
10
- console.log('Checking if source code is readable in binary...');
11
- console.log('='.repeat(60));
12
-
13
- // Search for newGlobal context
14
- const newGlobalIndex = str.indexOf('newGlobal');
15
- if (newGlobalIndex !== -1) {
16
- console.log('\nContext around "newGlobal":');
17
- const start = Math.max(0, newGlobalIndex - 100);
18
- const end = Math.min(str.length, newGlobalIndex + 200);
19
- const context = str.slice(start, end);
20
- // Show only printable characters
21
- const printable = context.replace(/[^\x20-\x7E\n]/g, '.');
22
- console.log(printable);
23
- }
24
-
25
- // Search for os.system context
26
- const osSystemIndex = str.indexOf('os.system');
27
- if (osSystemIndex !== -1) {
28
- console.log('\n\nContext around "os.system":');
29
- const start = Math.max(0, osSystemIndex - 100);
30
- const end = Math.min(str.length, osSystemIndex + 200);
31
- const context = str.slice(start, end);
32
- const printable = context.replace(/[^\x20-\x7E\n]/g, '.');
33
- console.log(printable);
34
- }
35
-
36
- console.log('\n' + '='.repeat(60));