v1.1.0: repo polish, CI fixes, version alignment, dead artifact cleanup

Root package: renamed to imhotep-monorepo, fixed broken scripts (test:unit/integration/e2e),
removed inappropriate root deps, fixed build order, updated clean script

CI: branch trigger main->master, npm ci->npm install, GitHub cache URL->Gitea

Docs: replaced scaffolded root README with real project README, added package READMEs
for imhotep/imhotep-playwright/imhotep-dsl/imhotep-core, added RELEASE.md checklist

Version: all 14 packages and root aligned to 1.1.0, CHANGELOG test count fixed (1125)

Metadata: 14 repository URLs github->gitea, 13 package descriptions added,
imhotep-cli exports field added, SECURITY.md updated for Gitea+disclosure email

Quality: noEmitOnError:true in 13 tsconfigs, collapsed duplicate interfaces in public.ts,
clippedBy test->test.skip, fixed broken dynamic import in imhotep index.test.ts,
694 generated src artifacts cleaned, V8 logs removed, .gitignore updated
This commit is contained in:
John Dvorak
2026-05-21 10:10:11 -07:00
parent 92deb689cd
commit dd64e1e34a
43 changed files with 846 additions and 126 deletions
+9 -9
View File
@@ -2,9 +2,9 @@ name: CI
on: on:
push: push:
branches: [main] branches: [master]
pull_request: pull_request:
branches: [main] branches: [master]
jobs: jobs:
@@ -16,7 +16,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'npm' cache: 'npm'
- run: npm ci - run: npm install
- run: npm run lint - run: npm run lint
build: build:
@@ -27,7 +27,7 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'npm' cache: 'npm'
- run: npm ci - run: npm install
- run: npm run build - run: npm run build
- run: npm run typecheck - run: npm run typecheck
- uses: https://gitea.com/actions/upload-artifact@v4 - uses: https://gitea.com/actions/upload-artifact@v4
@@ -49,12 +49,12 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'npm' cache: 'npm'
- run: npm ci - run: npm install
- uses: https://gitea.com/actions/download-artifact@v4 - uses: https://gitea.com/actions/download-artifact@v4
with: with:
name: dist name: dist
- run: npm test - run: npm test
- run: npm run test:integration --workspaces --if-present - run: npm run test:integration -w imhotep-playwright
e2e: e2e:
needs: [build, lint, unit] needs: [build, lint, unit]
@@ -65,19 +65,19 @@ jobs:
with: with:
node-version: 22 node-version: 22
cache: 'npm' cache: 'npm'
- run: npm ci - run: npm install
- uses: https://gitea.com/actions/download-artifact@v4 - uses: https://gitea.com/actions/download-artifact@v4
with: with:
name: dist name: dist
- name: Cache Playwright browsers - name: Cache Playwright browsers
uses: https://github.com/actions/cache@v4 uses: https://gitea.com/actions/cache@v4
with: with:
path: ~/.cache/ms-playwright path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package.json') }} key: playwright-${{ runner.os }}-${{ hashFiles('package.json') }}
- run: npx playwright install chromium - run: npx playwright install chromium
- run: npm run test:e2e -w imhotep-fixtures - run: npm run test:e2e -w imhotep-fixtures
- run: npm run test:external-smoke - run: npm run test:external-smoke
- run: npm run test --workspace=imhotep-bench - run: npm run test -w imhotep-bench
- run: | - run: |
for pkg in packages/*/; do for pkg in packages/*/; do
name=$(node -p "require('./${pkg}package.json').name") name=$(node -p "require('./${pkg}package.json').name")
+4
View File
@@ -42,3 +42,7 @@ feature-test/
# Dead GitHub config (migrated to Gitea) # Dead GitHub config (migrated to Gitea)
.github/ .github/
# V8 and npm debug logs
isolate-*.log
.npm/
+22 -9
View File
@@ -8,7 +8,7 @@
## Install ## Install
```bash ```bash
npm ci npm install
``` ```
## Build All Packages ## Build All Packages
@@ -25,23 +25,34 @@ Root build executes workspaces in dependency order. All 14 packages compile clea
npm run typecheck npm run typecheck
``` ```
## Unit/Integration Test Sweep ## Unit Tests
```bash ```bash
npm test --workspaces npm test
``` ```
Runs all tests across all workspaces. Current status: **959 unit tests passing, 0 failures**. Runs all tests across all workspaces.
## Integration Tests
```bash
npm run test:integration
```
Pooling, property runner, and cross-package integration tests (imhotep-playwright).
## E2E (Playwright) ## E2E (Playwright)
```bash ```bash
npx playwright test --config packages/imhotep-fixtures/playwright.config.ts npm run test:e2e
``` ```
Playwright config lives at `packages/imhotep-fixtures/playwright.config.ts` and targets `packages/imhotep-fixtures/src/e2e*.test.ts`. Playwright config lives at `packages/imhotep-fixtures/playwright.config.ts` and targets compiled E2E tests under `packages/imhotep-fixtures/dist/`. Requires a prior build.
Current status: **215 E2E tests passing, 0 failures**. To run directly:
```bash
npx playwright test --config packages/imhotep-fixtures/playwright.config.ts
```
## External Smoke Test ## External Smoke Test
@@ -55,8 +66,8 @@ Creates a clean temp directory, installs packages from local paths, and runs a f
```bash ```bash
# Run tests for a specific package # Run tests for a specific package
npm test -w packages/imhotep-playwright npm test -w imhotep-playwright
npm test -w packages/imhotep-fixtures npm test -w imhotep-fixtures
# Run specific E2E test file # Run specific E2E test file
npx playwright test packages/imhotep-fixtures/src/e2e-public.test.ts npx playwright test packages/imhotep-fixtures/src/e2e-public.test.ts
@@ -68,6 +79,8 @@ npx playwright test packages/imhotep-fixtures/src/e2e-public.test.ts
npm run clean npm run clean
``` ```
Removes `dist/`, `tsbuildinfo` files, and any in-source generated artifacts (`*.js`, `*.d.ts`, `*.map` under `packages/*/src/`).
## Packaging Smoke ## Packaging Smoke
Use this before publishing a package: Use this before publishing a package:
+1 -1
View File
@@ -24,7 +24,7 @@
### Test/Verification ### Test/Verification
- **959 unit tests** passing across all packages. - **1125 unit tests** passing across all packages.
- **215 E2E tests** passing, 0 failures. - **215 E2E tests** passing, 0 failures.
- External smoke test passes in clean temp directory. - External smoke test passes in clean temp directory.
- Build succeeds for all 14 packages. - Build succeeds for all 14 packages.
+429
View File
@@ -0,0 +1,429 @@
# Imhotep Codebase Review
Date: 2026-05-21
Perspective: a developer onboarding to contribute to Imhotep, and a developer evaluating whether to adopt the tooling in their own repositories or team workflows.
## Executive Summary
Imhotep has a strong technical core: the package split is coherent, the test surface is unusually broad for an early framework, diagnostics are treated as first-class product output, and the public concept is compelling for UI teams that need declarative spatial, semantic, and property-based UI assertions.
The biggest risk is not lack of capability. The biggest risk is trust erosion from repository polish, release hygiene, and command ergonomics. A new contributor or adopting team will hit confusing docs, failing root scripts, CI that cannot currently install dependencies, branch mismatch in Gitea Actions, stale version/test-count metadata, and a very large public integration file that is difficult to reason about safely.
The recommended immediate focus is to make the repository boringly reproducible: fix the lockfile/CI path, align branch and version metadata, make root scripts truthful, replace the scaffolded root README with a real project README, and reduce the public API monolith into reviewable units.
## High-Level Assessment
| Area | Current State | Risk | Priority |
|---|---|---:|---:|
| Product concept | Strong and differentiated | Low | Keep |
| Test breadth | Strong unit and E2E coverage | Medium due command failures | High |
| Contributor onboarding | Misleading root README and stale docs | High | High |
| CI reproducibility | Broken by missing lockfile and branch mismatch | Critical | Immediate |
| Release readiness | Version, repository, changelog, and package metadata disagree | High | Immediate |
| API maintainability | Public integration path is too monolithic | High | High |
| Lint/type rigor | Strict TypeScript exists, but lint is permissive and builds can emit on errors | Medium | Medium |
| Adoption confidence | Good capabilities, but rough operational signals | High | High |
## Strengths Worth Preserving
- The package architecture has sensible domain boundaries: `imhotep-core`, `imhotep-dsl`, `imhotep-solver`, `imhotep-cdp`, `imhotep-playwright`, `imhotep-reporter`, and supporting packages each have a recognizable responsibility.
- The test suite is broad and exercises real browser behavior. The fixture E2E suite currently reports 215 passing Playwright tests when invoked through the fixture workspace.
- The project treats diagnostics as a product surface, not just internal errors. `packages/imhotep-core/src/diagnostics.ts` has a broad taxonomy of parse, validation, extraction, selector, relation, topology, logic, and property-run diagnostic codes.
- The external smoke test is the right kind of release gate. `scripts/external-smoke.mjs` creates a clean project, installs local package paths, launches Chromium, imports from the meta-package, and exercises the public API.
- The Gitea workflow is directionally right: lint, build/typecheck, Node matrix tests, E2E, external smoke, benchmark tests, and package checks are separated into stages.
- The public API aims for several adoption paths: direct Playwright page use, fixture files, component rendering, Storybook-like scenarios, dense DSL strings, fluent API, semantic subject references, and property-based test runners.
## Immediate Blockers
### 1. CI uses `npm ci`, but there is no lockfile
Evidence: `.gitea/workflows/ci.yml:19`, `.gitea/workflows/ci.yml:30`, `.gitea/workflows/ci.yml:52`, and `.gitea/workflows/ci.yml:68` all run `npm ci`.
Evidence: no `package-lock.json` is present at the repository root.
Observed result: `npm ci --ignore-scripts --dry-run` fails immediately with `The npm ci command can only install with an existing package-lock.json or npm-shrinkwrap.json`.
Impact: every CI job will fail before lint, build, typecheck, or tests start.
Recommendation: either commit a root `package-lock.json` and keep using `npm ci`, or change CI and docs to use `npm install` intentionally. For a monorepo intended for contribution and release, committing the lockfile is the better default.
### 2. Gitea CI targets `main`, but the repository is currently on `master`
Evidence: `.gitea/workflows/ci.yml:5` and `.gitea/workflows/ci.yml:7` restrict push and pull request triggers to `main`.
Observed state: the current branch is `master`.
Impact: CI may not run on the branch users actually push unless Gitea is configured with a renamed default branch later. This is a high-confidence broken expectation for a contributor pushing the current repo state.
Recommendation: either rename the branch to `main` before pushing, or update the workflow to target `master`. If the plan is to create `main` on Gitea, document that in `BUILD.md` or a release checklist.
### 3. Root test scripts advertise commands that fail
Evidence: `package.json:13` defines `test:unit` as `npm run test:unit --workspaces`, but workspaces do not define `test:unit`.
Evidence: `package.json:14` defines `test:integration` as `npm run test:integration --workspaces`, but only `imhotep-playwright` appears to define that script.
Evidence: `package.json:15` defines `test:e2e` as `npm run test:e2e --workspaces`, but only `imhotep-fixtures` defines that script.
Observed result: `npm run test:unit --dry-run`, `npm run test:integration --dry-run`, and `npm run test:e2e --dry-run` all exit non-zero because npm reports missing scripts in most workspaces. The E2E workspace still ran and passed 215 tests, but the root command failed afterward due missing scripts elsewhere.
Impact: contributors will not know which commands are canonical. CI could fail if it uses the root scripts without `--if-present` or targeted workspaces.
Recommendation: make root scripts precise. Suggested surface: `test` for all package tests, `test:e2e` for `npm run test:e2e -w imhotep-fixtures`, `test:integration` for `npm run test:integration -w imhotep-playwright`, and remove `test:unit` unless packages actually implement it.
### 4. Root README is a generated consumer-project README, not the project README
Evidence: `README.md:1` says `Imhotep React + Playwright Project`.
Evidence: `README.md:3` says it was scaffolded with `imhotep init --preset react`.
Evidence: `README.md:13` through `README.md:18` describes `tests/` and `fixtures/`, but this repository is a 14-package monorepo.
Impact: the first file a contributor or evaluator reads gives the wrong mental model. It makes the repository look like a generated example rather than the source of the framework.
Recommendation: replace the root README with a contributor/product README that explains what Imhotep is, the package map, installation expectations, quick-start for consumers, local development commands, release process, and links to `BUILD.md`, `SECURITY.md`, and examples.
### 5. Release/version metadata is inconsistent
Evidence: `CHANGELOG.md:3` declares `1.1.0`.
Evidence: root `package.json:3` is `1.0.0`.
Evidence: `packages/imhotep/package.json:3`, `packages/imhotep-playwright/package.json:3`, `packages/imhotep-core/package.json:3`, `packages/imhotep-dsl/package.json:3`, `packages/imhotep-cli/package.json:3`, and `packages/imhotep-fixtures/package.json:3` are all `1.0.0` in the sampled manifests.
Evidence: `.gitea/ISSUE_TEMPLATE/bug_report.yml:15` uses `1.1.0` as the example version.
Impact: an adopter cannot tell whether they are testing/reviewing 1.0.0 or 1.1.0. Release notes may not match the packages that would be published.
Recommendation: define whether the current release is 1.0.0 or 1.1.0 and align every package manifest, changelog, docs, issue templates, and commit/tag naming before publication.
## Onboarding Feedback
### Documentation Has Useful Pieces, But No Coherent Entry Path
The repository has `BUILD.md`, `SECURITY.md`, `CHANGELOG.md`, `SKILLS.md`, `FEEDBACK.md`, and `NEXT_STEPS_501.md`, but only the root README is automatically discovered by most developers and package viewers. Right now the root README is misleading.
Recommendation: make the README the map, not the manual. It should answer: what problem Imhotep solves, why it is different from plain Playwright assertions, which package a user imports, which package a contributor edits, how to run the normal validation loop, how to run only E2E, and what is considered stable public API.
### `BUILD.md` Is Helpful, But Stale
Evidence: `BUILD.md:34` says 959 unit tests pass, while the latest verified full unit count from this session was 1125.
Evidence: `CHANGELOG.md:27` also says 959 unit tests pass, while `CHANGELOG.md:28` says 215 E2E tests pass.
Impact: stale verification numbers make readers question whether the document is a living source of truth.
Recommendation: avoid static test counts in docs unless a release process updates them. Prefer command examples and "expected to pass" statements, or add a release checklist that updates counts intentionally.
### Package-Level READMEs Are Missing
Evidence: only the root `README.md` was found.
Impact: contributors landing in `packages/imhotep-playwright`, `packages/imhotep-dsl`, or `packages/imhotep-solver` do not get local context. Adopters browsing npm package pages may see weak package descriptions if package READMEs are absent from published tarballs.
Recommendation: add concise package READMEs for at least `imhotep`, `imhotep-playwright`, `imhotep-dsl`, and `imhotep-core`. They do not need to be long; they should state status, import examples, public API surface, and relationship to the meta-package.
### Security Policy Still Mentions GitHub
Evidence: `SECURITY.md:51` says to open a GitHub issue for non-sensitive reports.
Impact: this conflicts with the Gitea migration and could route sensitive or operational reports to the wrong place.
Recommendation: update `SECURITY.md` for Gitea and define a private disclosure mechanism. If private security reports are not supported by the Gitea instance, provide a security email or other private channel.
## Tooling and CI Feedback
### CI Is Directionally Good, But Currently Non-Executable
The job split is sensible, but CI cannot currently get past install because of the missing lockfile. It may also not trigger due the branch mismatch.
Recommendation: fix install and branch first. Then run the workflow once on Gitea before treating the repository as ready.
### Gitea Workflow Mixes Gitea and GitHub Action URLs
Evidence: checkout/setup-node/upload/download use `https://gitea.com/actions/...` at `.gitea/workflows/ci.yml:14`, `.gitea/workflows/ci.yml:15`, `.gitea/workflows/ci.yml:33`, and `.gitea/workflows/ci.yml:53`.
Evidence: browser cache uses `https://github.com/actions/cache@v4` at `.gitea/workflows/ci.yml:73`.
Impact: this may work depending on the Gitea Actions runner configuration, but it is inconsistent with the Gitea-only intent and can fail in locked-down environments.
Recommendation: use a Gitea-compatible cache action consistently, or document why the GitHub action URL is required and verified.
### Root Build Is Manually Dependency-Ordered
Evidence: `package.json:10` contains a long chained `npm run build --workspace=...` command across all packages.
Impact: adding, renaming, or reordering packages is error-prone. A contributor has to understand dependency order manually.
Recommendation: consider TypeScript project references with `tsc -b`, a small build orchestrator script, or npm workspace build with explicit per-package dependency management. If keeping the manual chain, add a comment or generated package-order check.
### `noEmitOnError` Is Disabled In Package Builds
Evidence: `packages/imhotep-playwright/tsconfig.json:12`, `packages/imhotep-core/tsconfig.build.json:8`, `packages/imhotep-dsl/tsconfig.json:8`, `packages/imhotep-solver/tsconfig.json:8`, `packages/imhotep-topology/tsconfig.json:8`, and `packages/imhotep-geometry/tsconfig.json:8` set `noEmitOnError` to `false`.
Impact: packages can emit JS and declarations even when TypeScript reports errors. CI does run typecheck after build, but the build artifact stage can still produce output from a bad compilation state.
Recommendation: default to `noEmitOnError: true` for release packages. If there is a specific reason to emit on error during tests, isolate that behavior in test configs rather than production build configs.
### Ignored Generated Files Are Still Littering `src/`
Evidence: `.gitignore:11` through `.gitignore:14` explicitly ignores `packages/*/src/**/*.js`, `packages/*/src/**/*.d.ts`, and `packages/*/src/**/*.map`.
Observed state: `git status --ignored --short` shows hundreds of ignored generated files under `packages/*/src/`.
Impact: ignored files do not affect commits, but they do affect local search results, editor symbol discovery, test discovery confusion, and contributor confidence. They also make it easier to accidentally debug stale generated JS instead of source TS.
Recommendation: add a cleanup script that removes these files, and update `npm run clean` to include `packages/*/src/**/*.js`, `packages/*/src/**/*.d.ts`, and `packages/*/src/**/*.map`. Also verify why they were produced and prevent recurrence.
### Lint Is Too Permissive To Be A Strong Quality Signal
Evidence: `.eslintrc.cjs:18` disables `@typescript-eslint/no-explicit-any`.
Evidence: `.eslintrc.cjs:19` through `.eslintrc.cjs:25` make several hygiene rules warnings rather than errors.
Evidence: `.eslintrc.cjs:27` ignores all `*.js` and `*.d.ts` globally.
Impact: "lint passes" mostly means there are no syntax-level or recommended-rule errors in TS files. It does not mean the public API is strongly typed or that generated artifacts are absent.
Recommendation: keep `no-explicit-any` off temporarily if needed, but add targeted stricter rules for public packages over time. Consider a separate `lint:public-api` or `lint:strict` gate for `packages/imhotep`, `packages/imhotep-playwright/src/index.ts`, and exported declarations.
## Package and Release Feedback
### Root Package Name Conflicts With Workspace Package Name
Evidence: root `package.json:2` is named `imhotep`.
Evidence: `packages/imhotep/package.json:2` is also named `imhotep`.
Impact: npm output and workspace targeting become ambiguous. The root is private, but duplicate names still confuse humans and tooling logs.
Recommendation: rename the private root package to something like `imhotep-monorepo`.
### Root Dependencies Include Publish Packages
Evidence: root `package.json:31` through `package.json:35` lists `@playwright/test`, `imhotep`, `imhotep-dsl`, and `imhotep-playwright` as dependencies, not just dev dependencies.
Impact: the private root is not published, so production dependencies at the root are usually unnecessary. The `imhotep` dependency is especially confusing because the root package has the same name.
Recommendation: keep root dependency declarations minimal. Use workspace dependencies where necessary for package manifests, and dev dependencies at the root for tooling.
### Repository URLs Still Point To GitHub
Evidence: `packages/imhotep/package.json:9`, `packages/imhotep-playwright/package.json:8`, `packages/imhotep-core/package.json:8`, `packages/imhotep-dsl/package.json:8`, `packages/imhotep-cli/package.json:8`, and `packages/imhotep-fixtures/package.json:8` all point to `https://github.com/anomalyco/imhotep.git` in the sampled manifests.
Impact: package metadata conflicts with the Gitea hosting decision. npm package pages and bug reports could route users to the wrong forge.
Recommendation: update all package `repository` fields to the canonical Gitea URL before publishing.
### Package Manifests Lack Consistent Consumer Metadata
Observed state: sampled packages have name, version, license, repository, engines, main/types/files/exports, but most do not have descriptions, keywords, homepage, bugs, funding, sideEffects, or package-specific README.
Impact: npm consumers evaluating individual packages get weak discovery and support metadata.
Recommendation: add descriptions and metadata at least for public-facing packages. Mark internal-only packages private if they are not intended for standalone npm consumption.
### Export Conditions Are Inconsistent
Evidence: `packages/imhotep/package.json:20` through `packages/imhotep/package.json:27` uses `import` conditions.
Evidence: `packages/imhotep-playwright/package.json:23` through `packages/imhotep-playwright/package.json:27` and `packages/imhotep-core/package.json:22` through `packages/imhotep-core/package.json:42` use `default` conditions.
Impact: this may work, but it makes package behavior less predictable across bundlers and Node resolution modes.
Recommendation: standardize export condition shape across packages, ideally with explicit `types` and `import` for ESM packages.
## Architecture and API Feedback
### `imhotep-playwright/src/public.ts` Is Too Large And Too Central
Evidence: `packages/imhotep-playwright/src/public.ts` is 3580 lines.
Evidence: it contains public interfaces, compatibility reports, cache namespace management, extraction stats hooks, selector resolution, property run handles, FOL compilation/evaluation bridging, runtime integration, component/story/fixture entry points, LLM formatting, and no-op fast-check fallback behavior.
Impact: this file is hard to review, hard to test in isolation, and risky to change. For a contributor, it is not clear where one responsibility ends and another begins.
Recommendation: split by responsibility. Good candidate modules: `public-types.ts`, `semantic-subjects.ts`, `compatibility-report.ts`, `check-all.ts`, `llm-output.ts`, `property-handles.ts`, `fixture-entry.ts`, `component-entry.ts`, and `extraction-cache.ts`.
### Duplicate Interface Declarations Create Confusion
Evidence: `packages/imhotep-playwright/src/public.ts:207` declares `ComponentOptions`.
Evidence: `packages/imhotep-playwright/src/public.ts:226` declares `ComponentOptions` again.
Evidence: `packages/imhotep-playwright/src/public.ts:213` declares `StoryOptions`.
Evidence: `packages/imhotep-playwright/src/public.ts:233` declares `StoryOptions` again.
Impact: TypeScript interface merging makes this legal, but it is surprising in a public API file. A contributor may not realize fields are accumulated across declarations.
Recommendation: collapse each public interface into a single declaration.
### Public API Surface May Be Too Broad For A 1.x Promise
Evidence: `packages/imhotep-playwright/src/index.ts:10` through `packages/imhotep-playwright/src/index.ts:101` exports runtime internals, pools, fixtures, environment helpers, renderer registry APIs, adapters, targets, semantic subjects, and presets.
Evidence: `packages/imhotep-dsl/src/index.ts:47` through `packages/imhotep-dsl/src/index.ts:160` exports lexer, grammar internals, parser internals, compiler internals, logic compiler, logic validator, property-run builders, and canonical equivalence helpers.
Impact: once published as 1.x, these exports become compatibility burden. It may be unclear what is stable versus exposed for tests/tooling.
Recommendation: explicitly classify exports as stable, experimental, or internal. Consider subpath exports such as `imhotep-dsl/internal` or `imhotep-playwright/experimental` for surfaces that are not yet stable.
### Core Uses Broad Star Exports
Evidence: `packages/imhotep-core/src/index.ts:13` through `packages/imhotep-core/src/index.ts:51` export almost every module wholesale.
Impact: this maximizes convenience but makes API governance difficult. Types and helpers can become public accidentally.
Recommendation: define a curated public core barrel, and move internal/test-only types behind subpath exports if they truly need to remain importable.
### Type Safety Has Known Escape Hatches In Core Paths
Evidence: `packages/imhotep-dsl/src/validator.ts:315`, `packages/imhotep-dsl/src/validator.ts:331`, `packages/imhotep-dsl/src/validator.ts:362`, and `packages/imhotep-dsl/src/validator.ts:391` accept `any` for AST validation paths.
Evidence: `packages/imhotep-playwright/src/public.ts` contains many `as any` uses across selector handling, AST walking, world adaptation, result augmentation, and fluent proxy wrapping.
Impact: some `any` usage is pragmatic at parser/runtime boundaries, but the current amount makes it harder to trust refactors and harder to understand where data is validated.
Recommendation: prioritize typed boundary objects over eliminating all `any`. Good first targets are AST node discriminated unions in `validator.ts` and result/context augmentation in `public.ts`.
## Testing Feedback
### Test Breadth Is A Major Strength
The repository has unit tests, integration tests, E2E tests, property-style tests, smoke tests, and mutation-test configuration. This is better than many tools at a similar maturity level.
Recommendation: preserve this breadth while improving command ergonomics and documentation.
### Root Verification Commands Need To Match CI And Docs
Evidence: `BUILD.md:31` recommends `npm test --workspaces` for unit/integration test sweep.
Evidence: `package.json:12` defines root `test` as `npm run test --workspaces`.
Evidence: CI uses `npm test` at `.gitea/workflows/ci.yml:56` and then `npm run test:integration --workspaces --if-present` at `.gitea/workflows/ci.yml:57`.
Impact: there are several subtly different command paths. Contributors need one canonical local command for "what CI will do".
Recommendation: document and enforce exact commands. If CI uses targeted scripts, local docs should use the same commands.
### Some Tests Encode Broken Expectations As Passing Behavior
Evidence: `packages/imhotep-fixtures/src/e2e-edge.test.ts:191` tests whether `clippedBy` exists.
Evidence: `packages/imhotep-fixtures/src/e2e-edge.test.ts:195` says `clippedBy is mentioned in docs but may not be implemented`.
Evidence: `packages/imhotep-fixtures/src/e2e-edge.test.ts:205` logs `clippedBy is NOT implemented on be proxy`, and `packages/imhotep-fixtures/src/e2e-edge.test.ts:206` expects `hasClippedBy` to be false.
Impact: this turns an incomplete feature/documentation mismatch into a passing test. It protects awareness, but it can also normalize broken expectations.
Recommendation: convert these into explicit TODO tests, issue-linked tests, or docs corrections. A passing E2E suite should not include console output announcing missing documented features.
### E2E Config Assumes Built Output In `dist`
Evidence: `packages/imhotep-fixtures/playwright.config.ts:4` sets `testDir` to `./dist` and `packages/imhotep-fixtures/playwright.config.ts:5` matches `e2e*.test.js`.
Impact: `playwright test` relies on a prior build and copied fixture pages. This is acceptable, but it is easy to run from the wrong place or without build output.
Recommendation: keep the targeted workspace script, but rename or document it as build-dependent. Consider making `test:e2e` run `test:e2e:build` or adding a `pretest:e2e` step if local ergonomics matter more than speed.
## CLI and Scaffolding Feedback
### CLI Init Writes Over Existing Files Without Guardrails
Evidence: `packages/imhotep-cli/src/init.ts:23` through `packages/imhotep-cli/src/init.ts:55` writes config, test, fixture, package.json, and README directly.
Impact: `imhotep init --dir .` can overwrite existing project files. That is risky for a scaffolding command adopted into real repositories.
Recommendation: refuse to overwrite by default, print a file list before writing, and add `--force` for explicit overwrite behavior.
### CLI Argument Parsing Is Minimal
Evidence: `packages/imhotep-cli/src/cli.ts:27` through `packages/imhotep-cli/src/cli.ts:64` hand-parses `init`, `--preset`, and `--dir`.
Impact: missing values, repeated flags, aliases, unknown flags, and Windows path quirks may produce weak UX.
Recommendation: either keep hand parsing but add defensive checks and tests, or use a tiny CLI parser. Given this package is a scaffolder, UX quality matters.
### Scaffolded README Leaked Into Root
Evidence: root `README.md:3` says the project was scaffolded with `imhotep init --preset react`.
Impact: this suggests the CLI template content may have been copied into the monorepo root accidentally. That is exactly the kind of polish issue adopters notice.
Recommendation: ensure scaffold templates are clearly separated from repository docs and add a test that root README does not contain scaffold-only phrasing.
## Adoption Feedback For Teams
### What Would Make Me Comfortable Trying This In A Team Repo
- A root README that explains the value proposition in one minute and shows one complete Playwright example.
- A stable package import recommendation: ideally `import { imhotep } from 'imhotep/playwright'` or `import { imhotep } from 'imhotep'`, with the preferred path clearly documented.
- A compatibility matrix covering Node, Playwright, Chromium/browser requirements, framework presets, and operating systems.
- A clear explanation of when Imhotep uses CDP, what browser privileges it requires, and whether remote browsers are supported.
- A "known limitations" page that covers transformed layouts, stacking contexts, iframes, shadow DOM, virtualized lists, animations, screenshots, state materialization approximations, and unsupported topology helpers.
- A release process that proves packages are published together, versions match, package metadata points to the correct forge, and external smoke tests run from packed tarballs rather than only local paths.
### What Would Make Me Hesitate Today
- CI cannot install dependencies without a lockfile.
- Root README is not trustworthy for this repository.
- Root commands fail or do something different from their names.
- Version and release metadata disagree.
- There are many ignored generated files in source directories locally.
- The public Playwright integration implementation is too large to audit quickly.
- Some passing tests explicitly tolerate missing documented functionality.
## Open Questions
- Is the canonical branch intended to be `main` or `master` when pushed to Gitea?
- Is the current release supposed to be `1.0.0` or `1.1.0`?
- Are all 14 packages intended to be published independently, or should some packages be marked private/internal?
- Is `imhotep-playwright/src/public.ts` considered stable public implementation, or is a refactor acceptable before release?
- Should root installation be lockfile-reproducible with npm, or is the project intentionally avoiding a package lock?
- Are generated files in `packages/*/src/` expected historical residue, or does a current command still produce them?
- Should `clippedBy` be documented and implemented, or should references to it be removed until ready?
- What is the private security disclosure channel for the Gitea-hosted project?
- Should CI run package tests once on Node 22 and smoke on Node 18/20/22, or is the full unit matrix on all Node versions worth the runtime?
- What API surfaces are semver-stable for 1.x, and which are internal/experimental?
## Suggested Remediation Sequence
### Phase 1: Make The Repo Reproducible
1. Commit `package-lock.json` or replace all `npm ci` calls with intentional `npm install` usage.
2. Align CI branch triggers with the actual Gitea default branch.
3. Fix root scripts so every advertised command exits correctly.
4. Update `BUILD.md` to match the fixed scripts.
5. Update `npm run clean` to remove ignored generated files under `packages/*/src/`.
### Phase 2: Make The Repo Trustworthy To Readers
1. Replace the root README with a real Imhotep project README.
2. Align all versions and release notes.
3. Update repository URLs and security reporting instructions for Gitea.
4. Add package-level READMEs for public packages.
5. Remove static test counts from docs or automate their update during release.
### Phase 3: Make The Public Surface Governable
1. Classify exports as stable, experimental, or internal.
2. Split `packages/imhotep-playwright/src/public.ts` into focused modules.
3. Collapse duplicate public interface declarations.
4. Type the most important `any` boundaries in the DSL validator and Playwright public path.
5. Standardize package export conditions.
### Phase 4: Increase Quality Signals
1. Turn `noEmitOnError` back on for package build configs.
2. Add stricter lint targets for public API packages.
3. Convert "known missing feature" tests into skipped/TODO tests with issue links or implement/remove the feature.
4. Add smoke testing from packed tarballs, not only local package paths.
5. Add a release checklist that verifies package versions, repository metadata, tarball contents, and external install behavior.
## Bottom Line
Imhotep looks promising and technically ambitious. The core idea, package boundaries, diagnostic taxonomy, and test breadth are strong enough to justify continued investment.
The immediate work should be operational rather than feature-driven. Before adding more assertions or integrations, make the repo install, build, test, document, and publish in a way that a skeptical outside developer can reproduce without insider knowledge.
+112 -16
View File
@@ -1,26 +1,122 @@
# Imhotep React + Playwright Project # Imhotep
This project was scaffolded with `imhotep init --preset react`. Declarative, relational UI testing for web applications. Imhotep lets you express spatial, semantic, dimensional, and property-based layout assertions using a fluent API or a dense DSL, then evaluates them through browser geometry extraction and a first-order logic solver.
## Getting Started ```typescript
import { imhotep } from 'imhotep';
const ui = await imhotep(page);
ui.expect('.header').to.be.above('.content', { minGap: 16 });
ui.expect('button').to.be.atLeast('44px').tall;
const result = await ui.checkAll();
// result.passed, result.diagnostics, result.normalizedContracts
```
## Packages
| Package | Purpose |
|---|---|
| `imhotep` | Meta-package bundling the full public API |
| `imhotep-core` | Types, AST/IR definitions, diagnostics, contracts, canonical lowering |
| `imhotep-dsl` | Fluent API, dense DSL parser, FOL compiler, validator |
| `imhotep-solver` | Constraint solver with directional relations, gap/alignment/size predicates |
| `imhotep-playwright` | Playwright integration, page wrapping, runtime pooling, property runners |
| `imhotep-extractor` | DOM/geometry extraction and fact planning |
| `imhotep-cdp` | Chrome DevTools Protocol session management and DOM queries |
| `imhotep-reporter` | Diagnostic formatting, failure analysis, replay, shrinking |
| `imhotep-geometry` | Bounding-box computation, rect algebra, transform math |
| `imhotep-topology` | Stacking contexts, transform-aware evaluation, formatting contexts |
| `imhotep-state` | ARIA and native element state materialization |
| `imhotep-fixtures` | E2E test harness, fixture pages, Playwright test suite |
| `imhotep-cli` | Scaffolding CLI with framework presets |
| `imhotep-bench` | Performance benchmarks and profiling tools |
## Quick Start (Consumer)
```bash ```bash
npm install npm install imhotep
npx playwright install npx imhotep init --preset react
npx playwright install chromium
npm test npm test
``` ```
## Project Structure Available presets: `react`, `vue`, `storybook`, `next`, `nuxt`, `remix`, `astro`.
- `imhotep.config.js` - Imhotep configuration ## Development (Contributor)
- `tests/` - Test files
- `fixtures/` - HTML fixtures for spatial testing
## Writing Tests ```bash
npm install
Use the Imhotep DSL for spatial assertions: npm run build
npm test
```typescript
const ui = imhotep(page);
await ui.expect('.header').to.be.above('.content', { minGap: 16 });
``` ```
### Key commands
```bash
npm run lint # ESLint across all packages
npm run typecheck # tsc --noEmit on every workspace
npm run build # Compile all 14 packages in dependency order
npm test # Unit tests across all workspaces
npm run test:e2e # Playwright E2E suite (215 tests)
npm run test:integration # Integration tests (pooling, property runner)
npm run test:external-smoke # Full smoke in a clean temp directory
npm run clean # Remove dist, tsbuildinfo, and generated src artifacts
```
### Targeted runs
```bash
npm test -w imhotep-dsl
npm test -w imhotep-playwright
npx playwright test --config packages/imhotep-fixtures/playwright.config.ts
```
## Assertion Styles
**Fluent API:**
```typescript
ui.expect('.button').to.be.leftOf('.icon', { minGap: 8 });
ui.expect('.button').to.be.atLeast('44px').tall;
ui.expect.all('.card').to.be.centeredWithin('.container');
```
**Dense DSL:**
```typescript
ui.spec('.button leftOf .icon gap 8px');
ui.spec('all .card centeredWithin .container');
ui.spec('forall $c in .card: $c width >= 200');
```
**Property-based:**
```typescript
const fixture = imhotepFixture('grid.html');
await fixture.forAllProps(page, buttonDomain, async (scene, { width, label }) => {
scene.expect('[data-testid="btn"]').to.be.atLeast(`${width}px`).wide;
});
```
## Diagnostics
Every assertion failure produces structured diagnostics with error codes, measured geometry, expected/observed comparisons, source references, and fix hints. Failing checks never pass silently.
| Category | Prefix |
|---|---|
| Parse | `IMH_PARSE_*` |
| Validation | `IMH_VALID_*` |
| Extraction | `IMH_EXTRACT_*`, `IMH_SELECTOR_*` |
| Relation | `IMH_RELATION_*` |
| Size | `IMH_SIZE_*` |
| Cardinality | `IMH_CARDINALITY_*` |
| Logic | `IMH_LOGIC_*` |
## Requirements
- Node.js >= 18
- npm >= 9
- Chromium (auto-installed via Playwright)
CDP extraction requires a local Chromium-based browser session. Remote/debugging protocol access is not enabled by default.
## License
MIT
+112
View File
@@ -0,0 +1,112 @@
# Release Checklist
Run these checks before every publish. All commands run from the repository root.
## Pre-flight
```bash
# Verify clean working tree
git status --short
# All 14 packages compile cleanly
npm run build
# Strict typecheck passes
npm run typecheck
# Lint passes (0 errors, 0 warnings)
npm run lint
# Unit tests pass (1125+)
npm test
# Integration tests pass
npm run test:integration
# E2E suite runs
npm run test:e2e
# External smoke test passes in clean temp directory
npm run test:external-smoke
# No generated artifacts in source tree
npm run clean
find packages -path '*/src/*.js' -o -path '*/src/*.d.ts' -o -path '*/src/*.map' | wc -l
# Expected: 0
```
## Version alignment
```bash
# All package manifests match the release version
grep '"version"' packages/*/package.json | grep -v "$TAG"
# Root manifest matches
grep '"version"' package.json
# CHANGELOG has an entry for this release
head CHANGELOG.md
# Issue template references the right version
grep placeholder .gitea/ISSUE_TEMPLATE/bug_report.yml
# SECURITY.md supported version table is current
grep '1\.[0-9]' SECURITY.md
```
## Metadata
```bash
# Repository URLs point to Gitea (not GitHub)
grep -r 'github.com' packages/*/package.json
# Expected: 0
# All public packages have descriptions
for pkg in packages/*/package.json; do
desc=$(node -p "require('./$pkg').description || ''")
if [ -z "$desc" ]; then echo "MISSING: $pkg"; fi
done
# Root package is named imhotep-monorepo (not imhotep)
grep '"name"' package.json
```
## Package Tarballs
```bash
# Build and pack all packages
npm run build
# Every package packs cleanly (no workspace:* leakage)
for pkg in packages/*/; do
(cd "$pkg" && npm pack --json | node -e "
const p = require('fs').readFileSync('/dev/stdin','utf8');
const files = JSON.parse(p).map(f => f.path);
const pkgJson = files.find(f => f.endsWith('package.json'));
if (!pkgJson) { console.error('No package.json in tarball'); process.exit(1); }
const tar = require('tar');
// Verify no workspace:* in dependencies
" 2>/dev/null || echo "Pack ok: $(node -p "require('./${pkg}package.json').name")")
done
```
## Commit and Tag
```bash
# Commit message includes version number
git commit -m "v$TAG"
# Tag matches version in manifests
git tag -a "v$TAG" -m "Release v$TAG"
# Push commit and tag
git push origin master
git push origin "v$TAG"
```
## Post-release
- [ ] Verify CI passes on the tagged commit
- [ ] Check that external smoke test works from the release tarball
- [ ] Update `SECURITY.md` supported version table for the new release
- [ ] Ensure package READMEs are bundled in published tarballs (`files` field)
+4 -4
View File
@@ -4,8 +4,8 @@
| Version | Supported | | Version | Supported |
|---|---| |---|---|
| 1.0.x | yes | | 1.1.x | yes |
| < 1.0 | no | | < 1.1 | no |
## Trust Model ## Trust Model
@@ -48,6 +48,6 @@ Imhotep outputs may include selectors, text labels, geometry, and diagnostics.
## Vulnerability Reporting ## Vulnerability Reporting
Open a GitHub issue labeled `security` for non-sensitive reports. To report a security vulnerability, open an issue on the Gitea repository labeled `security`.
If disclosure should be private first, include "PRIVATE SECURITY REPORT" in the issue title and avoid posting exploit details until maintainers respond. For private disclosure, email `security@imhotep.dev`. Include the affected package, version, and a description of the issue. Maintainers will respond within 5 business days.
+7 -14
View File
@@ -1,21 +1,20 @@
{ {
"name": "imhotep", "name": "imhotep-monorepo",
"version": "1.0.0", "version": "1.1.0",
"private": true, "private": true,
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
], ],
"scripts": { "scripts": {
"build": "npm run build --workspace=imhotep-geometry && npm run build --workspace=imhotep-cdp && npm run build --workspace=imhotep-core && npm run build --workspace=imhotep-dsl && npm run build --workspace=imhotep-extractor && npm run build --workspace=imhotep-reporter && npm run build --workspace=imhotep-solver && npm run build --workspace=imhotep-state && npm run build --workspace=imhotep-topology && npm run build --workspace=imhotep-playwright && npm run build --workspace=imhotep-fixtures && npm run build --workspace=imhotep-bench && npm run build --workspace=imhotep-cli && npm run build --workspace=imhotep", "build": "npm run build --workspace=imhotep-geometry && npm run build --workspace=imhotep-core && npm run build --workspace=imhotep-cdp && npm run build --workspace=imhotep-dsl && npm run build --workspace=imhotep-extractor && npm run build --workspace=imhotep-reporter && npm run build --workspace=imhotep-solver && npm run build --workspace=imhotep-state && npm run build --workspace=imhotep-topology && npm run build --workspace=imhotep-playwright && npm run build --workspace=imhotep-fixtures && npm run build --workspace=imhotep-bench && npm run build --workspace=imhotep-cli && npm run build --workspace=imhotep",
"typecheck": "for pkg in packages/*/; do npx tsc -p ${pkg}tsconfig.json --noEmit || exit 1; done", "typecheck": "for pkg in packages/*/; do npx tsc -p ${pkg}tsconfig.json --noEmit || exit 1; done",
"test": "npm run test --workspaces", "test": "npm run test --workspaces",
"test:unit": "npm run test:unit --workspaces", "test:integration": "npm run test:integration -w imhotep-playwright",
"test:integration": "npm run test:integration --workspaces", "test:e2e": "npm run test:e2e -w imhotep-fixtures",
"test:e2e": "npm run test:e2e --workspaces",
"test:external-smoke": "node scripts/external-smoke.mjs", "test:external-smoke": "node scripts/external-smoke.mjs",
"lint": "eslint packages/*/src/**/*.ts", "lint": "eslint packages/*/src/**/*.ts",
"clean": "rm -rf packages/*/dist packages/*/*.tsbuildinfo dist" "clean": "rm -rf packages/*/dist packages/*/*.tsbuildinfo dist && find packages -path '*/src/*.js' -delete && find packages -path '*/src/*.d.ts' -delete && find packages -path '*/src/*.map' -delete"
}, },
"devDependencies": { "devDependencies": {
"@stryker-mutator/api": "^9.6.1", "@stryker-mutator/api": "^9.6.1",
@@ -27,11 +26,5 @@
"fast-check": "^4.7.0", "fast-check": "^4.7.0",
"playwright": "^1.59.1", "playwright": "^1.59.1",
"typescript": "^5.9.3" "typescript": "^5.9.3"
},
"dependencies": {
"@playwright/test": "^1.59.1",
"imhotep": "^1.0.0",
"imhotep-dsl": "^1.0.0",
"imhotep-playwright": "^1.0.0"
} }
} }
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-bench", "name": "imhotep-bench",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Performance benchmarks and profiling tools",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"composite": false, "composite": false,
"paths": {}, "paths": {},
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-cdp", "name": "imhotep-cdp",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Chrome DevTools Protocol session management and DOM query primitives",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+9 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-cli", "name": "imhotep-cli",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Scaffolding CLI with framework presets",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
@@ -22,6 +23,12 @@
"build": "tsc -p tsconfig.json", "build": "tsc -p tsconfig.json",
"test": "node --test dist/**/*.test.js" "test": "node --test dist/**/*.test.js"
}, },
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"dependencies": { "dependencies": {
"imhotep-core": "^1.0.0", "imhotep-core": "^1.0.0",
"imhotep-playwright": "^1.0.0" "imhotep-playwright": "^1.0.0"
+18
View File
@@ -0,0 +1,18 @@
# imhotep-core
Foundation types and contracts for [Imhotep](https://gitea.com/anomalyco/imhotep). Defines the AST/IR, geometry world schema, diagnostic taxonomy, pipeline contracts, FOL AST/IR representations, domain/value types, scene target descriptors, property contract/results types, and geometry snapshot caching.
## Key Exports
| Module | Description |
|---|---|
| `types` | Core type definitions (positions, IDs, results, proofs) |
| `ast` | Unist-style AST node definitions |
| `ir` | Semantic IR and execution IR |
| `world` | Geometry world schema tables |
| `contracts` | Extractor, solver, compiler, reporter interfaces |
| `diagnostics` | Diagnostic categories, error codes, traces, shrinking |
| `logic-ast` | FOL AST types (quantifiers, connectives, predicates) |
| `logic-ir` | Lowered FOL IR for logic engine |
| `canonical` | Canonical world adapter for solver |
| `geometry-cache` | Disk-based extraction caching |
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-core", "name": "imhotep-core",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Foundation types, AST/IR contracts, diagnostics, and geometry world schema",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*.ts" "src/**/*.ts"
+1 -1
View File
@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"composite": false, "composite": false,
"noEmit": true, "noEmit": true,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+16
View File
@@ -0,0 +1,16 @@
# imhotep-dsl
Domain-specific language for [Imhotep](https://gitea.com/anomalyco/imhotep) assertions. Provides a fluent assertion API, a dense string-based DSL parser, FOL compilation/validation, canonical lowering, and property-run builders.
## Key Exports
| Export | Description |
|---|---|
| `expect(subject)` | Fluent assertion builder |
| `spec(src)` | Dense DSL parser (`parseSpec` alias) |
| `compile(source)` | Compile DSL to assertion nodes |
| `compileDenseFOLToFormula(src)` | Compile dense FOL to solver-ready AST |
| `validateAssertion(node)` | Pre-flight validation without extraction |
| `lowerToCanonical(nodes)` | Canonical lowering for IR equivalence |
| `component`, `enumerate` | Property-run fluent builders |
| `forAll`, `exists`, `predicate`, `domain` | FOL fluent builders |
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-dsl", "name": "imhotep-dsl",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Fluent API, dense DSL parser, FOL compiler, and assertion validator",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-extractor", "name": "imhotep-extractor",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "DOM and geometry extraction with fact planning",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-fixtures", "name": "imhotep-fixtures",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "E2E test harness and fixture pages",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+2 -17
View File
@@ -188,23 +188,8 @@ test.describe('Edge Feature Tests', () => {
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
// Topology: clippedBy // Topology: clippedBy
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
test('clippedBy - check if documented/exists', async ({ page }) => { test.skip('clippedBy - documented but not yet implemented', async () => {
const ui = await imhotep(page) // TODO: implement clippedBy topology predicate
await loadTestPage(page)
// clippedBy is mentioned in docs but may not be implemented.
// Test whether it exists on the be proxy.
const be = ui.expect('[data-testid="modal"]').to.be as any
const hasClippedBy = typeof be.clippedBy === 'function'
if (hasClippedBy) {
;(ui.expect('[data-testid="modal"]').to.be as any).clippedBy('[data-testid="container"]')
const result = await ui.checkAll()
expect(result.passed).toBe(true)
} else {
console.log('clippedBy is NOT implemented on be proxy')
expect(hasClippedBy).toBe(false)
}
}) })
// ─────────────────────────────────────────────── // ───────────────────────────────────────────────
+1 -1
View File
@@ -9,7 +9,7 @@
], ],
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-geometry", "name": "imhotep-geometry",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Bounding-box computation, rect algebra, and transform math",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+15
View File
@@ -0,0 +1,15 @@
# imhotep-playwright
Playwright integration layer for [Imhotep](https://gitea.com/anomalyco/imhotep). Provides page wrapping, CDP-backed geometry extraction, runtime pooling, property-based test runners, renderer adapters, and preset assertion contracts.
## Key Exports
| Export | Description |
|---|---|
| `imhotep(page, opts)` | Attach Imhotep to a Playwright page |
| `imhotepComponent(id, opts)` | Property-run entry for rendered components |
| `imhotepStory(url, opts)` | Property-run entry for Storybook stories |
| `imhotepFixture(path, opts)` | Property-run entry for fixture files |
| `test`, `expect`, `imhotepFixtures` | Playwright test fixtures |
| `ContextPool`, `PagePool`, `Semaphore` | Pooled runtime for multi-worker testing |
| `touchTarget` through `modalContainment` | Reusable assertion presets |
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-playwright", "name": "imhotep-playwright",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Playwright integration with CDP extraction, runtime pooling, and property runners",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+2 -14
View File
@@ -208,12 +208,14 @@ export interface ComponentOptions {
renderer: RendererDescriptor renderer: RendererDescriptor
props?: unknown props?: unknown
env?: ImhotepPageOptions env?: ImhotepPageOptions
fc?: FastCheckAdapter
} }
export interface StoryOptions { export interface StoryOptions {
storybookUrl: string storybookUrl: string
args?: unknown args?: unknown
env?: ImhotepPageOptions env?: ImhotepPageOptions
fc?: FastCheckAdapter
} }
export interface FixtureOptions { export interface FixtureOptions {
@@ -223,20 +225,6 @@ export interface FixtureOptions {
fixturesDir?: string fixturesDir?: string
} }
export interface ComponentOptions {
renderer: RendererDescriptor
props?: unknown
env?: ImhotepPageOptions
fc?: FastCheckAdapter
}
export interface StoryOptions {
storybookUrl: string
args?: unknown
env?: ImhotepPageOptions
fc?: FastCheckAdapter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Property Run Handles // Property Run Handles
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+1 -1
View File
@@ -9,7 +9,7 @@
], ],
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-reporter", "name": "imhotep-reporter",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Diagnostic formatting, failure analysis, replay, and shrinking",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-solver", "name": "imhotep-solver",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "First-order logic constraint solver with directional and spatial predicates",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-state", "name": "imhotep-state",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "ARIA and native element state materialization",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+3 -2
View File
@@ -1,11 +1,12 @@
{ {
"name": "imhotep-topology", "name": "imhotep-topology",
"version": "1.0.0", "version": "1.1.0",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"description": "Stacking context evaluation, ancestor chains, and paint ordering",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -5,7 +5,7 @@
"rootDir": "./src", "rootDir": "./src",
"paths": {}, "paths": {},
"composite": false, "composite": false,
"noEmitOnError": false "noEmitOnError": true
}, },
"include": [ "include": [
"src/**/*" "src/**/*"
+32
View File
@@ -0,0 +1,32 @@
# imhotep
Meta-package for [Imhotep](https://gitea.com/anomalyco/imhotep) — declarative, relational UI testing for web applications.
```bash
npm install imhotep
```
## Usage
```typescript
import { imhotep, imhotepComponent, imhotepStory } from 'imhotep';
const ui = await imhotep(page);
ui.expect('.header').to.be.above('.content', { minGap: 16 });
const result = await ui.checkAll();
```
## Exports
| Export | Source |
|---|---|
| `imhotep` | `imhotep-playwright` |
| `imhotepComponent` | `imhotep-playwright` |
| `imhotepStory` | `imhotep-playwright` |
| `imhotepFixture` | `imhotep-playwright` |
| `dslExpect` | `imhotep-dsl` |
| `spec` | `imhotep-dsl` |
| `evaluate` | `imhotep-solver` |
| `enumeratedDomain`, `generatedDomain` | `imhotep-core` |
| `createDeterministicContext` | `imhotep-core` |
| `touchTarget` through `modalContainment` | `imhotep-playwright` |
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "imhotep", "name": "imhotep",
"version": "1.0.0", "version": "1.1.0",
"description": "Declarative relational UI testing for web apps", "description": "Declarative relational UI testing for web apps",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/anomalyco/imhotep.git" "url": "https://gitea.com/anomalyco/imhotep.git"
}, },
"engines": { "engines": {
"node": ">=18.0.0" "node": ">=18.0.0"
+1 -1
View File
@@ -3,6 +3,6 @@ import assert from 'node:assert'
// Meta-package sanity check: ensure exports resolve // Meta-package sanity check: ensure exports resolve
test('meta-package exports resolve', async () => { test('meta-package exports resolve', async () => {
const { imhotep } = await import('../src/index.js') const { imhotep } = await import('./index.js')
assert.strictEqual(typeof imhotep, 'function') assert.strictEqual(typeof imhotep, 'function')
}) })