mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 22:26:38 +03:00
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:
@@ -58,6 +58,22 @@ export const CODEX_WORKER_OUTPUT_SCHEMA = Object.freeze({
|
||||
required: ['files'],
|
||||
additionalProperties: false,
|
||||
});
|
||||
const DETECTOR_WAIVER_SCHEMA = Object.freeze({
|
||||
type: 'array',
|
||||
maxItems: 40,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rule: { type: 'string', minLength: 1 },
|
||||
file: { type: 'string' },
|
||||
snippet: { type: 'string' },
|
||||
ignoreValue: { type: 'string' },
|
||||
reason: { type: 'string', minLength: 1, maxLength: 500 },
|
||||
},
|
||||
required: ['rule', 'file', 'snippet', 'ignoreValue', 'reason'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
});
|
||||
export function codexWorkerOutputSchemaForPhase(
|
||||
phase,
|
||||
expectedVariants = 3,
|
||||
@@ -74,35 +90,61 @@ export function codexWorkerOutputSchemaForPhase(
|
||||
};
|
||||
}
|
||||
|
||||
export function codexWorkerDetectorRepairSchema(outputSchema) {
|
||||
return {
|
||||
...outputSchema,
|
||||
properties: {
|
||||
...outputSchema.properties,
|
||||
detectorWaivers: DETECTOR_WAIVER_SCHEMA,
|
||||
},
|
||||
required: [...outputSchema.required, 'detectorWaivers'],
|
||||
};
|
||||
}
|
||||
|
||||
function codexSourceDeltaOutputSchema(phase, requirePlan, expectedVariants) {
|
||||
const variantId = phase === 'first'
|
||||
? 1
|
||||
: phase === 'second'
|
||||
? 2
|
||||
: Number(expectedVariants) > 2 ? 3 : 2;
|
||||
const final = phase === 'final';
|
||||
const sourceDelta = {
|
||||
const variantDelta = (minimum, maximum = minimum) => ({
|
||||
type: 'object',
|
||||
properties: {
|
||||
variantId: { type: 'integer', minimum: variantId, maximum: variantId },
|
||||
variantId: { type: 'integer', minimum, maximum },
|
||||
markup: { type: 'string', minLength: 1 },
|
||||
css: { type: 'string', minLength: 1 },
|
||||
...(final ? {
|
||||
parameterCss: { type: 'string' },
|
||||
paramsJson: { type: 'string', minLength: 2 },
|
||||
} : {}),
|
||||
},
|
||||
required: final
|
||||
? ['variantId', 'markup', 'css', 'parameterCss', 'paramsJson']
|
||||
: ['variantId', 'markup', 'css'],
|
||||
required: ['variantId', 'markup', 'css'],
|
||||
additionalProperties: false,
|
||||
};
|
||||
});
|
||||
let phaseProperties;
|
||||
let phaseRequired;
|
||||
if (phase === 'first') {
|
||||
phaseProperties = { sourceDelta: variantDelta(1) };
|
||||
phaseRequired = ['sourceDelta'];
|
||||
} else if (phase === 'remainder') {
|
||||
phaseProperties = {
|
||||
sourceDeltas: {
|
||||
type: 'array',
|
||||
minItems: Math.max(1, Number(expectedVariants) - 1),
|
||||
maxItems: Math.max(1, Number(expectedVariants) - 1),
|
||||
items: variantDelta(2, Number(expectedVariants)),
|
||||
},
|
||||
parameterCss: { type: 'string' },
|
||||
paramsJson: { type: 'string', minLength: 2 },
|
||||
};
|
||||
phaseRequired = ['sourceDeltas', 'parameterCss', 'paramsJson'];
|
||||
} else if (phase === 'params') {
|
||||
phaseProperties = {
|
||||
parameterCss: { type: 'string' },
|
||||
paramsJson: { type: 'string', minLength: 2 },
|
||||
};
|
||||
phaseRequired = ['parameterCss', 'paramsJson'];
|
||||
} else {
|
||||
phaseProperties = { sourceDelta: variantDelta(Number(expectedVariants)) };
|
||||
phaseRequired = ['sourceDelta'];
|
||||
}
|
||||
return {
|
||||
type: 'object',
|
||||
properties: requirePlan
|
||||
? { sourceDelta, plan: VARIANT_PLAN_SCHEMA }
|
||||
: { sourceDelta },
|
||||
required: requirePlan ? ['sourceDelta', 'plan'] : ['sourceDelta'],
|
||||
? { ...phaseProperties, plan: VARIANT_PLAN_SCHEMA }
|
||||
: phaseProperties,
|
||||
required: requirePlan ? [...phaseRequired, 'plan'] : phaseRequired,
|
||||
additionalProperties: false,
|
||||
};
|
||||
}
|
||||
@@ -203,9 +245,9 @@ export function isCodexRuntime(env = process.env) {
|
||||
export function buildCodexWorkerInstructions(liveSpec) {
|
||||
return [
|
||||
'You are a dedicated Impeccable Live variant producer, never the foreground desktop task.',
|
||||
'The Impeccable skill is attached to generation turns. Its Setup context is already resolved in the user message; do not rerun setup.',
|
||||
'Do not write source or mutate the project. The supervisor supplies bounded project evidence, writes staged artifacts, and publishes transactionally.',
|
||||
'Use read-only tools only when a critical relationship is genuinely missing from the supplied evidence.',
|
||||
'The Impeccable skill is attached on the first turn of this persistent Live thread. Its Setup context is already resolved in the user message; do not rerun setup.',
|
||||
'Do not write source or mutate the project. The supervisor supplies the exact selected source artifact, writes staged artifacts, and publishes transactionally.',
|
||||
'Use read-only repository tools whenever needed to understand imports, shared layouts, styles, tokens, components, or route ownership. Inspect rather than guess; discoveries remain available to later turns in this same thread.',
|
||||
'Return only the JSON object required by the output schema. The supervisor alone writes staged artifacts and publishes them transactionally.',
|
||||
'Preserve existing copy, semantics, public component APIs, accessibility, brand identity, and supplied tokens. Preserve shared-child roles, but recompose the selected element itself when the action calls for a stronger layout or spatial relationship. Do not emit data-impeccable wrappers inside variant content.',
|
||||
'Treat shared-component visual roles as design-system evidence. Preserve their established background, border, radius, and state treatment unless the request explicitly targets that component; do not turn quiet or outlined controls into filled emphasis, inject decorative glyphs or pseudo-content, or change a component role.',
|
||||
@@ -232,15 +274,13 @@ export function buildGenerationTurnInput({
|
||||
design,
|
||||
actionReference,
|
||||
contextMetadata,
|
||||
sourceNeighborhood,
|
||||
}) {
|
||||
const count = Number(event.count || 3);
|
||||
const first = phase === 'first';
|
||||
const second = phase === 'second';
|
||||
const final = phase === 'final';
|
||||
const component = Boolean(prepared.previewMode);
|
||||
const sourceDelta = !component && (first || second || final);
|
||||
const sourceDeltaVariant = first ? 1 : second ? 2 : count > 2 ? 3 : 2;
|
||||
const remainder = phase === 'remainder';
|
||||
const params = phase === 'params';
|
||||
const component = isCodexComponentPreviewMode(prepared.previewMode);
|
||||
const sourceDelta = !component && (first || remainder || params);
|
||||
const actionRules = event.action === 'bolder' && count > 1
|
||||
? [
|
||||
'For /bolder, keep variant 1 low-risk: preserve the selected root’s high-level layout and create impact through controlled hierarchy, proportion, or rhythm. Reserve root recomposition for variant 2 or 3.',
|
||||
@@ -256,37 +296,58 @@ export function buildGenerationTurnInput({
|
||||
`Before authoring, define the shared identity lock and exactly ${count} distinct, meaningful design axes. Return them in plan.directions ordered by variantId so the final phase can complete the same coherent set.`,
|
||||
'Defer tunable parameters: params must be absent or empty for this phase.',
|
||||
]
|
||||
: second
|
||||
: remainder
|
||||
? [
|
||||
'Produce only variant 2 now so it can be reviewed immediately.',
|
||||
`Produce variants 2 through ${count} and the final tunable parameters together so the complete set becomes reviewable in one publication.`,
|
||||
'Variant 1 is already visible and immutable. Do not return or alter its markup or CSS.',
|
||||
'Follow the durable variant plan below and implement direction 2 as an independently shippable option.',
|
||||
'Defer tunable parameters: params must be absent or empty for this phase.',
|
||||
'Follow the durable variant plan below and implement every remaining direction as an independently shippable option.',
|
||||
'Return the parameter manifest and wiring CSS for all variants, including immutable variant 1. Parameters may only expose meaningful axes already present in the designs and must not change any default appearance.',
|
||||
'Parameter schema examples: range = {"id":"scale","kind":"range","label":"Scale","min":0.8,"max":1.2,"step":0.1,"default":1}; steps = {"id":"density","kind":"steps","label":"Density","options":[{"value":"compact","label":"Compact"},{"value":"roomy","label":"Roomy"}]}; toggle = {"id":"accent","kind":"toggle","label":"Accent","default":false}.',
|
||||
'Range wiring sets --p-<id>. Steps and toggles use data-p-<id> on the variant wrapper. Return an empty array for a variant only when no meaningful coarse axis exists.',
|
||||
]
|
||||
: phase === 'final'
|
||||
: params
|
||||
? [
|
||||
`Complete variants ${count > 2 ? 3 : 2} through ${count} and the final parameter manifest.`,
|
||||
`Variants 1 through ${count > 2 ? 2 : 1} are already visible and immutable. Do not return or alter their files, markup, or CSS.`,
|
||||
'Follow the durable variant plan below. Preserve its identity lock and implement each remaining named axis instead of improvising a new set.',
|
||||
`All ${count} variants are already reviewable and immutable. Return only their parameter manifest and parameter wiring CSS.`,
|
||||
'Do not return markup or restyle any default appearance. Parameters may only expose meaningful axes already present in the designs.',
|
||||
'The staged artifact and schema below are complete. Do not call tools or inspect the repository during this phase.',
|
||||
'Parameter schema examples: range = {"id":"scale","kind":"range","label":"Scale","min":0.8,"max":1.2,"step":0.1,"default":1}; steps = {"id":"density","kind":"steps","label":"Density","options":[{"value":"compact","label":"Compact"},{"value":"roomy","label":"Roomy"}]}; toggle = {"id":"accent","kind":"toggle","label":"Accent","default":false}.',
|
||||
'Range wiring sets --p-<id>. Steps and toggles use data-p-<id> on the variant wrapper. Return an empty array for a variant only when no meaningful coarse axis exists.',
|
||||
]
|
||||
: [
|
||||
`Produce the complete set of ${count} variants and final parameters atomically.`,
|
||||
`Before authoring, define the shared identity lock and exactly ${count} distinct, meaningful design axes and return them in plan.directions ordered by variantId.`,
|
||||
];
|
||||
const contextBlocks = [];
|
||||
if (product) contextBlocks.push('<product_context>', String(product), '</product_context>');
|
||||
if (design) contextBlocks.push('<design_context>', String(design), '</design_context>');
|
||||
if (actionReference) contextBlocks.push('<action_reference>', String(actionReference), '</action_reference>');
|
||||
if (contextMetadata && Object.keys(contextMetadata).length > 0) {
|
||||
contextBlocks.push('<context_metadata>', JSON.stringify(contextMetadata, null, 2), '</context_metadata>');
|
||||
}
|
||||
|
||||
return [
|
||||
`LIVE GENERATION PHASE: ${phase}`,
|
||||
...phaseRules,
|
||||
...actionRules,
|
||||
sourceDelta
|
||||
? `Return exactly sourceDelta for variant ${sourceDeltaVariant}${first && count > 1 ? ' plus the complete variant plan' : ''}. markup is only the selected root replacement, without an outer data-impeccable wrapper. css is only the complete fenced base CSS for variant ${sourceDeltaVariant}, following event.scaffold.cssAuthoring.${final ? ` parameterCss contains only deferred tuning rules for variants 1 through ${count}. paramsJson is a JSON-encoded object with exactly the keys ${Array.from({ length: count }, (_, index) => JSON.stringify(String(index + 1))).join(', ')}, each containing an array of 0-4 range, steps, or toggle parameter specs.` : ''}`
|
||||
? first
|
||||
? 'Return exactly sourceDelta for variant 1 plus the complete variant plan. markup is only the selected root replacement, without an outer data-impeccable wrapper. css is only the complete fenced base CSS for variant 1, following event.scaffold.cssAuthoring.'
|
||||
: remainder
|
||||
? `Return exactly sourceDeltas with one entry for each variant 2 through ${count}, ordered by variantId, plus parameterCss and paramsJson. Each markup value is only the selected root replacement; each css value is the complete fenced base CSS for that variant. parameterCss contains tuning rules for variants 1 through ${count}. paramsJson is a JSON-encoded object with exactly the keys ${Array.from({ length: count }, (_, index) => JSON.stringify(String(index + 1))).join(', ')}, each containing an array of 0-4 range, steps, or toggle parameter specs.`
|
||||
: `Return only parameterCss and paramsJson. parameterCss contains deferred tuning rules for variants 1 through ${count}. paramsJson is a JSON-encoded object with exactly the keys ${Array.from({ length: count }, (_, index) => JSON.stringify(String(index + 1))).join(', ')}, each containing an array of 0-4 range, steps, or toggle parameter specs.`
|
||||
: component
|
||||
? `Return staged component files relative to componentDir. Allowed variant extension: .${artifact.componentExtension}. The supervisor updates manifest.json.`
|
||||
? first
|
||||
? `Return only v1.${artifact.componentExtension} relative to componentDir. The supervisor updates manifest.json.`
|
||||
: remainder
|
||||
? `Return exactly v2.${artifact.componentExtension} through v${count}.${artifact.componentExtension} plus params.json relative to componentDir.`
|
||||
: params
|
||||
? 'Return only params.json relative to componentDir, keyed by variant number.'
|
||||
: `Return v1.${artifact.componentExtension} through v${count}.${artifact.componentExtension} plus params.json relative to componentDir.`
|
||||
: `Return exactly one file whose path is ${JSON.stringify(prepared.artifactFile)} and whose content is the complete staged source artifact.`,
|
||||
sourceDelta
|
||||
? `Do not repeat the staged artifact${second || final ? ', prior variants' : ''}, style tags, wrapper comments, or any data-impeccable attributes. The supervisor merges and validates this delta transactionally.${final ? ' parameterCss may target prior variants only to wire explicit data-p-* states or --p-* variables; it must not restyle their default appearance.' : ''}`
|
||||
? `Do not repeat the staged artifact${remainder || params ? ', prior variants' : ''}, style tags, wrapper comments, or any data-impeccable attributes. The supervisor merges and validates this output transactionally.${remainder || params ? ' parameterCss may only wire explicit data-p-* states or --p-* variables; it must not restyle default appearance.' : ''}`
|
||||
: component
|
||||
? 'For the final/atomic phase include params.json keyed by variant number. Never include manifest.json or paths outside componentDir.'
|
||||
? 'Never include manifest.json or paths outside componentDir. Never repeat an immutable variant in a later phase.'
|
||||
: 'Keep the existing session wrapper and markers intact. Add only valid variant blocks and preview CSS inside that wrapper.',
|
||||
'',
|
||||
'<event>',
|
||||
@@ -296,21 +357,7 @@ export function buildGenerationTurnInput({
|
||||
JSON.stringify(variantPlan || null, null, 2),
|
||||
'</variant_plan>',
|
||||
'',
|
||||
'<product_context>',
|
||||
String(product || ''),
|
||||
'</product_context>',
|
||||
'<design_context>',
|
||||
String(design || ''),
|
||||
'</design_context>',
|
||||
'<action_reference>',
|
||||
String(actionReference || ''),
|
||||
'</action_reference>',
|
||||
'<context_metadata>',
|
||||
JSON.stringify(contextMetadata || {}, null, 2),
|
||||
'</context_metadata>',
|
||||
'<source_neighborhood>',
|
||||
JSON.stringify(sourceNeighborhood || {}, null, 2),
|
||||
'</source_neighborhood>',
|
||||
...contextBlocks,
|
||||
'<staged_artifact>',
|
||||
JSON.stringify(artifact, null, 2),
|
||||
'</staged_artifact>',
|
||||
@@ -339,7 +386,7 @@ export function resolveCodexWorkerSkillPath(scriptsDir) {
|
||||
}
|
||||
|
||||
export function readPreparedArtifact(prepared, { cwd = process.cwd(), maxBytes = 2_000_000 } = {}) {
|
||||
if (prepared.previewMode) {
|
||||
if (isCodexComponentPreviewMode(prepared.previewMode)) {
|
||||
const componentDir = resolveInside(cwd, prepared.componentDir);
|
||||
const manifestPath = resolveInside(cwd, prepared.artifactFile);
|
||||
if (!componentDir || !manifestPath) throw workerError('artifact_path_outside_project');
|
||||
@@ -363,7 +410,7 @@ export function readPreparedArtifact(prepared, { cwd = process.cwd(), maxBytes =
|
||||
const artifactPath = resolveInside(cwd, prepared.artifactFile);
|
||||
if (!artifactPath) throw workerError('artifact_path_outside_project');
|
||||
return {
|
||||
previewMode: 'source',
|
||||
previewMode: prepared.previewMode || 'source',
|
||||
path: prepared.artifactFile,
|
||||
content: readBounded(artifactPath, maxBytes),
|
||||
};
|
||||
@@ -383,25 +430,43 @@ export function applyCodexWorkerOutput({
|
||||
const requirePlan = Number(expectedVariants) > 1 && (phase === 'first' || phase === 'atomic');
|
||||
if (requirePlan && !parsed?.plan) throw workerError('worker_output_plan_missing');
|
||||
const plan = parsed?.plan ? normalizeVariantPlan(parsed.plan, expectedVariants) : null;
|
||||
if (!prepared.previewMode && (phase === 'first' || phase === 'second' || phase === 'final')) {
|
||||
if (!isCodexComponentPreviewMode(prepared.previewMode) && (phase === 'first' || phase === 'remainder' || phase === 'params')) {
|
||||
const artifactPath = resolveInside(cwd, prepared.artifactFile);
|
||||
if (!artifactPath) throw workerError('artifact_path_outside_project');
|
||||
const content = applyCodexSourceDelta({
|
||||
source: fs.readFileSync(artifactPath, 'utf-8'),
|
||||
delta: parsed?.sourceDelta,
|
||||
const common = {
|
||||
sessionId,
|
||||
expectedVariantId: phase === 'first'
|
||||
? 1
|
||||
: phase === 'second'
|
||||
? 2
|
||||
: Number(expectedVariants) > 2 ? 3 : 2,
|
||||
expectedVariants: Number(expectedVariants),
|
||||
styleMode: scaffold?.styleMode || scaffold?.cssAuthoring?.mode || 'scoped',
|
||||
styleTag: scaffold?.styleTag,
|
||||
jsx: scaffold?.commentSyntax?.open === '{/*',
|
||||
parameterCss: parsed?.sourceDelta?.parameterCss,
|
||||
paramsJson: parsed?.sourceDelta?.paramsJson,
|
||||
});
|
||||
};
|
||||
let content = fs.readFileSync(artifactPath, 'utf-8');
|
||||
if (phase === 'first') {
|
||||
content = applyCodexSourceDelta({ ...common, source: content, delta: parsed?.sourceDelta, expectedVariantId: 1 });
|
||||
} else if (phase === 'remainder') {
|
||||
const deltas = Array.isArray(parsed?.sourceDeltas) ? parsed.sourceDeltas : [];
|
||||
const expectedIds = Array.from({ length: Math.max(0, Number(expectedVariants) - 1) }, (_, index) => index + 2);
|
||||
const ids = deltas.map((delta) => Number(delta?.variantId));
|
||||
if (ids.length !== expectedIds.length || ids.some((id, index) => id !== expectedIds[index])) {
|
||||
throw workerError('worker_output_source_delta_variant_invalid');
|
||||
}
|
||||
for (const delta of deltas) {
|
||||
content = applyCodexSourceDelta({ ...common, source: content, delta, expectedVariantId: Number(delta.variantId) });
|
||||
}
|
||||
content = applyCodexSourceParameters({
|
||||
...common,
|
||||
source: content,
|
||||
parameterCss: parsed?.parameterCss,
|
||||
paramsJson: parsed?.paramsJson,
|
||||
});
|
||||
} else {
|
||||
content = applyCodexSourceParameters({
|
||||
...common,
|
||||
source: content,
|
||||
parameterCss: parsed?.parameterCss,
|
||||
paramsJson: parsed?.paramsJson,
|
||||
});
|
||||
}
|
||||
if (Buffer.byteLength(content) > maxBytes) throw workerError('worker_output_too_large');
|
||||
fs.writeFileSync(artifactPath, content, 'utf-8');
|
||||
return { files: [prepared.artifactFile], plan, sourceDelta: true };
|
||||
@@ -420,7 +485,7 @@ export function applyCodexWorkerOutput({
|
||||
totalBytes += Buffer.byteLength(file.content);
|
||||
}
|
||||
if (totalBytes > maxBytes) throw workerError('worker_output_too_large');
|
||||
if (!prepared.previewMode) {
|
||||
if (!isCodexComponentPreviewMode(prepared.previewMode)) {
|
||||
if (parsed.files.length !== 1 || parsed.files[0].path !== prepared.artifactFile) {
|
||||
throw workerError('worker_output_source_path_invalid');
|
||||
}
|
||||
@@ -438,23 +503,17 @@ export function applyCodexWorkerOutput({
|
||||
|| (prepared.previewMode === 'vue-component' ? 'vue' : 'svelte');
|
||||
const variantPattern = new RegExp(`^v(\\d+)\\.${escapeRegExp(extension)}$`);
|
||||
const allowed = new Set();
|
||||
const firstVariant = phase === 'first'
|
||||
? 1
|
||||
: phase === 'second'
|
||||
? 2
|
||||
: phase === 'final'
|
||||
? (expectedVariants > 2 ? 3 : 2)
|
||||
: 1;
|
||||
const lastVariant = phase === 'first' ? 1 : phase === 'second' ? 2 : expectedVariants;
|
||||
for (let variant = firstVariant; variant <= lastVariant; variant += 1) {
|
||||
allowed.add(`v${variant}.${extension}`);
|
||||
const firstVariant = phase === 'first' ? 1 : phase === 'remainder' ? 2 : phase === 'atomic' ? 1 : null;
|
||||
const lastVariant = phase === 'first' ? 1 : phase === 'remainder' || phase === 'atomic' ? expectedVariants : null;
|
||||
if (firstVariant != null) {
|
||||
for (let variant = firstVariant; variant <= lastVariant; variant += 1) allowed.add(`v${variant}.${extension}`);
|
||||
}
|
||||
if (phase === 'final' || phase === 'atomic') allowed.add('params.json');
|
||||
if (phase === 'remainder' || phase === 'params' || phase === 'atomic') allowed.add('params.json');
|
||||
|
||||
for (const file of parsed.files) {
|
||||
if (!allowed.has(file.path)) {
|
||||
const attemptedVariant = Number(variantPattern.exec(file.path)?.[1] || 0);
|
||||
if ((phase === 'second' || phase === 'final') && attemptedVariant > 0 && attemptedVariant < firstVariant) {
|
||||
if (phase === 'remainder' && attemptedVariant > 0 && attemptedVariant < firstVariant) {
|
||||
throw workerError('published_variant_changed');
|
||||
}
|
||||
throw workerError('worker_output_component_path_invalid');
|
||||
@@ -470,7 +529,7 @@ export function applyCodexWorkerOutput({
|
||||
throw workerError('worker_output_component_file_missing', { file: required });
|
||||
}
|
||||
}
|
||||
manifest.arrivedVariants = phase === 'first' ? 1 : phase === 'second' ? 2 : expectedVariants;
|
||||
manifest.arrivedVariants = phase === 'first' ? 1 : expectedVariants;
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
||||
return { files: [...seen], plan };
|
||||
}
|
||||
@@ -596,6 +655,48 @@ export function applyCodexSourceDelta({
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function applyCodexSourceParameters({
|
||||
source,
|
||||
sessionId,
|
||||
expectedVariants = 3,
|
||||
styleMode = 'scoped',
|
||||
parameterCss = '',
|
||||
paramsJson,
|
||||
}) {
|
||||
const variantCount = Number(expectedVariants);
|
||||
const params = normalizeSourceParams(paramsJson, variantCount);
|
||||
const css = String(parameterCss || '').trim();
|
||||
if (/<\/?style\b|`|\$\{/i.test(css)) {
|
||||
throw workerError('worker_output_source_delta_css_unsafe');
|
||||
}
|
||||
if (css) {
|
||||
validateSourceDeltaCss(css, {
|
||||
variantIds: Array.from({ length: variantCount }, (_, index) => index + 1),
|
||||
styleMode,
|
||||
});
|
||||
}
|
||||
|
||||
const id = String(sessionId || '');
|
||||
if (!id) throw workerError('worker_output_source_delta_session_missing');
|
||||
let merged = String(source || '');
|
||||
if (css) {
|
||||
const escapedId = escapeRegExp(id);
|
||||
const styleOpen = new RegExp(`<style\\b[^>]*\\bdata-impeccable-css=(?:"${escapedId}"|'${escapedId}')[^>]*>`, 'i');
|
||||
const styleMatch = styleOpen.exec(merged);
|
||||
if (!styleMatch) throw workerError('worker_output_source_delta_style_missing');
|
||||
const contentStart = styleMatch.index + styleMatch[0].length;
|
||||
const styleClose = merged.indexOf('</style>', contentStart);
|
||||
if (styleClose < 0) throw workerError('worker_output_source_delta_style_invalid');
|
||||
const styleContent = merged.slice(contentStart, styleClose);
|
||||
const lastTick = styleContent.lastIndexOf('`');
|
||||
const nextStyleContent = lastTick >= 0
|
||||
? styleContent.slice(0, lastTick).trimEnd() + '\n' + css + '\n' + styleContent.slice(lastTick)
|
||||
: styleContent.trimEnd() + '\n' + css + '\n';
|
||||
merged = merged.slice(0, contentStart) + nextStyleContent + merged.slice(styleClose);
|
||||
}
|
||||
return applySourceParams(merged, id, params, variantCount);
|
||||
}
|
||||
|
||||
function validateSourceDeltaCss(css, { variantIds, styleMode, requireVariantId = null }) {
|
||||
const allowed = new Set(variantIds.map(String));
|
||||
const refs = [...String(css).matchAll(/\[data-impeccable-variant=(?:"([^"]+)"|'([^']+)')\]/g)]
|
||||
@@ -730,6 +831,7 @@ export function publishCodexWorkerPhase({
|
||||
event,
|
||||
prepared,
|
||||
arrivedVariants,
|
||||
phase,
|
||||
cwd = process.cwd(),
|
||||
}) {
|
||||
const published = publishGenerationArtifact({
|
||||
@@ -740,6 +842,7 @@ export function publishCodexWorkerPhase({
|
||||
expectedSourceHash: prepared.expectedSourceHash,
|
||||
arrivedVariants,
|
||||
expectedVariants: Number(event.count || arrivedVariants),
|
||||
publicationKind: ['remainder', 'params', 'atomic'].includes(phase) ? 'params' : 'variants',
|
||||
cwd,
|
||||
});
|
||||
if (!published.ok) throw workerError(`publish_${published.error}`, published);
|
||||
@@ -757,6 +860,10 @@ export function codexWorkerStateIsOwned(state, cwd) {
|
||||
&& state.threadId.length > 0;
|
||||
}
|
||||
|
||||
export function isCodexComponentPreviewMode(value) {
|
||||
return value === 'svelte-component' || value === 'vue-component';
|
||||
}
|
||||
|
||||
export function codexWorkerProcessStateIsOwned(state, cwd) {
|
||||
return codexWorkerOwnerMatches(state, cwd)
|
||||
&& Number.isInteger(state?.pid)
|
||||
|
||||
Reference in New Issue
Block a user