mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-17 23:28:04 +02:00
Addresses Greptile's review on #2994: - missing-dependency.js no longer hardcodes a second copy of the four runtime dependency versions; it reads them from package.json's dependencies field instead, so the two can't silently drift apart. describeMissingDependencyError() still recognizes a tracked dependency even if package.json can't be read for some reason, just without a version-pinned install command in that case. - The regression test now asserts no ancestor directory of its temp fixture has a node_modules, so a stray one wouldn't let Node resolve ajv/sql.js from there and mask what the test is actually meant to exercise. Also copies package.json into the fixture, matching a real plugin-marketplace git clone and what the version-lookup above now needs.
66 lines
2.3 KiB
JavaScript
66 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Runtime dependencies that can be missing when ECC is installed via the
|
|
// Claude Code plugin marketplace (a plain git clone, so `npm install` never
|
|
// runs), even though the code that needs them is fine. Versions are read
|
|
// straight from package.json's "dependencies" field instead of a second
|
|
// hardcoded copy, so this can't silently drift out of sync with what's
|
|
// actually declared there.
|
|
const TRACKED_DEPENDENCIES = ['ajv', 'sql.js', 'js-yaml', '@iarna/toml'];
|
|
|
|
function loadRuntimeDependencyVersions() {
|
|
try {
|
|
const packageJsonPath = path.join(__dirname, '..', '..', 'package.json');
|
|
const declared = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).dependencies || {};
|
|
|
|
const versions = {};
|
|
for (const name of TRACKED_DEPENDENCIES) {
|
|
const declaredVersion = declared[name];
|
|
if (declaredVersion) {
|
|
versions[name] = declaredVersion.replace(/^[\^~]/, '');
|
|
}
|
|
}
|
|
return versions;
|
|
} catch {
|
|
// package.json isn't reachable from here for some reason. Fall back to
|
|
// an empty map rather than crash — describeMissingDependencyError()
|
|
// just won't be able to suggest a pinned version in that case.
|
|
return {};
|
|
}
|
|
}
|
|
|
|
const RUNTIME_DEPENDENCY_VERSIONS = loadRuntimeDependencyVersions();
|
|
|
|
function describeMissingDependencyError(error) {
|
|
if (!error || error.code !== 'MODULE_NOT_FOUND') {
|
|
return null;
|
|
}
|
|
|
|
const match = /Cannot find module '([^']+)'/.exec(error.message || '');
|
|
const moduleName = match && match[1];
|
|
|
|
if (!moduleName || !TRACKED_DEPENDENCIES.includes(moduleName)) {
|
|
return null;
|
|
}
|
|
|
|
const pinnedVersion = RUNTIME_DEPENDENCY_VERSIONS[moduleName];
|
|
const installCommand = pinnedVersion
|
|
? `npm install --no-save ${moduleName}@${pinnedVersion}`
|
|
: `npm install --no-save ${moduleName}`;
|
|
|
|
return (
|
|
`Missing dependency '${moduleName}'. ECC's production dependencies aren't installed ` +
|
|
'(this happens when ECC was installed via the Claude Code plugin marketplace, which ' +
|
|
'clones the repo but never runs npm install). Run "npm install" from the ECC repo ' +
|
|
`root, or install just this package with "${installCommand}".`
|
|
);
|
|
}
|
|
|
|
module.exports = {
|
|
RUNTIME_DEPENDENCY_VERSIONS,
|
|
describeMissingDependencyError,
|
|
};
|