mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-17 23:28:04 +02:00
install-plan.js and install-apply.js both require ./lib/install/config at load time, and that module required ajv unconditionally at the top of the file even though ajv is only actually used when validating an ecc-install.json. When ECC is installed via the Claude Code plugin marketplace, the marketplace directory is a bare git clone with no node_modules, so requiring ajv crashes commands like --list-profiles that never touch install-config validation at all. Same root cause in scripts/lib/control-pane/state.js: sql.js and @iarna/toml were required at module scope even though they are only used inside openSqlDatabase() and readTomlConfig(), so control-pane.js --help crashed too. Make both requires lazy so they only load when the feature that actually needs them runs. For the case where ajv/sql.js/js-yaml/@iarna-toml is genuinely needed and still missing, add a small helper that turns the raw MODULE_NOT_FOUND into an actionable message naming the package and the install command, instead of a stack trace (install-apply.js) or, worse, an unhandled crash with a usage banner tacked on that reads like a bad argument (install-plan.js, control-pane.js). Applied the same helper to memory-mcp.mjs, where ajv is genuinely load-bearing (it compiles every MCP tool's JSON schema up front) so it can't be made lazy the same way. Added a regression test that copies just scripts/, schemas/, and manifests/ into a directory with no node_modules anywhere above it in the filesystem, which reproduces the plugin-marketplace install exactly, and asserts install-plan.js and control-pane.js still work.
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
/**
|
|
* Tests for scripts/lib/missing-dependency.js
|
|
*/
|
|
|
|
const assert = require('assert');
|
|
|
|
const { describeMissingDependencyError } = require('../../scripts/lib/missing-dependency');
|
|
|
|
function test(name, fn) {
|
|
try {
|
|
fn();
|
|
console.log(` ✓ ${name}`);
|
|
return true;
|
|
} catch (error) {
|
|
console.log(` ✗ ${name}`);
|
|
console.log(` Error: ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function moduleNotFoundError(moduleName, requireStack) {
|
|
const error = new Error(
|
|
`Cannot find module '${moduleName}'\nRequire stack:\n${requireStack.map(entry => `- ${entry}`).join('\n')}`
|
|
);
|
|
error.code = 'MODULE_NOT_FOUND';
|
|
return error;
|
|
}
|
|
|
|
function runTests() {
|
|
console.log('\n=== Testing missing-dependency.js ===\n');
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
if (test('describes a missing production dependency with an install command', () => {
|
|
const error = moduleNotFoundError('ajv', [
|
|
'scripts/lib/install/config.js',
|
|
'scripts/install-plan.js',
|
|
]);
|
|
const message = describeMissingDependencyError(error);
|
|
assert.ok(message.includes("'ajv'"));
|
|
assert.ok(message.includes('npm install'));
|
|
assert.ok(message.includes('ajv@8.20.0'));
|
|
})) passed++; else failed++;
|
|
|
|
if (test('recognizes every declared production dependency', () => {
|
|
for (const moduleName of ['ajv', 'sql.js', 'js-yaml', '@iarna/toml']) {
|
|
const error = moduleNotFoundError(moduleName, ['some/file.js']);
|
|
assert.ok(describeMissingDependencyError(error), `expected a message for ${moduleName}`);
|
|
}
|
|
})) passed++; else failed++;
|
|
|
|
if (test('returns null for an unrelated MODULE_NOT_FOUND error', () => {
|
|
const error = moduleNotFoundError('./lib/some-local-file', ['scripts/foo.js']);
|
|
assert.strictEqual(describeMissingDependencyError(error), null);
|
|
})) passed++; else failed++;
|
|
|
|
if (test('returns null for a non-MODULE_NOT_FOUND error', () => {
|
|
assert.strictEqual(describeMissingDependencyError(new Error('boom')), null);
|
|
})) passed++; else failed++;
|
|
|
|
if (test('returns null for a falsy error', () => {
|
|
assert.strictEqual(describeMissingDependencyError(null), null);
|
|
})) passed++; else failed++;
|
|
|
|
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
|
|
process.exit(failed > 0 ? 1 : 0);
|
|
}
|
|
|
|
runTests();
|