diff --git a/skill/scripts/live-accept.mjs b/skill/scripts/live-accept.mjs index 507418ea3..2a34dc12a 100644 --- a/skill/scripts/live-accept.mjs +++ b/skill/scripts/live-accept.mjs @@ -170,51 +170,35 @@ Output (JSON): } if (svelteComponentManifest) { - if (isDiscard) { - let result; - try { - result = withSourceLockSync( - path.resolve(process.cwd(), svelteComponentManifest.sourceFile), - 'discard:' + id, - () => { - removeSvelteComponentSession(id, process.cwd()); - return { handled: true }; - }, - { waitMs: ACCEPT_LOCK_WAIT_MS }, - ); - } catch (err) { - result = operationFailure(err); - } - emitResult({ - ...result, - file: svelteComponentManifest.sourceFile, - carbonize: false, - previewMode: 'svelte-component', - componentDir: svelteComponentManifest.componentDir, - }); - return; - } - - let result; - try { - result = withSourceLockSync( - path.resolve(process.cwd(), svelteComponentManifest.sourceFile), - 'accept:' + id, - () => inlineSvelteComponentAccept( + const { sourceFile, componentDir } = svelteComponentManifest; + const resultContext = { + file: sourceFile, + ...(isDiscard ? { carbonize: false } : { sourceFile }), + previewMode: 'svelte-component', + componentDir, + }; + const runOperation = isDiscard + ? () => { + removeSvelteComponentSession(id, process.cwd()); + return { handled: true, ...resultContext }; + } + : () => inlineSvelteComponentAccept( svelteComponentManifest, variantNum, paramValues, process.cwd(), - ), + ); + + let result; + try { + result = withSourceLockSync( + path.resolve(process.cwd(), sourceFile), + requestedOperation + ':' + id, + runOperation, { waitMs: ACCEPT_LOCK_WAIT_MS }, ); } catch (err) { - result = operationFailure(err, { - file: svelteComponentManifest.sourceFile, - sourceFile: svelteComponentManifest.sourceFile, - previewMode: 'svelte-component', - componentDir: svelteComponentManifest.componentDir, - }); + result = operationFailure(err, resultContext); } if (result.carbonize) { result.todo = 'REQUIRED before next poll: carbonize cleanup in ' + result.file + '. See reference/live.md "Required after accept".'; diff --git a/tests/live-svelte-component-accept.test.mjs b/tests/live-svelte-component-accept.test.mjs index c0c47988c..40d12d4ed 100644 --- a/tests/live-svelte-component-accept.test.mjs +++ b/tests/live-svelte-component-accept.test.mjs @@ -1,7 +1,8 @@ import { describe, it, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; import { cpSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync, symlinkSync } from 'node:fs'; -import { join, dirname } from 'node:path'; +import { join, dirname, resolve } from 'node:path'; import { tmpdir } from 'node:os'; import { fileURLToPath } from 'node:url'; import { @@ -17,6 +18,7 @@ import { const __dirname = dirname(fileURLToPath(import.meta.url)); const REPO_NODE_MODULES = join(__dirname, '..', 'node_modules'); +const ACCEPT = resolve(__dirname, '..', 'skill/scripts/live-accept.mjs'); const ROUTE_SOURCE = ` + +
    + {#each stages as stage, i} +
  1. + {stage.label} +

    {stage.detail}

    +
  2. + {/each} +
+ + +`); + + const result = runAccept(tmp, ['--id', 'cliacc1', '--variant', '1']); + assert.equal(result.handled, true, result.error); + assert.equal(result.file, 'src/routes/+page.svelte'); + assert.equal(result.previewMode, 'svelte-component'); + assert.equal(result.componentDir, session.componentDir); + assert.match(readFileSync(join(tmp, result.file), 'utf-8'), /class="[^"]*\baccepted-board\b/); + assert.equal(findSvelteComponentManifest('cliacc1', tmp), null); + }); + + it('discards a Svelte component session through the CLI', () => { + const session = scaffold('clidisc1'); + + const result = runAccept(tmp, ['--id', 'clidisc1', '--discard']); + assert.deepEqual(result, { + handled: true, + file: 'src/routes/+page.svelte', + carbonize: false, + previewMode: 'svelte-component', + componentDir: session.componentDir, + }); + assert.equal(readFileSync(join(tmp, result.file), 'utf-8'), ROUTE_SOURCE); + assert.equal(findSvelteComponentManifest('clidisc1', tmp), null); + }); + it('falls back to source-preview for markup with component tags', () => { const res = scaffoldSvelteComponentSession({ id: 'fallb1',