@cnrai/pave 0.3.33 → 0.3.35

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/MARKETPLACE.md +406 -0
  2. package/README.md +218 -21
  3. package/build-binary.js +591 -0
  4. package/build-npm.js +537 -0
  5. package/build.js +230 -0
  6. package/check-binary.js +26 -0
  7. package/deploy.sh +95 -0
  8. package/index.js +5776 -0
  9. package/lib/agent-registry.js +1037 -0
  10. package/lib/args-parser.js +837 -0
  11. package/lib/blessed-widget-patched.js +93 -0
  12. package/lib/cli-markdown.js +590 -0
  13. package/lib/compaction.js +153 -0
  14. package/lib/duration.js +94 -0
  15. package/lib/hash.js +22 -0
  16. package/lib/marketplace.js +866 -0
  17. package/lib/memory-config.js +166 -0
  18. package/lib/skill-manager.js +891 -0
  19. package/lib/soul.js +31 -0
  20. package/lib/tool-output-formatter.js +180 -0
  21. package/package.json +35 -32
  22. package/start-pave.sh +149 -0
  23. package/status.js +271 -0
  24. package/test/abort-stream.test.js +445 -0
  25. package/test/agent-auto-compaction.test.js +552 -0
  26. package/test/agent-comm-abort.test.js +95 -0
  27. package/test/agent-comm.test.js +598 -0
  28. package/test/agent-inbox.test.js +576 -0
  29. package/test/agent-init.test.js +264 -0
  30. package/test/agent-interrupt.test.js +314 -0
  31. package/test/agent-lifecycle.test.js +520 -0
  32. package/test/agent-log-files.test.js +349 -0
  33. package/test/agent-mode.manual-test.js +392 -0
  34. package/test/agent-parsing.test.js +228 -0
  35. package/test/agent-post-stream-idle.test.js +762 -0
  36. package/test/agent-registry.test.js +359 -0
  37. package/test/agent-rm.test.js +442 -0
  38. package/test/agent-spawn.test.js +933 -0
  39. package/test/agent-status-api.test.js +624 -0
  40. package/test/agent-update.test.js +435 -0
  41. package/test/args-parser.test.js +391 -0
  42. package/test/auto-compaction-chat.manual-test.js +227 -0
  43. package/test/auto-compaction.test.js +941 -0
  44. package/test/build-config.test.js +120 -0
  45. package/test/build-npm.test.js +388 -0
  46. package/test/chat-command.test.js +137 -0
  47. package/test/chat-leading-lines.test.js +159 -0
  48. package/test/config-flag.test.js +272 -0
  49. package/test/cursor-drift.test.js +135 -0
  50. package/test/debug-require.js +23 -0
  51. package/test/dir-migration.test.js +323 -0
  52. package/test/duration.test.js +229 -0
  53. package/test/ghostty-term.test.js +202 -0
  54. package/test/http500-backoff.test.js +854 -0
  55. package/test/integration.test.js +86 -0
  56. package/test/memory-guard-env.test.js +220 -0
  57. package/test/pr233-fixes.test.js +259 -0
  58. package/test/run-agent-init.js +297 -0
  59. package/test/run-all.js +64 -0
  60. package/test/run-config-flag.js +159 -0
  61. package/test/run-cursor-drift.js +82 -0
  62. package/test/run-session-path.js +154 -0
  63. package/test/run-tests.js +643 -0
  64. package/test/sandbox-redirect.test.js +202 -0
  65. package/test/session-path.test.js +132 -0
  66. package/test/shebang-strip.test.js +241 -0
  67. package/test/soul-reinject.test.js +1027 -0
  68. package/test/soul-reread.test.js +281 -0
  69. package/test/tool-output-formatter.test.js +486 -0
  70. package/test/tool-output-gating.test.js +143 -0
  71. package/test/tool-states.test.js +167 -0
  72. package/test/tools-flag.test.js +65 -0
  73. package/test/tui-attach.test.js +1255 -0
  74. package/test/tui-compaction.test.js +354 -0
  75. package/test/tui-wrap.test.js +568 -0
  76. package/test-binary.js +52 -0
  77. package/test-binary2.js +36 -0
  78. package/LICENSE +0 -21
  79. package/pave.js +0 -3
  80. package/sandbox/SandboxRunner.js +0 -1
  81. package/sandbox/pave-run.js +0 -2
  82. package/sandbox/permission.js +0 -1
  83. package/sandbox/utils/yaml.js +0 -1
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Tests for TERM=xterm-ghostty TUI crash fix (Issue #125).
3
+ *
4
+ * Verifies:
5
+ * 1. resolveTerminal() remaps xterm-ghostty to xterm-256color
6
+ * 2. resolveTerminal() passes known terminals through unchanged
7
+ * 3. resolveTerminal() falls back to xterm-256color for unknown terminals
8
+ * 4. resolveTerminal() leaves 'unknown' as-is (special case)
9
+ * 5. _internal.REMAP_TERMINALS and _internal.KNOWN_TERMINALS are exported and correct
10
+ * 6. Catch-block retry with xterm-256color fallback exists in source
11
+ *
12
+ * Uses checkmark/X format so run-all.js correctly counts results.
13
+ */
14
+
15
+ let passed = 0;
16
+ let failed = 0;
17
+
18
+ function assert(cond, msg) {
19
+ if (cond) {
20
+ passed++;
21
+ console.log('\u2705 ' + msg);
22
+ } else {
23
+ failed++;
24
+ console.log('\u274c ' + msg);
25
+ }
26
+ }
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+ const child_process = require('child_process');
31
+ const os = require('os');
32
+
33
+ const projDir = path.resolve(__dirname, '../../../..');
34
+
35
+ // Counter for unique temp file names (avoids Date.now() collisions in parallel)
36
+ let tmpCounter = 0;
37
+
38
+ // Helper to run a script via temp file and get JSON output
39
+ function runScript(code) {
40
+ tmpCounter++;
41
+ const tmp = path.join(os.tmpdir(), '_test_ghostty_' + Date.now() + '_' + tmpCounter + '.js');
42
+ try {
43
+ fs.writeFileSync(tmp, code, 'utf8');
44
+ const out = child_process.execFileSync(process.execPath, [tmp], {
45
+ cwd: projDir, encoding: 'utf8', timeout: 5000,
46
+ }).trim();
47
+ return JSON.parse(out);
48
+ } catch (e) {
49
+ const errMsg = (e.stderr || e.message || '').slice(0, 200);
50
+ // Known sandbox limitation: execFileSync not available in SpiderMonkey sandbox
51
+ if (errMsg.indexOf('execFileSync is not a function') !== -1) {
52
+ console.log('SKIP (sandbox limitation): ' + errMsg.slice(0, 120));
53
+ return null;
54
+ }
55
+ // Unexpected error - report as failure
56
+ failed++;
57
+ console.log('\u274c Unexpected subprocess error: ' + errMsg);
58
+ return null;
59
+ } finally {
60
+ try { fs.unlinkSync(tmp); } catch (e2) {}
61
+ }
62
+ }
63
+
64
+ // Try to load the resolveTerminal function via subprocess (avoids sandbox #shebang issue)
65
+ const resolveResult = runScript([
66
+ 'var tui = require(process.cwd() + "/src/packages/tui/index.js");',
67
+ 'var r = tui.resolveTerminal;',
68
+ 'var tests = [',
69
+ ' r("xterm-ghostty"),',
70
+ ' r("xterm-Ghostty"),',
71
+ ' r("xterm-256color"),',
72
+ ' r("linux"),',
73
+ ' r("screen-256color"),',
74
+ ' r("tmux-256color"),',
75
+ ' r("totally-unknown"),',
76
+ ' r("unknown"),',
77
+ ' r("xterm"),',
78
+ ' r("xterm-color"),',
79
+ ' r("rxvt-unicode-256color"),',
80
+ ' r("putty-256color"),',
81
+ ' r("kitty"),',
82
+ ' r("alacritty"),',
83
+ ' r(undefined),',
84
+ ' r(null),',
85
+ ' r("")',
86
+ '];',
87
+ 'var int = tui._internal || {};',
88
+ 'var hasRemap = typeof int.REMAP_TERMINALS === "object";',
89
+ 'var hasKnown = Array.isArray(int.KNOWN_TERMINALS);',
90
+ 'var remapGhostty = hasRemap ? int.REMAP_TERMINALS["xterm-ghostty"] : null;',
91
+ 'var knownHasGhostty = hasKnown ? int.KNOWN_TERMINALS.indexOf("xterm-ghostty") !== -1 : null;',
92
+ 'console.log(JSON.stringify({tests:tests,hasRemap:hasRemap,hasKnown:hasKnown,remapGhostty:remapGhostty,knownHasGhostty:knownHasGhostty}));',
93
+ ].join('\n'));
94
+
95
+ if (resolveResult) {
96
+ const t = resolveResult.tests;
97
+
98
+ // ---- 1. resolveTerminal() remapping ----
99
+ assert(t[0].effectiveTerm === 'xterm-256color' && t[0].wasRemapped === true,
100
+ 'resolveTerminal: xterm-ghostty -> xterm-256color (remapped)');
101
+ assert(t[1].effectiveTerm === 'xterm-256color' && t[1].wasRemapped === true,
102
+ 'resolveTerminal: xterm-Ghostty -> xterm-256color (case-insensitive)');
103
+
104
+ // ---- 2. Known terminals pass through ----
105
+ assert(t[2].effectiveTerm === 'xterm-256color' && !t[2].wasRemapped && !t[2].wasUnknown,
106
+ 'resolveTerminal: xterm-256color -> unchanged');
107
+ assert(t[3].effectiveTerm === 'linux' && !t[3].wasRemapped,
108
+ 'resolveTerminal: linux -> unchanged');
109
+ assert(t[4].effectiveTerm === 'screen-256color' && !t[4].wasRemapped,
110
+ 'resolveTerminal: screen-256color -> unchanged');
111
+ assert(t[5].effectiveTerm === 'tmux-256color' && !t[5].wasRemapped,
112
+ 'resolveTerminal: tmux-256color -> unchanged');
113
+
114
+ // ---- 3. Unknown terminals -> xterm-256color ----
115
+ assert(t[6].effectiveTerm === 'xterm-256color' && t[6].wasUnknown === true,
116
+ 'resolveTerminal: totally-unknown -> xterm-256color (unknown fallback)');
117
+
118
+ // ---- 4. 'unknown' is special - left as-is ----
119
+ assert(t[7].effectiveTerm === 'unknown' && !t[7].wasUnknown,
120
+ 'resolveTerminal: unknown -> unchanged (special case)');
121
+
122
+ // ---- 5. More known terminals ----
123
+ assert(t[8].effectiveTerm === 'xterm' && !t[8].wasRemapped,
124
+ 'resolveTerminal: xterm -> unchanged');
125
+ assert(t[9].effectiveTerm === 'xterm-color' && !t[9].wasRemapped,
126
+ 'resolveTerminal: xterm-color -> unchanged');
127
+ assert(t[10].effectiveTerm === 'rxvt-unicode-256color' && !t[10].wasRemapped,
128
+ 'resolveTerminal: rxvt-unicode-256color -> unchanged');
129
+ assert(t[11].effectiveTerm === 'putty-256color' && !t[11].wasRemapped,
130
+ 'resolveTerminal: putty-256color -> unchanged');
131
+
132
+ // ---- 6. Other unknown terminals ----
133
+ assert(t[12].effectiveTerm === 'xterm-256color' && t[12].wasUnknown === true,
134
+ 'resolveTerminal: kitty -> xterm-256color (unknown fallback)');
135
+ assert(t[13].effectiveTerm === 'xterm-256color' && t[13].wasUnknown === true,
136
+ 'resolveTerminal: alacritty -> xterm-256color (unknown fallback)');
137
+
138
+ // ---- 7. Non-string input guard ----
139
+ assert(t[14].effectiveTerm === 'unknown' && !t[14].wasRemapped && !t[14].wasUnknown,
140
+ 'resolveTerminal: undefined -> unknown (guard)');
141
+ assert(t[15].effectiveTerm === 'unknown' && !t[15].wasRemapped && !t[15].wasUnknown,
142
+ 'resolveTerminal: null -> unknown (guard)');
143
+ assert(t[16].effectiveTerm === 'xterm-256color' && t[16].wasUnknown === true,
144
+ 'resolveTerminal: empty string -> xterm-256color (unknown fallback)');
145
+
146
+ // ---- 8. Exported constants ----
147
+ assert(resolveResult.hasRemap === true,
148
+ 'export: _internal.REMAP_TERMINALS is exported');
149
+ assert(resolveResult.hasKnown === true,
150
+ 'export: _internal.KNOWN_TERMINALS is exported');
151
+ assert(resolveResult.remapGhostty === 'xterm-256color',
152
+ 'export: _internal.REMAP_TERMINALS["xterm-ghostty"] = xterm-256color');
153
+ assert(resolveResult.knownHasGhostty === false,
154
+ 'export: xterm-ghostty NOT in _internal.KNOWN_TERMINALS');
155
+ } else {
156
+ console.log('SKIP: resolveTerminal subprocess not available - running source checks only');
157
+ }
158
+
159
+ // ---- 9. Source-level structural checks (minimal, verifying key patterns) ----
160
+ // resolveTerminal was extracted from index.js into lib/terminal-utils.js
161
+ const tuiSrc = fs.readFileSync(path.resolve(__dirname, '../../tui/index.js'), 'utf8');
162
+ const termUtilsSrc = fs.readFileSync(path.resolve(__dirname, '../../tui/lib/terminal-utils.js'), 'utf8');
163
+
164
+ // Verify resolveTerminal function is defined in terminal-utils.js
165
+ assert(/function resolveTerminal/.test(termUtilsSrc),
166
+ 'source: resolveTerminal function defined');
167
+ // Verify resolveTerminal is re-exported from index.js
168
+ assert(/module\.exports[\s\S]*resolveTerminal/.test(tuiSrc),
169
+ 'source: resolveTerminal is exported');
170
+ assert(/_internal:\s*\{[\s\S]*KNOWN_TERMINALS[\s\S]*REMAP_TERMINALS/.test(tuiSrc) ||
171
+ /_internal:\s*\{[\s\S]*REMAP_TERMINALS[\s\S]*KNOWN_TERMINALS/.test(tuiSrc),
172
+ 'source: KNOWN_TERMINALS and REMAP_TERMINALS under _internal namespace');
173
+
174
+ // Verify catch block retries with xterm-256color fallback
175
+ assert(/catch\s*\(err\)[\s\S]*?effectiveTerm\s*!==\s*'xterm-256color'/.test(tuiSrc),
176
+ 'source: catch block checks effectiveTerm !== xterm-256color');
177
+ assert(/catch\s*\(err\)[\s\S]*?blessed\.screen\(/.test(tuiSrc),
178
+ 'source: catch block retries blessed.screen()');
179
+
180
+ // Verify error output helper exists (reduces duplication)
181
+ assert(/function printTerminalInitFailure/.test(tuiSrc),
182
+ 'source: printTerminalInitFailure helper extracted');
183
+
184
+ // Verify non-string guard in resolveTerminal (now in terminal-utils.js)
185
+ assert(/term\s*==\s*null/.test(termUtilsSrc) || /String\(term\)/.test(termUtilsSrc),
186
+ 'source: resolveTerminal guards against non-string input');
187
+
188
+ // Verify effectiveTerm is normalized to lowercase for terminfo compatibility (now in terminal-utils.js)
189
+ assert(/effectiveTerm\s*=\s*effectiveTerm\.toLowerCase\(\)/.test(termUtilsSrc),
190
+ 'source: effectiveTerm normalized to lowercase');
191
+
192
+ // Verify error helper handles non-Error objects
193
+ assert(/String\(error\)/.test(tuiSrc),
194
+ 'source: printTerminalInitFailure handles non-Error objects');
195
+
196
+ // Verify error messages show both original and effective TERM
197
+ assert(/Original TERM/.test(tuiSrc) && /Effective TERM/.test(tuiSrc),
198
+ 'source: error messages show both Original and Effective TERM');
199
+
200
+ console.log('');
201
+ console.log(passed + ' passed, ' + failed + ' failed');
202
+ if (failed > 0) throw new Error(failed + ' test(s) failed');