Preserve experimental Live app-server workstream

Snapshot the current app-server implementation, shared Live optimizations, generated harness output, and in-progress site work before restoring polling as the primary runtime path.

Prepared with Codex assistance under maintainer direction.
This commit is contained in:
Paul Bakaus
2026-07-15 16:07:34 -07:00
parent ed7a6fbe4e
commit ead6ddabe5
603 changed files with 148852 additions and 7584 deletions
+333 -158
View File
@@ -1,10 +1,10 @@
import fs from 'node:fs';
import path from 'node:path';
import { execFileSync } from 'node:child_process';
import { execFileSync, spawnSync } from 'node:child_process';
import { randomBytes } from 'node:crypto';
import { fileURLToPath } from 'node:url';
import {
selectFastCodexModel,
selectLowestReasoningEffort,
selectQualityCodexModel,
} from './codex-app-server-client.mjs';
@@ -17,9 +17,11 @@ import {
buildCodexWorkerInstructions,
buildCodexWorkerTurnInputs,
buildGenerationTurnInput,
codexWorkerDetectorRepairSchema,
codexWorkerOutputSchemaForPhase,
codexWorkerStateIsOwned,
generationIsCanceled,
isCodexComponentPreviewMode,
prepareCodexWorkerPhase,
publishCodexWorkerPhase,
readPreparedArtifact,
@@ -36,6 +38,7 @@ import { createLiveSessionStore } from './session-store.mjs';
export const CODEX_WORKER_EVENT_TYPES = Object.freeze(['generate', 'accept', 'discard', 'prefetch']);
export const CODEX_WORKER_EVENT_LEASE_MS = 15_000;
const LOCAL_SCRIPTS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
export class CodexLiveWorkerSupervisor {
constructor({
@@ -53,6 +56,7 @@ export class CodexLiveWorkerSupervisor {
publishCheckpoint = postVariantCheckpoint,
publishPhase = postAgentPhase,
postCleanup = postCarbonizeCleanup,
detectCandidate = detectPreparedArtifact,
sessionStore = null,
log = () => {},
}) {
@@ -70,6 +74,7 @@ export class CodexLiveWorkerSupervisor {
this.publishCheckpoint = publishCheckpoint;
this.publishPhase = publishPhase;
this.postCleanup = postCleanup;
this.detectCandidate = detectCandidate;
this.sessionStore = sessionStore || createLiveSessionStore({ cwd: this.cwd });
this.log = log;
this.running = false;
@@ -84,10 +89,11 @@ export class CodexLiveWorkerSupervisor {
this.threadReady = Promise.resolve(null);
this.model = null;
this.liveSpec = '';
this.threadPrimed = false;
}
async initialize() {
this.liveSpec = readOptional(path.join(this.scriptsDir, '..', 'reference', 'live.md'));
this.liveSpec = readOptional(path.join(this.scriptsDir, '..', 'reference', 'live-generation.md'));
await this.client.connect();
const models = await this.client.listModels();
this.model = this.config.model
@@ -107,6 +113,7 @@ export class CodexLiveWorkerSupervisor {
sandbox: 'read-only',
baseInstructions: buildCodexWorkerInstructions(this.liveSpec),
});
this.threadPrimed = prior.threadPrimed === true;
} catch (error) {
this.log(`resume failed; creating replacement worker thread: ${error.message}`);
}
@@ -212,19 +219,22 @@ export class CodexLiveWorkerSupervisor {
const snapshot = this.sessionStore.getSnapshot(event.id, { includeCompleted: true });
const sameEpoch = Number(snapshot?.generationEpoch || 1) === Number(event.generationEpoch || 1);
let arrivedVariants = sameEpoch ? Number(snapshot?.arrivedVariants || 0) : 0;
let completedRemainder = false;
if (this.config.delivery === 'progressive' && expectedVariants > 1) {
if (arrivedVariants < 1) {
await this.runGenerationPhase(event, 'first', 1);
arrivedVariants = 1;
}
if (this.isCanceled(event.id)) return;
if (expectedVariants > 2 && arrivedVariants < 2) {
await this.runGenerationPhase(event, 'second', 2);
arrivedVariants = 2;
if (arrivedVariants < expectedVariants) {
await this.runGenerationPhase(event, 'remainder', expectedVariants);
arrivedVariants = expectedVariants;
completedRemainder = true;
}
if (this.isCanceled(event.id)) return;
if (arrivedVariants < expectedVariants) {
await this.runGenerationPhase(event, 'final', expectedVariants);
const latest = this.sessionStore.getSnapshot(event.id, { includeCompleted: true });
if (!completedRemainder && arrivedVariants >= expectedVariants && latest?.paramsPublished !== true) {
await this.runGenerationPhase(event, 'params', expectedVariants);
}
} else if (arrivedVariants < expectedVariants) {
await this.runGenerationPhase(event, 'atomic', expectedVariants);
@@ -245,6 +255,7 @@ export class CodexLiveWorkerSupervisor {
}
startWorkerThread() {
this.threadPrimed = false;
return this.client.startDedicatedThread({
model: this.model.model || this.model.id,
cwd: this.cwd,
@@ -311,7 +322,9 @@ export class CodexLiveWorkerSupervisor {
cwd: this.cwd,
maxBytes: this.config.maxArtifactBytes,
});
const contexts = readGenerationContexts(this.cwd, this.scriptsDir, event);
const contexts = readGenerationContexts(this.cwd, this.scriptsDir, event, {
includeStable: !this.threadPrimed,
});
const prompt = buildGenerationTurnInput({
event,
phase,
@@ -322,108 +335,146 @@ export class CodexLiveWorkerSupervisor {
});
const input = buildCodexWorkerTurnInputs({
prompt,
skillPath: resolveCodexWorkerSkillPath(this.scriptsDir),
skillPath: this.threadPrimed ? null : resolveCodexWorkerSkillPath(this.scriptsDir),
screenshotPath: event.screenshotPath,
cwd: this.cwd,
});
let publishedFromMessage = false;
let publicationPromise = null;
let earlyCandidateError = null;
let durableCandidate = null;
const publishCandidate = async (answer) => {
if (publishedFromMessage || this.isCanceled(event.id)) return;
if (!publicationPromise) {
publicationPromise = (async () => {
await this.publishPhase(this.base, this.token, {
eventId: event.id,
phase: generationPhaseName(phase, 'validating'),
durationMs: Date.now() - phaseStartedAt,
});
if (!durableCandidate) {
const candidatePath = path.resolve(this.cwd, prepared.artifactFile);
if (!prepared.previewMode && (phase === 'first' || phase === 'second' || phase === 'final')) {
// A structured agent message and the final turn result can contain
// the same delta. Always apply against the immutable phase input so
// a failed publication/checkpoint retry cannot double-insert it.
fs.writeFileSync(candidatePath, artifact.content, 'utf-8');
}
const applied = applyCodexWorkerOutput({
output: answer,
prepared,
phase,
expectedVariants: Number(event.count || arrivedVariants),
sessionId: event.id,
scaffold: event.scaffold,
cwd: this.cwd,
maxBytes: this.config.maxArtifactBytes,
});
if (!prepared.previewMode && !applied.sourceDelta && (phase === 'second' || phase === 'final')) {
const reconciled = reconcilePublishedSourceVariants({
current: artifact.content,
candidate: fs.readFileSync(candidatePath, 'utf-8'),
priorArrived: Math.max(1, arrivedVariants - 1),
});
if (!reconciled.ok) throw supervisorError(`reconcile_${reconciled.error}`);
fs.writeFileSync(candidatePath, reconciled.content, 'utf-8');
}
if (this.isCanceled(event.id)) return;
const published = publishCodexWorkerPhase({ event, prepared, arrivedVariants, cwd: this.cwd });
durableCandidate = { applied, published, planRecorded: false };
}
if (durableCandidate.applied.plan && !durableCandidate.planRecorded) {
this.sessionStore.appendEvent({
type: 'variant_plan',
id: event.id,
plan: durableCandidate.applied.plan,
});
durableCandidate.planRecorded = true;
}
if (this.isCanceled(event.id)) return;
await this.publishCheckpoint(this.base, this.token, {
event,
published: durableCandidate.published,
scaffold: event.scaffold,
arrivedVariants,
});
publishedFromMessage = true;
})();
}
const pendingPublication = publicationPromise;
try {
await pendingPublication;
} catch (error) {
if (!earlyCandidateError) earlyCandidateError = error;
} finally {
if (publicationPromise === pendingPublication) publicationPromise = null;
}
};
if (this.isCanceled(event.id)) return;
const result = await this.runTurnWithReconnect({
const outputSchema = codexWorkerOutputSchemaForPhase(
phase,
Number(event.count || arrivedVariants),
{ sourceDelta: (phase === 'first' || phase === 'remainder' || phase === 'params') && !isCodexComponentPreviewMode(prepared.previewMode) },
);
let result = await this.runTurnWithReconnect({
input,
outputSchema: codexWorkerOutputSchemaForPhase(
phase,
Number(event.count || arrivedVariants),
{ sourceDelta: (phase === 'first' || phase === 'second' || phase === 'final') && !prepared.previewMode },
),
onAgentMessage: publishCandidate,
outputSchema,
eventId: event.id,
effort: phase === 'params' ? 'low' : undefined,
});
this.threadPrimed = true;
this.writeState('working', { eventId: event.id });
if (this.isCanceled(event.id)) return;
if (!publishedFromMessage) await publishCandidate(result.answer);
if (!publishedFromMessage) throw earlyCandidateError || supervisorError('worker_output_not_published');
await this.publishPhase(this.base, this.token, {
eventId: event.id,
phase: generationPhaseName(phase, 'validating'),
durationMs: Date.now() - phaseStartedAt,
});
const baselineFindings = this.detectCandidate(prepared, {
cwd: this.cwd,
scriptsDir: this.scriptsDir,
});
let applied;
let newFindings;
let acceptedDetectorWaivers = [];
for (let repairAttempt = 0; repairAttempt <= 1; repairAttempt += 1) {
restorePreparedArtifact(prepared, artifact, { cwd: this.cwd });
applied = applyCodexWorkerOutput({
output: result.answer,
prepared,
phase,
expectedVariants: Number(event.count || arrivedVariants),
sessionId: event.id,
scaffold: event.scaffold,
cwd: this.cwd,
maxBytes: this.config.maxArtifactBytes,
});
reconcileCandidateIfNeeded({
applied,
artifact,
prepared,
phase,
arrivedVariants,
cwd: this.cwd,
});
newFindings = diffDetectorFindings(
baselineFindings,
this.detectCandidate(prepared, { cwd: this.cwd, scriptsDir: this.scriptsDir }),
);
const waiverResolution = resolveDetectorFindingWaivers(
newFindings,
extractDetectorWaivers(result.answer),
);
newFindings = waiverResolution.unresolved;
acceptedDetectorWaivers = waiverResolution.accepted;
if (newFindings.length === 0) break;
if (repairAttempt === 1) {
const error = supervisorError('worker_output_detector_findings');
error.findings = newFindings;
throw error;
}
restorePreparedArtifact(prepared, artifact, { cwd: this.cwd });
result = await this.runTurnWithReconnect({
input: buildCodexWorkerTurnInputs({
prompt: buildDetectorRepairPrompt(phase, newFindings),
cwd: this.cwd,
}),
outputSchema: codexWorkerDetectorRepairSchema(outputSchema),
eventId: event.id,
});
if (this.isCanceled(event.id)) return;
}
if (applied.plan) {
this.sessionStore.appendEvent({
type: 'variant_plan',
id: event.id,
plan: applied.plan,
});
}
if (acceptedDetectorWaivers.length > 0) {
this.sessionStore.appendEvent({
type: 'detector_waivers',
id: event.id,
phase,
waivers: acceptedDetectorWaivers.map(({ waiver }) => waiver),
});
}
if (this.isCanceled(event.id)) return;
const published = publishCodexWorkerPhase({ event, prepared, arrivedVariants, phase, cwd: this.cwd });
let checkpointError;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
await this.publishCheckpoint(this.base, this.token, {
event,
published,
scaffold: event.scaffold,
arrivedVariants,
});
checkpointError = null;
break;
} catch (error) {
checkpointError = error;
}
}
if (checkpointError) throw checkpointError;
if (['remainder', 'params', 'atomic'].includes(phase)) {
await this.publishPhase(this.base, this.token, {
eventId: event.id,
phase: 'parameters_ready',
durationMs: Date.now() - phaseStartedAt,
});
}
}
async runTurnWithReconnect({ input, outputSchema, onAgentMessage, eventId = this.active?.eventId }) {
async runTurnWithReconnect({
input,
outputSchema,
onAgentMessage,
eventId = this.active?.eventId,
effort,
}) {
let firstError;
for (let attempt = 0; attempt < 2; attempt += 1) {
try {
const threadId = this.thread.id;
if (this.active?.eventId === eventId) this.active.threadId = threadId;
const turn = await this.client.startTurn({
threadId,
input,
cwd: this.cwd,
model: this.model.model || this.model.id,
effort: preferredEffort(this.model, this.config.effort),
effort: preferredEffort(this.model, effort || this.config.effort),
summary: 'none',
approvalPolicy: 'never',
sandboxPolicy: { type: 'readOnly' },
@@ -449,17 +500,26 @@ export class CodexLiveWorkerSupervisor {
}
async reconnect() {
this.thread = await this.client.reconnect({
threadId: this.thread.id,
this.thread = await this.reconnectThread(this.thread, this.model);
this.writeState('ready', { reconnectedAt: new Date().toISOString() });
}
async reconnectThread(thread, model = this.model) {
const resumed = await this.client.reconnect({
threadId: thread.id,
resumeParams: {
model: this.model.model || this.model.id,
model: model.model || model.id,
cwd: this.cwd,
approvalPolicy: 'never',
sandbox: 'read-only',
baseInstructions: buildCodexWorkerInstructions(this.liveSpec),
},
});
this.writeState('ready', { reconnectedAt: new Date().toISOString() });
if (thread === this.thread) {
this.thread = resumed;
this.writeState('ready', { reconnectedAt: new Date().toISOString() });
}
return resumed;
}
async cancelActive(reason, eventId = null) {
@@ -547,6 +607,7 @@ export class CodexLiveWorkerSupervisor {
effort: this.model ? preferredEffort(this.model, this.config.effort) : this.config.effort,
profile: this.config.profile,
delivery: this.config.delivery,
threadPrimed: this.threadPrimed,
eventId: this.active?.eventId || null,
};
}
@@ -565,7 +626,7 @@ export class CodexLiveWorkerSupervisor {
function generationPhaseName(phase, state) {
if (phase === 'first') return `first_variant_${state}`;
if (phase === 'second') return `second_variant_${state}`;
if (phase === 'params') return `variant_parameters_${state}`;
return `remaining_variants_${state}`;
}
@@ -591,6 +652,7 @@ export async function postVariantCheckpoint(base, token, {
type: 'checkpoint',
id: event.id,
revision: published.revision,
revisionDomain: 'publication',
phase: 'cycling',
reason: 'variants_progress',
arrivedVariants,
@@ -598,6 +660,7 @@ export async function postVariantCheckpoint(base, token, {
sourceFile: scaffold.sourceFile || scaffold.file,
previewFile: scaffold.file,
previewMode: scaffold.previewMode || 'source',
publicationKind: published.publicationKind || 'variants',
}),
});
if (!response.ok) throw supervisorError(`checkpoint_${response.status}`);
@@ -652,6 +715,7 @@ export function buildDeterministicScaffoldCommand(event, scriptsDir) {
const script = path.join(scriptsDir, insert ? 'live-insert.mjs' : 'live-wrap.mjs');
const args = ['--id', String(event.id), '--count', String(event.count || 3)];
const target = insert ? event.insert?.anchor || {} : event.element || {};
if (!insert) args.push('--isolated');
if (insert) args.push('--position', String(event.insert?.position || 'after'));
if (target.id) args.push('--element-id', String(target.id));
const classes = Array.isArray(target.classes) ? target.classes.join(',') : target.className;
@@ -687,84 +751,195 @@ export function runDeterministicScaffold(event, {
return scaffold;
}
function readGenerationContexts(cwd, scriptsDir, event) {
function restorePreparedArtifact(prepared, artifact, { cwd }) {
if (!isCodexComponentPreviewMode(prepared.previewMode)) {
fs.writeFileSync(path.resolve(cwd, prepared.artifactFile), artifact.content, 'utf-8');
return;
}
const componentDir = path.resolve(cwd, prepared.componentDir);
fs.mkdirSync(componentDir, { recursive: true });
for (const name of fs.readdirSync(componentDir)) {
if (/^(?:v\d+\.(?:svelte|vue)|params\.json)$/.test(name)) {
fs.unlinkSync(path.join(componentDir, name));
}
}
for (const [name, content] of Object.entries(artifact.files || {})) {
fs.writeFileSync(path.join(componentDir, name), content, 'utf-8');
}
fs.writeFileSync(
path.resolve(cwd, prepared.artifactFile),
JSON.stringify(artifact.manifest, null, 2) + '\n',
'utf-8',
);
}
function reconcileCandidateIfNeeded({ applied, artifact, prepared, phase, arrivedVariants, cwd }) {
if (isCodexComponentPreviewMode(prepared.previewMode) || applied.sourceDelta || phase !== 'remainder') return;
const candidatePath = path.resolve(cwd, prepared.artifactFile);
const reconciled = reconcilePublishedSourceVariants({
current: artifact.content,
candidate: fs.readFileSync(candidatePath, 'utf-8'),
priorArrived: Math.max(1, arrivedVariants - 1),
});
if (!reconciled.ok) throw supervisorError(`reconcile_${reconciled.error}`);
fs.writeFileSync(candidatePath, reconciled.content, 'utf-8');
}
export function detectPreparedArtifact(prepared, {
cwd = process.cwd(),
scriptsDir = LOCAL_SCRIPTS_DIR,
spawn = spawnSync,
} = {}) {
const targets = detectorTargets(prepared, cwd);
if (targets.length === 0) return [];
const detectorScript = [
path.join(scriptsDir, 'detect.mjs'),
path.join(LOCAL_SCRIPTS_DIR, 'detect.mjs'),
].find((candidate) => fs.existsSync(candidate));
if (!detectorScript) throw supervisorError('codex_worker_detector_unavailable');
const result = spawn(process.execPath, [detectorScript, '--json', ...targets], {
cwd,
encoding: 'utf-8',
maxBuffer: 8 * 1024 * 1024,
});
if (result.error) throw supervisorError(`codex_worker_detector_failed:${result.error.message}`);
try {
const findings = JSON.parse(String(result.stdout || '[]'));
if (!Array.isArray(findings)) throw new Error('expected findings array');
return findings;
} catch (error) {
throw supervisorError(`codex_worker_detector_invalid:${error.message}`);
}
}
function detectorTargets(prepared, cwd) {
if (!isCodexComponentPreviewMode(prepared.previewMode)) {
return [path.resolve(cwd, prepared.artifactFile)];
}
const componentDir = path.resolve(cwd, prepared.componentDir);
try {
return fs.readdirSync(componentDir)
.filter((name) => /\.(?:vue|svelte)$/.test(name))
.map((name) => path.join(componentDir, name));
} catch {
return [];
}
}
export function diffDetectorFindings(before, after) {
const remaining = new Map();
for (const finding of before || []) {
const key = detectorFindingKey(finding);
remaining.set(key, (remaining.get(key) || 0) + 1);
}
const added = [];
for (const finding of after || []) {
const key = detectorFindingKey(finding);
const count = remaining.get(key) || 0;
if (count > 0) remaining.set(key, count - 1);
else added.push(finding);
}
return added;
}
function detectorFindingKey(finding) {
return [
path.basename(String(finding?.file || '')),
finding?.antipattern || finding?.id || '',
finding?.snippet || '',
finding?.ignoreValue || '',
].join('\u0000');
}
export function buildDetectorRepairPrompt(phase, findings) {
return [
`The candidate for Live phase ${phase} has new Impeccable detector findings.`,
'Use design judgment on every finding. Fix real defects. If a finding is contextually intentional or a detector false positive, leave that design intact and add one narrow detectorWaivers entry copied from the finding with a concrete reason. Return detectorWaivers as an empty array when every finding was fixed. Every finding must either disappear on the next scan or match an explicit waiver; unresolved findings still block publication.',
'Return the complete replacement JSON for the same phase and schema. Do not explain, call tools, persist project detector config, add inline ignore comments, or alter immutable variants.',
'<detector_findings>',
JSON.stringify((findings || []).slice(0, 40).map((finding) => ({
rule: finding.antipattern || finding.id,
name: finding.name,
description: finding.description,
severity: finding.severity,
snippet: finding.snippet,
file: path.basename(String(finding.file || '')),
ignoreValue: finding.ignoreValue || '',
})), null, 2),
'</detector_findings>',
].join('\n');
}
export function resolveDetectorFindingWaivers(findings, waivers) {
const candidates = (Array.isArray(waivers) ? waivers : [])
.map(normalizeDetectorWaiver)
.filter(Boolean);
const accepted = [];
const unresolved = [];
for (const finding of findings || []) {
const waiver = candidates.find((candidate) => detectorWaiverMatches(candidate, finding));
if (waiver) accepted.push({ finding, waiver });
else unresolved.push(finding);
}
return { accepted, unresolved };
}
function extractDetectorWaivers(output) {
try {
const parsed = typeof output === 'string' ? JSON.parse(output) : output;
return Array.isArray(parsed?.detectorWaivers) ? parsed.detectorWaivers : [];
} catch {
return [];
}
}
function normalizeDetectorWaiver(waiver) {
if (!waiver || typeof waiver !== 'object') return null;
const normalized = {
rule: String(waiver.rule || '').trim().toLowerCase(),
file: path.basename(String(waiver.file || '').trim()),
snippet: String(waiver.snippet || '').trim(),
ignoreValue: String(waiver.ignoreValue || '').trim(),
reason: String(waiver.reason || '').trim(),
};
return normalized.rule && normalized.reason && (normalized.snippet || normalized.ignoreValue)
? normalized
: null;
}
function detectorWaiverMatches(waiver, finding) {
const rule = String(finding?.antipattern || finding?.id || '').trim().toLowerCase();
const file = path.basename(String(finding?.file || '').trim());
const snippet = String(finding?.snippet || '').trim();
const ignoreValue = String(finding?.ignoreValue || '').trim();
if (waiver.rule !== rule) return false;
if (waiver.file && waiver.file !== file) return false;
if (waiver.ignoreValue) return waiver.ignoreValue === ignoreValue;
return Boolean(waiver.snippet && waiver.snippet === snippet);
}
function readGenerationContexts(cwd, scriptsDir, event, { includeStable = true } = {}) {
const context = loadContext(cwd);
const action = event?.action;
const safeAction = typeof action === 'string' && /^[a-z-]+$/.test(action) && action !== 'impeccable'
? action
: null;
return {
product: context.product || '',
design: context.design || '',
product: includeStable ? context.product || '' : '',
design: includeStable ? context.design || '' : '',
actionReference: safeAction
? readOptional(path.join(scriptsDir, '..', 'reference', `${safeAction}.md`))
: '',
contextMetadata: {
contextMetadata: includeStable ? {
productPath: context.productPath,
designPath: context.designPath,
projectRoot: context.projectRoot,
repoRoot: context.repoRoot,
isMonorepo: context.isMonorepo,
},
sourceNeighborhood: readSourceNeighborhood(cwd, context.projectRoot, event?.scaffold?.sourceFile || event?.scaffold?.file),
} : {},
};
}
function readSourceNeighborhood(cwd, projectRoot, sourceFile) {
const roots = [projectRoot, cwd].filter(Boolean).map((value) => path.resolve(value));
const result = {};
let totalBytes = 0;
const maxBytes = 180_000;
const candidateNames = [
sourceFile,
'package.json',
'src/styles.css',
'src/index.css',
'src/globals.css',
'app/globals.css',
'styles/globals.css',
'tailwind.config.js',
'tailwind.config.ts',
].filter(Boolean);
if (sourceFile) {
for (const root of roots) {
const source = readOptional(path.join(root, sourceFile));
for (const specifier of localImportSpecifiers(source)) {
const base = path.join(path.dirname(sourceFile), specifier);
for (const suffix of ['', '.js', '.jsx', '.ts', '.tsx', '.css', '/index.js', '/index.jsx', '/index.ts', '/index.tsx']) {
const candidate = `${base}${suffix}`.split(path.sep).join('/');
if (fs.existsSync(path.join(root, candidate))) {
candidateNames.push(candidate);
break;
}
}
}
}
}
for (const root of roots) {
for (const name of candidateNames) {
if (Object.hasOwn(result, name)) continue;
const file = path.join(root, name);
const body = readOptional(file);
if (!body) continue;
const bytes = Buffer.byteLength(body);
if (totalBytes + bytes > maxBytes) continue;
result[name] = body;
totalBytes += bytes;
}
}
return result;
}
function localImportSpecifiers(source) {
if (!source) return [];
const imports = [];
const pattern = /(?:from\s*|import\s*)["'](\.{1,2}\/[^"']+)["']/g;
let match;
while ((match = pattern.exec(source))) imports.push(match[1]);
return [...new Set(imports)];
}
function readOptional(file) {
try { return fs.readFileSync(file, 'utf-8'); } catch { return ''; }
}