mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "npm run agent:setup-repo"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
// @ts-check
|
||||
|
||||
import { cpSync, existsSync, lstatSync, readFileSync } from 'node:fs';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { basename, dirname, resolve, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
||||
const nodeModulesPath = resolve(repoRoot, 'node_modules');
|
||||
const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
|
||||
/** @typedef {{ folder: string; reason: string }} Candidate */
|
||||
|
||||
/** @param {string} message */
|
||||
function log(message) {
|
||||
console.info(`[setup-fast] ${message}`);
|
||||
}
|
||||
|
||||
/** @param {string[]} args */
|
||||
function runNpm(args) {
|
||||
log(`Running: npm ${args.join(' ')}`);
|
||||
const result = spawnSync(npmExecutable, args, {
|
||||
cwd: repoRoot,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
if ((result.status ?? 1) !== 0) {
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Candidate[]} candidates
|
||||
* @param {string | undefined} folder
|
||||
* @param {string} reason
|
||||
*/
|
||||
function addCandidate(candidates, folder, reason) {
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
if (candidates.some(candidate => candidate.folder === folder)) {
|
||||
return;
|
||||
}
|
||||
candidates.push({ folder, reason });
|
||||
log(`Candidate found (${reason}): ${folder}`);
|
||||
}
|
||||
|
||||
function detectMainSiblingFolder() {
|
||||
const currentFolderName = basename(repoRoot);
|
||||
if (!currentFolderName.startsWith('xterm.js') || currentFolderName === 'xterm.js') {
|
||||
log(`Current folder is "${currentFolderName}", skipping xterm.js sibling lookup.`);
|
||||
return undefined;
|
||||
}
|
||||
const siblingFolder = resolve(dirname(repoRoot), 'xterm.js');
|
||||
log(`Current folder is "${currentFolderName}", sibling main folder candidate: ${siblingFolder}`);
|
||||
return siblingFolder;
|
||||
}
|
||||
|
||||
function detectWorktreeMainFolder() {
|
||||
const gitPath = resolve(repoRoot, '.git');
|
||||
if (!existsSync(gitPath)) {
|
||||
log('No .git entry found at repo root.');
|
||||
return undefined;
|
||||
}
|
||||
const gitStat = lstatSync(gitPath);
|
||||
if (!gitStat.isFile()) {
|
||||
log('.git is not a file, this repo does not appear to be a worktree checkout.');
|
||||
return undefined;
|
||||
}
|
||||
const gitFileContent = readFileSync(gitPath, 'utf8').trim();
|
||||
const gitDirMatch = /^gitdir:\s*(.+)$/m.exec(gitFileContent);
|
||||
if (!gitDirMatch) {
|
||||
log('Could not parse gitdir from .git file.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const gitDirPath = resolve(repoRoot, gitDirMatch[1].trim());
|
||||
log(`Parsed gitdir from .git file: ${gitDirPath}`);
|
||||
|
||||
const normalizedGitDirPath = gitDirPath.replace(/\\/g, '/');
|
||||
const worktreeMarker = '/.git/worktrees/';
|
||||
const markerIndex = normalizedGitDirPath.indexOf(worktreeMarker);
|
||||
if (markerIndex === -1) {
|
||||
log('gitdir path does not contain /.git/worktrees/, skipping worktree main folder lookup.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const normalizedMainFolder = normalizedGitDirPath.slice(0, markerIndex);
|
||||
const mainFolder = sep === '/' ? normalizedMainFolder : normalizedMainFolder.split('/').join(sep);
|
||||
log(`Worktree main folder candidate: ${mainFolder}`);
|
||||
return mainFolder;
|
||||
}
|
||||
|
||||
function resolveSourceFolder() {
|
||||
/** @type {Candidate[]} */
|
||||
const candidates = [];
|
||||
addCandidate(candidates, detectMainSiblingFolder(), 'xterm.js sibling');
|
||||
addCandidate(candidates, detectWorktreeMainFolder(), 'worktree main repo');
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const candidateNodeModulesPath = resolve(candidate.folder, 'node_modules');
|
||||
if (existsSync(candidateNodeModulesPath)) {
|
||||
log(`Using candidate (${candidate.reason}) with node_modules: ${candidate.folder}`);
|
||||
return candidate.folder;
|
||||
}
|
||||
log(`Candidate skipped (${candidate.reason}), node_modules missing: ${candidateNodeModulesPath}`);
|
||||
}
|
||||
|
||||
log('No candidate folder with node_modules was found.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!existsSync(nodeModulesPath)) {
|
||||
log(`node_modules missing: ${nodeModulesPath}`);
|
||||
const sourceFolder = resolveSourceFolder();
|
||||
if (sourceFolder) {
|
||||
const sourceNodeModulesPath = resolve(sourceFolder, 'node_modules');
|
||||
log(`Copying node_modules from ${sourceNodeModulesPath} to ${nodeModulesPath}`);
|
||||
try {
|
||||
cpSync(sourceNodeModulesPath, nodeModulesPath, { recursive: true });
|
||||
log('node_modules copy completed.');
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
log(`node_modules copy failed: ${message}`);
|
||||
log('Falling back to npm ci.');
|
||||
runNpm(['ci']);
|
||||
}
|
||||
} else {
|
||||
log('No source folder available, running npm ci.');
|
||||
runNpm(['ci']);
|
||||
}
|
||||
} else {
|
||||
log(`node_modules already exists: ${nodeModulesPath}`);
|
||||
}
|
||||
|
||||
runNpm(['run', 'setup']);
|
||||
+2
-1
@@ -72,7 +72,8 @@
|
||||
"prepackage-headless": "npm run esbuild-package-headless-only",
|
||||
"package-headless": "webpack --config ./webpack.config.headless.js",
|
||||
"postpackage-headless": "node ./bin/package_headless.js",
|
||||
"prepublishOnly": "npm run package"
|
||||
"prepublishOnly": "npm run package",
|
||||
"agent:session-start": "node bin/agent/setup-repo.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lunapaint/png-codec": "^0.2.0",
|
||||
|
||||
Reference in New Issue
Block a user