mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-03 11:05:35 +08:00
feat(refactor): move plugins to typescript (#557)
* feat(refactor): move plugins to typescript * chore: add timeout to plugin build function
This commit is contained in:
Submodule plugins/starter updated: bfa6332810...4895cd3fd3
@@ -93,6 +93,55 @@ export function validateManifest(manifest) {
|
|||||||
return { valid: true };
|
return { valid: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BUILD_TIMEOUT_MS = 60_000;
|
||||||
|
|
||||||
|
/** Run `npm run build` if the plugin's package.json declares a build script. */
|
||||||
|
function runBuildIfNeeded(dir, packageJsonPath, onSuccess, onError) {
|
||||||
|
try {
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||||
|
if (!pkg.scripts?.build) {
|
||||||
|
return onSuccess();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return onSuccess(); // Unreadable package.json — skip build
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildProcess = spawn('npm', ['run', 'build'], {
|
||||||
|
cwd: dir,
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
});
|
||||||
|
|
||||||
|
let stderr = '';
|
||||||
|
let settled = false;
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
buildProcess.removeAllListeners();
|
||||||
|
buildProcess.kill();
|
||||||
|
onError(new Error('npm run build timed out'));
|
||||||
|
}, BUILD_TIMEOUT_MS);
|
||||||
|
|
||||||
|
buildProcess.stderr.on('data', (data) => { stderr += data.toString(); });
|
||||||
|
|
||||||
|
buildProcess.on('close', (code) => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
if (code !== 0) {
|
||||||
|
return onError(new Error(`npm run build failed (exit code ${code}): ${stderr.trim()}`));
|
||||||
|
}
|
||||||
|
onSuccess();
|
||||||
|
});
|
||||||
|
|
||||||
|
buildProcess.on('error', (err) => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
onError(new Error(`Failed to spawn build: ${err.message}`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function scanPlugins() {
|
export function scanPlugins() {
|
||||||
const pluginsDir = getPluginsDir();
|
const pluginsDir = getPluginsDir();
|
||||||
const config = getPluginsConfig();
|
const config = getPluginsConfig();
|
||||||
@@ -289,7 +338,7 @@ export function installPluginFromGit(url) {
|
|||||||
// --ignore-scripts prevents postinstall hooks from executing arbitrary code.
|
// --ignore-scripts prevents postinstall hooks from executing arbitrary code.
|
||||||
const packageJsonPath = path.join(tempDir, 'package.json');
|
const packageJsonPath = path.join(tempDir, 'package.json');
|
||||||
if (fs.existsSync(packageJsonPath)) {
|
if (fs.existsSync(packageJsonPath)) {
|
||||||
const npmProcess = spawn('npm', ['install', '--production', '--ignore-scripts'], {
|
const npmProcess = spawn('npm', ['install', '--ignore-scripts'], {
|
||||||
cwd: tempDir,
|
cwd: tempDir,
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
});
|
});
|
||||||
@@ -299,7 +348,7 @@ export function installPluginFromGit(url) {
|
|||||||
cleanupTemp();
|
cleanupTemp();
|
||||||
return reject(new Error(`npm install for ${repoName} failed (exit code ${npmCode})`));
|
return reject(new Error(`npm install for ${repoName} failed (exit code ${npmCode})`));
|
||||||
}
|
}
|
||||||
finalize(manifest);
|
runBuildIfNeeded(tempDir, packageJsonPath, () => finalize(manifest), (err) => { cleanupTemp(); reject(err); });
|
||||||
});
|
});
|
||||||
|
|
||||||
npmProcess.on('error', (err) => {
|
npmProcess.on('error', (err) => {
|
||||||
@@ -356,7 +405,7 @@ export function updatePluginFromGit(name) {
|
|||||||
// Re-run npm install if package.json exists
|
// Re-run npm install if package.json exists
|
||||||
const packageJsonPath = path.join(pluginDir, 'package.json');
|
const packageJsonPath = path.join(pluginDir, 'package.json');
|
||||||
if (fs.existsSync(packageJsonPath)) {
|
if (fs.existsSync(packageJsonPath)) {
|
||||||
const npmProcess = spawn('npm', ['install', '--production', '--ignore-scripts'], {
|
const npmProcess = spawn('npm', ['install', '--ignore-scripts'], {
|
||||||
cwd: pluginDir,
|
cwd: pluginDir,
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
});
|
});
|
||||||
@@ -364,7 +413,7 @@ export function updatePluginFromGit(name) {
|
|||||||
if (npmCode !== 0) {
|
if (npmCode !== 0) {
|
||||||
return reject(new Error(`npm install for ${name} failed (exit code ${npmCode})`));
|
return reject(new Error(`npm install for ${name} failed (exit code ${npmCode})`));
|
||||||
}
|
}
|
||||||
resolve(manifest);
|
runBuildIfNeeded(pluginDir, packageJsonPath, () => resolve(manifest), (err) => reject(err));
|
||||||
});
|
});
|
||||||
npmProcess.on('error', (err) => reject(err));
|
npmProcess.on('error', (err) => reject(err));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user