From 325aeaf239808a0a8a763fe328e1dc1c3e2351df Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 8 Jun 2026 16:58:55 -0700 Subject: [PATCH] Organize skill script support modules --- AGENTS.md | 2 +- CLAUDE.md | 2 +- scripts/test-suites.mjs | 12 ++++++++---- site/components/LiveDemoPalette.astro | 4 ++-- skill/scripts/context-signals.mjs | 2 +- skill/scripts/critique-storage.mjs | 2 +- skill/scripts/{ => lib}/design-parser.mjs | 0 skill/scripts/{ => lib}/impeccable-paths.mjs | 0 skill/scripts/{ => lib}/is-generated.mjs | 0 skill/scripts/live-accept.mjs | 6 +++--- skill/scripts/live-browser.js | 4 ++-- skill/scripts/live-commit-manual-edits.mjs | 4 ++-- skill/scripts/live-complete.mjs | 4 ++-- skill/scripts/live-discard-manual-edits.mjs | 2 +- skill/scripts/live-inject.mjs | 4 ++-- skill/scripts/live-insert.mjs | 4 ++-- skill/scripts/live-manual-edit-evidence.mjs | 4 ++-- skill/scripts/live-poll.mjs | 4 ++-- skill/scripts/live-resume.mjs | 2 +- skill/scripts/live-server.mjs | 14 +++++++------- skill/scripts/live-status.mjs | 4 ++-- skill/scripts/live-wrap.mjs | 6 +++--- skill/scripts/live.mjs | 2 +- .../{live-completion.mjs => live/completion.mjs} | 0 .../event-validation.mjs} | 4 ++-- .../{live-insert-ui.mjs => live/insert-ui.mjs} | 0 .../manual-edits-buffer.mjs} | 2 +- .../session-store.mjs} | 2 +- .../svelte-component.mjs} | 0 .../sveltekit-adapter.mjs} | 0 .../scripts/{live-ui-core.mjs => live/ui-core.mjs} | 0 .../{live-vocabulary.mjs => live/vocabulary.mjs} | 2 +- tests/design-parser.test.mjs | 2 +- tests/framework-fixtures.test.mjs | 2 +- tests/framework-fixtures/README.md | 2 +- tests/impeccable-paths.test.mjs | 2 +- tests/live-accept-scrub.test.mjs | 2 +- tests/live-commit-manual-edits.test.mjs | 2 +- tests/live-completion.test.mjs | 2 +- tests/live-discard-manual-edits.test.mjs | 2 +- tests/live-e2e/agent.mjs | 2 +- tests/live-event-validation.test.mjs | 2 +- tests/live-insert-ui.test.mjs | 2 +- tests/live-manual-edits-buffer.test.mjs | 2 +- tests/live-poll-stream.test.mjs | 2 +- tests/live-recovery-commands.test.mjs | 2 +- tests/live-server.test.mjs | 4 ++-- tests/live-session-store.test.mjs | 4 ++-- tests/live-wrap-buffer-aware.test.mjs | 2 +- 49 files changed, 70 insertions(+), 66 deletions(-) rename skill/scripts/{ => lib}/design-parser.mjs (100%) rename skill/scripts/{ => lib}/impeccable-paths.mjs (100%) rename skill/scripts/{ => lib}/is-generated.mjs (100%) rename skill/scripts/{live-completion.mjs => live/completion.mjs} (100%) rename skill/scripts/{live-event-validation.mjs => live/event-validation.mjs} (98%) rename skill/scripts/{live-insert-ui.mjs => live/insert-ui.mjs} (100%) rename skill/scripts/{live-manual-edits-buffer.mjs => live/manual-edits-buffer.mjs} (98%) rename skill/scripts/{live-session-store.mjs => live/session-store.mjs} (99%) rename skill/scripts/{live-svelte-component.mjs => live/svelte-component.mjs} (100%) rename skill/scripts/{live-sveltekit-adapter.mjs => live/sveltekit-adapter.mjs} (100%) rename skill/scripts/{live-ui-core.mjs => live/ui-core.mjs} (100%) rename skill/scripts/{live-vocabulary.mjs => live/vocabulary.mjs} (98%) diff --git a/AGENTS.md b/AGENTS.md index 4e9acb138..9b5b7e08d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,7 +46,7 @@ Use ESM, semicolons, and the existing two-space indentation style in JS, HTML, a Tests use Bun’s test runner plus Node’s built-in `--test`. Name tests `*.test.js` or `*.test.mjs` and place new fixtures near the behavior they cover, usually under `tests/fixtures/`. Prefer targeted test runs while iterating, then finish with `bun run test`. If you change generated outputs or provider transforms, verify both source parsing and at least one affected provider path in `dist/`. -For changes to `skill/scripts/live-*.{mjs,js}`, also run `bun run test:live-e2e` (kept out of the default suite because it does real `npm install` per fixture and boots framework dev servers). Scope to one fixture with `IMPECCABLE_E2E_ONLY=` while iterating; pass `IMPECCABLE_E2E_DEBUG=1` for page-DOM and dev-server-log dumps on failure. Schema and authoring guide for new fixtures live in `tests/framework-fixtures/README.md`. +For changes to `skill/scripts/live-*.{mjs,js}` or `skill/scripts/live/**`, also run `bun run test:live-e2e` (kept out of the default suite because it does real `npm install` per fixture and boots framework dev servers). Scope to one fixture with `IMPECCABLE_E2E_ONLY=` while iterating; pass `IMPECCABLE_E2E_DEBUG=1` for page-DOM and dev-server-log dumps on failure. Schema and authoring guide for new fixtures live in `tests/framework-fixtures/README.md`. Set `IMPECCABLE_E2E_AGENT=llm` to swap the deterministic fake agent for an API-backed one (`tests/live-e2e/agents/llm-agent.mjs`). Claude Haiku 4.5 is the primary path whenever `ANTHROPIC_API_KEY` is set. DeepSeek V4 Flash is the secondary cheap fallback when only `DEEPSEEK_API_KEY` is set, and can be forced with `IMPECCABLE_E2E_LLM_PROVIDER=deepseek` or `bun run test:live-e2e -- --llm-provider=deepseek`; override either model via `IMPECCABLE_E2E_LLM_MODEL` or `--llm-model=`. Tests skip cleanly when the selected provider key is unset. This path hits the API — use it for verification, not CI. diff --git a/CLAUDE.md b/CLAUDE.md index dd36ed1a4..1337592b8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -159,7 +159,7 @@ IMPECCABLE_E2E_DEBUG=1 bun run test:live-e2e # dump page DOM + de **One-time setup**: `npx playwright install chromium` (the suite uses a specific Chromium build keyed to the bundled Playwright version). -**Kept out of the default `bun run test`** because (a) it does real `npm install` per fixture, (b) it boots framework dev servers, (c) wall time is ~2 minutes, and (d) it requires Playwright's browser cache. Run it locally before shipping changes to anything in `skill/scripts/live-*.{mjs,js}`. +**Kept out of the default `bun run test`** because (a) it does real `npm install` per fixture, (b) it boots framework dev servers, (c) wall time is ~2 minutes, and (d) it requires Playwright's browser cache. Run it locally before shipping changes to anything in `skill/scripts/live-*.{mjs,js}` or `skill/scripts/live/**`. The agent is pluggable via a one-method interface in `tests/live-e2e/agent.mjs`: `generateVariants(event, context) → { scopedCss, variants[] }`. The default fake agent emits canned variants that exercise all three param kinds (`range`, `steps`, `toggle`). The orchestrator (wrap, write, accept, carbonize) is agent-agnostic. diff --git a/scripts/test-suites.mjs b/scripts/test-suites.mjs index 68205a0fd..5eae8d2c0 100644 --- a/scripts/test-suites.mjs +++ b/scripts/test-suites.mjs @@ -92,7 +92,7 @@ export const SUITES = { description: 'Fast live-mode unit and local-server integration tests, excluding full browser fixture sweeps.', triggers: [ ...COMMON_INFRA_PATTERNS, - /^skill\/(reference\/live\.md|scripts\/(detect-csp|is-generated|live|live-|modern-screenshot|pin|palette))/, + /^skill\/(reference\/live\.md|scripts\/(detect-csp|lib\/is-generated|live\/|live|live-|modern-screenshot|pin|palette))/, /^tests\/live-/, /^tests\/live-e2e\/(agent|agents\/llm-agent|cli-options|preactions|session|steer|ui)\.mjs$/, /^tests\/live-e2e\/agent-insert\.test\.mjs$/, @@ -138,7 +138,9 @@ export const SUITES = { ...COMMON_INFRA_PATTERNS, /^tests\/framework-fixtures/, /^tests\/framework-fixtures\.test\.mjs$/, - /^skill\/scripts\/(detect-csp|is-generated|live-inject|live-sveltekit-adapter|live-wrap)\.mjs$/, + /^skill\/scripts\/(detect-csp|live-inject|live-wrap)\.mjs$/, + /^skill\/scripts\/lib\/is-generated\.mjs$/, + /^skill\/scripts\/live\/sveltekit-adapter\.mjs$/, ], commands: [ { @@ -197,7 +199,8 @@ export const SUITES = { needsPlaywright: true, triggers: [ ...COMMON_INFRA_PATTERNS, - /^skill\/scripts\/(live-accept|live-browser|live-server|live-sveltekit-adapter|live-wrap)\.mjs$/, + /^skill\/scripts\/(live-accept|live-browser|live-server|live-wrap)\.mjs$/, + /^skill\/scripts\/live\/sveltekit-adapter\.mjs$/, /^tests\/live-e2e-accept-cleanup-regression\.test\.mjs$/, /^tests\/live-e2e\//, ], @@ -242,7 +245,8 @@ export const SUITES = { needsPlaywright: true, triggers: [ ...COMMON_INFRA_PATTERNS, - /^skill\/scripts\/(live-sveltekit-adapter|live-svelte-component|live-server|live-wrap)\.mjs$/, + /^skill\/scripts\/(live-server|live-wrap)\.mjs$/, + /^skill\/scripts\/live\/(sveltekit-adapter|svelte-component)\.mjs$/, /^tests\/framework-fixtures\/vite8-sveltekit-stateful\//, /^tests\/live-svelte-adapter-deepseek\.test\.mjs$/, ], diff --git a/site/components/LiveDemoPalette.astro b/site/components/LiveDemoPalette.astro index cb00374f9..54dd2df98 100644 --- a/site/components/LiveDemoPalette.astro +++ b/site/components/LiveDemoPalette.astro @@ -4,9 +4,9 @@ // lands on the `pick` verb. // // Values/labels/icons come from the same canonical source the real picker uses -// (skill/scripts/live-vocabulary.mjs), imported at build time, so the demo and +// (skill/scripts/live/vocabulary.mjs), imported at build time, so the demo and // the product never drift. -import { LIVE_COMMANDS } from '../../skill/scripts/live-vocabulary.mjs'; +import { LIVE_COMMANDS } from '../../skill/scripts/live/vocabulary.mjs'; interface Props { pick: string; diff --git a/skill/scripts/context-signals.mjs b/skill/scripts/context-signals.mjs index c03843812..f631d7561 100644 --- a/skill/scripts/context-signals.mjs +++ b/skill/scripts/context-signals.mjs @@ -22,7 +22,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { execFileSync } from 'node:child_process'; import { loadContext, extractRegister } from './context.mjs'; -import { getCritiqueDir } from './impeccable-paths.mjs'; +import { getCritiqueDir } from './lib/impeccable-paths.mjs'; /** Is there code here at all, or just context files / an empty repo? */ function hasCode(cwd) { diff --git a/skill/scripts/critique-storage.mjs b/skill/scripts/critique-storage.mjs index eba12383e..645628c8c 100644 --- a/skill/scripts/critique-storage.mjs +++ b/skill/scripts/critique-storage.mjs @@ -28,7 +28,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import { getCritiqueDir } from './impeccable-paths.mjs'; +import { getCritiqueDir } from './lib/impeccable-paths.mjs'; const SLUG_MAX = 50; diff --git a/skill/scripts/design-parser.mjs b/skill/scripts/lib/design-parser.mjs similarity index 100% rename from skill/scripts/design-parser.mjs rename to skill/scripts/lib/design-parser.mjs diff --git a/skill/scripts/impeccable-paths.mjs b/skill/scripts/lib/impeccable-paths.mjs similarity index 100% rename from skill/scripts/impeccable-paths.mjs rename to skill/scripts/lib/impeccable-paths.mjs diff --git a/skill/scripts/is-generated.mjs b/skill/scripts/lib/is-generated.mjs similarity index 100% rename from skill/scripts/is-generated.mjs rename to skill/scripts/lib/is-generated.mjs diff --git a/skill/scripts/live-accept.mjs b/skill/scripts/live-accept.mjs index 5e8687187..278dfbb2e 100644 --- a/skill/scripts/live-accept.mjs +++ b/skill/scripts/live-accept.mjs @@ -15,14 +15,14 @@ import fs from 'node:fs'; import path from 'node:path'; -import { isGeneratedFile } from './is-generated.mjs'; -import { readBuffer as readManualEditsBuffer, writeBuffer as writeManualEditsBuffer } from './live-manual-edits-buffer.mjs'; +import { isGeneratedFile } from './lib/is-generated.mjs'; +import { readBuffer as readManualEditsBuffer, writeBuffer as writeManualEditsBuffer } from './live/manual-edits-buffer.mjs'; import { applyDeferredSvelteComponentAccepts, findSvelteComponentManifest, inlineSvelteComponentAccept, removeSvelteComponentSession, -} from './live-svelte-component.mjs'; +} from './live/svelte-component.mjs'; const EXTENSIONS = ['.html', '.jsx', '.tsx', '.vue', '.svelte', '.astro']; diff --git a/skill/scripts/live-browser.js b/skill/scripts/live-browser.js index 0a533945f..9c4b6c21e 100644 --- a/skill/scripts/live-browser.js +++ b/skill/scripts/live-browser.js @@ -82,7 +82,7 @@ ]); // Command vocabulary (values + labels + icons) comes from the canonical source, - // skill/scripts/live-vocabulary.mjs, which live-server.mjs serializes into + // skill/scripts/live/vocabulary.mjs, which live-server.mjs serializes into // window.__IMPECCABLE_VOCAB__ when it serves /live.js (same injection path as // the token/port above, so it is always present here). The icons stack above // each chip label and recolor to C.brand when selected (strokes use @@ -1216,7 +1216,7 @@ : (focused ? BP.accentSoft : BP.hairline); } - // Insert mode helpers (mirrors skill/scripts/live-insert-ui.mjs) + // Insert mode helpers (mirrors skill/scripts/live/insert-ui.mjs) function detectInsertAxisFromStyle(style) { const display = style?.display || 'block'; diff --git a/skill/scripts/live-commit-manual-edits.mjs b/skill/scripts/live-commit-manual-edits.mjs index 44bc5ea4b..8bde46b50 100644 --- a/skill/scripts/live-commit-manual-edits.mjs +++ b/skill/scripts/live-commit-manual-edits.mjs @@ -16,8 +16,8 @@ */ import { buildManualEditEvidence } from './live-manual-edit-evidence.mjs'; -import { readBuffer, readBufferStrict, writeBuffer, countByPage } from './live-manual-edits-buffer.mjs'; -import { isGeneratedFile } from './is-generated.mjs'; +import { readBuffer, readBufferStrict, writeBuffer, countByPage } from './live/manual-edits-buffer.mjs'; +import { isGeneratedFile } from './lib/is-generated.mjs'; import { runCopyEditBatchAgent, runCopyEditPostApplyChecks, diff --git a/skill/scripts/live-complete.mjs b/skill/scripts/live-complete.mjs index 78155af85..1cc4e7543 100644 --- a/skill/scripts/live-complete.mjs +++ b/skill/scripts/live-complete.mjs @@ -3,8 +3,8 @@ * Canonical durable completion acknowledgement for Impeccable live sessions. */ -import { createLiveSessionStore } from './live-session-store.mjs'; -import { readLiveServerInfo } from './impeccable-paths.mjs'; +import { createLiveSessionStore } from './live/session-store.mjs'; +import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; function parseArgs(argv) { const out = { status: 'complete' }; diff --git a/skill/scripts/live-discard-manual-edits.mjs b/skill/scripts/live-discard-manual-edits.mjs index 435f22413..aa669fd20 100755 --- a/skill/scripts/live-discard-manual-edits.mjs +++ b/skill/scripts/live-discard-manual-edits.mjs @@ -16,7 +16,7 @@ * Output JSON: { discarded: N, entries: [...discardedEntries], totalCount: N } */ -import { readBuffer, removeEntries, truncateBuffer } from './live-manual-edits-buffer.mjs'; +import { readBuffer, removeEntries, truncateBuffer } from './live/manual-edits-buffer.mjs'; function argVal(args, name) { const prefix = name + '='; diff --git a/skill/scripts/live-inject.mjs b/skill/scripts/live-inject.mjs index 3a1f36e46..c006ad09e 100644 --- a/skill/scripts/live-inject.mjs +++ b/skill/scripts/live-inject.mjs @@ -16,12 +16,12 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { resolveLiveConfigPath } from './impeccable-paths.mjs'; +import { resolveLiveConfigPath } from './lib/impeccable-paths.mjs'; import { applySvelteKitLiveAdapter, detectSvelteKitProject, removeSvelteKitLiveAdapter, -} from './live-sveltekit-adapter.mjs'; +} from './live/sveltekit-adapter.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const CONFIG_PATH = resolveLiveConfigPath({ cwd: process.cwd(), scriptsDir: __dirname }); diff --git a/skill/scripts/live-insert.mjs b/skill/scripts/live-insert.mjs index 0658e9914..0ed3cafea 100644 --- a/skill/scripts/live-insert.mjs +++ b/skill/scripts/live-insert.mjs @@ -9,7 +9,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import { isGeneratedFile } from './is-generated.mjs'; +import { isGeneratedFile } from './lib/is-generated.mjs'; import { buildSearchQueries, findElement, @@ -25,7 +25,7 @@ import { buildSvelteComponentCssAuthoring, scaffoldSvelteComponentInsertSession, shouldUseSvelteComponentInjection, -} from './live-svelte-component.mjs'; +} from './live/svelte-component.mjs'; const INSERT_POSITIONS = new Set(['before', 'after']); diff --git a/skill/scripts/live-manual-edit-evidence.mjs b/skill/scripts/live-manual-edit-evidence.mjs index 860278b73..dd10e96dc 100644 --- a/skill/scripts/live-manual-edit-evidence.mjs +++ b/skill/scripts/live-manual-edit-evidence.mjs @@ -10,8 +10,8 @@ import fs from 'node:fs'; import path from 'node:path'; -import { isGeneratedFile } from './is-generated.mjs'; -import { readBuffer, getBufferPath } from './live-manual-edits-buffer.mjs'; +import { isGeneratedFile } from './lib/is-generated.mjs'; +import { readBuffer, getBufferPath } from './live/manual-edits-buffer.mjs'; const EVIDENCE_VERSION = 1; const TEXT_EXTENSIONS = new Set(['.html', '.jsx', '.tsx', '.vue', '.svelte', '.astro', '.js', '.mjs', '.ts']); diff --git a/skill/scripts/live-poll.mjs b/skill/scripts/live-poll.mjs index 1e1259fbc..b031055fe 100644 --- a/skill/scripts/live-poll.mjs +++ b/skill/scripts/live-poll.mjs @@ -12,8 +12,8 @@ import { execFileSync } from 'node:child_process'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live-completion.mjs'; -import { readLiveServerInfo } from './impeccable-paths.mjs'; +import { completionAckForAcceptResult, completionTypeForAcceptResult } from './live/completion.mjs'; +import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; // Node's built-in fetch (undici under the hood) enforces a 300s headers // timeout that can't be lowered per-request. We cap each request below diff --git a/skill/scripts/live-resume.mjs b/skill/scripts/live-resume.mjs index e54831f12..74284d48a 100644 --- a/skill/scripts/live-resume.mjs +++ b/skill/scripts/live-resume.mjs @@ -3,7 +3,7 @@ * Recover the next agent action from the durable live-session journal. */ -import { createLiveSessionStore } from './live-session-store.mjs'; +import { createLiveSessionStore } from './live/session-store.mjs'; function manualApplyReplyCommand(eventOrId = 'EVENT_ID') { const id = typeof eventOrId === 'string' ? eventOrId : eventOrId?.id || 'EVENT_ID'; diff --git a/skill/scripts/live-server.mjs b/skill/scripts/live-server.mjs index d9e06f449..187af0ac1 100644 --- a/skill/scripts/live-server.mjs +++ b/skill/scripts/live-server.mjs @@ -20,11 +20,11 @@ import fs from 'node:fs'; import path from 'node:path'; import net from 'node:net'; import { fileURLToPath } from 'node:url'; -import { parseDesignMd } from './design-parser.mjs'; +import { parseDesignMd } from './lib/design-parser.mjs'; import { resolveContextDir } from './context.mjs'; -import { createLiveSessionStore } from './live-session-store.mjs'; -import { validateEvent } from './live-event-validation.mjs'; -import { LIVE_COMMANDS } from './live-vocabulary.mjs'; +import { createLiveSessionStore } from './live/session-store.mjs'; +import { validateEvent } from './live/event-validation.mjs'; +import { LIVE_COMMANDS } from './live/vocabulary.mjs'; import { getDesignSidecarPath, getLiveDir, @@ -33,20 +33,20 @@ import { removeLiveServerInfo, resolveDesignSidecarPath, writeLiveServerInfo, -} from './impeccable-paths.mjs'; +} from './lib/impeccable-paths.mjs'; import { countByPage as countPendingByPage, readBuffer as readManualEditsBuffer, removeEntries as removeManualEditEntries, stageEntry as stageManualEditEntry, truncateBuffer as truncateManualEditsBuffer, -} from './live-manual-edits-buffer.mjs'; +} from './live/manual-edits-buffer.mjs'; import { buildManualEditEvidence } from './live-manual-edit-evidence.mjs'; import { commitManualEdits } from './live-commit-manual-edits.mjs'; import { applyDeferredSvelteComponentAccepts, removeAllSvelteComponentSessions, -} from './live-svelte-component.mjs'; +} from './live/svelte-component.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); // PRODUCT.md / DESIGN.md live wherever context.mjs resolves. The generated diff --git a/skill/scripts/live-status.mjs b/skill/scripts/live-status.mjs index a7009cc29..f7e464999 100644 --- a/skill/scripts/live-status.mjs +++ b/skill/scripts/live-status.mjs @@ -3,8 +3,8 @@ * Print durable recovery status for Impeccable live sessions. */ -import { createLiveSessionStore } from './live-session-store.mjs'; -import { readLiveServerInfo } from './impeccable-paths.mjs'; +import { createLiveSessionStore } from './live/session-store.mjs'; +import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; import { manualApplyResumeHint } from './live-resume.mjs'; function readServerInfo() { diff --git a/skill/scripts/live-wrap.mjs b/skill/scripts/live-wrap.mjs index a83cbcc56..c3f00f3a4 100644 --- a/skill/scripts/live-wrap.mjs +++ b/skill/scripts/live-wrap.mjs @@ -13,13 +13,13 @@ import fs from 'node:fs'; import path from 'node:path'; -import { isGeneratedFile } from './is-generated.mjs'; -import { readBuffer as readManualEditsBuffer } from './live-manual-edits-buffer.mjs'; +import { isGeneratedFile } from './lib/is-generated.mjs'; +import { readBuffer as readManualEditsBuffer } from './live/manual-edits-buffer.mjs'; import { buildSvelteComponentCssAuthoring, scaffoldSvelteComponentSession, shouldUseSvelteComponentInjection, -} from './live-svelte-component.mjs'; +} from './live/svelte-component.mjs'; const EXTENSIONS = ['.html', '.jsx', '.tsx', '.vue', '.svelte', '.astro']; diff --git a/skill/scripts/live.mjs b/skill/scripts/live.mjs index 8acd300ed..0992da1bd 100644 --- a/skill/scripts/live.mjs +++ b/skill/scripts/live.mjs @@ -23,7 +23,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { loadContext } from './context.mjs'; import { resolveFiles } from './live-inject.mjs'; -import { readLiveServerInfo } from './impeccable-paths.mjs'; +import { readLiveServerInfo } from './lib/impeccable-paths.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); diff --git a/skill/scripts/live-completion.mjs b/skill/scripts/live/completion.mjs similarity index 100% rename from skill/scripts/live-completion.mjs rename to skill/scripts/live/completion.mjs diff --git a/skill/scripts/live-event-validation.mjs b/skill/scripts/live/event-validation.mjs similarity index 98% rename from skill/scripts/live-event-validation.mjs rename to skill/scripts/live/event-validation.mjs index 15ae3265d..0897b1317 100644 --- a/skill/scripts/live-event-validation.mjs +++ b/skill/scripts/live/event-validation.mjs @@ -3,12 +3,12 @@ * Extracted for unit testing (insert mode rules). */ -import { canCreateInsert } from './live-insert-ui.mjs'; +import { canCreateInsert } from './insert-ui.mjs'; // The accepted visual action values come from the canonical vocabulary so the // validator, the picker UI, and the marketing demo never drift. Imported (not // just re-exported) so it is also in scope for the validators below. -import { VISUAL_ACTIONS } from './live-vocabulary.mjs'; +import { VISUAL_ACTIONS } from './vocabulary.mjs'; export { VISUAL_ACTIONS }; const ID_PATTERN = /^[0-9a-f]{8}$/; diff --git a/skill/scripts/live-insert-ui.mjs b/skill/scripts/live/insert-ui.mjs similarity index 100% rename from skill/scripts/live-insert-ui.mjs rename to skill/scripts/live/insert-ui.mjs diff --git a/skill/scripts/live-manual-edits-buffer.mjs b/skill/scripts/live/manual-edits-buffer.mjs similarity index 98% rename from skill/scripts/live-manual-edits-buffer.mjs rename to skill/scripts/live/manual-edits-buffer.mjs index 9e3dcf455..d96ebbe34 100644 --- a/skill/scripts/live-manual-edits-buffer.mjs +++ b/skill/scripts/live/manual-edits-buffer.mjs @@ -12,7 +12,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import { getLiveDir } from './impeccable-paths.mjs'; +import { getLiveDir } from '../lib/impeccable-paths.mjs'; const BUFFER_VERSION = 1; const BUFFER_FILENAME = 'pending-manual-edits.json'; diff --git a/skill/scripts/live-session-store.mjs b/skill/scripts/live/session-store.mjs similarity index 99% rename from skill/scripts/live-session-store.mjs rename to skill/scripts/live/session-store.mjs index 5ec4d34d4..affba67c9 100644 --- a/skill/scripts/live-session-store.mjs +++ b/skill/scripts/live/session-store.mjs @@ -1,6 +1,6 @@ import fs from 'node:fs'; import path from 'node:path'; -import { getLegacyLiveSessionsDir, getLiveSessionsDir } from './impeccable-paths.mjs'; +import { getLegacyLiveSessionsDir, getLiveSessionsDir } from '../lib/impeccable-paths.mjs'; const COMPLETED_PHASES = new Set(['completed', 'discarded']); diff --git a/skill/scripts/live-svelte-component.mjs b/skill/scripts/live/svelte-component.mjs similarity index 100% rename from skill/scripts/live-svelte-component.mjs rename to skill/scripts/live/svelte-component.mjs diff --git a/skill/scripts/live-sveltekit-adapter.mjs b/skill/scripts/live/sveltekit-adapter.mjs similarity index 100% rename from skill/scripts/live-sveltekit-adapter.mjs rename to skill/scripts/live/sveltekit-adapter.mjs diff --git a/skill/scripts/live-ui-core.mjs b/skill/scripts/live/ui-core.mjs similarity index 100% rename from skill/scripts/live-ui-core.mjs rename to skill/scripts/live/ui-core.mjs diff --git a/skill/scripts/live-vocabulary.mjs b/skill/scripts/live/vocabulary.mjs similarity index 98% rename from skill/scripts/live-vocabulary.mjs rename to skill/scripts/live/vocabulary.mjs index 1123d41c4..5c7b0b713 100644 --- a/skill/scripts/live-vocabulary.mjs +++ b/skill/scripts/live/vocabulary.mjs @@ -4,7 +4,7 @@ * so the icon recolors when its chip is selected. * * Single source of truth, consumed by: - * - skill/scripts/live-event-validation.mjs — re-exports VISUAL_ACTIONS. + * - skill/scripts/live/event-validation.mjs — re-exports VISUAL_ACTIONS. * - skill/scripts/live-browser.js — the real picker. It is served raw and * injected as an IIFE, so it cannot import this at runtime; live-server.mjs * serializes LIVE_COMMANDS into window.__IMPECCABLE_VOCAB__ alongside the diff --git a/tests/design-parser.test.mjs b/tests/design-parser.test.mjs index 027454660..ea77ee7e5 100644 --- a/tests/design-parser.test.mjs +++ b/tests/design-parser.test.mjs @@ -5,7 +5,7 @@ import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; -import { parseDesignMd } from '../skill/scripts/design-parser.mjs'; +import { parseDesignMd } from '../skill/scripts/lib/design-parser.mjs'; describe('parseDesignMd frontmatter branch', () => { it('returns null frontmatter when the file has no YAML header', () => { diff --git a/tests/framework-fixtures.test.mjs b/tests/framework-fixtures.test.mjs index 67f6589d6..7d3769298 100644 --- a/tests/framework-fixtures.test.mjs +++ b/tests/framework-fixtures.test.mjs @@ -17,7 +17,7 @@ import { tmpdir } from 'node:os'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { isGeneratedFile } from '../skill/scripts/is-generated.mjs'; +import { isGeneratedFile } from '../skill/scripts/lib/is-generated.mjs'; import { detectCsp } from '../skill/scripts/detect-csp.mjs'; const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/tests/framework-fixtures/README.md b/tests/framework-fixtures/README.md index 2b638001e..ddac42a6e 100644 --- a/tests/framework-fixtures/README.md +++ b/tests/framework-fixtures/README.md @@ -1,6 +1,6 @@ # Framework fixtures -Representative project shapes for exercising live mode against different framework conventions. Each fixture is a small directory tree that the test harness copies into a temp git repo, then drives `live-inject.mjs`, `live-wrap.mjs`, `live-accept.mjs`, and `is-generated.mjs` against. +Representative project shapes for exercising live mode against different framework conventions. Each fixture is a small directory tree that the test harness copies into a temp git repo, then drives `live-inject.mjs`, `live-wrap.mjs`, `live-accept.mjs`, and `lib/is-generated.mjs` against. Fixtures can also opt into a **runtime E2E** pass that actually installs dependencies, boots the framework dev server, and drives a Playwright browser to verify the live handshake. See the `runtime` block below. diff --git a/tests/impeccable-paths.test.mjs b/tests/impeccable-paths.test.mjs index c3555cbd4..3a8fb552a 100644 --- a/tests/impeccable-paths.test.mjs +++ b/tests/impeccable-paths.test.mjs @@ -19,7 +19,7 @@ import { readLiveServerInfo, resolveDesignSidecarPath, resolveLiveConfigPath, -} from '../skill/scripts/impeccable-paths.mjs'; +} from '../skill/scripts/lib/impeccable-paths.mjs'; describe('impeccable project paths', () => { let tmp; diff --git a/tests/live-accept-scrub.test.mjs b/tests/live-accept-scrub.test.mjs index 50ce42c56..31dcf34c7 100644 --- a/tests/live-accept-scrub.test.mjs +++ b/tests/live-accept-scrub.test.mjs @@ -3,7 +3,7 @@ import assert from 'node:assert'; import fs from 'node:fs'; import path from 'node:path'; import os from 'node:os'; -import { writeBuffer, readBuffer } from '../skill/scripts/live-manual-edits-buffer.mjs'; +import { writeBuffer, readBuffer } from '../skill/scripts/live/manual-edits-buffer.mjs'; import { scrubManualEditsAgainstOriginalBlock } from '../skill/scripts/live-accept.mjs'; let tmpDir; diff --git a/tests/live-commit-manual-edits.test.mjs b/tests/live-commit-manual-edits.test.mjs index e6fe86a7b..e28218786 100644 --- a/tests/live-commit-manual-edits.test.mjs +++ b/tests/live-commit-manual-edits.test.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; import os from 'node:os'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { writeBuffer, readBuffer } from '../skill/scripts/live-manual-edits-buffer.mjs'; +import { writeBuffer, readBuffer } from '../skill/scripts/live/manual-edits-buffer.mjs'; import { buildManualEditEvidence } from '../skill/scripts/live-manual-edit-evidence.mjs'; import { commitManualEdits } from '../skill/scripts/live-commit-manual-edits.mjs'; import { diff --git a/tests/live-completion.test.mjs b/tests/live-completion.test.mjs index c4c219b8e..7fc51a742 100644 --- a/tests/live-completion.test.mjs +++ b/tests/live-completion.test.mjs @@ -4,7 +4,7 @@ import assert from 'node:assert/strict'; import { completionAckForAcceptResult, completionTypeForAcceptResult, -} from '../skill/scripts/live-completion.mjs'; +} from '../skill/scripts/live/completion.mjs'; describe('live completion type classification', () => { it('treats generated-file fallback accept as normal agent handoff, not error', () => { diff --git a/tests/live-discard-manual-edits.test.mjs b/tests/live-discard-manual-edits.test.mjs index 497fb463c..a42309d35 100644 --- a/tests/live-discard-manual-edits.test.mjs +++ b/tests/live-discard-manual-edits.test.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; import os from 'node:os'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { writeBuffer, readBuffer } from '../skill/scripts/live-manual-edits-buffer.mjs'; +import { writeBuffer, readBuffer } from '../skill/scripts/live/manual-edits-buffer.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = path.resolve(__dirname, '..'); diff --git a/tests/live-e2e/agent.mjs b/tests/live-e2e/agent.mjs index 2db743c69..73bfefc6c 100644 --- a/tests/live-e2e/agent.mjs +++ b/tests/live-e2e/agent.mjs @@ -26,7 +26,7 @@ import { readFileSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; -import { completionTypeForAcceptResult } from '../../skill/scripts/live-completion.mjs'; +import { completionTypeForAcceptResult } from '../../skill/scripts/live/completion.mjs'; const execFileP = promisify(execFile); diff --git a/tests/live-event-validation.test.mjs b/tests/live-event-validation.test.mjs index bb76cd1eb..8282f5137 100644 --- a/tests/live-event-validation.test.mjs +++ b/tests/live-event-validation.test.mjs @@ -5,7 +5,7 @@ import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; -import { validateEvent } from '../skill/scripts/live-event-validation.mjs'; +import { validateEvent } from '../skill/scripts/live/event-validation.mjs'; const VALID_ID = 'a1b2c3d4'; diff --git a/tests/live-insert-ui.test.mjs b/tests/live-insert-ui.test.mjs index 94ae84227..2200d1752 100644 --- a/tests/live-insert-ui.test.mjs +++ b/tests/live-insert-ui.test.mjs @@ -30,7 +30,7 @@ import { resolveInsertSessionAnchor, buildInsertPlaceholderSnapshot, findInsertAnchorInDom, -} from '../skill/scripts/live-insert-ui.mjs'; +} from '../skill/scripts/live/insert-ui.mjs'; describe('detectInsertAxisFromStyle', () => { it('maps flex row and grid multi-column to row axis', () => { diff --git a/tests/live-manual-edits-buffer.test.mjs b/tests/live-manual-edits-buffer.test.mjs index 2a848facf..5dcba600f 100644 --- a/tests/live-manual-edits-buffer.test.mjs +++ b/tests/live-manual-edits-buffer.test.mjs @@ -12,7 +12,7 @@ import { countByPage, truncateBuffer, getBufferPath, -} from '../skill/scripts/live-manual-edits-buffer.mjs'; +} from '../skill/scripts/live/manual-edits-buffer.mjs'; let tmpDir; diff --git a/tests/live-poll-stream.test.mjs b/tests/live-poll-stream.test.mjs index b12e00fbe..55c802e97 100644 --- a/tests/live-poll-stream.test.mjs +++ b/tests/live-poll-stream.test.mjs @@ -9,7 +9,7 @@ import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { spawn } from 'node:child_process'; import { tmpdir } from 'node:os'; -import { getLiveServerPath } from '../skill/scripts/impeccable-paths.mjs'; +import { getLiveServerPath } from '../skill/scripts/lib/impeccable-paths.mjs'; import { postReply } from '../skill/scripts/live-poll.mjs'; const REPO_ROOT = process.cwd(); diff --git a/tests/live-recovery-commands.test.mjs b/tests/live-recovery-commands.test.mjs index 9f7ade688..157fe3d1d 100644 --- a/tests/live-recovery-commands.test.mjs +++ b/tests/live-recovery-commands.test.mjs @@ -4,7 +4,7 @@ import { mkdtempSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { execFileSync } from 'node:child_process'; -import { createLiveSessionStore } from '../skill/scripts/live-session-store.mjs'; +import { createLiveSessionStore } from '../skill/scripts/live/session-store.mjs'; const REPO_ROOT = process.cwd(); const STATUS_SCRIPT = join(REPO_ROOT, 'skill/scripts/live-status.mjs'); diff --git a/tests/live-server.test.mjs b/tests/live-server.test.mjs index 1634791f0..57380ab7b 100644 --- a/tests/live-server.test.mjs +++ b/tests/live-server.test.mjs @@ -14,7 +14,7 @@ import { getLiveDir, getLiveServerPath, getLiveSessionsDir, -} from '../skill/scripts/impeccable-paths.mjs'; +} from '../skill/scripts/lib/impeccable-paths.mjs'; const REPO_ROOT = process.cwd(); const SERVER_SCRIPT = join(REPO_ROOT, 'skill/scripts/live-server.mjs'); @@ -162,7 +162,7 @@ describe('live-server integration', () => { // live-browser.js builds its action picker from window.__IMPECCABLE_VOCAB__ // rather than an inline copy, so the server must serialize the canonical // vocabulary into /live.js (next to the token/port). - const { LIVE_COMMANDS } = await import('../skill/scripts/live-vocabulary.mjs'); + const { LIVE_COMMANDS } = await import('../skill/scripts/live/vocabulary.mjs'); const body = await (await fetch(`http://localhost:${server.port}/live.js`)).text(); assert.match(body, /window\.__IMPECCABLE_VOCAB__\s*=/); const injected = JSON.parse(body.match(/window\.__IMPECCABLE_VOCAB__\s*=\s*(\[.*?\]);/s)[1]); diff --git a/tests/live-session-store.test.mjs b/tests/live-session-store.test.mjs index dc4c5c61e..abfc0af3f 100644 --- a/tests/live-session-store.test.mjs +++ b/tests/live-session-store.test.mjs @@ -9,12 +9,12 @@ import { mkdirSync, mkdtempSync, rmSync, appendFileSync, readFileSync } from 'no import { join } from 'node:path'; import { tmpdir } from 'node:os'; -import { createLiveSessionStore } from '../skill/scripts/live-session-store.mjs'; +import { createLiveSessionStore } from '../skill/scripts/live/session-store.mjs'; import { getLegacyLiveSessionsDir, getLiveAnnotationsDir, getLiveSessionsDir, -} from '../skill/scripts/impeccable-paths.mjs'; +} from '../skill/scripts/lib/impeccable-paths.mjs'; describe('live-session-store', () => { let tmp; diff --git a/tests/live-wrap-buffer-aware.test.mjs b/tests/live-wrap-buffer-aware.test.mjs index 5196869cf..ff0671ef2 100644 --- a/tests/live-wrap-buffer-aware.test.mjs +++ b/tests/live-wrap-buffer-aware.test.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; import os from 'node:os'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { writeBuffer } from '../skill/scripts/live-manual-edits-buffer.mjs'; +import { writeBuffer } from '../skill/scripts/live/manual-edits-buffer.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = path.resolve(__dirname, '..');