feat(chat): ChatApprovalCard dialog composition + ChatInterruptPanel refresh#552
Merged
Conversation
Also include the design spec + implementation plan for the HITL refund work stream.
Drop the thick amber left border and triangle warning icon. Adopt the eyebrow + small dot pattern that matches the new ChatApprovalCard composition. Share .btn / .btn-primary / .btn-secondary / .btn-text styles across both compositions. No API change.
Drop the typeof-function guards from ChatApprovalCardComponent — they were coupling production code to a JSDOM limitation. Stub HTMLDialogElement.prototype.showModal/close in the spec's beforeEach so Vitest still runs. Add two missing tests covering the dialog open/close effect on interrupt presence and the native cancel event (Escape) emitting 'cancel' with preventDefault.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Added in PR #433 with `test.skip(...)` and no condition or comment explaining the skip. Two years later it's still skipped and adds nothing to CI signal. The test's intent — assert the "Stop generating" button is visible mid-stream, click it, observe abort — is fundamentally flaky against aimock-replayed streams: the streaming chunks arrive in <100ms and signal-batched updates can collapse the visible-then-hidden state below Playwright's polling resolution. This is already documented in test-helpers.ts:95-100 as the reason `submitAndWaitForResponse` asserts on the rendered `chat-message` element's `data-streaming` attribute (not on input/button affordances). The same constraint makes this test unimplementable as-written against aimock. If/when we add a slow-streaming fixture path (or run e2e against a non-aimock backend), reintroduce the test alongside that. Until then it's dead code. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…onstraint (#549) * fix(docs): defer sidebar reveal to lg breakpoint Mobile audit flagged the docs sidebar as 500–925% viewport-height sticky on tablet (768px). At that width it crowded the article and was the largest sticky/fixed offender. Pushing the reveal from md:block (768px) to lg:block (1024px) hides it for tablet/narrow-desktop and lets the article use the full width. Mobile menu's docs tab already covers nav at <lg. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(website): constrain layout viewport on mobile Follow-up to #547. body { overflow-x: hidden } prevents the user-visible scrollbar but doesn't stop mobile browsers from EXPANDING the layout viewport when child content (code blocks, wide grids) exceeds device-width. The fixed nav then renders at that expanded width — its right side (hamburger button) ends up clipped offscreen. Two additions: 1. html { overflow-x: hidden } — anchors the layout viewport to the visual viewport so the fixed nav and other position:fixed elements stay aligned with what the user sees. 2. pre { max-width: 100%; overflow-x: auto } as a universal rule (was already on .shiki and .docs-prose pre; this catches any other pre that might appear in landing components without those classes). Verified live in prod via Chrome MCP: the previous PR's body { overflow-x: hidden } and h1..h6 { word-break } are both applied; the remaining overflow numbers come from layout-viewport expansion, which this PR addresses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…gistry (#551) * docs(spec): cockpit port registry design * docs(plan): cockpit port registry implementation plan * feat(ci): cockpit ports registry + verifier spec (skeleton) Registry starts empty; the verifier spec tests both the registry shape (positive int ports, no duplicates, range/convention checks) and cross-file invariants (python --port + playwright baseURL match registry). Empty registry intentionally fails the 'covers every cap' test until Task 2 populates it. Spec: docs/superpowers/specs/2026-05-27-cockpit-port-registry-design.md * feat(ci): populate cockpit ports registry from on-disk values 31 entries, extracted from each cap's proxy.conf.json target + playwright.config.ts baseURL (or langgraph - 1000 for non-e2e caps). Verifier confirms the registry round-trips cleanly against every python/project.json --port literal. * test(ports): verifier skips python --port check for caps without literal Only chat caps have --port in their python/project.json serve target; langgraph/deep-agents/render caps rely on the e2e harness spawning langgraph with explicit --port from global-setup-impl.ts. Skip verifier check for those rather than fail. * refactor(cockpit): 31 proxy.conf.json → proxy.conf.mjs (import ports registry) Every cockpit cap's proxy.conf.json is replaced with proxy.conf.mjs that imports portsFor(capName) from cockpit/ports.mjs and templates the langgraph port into the target URL. Each angular/project.json's serve.options.proxyConfig is updated to point at the .mjs file. cockpit/ag-ui/streaming is excluded — non-LangGraph backend, kept as proxy.conf.json with its /agent → :3000 literal. * refactor(cockpit): 24 e2e configs import ports from registry Each cap's e2e/global-setup-impl.ts now imports portsFor() and reads angular/langgraph ports from the registry instead of literal numbers. playwright.config.ts is updated similarly for baseURL. All 24 e2e tsconfig.json files gain allowJs: true so tsc accepts the .mjs import without a declaration file. The verifier's playwright-baseURL check now skips templated configs (its regex only matches literal URLs); drift is impossible because the value imports directly from the registry. * ci: gate cockpit-ports.spec.mjs in ci-scope test job Appends the new verifier spec to the existing node --test invocation so registry drift is caught at PR time. * test(cockpit): wiring spec reads ports from registry; recognizes .mjs proxy The drift-guard test previously parsed proxy.conf.json target + the literal langgraphPort/angularPort lines in global-setup-impl.ts. Both were removed by the port-registry migration: - proxy.conf.json → proxy.conf.mjs (templates target from registry) - global-setup-impl.ts now reads `ports.langgraph` / `ports.angular` Updated wiring spec: - Imports `portsFor` from cockpit/ports.mjs to look up expected ports by project name. Falls back to literal parsing for the ag-ui exception (not in registry). - Replaces the proxy.conf.json content assertion with a proxy.conf.mjs existence + `portsFor('<name>')` call check. Drift is impossible because the .mjs templates from the same registry. - Legacy proxy.conf.json branch retained for ag-ui (single-cap exception). 79/79 cockpit unit tests pass locally.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Library foundation for the HITL refund forcing-function work stream (PR #1 of 3).
libs/langgraphtest demonstrates multi-field structured objects ({ approved, amount, idempotency_key, meta }) forwarding throughagent.submit({ resume })to LangGraph'sCommand(resume=…)verbatim. The forwarding logic already existed; the test locks the contract PR feat(cockpit): server-side content bundle with Shiki highlighting #2 will depend on.ChatApprovalCardcomposition. Native HTML<dialog>+showModal(), top-layer rendering, focus trap and Escape for free. API:[agent],[matchKind],[title],[showEdit],(action)emits'approve' | 'edit' | 'cancel'. Body is a content-projected<ng-template #body let-payload>slot. 9 unit tests cover body projection, matchKind filter (both branches), all three action emits, showEdit visibility, dialog open/close transitions, and Escape → cancel with preventDefault.(action)enum, same DOM placement.docs/superpowers/.Visual design
Approval card uses an HTML
<dialog>modal — explicitly halts the conversation for high-stakes consent. Backdrop click does NOT close (must use a button). Escape → cancel. Refreshed interrupt panel stays inline (lower-stakes "agent paused, look at this" pattern). The two compositions share visual vocabulary but signal different intent.Test plan
nx test langgraphgreennx test chatgreen (9 new ChatApprovalCard tests + existing ChatInterruptPanel suite)Spec:
docs/superpowers/specs/2026-05-25-hitl-refund-cockpit-blog-design.mdPlan:
docs/superpowers/plans/2026-05-25-hitl-refund-cockpit-blog.md🤖 Generated with Claude Code