@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.
- package/LICENSE +21 -0
- package/README.md +21 -218
- package/package.json +32 -35
- package/pave.js +3 -0
- package/sandbox/SandboxRunner.js +1 -0
- package/sandbox/pave-run.js +2 -0
- package/sandbox/permission.js +1 -0
- package/sandbox/utils/yaml.js +1 -0
- package/MARKETPLACE.md +0 -406
- package/build-binary.js +0 -591
- package/build-npm.js +0 -537
- package/build.js +0 -230
- package/check-binary.js +0 -26
- package/deploy.sh +0 -95
- package/index.js +0 -5776
- package/lib/agent-registry.js +0 -1037
- package/lib/args-parser.js +0 -837
- package/lib/blessed-widget-patched.js +0 -93
- package/lib/cli-markdown.js +0 -590
- package/lib/compaction.js +0 -153
- package/lib/duration.js +0 -94
- package/lib/hash.js +0 -22
- package/lib/marketplace.js +0 -866
- package/lib/memory-config.js +0 -166
- package/lib/skill-manager.js +0 -891
- package/lib/soul.js +0 -31
- package/lib/tool-output-formatter.js +0 -180
- package/start-pave.sh +0 -149
- package/status.js +0 -271
- package/test/abort-stream.test.js +0 -445
- package/test/agent-auto-compaction.test.js +0 -552
- package/test/agent-comm-abort.test.js +0 -95
- package/test/agent-comm.test.js +0 -598
- package/test/agent-inbox.test.js +0 -576
- package/test/agent-init.test.js +0 -264
- package/test/agent-interrupt.test.js +0 -314
- package/test/agent-lifecycle.test.js +0 -520
- package/test/agent-log-files.test.js +0 -349
- package/test/agent-mode.manual-test.js +0 -392
- package/test/agent-parsing.test.js +0 -228
- package/test/agent-post-stream-idle.test.js +0 -762
- package/test/agent-registry.test.js +0 -359
- package/test/agent-rm.test.js +0 -442
- package/test/agent-spawn.test.js +0 -933
- package/test/agent-status-api.test.js +0 -624
- package/test/agent-update.test.js +0 -435
- package/test/args-parser.test.js +0 -391
- package/test/auto-compaction-chat.manual-test.js +0 -227
- package/test/auto-compaction.test.js +0 -941
- package/test/build-config.test.js +0 -120
- package/test/build-npm.test.js +0 -388
- package/test/chat-command.test.js +0 -137
- package/test/chat-leading-lines.test.js +0 -159
- package/test/config-flag.test.js +0 -272
- package/test/cursor-drift.test.js +0 -135
- package/test/debug-require.js +0 -23
- package/test/dir-migration.test.js +0 -323
- package/test/duration.test.js +0 -229
- package/test/ghostty-term.test.js +0 -202
- package/test/http500-backoff.test.js +0 -854
- package/test/integration.test.js +0 -86
- package/test/memory-guard-env.test.js +0 -220
- package/test/pr233-fixes.test.js +0 -259
- package/test/run-agent-init.js +0 -297
- package/test/run-all.js +0 -64
- package/test/run-config-flag.js +0 -159
- package/test/run-cursor-drift.js +0 -82
- package/test/run-session-path.js +0 -154
- package/test/run-tests.js +0 -643
- package/test/sandbox-redirect.test.js +0 -202
- package/test/session-path.test.js +0 -132
- package/test/shebang-strip.test.js +0 -241
- package/test/soul-reinject.test.js +0 -1027
- package/test/soul-reread.test.js +0 -281
- package/test/tool-output-formatter.test.js +0 -486
- package/test/tool-output-gating.test.js +0 -143
- package/test/tool-states.test.js +0 -167
- package/test/tools-flag.test.js +0 -65
- package/test/tui-attach.test.js +0 -1255
- package/test/tui-compaction.test.js +0 -354
- package/test/tui-wrap.test.js +0 -568
- package/test-binary.js +0 -52
- package/test-binary2.js +0 -36
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Tests for build configuration
|
|
4
|
-
* Verifies that Bun compile targets are correctly configured
|
|
5
|
-
*
|
|
6
|
-
* Issue #73: CPU AVX Support Warning on macOS Startup
|
|
7
|
-
* Solution: Use baseline builds for x64 platforms to avoid AVX requirement
|
|
8
|
-
*
|
|
9
|
-
* This test validates the TARGETS configuration from build-binary.js
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
// Import the actual TARGETS from build-binary.js to validate the real source of truth
|
|
15
|
-
// This ensures tests will catch regressions if build-binary.js is changed
|
|
16
|
-
const buildBinaryPath = path.join(__dirname, '..', 'build-binary.js');
|
|
17
|
-
const { TARGETS } = require(buildBinaryPath);
|
|
18
|
-
|
|
19
|
-
// Test state tracking
|
|
20
|
-
let testsPassed = 0;
|
|
21
|
-
let testsFailed = 0;
|
|
22
|
-
|
|
23
|
-
// Test helpers
|
|
24
|
-
function runTest(name, testFn) {
|
|
25
|
-
try {
|
|
26
|
-
testFn();
|
|
27
|
-
console.log(`✅ ${name}`);
|
|
28
|
-
testsPassed++;
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.log(`❌ ${name}: ${error.message}`);
|
|
31
|
-
testsFailed++;
|
|
32
|
-
process.exitCode = 1;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function assertEqual(actual, expected, message) {
|
|
37
|
-
if (actual !== expected) {
|
|
38
|
-
throw new Error(`${message || 'Assertion'}: expected ${expected}, got ${actual}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function assertTrue(condition, message) {
|
|
43
|
-
if (!condition) {
|
|
44
|
-
throw new Error(message || 'Expected condition to be true');
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function assertContains(str, substring, message) {
|
|
49
|
-
if (!str.includes(substring)) {
|
|
50
|
-
throw new Error(`${message || 'Assertion'}: expected "${str}" to contain "${substring}"`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function assertNotContains(str, substring, message) {
|
|
55
|
-
if (str.includes(substring)) {
|
|
56
|
-
throw new Error(`${message || 'Assertion'}: expected "${str}" to NOT contain "${substring}"`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
console.log('🔧 Build Configuration Tests (Issue #73: AVX Compatibility)\n');
|
|
61
|
-
|
|
62
|
-
// Test: darwin-x64 should use baseline build
|
|
63
|
-
runTest('darwin-x64 should use baseline build to avoid AVX requirement', () => {
|
|
64
|
-
assertEqual(TARGETS['darwin-x64'], 'bun-darwin-x64-baseline', 'darwin-x64 target');
|
|
65
|
-
assertContains(TARGETS['darwin-x64'], 'baseline', 'darwin-x64 should contain baseline');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Test: linux-x64 should use baseline build
|
|
69
|
-
runTest('linux-x64 should use baseline build to avoid AVX requirement', () => {
|
|
70
|
-
assertEqual(TARGETS['linux-x64'], 'bun-linux-x64-baseline', 'linux-x64 target');
|
|
71
|
-
assertContains(TARGETS['linux-x64'], 'baseline', 'linux-x64 should contain baseline');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Test: darwin-arm64 should use standard build (ARM does not have AVX)
|
|
75
|
-
runTest('darwin-arm64 should use standard build (ARM does not have AVX)', () => {
|
|
76
|
-
assertEqual(TARGETS['darwin-arm64'], 'bun-darwin-arm64', 'darwin-arm64 target');
|
|
77
|
-
assertNotContains(TARGETS['darwin-arm64'], 'baseline', 'darwin-arm64 should NOT contain baseline');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Test: linux-arm64 should use standard build (ARM does not have AVX)
|
|
81
|
-
runTest('linux-arm64 should use standard build (ARM does not have AVX)', () => {
|
|
82
|
-
assertEqual(TARGETS['linux-arm64'], 'bun-linux-arm64', 'linux-arm64 target');
|
|
83
|
-
assertNotContains(TARGETS['linux-arm64'], 'baseline', 'linux-arm64 should NOT contain baseline');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Test: Required platform targets should be defined
|
|
87
|
-
// Using Object.prototype.hasOwnProperty.call() to avoid issues if hasOwnProperty is shadowed
|
|
88
|
-
runTest('required platform targets should be defined', () => {
|
|
89
|
-
assertTrue(Object.prototype.hasOwnProperty.call(TARGETS, 'darwin-arm64'), 'darwin-arm64 should be defined');
|
|
90
|
-
assertTrue(Object.prototype.hasOwnProperty.call(TARGETS, 'darwin-x64'), 'darwin-x64 should be defined');
|
|
91
|
-
assertTrue(Object.prototype.hasOwnProperty.call(TARGETS, 'linux-arm64'), 'linux-arm64 should be defined');
|
|
92
|
-
assertTrue(Object.prototype.hasOwnProperty.call(TARGETS, 'linux-x64'), 'linux-x64 should be defined');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Test: x64 targets should use baseline builds, ARM targets should not
|
|
96
|
-
runTest('x64 targets should use baseline builds, ARM targets should not', () => {
|
|
97
|
-
const x64Targets = Object.entries(TARGETS).filter(([key]) => key.includes('x64'));
|
|
98
|
-
const arm64Targets = Object.entries(TARGETS).filter(([key]) => key.includes('arm64'));
|
|
99
|
-
|
|
100
|
-
// All x64 targets should use baseline
|
|
101
|
-
for (const [key, value] of x64Targets) {
|
|
102
|
-
assertContains(value, 'baseline', `${key} should use baseline build`);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// No ARM64 targets should use baseline
|
|
106
|
-
for (const [key, value] of arm64Targets) {
|
|
107
|
-
assertNotContains(value, 'baseline', `${key} should NOT use baseline build`);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Print summary based on test results
|
|
112
|
-
// Note: Don't start with ✅/❌ as run-all.js counts those as test results
|
|
113
|
-
if (testsFailed === 0) {
|
|
114
|
-
console.log(`\nSummary: All ${testsPassed} build configuration tests passed!`);
|
|
115
|
-
} else {
|
|
116
|
-
console.log(`\nSummary: ${testsFailed} of ${testsPassed + testsFailed} tests failed`);
|
|
117
|
-
// Throw an error so the test runner marks this file as failed when any test fails
|
|
118
|
-
// The test runner uses require() which only fails if the module throws
|
|
119
|
-
throw new Error(`build-config.test.js: ${testsFailed} test(s) failed`);
|
|
120
|
-
}
|
package/test/build-npm.test.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for build-npm.js (Issue #157)
|
|
3
|
-
*
|
|
4
|
-
* Verifies that the npm build script:
|
|
5
|
-
* - Exists and is properly structured
|
|
6
|
-
* - Generates correct package.json for @cnrai/pave
|
|
7
|
-
* - Obfuscates sandbox files
|
|
8
|
-
* - Integrates with GitHub Actions workflow
|
|
9
|
-
* - Produces valid npm package structure
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
const paveDir = path.join(__dirname, '..');
|
|
16
|
-
const buildNpmSource = fs.readFileSync(path.join(paveDir, 'build-npm.js'), 'utf-8');
|
|
17
|
-
const packageJson = JSON.parse(fs.readFileSync(path.join(paveDir, 'package.json'), 'utf-8'));
|
|
18
|
-
const workflowPath = path.join(paveDir, '..', '..', '..', '.github', 'workflows', 'publish-obfuscated-dist.yml');
|
|
19
|
-
const workflowSource = fs.readFileSync(workflowPath, 'utf-8');
|
|
20
|
-
|
|
21
|
-
let passed = 0;
|
|
22
|
-
let failed = 0;
|
|
23
|
-
let total = 0;
|
|
24
|
-
|
|
25
|
-
function test(name, fn) {
|
|
26
|
-
total++;
|
|
27
|
-
try {
|
|
28
|
-
fn();
|
|
29
|
-
console.log('\u2705 ' + name);
|
|
30
|
-
passed++;
|
|
31
|
-
} catch (err) {
|
|
32
|
-
console.log('\u274c ' + name);
|
|
33
|
-
console.log(' ' + err.message);
|
|
34
|
-
failed++;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function assert(cond, msg) {
|
|
39
|
-
if (!cond) throw new Error(msg || 'Assertion failed');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function assertIncludes(haystack, needle, msg) {
|
|
43
|
-
if (haystack.indexOf(needle) === -1) {
|
|
44
|
-
throw new Error(msg || 'Expected to find "' + needle + '"');
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function assertEqual(actual, expected, msg) {
|
|
49
|
-
if (actual !== expected) {
|
|
50
|
-
throw new Error((msg || '') + ' Expected: ' + JSON.stringify(expected) + ', got: ' + JSON.stringify(actual));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
console.log('\nTesting npm publish build (Issue #157)\n');
|
|
55
|
-
console.log('='.repeat(60));
|
|
56
|
-
|
|
57
|
-
// --- build-npm.js structure ---
|
|
58
|
-
console.log('\n--- build-npm.js structure ---\n');
|
|
59
|
-
|
|
60
|
-
test('build-npm.js exists', () => {
|
|
61
|
-
assert(buildNpmSource.length > 0, 'build-npm.js should not be empty');
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('build-npm.js has shebang', () => {
|
|
65
|
-
assert(buildNpmSource.startsWith('#!/usr/bin/env node'), 'Should start with node shebang');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('build-npm.js uses esbuild for bundling', () => {
|
|
69
|
-
assertIncludes(buildNpmSource, "require('esbuild')", 'Should require esbuild');
|
|
70
|
-
assertIncludes(buildNpmSource, 'esbuild.build(', 'Should call esbuild.build');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('build-npm.js targets node16', () => {
|
|
74
|
-
assertIncludes(buildNpmSource, "'node16'", 'Should target node16');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('build-npm.js uses javascript-obfuscator', () => {
|
|
78
|
-
assertIncludes(buildNpmSource, 'javascript-obfuscator', 'Should use javascript-obfuscator');
|
|
79
|
-
assertIncludes(buildNpmSource, 'obfuscateFile', 'Should have obfuscateFile function');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test('build-npm.js outputs to dist/npm/', () => {
|
|
83
|
-
assertIncludes(buildNpmSource, "'dist', 'npm'", 'Should output to dist/npm/');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test('build-npm.js reads version from package.json', () => {
|
|
87
|
-
assertIncludes(buildNpmSource, 'packageJson.version', 'Should read version from package.json');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// --- Package metadata ---
|
|
91
|
-
console.log('\n--- Package metadata ---\n');
|
|
92
|
-
|
|
93
|
-
test('build-npm.js sets package name to @cnrai/pave', () => {
|
|
94
|
-
assertIncludes(buildNpmSource, "'@cnrai/pave'", 'Should use @cnrai/pave as package name');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('build-npm.js sets bin.pave to ./pave.js', () => {
|
|
98
|
-
assertIncludes(buildNpmSource, "'./pave.js'", 'Should set bin to ./pave.js');
|
|
99
|
-
// Verify it's in the bin field
|
|
100
|
-
const idx = buildNpmSource.indexOf('bin:');
|
|
101
|
-
assert(idx > -1, 'Should have bin field');
|
|
102
|
-
const block = buildNpmSource.substring(idx, idx + 100);
|
|
103
|
-
assertIncludes(block, 'pave', 'bin should include pave');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('build-npm.js sets engines >= 16', () => {
|
|
107
|
-
assertIncludes(buildNpmSource, "'>=16.0.0'", 'Should require Node >= 16.0.0');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('build-npm.js includes blessed as dependency', () => {
|
|
111
|
-
assertIncludes(buildNpmSource, "blessed", 'Should include blessed as dependency');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('build-npm.js includes js-yaml as dependency', () => {
|
|
115
|
-
assertIncludes(buildNpmSource, "js-yaml", 'Should include js-yaml as dependency');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('build-npm.js specifies files field', () => {
|
|
119
|
-
assertIncludes(buildNpmSource, "'pave.js'", 'Should include pave.js in files');
|
|
120
|
-
assertIncludes(buildNpmSource, "'sandbox/'", 'Should include sandbox/ in files');
|
|
121
|
-
assertIncludes(buildNpmSource, "'README.md'", 'Should include README.md in files');
|
|
122
|
-
assertIncludes(buildNpmSource, "'LICENSE'", 'Should include LICENSE in files');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test('build-npm.js generates README.md', () => {
|
|
126
|
-
assertIncludes(buildNpmSource, 'README.md', 'Should generate README');
|
|
127
|
-
assertIncludes(buildNpmSource, 'npm install -g @cnrai/pave', 'README should have install command');
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test('build-npm.js generates LICENSE', () => {
|
|
131
|
-
assertIncludes(buildNpmSource, 'MIT License', 'Should generate MIT LICENSE');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// --- Obfuscation ---
|
|
135
|
-
console.log('\n--- Obfuscation ---\n');
|
|
136
|
-
|
|
137
|
-
test('build-npm.js uses same obfuscation settings as build-binary.js', () => {
|
|
138
|
-
assertIncludes(buildNpmSource, "'low-obfuscation'", 'Should use low-obfuscation preset');
|
|
139
|
-
assertIncludes(buildNpmSource, "'base64'", 'Should use base64 string array encoding');
|
|
140
|
-
assertIncludes(buildNpmSource, "'mangled'", 'Should use mangled identifier names');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test('build-npm.js uses deterministic obfuscation for CI', () => {
|
|
144
|
-
assertIncludes(buildNpmSource, "'1.0'", 'Should use threshold 1.0 to move all strings');
|
|
145
|
-
assertIncludes(buildNpmSource, "'--seed'", 'Should use fixed seed for determinism');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('build-npm.js surfaces obfuscator stderr on failure', () => {
|
|
149
|
-
assertIncludes(buildNpmSource, 'err.stderr', 'Should include stderr in error message');
|
|
150
|
-
assertIncludes(buildNpmSource, 'err.stdout', 'Should include stdout in error message');
|
|
151
|
-
assertIncludes(buildNpmSource, 'javascript-obfuscator failed for', 'Should identify which file failed');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test('build-npm.js obfuscates sandbox files', () => {
|
|
155
|
-
assertIncludes(buildNpmSource, 'obfuscateFile(tempPath', 'Should obfuscate sandbox files');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test('build-npm.js adds shebang to obfuscated bundle', () => {
|
|
159
|
-
assertIncludes(buildNpmSource, '#!/usr/bin/env node', 'Should add shebang');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test('build-npm.js fails build if sensitive strings visible', () => {
|
|
163
|
-
assertIncludes(buildNpmSource, 'process.exit(1)', 'Should exit with error on obfuscation failure');
|
|
164
|
-
assertIncludes(buildNpmSource, "Error: Some sensitive strings", 'Should log error message');
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test('build-npm.js removes intermediate bundle file', () => {
|
|
168
|
-
assertIncludes(buildNpmSource, 'unlinkSync(bundlePath)', 'Should remove intermediate bundle');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test('build-npm.js uses execFileSync for safe path handling', () => {
|
|
172
|
-
assertIncludes(buildNpmSource, 'execFileSync', 'Should use execFileSync');
|
|
173
|
-
assertIncludes(buildNpmSource, "npxPath, args", 'Should pass arguments as array');
|
|
174
|
-
assertIncludes(buildNpmSource, 'cwd: ROOT_DIR', 'Should set cwd for deterministic resolution');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('build-npm.js uses octal chmod mode', () => {
|
|
178
|
-
assertIncludes(buildNpmSource, '0o755', 'Should use octal 0o755 for chmod');
|
|
179
|
-
assert(buildNpmSource.indexOf("'755'") === -1, 'Should NOT use string chmod mode');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test('build-npm.js fails on missing sandbox files', () => {
|
|
183
|
-
assertIncludes(buildNpmSource, 'Required sandbox file is missing', 'Should error on missing sandbox files');
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
test('build-npm.js fails fast if javascript-obfuscator not installed', () => {
|
|
187
|
-
assertIncludes(buildNpmSource, '--no-install', 'Should use npx --no-install');
|
|
188
|
-
assertIncludes(buildNpmSource, 'execFileSync(npxCheck', 'Availability check should use execFileSync');
|
|
189
|
-
assertIncludes(buildNpmSource, "cwd: ROOT_DIR", 'Availability check should set cwd: ROOT_DIR');
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
test('obfuscateFile uses --no-install to prevent network installs', () => {
|
|
193
|
-
// The obfuscateFile function args array should include --no-install
|
|
194
|
-
const fnMatch = buildNpmSource.match(/function obfuscateFile\b[\s\S]*?(?:const|let|var) args\s*=\s*\[([\s\S]*?)\];/);
|
|
195
|
-
assert(fnMatch, 'Should find obfuscateFile args array');
|
|
196
|
-
assertIncludes(fnMatch[1], "'--no-install'", 'obfuscateFile args should include --no-install');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('build-npm.js strips developer-specific paths from permission.js', () => {
|
|
200
|
-
// permission.js has a hard-coded /Users/raymond/... path that must be stripped
|
|
201
|
-
const idx = buildNpmSource.indexOf("file.dest === 'permission.js'");
|
|
202
|
-
assert(idx > -1, 'Should find permission.js patching block');
|
|
203
|
-
const block = buildNpmSource.substring(idx, idx + 500);
|
|
204
|
-
// The regex pattern uses escaped forward slashes: \/Users\/
|
|
205
|
-
assert(block.indexOf('Users') > -1, 'Should have regex to strip /Users/ paths');
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
test('build-npm.js checks sandbox outputs for developer paths', () => {
|
|
209
|
-
assertIncludes(buildNpmSource, 'devPathPatterns', 'Should define developer path patterns');
|
|
210
|
-
assertIncludes(buildNpmSource, 'Developer-specific path found', 'Should report developer path errors');
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
test('build-npm.js treats sandbox obfuscation failure as hard error', () => {
|
|
214
|
-
assertIncludes(buildNpmSource, 'Failed to obfuscate sandbox/', 'Should error on sandbox obfuscation failure');
|
|
215
|
-
// yaml.js is the exception
|
|
216
|
-
assertIncludes(buildNpmSource, "utils/yaml.js", 'Should allow yaml.js exception');
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
test('build-npm.js verifies sandbox output files for sensitive strings', () => {
|
|
220
|
-
assertIncludes(buildNpmSource, 'sandboxSensitive', 'Should define sandbox-specific sensitive strings');
|
|
221
|
-
assertIncludes(buildNpmSource, 'whitelistedSandbox', 'Should whitelist yaml.js from sandbox check');
|
|
222
|
-
assertIncludes(buildNpmSource, 'Sensitive strings in sandbox/', 'Should report which sandbox file has issues');
|
|
223
|
-
assertIncludes(buildNpmSource, 'Sandbox files verified', 'Should log success after verification');
|
|
224
|
-
// Ensure SandboxRunner is checked in sandbox files too (matches the workflow grep)
|
|
225
|
-
const idx = buildNpmSource.indexOf('sandboxSensitive');
|
|
226
|
-
assert(idx > -1, 'Should find sandboxSensitive definition');
|
|
227
|
-
const line = buildNpmSource.substring(idx, idx + 100);
|
|
228
|
-
assertIncludes(line, 'SandboxRunner', 'sandboxSensitive should include SandboxRunner');
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// --- Sandbox files ---
|
|
232
|
-
console.log('\n--- Sandbox files ---\n');
|
|
233
|
-
|
|
234
|
-
test('build-npm.js copies all 4 sandbox files', () => {
|
|
235
|
-
assertIncludes(buildNpmSource, "'pave-run.js'", 'Should copy pave-run.js');
|
|
236
|
-
assertIncludes(buildNpmSource, "'SandboxRunner.js'", 'Should copy SandboxRunner.js');
|
|
237
|
-
assertIncludes(buildNpmSource, "'permission.js'", 'Should copy permission.js');
|
|
238
|
-
assertIncludes(buildNpmSource, "'utils/yaml.js'", 'Should copy utils/yaml.js');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test('build-npm.js fixes require paths in sandbox files', () => {
|
|
242
|
-
// Same path fixing as build.js
|
|
243
|
-
assertIncludes(buildNpmSource, "require('./permission')", 'Should fix permission require path');
|
|
244
|
-
assertIncludes(buildNpmSource, "require('./utils/yaml')", 'Should fix yaml require path');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
test('build-npm.js creates sandbox utils subdirectory', () => {
|
|
248
|
-
assertIncludes(buildNpmSource, "'utils'", 'Should create utils subdirectory');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// --- Publish support ---
|
|
252
|
-
console.log('\n--- Publish support ---\n');
|
|
253
|
-
|
|
254
|
-
test('build-npm.js supports --publish flag', () => {
|
|
255
|
-
assertIncludes(buildNpmSource, "'--publish'", 'Should support --publish flag');
|
|
256
|
-
assertIncludes(buildNpmSource, 'npm publish --access public', 'Should use npm publish --access public');
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test('build-npm.js supports --dry-run flag', () => {
|
|
260
|
-
assertIncludes(buildNpmSource, "'--dry-run'", 'Should support --dry-run flag');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
test('--dry-run treats npm pack failures as errors', () => {
|
|
264
|
-
// Should only ignore ENOENT / exit code 127 (command not found)
|
|
265
|
-
assertIncludes(buildNpmSource, 'ENOENT', 'Should check for ENOENT (command not found)');
|
|
266
|
-
assertIncludes(buildNpmSource, '127', 'Should check for exit code 127');
|
|
267
|
-
assertIncludes(buildNpmSource, 'npm pack --dry-run failed', 'Should report pack failures');
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
test('build-npm.js rejects --publish and --dry-run together', () => {
|
|
271
|
-
assertIncludes(buildNpmSource, 'hasPublishFlag && hasDryRunFlag', 'Should check for mutual exclusivity');
|
|
272
|
-
assertIncludes(buildNpmSource, 'cannot be used together', 'Should have clear error message');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// --- package.json integration ---
|
|
276
|
-
console.log('\n--- package.json integration ---\n');
|
|
277
|
-
|
|
278
|
-
test('package.json has build:npm script', () => {
|
|
279
|
-
assert(packageJson.scripts['build:npm'], 'Should have build:npm script');
|
|
280
|
-
assertEqual(packageJson.scripts['build:npm'], 'node build-npm.js');
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
test('package.json has build:npm:publish script', () => {
|
|
284
|
-
assert(packageJson.scripts['build:npm:publish'], 'Should have build:npm:publish script');
|
|
285
|
-
assertEqual(packageJson.scripts['build:npm:publish'], 'node build-npm.js --publish');
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
// --- GitHub Actions workflow ---
|
|
289
|
-
console.log('\n--- GitHub Actions workflow ---\n');
|
|
290
|
-
|
|
291
|
-
test('workflow has publish-npm job', () => {
|
|
292
|
-
assertIncludes(workflowSource, 'publish-npm:', 'Should have publish-npm job');
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test('publish-npm job depends on smoke-test', () => {
|
|
296
|
-
// Find the publish-npm job block (needs may not be on the immediately next line due to if: guard)
|
|
297
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
298
|
-
assert(idx > -1, 'Should find publish-npm job');
|
|
299
|
-
const block = workflowSource.substring(idx, idx + 500);
|
|
300
|
-
assertIncludes(block, 'needs: smoke-test', 'Should depend on smoke-test');
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
test('publish-npm job uses setup-node with registry-url', () => {
|
|
304
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
305
|
-
const block = workflowSource.substring(idx);
|
|
306
|
-
assertIncludes(block, 'registry-url', 'Should set registry-url for npm auth');
|
|
307
|
-
assertIncludes(block, 'registry.npmjs.org', 'Should use npmjs.org registry');
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
test('publish-npm job runs build-npm.js', () => {
|
|
311
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
312
|
-
const block = workflowSource.substring(idx);
|
|
313
|
-
assertIncludes(block, 'node build-npm.js', 'Should run build-npm.js');
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test('publish-npm job uses NPM_TOKEN secret', () => {
|
|
317
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
318
|
-
const block = workflowSource.substring(idx);
|
|
319
|
-
assertIncludes(block, 'NPM_TOKEN', 'Should use NPM_TOKEN secret');
|
|
320
|
-
assertIncludes(block, 'NODE_AUTH_TOKEN', 'Should set NODE_AUTH_TOKEN env var');
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test('publish-npm job publishes with --access public', () => {
|
|
324
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
325
|
-
const block = workflowSource.substring(idx);
|
|
326
|
-
assertIncludes(block, 'npm publish --access public', 'Should publish with --access public');
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
test('publish-npm job verifies obfuscation in bundle and sandbox files', () => {
|
|
330
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
331
|
-
const block = workflowSource.substring(idx);
|
|
332
|
-
assertIncludes(block, 'Verify obfuscation', 'Should have obfuscation verification step');
|
|
333
|
-
assertIncludes(block, 'SandboxRunner', 'Should check for SandboxRunner string');
|
|
334
|
-
assertIncludes(block, 'exit 1', 'Should exit 1 if SandboxRunner found');
|
|
335
|
-
assertIncludes(block, "find sandbox -name '*.js'", 'Should recursively check sandbox JS files');
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
test('publish-npm job guards against duplicate publish', () => {
|
|
339
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
340
|
-
const block = workflowSource.substring(idx, idx + 300);
|
|
341
|
-
assertIncludes(block, "github.event_name != 'push'", 'Should skip on push events to prevent duplicates');
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
test('publish-npm job syncs version before build', () => {
|
|
345
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
346
|
-
const block = workflowSource.substring(idx);
|
|
347
|
-
assertIncludes(block, 'Sync version', 'Should sync version to package.json');
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
test('publish-npm job installs all dependencies', () => {
|
|
351
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
352
|
-
const block = workflowSource.substring(idx);
|
|
353
|
-
assertIncludes(block, 'opencode-lite', 'Should install opencode-lite deps');
|
|
354
|
-
assertIncludes(block, 'npm install', 'Should run npm install');
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
test('publish-npm job checks out correct ref for workflow_dispatch', () => {
|
|
358
|
-
const idx = workflowSource.indexOf('publish-npm:');
|
|
359
|
-
const block = workflowSource.substring(idx, idx + 800);
|
|
360
|
-
assertIncludes(block, 'workflow_dispatch', 'Should reference workflow_dispatch in checkout');
|
|
361
|
-
assertIncludes(block, 'ref:', 'Should specify a ref for checkout');
|
|
362
|
-
assertIncludes(block, 'github.event.inputs.version', 'Should use input version for ref');
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
// --- Consistency with build.js ---
|
|
366
|
-
console.log('\n--- Consistency with build.js ---\n');
|
|
367
|
-
|
|
368
|
-
test('build-npm.js uses same externals as build.js', () => {
|
|
369
|
-
assertIncludes(buildNpmSource, "'blessed'", 'Should externalize blessed');
|
|
370
|
-
assertIncludes(buildNpmSource, "'abort-controller'", 'Should externalize abort-controller');
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
test('build-npm.js bundles same entry point as build.js', () => {
|
|
374
|
-
assertIncludes(buildNpmSource, "'index.js'", 'Should bundle index.js');
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test('build-npm.js uses PAVE_VERSION define like build.js', () => {
|
|
378
|
-
assertIncludes(buildNpmSource, 'PAVE_VERSION', 'Should define PAVE_VERSION');
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// Results
|
|
382
|
-
console.log('\n' + '='.repeat(60));
|
|
383
|
-
console.log('Results: ' + passed + ' passed, ' + failed + ' failed, ' + total + ' total');
|
|
384
|
-
console.log('='.repeat(60));
|
|
385
|
-
|
|
386
|
-
if (failed > 0) {
|
|
387
|
-
throw new Error(failed + ' test(s) failed in build-npm');
|
|
388
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Test cases for chat command functionality
|
|
4
|
-
* Tests the parameter passing and integration
|
|
5
|
-
* Run with: node test/chat-command.test.js
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { parseArgs } = require('../lib/args-parser');
|
|
9
|
-
|
|
10
|
-
function runTest(name, testFn) {
|
|
11
|
-
try {
|
|
12
|
-
testFn();
|
|
13
|
-
console.log(` ${name}`);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
console.log(`L ${name}: ${error.message}`);
|
|
16
|
-
process.exitCode = 1;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function assertEqual(actual, expected, message) {
|
|
21
|
-
if (actual !== expected) {
|
|
22
|
-
throw new Error(`${message}: expected ${expected}, got ${actual}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Mock the handleChatCommand function to test parameter extraction
|
|
27
|
-
function mockHandleChatCommand(args) {
|
|
28
|
-
// This simulates the parameter extraction in the actual function
|
|
29
|
-
const { commandArgs, verbose, json, session, noStream, color, model, showTools } = args;
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
commandArgs,
|
|
33
|
-
verbose,
|
|
34
|
-
json,
|
|
35
|
-
session,
|
|
36
|
-
noStream,
|
|
37
|
-
color,
|
|
38
|
-
model,
|
|
39
|
-
showTools,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Test parameter extraction for default case (showTools defaults to true)
|
|
44
|
-
runTest('handleChatCommand should extract showTools parameter (default true)', () => {
|
|
45
|
-
const args = parseArgs(['chat', 'hello world']);
|
|
46
|
-
const extracted = mockHandleChatCommand(args);
|
|
47
|
-
|
|
48
|
-
assertEqual(extracted.showTools, true, 'showTools should default to true');
|
|
49
|
-
assertEqual(extracted.commandArgs.join(' '), 'hello world', 'commandArgs should be correct');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Test parameter extraction with --no-tools
|
|
53
|
-
runTest('handleChatCommand should extract showTools parameter (explicit false)', () => {
|
|
54
|
-
const args = parseArgs(['chat', '--no-tools', 'hello world']);
|
|
55
|
-
const extracted = mockHandleChatCommand(args);
|
|
56
|
-
|
|
57
|
-
assertEqual(extracted.showTools, false, 'showTools should be false with --no-tools');
|
|
58
|
-
assertEqual(extracted.commandArgs.join(' '), 'hello world', 'commandArgs should exclude flags');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Test with multiple parameters
|
|
62
|
-
runTest('handleChatCommand should extract all parameters correctly', () => {
|
|
63
|
-
const args = parseArgs(['chat', '--no-tools', '--verbose', 'test message']);
|
|
64
|
-
const extracted = mockHandleChatCommand(args);
|
|
65
|
-
|
|
66
|
-
assertEqual(extracted.showTools, false, 'showTools should be false');
|
|
67
|
-
assertEqual(extracted.verbose, true, 'verbose should be true');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Mock the sendMessageAndStream function to test options passing
|
|
71
|
-
function mockSendMessageAndStream(serverUrl, sessionId, message, options = {}) {
|
|
72
|
-
// This simulates the options parameter reception
|
|
73
|
-
return {
|
|
74
|
-
receivedOptions: options,
|
|
75
|
-
success: true,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Test options passing to sendMessageAndStream (default true)
|
|
80
|
-
runTest('sendMessageAndStream should receive showTools option (default true)', () => {
|
|
81
|
-
const args = parseArgs(['chat', 'test message']);
|
|
82
|
-
const extracted = mockHandleChatCommand(args);
|
|
83
|
-
|
|
84
|
-
const options = {
|
|
85
|
-
verbose: extracted.verbose,
|
|
86
|
-
json: extracted.json,
|
|
87
|
-
noStream: extracted.noStream,
|
|
88
|
-
model: extracted.model,
|
|
89
|
-
showTools: extracted.showTools,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const result = mockSendMessageAndStream('http://localhost:4096', 'session123', 'test message', options);
|
|
93
|
-
|
|
94
|
-
assertEqual(result.receivedOptions.showTools, true, 'showTools should be passed as true by default');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Test options passing with --no-tools
|
|
98
|
-
runTest('sendMessageAndStream should receive showTools option (false with --no-tools)', () => {
|
|
99
|
-
const args = parseArgs(['chat', '--no-tools', 'test message']);
|
|
100
|
-
const extracted = mockHandleChatCommand(args);
|
|
101
|
-
|
|
102
|
-
const options = {
|
|
103
|
-
verbose: extracted.verbose,
|
|
104
|
-
json: extracted.json,
|
|
105
|
-
noStream: extracted.noStream,
|
|
106
|
-
model: extracted.model,
|
|
107
|
-
showTools: extracted.showTools,
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const result = mockSendMessageAndStream('http://localhost:4096', 'session123', 'test message', options);
|
|
111
|
-
|
|
112
|
-
assertEqual(result.receivedOptions.showTools, false, 'showTools should be passed as false with --no-tools');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Test real-world command scenarios
|
|
116
|
-
runTest('Real-world scenario: default file listing (shows tool output)', () => {
|
|
117
|
-
const args = parseArgs(['chat', 'list', 'all', 'files', 'in', 'current', 'directory']);
|
|
118
|
-
const extracted = mockHandleChatCommand(args);
|
|
119
|
-
|
|
120
|
-
assertEqual(extracted.showTools, true, 'Should show tool output by default');
|
|
121
|
-
assertEqual(extracted.commandArgs.join(' '), 'list all files in current directory', 'Should preserve full message');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
runTest('Real-world scenario: clean summary only (no tool output)', () => {
|
|
125
|
-
const args = parseArgs(['chat', '--no-tools', 'summarize', 'project', 'structure']);
|
|
126
|
-
const extracted = mockHandleChatCommand(args);
|
|
127
|
-
|
|
128
|
-
assertEqual(extracted.showTools, false, 'Should hide tool output for clean summary');
|
|
129
|
-
assertEqual(extracted.commandArgs.join(' '), 'summarize project structure', 'Should preserve message without flags');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
console.log('\n=� Test Summary:');
|
|
133
|
-
if (process.exitCode === 1) {
|
|
134
|
-
console.log('Some tests failed. Please fix the issues above.');
|
|
135
|
-
} else {
|
|
136
|
-
console.log('All tests passed! <�');
|
|
137
|
-
}
|