Layout: - scripts/ holds the four build scripts plus the new clean.sh - cmake/ holds mingw64-toolchain.cmake - the scripts default to build/linux, build/macos, build/windows, build/harness - docs/ holds the audit documents, with the round 1 task list archived Cleanup: - scripts/clean.sh removes generated output, with --dry-run, --staging, --legacy and --all, and refuses tracked, protected or outside paths - the Windows VST3 manifest now comes from cmake/moduleinfo.json.in, so its version, vendor and class IDs follow cmake/Plugin.cmake instead of a hand-written heredoc that could drift - deleted the unused Source/GUI/Slider, which no code constructed - fixed the hidden double processBlock overload: three warning lines to zero - unslopped the build scripts, the two .cjs helpers and the CMake comments - .gitignore covers the upstream JUCE Projucer and DemoRunner binaries Verified: five scripts pass bash -n; the harness passes CTest with zero warning lines; the Linux VST3 and Standalone link; the Windows cross-build passes its x86-64, runtime-import and entry-point checks; each configure exposes only its own targets; and a full build leaves Source/ and third_party/JUCE unchanged. The generated manifest is identical to the previous hand-written one.
68 lines
2.6 KiB
JavaScript
Executable File
68 lines
2.6 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const { pathToFileURL } = require('url');
|
|
const { execFileSync } = require('child_process');
|
|
const dir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
const BAKED = "/usr/lib/node_modules/@nanonets/graft/dist/claude";
|
|
|
|
// dist/claude inside @nanonets/graft, resolved from a directory npm searches.
|
|
function fromPkg(base) {
|
|
try {
|
|
const pkg = require.resolve('@nanonets/graft/package.json', { paths: [base] });
|
|
return path.join(path.dirname(pkg), 'dist', 'claude');
|
|
} catch { return null; }
|
|
}
|
|
|
|
// The global node_modules directory, as npm reports it. Queried only when needed.
|
|
function globalRoot() {
|
|
try {
|
|
const root = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], shell: process.platform === 'win32' }).trim();
|
|
return root || null;
|
|
} catch { return null; /* npm unavailable */ }
|
|
}
|
|
|
|
// The version of the package that owns a dist/claude directory, or null.
|
|
function versionOf(distClaude) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(path.join(distClaude, '..', '..', 'package.json'), 'utf8')).version || null;
|
|
} catch { return null; }
|
|
}
|
|
|
|
// Compares dotted version numbers. An unreadable version counts as older.
|
|
function newer(a, b) {
|
|
if (!a) return false;
|
|
if (!b) return true;
|
|
const p = (v) => String(v).split('-')[0].split('.').map((n) => Number(n) || 0);
|
|
const pa = p(a), pb = p(b);
|
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
const d = (pa[i] || 0) - (pb[i] || 0);
|
|
if (d !== 0) return d > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// The highest-versioned entry in `dirs` that contains `name`, or null.
|
|
function best(dirs, name) {
|
|
let bestDir = null, bestVer = null;
|
|
for (const d of dirs) {
|
|
if (!d || !fs.existsSync(path.join(d, name))) continue;
|
|
const v = versionOf(d);
|
|
if (bestDir === null || newer(v, bestVer)) { bestDir = d; bestVer = v; }
|
|
}
|
|
return bestDir;
|
|
}
|
|
|
|
function entry(name) {
|
|
// Check the cheap candidates first, and run npm only if none of them match.
|
|
const cheap = [BAKED, fromPkg(dir), fromPkg(path.join(path.dirname(process.execPath), '..', 'lib'))];
|
|
const hit = best(cheap, name);
|
|
if (hit) return path.join(hit, name);
|
|
const gr = globalRoot();
|
|
const global = gr && path.join(gr, '@nanonets', 'graft', 'dist', 'claude');
|
|
if (global && fs.existsSync(path.join(global, name))) return path.join(global, name);
|
|
return path.join(dir, 'dist', 'claude', name); // fallback; the import does nothing when the file is absent
|
|
}
|
|
|
|
import(pathToFileURL(entry("statusline.js")).href).then((m) => m.main()).catch(() => { /* graft is unavailable: do nothing */ });
|