From d2400dff86827165d1e74f716e9af5fcf8f28b4b Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 12:47:31 -0700 Subject: [PATCH 1/8] docs: e2e harness rename + chat folder consistency design --- .../2026-05-16-e2e-harness-rename-design.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-16-e2e-harness-rename-design.md diff --git a/docs/superpowers/specs/2026-05-16-e2e-harness-rename-design.md b/docs/superpowers/specs/2026-05-16-e2e-harness-rename-design.md new file mode 100644 index 000000000..726dae75e --- /dev/null +++ b/docs/superpowers/specs/2026-05-16-e2e-harness-rename-design.md @@ -0,0 +1,175 @@ +# E2E harness rename + chat folder consistency — design + +> **Place in the larger plan.** Reframe after the aborted full migration ([discussion in this branch's history]; not pushed). Lessons learned: +> 1. The chat and cockpit harnesses solve different problems — chat is single-turn fast replays of one rich app; cockpit is per-app multi-turn tool/subagent flows. The lib's `sendPromptAndWait` is correctly tuned for cockpit but doesn't fit chat. +> 2. The only truly shared piece is the aimock runner (`startAimock` + `AimockHandle`). Process orchestration glue is shared between cockpit examples but NOT with chat. +> 3. The earlier "one helper for everyone" framing made both harnesses worse. Partial sharing (runner only) is the right shape. + +## Goal + +Rename the harness library from `libs/internal/aimock-harness/` to `libs/e2e-harness/`. Rename the chat aimock e2e dir from `examples/chat/aimock-e2e/` to `examples/chat/angular/e2e/` (location-only, behavior preserved). Chat continues to use its own inline harness modules; the lib's broader API (`createGlobalSetup`, `sendPromptAndWait`, `global-teardown`) stays for cockpit's exclusive use. Chat consumes ONLY `startAimock` from the lib (or stays fully self-contained by keeping its own runner — TBD per-implementation, both are fine). + +No behavior change for either harness. All 10 chat specs + all 5+ cockpit specs continue to pass. + +## Non-goals + +- Changing chat's harness semantics (helpers, wait shape, teardown) — all preserved exactly. +- Changing cockpit harness semantics — preserved exactly. +- Sharing the lib's `sendPromptAndWait` or `createGlobalSetup` with chat. Chat keeps its own. +- Adding new e2e coverage anywhere. +- Renaming Angular projects (`examples-chat-angular`, `cockpit-*-angular` all unchanged). +- Renaming Python projects. + +## What changes + +### Lib rename: `libs/internal/aimock-harness/` → `libs/e2e-harness/` + +- `git mv` the entire directory. +- `project.json`: name `internal-aimock-harness` → `e2e-harness`. `sourceRoot` updates. +- README updates: new project name; clarifies that the lib's broader API is cockpit-tuned and chat uses only the runner. +- All cockpit per-example dirs update their relative imports: + - OLD: `'../../../../../libs/internal/aimock-harness/src'` (and `/global-teardown`) + - NEW: `'../../../../../libs/e2e-harness/src'` (and `/global-teardown`) + - Same 5-segment depth to repo root; only the post-root path simplifies. + +### Lib's `sendPromptAndWait` reverted to working cockpit-tuned shape + +During the failed migration I changed the lib helper trying to make it chat-friendly. Revert to the cockpit-tuned version that passed c-tool-calls + c-subagents (the agent-idle / "Stop generating" wait): + +```typescript +// Wait for the agent to enter the loading state (Stop generating visible). +await expect(page.getByRole('button', { name: /stop generating/i })).toBeVisible({ timeout: 10_000 }); +// Wait for the agent to fully finish. +await expect(page.getByRole('button', { name: /stop generating/i })).not.toBeAttached({ timeout: 60_000 }); +// Return the last finalized assistant bubble. +const finalizedAssistant = page.locator('chat-message[data-role="assistant"][data-streaming="false"]').last(); +await expect(finalizedAssistant).toBeAttached({ timeout: 5_000 }); +return finalizedAssistant; +``` + +This was working pre-session. The earlier modifications hurt chat without helping cockpit; revert. + +### Chat dir rename: `examples/chat/aimock-e2e/` → `examples/chat/angular/e2e/` + +Pure file move + path adjustments. All chat harness files (`aimock-runner.ts`, `test-helpers.ts`, `global-setup.ts`, `global-teardown.ts`, `playwright.config.ts`, fixtures, scripts, specs, README, project.json, tsconfig.json) move verbatim. Internal relative paths inside the moved files may need adjustment (e.g., `REPO_ROOT = resolve(__dirname, '../../..')` in `global-setup.ts` becomes `'../../../..'` due to one more directory level). + +The chat harness keeps its own `aimock-runner.ts` for now. Option to thin it to a re-export from `@e2e-harness` later, but not in this PR — the runner copy is harmless and decouples chat from any future lib changes. + +### Chat Nx project dissolved; `e2e` target rolls into `examples-chat-angular` + +- Delete `examples/chat/aimock-e2e/project.json` (now `examples/chat/angular/e2e/project.json` — delete). +- Add to `examples/chat/angular/project.json`: + ```json + "e2e": { + "executor": "@nx/playwright:playwright", + "options": { "config": "examples/chat/angular/e2e/playwright.config.ts" } + } + ``` +- The `record` and `drift` targets that lived in the chat aimock project.json — move to `examples-chat-angular`'s project.json too (or drop; they're dev-only and the scripts can be shell-invoked directly). + +### CI updates + +- `ci.yml`: + - Job id `examples-chat-aimock-e2e` → `examples-chat-e2e` + - Display name `examples/chat — aimock e2e` → `examples/chat — e2e` + - Command `npx nx run examples-chat-aimock-e2e:test --skip-nx-cache` → `npx nx e2e examples-chat-angular --skip-nx-cache` + - Trace artifact path → `examples/chat/angular/e2e/test-results/`, name → `examples-chat-e2e-trace` + - `deploy.needs` array: swap `examples-chat-aimock-e2e` → `examples-chat-e2e` +- `aimock-drift.yml`: + - `npx nx run examples-chat-aimock-e2e:drift --skip-nx-cache` → `npx tsx examples/chat/angular/e2e/scripts/drift.ts` + +## File deltas at a glance + +### Renames (git mv) + +- `libs/internal/aimock-harness/` → `libs/e2e-harness/` (whole dir + contents) +- `examples/chat/aimock-e2e/` → `examples/chat/angular/e2e/` (whole dir + contents) + +### Modifications + +- `libs/e2e-harness/project.json` — `name` field +- `libs/e2e-harness/README.md` — rename references + scope clarification +- `libs/e2e-harness/src/test-helpers.ts` — revert to working cockpit-tuned shape +- Per-example cockpit dirs (3 currently): playwright.config.ts + global-setup-impl.ts + any spec files — update relative imports from `libs/internal/aimock-harness/src` to `libs/e2e-harness/src` +- `examples/chat/angular/e2e/global-setup.ts` — `REPO_ROOT` relative path adjustment for new depth +- `examples/chat/angular/project.json` — add `e2e` target (and optional `record`, `drift` targets) +- `.github/workflows/ci.yml` — chat job rename + path/command updates + `deploy.needs` update +- `.github/workflows/aimock-drift.yml` — invocation path update + +### Deletions + +- `examples/chat/angular/e2e/project.json` (the `examples-chat-aimock-e2e` Nx project dissolves) +- The empty `examples/chat/aimock-e2e/` directory (after move) + +## Components + +### Cockpit per-example imports + +Each of `cockpit///angular/e2e/global-setup-impl.ts` has: + +```typescript +import { createGlobalSetup } from '../../../../../libs/internal/aimock-harness/src'; +``` + +Becomes: + +```typescript +import { createGlobalSetup } from '../../../../../libs/e2e-harness/src'; +``` + +Each `playwright.config.ts` has: + +```typescript +globalTeardown: require.resolve('../../../../../libs/internal/aimock-harness/src/global-teardown'), +``` + +Becomes: + +```typescript +globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'), +``` + +Cockpit per-example dirs touched (verify during implementation): +- `cockpit/langgraph/streaming/angular/e2e/` +- `cockpit/chat/tool-calls/angular/e2e/` +- `cockpit/chat/subagents/angular/e2e/` + +Their spec files generally don't import from the lib (they import from `sendPromptAndWait` via the global-setup-impl path or via a wrapper). Verify with grep. + +### Chat e2e dir internal references + +After the move, `examples/chat/angular/e2e/global-setup.ts` has: + +```typescript +const REPO_ROOT = resolve(__dirname, '../../..'); +``` + +The old `examples/chat/aimock-e2e/` was 3 levels deep (`examples/chat/aimock-e2e/`). The new `examples/chat/angular/e2e/` is 4 levels deep. So: + +```typescript +const REPO_ROOT = resolve(__dirname, '../../../..'); +``` + +Other `__dirname`-relative paths in the chat global-setup, scripts, etc. — audit and update. + +## Risk surface + +- **Chat helper behavior** must NOT change. The migration's failure mode was a lib helper modification breaking chat markdown rendering. This rename keeps chat's own helper intact, so the failure mode can't repeat. +- **Cockpit helper behavior** must NOT change. Reverting the lib's `sendPromptAndWait` to the pre-session working version restores the cockpit-tuned signal. +- **Relative imports** for cockpit per-example dirs need correct path-segment count. Easy to typo; grep verification after the move. +- **`REPO_ROOT` resolution** inside chat's moved global-setup needs the right number of `..` segments. Audit script needed. + +## Acceptance criteria + +- `libs/internal/aimock-harness/` directory is gone; `libs/e2e-harness/` exists with all the same files (renamed via `git mv`). +- `libs/e2e-harness/project.json` has `name: "e2e-harness"`. +- `libs/e2e-harness/src/test-helpers.ts` matches the pre-session cockpit-tuned shape. +- `examples/chat/aimock-e2e/` directory is gone; `examples/chat/angular/e2e/` exists with all the same files. +- `examples/chat/angular/project.json` has an `e2e` target. +- `examples-chat-aimock-e2e` Nx project no longer exists. +- `nx e2e examples-chat-angular` passes locally with 3/3 consecutive stability runs. All 7 chat specs + the runner spec pass. +- `nx e2e cockpit-langgraph-streaming-angular`, `nx e2e cockpit-chat-tool-calls-angular`, `nx e2e cockpit-chat-subagents-angular` all pass — proves the cockpit lib import rename worked. +- `nx run-many --target=e2e --projects=cockpit-*-angular` (or the equivalent CI loop) passes. +- `ci.yml`'s `examples-chat-e2e` job is green; `deploy.needs` updated. +- `aimock-drift.yml` YAML parses (manual `workflow_dispatch` verification is optional post-merge). +- Final reference grep `grep -rn 'internal/aimock-harness\|examples-chat-aimock-e2e\|examples/chat/aimock-e2e' ... ` returns zero matches outside `docs/superpowers/`. From 8752ca8fb585c4c6167a2d9471ad20dd47c3c773 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 13:49:23 -0700 Subject: [PATCH 2/8] docs: e2e harness rename + chat folder consistency plan Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-05-16-e2e-harness-rename.md | 593 ++++++++++++++++++ 1 file changed, 593 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-16-e2e-harness-rename.md diff --git a/docs/superpowers/plans/2026-05-16-e2e-harness-rename.md b/docs/superpowers/plans/2026-05-16-e2e-harness-rename.md new file mode 100644 index 000000000..3f4932a47 --- /dev/null +++ b/docs/superpowers/plans/2026-05-16-e2e-harness-rename.md @@ -0,0 +1,593 @@ +# E2E harness rename + chat folder consistency implementation plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`) syntax. + +**Goal:** Rename `libs/internal/aimock-harness/` → `libs/e2e-harness/`. Rename `examples/chat/aimock-e2e/` → `examples/chat/angular/e2e/`. Chat keeps its own inline harness (preserves working behavior); cockpit consumers update their relative imports to the new lib path. + +**Architecture:** Pure rename + path-relative updates. No semantic changes to either harness. Lib's `sendPromptAndWait` (cockpit-tuned) is already correct on main; no revert needed. + +**Tech Stack:** Nx, Playwright, `@copilotkit/aimock` (via the lib's runner). + +**Spec:** [docs/superpowers/specs/2026-05-16-e2e-harness-rename-design.md](../specs/2026-05-16-e2e-harness-rename-design.md) + +--- + +## Working environment + +- Worktree: `/tmp/e2e-rename` (branch `claude/e2e-harness-rename`). +- `node_modules` symlinked from main checkout; `npx`/`nx`/`uv` work directly. +- License header `// SPDX-License-Identifier: MIT` on line 1 of any new TS file. None are CREATED here — all touches are moves + path/string edits. +- One commit per task. DO NOT push, amend, or `git add -A`. +- Spec commit (`d2400dff`) already on branch; this plan adds a second commit, then implementation. + +## Pre-flight survey (already verified by orchestrator, recorded here for reference) + +- Lib current state on main: `libs/internal/aimock-harness/src/{aimock-runner.ts, aimock-runner.spec.ts, global-setup-factory.ts, global-teardown.ts, index.ts, test-helpers.spec.ts, test-helpers.ts}` — 7 files. +- Lib's `test-helpers.ts` already has the cockpit-tuned shape (Stop-generating waits + 5_000ms `toBeAttached`). NO revert needed. +- Cockpit per-example dirs that reference the lib: 3 + - `cockpit/langgraph/streaming/angular/e2e/` + - `cockpit/chat/tool-calls/angular/e2e/` + - `cockpit/chat/subagents/angular/e2e/` + - Each has 3 import lines using `../../../../../libs/internal/aimock-harness/src` (spec + global-setup-impl + playwright.config) +- Chat dir current state: `examples/chat/aimock-e2e/{README.md, project.json, tsconfig.json, playwright.config.ts, global-setup.ts, global-teardown.ts, test-helpers.ts, aimock-runner.ts, aimock-runner.spec.ts, fixtures/, scripts/, 8 *.spec.ts}` — 8 specs total. + +## Path-segment notes + +- Cockpit per-example imports go to `repoRoot/libs//src` from `cockpit///angular/e2e/`. That's 5 segments up to root. Path becomes `'../../../../../libs/e2e-harness/src'`. +- Chat's moved global-setup.ts goes from `examples/chat/aimock-e2e/` (3 segments to root) to `examples/chat/angular/e2e/` (4 segments to root). `REPO_ROOT = resolve(__dirname, '../../..')` becomes `'../../../..'`. + +--- + +## Task 1: Rename `libs/internal/aimock-harness/` → `libs/e2e-harness/` + +**Files:** +- Move (via `git mv`): entire `libs/internal/aimock-harness/` directory tree to `libs/e2e-harness/` +- Modify: `libs/e2e-harness/project.json` — rename `name` field + +- [ ] **Step 1: Move the directory** + +```bash +cd /tmp/e2e-rename +mkdir -p libs +git mv libs/internal/aimock-harness libs/e2e-harness +``` + +Verify: +```bash +ls libs/e2e-harness/src/ +``` + +Expected output: +``` +aimock-runner.spec.ts +aimock-runner.ts +global-setup-factory.ts +global-teardown.ts +index.ts +test-helpers.spec.ts +test-helpers.ts +``` + +If `libs/internal/` is now empty, remove it (Nx doesn't need empty intermediate dirs): + +```bash +# Check first — there may be other libs under internal/ +ls libs/internal/ 2>/dev/null +# If empty, remove +rmdir libs/internal 2>/dev/null || true +``` + +- [ ] **Step 2: Update project.json name** + +Open `libs/e2e-harness/project.json`. Change the `name` field from `"internal-aimock-harness"` to `"e2e-harness"`. The `sourceRoot` should also be updated (if it references the old path). + +Before (likely): +```json +{ + "name": "internal-aimock-harness", + "sourceRoot": "libs/internal/aimock-harness/src", + ... +} +``` + +After: +```json +{ + "name": "e2e-harness", + "sourceRoot": "libs/e2e-harness/src", + ... +} +``` + +Verify JSON is still valid: +```bash +cd /tmp/e2e-rename +python3 -c "import json; json.load(open('libs/e2e-harness/project.json'))" && echo "OK" +``` + +Expected: `OK`. + +- [ ] **Step 3: Update README references** + +Open `libs/e2e-harness/README.md`. Find references to `internal/aimock-harness`, `internal-aimock-harness`, `@ngaf-internal/aimock-harness` and update to `e2e-harness`, `@ngaf/e2e-harness` (if mentioned), etc. Edit conservatively — only rename references. + +If the README's "Per-example consumer shape" section references cockpit-only patterns, also add a one-line note that chat uses its own inline harness and consumes only `startAimock` from this lib (or doesn't consume anything; chat keeps its own runner copy for now). + +- [ ] **Step 4: Run lib vitest** + +```bash +cd /tmp/e2e-rename/libs/e2e-harness +npx vitest run +``` + +Expected: 5 passed (3 from aimock-runner + 2 from test-helpers). + +- [ ] **Step 5: Type-check the lib** + +```bash +cd /tmp/e2e-rename/libs/e2e-harness +npx tsc --noEmit +``` + +Expected: no errors. + +- [ ] **Step 6: Commit Task 1** + +```bash +cd /tmp/e2e-rename +git add libs/e2e-harness/project.json libs/e2e-harness/README.md +git commit -m "chore(e2e-harness): rename libs/internal/aimock-harness → libs/e2e-harness" +``` + +(`git mv` from Step 1 staged the moves.) + +--- + +## Task 2: Update cockpit per-example imports to new lib path + +**Files (3 dirs × 3 imports = 9 lines):** +- `cockpit/langgraph/streaming/angular/e2e/{streaming.spec.ts, global-setup-impl.ts, playwright.config.ts}` +- `cockpit/chat/tool-calls/angular/e2e/{c-tool-calls.spec.ts, global-setup-impl.ts, playwright.config.ts}` +- `cockpit/chat/subagents/angular/e2e/{c-subagents.spec.ts, global-setup-impl.ts, playwright.config.ts}` + +- [ ] **Step 1: Bulk-replace the import path across all cockpit per-example files** + +```bash +cd /tmp/e2e-rename +find cockpit -path "*/angular/e2e/*.ts" -type f -exec sed -i '' \ + -e 's|libs/internal/aimock-harness/src|libs/e2e-harness/src|g' \ + {} + +``` + +- [ ] **Step 2: Verify all references updated** + +```bash +cd /tmp/e2e-rename +grep -rn "internal/aimock-harness" cockpit/ 2>/dev/null +``` + +Expected: zero matches. + +```bash +grep -rn "libs/e2e-harness/src" cockpit/ 2>/dev/null | wc -l +``` + +Expected: at least 9 (3 per dir × 3 dirs). + +- [ ] **Step 3: Type-check one of the cockpit e2e dirs** + +```bash +cd /tmp/e2e-rename/cockpit/chat/tool-calls/angular/e2e +npx tsc --noEmit +``` + +Expected: no errors. + +- [ ] **Step 4: Commit Task 2** + +```bash +cd /tmp/e2e-rename +git add cockpit/langgraph/streaming/angular/e2e/ \ + cockpit/chat/tool-calls/angular/e2e/ \ + cockpit/chat/subagents/angular/e2e/ +git commit -m "chore(cockpit-e2e): update lib imports to libs/e2e-harness path" +``` + +--- + +## Task 3: Move `examples/chat/aimock-e2e/` → `examples/chat/angular/e2e/` + +**Files:** +- Move (via `git mv`): entire `examples/chat/aimock-e2e/` directory tree to `examples/chat/angular/e2e/` +- Modify: `examples/chat/angular/e2e/global-setup.ts` — `REPO_ROOT` relative-path adjustment for new depth + +- [ ] **Step 1: Confirm `examples/chat/angular/e2e/` doesn't already exist** + +```bash +cd /tmp/e2e-rename +ls examples/chat/angular/e2e 2>/dev/null +``` + +Expected: error / "no such file". If a stray `e2e/` already exists under `examples/chat/angular/`, STOP and report. + +- [ ] **Step 2: Move the directory** + +```bash +cd /tmp/e2e-rename +git mv examples/chat/aimock-e2e examples/chat/angular/e2e +``` + +- [ ] **Step 3: Update `REPO_ROOT` in moved global-setup.ts** + +Open `examples/chat/angular/e2e/global-setup.ts`. Find: + +```typescript +const REPO_ROOT = resolve(__dirname, '../../..'); +``` + +Replace with (one additional `../`): + +```typescript +const REPO_ROOT = resolve(__dirname, '../../../..'); +``` + +- [ ] **Step 4: Audit other `__dirname`-relative paths in moved files** + +```bash +cd /tmp/e2e-rename +grep -rn "__dirname\|\\.\\./\\.\\./\\.\\." examples/chat/angular/e2e/ 2>/dev/null | grep -v node_modules +``` + +Inspect each match. For each, determine if it was depth-3-relative-to-old-location and needs to become depth-4-relative-to-new-location. Typical patterns to update: + +- `resolve(__dirname, '../../..')` → `resolve(__dirname, '../../../..')` +- `path.join(__dirname, '../..', 'fixtures')` → no change (relative to its own dir, not repo root) + +The fixtures dir reference inside global-setup.ts is `resolve(__dirname, 'fixtures')` — relative to its own dir, no change needed. + +Inside `scripts/record.ts` and `scripts/drift.ts`, check for similar patterns. If found, update. + +- [ ] **Step 5: Verify the move** + +```bash +cd /tmp/e2e-rename +ls examples/chat/angular/e2e/ +``` + +Expected: same file listing as `examples/chat/aimock-e2e/` had pre-move (8 spec files, fixtures/, scripts/, project.json, etc.). + +- [ ] **Step 6: Commit Task 3** + +```bash +cd /tmp/e2e-rename +git add examples/chat/angular/e2e/ +git commit -m "chore(examples-chat): move aimock-e2e → angular/e2e for folder consistency" +``` + +--- + +## Task 4: Dissolve chat Nx project; add `e2e` target to `examples-chat-angular` + +**Files:** +- Delete: `examples/chat/angular/e2e/project.json` +- Modify: `examples/chat/angular/project.json` — add `e2e` target (and optionally `record`, `drift`) + +- [ ] **Step 1: Inspect the chat e2e project.json** + +```bash +cd /tmp/e2e-rename +cat examples/chat/angular/e2e/project.json +``` + +Note the targets present (`test`, `record`, `drift`). The `test` target becomes `e2e` on the angular project. `record` + `drift` are dev-only; either move to the angular project or drop entirely (the scripts can be shell-invoked directly). + +- [ ] **Step 2: Delete the chat e2e project.json** + +```bash +cd /tmp/e2e-rename +git rm examples/chat/angular/e2e/project.json +``` + +- [ ] **Step 3: Add `e2e`, `record`, `drift` targets to examples-chat-angular project.json** + +Open `examples/chat/angular/project.json`. Add to `targets`: + +```json +"e2e": { + "executor": "@nx/playwright:playwright", + "options": { + "config": "examples/chat/angular/e2e/playwright.config.ts" + } +}, +"record": { + "executor": "nx:run-commands", + "options": { + "cwd": "examples/chat/angular/e2e", + "command": "tsx scripts/record.ts" + } +}, +"drift": { + "executor": "nx:run-commands", + "options": { + "cwd": "examples/chat/angular/e2e", + "command": "tsx scripts/drift.ts" + } +} +``` + +Position them near the existing targets. Maintain JSON syntax (commas). + +Verify: +```bash +cd /tmp/e2e-rename +python3 -c "import json; d=json.load(open('examples/chat/angular/project.json')); print('targets:', list(d['targets'].keys()))" +``` + +Expected: targets list includes `e2e`, `record`, `drift` plus the existing ones. + +- [ ] **Step 4: Verify the now-orphaned `examples-chat-aimock-e2e` Nx project name no longer exists** + +```bash +cd /tmp/e2e-rename +npx nx show projects 2>&1 | grep -E "examples-chat-aimock-e2e|examples-chat-angular" | head +``` + +Expected: no `examples-chat-aimock-e2e` (we deleted its project.json). `examples-chat-angular` present. + +If Nx complains about the path, run `npx nx reset` to clear the daemon cache. + +- [ ] **Step 5: Commit Task 4** + +```bash +cd /tmp/e2e-rename +git add examples/chat/angular/project.json +git commit -m "chore(examples-chat): dissolve aimock-e2e Nx project; add e2e/record/drift targets to angular project" +``` + +--- + +## Task 5: Update CI workflows + +**Files:** +- Modify: `.github/workflows/ci.yml` +- Modify: `.github/workflows/aimock-drift.yml` + +- [ ] **Step 1: Update ci.yml chat job** + +Open `.github/workflows/ci.yml`. Find the `examples-chat-aimock-e2e` job. Replace its definition: + +OLD (find this block): +```yaml + examples-chat-aimock-e2e: + name: examples/chat — aimock e2e + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.2 + - uses: actions/setup-node@v6.3.0 + with: + node-version: 22 + cache: npm + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + python-version: '3.12' + - run: npm ci + - working-directory: examples/chat/python + run: uv sync + - run: npx playwright install --with-deps chromium + - run: npx nx run examples-chat-aimock-e2e:test --skip-nx-cache + - name: Upload Playwright trace on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: aimock-e2e-trace + path: examples/chat/aimock-e2e/test-results/ + retention-days: 7 +``` + +NEW (rename id, display name, command, artifact name + path): +```yaml + examples-chat-e2e: + name: examples/chat — e2e + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.2 + - uses: actions/setup-node@v6.3.0 + with: + node-version: 22 + cache: npm + - name: Install uv + uses: astral-sh/setup-uv@v8.0.0 + with: + python-version: '3.12' + - run: npm ci + - working-directory: examples/chat/python + run: uv sync + - run: npx playwright install --with-deps chromium + - run: npx nx e2e examples-chat-angular --skip-nx-cache + - name: Upload Playwright trace on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: examples-chat-e2e-trace + path: examples/chat/angular/e2e/test-results/ + retention-days: 7 +``` + +- [ ] **Step 2: Update `deploy.needs` array in ci.yml** + +Find the `deploy` job's `needs:` array. Replace `examples-chat-aimock-e2e` with `examples-chat-e2e`. + +- [ ] **Step 3: Update aimock-drift.yml** + +Open `.github/workflows/aimock-drift.yml`. Find: + +```yaml + run: npx nx run examples-chat-aimock-e2e:drift --skip-nx-cache +``` + +Replace with: + +```yaml + run: npx nx run examples-chat-angular:drift --skip-nx-cache +``` + +(Or the equivalent direct shell invocation `npx tsx examples/chat/angular/e2e/scripts/drift.ts` — both work; nx target is more consistent with the new layout.) + +- [ ] **Step 4: Verify both workflows parse** + +```bash +cd /tmp/e2e-rename +npx -y js-yaml .github/workflows/ci.yml > /dev/null && echo "ci.yml OK" +npx -y js-yaml .github/workflows/aimock-drift.yml > /dev/null && echo "aimock-drift.yml OK" +``` + +Expected: both `OK`. + +- [ ] **Step 5: Commit Task 5** + +```bash +cd /tmp/e2e-rename +git add .github/workflows/ci.yml .github/workflows/aimock-drift.yml +git commit -m "ci(examples-chat): rename job and target to new e2e layout" +``` + +--- + +## Task 6: Final reference grep + +**Files:** none — verification only. + +- [ ] **Step 1: Final grep for stale references** + +```bash +cd /tmp/e2e-rename +grep -rn "internal/aimock-harness\|examples-chat-aimock-e2e\|examples/chat/aimock-e2e" \ + --include='*.ts' --include='*.json' --include='*.yml' --include='*.md' \ + . | grep -v "node_modules\|test-results\|playwright-report\|docs/superpowers/" +``` + +Expected: zero matches (the spec/plan docs under `docs/superpowers/` are excluded since they document the rename). + +If any non-docs matches remain, fix them in this task before considering complete. + +- [ ] **Step 2: Final grep for the OLD lib name** + +```bash +cd /tmp/e2e-rename +grep -rn "internal-aimock-harness\|@ngaf-internal/aimock-harness" \ + --include='*.ts' --include='*.json' --include='*.yml' --include='*.md' \ + . | grep -v "node_modules\|docs/superpowers/" +``` + +Expected: zero matches. + +If matches remain, edit them (likely tsconfig path aliases — if there's a `paths` entry, update to `e2e-harness`). + +- [ ] **Step 3: Commit Task 6 ONLY IF edits happened** + +If Steps 1 or 2 found stale references that you edited, commit: + +```bash +cd /tmp/e2e-rename +git add -p # interactively stage just the cleanups +git commit -m "chore: clean up stale internal-aimock-harness references" +``` + +If both grep steps found zero matches, no commit needed; skip to Task 7. + +--- + +## Task 7: Verify locally + +- [ ] **Step 1: Set up env** + +```bash +cd /tmp/e2e-rename +cp /Users/blove/repos/angular-agent-framework/examples/chat/python/.env examples/chat/python/.env +node libs/licensing/scripts/generate-public-key.mjs 2>&1 | tail -1 +npx playwright install --with-deps chromium # idempotent +``` + +- [ ] **Step 2: Run lib vitest** + +```bash +cd /tmp/e2e-rename/libs/e2e-harness +npx vitest run +``` + +Expected: 5 passed. + +- [ ] **Step 3: Run chat e2e** + +```bash +cd /tmp/e2e-rename +lsof -ti :2024 :4200 2>/dev/null | xargs kill -9 2>/dev/null +ps aux | grep -E "uv |langgraph dev" | grep -v grep | awk '{print $2}' | xargs kill -9 2>/dev/null +sleep 5 +npx nx e2e examples-chat-angular --skip-nx-cache 2>&1 | tail -8 +``` + +Expected: all 8 chat specs pass (or however many were passing pre-rename — chat's behavior is preserved exactly). Wall-clock ~2-3 min. + +If anything fails, STOP and report. + +- [ ] **Step 4: Run each cockpit e2e** + +```bash +cd /tmp/e2e-rename +for proj in cockpit-langgraph-streaming-angular cockpit-chat-tool-calls-angular cockpit-chat-subagents-angular; do + echo "=== $proj ===" + lsof -ti :8123 :8124 :8125 :4300 :4504 :4505 2>/dev/null | xargs kill -9 2>/dev/null + ps aux | grep -E "uv |langgraph dev" | grep -v grep | awk '{print $2}' | xargs kill -9 2>/dev/null + sleep 5 + npx nx e2e "$proj" --skip-nx-cache 2>&1 | tail -3 +done +``` + +Expected: all 3 cockpit projects pass. Wall-clock ~5-8 min total. + +If anything fails, STOP and report. + +- [ ] **Step 5: Confirm working tree is clean** + +```bash +cd /tmp/e2e-rename +rm -rf examples/chat/angular/e2e/test-results examples/chat/angular/e2e/playwright-report +rm -rf cockpit/*/angular/e2e/test-results cockpit/*/angular/e2e/playwright-report +git status --short +``` + +Expected: only `node_modules` symlink as untracked. + +--- + +## Task 8: Push, open PR, watch CI, merge + +(Orchestrator handles — implementer STOPS after Task 7.) + +- Push branch. +- Open PR titled `chore: rename aimock-harness → e2e-harness; chat aimock-e2e → angular/e2e for folder consistency`. +- Watch CI: `examples/chat — e2e` and `Cockpit — e2e` must both pass green. +- Merge with `--squash` when green; clean up worktree. + +--- + +## Self-review checklist + +- [x] Spec coverage: + - Lib rename + project.json + README → Task 1 + - Cockpit consumer import updates → Task 2 + - Chat dir move + REPO_ROOT adjustment → Task 3 + - Dissolve chat Nx project + add targets to angular project → Task 4 + - CI updates → Task 5 + - Final grep cleanup → Task 6 + - Local verification → Task 7 + - Push + PR + merge → Task 8 (orchestrator) +- [x] Placeholder scan: no TBD/TODO. Conditional commit in Task 6 ("only if edits happened") is intentional — the find-and-fix loop is real work, but might find nothing if the rename was complete. +- [x] Type consistency: `e2e-harness` is the only new identifier introduced. Used consistently. +- [x] No new code authored — all tasks are file moves + string-replace edits + JSON modifications. + +## Execution handoff + +Plan complete. Recommended: **subagent-driven-development**, one implementer for Tasks 1-7 (sequential, mechanical). Orchestrator handles Task 8 (push + PR + merge). From d5d5868f98971514d710cc35415b2f3f9c286acc Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 13:59:46 -0700 Subject: [PATCH 3/8] =?UTF-8?q?chore(e2e-harness):=20rename=20libs/interna?= =?UTF-8?q?l/aimock-harness=20=E2=86=92=20libs/e2e-harness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update project.json name + sourceRoot, README, and tsconfig.base.json path aliases (@ngaf-internal/e2e-harness). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../{internal/aimock-harness => e2e-harness}/README.md | 9 ++++++--- .../aimock-harness => e2e-harness}/project.json | 10 +++++----- .../src/aimock-runner.spec.ts | 0 .../src/aimock-runner.ts | 0 .../src/global-setup-factory.ts | 0 .../src/global-teardown.ts | 0 .../aimock-harness => e2e-harness}/src/index.ts | 0 .../src/test-helpers.spec.ts | 0 .../aimock-harness => e2e-harness}/src/test-helpers.ts | 0 .../aimock-harness => e2e-harness}/tsconfig.json | 0 tsconfig.base.json | 4 ++-- 11 files changed, 13 insertions(+), 10 deletions(-) rename libs/{internal/aimock-harness => e2e-harness}/README.md (64%) rename libs/{internal/aimock-harness => e2e-harness}/project.json (55%) rename libs/{internal/aimock-harness => e2e-harness}/src/aimock-runner.spec.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/aimock-runner.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/global-setup-factory.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/global-teardown.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/index.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/test-helpers.spec.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/src/test-helpers.ts (100%) rename libs/{internal/aimock-harness => e2e-harness}/tsconfig.json (100%) diff --git a/libs/internal/aimock-harness/README.md b/libs/e2e-harness/README.md similarity index 64% rename from libs/internal/aimock-harness/README.md rename to libs/e2e-harness/README.md index b10391a94..efdde3594 100644 --- a/libs/internal/aimock-harness/README.md +++ b/libs/e2e-harness/README.md @@ -1,13 +1,16 @@ -# @ngaf-internal/aimock-harness +# e2e-harness Internal-only library that wraps [`@copilotkit/aimock`](https://github.com/CopilotKit/aimock) for our cockpit example aimock e2e suite. -NOT published. The `@ngaf-internal/*` namespace is reserved for internal libraries that are tightly coupled to repo-specific orchestration (langgraph + Angular dev server boot) and shouldn't appear in consumer-facing API surfaces. +NOT published. This lib is tightly coupled to repo-specific orchestration (langgraph + Angular dev server boot) and shouldn't appear in consumer-facing API surfaces. + +> The `examples/chat/angular/e2e/` suite currently maintains its own inline harness copy and does not consume this lib. Cockpit per-example e2e suites are the only consumers. ## API ```typescript -import { createGlobalSetup, sendPromptAndWait } from '@ngaf-internal/aimock-harness'; +// Cockpit consumers import via repo-root-relative path (no published package): +import { createGlobalSetup, sendPromptAndWait } from '../../../../../libs/e2e-harness/src'; ``` - `createGlobalSetup(opts)` — returns a Playwright globalSetup function that boots aimock + langgraph + the named Angular dev server. diff --git a/libs/internal/aimock-harness/project.json b/libs/e2e-harness/project.json similarity index 55% rename from libs/internal/aimock-harness/project.json rename to libs/e2e-harness/project.json index 74d394186..5d4e72ce6 100644 --- a/libs/internal/aimock-harness/project.json +++ b/libs/e2e-harness/project.json @@ -1,21 +1,21 @@ { - "name": "internal-aimock-harness", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "name": "e2e-harness", + "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "library", - "sourceRoot": "libs/internal/aimock-harness/src", + "sourceRoot": "libs/e2e-harness/src", "tags": ["scope:internal"], "targets": { "lint": { "executor": "nx:run-commands", "options": { - "cwd": "libs/internal/aimock-harness", + "cwd": "libs/e2e-harness", "command": "tsc --noEmit" } }, "test": { "executor": "nx:run-commands", "options": { - "cwd": "libs/internal/aimock-harness", + "cwd": "libs/e2e-harness", "command": "vitest run" } } diff --git a/libs/internal/aimock-harness/src/aimock-runner.spec.ts b/libs/e2e-harness/src/aimock-runner.spec.ts similarity index 100% rename from libs/internal/aimock-harness/src/aimock-runner.spec.ts rename to libs/e2e-harness/src/aimock-runner.spec.ts diff --git a/libs/internal/aimock-harness/src/aimock-runner.ts b/libs/e2e-harness/src/aimock-runner.ts similarity index 100% rename from libs/internal/aimock-harness/src/aimock-runner.ts rename to libs/e2e-harness/src/aimock-runner.ts diff --git a/libs/internal/aimock-harness/src/global-setup-factory.ts b/libs/e2e-harness/src/global-setup-factory.ts similarity index 100% rename from libs/internal/aimock-harness/src/global-setup-factory.ts rename to libs/e2e-harness/src/global-setup-factory.ts diff --git a/libs/internal/aimock-harness/src/global-teardown.ts b/libs/e2e-harness/src/global-teardown.ts similarity index 100% rename from libs/internal/aimock-harness/src/global-teardown.ts rename to libs/e2e-harness/src/global-teardown.ts diff --git a/libs/internal/aimock-harness/src/index.ts b/libs/e2e-harness/src/index.ts similarity index 100% rename from libs/internal/aimock-harness/src/index.ts rename to libs/e2e-harness/src/index.ts diff --git a/libs/internal/aimock-harness/src/test-helpers.spec.ts b/libs/e2e-harness/src/test-helpers.spec.ts similarity index 100% rename from libs/internal/aimock-harness/src/test-helpers.spec.ts rename to libs/e2e-harness/src/test-helpers.spec.ts diff --git a/libs/internal/aimock-harness/src/test-helpers.ts b/libs/e2e-harness/src/test-helpers.ts similarity index 100% rename from libs/internal/aimock-harness/src/test-helpers.ts rename to libs/e2e-harness/src/test-helpers.ts diff --git a/libs/internal/aimock-harness/tsconfig.json b/libs/e2e-harness/tsconfig.json similarity index 100% rename from libs/internal/aimock-harness/tsconfig.json rename to libs/e2e-harness/tsconfig.json diff --git a/tsconfig.base.json b/tsconfig.base.json index 3436e1f35..453b76c99 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -39,8 +39,8 @@ "@ngaf/telemetry/browser": ["libs/telemetry/src/browser/public-api.ts"], "@ngaf/telemetry/node": ["libs/telemetry/src/node/index.ts"], "@ngaf/telemetry/shared": ["libs/telemetry/src/shared/public-api.ts"], - "@ngaf-internal/aimock-harness": ["libs/internal/aimock-harness/src/index.ts"], - "@ngaf-internal/aimock-harness/global-teardown": ["libs/internal/aimock-harness/src/global-teardown.ts"] + "@ngaf-internal/e2e-harness": ["libs/e2e-harness/src/index.ts"], + "@ngaf-internal/e2e-harness/global-teardown": ["libs/e2e-harness/src/global-teardown.ts"] }, "skipLibCheck": true, "strict": true, From 645a8fd7e2a39aa8badee4e8167b3ab7aab51069 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 14:03:03 -0700 Subject: [PATCH 4/8] chore(cockpit-e2e): update lib imports to libs/e2e-harness path Co-Authored-By: Claude Opus 4.7 (1M context) --- cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts | 2 +- cockpit/chat/subagents/angular/e2e/global-setup-impl.ts | 2 +- cockpit/chat/subagents/angular/e2e/playwright.config.ts | 2 +- cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts | 2 +- cockpit/chat/tool-calls/angular/e2e/global-setup-impl.ts | 2 +- cockpit/chat/tool-calls/angular/e2e/playwright.config.ts | 2 +- cockpit/langgraph/streaming/angular/e2e/global-setup-impl.ts | 2 +- cockpit/langgraph/streaming/angular/e2e/playwright.config.ts | 2 +- cockpit/langgraph/streaming/angular/e2e/streaming.spec.ts | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts b/cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts index 6cc6375f5..8292e8ac6 100644 --- a/cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts +++ b/cockpit/chat/subagents/angular/e2e/c-subagents.spec.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { test, expect } from '@playwright/test'; -import { sendPromptAndWait } from '../../../../../libs/internal/aimock-harness/src'; +import { sendPromptAndWait } from '../../../../../libs/e2e-harness/src'; const PROMPT = 'Plan a trip from LAX to JFK'; diff --git a/cockpit/chat/subagents/angular/e2e/global-setup-impl.ts b/cockpit/chat/subagents/angular/e2e/global-setup-impl.ts index ae254cd33..26f51ce9a 100644 --- a/cockpit/chat/subagents/angular/e2e/global-setup-impl.ts +++ b/cockpit/chat/subagents/angular/e2e/global-setup-impl.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { resolve } from 'node:path'; -import { createGlobalSetup } from '../../../../../libs/internal/aimock-harness/src'; +import { createGlobalSetup } from '../../../../../libs/e2e-harness/src'; export default createGlobalSetup({ langgraphCwd: 'cockpit/langgraph/streaming/python', diff --git a/cockpit/chat/subagents/angular/e2e/playwright.config.ts b/cockpit/chat/subagents/angular/e2e/playwright.config.ts index ae04d7fb7..9900846a5 100644 --- a/cockpit/chat/subagents/angular/e2e/playwright.config.ts +++ b/cockpit/chat/subagents/angular/e2e/playwright.config.ts @@ -14,5 +14,5 @@ export default defineConfig({ }, projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], globalSetup: './global-setup-impl.ts', - globalTeardown: require.resolve('../../../../../libs/internal/aimock-harness/src/global-teardown'), + globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'), }); diff --git a/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts b/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts index 2aa396c68..3a9c06aca 100644 --- a/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts +++ b/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { test, expect } from '@playwright/test'; -import { sendPromptAndWait } from '../../../../../libs/internal/aimock-harness/src'; +import { sendPromptAndWait } from '../../../../../libs/e2e-harness/src'; const PROMPT = "What's the status of UA123?"; diff --git a/cockpit/chat/tool-calls/angular/e2e/global-setup-impl.ts b/cockpit/chat/tool-calls/angular/e2e/global-setup-impl.ts index 9125b1a47..5c65ee875 100644 --- a/cockpit/chat/tool-calls/angular/e2e/global-setup-impl.ts +++ b/cockpit/chat/tool-calls/angular/e2e/global-setup-impl.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { resolve } from 'node:path'; -import { createGlobalSetup } from '../../../../../libs/internal/aimock-harness/src'; +import { createGlobalSetup } from '../../../../../libs/e2e-harness/src'; export default createGlobalSetup({ langgraphCwd: 'cockpit/langgraph/streaming/python', diff --git a/cockpit/chat/tool-calls/angular/e2e/playwright.config.ts b/cockpit/chat/tool-calls/angular/e2e/playwright.config.ts index d473509d5..652db126c 100644 --- a/cockpit/chat/tool-calls/angular/e2e/playwright.config.ts +++ b/cockpit/chat/tool-calls/angular/e2e/playwright.config.ts @@ -14,5 +14,5 @@ export default defineConfig({ }, projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], globalSetup: './global-setup-impl.ts', - globalTeardown: require.resolve('../../../../../libs/internal/aimock-harness/src/global-teardown'), + globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'), }); diff --git a/cockpit/langgraph/streaming/angular/e2e/global-setup-impl.ts b/cockpit/langgraph/streaming/angular/e2e/global-setup-impl.ts index 3f2390e7b..76fb474d0 100644 --- a/cockpit/langgraph/streaming/angular/e2e/global-setup-impl.ts +++ b/cockpit/langgraph/streaming/angular/e2e/global-setup-impl.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { resolve } from 'node:path'; -import { createGlobalSetup } from '../../../../../libs/internal/aimock-harness/src'; +import { createGlobalSetup } from '../../../../../libs/e2e-harness/src'; export default createGlobalSetup({ langgraphCwd: 'cockpit/langgraph/streaming/python', diff --git a/cockpit/langgraph/streaming/angular/e2e/playwright.config.ts b/cockpit/langgraph/streaming/angular/e2e/playwright.config.ts index 9ec8c24f5..9592e1d79 100644 --- a/cockpit/langgraph/streaming/angular/e2e/playwright.config.ts +++ b/cockpit/langgraph/streaming/angular/e2e/playwright.config.ts @@ -14,5 +14,5 @@ export default defineConfig({ }, projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], globalSetup: './global-setup-impl.ts', - globalTeardown: require.resolve('../../../../../libs/internal/aimock-harness/src/global-teardown'), + globalTeardown: require.resolve('../../../../../libs/e2e-harness/src/global-teardown'), }); diff --git a/cockpit/langgraph/streaming/angular/e2e/streaming.spec.ts b/cockpit/langgraph/streaming/angular/e2e/streaming.spec.ts index 18231181a..454ebe0cf 100644 --- a/cockpit/langgraph/streaming/angular/e2e/streaming.spec.ts +++ b/cockpit/langgraph/streaming/angular/e2e/streaming.spec.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT import { test, expect } from '@playwright/test'; -import { sendPromptAndWait } from '../../../../../libs/internal/aimock-harness/src'; +import { sendPromptAndWait } from '../../../../../libs/e2e-harness/src'; test('streaming: assistant text from the mocked LLM renders in the cockpit chat composition', async ({ page }) => { const bubble = await sendPromptAndWait( From 18a0a1b4a3408b852d557c881f5aff8d0213c134 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 14:09:44 -0700 Subject: [PATCH 5/8] =?UTF-8?q?chore(examples-chat):=20move=20aimock-e2e?= =?UTF-8?q?=20=E2=86=92=20angular/e2e=20for=20folder=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust REPO_ROOT in global-setup.ts for new depth (4 segments to repo root). Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/chat/{aimock-e2e => angular/e2e}/.gitignore | 0 examples/chat/{aimock-e2e => angular/e2e}/README.md | 0 .../chat/{aimock-e2e => angular/e2e}/a2ui-single-bubble.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/aimock-runner.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/aimock-runner.ts | 0 .../chat/{aimock-e2e => angular/e2e}/fixtures/a2ui-surface.json | 0 examples/chat/{aimock-e2e => angular/e2e}/fixtures/hi.json | 0 .../e2e}/fixtures/interrupt-approval.json | 0 .../chat/{aimock-e2e => angular/e2e}/fixtures/markdown.json | 0 .../{aimock-e2e => angular/e2e}/fixtures/research-subagent.json | 0 examples/chat/{aimock-e2e => angular/e2e}/global-setup.ts | 2 +- examples/chat/{aimock-e2e => angular/e2e}/global-teardown.ts | 0 .../chat/{aimock-e2e => angular/e2e}/interrupt-approval.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/markdown.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/playwright.config.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/project.json | 0 examples/chat/{aimock-e2e => angular/e2e}/regenerate.spec.ts | 0 .../chat/{aimock-e2e => angular/e2e}/research-subagent.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/scripts/drift.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/scripts/record.ts | 0 .../e2e}/sidebar-mode-coexistence.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/smoke.spec.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/test-helpers.ts | 0 examples/chat/{aimock-e2e => angular/e2e}/tsconfig.json | 0 24 files changed, 1 insertion(+), 1 deletion(-) rename examples/chat/{aimock-e2e => angular/e2e}/.gitignore (100%) rename examples/chat/{aimock-e2e => angular/e2e}/README.md (100%) rename examples/chat/{aimock-e2e => angular/e2e}/a2ui-single-bubble.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/aimock-runner.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/aimock-runner.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/fixtures/a2ui-surface.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/fixtures/hi.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/fixtures/interrupt-approval.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/fixtures/markdown.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/fixtures/research-subagent.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/global-setup.ts (97%) rename examples/chat/{aimock-e2e => angular/e2e}/global-teardown.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/interrupt-approval.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/markdown.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/playwright.config.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/project.json (100%) rename examples/chat/{aimock-e2e => angular/e2e}/regenerate.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/research-subagent.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/scripts/drift.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/scripts/record.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/sidebar-mode-coexistence.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/smoke.spec.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/test-helpers.ts (100%) rename examples/chat/{aimock-e2e => angular/e2e}/tsconfig.json (100%) diff --git a/examples/chat/aimock-e2e/.gitignore b/examples/chat/angular/e2e/.gitignore similarity index 100% rename from examples/chat/aimock-e2e/.gitignore rename to examples/chat/angular/e2e/.gitignore diff --git a/examples/chat/aimock-e2e/README.md b/examples/chat/angular/e2e/README.md similarity index 100% rename from examples/chat/aimock-e2e/README.md rename to examples/chat/angular/e2e/README.md diff --git a/examples/chat/aimock-e2e/a2ui-single-bubble.spec.ts b/examples/chat/angular/e2e/a2ui-single-bubble.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/a2ui-single-bubble.spec.ts rename to examples/chat/angular/e2e/a2ui-single-bubble.spec.ts diff --git a/examples/chat/aimock-e2e/aimock-runner.spec.ts b/examples/chat/angular/e2e/aimock-runner.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/aimock-runner.spec.ts rename to examples/chat/angular/e2e/aimock-runner.spec.ts diff --git a/examples/chat/aimock-e2e/aimock-runner.ts b/examples/chat/angular/e2e/aimock-runner.ts similarity index 100% rename from examples/chat/aimock-e2e/aimock-runner.ts rename to examples/chat/angular/e2e/aimock-runner.ts diff --git a/examples/chat/aimock-e2e/fixtures/a2ui-surface.json b/examples/chat/angular/e2e/fixtures/a2ui-surface.json similarity index 100% rename from examples/chat/aimock-e2e/fixtures/a2ui-surface.json rename to examples/chat/angular/e2e/fixtures/a2ui-surface.json diff --git a/examples/chat/aimock-e2e/fixtures/hi.json b/examples/chat/angular/e2e/fixtures/hi.json similarity index 100% rename from examples/chat/aimock-e2e/fixtures/hi.json rename to examples/chat/angular/e2e/fixtures/hi.json diff --git a/examples/chat/aimock-e2e/fixtures/interrupt-approval.json b/examples/chat/angular/e2e/fixtures/interrupt-approval.json similarity index 100% rename from examples/chat/aimock-e2e/fixtures/interrupt-approval.json rename to examples/chat/angular/e2e/fixtures/interrupt-approval.json diff --git a/examples/chat/aimock-e2e/fixtures/markdown.json b/examples/chat/angular/e2e/fixtures/markdown.json similarity index 100% rename from examples/chat/aimock-e2e/fixtures/markdown.json rename to examples/chat/angular/e2e/fixtures/markdown.json diff --git a/examples/chat/aimock-e2e/fixtures/research-subagent.json b/examples/chat/angular/e2e/fixtures/research-subagent.json similarity index 100% rename from examples/chat/aimock-e2e/fixtures/research-subagent.json rename to examples/chat/angular/e2e/fixtures/research-subagent.json diff --git a/examples/chat/aimock-e2e/global-setup.ts b/examples/chat/angular/e2e/global-setup.ts similarity index 97% rename from examples/chat/aimock-e2e/global-setup.ts rename to examples/chat/angular/e2e/global-setup.ts index 32a55a398..eb9e42531 100644 --- a/examples/chat/aimock-e2e/global-setup.ts +++ b/examples/chat/angular/e2e/global-setup.ts @@ -15,7 +15,7 @@ declare global { var __AIMOCK_E2E_STATE__: SharedState | undefined; } -const REPO_ROOT = resolve(__dirname, '../../..'); +const REPO_ROOT = resolve(__dirname, '../../../..'); const FIXTURE_PATH = process.env.AIMOCK_FIXTURE ? resolve(__dirname, process.env.AIMOCK_FIXTURE) : resolve(__dirname, 'fixtures'); diff --git a/examples/chat/aimock-e2e/global-teardown.ts b/examples/chat/angular/e2e/global-teardown.ts similarity index 100% rename from examples/chat/aimock-e2e/global-teardown.ts rename to examples/chat/angular/e2e/global-teardown.ts diff --git a/examples/chat/aimock-e2e/interrupt-approval.spec.ts b/examples/chat/angular/e2e/interrupt-approval.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/interrupt-approval.spec.ts rename to examples/chat/angular/e2e/interrupt-approval.spec.ts diff --git a/examples/chat/aimock-e2e/markdown.spec.ts b/examples/chat/angular/e2e/markdown.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/markdown.spec.ts rename to examples/chat/angular/e2e/markdown.spec.ts diff --git a/examples/chat/aimock-e2e/playwright.config.ts b/examples/chat/angular/e2e/playwright.config.ts similarity index 100% rename from examples/chat/aimock-e2e/playwright.config.ts rename to examples/chat/angular/e2e/playwright.config.ts diff --git a/examples/chat/aimock-e2e/project.json b/examples/chat/angular/e2e/project.json similarity index 100% rename from examples/chat/aimock-e2e/project.json rename to examples/chat/angular/e2e/project.json diff --git a/examples/chat/aimock-e2e/regenerate.spec.ts b/examples/chat/angular/e2e/regenerate.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/regenerate.spec.ts rename to examples/chat/angular/e2e/regenerate.spec.ts diff --git a/examples/chat/aimock-e2e/research-subagent.spec.ts b/examples/chat/angular/e2e/research-subagent.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/research-subagent.spec.ts rename to examples/chat/angular/e2e/research-subagent.spec.ts diff --git a/examples/chat/aimock-e2e/scripts/drift.ts b/examples/chat/angular/e2e/scripts/drift.ts similarity index 100% rename from examples/chat/aimock-e2e/scripts/drift.ts rename to examples/chat/angular/e2e/scripts/drift.ts diff --git a/examples/chat/aimock-e2e/scripts/record.ts b/examples/chat/angular/e2e/scripts/record.ts similarity index 100% rename from examples/chat/aimock-e2e/scripts/record.ts rename to examples/chat/angular/e2e/scripts/record.ts diff --git a/examples/chat/aimock-e2e/sidebar-mode-coexistence.spec.ts b/examples/chat/angular/e2e/sidebar-mode-coexistence.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/sidebar-mode-coexistence.spec.ts rename to examples/chat/angular/e2e/sidebar-mode-coexistence.spec.ts diff --git a/examples/chat/aimock-e2e/smoke.spec.ts b/examples/chat/angular/e2e/smoke.spec.ts similarity index 100% rename from examples/chat/aimock-e2e/smoke.spec.ts rename to examples/chat/angular/e2e/smoke.spec.ts diff --git a/examples/chat/aimock-e2e/test-helpers.ts b/examples/chat/angular/e2e/test-helpers.ts similarity index 100% rename from examples/chat/aimock-e2e/test-helpers.ts rename to examples/chat/angular/e2e/test-helpers.ts diff --git a/examples/chat/aimock-e2e/tsconfig.json b/examples/chat/angular/e2e/tsconfig.json similarity index 100% rename from examples/chat/aimock-e2e/tsconfig.json rename to examples/chat/angular/e2e/tsconfig.json From 9ac777bc717f6d33bd40de7b2502c782f8b0f6a5 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 14:16:28 -0700 Subject: [PATCH 6/8] chore(examples-chat): dissolve aimock-e2e Nx project; add e2e/record/drift targets to angular project Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/chat/angular/e2e/project.json | 29 -------------------------- examples/chat/angular/project.json | 20 ++++++++++++++++++ 2 files changed, 20 insertions(+), 29 deletions(-) delete mode 100644 examples/chat/angular/e2e/project.json diff --git a/examples/chat/angular/e2e/project.json b/examples/chat/angular/e2e/project.json deleted file mode 100644 index 70467a2e7..000000000 --- a/examples/chat/angular/e2e/project.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "examples-chat-aimock-e2e", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "examples/chat/aimock-e2e", - "targets": { - "test": { - "executor": "nx:run-commands", - "options": { - "cwd": "examples/chat/aimock-e2e", - "command": "playwright test" - } - }, - "record": { - "executor": "nx:run-commands", - "options": { - "cwd": "examples/chat/aimock-e2e", - "command": "tsx scripts/record.ts" - } - }, - "drift": { - "executor": "nx:run-commands", - "options": { - "cwd": "examples/chat/aimock-e2e", - "command": "tsx scripts/drift.ts" - } - } - } -} diff --git a/examples/chat/angular/project.json b/examples/chat/angular/project.json index 6f503ad09..06814c630 100644 --- a/examples/chat/angular/project.json +++ b/examples/chat/angular/project.json @@ -63,6 +63,26 @@ }, "lint": { "executor": "@nx/eslint:lint" + }, + "e2e": { + "executor": "@nx/playwright:playwright", + "options": { + "config": "examples/chat/angular/e2e/playwright.config.ts" + } + }, + "record": { + "executor": "nx:run-commands", + "options": { + "cwd": "examples/chat/angular/e2e", + "command": "tsx scripts/record.ts" + } + }, + "drift": { + "executor": "nx:run-commands", + "options": { + "cwd": "examples/chat/angular/e2e", + "command": "tsx scripts/drift.ts" + } } }, "tags": ["scope:examples", "type:app"] From d1ede29d86268614af0e50e8fe9e583ca06cf2fa Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 14:21:22 -0700 Subject: [PATCH 7/8] ci(examples-chat): rename job and target to new e2e layout Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/aimock-drift.yml | 2 +- .github/workflows/ci.yml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/aimock-drift.yml b/.github/workflows/aimock-drift.yml index 3ab1e9226..c0f8e1791 100644 --- a/.github/workflows/aimock-drift.yml +++ b/.github/workflows/aimock-drift.yml @@ -20,7 +20,7 @@ jobs: - name: Run drift check env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - run: npx nx run examples-chat-aimock-e2e:drift --skip-nx-cache + run: npx nx run examples-chat-angular:drift --skip-nx-cache - name: Open issue on drift if: failure() uses: actions/github-script@v8 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f1809d26..adad65d5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,8 +126,8 @@ jobs: run: uv sync - run: npx nx run examples-chat-python:smoke --skip-nx-cache - examples-chat-aimock-e2e: - name: examples/chat — aimock e2e + examples-chat-e2e: + name: examples/chat — e2e runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 @@ -143,13 +143,13 @@ jobs: - working-directory: examples/chat/python run: uv sync - run: npx playwright install --with-deps chromium - - run: npx nx run examples-chat-aimock-e2e:test --skip-nx-cache + - run: npx nx e2e examples-chat-angular --skip-nx-cache - name: Upload Playwright trace on failure if: failure() uses: actions/upload-artifact@v4 with: - name: aimock-e2e-trace - path: examples/chat/aimock-e2e/test-results/ + name: examples-chat-e2e-trace + path: examples/chat/angular/e2e/test-results/ retention-days: 7 cockpit-e2e: @@ -222,7 +222,7 @@ jobs: cockpit-secret-integration, cockpit-deploy-smoke, examples-chat-smoke, - examples-chat-aimock-e2e, + examples-chat-e2e, cockpit-e2e, website-e2e, ] From 9c58cd30cab01d2752c8597d2150ecf13d37f129 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 16 May 2026 14:24:52 -0700 Subject: [PATCH 8/8] chore: clean up stale examples-chat-aimock-e2e references in chat e2e README Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/chat/angular/e2e/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/chat/angular/e2e/README.md b/examples/chat/angular/e2e/README.md index 6eef37090..de15b6330 100644 --- a/examples/chat/angular/e2e/README.md +++ b/examples/chat/angular/e2e/README.md @@ -1,11 +1,11 @@ -# examples-chat-aimock-e2e +# examples-chat-angular e2e Cross-stack E2E harness for the chat example. Uses [`@copilotkit/aimock`](https://github.com/CopilotKit/aimock) as a deterministic mock for LLM API calls; the Python LangGraph dev server is launched with `OPENAI_BASE_URL` pointed at it; Playwright drives the Angular `/embed` route in real Chromium. ## Run the suite ``` -npx nx run examples-chat-aimock-e2e:test +npx nx e2e examples-chat-angular ``` Replay-only. No `OPENAI_API_KEY` needed. Reads committed fixtures from `fixtures/`. @@ -13,7 +13,7 @@ Replay-only. No `OPENAI_API_KEY` needed. Reads committed fixtures from `fixtures ## Refresh a fixture ``` -OPENAI_API_KEY=sk-... npx nx run examples-chat-aimock-e2e:record -- hi +OPENAI_API_KEY=sk-... npx nx run examples-chat-angular:record -- hi ``` Captures a real OpenAI run for the named scenario, writes the result to `fixtures/.json`. Commit the updated fixture. @@ -21,7 +21,7 @@ Captures a real OpenAI run for the named scenario, writes the result to `fixture ## Detect fixture drift ``` -OPENAI_API_KEY=sk-... npx nx run examples-chat-aimock-e2e:drift +OPENAI_API_KEY=sk-... npx nx run examples-chat-angular:drift ``` Re-records each committed fixture against real OpenAI and reports byte-level diffs. CI runs this on a daily schedule and opens an issue when drift is detected; it does NOT auto-update fixtures.