fix(loop-init): serialize asset bundling#80
Conversation
Jalendar10
left a comment
There was a problem hiding this comment.
I found and fixed a race in tools/loop-init/scripts/bundle-assets.mjs.
Repeated or concurrent npm test / npm run build runs could fail while replacing bundled starters/ and templates/ directories, with errors like EEXIST or partial cleanup failures. The fix serializes bundling with a small filesystem lock and replaces directories through a temp path.
Verified locally with:
npm run validate:registry && npm run check:loop-init && npm run test:tools && cd tools/goal-audit && npm test && cd ../.. && bash scripts/ci-audit-gates.sh && bash scripts/ci-validate-gates.sh'''There was a problem hiding this comment.
Pull request overview
This PR hardens tools/loop-init asset bundling to avoid concurrent rebuild failures (e.g., EEXIST and directory cleanup races) by serializing the bundle step and using a temp-directory swap strategy.
Changes:
- Add an inter-process lock (
.bundle-assets.lock) around bundling to serialize concurrent rebuilds. - Bundle
starters/andtemplates/via copy-to-temp thenrename()into place to reduce partial-update windows. - Add a CLI test that runs two concurrent
bundle-assetsexecutions and asserts key bundled outputs exist.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tools/loop-init/scripts/bundle-assets.mjs | Adds lock + temp swap logic to make bundling robust under concurrent execution. |
| tools/loop-init/test/cli.test.mjs | Adds a concurrency regression test for bundle-assets. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async function sleep(ms) { | ||
| return new Promise((resolve) => { | ||
| setTimeout(resolve, ms); | ||
| }); | ||
| } | ||
|
|
||
| async function acquireLock() { | ||
| for (let attempt = 0; attempt < 100; attempt += 1) { | ||
| try { | ||
| await mkdir(LOCK_DIR); | ||
| return async () => rm(LOCK_DIR, { recursive: true, force: true }); | ||
| } catch (err) { | ||
| if (err?.code !== 'EEXIST') { | ||
| throw err; | ||
| } | ||
| await sleep(50); | ||
| } | ||
| } | ||
| throw new Error(`bundle-assets: timed out waiting for ${LOCK_DIR}`); | ||
| } |
Summary
Fix
loop-initasset bundling so concurrent rebuilds do not fail withEEXISTor partial directory cleanup races.Changes
templates/pattern-template.md+ updatedregistry.yaml)Checklist (from CONTRIBUTING)
STATE.md*examples use.examplesuffixdocs/safety.mdnode tools/loop-audit/dist/cli.js .(or on the starter) and addressed findingsTesting / Dogfood
loop-auditpasses on affected starters or this repoVerification run locally:
Screenshots / Examples (if UI or command output)
N/A
This template enforces the high bar this reference is known for.