Commit Graph

6858 Commits

Author SHA1 Message Date
Jordan Ritter 2a2bcb2209 fix(shell-docs/docs-render): match doubled-brace components prop in inlineSnippets
MDX authors pass component-map overrides via doubled-brace object
syntax, e.g. `<SharedContent components={{ Foo: Bar }} />`. The
previous regex used `[^}]*` which truncates at the inner `}`, so
the tag never matched and the snippet was never inlined. Match the
doubled-brace object form explicitly with `\{\{...\}\}` and
`[\s\S]*?` so multi-line prop objects still match.
2026-04-20 22:18:14 -07:00
Jordan Ritter f1be2bc0d3 fix(shell-docs/docs-render): backref and longest-first alternation in convertTablesInJSX
JS regex alternation is leftmost-first, not leftmost-longest, so for
source like `<Tabs>` the pattern `Tab|Tabs` matches "Tab", `[^>]*`
consumes the "s", and the close-side alternation would then pair
with any container's `</...>` regardless of which tag opened. Two
separate bugs fell out of this:

- Prefix collisions (Tab vs Tabs) silently skipped table conversion.
  Sort JSX_CONTAINER_TAGS longest-first so the opener always matches
  the actual outer tag name.
- Mismatched pairs like `<Tabs><Tab>x</Tab></Tabs>` paired the outer
  `<Tabs>` with the inner `</Tab>`, stranding `</Tabs>`. Use a
  numbered backref (`\\2`) on the closing tag so only the same tag
  name can close the match.

Also tighten the inline comment on the nested-same-tag bailout to
reflect that the non-greedy match now closes on the same tag, not
"any container in the set".
2026-04-20 22:18:00 -07:00
Jordan Ritter 0dadff324c fix(ci): drop dead HTTP_CODE sentinel and redundant fromJSON in showcase_deploy
matrix.service.timeout is already a number in the generated matrix
JSON, so wrapping it in fromJSON() was a no-op that only obscured
the expression. Drop the wrapper.

The HTTP_CODE="000" sentinel assigned immediately before the probe
loop is dead: the loop's first iteration unconditionally overwrites
HTTP_CODE before any reader runs. Remove it to avoid implying a
meaningful default where there isn't one.
2026-04-20 22:17:29 -07:00
Jordan Ritter 136f36a178 fix(ci): extend shell-dashboard and shell-docs path filters to shared and scripts
The shell-family starters bundle shared demo content and tooling at
build time via showcase/scripts/bundle-demo-content.ts, which walks
showcase/shared and showcase/packages/*/manifest.yaml. A change to
any of those inputs can alter the generated bundle without touching
the package directory, so path-filter was under-reporting changes
and skipping deploys that actually needed to rebuild. Extend the
filters to shared/**, scripts/**, and packages/*/manifest.yaml so
those inputs trigger the correct downstream deploys.
2026-04-20 22:17:06 -07:00
Jordan Ritter edbc2b0331 fix(ci): harden showcase_deploy Slack notify, concurrency, shared copy scope
- Promote SLACK_WEBHOOK_OSS_ALERTS to job-level env so the step-level
  if: gate can actually see it. Step-level env: is not visible to the
  same step's if:, which silently disabled every Slack post.
- Drop the service suffix from the concurrency group so two manual
  dispatches for different services don't serialize unexpectedly and
  push-triggered runs cancel each other deterministically.
- Rewrite the shared-module copy skip guard as an allowlist scoped to
  showcase/packages/*. Starters, shell-family, aimock, and shell-dojo
  don't consume shared modules, so the previous denylist missed every
  new self-contained context (context=".") and polluted the repo root.
2026-04-20 22:16:52 -07:00
Benjamin Taylor ef3b8eeeaa docs(learn): surface Intelligence Platform on the Learn landing page
Add a card for the new Intelligence Platform explainer to the Learn
index card grid, positioned between Architecture and Threads so the
landing page reads overall architecture → platform → features → protocols.
Without this, the page is reachable only via the sidebar and is
invisible to evaluators browsing /learn top-down.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:12:52 -05:00
Benjamin Taylor f23eebea06 docs(intelligence-platform): add self-hosting how-to and platform architecture explainer
Add the documentation kit for self-hosted CopilotKit Intelligence:

- (root)/premium/self-hosting.mdx — canonical how-to covering platform
  prerequisites, values file configuration (AWS ALB/IRSA and on-prem
  nginx paths), secret delivery via External Secrets or direct
  Kubernetes Secrets, install/verify/upgrade/uninstall steps, and an
  inline values.yaml reference
- learn/intelligence-platform.mdx — Diataxis explanation covering the
  app-api / app-frontend / realtime-gateway workloads, the
  control-plane/data-plane split, the multi-tenancy model
  (organization/project/user with auth.deploymentMode postures), the
  platform-layer vs application-layer split for self-hosted installs,
  secret rotation, scaling, upgrade, error handling, and the
  hosted-vs-self-hosted decision
- snippets/shared/premium/self-hosting.mdx — shared snippet that
  mirrors the canonical how-to for integration pointer pages
- integrations/*/premium/self-hosting.mdx (12 frameworks) — thin
  pointer pages that import the shared snippet, so Self-Hosting is
  discoverable from every integration sidebar (a2a has no /premium/
  subdir and is intentionally skipped)
- meta.json nav entries in (root)/premium, learn, and every integration
  premium sidebar

Also wraps the remaining Threads docs with the ThreadsEarlyAccess gate
(root threads.mdx, shared threads snippet, multi-conversation-chat
tutorial) and replaces the previous "self-hosted Enterprise, configure
your database connection per the Enterprise setup guide" placeholders
with real /premium/self-hosting links — the Threads docs referenced a
setup guide that did not exist until now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:12:52 -05:00
Benjamin Taylor 55af709e51 feat(docs): gate Threads docs behind early-access password wrapper
Wrap the Threads documentation surface with the existing
InsecurePasswordProtected component via a thin ThreadsEarlyAccess
wrapper that surfaces Threads-specific splash copy and the shareable
early-access URL. Register the wrapper in both route handlers so the
gate works for docs under both (home) and integrations slug routes.

Wraps learn/threads.mdx and reference/v2/hooks/useThreads.mdx; the
remaining Threads pages are wrapped in the follow-up commit that also
fixes the cross-links to the new Self-Hosting docs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:12:52 -05:00
Benjamin Taylor 14e751e644 docs(threads): align pagination API names and document lock tuning options
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:12:52 -05:00
Benjamin Taylor cc260e372f docs(threads): rewrite for developer-facing surface, add error handling, fix JSX highlight
- Rewrite explanation page: remove internal class names (IntelligenceAgent, AgentRunner),
  Phoenix channel references, and internal metadata fields (cpki_event_id)
- Add error handling section: mutation failures, WebSocket disconnection, thread locked (409)
- Add auto-naming, archive vs delete, and thread switching details across all pages
- Fix [!code highlight] in JSX (use {/* */} syntax)
- Fix tutorial What's Next suggesting auto-naming as extension (already built in)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 23:12:52 -05:00
Benjamin Taylor 7db5d068ac docs(threads): Add initial docs for Threads, plus a Learn landing page 2026-04-20 23:12:52 -05:00
Jordan Ritter 235f6a67a6 Merge jpr5/shell-docs-td-routes-infra into tech-debt branch 2026-04-20 19:44:57 -07:00
Jordan Ritter 4b2ef609bb Merge jpr5/shell-docs-td-lib into tech-debt branch 2026-04-20 19:44:57 -07:00
Jordan Ritter c02a0176ce Merge jpr5/shell-docs-td-framework into tech-debt branch 2026-04-20 19:44:56 -07:00
Jordan Ritter 1d5131c2d5 fix(showcase/scripts): bundle-demo-content path-traversal guard; generate-registry manifest.slug assertion
- bundle-demo-content: reject highlight: paths that resolve outside
  the package root. The bundle output is committed to the repo and
  consumed by both shells at build time, so a malicious or
  mistake-riddled manifest could otherwise smuggle arbitrary
  filesystem contents (../../secrets, absolute paths) into
  demo-content.json. Resolve relative to pkgRoot and throw on
  escape (finding #19).
- generate-registry: add a runtime guard that manifest.slug is a
  non-empty string before path.join(PACKAGES_DIR, manifest.slug).
  Schema validation upstream already enforces this, but a
  silently-undefined slug fed to path.join yields
  "<packages-dir>/undefined" and would produce an empty docs_links
  without surfacing any error. Fail loudly instead (finding #20).
2026-04-20 19:42:28 -07:00
Jordan Ritter 183cae2a43 fix(ci): check-binaries extends extension regex + set -euo pipefail + SIZE validation
- Extend the binary-extension regex to cover .class, .jar, .pyd,
  .pyc, .node, .bin, .pdb, .zip, .whl — any of which a build tool
  can drop into a PR and none of which the previous regex caught.
- Add set -euo pipefail at the top of the run block. Previously
  a transient wc failure (file deleted mid-diff) produced an empty
  SIZE, which then failed [ "$SIZE" -gt ... ] with "integer
  expression expected" on stderr while the script marched on —
  silent false-green possible. Now errors fail the job loudly.
- Guard the wc -c call with an explicit numeric-regex check on
  SIZE. A non-numeric or blank result now emits a ::warning:: and
  skips the file rather than falling into the arithmetic
  comparison and crashing under set -e (finding #17, #18).
2026-04-20 19:42:18 -07:00
Jordan Ritter a5461a5872 fix(ci): showcase_deploy documents prior-deploy ordering + hardens truncate_csv
- Add a comment to the prior-deploy Railway GraphQL query explaining
  that deployments(first: 1) relies on the API default of
  createdAt DESC ordering. Railway has no explicit orderBy argument
  on this field; documenting the assumption means a future schema
  change (or an operator reading the file cold) has something to
  point at before debugging stale-deployment guard regressions
  (finding #15).
- Harden both truncate_csv shell helpers (one per run block): disable
  pathname globbing via set -f for the iteration so a slug
  containing a glob char (*, ?, [) cannot expand against the
  filesystem, and lock IFS to whitespace for deterministic
  word-splitting regardless of caller env. Restore the prior glob
  state on the way out so other shell blocks see no side effect
  (finding #16).
2026-04-20 19:42:08 -07:00
Jordan Ritter 9773491455 refactor(showcase/shell-docs): shared ErrorBoundaryCard; thin route-level error wrappers
Extract the near-identical card markup from both route-level
error.tsx files into src/components/error-boundary-card.tsx. The
route-level handlers remain required (Next.js discovers them per
route segment) but are now one-line wrappers that forward props
with a scope label ("docs" / "ag-ui") so console.error entries
stay distinguishable per route segment (finding #14).
2026-04-20 19:41:57 -07:00
Jordan Ritter 4ca108ada0 fix(showcase/shell-docs): reference breadcrumb Title-Cases; category list derived from items
- Replace the className="capitalize" breadcrumb span (which only
  cased the first character, rendering my-component as
  My-component) with an explicit titleCase helper that splits on
  hyphens and capitalizes each segment (finding #12).
- Derive the sidebar category list from loadAllReferenceItems
  instead of hardcoding ["Components", "Hooks"]. A new
  REFERENCE_SUBDIRS entry in reference-items.ts now shows up
  automatically without a second edit here (finding #13).
2026-04-20 19:41:50 -07:00
Jordan Ritter f2af758f0c fix(showcase/shell-docs): ag-ui titleFromSlug title-cases + caches nav titles
- titleFromSlug now Title-Cases the result (multimodal-inputs →
  Multimodal Inputs) instead of returning a lowercased fallback.
  The lowercase labels previously clashed with the docs-render
  and reference-breadcrumb conventions elsewhere (finding #10).
- Wrap getTitleForSlug in a process-scoped cache with dev-mode
  invalidation, mirroring reference-items.ts. Previously every
  entry in NAV_DEFINITION re-opened and re-parsed its MDX file on
  every request — multiply across ~20 nav entries per render and
  it added noticeable fs churn (finding #11).
2026-04-20 19:41:42 -07:00
Jordan Ritter e6f2476fe3 fix(showcase/shell-docs): harden [framework] route — RESERVED slugs, null-alt filter, registry-gated landing cards
- Reject RESERVED_ROUTE_SLUGS at the handler as defense-in-depth.
  Next.js already prefers exact-match top-level routes over this
  catch-all, so /docs, /ag-ui, etc. never reach here under normal
  routing — but if the registry ever ships an integration whose slug
  collides with a reserved segment, the handler now short-circuits
  with notFound() rather than rendering garbage (finding #6).
- Import the shared findFrameworksWithCell helper instead of a
  duplicated local copy (finding #3 follow-through).
- Filter out unresolved alternative-framework slugs BEFORE mapping
  to React fragments so the ", " separator aligns with the final
  rendered count. The pre-filter index previously emitted stray
  commas when an entry dropped to null mid-sequence (finding #7).
- FrameworkLandingPage's four hardcoded LandingCards are now gated by
  registry integration.features presence: strands (no HITL support)
  no longer shows a dead "Human-in-the-Loop" card. The card
  definitions are hoisted into a module-level constant with a TODO
  pointing at the eventual feature-id → doc-slug mapping
  (finding #8).
- Declare export const dynamicParams = true explicitly so a future
  migration to output: "export" fails loudly here (under static
  export dynamicParams must be false) rather than silently 404ing
  every /<framework>/<slug> URL (finding #9).
2026-04-20 19:41:34 -07:00
Jordan Ritter bf8da2c216 refactor(showcase/shell-docs): extract findFrameworksWithCell; validate integration slug; sort-ordered preview selection
- Extract findFrameworksWithCell into @/lib/docs-render so the docs
  catch-all and framework-scoped catch-all share one implementation
  instead of carrying a near-identical local copy in each (finding #3).
- Validate /docs/integrations/<slug> against the registry with
  notFound() when the slug is unknown. Previously a crafted URL like
  /docs/integrations/fake-framework silently fell through to an empty
  nav tree, indistinguishable from a valid integration with no scoped
  content (finding #4).
- Sort integrations by sort_order then slug before picking the
  animated preview URL. Registry iteration order alone isn't
  deterministic w.r.t. the visual priority the docs UI shows
  everywhere else, so the preview now matches (finding #5).
2026-04-20 19:41:21 -07:00
Jordan Ritter a12be881ad feat(showcase/shell-docs): snippet supports comma-separated line ranges + maps tsx/jsx/sh/bash to hljs langs
Two additions in snippet.tsx:

1. parseLineRange now accepts comma-separated segments like
   `lines="1-5,10-15"`. Each segment is validated and sliced
   independently; discontinuous sections are stitched with a visible
   `// ...` gap marker so readers see the jump. Invalid segments fail
   the whole prop (clear error beats partial rendering). Single-range
   and open-ended ("A-") forms continue to work unchanged.

2. resolveHljsLanguage now has explicit entries for tsx (→ typescript),
   jsx (→ javascript), and sh / bash / shell (→ bash). These are the
   common bundler-emitted hints that previously returned null and
   fell through to highlightAuto — producing noisy one-shot warnings
   and non-deterministic highlighting.
2026-04-20 19:36:57 -07:00
Jordan Ritter 38b9858920 chore(showcase/shell-docs): reference-items documents cache-lifecycle
The __itemsCache has no invalidation hook and lives for the life of
the Node process. That's correct for the current `next start`
deployment but silently fragile if we ever add ISR to /reference —
the cache would serve stale items forever.

Replace the two-line inline comment with a JSDoc block that spells
out the prod vs dev behaviour and the ISR caveat, so future changes
know where the assumption lives.
2026-04-20 19:36:45 -07:00
Jordan Ritter 69d497412b fix(showcase/shell-docs): mdx-registry Tooltip warns on dropped props; validate iframe src; Link detects external href
Three loosely-coupled shim hardenings in one commit (all in mdx-registry.tsx):

- Tooltip / TooltipProvider were children-only shims that silently
  dropped Radix-style `content` / `label` props. Route through
  stub() so dev gets a one-shot warning with the dropped prop names.

- YouTubeVideo + IframeSwitcher now validate author-controlled URLs
  via a shared validateIframeSrc() helper: only https:// is accepted,
  malformed URLs fall back to rendering nothing, and dev gets a
  targeted warning. YouTubeVideo also enforces the 11-char video-id
  shape so a stray value can't traversal-inject query params into the
  embed URL.

- Link shim now detects external hrefs (https://..., mailto:..., etc.)
  and routes them through a plain <a> with sensible defaults
  (target=_blank, rel=noopener noreferrer). Internal hrefs continue to
  use next/link for client-side navigation. next/link should never be
  used for external URLs — it spuriously prefetches them.
2026-04-20 19:36:37 -07:00
Jordan Ritter 1a354f5b5b refactor(showcase/shell-docs): document inlineSnippets regex selectivity
The inlineSnippets regex deliberately only matches strict self-closing
JSX with an optional `components={...}` attr, which confused readers
into thinking tags like `<Snippet region="x" />` fall through by
accident. Document the two-path design (SNIPPET_MAP inlining vs MDX
component map) so future edits don't try to "fix" the selectivity.

No behaviour change. SNIPPET_MAP aliases were already documented
in-place (finding noted earlier); this commit covers the regex comment
only.
2026-04-20 19:36:25 -07:00
Jordan Ritter 04b1353f9d perf(showcase/shell-docs): disable readTitle/readMeta caches in dev
readTitle/readMeta are backed by process-scoped Maps. Without a dev
bypass, editing an MDX title or meta.json required a server restart to
see the change — the nav sidebar would keep showing the old title.

Match the convention already used in reference-items.ts: gate both the
read and write paths on isProd() so `next dev` re-reads the source on
every request. Production behaviour is unchanged.
2026-04-20 19:36:04 -07:00
Jordan Ritter c7d225a48e fix(showcase/shell-docs): oxfmt pass on router-pivot 2026-04-20 19:35:57 -07:00
Jordan Ritter 4c955d9ef7 refactor(showcase/shell-docs): sidebar-link drop dead scope/fallbackHref props + update callers
Both props were accepted but ignored (underscore-destructured). scope
was originally intended to switch resolution logic, but both branches
collapsed to the same href rule. fallbackHref was a pre-hydration
placeholder that became unnecessary once the provider made framework
URL-derived.

Remove them from the public SidebarLinkProps and from the only caller
(docs-page-view), which was computing a scope based on slugHrefPrefix
solely to pass it through.
2026-04-20 19:35:33 -07:00
Jordan Ritter db4f94c9a2 refactor(showcase/shell-docs): framework-tabs cell/region props optional + documented
cell and region are authored on the interface for MDX usage + tooling
but the component doesn't consume them at runtime — the parent MDX
renderer pre-renders one <Snippet> per framework on the server and
emits them as children. Mark them optional and document the contract.

Also filter React.Children.toArray output to valid elements before the
index→framework map, so stray whitespace text nodes injected by MDX
don't shift the mapping and render the wrong snippet.
2026-04-20 19:35:26 -07:00
Jordan Ritter 126416d318 fix(showcase/shell-docs): framework-selector adds touchstart click-outside handler
iOS Safari does not reliably fire mousedown for taps landing outside
focusable UI, so the panel stayed open on mobile. Mirror the existing
click-outside handler on touchstart and widen the handler type to
MouseEvent | TouchEvent. stripFrameworkPrefix already restricts its
match to the first path segment (docstring makes this explicit).
2026-04-20 19:35:19 -07:00
Jordan Ritter 4f08823384 fix(showcase/shell-docs): docs-tabs handles items/children mismatch + stale active
- Dev-only console.warn when author-supplied items.length diverges from
  the number of <Tab> children — silent drop of extra entries hid bugs.
- Dev-only console.warn on duplicate labels — React keys on label below
  so duplicates broke reconciliation.
- Tab button keys now include the index so duplicate labels don't cause
  React key collisions.
- Added a useEffect that re-seeds the active tab when the set of labels
  changes (e.g. MDX edit swaps titles, HMR reload). Previously useState
  initialized once on mount, so a tab whose label disappeared left the
  panel stuck empty.
2026-04-20 19:35:13 -07:00
Jordan Ritter ee9acdf334 fix(showcase/shell-docs): docs-steps filters to Step children; adds list a11y
Previously any valid child element received the injected __index/__total
props — stray non-Step valid elements (e.g. spacer divs) would have those
props passed straight to the DOM, triggering React warnings. Now filter
to elements whose type === Step before cloning.

Also add role='list' to the Steps container and role='listitem' to each
Step so assistive tech can enumerate the sequence.
2026-04-20 19:35:04 -07:00
Jordan Ritter e4c1b94e2b fix(showcase/shell-docs): docs-callout warns on unknown type
Silent fallback to 'info' masked typos in MDX authors' type props. Now
emit a dev-only console.warn listing the known types when an unknown
one slips past TypeScript (e.g. from raw MDX string literals).
2026-04-20 19:34:58 -07:00
Jordan Ritter 7b62d36bfd fix(showcase/shell-docs): brand-nav activeBrand boundary + z-index layering + drop dead props
- activeBrandFromPath now matches /ag-ui exactly or /ag-ui/..., not any
  path starting with those six chars — prevents misclassifying a future
  /ag-ui-* slug as AG-UI.
- Mobile menu panel z-index bumped to z-[51] so layering above the z-50
  backdrop doesn't rely on DOM sibling order.
- BrandNavProps (frameworkOptions, frameworkCategoryOrder) were unused
  dead API — removed from the interface and function signature. Call
  site passes no props, so no caller changes.
2026-04-20 19:34:51 -07:00
Jordan Ritter 92252c6ba5 refactor(showcase/shell-docs): property-reference deep walker for nested collapsable propagation
React.Children.map only visits *direct* children. When an author
wraps nested <PropertyReference> in a <div> or <Fragment> (a common
MDX pattern), the nested references silently lost `collapsable:
true` propagation because the walk stopped at the wrapper.

Replace the single-level `React.Children.map` with
`deepMapPropertyReferences`, a recursive helper that:
  - clones + enhances any PropertyReference at any depth with
    `collapsable: true`
  - preserves arbitrary wrapper elements (div, Fragment, other
    components) and recurses into their children
  - stops recursing once it hits a PropertyReference — that
    reference's own render will deep-walk ITS children on its turn,
    which is the correct nesting semantic

Updates the JSDoc above the enhanced-children block to reflect the
new behavior — nested wrappers are now supported.
2026-04-20 19:34:36 -07:00
Jordan Ritter f6c945a0d4 fix(showcase/shell-docs): router-pivot guards hydration flash via hasHydrated flag
Both FrameworkGuardedContent and RouterPivot used to render against
`storedFramework` on the very first client render, when it is always
null (localStorage is read in a mount effect inside
FrameworkProvider). A returning user who picked LangChain would
briefly see the full pivot grid + MDX body flash in before
storedFramework flipped from null to "langgraph-python" and the
redirect fired.

Gate both components behind a local `hasHydrated` flag flipped in a
mount useEffect. Pre-hydration we render null (for the MDX body) or
a minimal "Loading…" placeholder (for the pivot itself), so
returning users go straight to the redirect placeholder instead of
flashing content that's about to disappear. Fresh visitors see the
pivot on the next tick — imperceptible in practice.
2026-04-20 19:32:32 -07:00
Jordan Ritter 1b8ce7c1ce fix(showcase/shell-docs): framework-provider exposes storageAvailable + cross-tab storage listener
Previously readStoredFramework returned null for both "never set" and
"localStorage unavailable" — consumers couldn't distinguish a fresh
visitor from a private-mode browser. Introduce a tri-state: keep
storedFramework: string | null for the value, and add
storageAvailable: boolean so UIs can branch on "we can't persist
your pick" separately from "you haven't picked yet".

Also subscribe to window `storage` events so that when another tab
clears or changes selectedFramework, this tab's stored state stays
in sync (StoredFrameworkHighlight badge + RouterPivot redirect
react immediately without a reload).

Strengthens the comment above the URL-persistence effect explaining
why `stored` is intentionally excluded from the deps array (prevents
a setState ping-pong loop), and adds behavioral "Covered by:" notes
above each non-trivial fix.
2026-04-20 19:31:46 -07:00
Jordan Ritter 05cd01ec04 Finish the grid: #4085 + shell platform restructure (shell-docs, shell-dashboard, shell-dojo) (#4109)
## Summary

- Merges #4085 (Atai's no-docker-restructure feature port — merge-ready
variant) as the primary base.
- Renames `showcase/shell-internal/` → `showcase/shell-dashboard/` +
provisions Railway service at `dashboard.showcase.copilotkit.ai`.
- Renames `showcase/shell-dojolike/` → `showcase/shell-dojo/` + renames
Railway service in place (domain unchanged).
- Extracts MDX-docs infrastructure (`/docs`, `/[framework]`, `/ag-ui`,
`/reference` + components, libs, content) from `showcase/shell/` into
new standalone `showcase/shell-docs/` package; provisions Railway
service at `docs.showcase.copilotkit.ai`; adds 301 redirects on shell
for every moved route (including 17 per-framework slugs enumerated from
`registry.json`).
- Fixes `starter-langroid` `/api/health` 503 (sed stdout wrappers +
readiness gate); adds red-green regression guards in
`starter-consistency.test.ts`.

## DNS state

- `dashboard.showcase.copilotkit.ai` CNAME → `6u9icvje.up.railway.app` —
✅ live in Route53.
- `docs.showcase.copilotkit.ai` CNAME → `t6ge0qwv.up.railway.app` —
pending Route53 add.

## Railway services

- `showcase-shell-dashboard` (ID `4d5dfd74-be61-40b2-8564-b53b7dd4c15b`)
— provisioned, image pending first deploy.
- `showcase-shell-docs` (ID `7badfb8d-4228-414c-9145-b4026803714f`) —
provisioned, image pending first deploy.
- `showcase-shell-dojo` (ID `7ad1ece7-2228-49cd-8a78-bddf30322907`) —
renamed from shell-dojolike; already live.

## Closes / supersedes

- Supersedes #4084 (docker-restructure variant; preserved on
`jpr5/ftg-shell-ops` for future consideration, not merged here).
- True-merges #4085 via `--no-ff` — that PR auto-closes on this PR's
merge.

## Known non-blockers

- `/ag-ui/introduction` throws a server-component `onMouseEnter` runtime
error on `next start`. Same issue exists in shell today — pre-existing,
not a regression. Follow-up needed.
- `showcase/shell-dojo` lacks `package-lock.json` and `.gitignore`;
trivial follow-up for parity with siblings.
- `search-modal` retains the flat `search-index.json` shape (not the
extensible `{version:1, sources:[...]}` shape). Generator is the single
point of change if multi-shell search is wanted later.
- oxfmt has a pre-existing oscillation bug on 14 `.mdx` files with
`<Steps>` structures; sidestepped by mirroring the existing
`showcase/shell/src/content/**` ignore policy to the new
`showcase/shell-docs/src/content/**` path.

## Test plan

- [ ] CI green end-to-end (Validate Showcase, unit tests on 20/22/24,
format, oxlint, commitlint, starter-smoke).
- [ ] \`showcase_deploy.yml\` builds shell-dashboard + shell-docs images
to GHCR and Railway pulls them successfully.
- [ ] Add \`docs.showcase\` CNAME in Route53
(\`t6ge0qwv.up.railway.app\`) — without this,
docs.showcase.copilotkit.ai won't resolve and Railway won't provision
its TLS cert.
- [ ] Verify \`dashboard.showcase.copilotkit.ai/\` returns 200.
- [ ] Verify \`docs.showcase.copilotkit.ai/\` returns 200 and
\`/langgraph-python/quickstart\` renders.
- [ ] Verify \`showcase.copilotkit.ai/\` returns grid (200);
\`/docs/foo\` 301s to \`docs.showcase.copilotkit.ai/foo\`;
\`/react/foo\` 301s; \`/integrations\` and \`/matrix\` do NOT redirect.
- [ ] \`starter-langroid\` redeploy via \`showcase-deploy\` workflow:
\`/api/health\` returns 200.
2026-04-20 19:25:39 -07:00
Jordan Ritter 5964b44b57 fix(ci): shell-dashboard ALL_SERVICES entry mirrors shell-docs structure 2026-04-20 18:58:57 -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 539c860861 refactor(showcase/shell-docs): 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 1c85fc0d70 fix: clarify pin-drift alert wording (DRIFT vs FAIL) (#4110)
## Summary
- Rename `FAIL=N` → `DRIFT=N` in the weekly showcase pin-drift Slack
alert; "FAIL" reads as a regression even when N matches the ratchet
baseline.
- Restructure three paths: `[stable]` (match), `[REGRESSION]` (count or
hash grew), `[IMPROVED, ratchet me]` (count shrunk).
- Red path retains run URL link. Ratchet logic, baseline file, and
hashing unchanged.

## Test plan
- [ ] Verify `.github/workflows/<name>.yml` YAML parses.
- [ ] Confirm next weekly run posts `[stable]` framing (or dry-run the
step manually if feasible).
- [ ] No change to `showcase/scripts/fail-baseline.json` or ratchet
logic.
2026-04-20 18:16:01 -07:00
Jordan Ritter c3ad48a8af fix: clarify pin-drift alert wording (DRIFT vs FAIL)
The weekly Showcase pin-drift Slack alert previously read
"📉 Showcase pin-drift (weekly): FAIL=N
(baseline N) [ok]". The token "FAIL=N" read as a regression even when N
matched the ratchet baseline exactly (a stable week), generating recurring
false-alarm fatigue on #oss-alerts.

Reframe the notification text into three explicit states:

- [stable]   — DRIFT=N matches baseline AND hash matches
- [REGRESSION] — DRIFT=N grew OR hash mismatch (set drifted); keeps the
  🚨 emoji + run URL for actionable alerts
- [IMPROVED, ratchet me] — DRIFT=N shrank; reminder to update the baseline

Presentation-only. The ratchet logic in validate-pins.ts, the baseline file
(showcase/scripts/fail-baseline.json), and the FAIL-line hashing are
unchanged.
2026-04-20 18:14:13 -07:00
Jordan Ritter 41c006fa31 chore: re-trigger CI on formatting commit 2026-04-20 18:02:57 -07:00
github-actions[bot] dc587abbcd style: auto-fix formatting 2026-04-21 00:51:40 +00:00
Jordan Ritter c91c7c567d fix(showcase/scripts): generate-search-index warns on missing scan dirs
If shell-docs/src/content/{reference,ag-ui,docs} didn't exist the
script silently produced a tiny index with no warning — operators
only found out by noticing Cmd-K search returning nothing.
Warn per missing directory and exit non-zero if ALL scan roots are
missing (that means we're running outside a prepared tree, e.g.
shell-docs didn't emit into the expected layout).
2026-04-20 17:49:59 -07:00
Jordan Ritter 1bc90bc9ec fix(ci): showcase_deploy prior-deploy jq uses // empty for null normalization
The main-deploy step already uses '// empty' on PRIOR_DEPLOY_ID but
the verify step extracted DEPLOY_ID / STATUS / DOMAIN without it, so
when Railway's edges array was transiently empty these became the
literal string 'null'. That breaks the prior-vs-fresh comparison and
the DOMAIN emptiness guard in inconsistent ways. Add '// empty' to
all three jq filters so empty-edge responses normalize to '' the
same way everywhere.
2026-04-20 17:49:59 -07:00
Jordan Ritter c647a1dc9b fix(showcase/scripts): bundle-demo-content watch-mode tracks failure state
The watch loop logged '[watch] bundle failed' once and then fell
silent — repeat failures looked like success, and recoveries were
invisible (no news = assumed fine). Track the last error in module
scope so we distinguish first-failure from repeat-failure, and log an
explicit 'bundle recovered' note when the next green run clears the
state. Makes dev-mode transitions visible instead of silent.
2026-04-20 17:49:58 -07:00