Commit Graph

191 Commits

Author SHA1 Message Date
Jordan Ritter 8b3f53aefb fix(shell-dashboard): replace double cast with single CatalogData cast
CR-C-page.1: `catalog as unknown as CatalogData` violated the project
policy against double casts. catalog.json is generated by pretest/
predev/prebuild from generate-registry.ts and conforms to CatalogData
by construction, so a single `as CatalogData` cast is safe and clearer.

Typecheck: no new errors (pre-existing __tests__ + status-table.tsx
errors are unrelated and unchanged). All 220 vitest tests pass.
2026-04-25 19:07:22 -07:00
Jordan Ritter d24a9d9a5f merge: cr-fix-B2 CR fixes 2026-04-25 19:05:05 -07:00
Jordan Ritter d3ab9d0387 fix(showcase-dashboard): collapse sub-second formatRelative to 'now' sentinel
Sub-second deltas previously rendered as "in 0s" / "0s ago", which
flickered between sides of the boundary on every tick. Collapse to a
single "now" sentinel for |delta| < 1s and add a Number.isFinite guard
that falls back to "—" so non-finite inputs don't cascade into
unreadable output.
2026-04-25 18:56:15 -07:00
Jordan Ritter f727665124 fix(showcase-dashboard): guard sparkline against tiny widths and drop dead branch
Sparkline previously divided unconditionally by (durations.length - 1)
inside a length===1 branch that the early return at length<2 made
unreachable. Removed the dead conditional. Added a small-viewport guard
that falls back to the flat-dash placeholder when innerW or innerH is
non-positive, preventing negative or NaN coords when callers pass
width <= PADDING * 2.
2026-04-25 18:56:10 -07:00
Jordan Ritter 8a8e4d81d5 fix(showcase-dashboard): stabilize handleTrigger with useCallback for tabs deps
The tabs useMemo closed over handleTrigger but did not list it in its
dependency array. Today the handler is a no-op so the latent bug is
invisible, but once B4b wires this to the real ops API trigger
endpoint the memo would retain a stale closure. Wrap handleTrigger in
useCallback and add it to the tabs deps array so the memo refreshes
correctly.
2026-04-25 18:56:04 -07:00
Jordan Ritter fa612ac4a7 fix(showcase-dashboard): hide Run specific... when no service slugs are known
The trigger menu's "Run specific..." entry was unusable for idle probes
because slugs are sourced from inflight.services, which is null in the
typical manual-trigger case. Hide the entry entirely when serviceSlugs
is empty (Option C); operators can still trigger all targets via "Run
all". A richer ProbeScheduleEntry contract that exposes discovered
targets for idle probes is tracked separately.

Also wraps onTrigger awaits in try/catch so async rejections surface
through a local error state instead of bubbling up as unhandled promise
rejections, and resets the selected slug set on completion so the next
trigger session starts clean.
2026-04-25 18:55:57 -07:00
Jordan Ritter d719e8380e fix(showcase-dashboard): align run state label with tone for missing summary
runTone returned "gray" (unknown) when finishedAt was set but summary
was null, while runStateLabel returned "completed" for the same case —
producing a gray badge labeled "completed", exactly the misleading
combination the tone comment said it was avoiding. runStateLabel now
returns "unknown" so label and tone agree.
2026-04-25 18:55:49 -07:00
Jordan Ritter 7cec1033c2 fix(showcase-dashboard): filter past nextRunAt from idle next-run banner
When all probes are idle, findNextScheduled previously returned the
entry with the smallest nextRunAt regardless of whether that timestamp
was already in the past, producing nonsensical "Next: smoke 5m ago"
banners. Filter out entries whose nextRunAt is < now and fall back to
the existing "No upcoming runs scheduled." sentinel.

Also typed STATE_ICON as Record<ServiceState, string> so missing service
states fail to compile rather than silently rendering undefined icons.
2026-04-25 18:55:43 -07:00
Jordan Ritter 7d8228075d fix(shell-dashboard): drop duplicate ProbeScheduleEntry, re-export canonical
The local interface in status-tab.tsx was marked TODO and had drifted
from the canonical lib/ops-api definition: it lacked error? and
finishedAt? on service progress entries, and used a bare 'string' for
'kind' instead of the ProbeKind union.

Delete the local interface and re-export the canonical type from
lib/ops-api so existing 'import type { ProbeScheduleEntry } from
"./status-tab"' call sites continue to compile against the single
source of truth (CR-B1.1).
2026-04-25 18:55:30 -07:00
Jordan Ritter 02a54712b9 fix(shell-dashboard): replace aliveRef with per-effect cancelled flag
The previous useProbes/useProbeDetail hooks reset aliveRef.current to
true at the top of every effect run. A fetch from the prior cycle that
resolved between cleanup and re-init could pass the new effect's alive
check and clobber state with stale data.

- useProbes: per-effect 'cancelledRef' (mirrored so the imperative
  refetch callback can honor it). Cleanup flips cancelledRef true.
- useProbeDetail: per-effect 'let cancelled = false' closure; cleanup
  flips it. Each effect run gets its own closure, so a stale fetch from
  the prior cycle cannot land setData (CR-B1.3).
- useProbeDetail also clears data immediately on id change so the
  panel header (driven by prop) is never out of sync with the body
  while the new fetch is still in flight (CR-B1.4).
- useTriggerProbe gains a per-call AbortController whose signal is
  forwarded to triggerProbe; unmount aborts any in-flight POST so we
  don't fire duplicate runs after the user navigates away (CR-B1.5).

Tests cover: rapid-deps stale-data path, rapid-id stale-data path,
data-clear on id change, and unmount-during-trigger abort.
2026-04-25 18:55:18 -07:00
Jordan Ritter c3382e5ea1 fix(shell-dashboard): harden ops-api types and error reporting
- ProbeLastRun.summary is now nullable to match ProbeRun.summary; the
  server can complete a run with no summary (showcase-ops CR-A1.5).
- ensureOk surfaces body-read failures with a 'body read failed: ...'
  marker instead of swallowing them silently (CR-B1.6 / CR-C15).
- New parseJson helper attributes JSON parse failures to the requesting
  URL so call sites can tell which endpoint produced bad bytes.
- triggerProbe gains a TriggerProbeOptions interface with an optional
  AbortSignal; passed straight through to fetch() so callers can cancel
  in-flight POSTs (CR-B1.5).
2026-04-25 18:55:07 -07:00
github-actions[bot] d258bcf7d8 style: auto-fix formatting 2026-04-26 01:39:40 +00:00
Jordan Ritter dfdd8d4e88 chore(showcase-dashboard): add missing CatalogCell fields to test fixtures
The CatalogCell type gained three required fields (integration_name,
feature_name, category_name) before this branch landed; the existing
test fixtures predate that change and surface as 32 typecheck errors
in CI. Add plausible Title-Case names to each fixture so the type
checker is happy. Test logic and assertions are unchanged.
2026-04-25 18:34:27 -07:00
Jordan Ritter 77c510c0b5 feat(showcase-dashboard): wire row click selection to open the probe-detail panel
StatusTable gains an optional onSelect(probeId) prop. When provided, rows
become clickable (cursor-pointer) and the action cell stops propagation so
that clicking the trigger button does not also open the drilldown.

StatusTab owns the selection state (useState) and renders StatusDetailPanel
beneath the running panel. The panel returns null when no probe is
selected, so this is a zero-cost addition to the default render.
2026-04-25 18:30:24 -07:00
Jordan Ritter 11b1f39a9f feat(showcase-dashboard): add probe-detail panel with runs list and duration sparkline
Adds three new components for the Status tab drilldown:

- StatusRunsList: recent-runs table with relative-time, duration, state badge
  (running/completed/failed tones), manual chip when triggered=true, and
  pass/total summary with em-dash fallback.
- StatusDurationSparkline: pure-SVG inline sparkline (no charting deps),
  oldest-to-newest convention, dash placeholder for <2 points, configurable
  width/height.
- StatusDetailPanel: renders nothing when probeId is null, shows loading,
  error, and data states from useProbeDetail; composes the runs list and the
  sparkline; close button calls onClose.

All three components ship with red-green vitest + RTL coverage (21 new tests).
2026-04-25 18:30:19 -07:00
Jordan Ritter d7e7b08339 feat(showcase-dashboard): wire D5/D6 PB keys into live-status pipeline
Extends `resolveCell` to read the `d5:<slug>/<featureType>` and
`d6:<slug>/<featureType>` PB row keys produced by the e2e-deep (D5)
and e2e-parity (D6) drivers. The new badges are informational and do
NOT contribute to the rollup — same model as the post-Phase-3 smoke
slot — because the alert engine routes those dimensions independently.

`useLiveStatus` already pulls every dimension via the page-level
unfiltered subscription, so no subscription-shape change is required.
The `d5` / `d6` literals already live in the closed `DIMENSIONS` enum
in showcase/ops/src/types/index.ts.

Adds D5 / D6 chips to `CellStatus` next to the existing E2E badge —
two ~4-line additions that reuse the existing LiveBadge wrapper, no
structural changes to feature-grid / cells-view / parity-view.
2026-04-25 18:29:41 -07:00
Jordan Ritter a53d472428 merge: integrate B3+B4a+B4b deps for B8 scope 2026-04-25 18:25:14 -07:00
Jordan Ritter ffafa2f70a feat(shell-dashboard): add showcase-ops API client and probe hooks for Status tab
Provides the data layer for the dashboard's Status tab against the
showcase-ops HTTP contract being built in parallel (B3).

- lib/ops-api.ts: types + fetchProbes / fetchProbeDetail / triggerProbe.
  baseUrl resolves explicit param → NEXT_PUBLIC_OPS_BASE_URL → /api/ops.
  Trigger sends Bearer token from caller; URL-encodes ids; uniform
  status-line errors on non-2xx.
- hooks/use-probes.ts: useProbes / useProbeDetail / useTriggerProbe.
  10s default polling, AbortController cancels in-flight on unmount or
  interval rollover, AbortError suppressed from user-visible state.

33 new tests (red→green), full shell-dashboard suite green (163/164,
1 pre-existing skip).
2026-04-25 18:06:04 -07:00
Jordan Ritter 8168e37514 feat(showcase-dashboard): add Status tab with probe schedule and run controls
Adds a 5th "Status" tab to shell-dashboard that visualizes the probe
schedule (humanized cron, relative next/last run, duration, pass/fail
result), a "currently running" panel with progress bar and per-service
state grid, and a per-row Trigger control with "Run all" / "Run
specific..." menu.

Components live in src/components: status-tab, status-table,
status-running-panel, status-trigger-button. Local ProbeScheduleEntry
interface is a placeholder; B4b's lib/ops-api types replace it at
merge time. page.tsx wires the tab with an empty placeholder list and
no-op trigger; B4b's useProbes() hook lands in a follow-up.

19 new vitest cases cover humanized cron, relative-time tick, last-run
color tone (green/red/gray), trigger menu actions, and idle vs inflight
panel modes. Full dashboard suite green (150 tests, 1 skipped).
2026-04-25 18:02:24 -07:00
github-actions[bot] 9a6ef908ea style: auto-fix formatting 2026-04-25 05:21:44 +00:00
Jordan Ritter 3f88ad2c90 fix(showcase-dashboard): align e2e key lookup with probe dimension
The e2e-demos probe writes per-demo rows keyed as e2e:<slug>/<featureId>
but resolveCell looked up e2e_smoke:<slug>/<featureId>. The mismatch
caused every per-demo depth chip to show gray (no data), leaving cells
stuck at D2. Fix: read the e2e dimension the probe actually writes.
2026-04-24 22:20:14 -07:00
Jordan Ritter abd5759324 fix(showcase): use single PB subscription to prevent SSE connection race
Seven concurrent useLiveStatus hooks each opened their own PocketBase
SSE connection during hydration. The PB SDK multiplexes subscriptions
over a single EventSource, but the concurrent subscribe() calls raced
the initial SSE handshake — some POST /api/realtime calls fired before
the clientId was available, returning 400. After MAX_RECONNECT_ATTEMPTS
(3), affected hooks set connection="error", triggering the "dashboard
unavailable" banner on all tabs.

Fix: replace 7 per-dimension hooks with a single useLiveStatus() call
(no dimension filter). All rows are fetched in one subscription and
the existing client-side keyFor() lookups filter by dimension
implicitly. Eliminates the 7-way race, reduces PB connection count
from 7 to 1, and removes the aggregateConnection helper entirely.

Verified live at dashboard.showcase.copilotkit.ai — zero banners, all
four tabs show real PB data with D2/D4 depth chips.
2026-04-24 01:04:49 -07:00
github-actions[bot] ba4d47e45f style: auto-fix formatting 2026-04-24 07:49:44 +00:00
Jordan Ritter 692d47bb7c fix(showcase): wire build-time env vars + flatten table alignment
Three fixes batched to minimize PR churn:

1. Dockerfile: add ARG NEXT_PUBLIC_POCKETBASE_URL so the PB URL gets
   baked into the Next.js bundle at build time. Without this, pb.ts
   resolves to the sentinel URL and the dashboard shows "unavailable"
   on every tab. Pre-existing bug exposed by fresh deploys.

2. showcase_deploy.yml: pass NEXT_PUBLIC_POCKETBASE_URL and
   NEXT_PUBLIC_SHELL_URL as build args for the shell-dashboard service
   in the CI matrix. Neither was ever passed before.

3. cell-matrix.tsx + parity-matrix.tsx: flatten nested table pattern
   that caused column misalignment. Category rows used colSpan with
   an inner <table> whose columns floated independently of the header.
   Replaced with useCollapsible hook + flat sibling <tr> rows.

Also regenerates package-lock.json for the plugin-react downgrade
from PR #4241 (npm ci was failing in Docker).

Local Docker build verified with --build-arg for both NEXT_PUBLIC vars.
2026-04-24 00:48:12 -07:00
github-actions[bot] 9acb3e3f24 style: auto-fix formatting 2026-04-24 06:38:58 +00:00
Jordan Ritter a2976ef6f0 fix(showcase): downgrade @vitejs/plugin-react to ^5.2.0
6.0.1 requires vite ^8.0.0 but pnpm resolves vite 7.3.1, causing
ERR_PACKAGE_PATH_NOT_EXPORTED when vitest loads. 5.2.0 supports
vite ^4-8 and resolves the issue. Pre-existing on main.
2026-04-23 23:37:02 -07:00
Jordan Ritter 887e96b36f test(showcase): add unit tests for D0-D4 dashboard components
68 new tests across 7 files: depth derivation, DepthChip, ParityBadge,
CollapsibleCategory, CellMatrix, ParityMatrix, PackagesSection depth.
2026-04-23 23:37:02 -07:00
Jordan Ritter b31a4fa4cf feat(showcase): wire D0-D4 tabs into dashboard page
Lift 7 PB subscriptions to page level, shared across 4 tabs. Add
Cells, Parity, Packages tabs via TabShell. Packages section gains
depth column. live-status dim union widened for D3 e2e data.
2026-04-23 23:37:02 -07:00
Jordan Ritter cbdc4259aa feat(showcase): add Cells and Parity tab components
CellsView + CellMatrix: 663-cell grid with collapse/expand by category,
filter chips, parity-tier column sorting. ParityView + ParityMatrix:
38 features x 17 integrations with LGP reference depth column.
2026-04-23 23:37:02 -07:00
Jordan Ritter 6c53c6e328 feat(showcase): add shared primitives for D0-D4 dashboard tabs
DepthChip, ParityBadge, CollapsibleCategory, IntegrationHeader,
StatsBar, CoverageBar, FilterChips, TabShell, depth-utils, and
CatalogData types.
2026-04-23 23:37:01 -07:00
Jordan Ritter f861bd39b4 fix(showcase): make shell-dashboard import from its own data directory
Shell apps should be independent — no shell cross-imports another
shell's data directory. Replace ../../../shell/src/data/ imports in
shell-dashboard with @/data/ (resolves to src/data/ via tsconfig path
alias). Update Dockerfile to copy shell-docs content (for probe-docs
MDX checks) instead of the entire shell package. Remove unused
bundle-demo-content from dashboard's build pipeline.
2026-04-23 21:12:40 -07:00
Jordan Ritter 58f95a08ae fix(showcase): strip generated_at timestamps from generators and consumers
Every generator embedded `generated_at: new Date().toISOString()` in its
output, causing constant git noise on every build/dev run even when
actual content was unchanged. Remove the field from all 4 generator
scripts, all consumer interfaces (Registry, BundledContent,
BundledStarters, DocsStatusBundle), inline type casts, and test
assertions.

Also: add shell-dashboard as a generate-registry output directory (it
was cross-importing from shell); move probe-docs output to
shell-dashboard/src/data/ (sole consumer); update test beforeAll to
generate files instead of restoring from git HEAD (prep for gitignore).
2026-04-23 21:12:32 -07:00
Alem Tuzlak 6dff6200e8 feat(showcase): wire open-gen-ui demos, update manifest and constraints
Declare open-gen-ui and open-gen-ui-advanced in langgraph-python
manifest (code existed, was never registered). Add both to
constrained-explicit allowlist, fill shell_docs_path for 5 demos,
add hitl-in-app override, drop stale chat-customization-css fallback.

Regenerate registry.json, demo-content.json, constraints.json,
and docs-status.json across shell / shell-dojo / shell-docs.
Bump feature/demo count assertion 30→32 in generate-registry test.
Extend check-binaries.sh whitelist for sister-shell demo-content.
2026-04-23 12:45:36 -07:00
github-actions[bot] e94aa1d4e1 style: auto-fix formatting 2026-04-23 16:16:22 +00:00
Jordan Ritter 9bce821779 feat(shell-dashboard): Phase 3 dashboard honesty pass
Phase 3.0: Pre-flight verified — 34 e2e_smoke rows in PB (producer
gap from PR #4200 resolved).

Phase 3.1: Rename dashboard e2e subscription to e2e_smoke to match
ops producer key. Update formatLabel/formatTooltip dim unions.

Phase 3.2: Add per-integration L1-L4 LevelStrip with Up/Wired/Chats/
Tools badges. New subscriptions for agent, chat, tools, e2e_smoke.
Widen aggregateConnection to variadic. Tools n/a gate uses
integration.demos.some(d => d.id === "tool-rendering").

Phase 3.3: Retire HealthDot from per-feature cells (L1 Up badge in
strip replaces it). Drop smokeRow from per-cell rollup (Decision #7).
Rollup now uses [healthRow, e2eRow] only. First-ever green rollups
enabled (smokeRow was always null in production).

Phase 3.4: Remove QA column — drop LiveBadge QA, CellState.qa,
subscription, legend entry. No producer ever existed.

Phase 3.5: Docs four-glyph mapping: ok->checkmark, missing->middle
dot, notfound->cross, error->exclamation. Each DocState has a
distinct glyph and tone.

Phase 3.6: Legend rewrite — drop QA/Hosted, add L1-L4 strip docs,
expand docs row for four glyphs, rewrite ? footnote.

Phase 3.7: Add PackagesSection below starters grid. Extends
registry.json with packages array from shared/packages.json. CI
drift test ensures package set matches integration set.
2026-04-23 09:14:05 -07:00
Jordan Ritter c1360c4bcc fix(shell-dashboard): resync scripts lockfile + unsilence npm ci
showcase/scripts/package.json bumped vitest to ^4.1.5 and added
@vitest/coverage-v8 ^4.1.5, but package-lock.json still carried vitest
4.1.4 and was missing the coverage package entirely. Docker builder
stage runs `npm ci`, which refuses to reconcile drift and fails with:

    Missing: @vitest/coverage-v8@4.1.5 from lock file
    Invalid: lock file's vitest@4.1.4 does not satisfy vitest@4.1.5

Regenerated showcase/scripts/package-lock.json with
`npm install --package-lock-only` to bring it back in sync.

Also removed --silent from the builder-stage `npm ci` calls so the
next same-class lockfile drift surfaces the real error in CI instead
of a bare 'exit code: 1'. Kept --silent on the prod-deps stage (that
one wasn't masking anything here).

Verified: `docker build -f showcase/shell-dashboard/Dockerfile .`
completes end-to-end locally.
2026-04-22 12:16:39 -07:00
Jordan Ritter 7f3fab47b2 feat(showcase/shell-dashboard): live PocketBase status wiring + tests
Replace the static status.json feed with a live PocketBase subscription
(useLiveStatus / useLastTransition hooks + live-status lib + pb client),
add vitest + playwright visual test setup, wire feature-grid + cell
pieces + badges to the live data model. Adds Dockerfile + .dockerignore
for Railway deployment of the dashboard.
2026-04-22 11:00:46 -07:00
Jordan Ritter aa4af554a0 Fix shell-dashboard shell links by plumbing NEXT_PUBLIC_SHELL_URL through build
The shell-dashboard app baked http://localhost:3000 into every demo and code link because NEXT_PUBLIC_SHELL_URL was never provided at build time and the source defaulted to localhost. Next.js inlines NEXT_PUBLIC_* at next build, so setting the value on Railway at runtime does nothing.

Fix: remove the silent localhost fallback, pass NEXT_PUBLIC_SHELL_URL as a Docker build arg from showcase_deploy.yml, and fail loudly if it's unset at build so this can't regress silently.
2026-04-21 13:09:47 -07:00
Jordan Ritter d143a197e2 refactor(showcase/shell-dashboard): simplify Dockerfile to match showcase-shell pattern 2026-04-20 18:58:57 -07:00
Jordan Ritter 863bee7966 fix(showcase/shell-dashboard): add missing Dockerfile modeled after shell-docs 2026-04-20 18:18:41 -07:00
Jordan Ritter daf09358c4 chore(showcase): rename shell-internal → shell-dashboard and provision Railway service @ dashboard.showcase.copilotkit.ai
- Renamed showcase/shell-internal/ → showcase/shell-dashboard/ (git mv for history).
- Updated package name to @copilotkit/showcase-shell-dashboard (+ lockfile).
- Updated external references: showcase/scripts/{probe-docs,generate-status}.ts comments and showcase/README.md.
- Added dispatch + filter + ALL_SERVICES entry for shell-dashboard in .github/workflows/showcase_deploy.yml.
- Provisioned Railway service showcase-shell-dashboard (id 4d5dfd74-be61-40b2-8564-b53b7dd4c15b):
  - image source ghcr.io/copilotkit/showcase-shell-dashboard:latest
  - env vars OPENAI_API_KEY, ANTHROPIC_API_KEY, PORT copied from showcase-shell
  - custom domain dashboard.showcase.copilotkit.ai attached (CNAME → 6u9icvje.up.railway.app)
  - image will be built and pushed via showcase_deploy.yml on merge
2026-04-20 13:54:17 -07:00