Commit Graph
3 Commits
Author SHA1 Message Date
Paul BakausandClaude Opus 4.7 d5480caee3 feat(live): CSP detection + consent-gated patch flow at first-time setup
Real-world tests (EAC Next turborepo) confirmed that CSP is the common
blocker for live mode. Adds setup-time detection with a one-time user
consent flow — the patch becomes a permanent, dev-guarded entry in the
user's own config, not a transient add/remove.

## Changes

- New detect-csp.mjs helper: grep-based classifier returning
  { shape, signals }. Shape is one of:
    - "shared-helper" (monorepo CSP helper with additional*Src arrays)
    - "inline-headers" (literal CSP string in headers())
    - "middleware" (response.headers.set in middleware.ts; detect-only v1)
    - "meta-tag" (<meta http-equiv>; detect-only v1)
    - null (no CSP)
  Max depth 6, skips node_modules / build / cache dirs, 64KB per file.

- cspChecked boolean on config.json. First-run setup runs detection;
  subsequent runs skip. Users re-trigger by deleting the flag.
  Validator accepts it.

- Skill live.md gains:
    - CSP detection step in first-time setup (gated by cspChecked)
    - Consent-prompt template (so every agent phrases it the same way)
    - Shape 1 patch template: append `...__impeccableLiveDev` to
      additionalScriptSrc/additionalConnectSrc in the app's config
    - Shape 2 patch template: two-point edit — declare a dev-only
      variable, interpolate into script-src and connect-src in the
      CSP literal string
    - Troubleshooting note for "said no but now live doesn't work"

## Fixtures

- nextjs-turborepo/: Turborepo shape (shared CSP helper with
  additionalScriptSrc options). Sanitized from a real monorepo so the
  patch mechanics get tested against realistic layering. Includes
  expected-after-patch.ts for human/agent review.

- nextjs-inline-csp/: app-level next.config.js with a literal CSP
  string. Includes expected-after-patch.js showing the Shape 2 edit.

## Tests

Framework-fixture harness extended with a detect-csp shape-classification
assertion per fixture. 42 tests across 7 fixtures pass. Clean fixtures
(vite-react, nextjs-app, astro, sveltekit, multipage-with-generator)
correctly return shape: null.

## Deliberately not doing

- No patches[] array, no marker-based rollback, no add/remove lifecycle.
  The patch is a permanent dev-guarded config line — the same kind of
  edit a user would make themselves.
- No base URL rewriting or proxy mechanism. Script tag still points at
  localhost:8400; CSP permits it once patched. No browser-side changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:41:11 -07:00
Paul BakausandClaude Opus 4.7 444f881295 fix(test): un-ignore fixture dist/ trees so they actually track
Top-level .gitignore excludes dist/ broadly, which silently dropped the
multipage-with-generator fixture's files/dist/*.html from the previous
commit. The fixture tests need those files on disk to copy into the
tmp repo and assert is-generated behavior — without them, the test
suite fails on a fresh clone.

Added a negation pattern that re-includes tests/framework-fixtures/**/dist/
paths. The real dist/ output directories elsewhere in the repo remain
ignored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:43:35 -07:00
Paul BakausandClaude Opus 4.7 c9c152f0f0 test(live): framework fixture matrix for inject / wrap / is-generated
Five representative project shapes under tests/framework-fixtures/ that
stage into fresh tmp git repos and drive the live scripts against each:

- vite-react: tracked index.html shell + src/App.jsx
- nextjs-app: app/layout.tsx as JSX inject target
- astro: src/layouts/Layout.astro
- sveltekit: src/app.html shell + src/routes/+page.svelte
- multipage-with-generator: src/ tracked, dist/ gitignored (our own
  repo's shape); exercises the is-generated guard and
  element_not_in_source fallback

Each fixture declares its config, expected source/generated paths, and
wrap cases in fixture.json. The harness copies into tmpdir, applies
gitignore, commits, then asserts:

- inject --port lands the script tag at the correct anchor across all
  configured files
- inject --remove strips it cleanly
- is-generated classifies source vs generated paths correctly
- wrap routes to the expected source file or emits the expected
  fallback error

Plumbing + bug caught while building out the matrix:

- IMPECCABLE_LIVE_CONFIG env var so tests can point live-inject at a
  fixture-specific config.json without clobbering the harness copy.
  Backwards-compatible.
- live-wrap.mjs no longer hardcodes dist/build in its directory skip
  list. Only node_modules and .git remain universal skips; the
  isGeneratedFile check is now the sole guard for generated paths. This
  lets the includeGenerated second pass find elements in dist/ and
  report generatedMatch, which is what the multipage-with-generator
  fixture needs to exercise.

Wired into bun run test. 25 tests, 5 suites.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:42:28 -07:00