Commit Graph

6858 Commits

Author SHA1 Message Date
Jordan Ritter 0f46be9c37 chore(showcase/shell-docs): mdx-registry stubs log discarded props in dev
Add three dev-mode visibility affordances so MDX authors learn when
their embeds render nothing or when stub components silently discard
props:

- stub(name) helper wraps children-only shims and warns once per
  (component, propKeys) pair when non-children props are passed.
  Applied to Inspector and MCPApps as representative cases.
- warnSilentNull() + visible dev-mode fallback for FeatureIntegrations
  when no deployed integrations support the requested feature.
- InlineDemo now warns (missing props, unknown slug, or not-deployed)
  so authors see why their live demo didn't appear.
- Snippet base stub now emits a visible '[Snippet] runtime override
  required' placeholder in dev so missing DocsPageView override is
  obvious.

All warnings are gated on NODE_ENV !== 'production' and deduped so
HMR re-renders don't spam the console.
2026-04-20 16:48:01 -07:00
Jordan Ritter 5492fab195 fix(showcase/shell-docs): guard MDX filesystem reads against path traversal
Slug paths reaching loadDoc and buildBreadcrumbs come straight from
URL segments. Before this change, path.join(CONTENT_DIR, slugPath)
would silently escape CONTENT_DIR when slugPath contained '..'
segments (e.g. /docs/..%2F..%2Fsecrets), letting an attacker read
arbitrary files the server process has access to.

- Add a tiny safe-fs helper (resolveWithinDir / safeExistsSync /
  safeReadFileSync) that resolves a relative path under a declared
  base and returns null when the resolved path escapes.
- Route loadDoc and buildBreadcrumbs through resolveWithinDir so any
  traversal attempt collapses to a clean 'not found' fall-through.
- Apply the same guard to inlineSnippets' SNIPPETS_DIR reads for
  defense-in-depth, even though its inputs are currently internal.
2026-04-20 16:47:53 -07:00
Jordan Ritter 7d0b77f8a9 fix(showcase/shell-docs): copy-button surfaces clipboard failure
- Replace the silent empty `catch {}` with a proper error state:
  clipboard write failures now set state to "error", surface a
  "Copy blocked" label for 2s, and log the original error so devs
  can debug (permissions, insecure context, etc.) instead of the
  button failing invisibly.
- Collapse the two booleans into a single `CopyState` so idle/copied/
  error styling and aria-label stay in sync.
2026-04-20 16:47:37 -07:00
Jordan Ritter f119bbede1 fix(showcase/shell-docs): snippet validates reg.code shape + logs unknown langs
- Guard `reg.code` as a string before rendering; malformed
  `demo-content.json` (missing `code`, stale bundle) now produces a
  visible WarningBox instead of crashing React on `undefined`.
- `resolveHljsLanguage` warns once per unknown language via a
  module-scope Set, so authors learn the right names to use and stop
  relying on hljs.highlightAuto guessing wrong.
2026-04-20 16:47:23 -07:00
Jordan Ritter bcbc8276f8 fix(showcase/shell-docs): snippet highlight error logging + fallback class + range clamping
- hljs try/catch now logs key/file/language + original error instead of
  swallowing silently, so authors can spot bad snippets.
- When highlighting fails, drop the `hljs language-*` class so the
  escaped plain-text fallback isn't styled as though it were highlighted.
- Defense-in-depth non-string hljs return guard.
- `regionFromFile` normalizes by stripping a single trailing newline
  once, then splits — trailing-newline shape is consistent whether or
  not `lines=` is supplied, so CopyButton text is predictable.
- Clamp `end` via `effectiveEnd = Math.min(end, allLines.length)` and
  warn when an explicit range drifts past the file.
- Move the `WarningMessage` interface up next to the other type decls.
2026-04-20 16:46:23 -07:00
Jordan Ritter 6a292151b5 fix(showcase/shell-docs): escape table cell HTML + restrict frontmatter regexes to fm block
- Escape every interpolated value in convertMarkdownTableToHtml to
  close an XSS vector: MDX table cells with HTML-significant characters
  (e.g. <script>, &) previously landed raw in the generated markup.
- Scope readTitle and loadDoc title/description lookups to the
  frontmatter block so a 'title:' / 'description:' that happens to
  appear inside the MDX body (code samples, example config) can't
  override the real frontmatter.
- Export a small escapeHtml helper for reuse within this module;
  duplicated rather than imported from snippet.tsx to keep
  docs-render server-only.
2026-04-20 16:46:06 -07:00
Jordan Ritter 48329bb8e0 fix(showcase/shell-docs): mdx img/video accept user className; Button default type=button
The img and video MDX shims spread props then overrode className to
undefined, silently dropping any className from authors' MDX. Remove the
bogus override so user-supplied className flows through.

Button had no type attribute, defaulting to type="submit" inside a
form (unintentional submits). Default to type="button", accept and
forward onClick/disabled/aria-label, and emit a dev-mode warning when
rendered without onClick so MDX authors learn their Button is
non-interactive.
2026-04-20 16:45:42 -07:00
Jordan Ritter 87b2bb0250 fix(showcase/shell-docs): add iframe sandbox + a11y title on IframeSwitcher & YouTubeVideo
IframeSwitcher had no sandbox attribute, letting user-controlled MDX embed
malicious-origin iframes with full browser capabilities. Mirror the
InlineDemo sandbox policy (scripts/same-origin/forms/popups) and add an
a11y title.

YouTubeVideo was missing both a title (screen readers announced only the
URL) and a sandbox policy. Add sandbox tuned for YouTube embeds
(scripts/same-origin/presentation/popups) and title fallback.
2026-04-20 16:45:21 -07:00
Jordan Ritter 40aa676e8c chore(showcase/shell-docs): bump tsconfig target to ES2022
React 19 / Next 15 expects modern runtimes; ES2017 is stale. ES2022 gives
us top-level await, class fields, and error cause without needing additional
helpers. `next build` still passes.
2026-04-20 16:42:08 -07:00
Jordan Ritter 1db5e4047e chore(showcase/shell-docs): engines, start port, drop unused deps
- Add `engines.node >=18.18` to match Next.js 15 runtime requirements.
- Align `npm run start` with the dev port (3003) for local parity; the
  Docker runner sets PORT=10000 via ENV and is unaffected.
- Drop unused dependencies that are not imported anywhere in shell-docs:
  `react-markdown`, `react-syntax-highlighter`, `rehype-raw`, and
  `@types/react-syntax-highlighter`. These are used in showcase/shell/
  but not here; removing them keeps the dependency surface honest.
- Regenerate package-lock.json to match.
2026-04-20 16:42:03 -07:00
Jordan Ritter 0da65ecbce chore(showcase/shell-docs): .gitignore parity + env secret ignores
Add `.env*.local` and `*.log` entries so accidental secrets and debug
logs never land in the tree. Matches the pattern used by showcase/shell.
Leave the generated /src/data/*.json files tracked, as they are today.
2026-04-20 16:41:56 -07:00
Jordan Ritter e2d5742dfd fix(showcase/shell-docs): Dockerfile hygiene (ARG scope, npm ci, .dockerignore, direct next binary)
- Re-declare COMMIT_SHA and BRANCH ARGs in the runner stage so ENV
  interpolation resolves (ARGs do not cross stages in multi-stage builds).
- Declare NEXT_PUBLIC_BASE_URL as a build-time ARG/ENV so CI can pass it
  via --build-arg for the production `next build` (next.config.ts requires it).
- Copy lockfile for shell-docs and switch to `npm ci` for reproducible installs.
  scripts/ has no committed lockfile yet, so keep `npm install` there.
- Add .dockerignore so local .next/, node_modules/, .git, logs, and .env*
  are not slurped into the build context.
- Invoke next via node_modules/.bin/next (both build and CMD) instead of
  npx to avoid runtime network-fallback risk.
- Document the required build context at the top of the Dockerfile.
- Note the libc6-compat discussion: the slim base is Debian (glibc), so
  no compat shim is required; note how to enable it if we ever move to
  node:20-alpine.
2026-04-20 16:41:51 -07:00
Jordan Ritter 9ed2f9fb37 fix(showcase/shell-docs): StoredFrameworkHighlight reads storedFramework (feature was broken on /docs/*)
The component's name, comments, and stated purpose are to highlight the
user's remembered framework pick on the docs root pivot. The code was
keying off 'framework' (strictly URL-derived), which is always null on
/docs/* where this component is actually mounted — the 'Your choice'
badge and accent ring NEVER rendered.

Now reads 'storedFramework' (the remembered advisory preference) and
compares it against the card's slug, which is what the rest of the file
already documents it doing.
2026-04-20 16:38:20 -07:00
Jordan Ritter 4c73052c1d fix(showcase/shell-docs): RouterPivot redirects using storedFramework; aligned supported/unsupported deployed filter
Functional regressions in the docs router pivot:

1. The redirect effect was reading 'framework' (URL-derived) only. On
   /docs/<feature> the URL prefix 'docs' is never in knownFrameworks, so
   'framework' is always null and the effect never fired. The whole
   'picked-once, sticks' feature was silently broken — users with a
   stored preference were never redirected. Now prefers URL framework,
   falling back to storedFramework, as a single 'target' signal.

2. The 'Loading <framework> view...' placeholder was unreachable for the
   same reason. Now renders when 'target' is set.

3. The supported/unsupported filters disagreed on whether 'deployed'
   applied. supported = withCell (ignored deployed); unsupported =
   !withCell && deployed. Now both require deployed; undeployed
   integrations are omitted entirely rather than surfacing dead links.

4. FrameworkGuardedContent previously returned null whenever 'framework'
   was null, which on /docs/* is always. The MDX body was permanently
   hidden. Now it hides only while a redirect is imminent (URL framework
   set, or storedFramework set — both cases are about to navigate away);
   users with no stored preference see the pivot alongside the MDX body.
2026-04-20 16:38:14 -07:00
Jordan Ritter a2565ec87a fix(showcase/shell-docs): dark-mode-aware highlight.js theme import + layer ordering
- Move highlight.js @import ahead of @import "tailwindcss" so Tailwind
  utility layers can still override specific hljs selectors when needed
  rather than being silently shadowed in Tailwind v4's layer ordering.
- Scope the dark-dimmed theme via prefers-color-scheme so it only
  paints when the user's system is in dark mode. shell-docs does not
  yet ship a dark theme, but this makes syntax blocks correct the
  moment it does.
2026-04-20 16:38:05 -07:00
Jordan Ritter de5301be50 fix(showcase/shell-docs): throw on useFramework outside provider; log localStorage errors; validate slugs
- useFramework() now throws when called outside FrameworkProvider instead
  of returning a silent no-op context. Silent fallback was masking wiring
  bugs where components rendered outside the provider would report no
  framework forever.
- readStoredFramework / writeStoredFramework now log once per session on
  failure (guarded by module-scope flags) instead of swallowing errors
  entirely. localStorage may still be unavailable (SSR, private mode),
  but devs get a warning the first time.
- Dropped 'stored' from the URL-persist effect's deps. It was causing
  redundant re-check cycles every time we called setStored from within.
  The internal !== guard still short-circuits the no-op case.
- setStoredFramework now validates against knownFrameworks. Previously
  any string could poison the stored preference (e.g. a route segment
  like 'docs'); invalid slugs now warn and no-op.
2026-04-20 16:38:02 -07:00
Jordan Ritter 286b214fbf fix(showcase/shell-docs): middleware skips non-GET requests and router prefetches
`docs_pageview` was firing on every matched request — HEAD probes,
POSTs, and Next.js router prefetches all counted as pageviews, which
inflated counts and polluted funnels. Next.js App Router prefetches
links via low-priority fetches that still hit middleware, so they're
especially noisy on pages with long link lists.

We now bail out of tracking when:
  - the method is not GET
  - `next-router-prefetch: 1` is set (Next.js App Router)
  - `purpose: prefetch` is set (generic prefetch hint)

The response is still served normally; only the PostHog capture is
skipped.
2026-04-20 16:37:40 -07:00
Jordan Ritter 16d940779a chore(showcase/shell-docs): a11y-hide commit-SHA overlay; short-sha 7 chars; distinguish dev vs empty
- Add aria-hidden=true so the SHA is not announced by screen readers.
- Shorten to the conventional 7-char git short-sha (was 9).
- Distinguish 'dev' (NEXT_PUBLIC_COMMIT_SHA undefined) from 'unknown'
  (env present but empty string) so Docker ARG-scope bugs surface as
  something other than a misleading 'dev' label in production.
2026-04-20 16:37:25 -07:00
Jordan Ritter b69846c353 fix(showcase/shell-docs): tighten middleware matcher + log posthog errors + module-load warning
Three smaller cleanups to the middleware:

1. Matcher regex: `(?!api|...)` matched `/apidocs` as well as `/api`,
   dropping analytics for any docs path whose first segment starts with
   'api'. The pattern now uses `api/` with a terminator, and also
   excludes `robots.txt`, `sitemap.xml`, `manifest.webmanifest`, and
   the `.well-known/` prefix, which some static-path tooling expects
   to reach without middleware interception.

2. Capture errors are now logged via `console.warn` rather than
   silently swallowed. PostHog 401/403/5xx, DNS failures, etc. were
   invisible to operators.

3. The missing-`POSTHOG_PROJECT_KEY` warning now fires once at module
   load rather than via a module-scoped mutable flag. Edge runtime
   isolates are short-lived and per-request, so the in-memory
   warn-once flag was unreliable. Module-load is the cleanest
   available single-fire hook.
2026-04-20 16:37:07 -07:00
Jordan Ritter bb1c337255 fix(showcase/shell-docs): guard knownFrameworks against reserved-route-slug collisions
If a registry integration ever ships a slug matching a top-level route
segment (docs, ag-ui, reference, api, matrix, integrations), the
FrameworkProvider.urlFramework resolver would treat the route as a
framework scope and hijack navigation. Filter those slugs out in the
root layout and log a dev-only console.error so the collision is
visible to the maintainer.
2026-04-20 16:37:06 -07:00
Jordan Ritter 6a355693ea fix(showcase/shell-docs): drop redundant env block in next.config.ts; validate NEXT_PUBLIC_BASE_URL at build time 2026-04-20 16:37:01 -07:00
Jordan Ritter 6faf3a7bb7 fix(showcase/shell-docs): middleware uses per-visitor distinct_id via first-party cookie
The previous hard-coded distinct_id ("docs-pageview-tracker") collapsed
every visitor into a single synthetic PostHog person, which destroyed
unique-visitor analytics.

Each visitor now gets a stable UUID minted on first visit, persisted
in a first-party `ph_distinct_id` cookie (Lax, Secure, ~2 year TTL)
and read back on subsequent requests. This avoids IP+UA hashing and
the PII concerns that come with it.

Also wraps the PostHog capture POST in `event.waitUntil()` — the
middleware signature now takes `NextFetchEvent` — so the Edge runtime
keeps the request alive until the POST resolves. A bare fire-and-forget
fetch can be torn down as soon as `NextResponse.next()` returns,
dropping events.
2026-04-20 16:36:40 -07:00
Jordan Ritter 7c09e25ca3 ci(showcase): allowlist shell-docs/src/data/* in check-binaries 2026-04-20 14:28:54 -07:00
Jordan Ritter 9c4503ec3b chore(showcase/shell-dojo): add .gitignore and lockfile for parity with sibling shell packages 2026-04-20 14:22:58 -07:00
Jordan Ritter 8d56c2230b chore: apply formatter to integration branch
- Extend .oxfmtrc.json ignore to cover shell-docs/src/content
  (mirrors existing shell/src/content ignore, which was not updated
  when shell-ops-v2 moved MDX content into the new shell-docs package)
- Format showcase/scripts/generate-registry.ts and probe-docs.ts
2026-04-20 14:13:30 -07:00
Jordan Ritter a6836556d7 chore(showcase/shell-docs): add package-lock.json
Matches shell/ and shell-dashboard/ which commit their npm lockfiles to
pin standalone (non-pnpm-workspace) install closures. Ensures reproducible
Docker builds in CI.
2026-04-20 14:05:11 -07:00
Jordan Ritter b6568518ee fix(showcase/shell-docs): drop @copilotkitnext/react CSS import
shell-docs renders pure MDX docs with iframed live demos (via <InlineDemo>
and <IframeSwitcher>) — it never instantiates the live copilot runtime
inline, so it doesn't need @copilotkitnext/react or its styles. Dropping
the import also removes the package from shell-docs's dep closure, keeping
the docs shell lean.
2026-04-20 14:04:51 -07:00
Jordan Ritter c320457180 chore(showcase/shell-docs): add .gitignore matching shell-dashboard pattern 2026-04-20 14:02:45 -07:00
Jordan Ritter c298fe2ae2 fix(showcase/shell-docs): move 4085-added unselected/prebuilt-components content into shell-docs
These files were added in #4085 but landed in showcase/shell/src/content/docs/
after the MDX-docs extraction had already moved the rest of content/docs into
shell-docs. Follow The Rule (MDX docs content belongs in shell-docs) and
relocate them so they render correctly on docs.showcase.copilotkit.ai.
2026-04-20 14:00:57 -07:00
Jordan Ritter a0daa21166 ci(showcase): add shell-docs to ALL_SERVICES; provision Railway service showcase-shell-docs
Adds the shell-docs package to the deploy matrix, paths-filter, and
dispatch options. Railway service `showcase-shell-docs` (ID
7badfb8d-4228-414c-9145-b4026803714f) has been provisioned with the
custom domain `docs.showcase.copilotkit.ai` and the Railway-generated
CNAME target `t6ge0qwv.up.railway.app`.

Env vars seeded on the Railway service: OPENAI_API_KEY,
ANTHROPIC_API_KEY, GOOGLE_API_KEY, POSTHOG_PROJECT_KEY, PORT=10000,
NEXT_PUBLIC_BASE_URL=https://docs.showcase.copilotkit.ai,
NEXT_PUBLIC_SHELL_URL=https://showcase.copilotkit.ai.

Matrix entry uses lfs:true + context:"." + explicit Dockerfile path
(mirrors shell) because the image pulls in shared/ scripts/ packages/
at build time. build_args_sha/branch are included so the build surface
embeds commit metadata, matching shell's pattern.
2026-04-20 14:00:28 -07:00
Jordan Ritter debfa6600d refactor(showcase): update generator scripts to emit into both shell and shell-docs where applicable
MDX docs moved from shell to shell-docs, but several generated artifacts
are still consumed by both shells:
- registry.json: shell uses it (home grid, integrations, matrix,
  middleware, layout); shell-docs uses it (docs renderer framework lookup)
- demo-content.json: shell uses it (integrations/[slug]/[demo]); shell-docs
  uses it (<Snippet> in docs renderer)
- search-index.json: shell-docs consumes it for the docs search modal;
  shell also keeps a copy so its header search still works — links 301
  across to docs.showcase.copilotkit.ai.

Updated scripts:
- generate-registry.ts: dual-emits registry.json to both shells
  (constraints.json stays shell-only — integration-explorer is shell)
- bundle-demo-content.ts: dual-emits demo-content.json
- generate-search-index.ts: scans from shell-docs/src/content (where MDX
  now lives), writes to both shells' data dirs
- probe-docs.ts: scans shell-docs/src/content/docs (content source moved),
  still writes docs-status.json under shell/ for the dashboard
- sync-docs-from-main.ts: target path updated to shell-docs/src/content

Tests in __tests__/ reference shell/src/data paths; dual-emit keeps
those stable so existing afterEach-restore hooks continue to work.
2026-04-20 14:00:28 -07:00
Jordan Ritter c6e4b809e9 feat(showcase/shell): add 301 redirects from /docs /ag-ui /reference /[framework] to docs.showcase.copilotkit.ai
Shell no longer hosts MDX docs routes — they live on shell-docs
(docs.showcase.copilotkit.ai). Add permanent redirects from the legacy
shell paths so old URLs and SEO authority carry over to the new host.

Framework slugs are enumerated from registry.json at build time (not a
:slug* wildcard) so /integrations and /matrix — both still owned by
shell — are NOT caught by the redirect. Fixed routes (/docs, /ag-ui,
/reference) cover the three other docs catch-alls.
2026-04-20 14:00:28 -07:00
Jordan Ritter fc80501048 feat(showcase): move MDX docs routes + components + libs + content into shell-docs
Extracts everything that exists to render MDX documentation (docs/[[...slug]],
[framework]/[[...slug]], ag-ui/[[...slug]], reference/[...slug]) out of shell
into the new shell-docs package that will serve docs.showcase.copilotkit.ai.

Moves (git mv preserves history):
  - App routes: /docs, /[framework], /ag-ui, /reference
  - Docs-only components: docs-page-view, docs-callout, docs-steps, docs-tabs,
    mdx-components, framework-tabs, framework-selector, sidebar-*, snippet,
    property-reference, router-pivot, stored-framework-highlight, react/*
  - Docs-only libs: lib/docs-render, lib/mdx-registry
  - All content: content/docs, content/ag-ui, content/reference, content/snippets
  - .docs-sync-sha marker (follows the content)

Duplicates into shell-docs (both shells need them):
  - brand-nav, search-modal, search-trigger, copy-button, framework-provider
  - lib/registry.ts, data/registry.json, data/demo-content.json,
    data/search-index.json
  - app/layout.tsx + globals.css + public/{images,logos}

shell-docs gets its own minimal middleware (PostHog-only — no SEO redirect
table, docs host never served legacy URLs). shell keeps seo-redirects.ts
for the legacy-URL migration table; framework-scope protection in its
middleware is now effectively dead but harmless (next.config.ts redirects
fire before middleware ever sees /<framework>/ paths).

InlineDemo updated for cross-host context: 'Open full demo' link points
at the shell host (showcase.copilotkit.ai) since the integration profile
route only exists there.
2026-04-20 14:00:28 -07:00
Jordan Ritter dc73b9f334 chore(showcase): scaffold shell-docs package 2026-04-20 13:59:48 -07:00
Jordan Ritter 878ac3af2d chore(showcase): rename shell-dojolike → shell-dojo for naming consistency with dojo.showcase.copilotkit.ai
- Renamed showcase/shell-dojolike/ → showcase/shell-dojo/ (git mv for history).
- Updated package name to @copilotkit/showcase-shell-dojo.
- Updated .github/workflows/showcase_deploy.yml: dispatch option, paths-filter key, ALL_SERVICES entry (context, image, comment).
- Updated .github/workflows/static_check-binaries.yml size allowlist path.
- Renamed Railway service showcase-shell-dojolike → showcase-shell-dojo (id 7ad1ece7-2228-49cd-8a78-bddf30322907 preserved; domain dojo.showcase.copilotkit.ai unchanged).
- Updated image source to ghcr.io/copilotkit/showcase-shell-dojo:latest.
2026-04-20 13:54:42 -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
Jordan Ritter 82e9769f5c fix(showcase/starters/langroid): restore /api/health 200 by dropping sed log-prefix wrappers and gating Next.js on agent readiness
Production showcase-starter-langroid returns ``{"status":"degraded","agent":"down"}`` HTTP 503
at ``/api/health`` — the exact path the showcase-deploy workflow's ``ALL_SERVICES.health_path``
verify step asserts, so the next CI redeploy of this starter would fail verification.

Root cause: two compounding bugs in ``showcase/starters/langroid/entrypoint.sh``.

1. Process-substitution log prefixers suppressed stdout. Both backgrounded
   services were wrapped with ``> >(sed 's/^/[agent] /') 2>&1 &`` /
   ``> >(sed 's/^/[nextjs] /') 2>&1 &``. In Railway's V2 runtime this shape
   reliably produced ZERO ``[agent]``/``[nextjs]`` log lines (confirmed against
   several weeks of Railway logs for this service) and correlated with
   agent-unreachable 503s at ``/api/health``. The package entrypoint
   (``showcase/packages/langroid/entrypoint.sh``) uses the plain-``&`` pattern
   with no wrapper, stays green on the same Railway runtime, and shows full
   uvicorn ``INFO:`` startup logs including ``127.0.0.1:...  "GET /health
   HTTP/1.1" 200 OK`` from Next.js's fetch. Match the working package pattern.

2. Cold-start race amplified by ``sleepApplication=true``. Railway sleeps
   idle services. On wake, Next.js is ready in <1s but Python + langroid
   imports take 10-20s. Without a readiness gate, Next.js answered the first
   post-wake ``/api/health`` probe with ``agent:"down"`` before uvicorn had
   bound port 8123. The deploy workflow's verify step then saw the 503 and
   reported the deploy as unhealthy. Add a 30s readiness probe that curls
   ``http://127.0.0.1:8123/health`` in a loop before starting Next.js. The
   IPv4 literal (``127.0.0.1`` not ``localhost``) is load-bearing — Node
   22+'s fetch resolves ``localhost`` to IPv6 ``::1`` first, and uvicorn
   binds IPv4 only; the readiness probe must not false-negative on resolver
   semantics alone.

Also export ``PYTHONUNBUFFERED=1`` so Python import-time tracebacks (e.g.
langroid module-load failures) reach the container log immediately instead
of sitting in userspace buffers until process exit closes them off.

Verification:
- Built langroid starter image locally from this branch. ``/api/health``
  returns 200 with ``{"status":"ok","agent":"ok"}``. Full uvicorn INFO
  logs visible including ``127.0.0.1:xxxxx - "GET /health HTTP/1.1"
  200 OK`` confirming Next.js -> agent path works.
- Readiness probe fires before Next.js launch: ``[entrypoint] Agent
  /health ready after 3s``.
- New regression guards in ``starter-consistency.test.ts`` cover all four
  invariants (no sed wrapping around uvicorn, no sed wrapping around next
  start, ``PYTHONUNBUFFERED=1`` export, readiness probe on 127.0.0.1:8123
  before ``next start``). Verified red→green (reverted entrypoint -> 4
  fails; restored -> 4 pass). Full showcase/scripts suite: 1079/1079 pass.
2026-04-20 13:53:08 -07:00
Jordan Ritter afc9d0fbea Merge #4085 into integration branch (feature port, no-docker variant) 2026-04-20 13:52:57 -07:00
Martha Schumann 857c7bd106 docs(mastra): use requestContext in Agent instructions example
Restores the API-surface change from the original QA PR #3866 (merged
via mirror #4040) that was inadvertently reverted in 804c5d0f. Keeps
Jordan's other fixes (imports, model, null guards, grammar) intact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 13:40:29 -07:00
Martha Schumann 0e77affe14 Merge main: remove langgraph_agent.py (deprecated), resolve lock conflict
- Keep deletion of sdk-python/copilotkit/langgraph_agent.py (deprecated LangGraphAgent
  removed in this PR; main's unrelated bug fixes are superseded by our removal)
- Resolve poetry.lock conflict by taking main's ag_ui_langgraph 0.0.33

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 12:10:19 -07:00
github-actions[bot] 146fa4e6a5 style: auto-fix formatting 2026-04-20 17:15:35 +00:00
Alem Tuzlak ecf79393e4 ci(vscode-extension): least-privilege perms, concurrency guard, drop dead lint step
- Add top-level 'permissions: contents: read' — the workflow performs
  no repo writes, so declaring the minimum explicitly closes a
  default-token hardening gap.
- Serialize publishes with concurrency: group: vscode-extension-publish,
  cancel-in-progress: false. Two rapid pushes to main used to race
  straight into vsce publish; the second failed noisily on duplicate
  version or, worse, published out of order.
- Remove the 'Lint' step. The Nx target 'copilotkit-vscode-extension:lint'
  doesn't exist and there's no 'lint' npm script either, so the step
  always failed — 'continue-on-error: true' just hid it while never
  actually linting anything. Re-add once a real lint target lands.

check-binaries.sh:
- Replace '[ ] && exit 1 / exit 0' with an explicit 'if [ ]; then
  exit 1; fi; exit 0' block. Under 'set -e' the old form was safe
  only because the trailing 'exit 0' existed; the explicit form is
  robust regardless of what follows.
2026-04-20 19:13:50 +02:00
Alem Tuzlak f5cd389371 fix(vscode-extension): surface silent failures + buffer-aware lens + bounded queues
Review-loop fixes on the VS Code extension surface:

Scanner / lens
- hook-scanner.ts: extract scanContent(filePath, content) so callers
  with the live editor buffer can parse that instead of re-reading the
  last-saved on-disk version. scanFile keeps the same on-disk semantics
  via delegation.
- hook-scanner.ts: scanWorkspace now returns {sites, capped, filesScanned}
  so MAX_FILES_SCANNED truncation is observable instead of silent.
- activate-hook-explorer.ts: when the cap trips, log the detail to the
  Hook Explorer output channel and surface a user-facing warning toast
  pointing at it. Tighten the save-path catch to log unexpected throws
  instead of swallowing them.
- hook-lens-provider.ts: consume document.getText() via scanContent so
  lenses follow unsaved edits. Output channel is now required and the
  scanContent-throw path logs to it.

Panels (bounded queues + durable error trails)
- preview-panel.ts + hooks/panel.ts: pendingMessages now capped
  (1000 and 32 respectively). A wedged webview (CSP violation, crashed
  bundle, never-ready) used to grow these buffers unbounded on every
  save. Latched pendingCapLogged logs one breadcrumb per wedged
  episode, resets on 'ready' (and on dispose for hooks/panel) so a
  recovered session can re-arm the warning.
- preview-panel.ts: removed the misleading type:'error' message on
  successful .fixture.ts[x] bundles — a valid fixture is not an error.
- activate.ts: catalog onOpenSource now wraps openTextDocument in a
  try/catch that appends the full stack to a dedicated
  'CopilotKit A2UI Catalog' output channel in addition to the toast,
  so open-source failures leave a durable trail instead of a 5-second
  flash.
- activate.ts: revert the dead startOffset param added to
  findValuePosition — the plumbing through validateFixtureMessages
  wasn't done in the same PR, leaving unused API surface. Kept the
  limitation comment as documentation.

Catalog wire protocol
- catalog-list-view-provider.ts: normalize fixtureName (?? undefined)
  at the wire boundary so a JSON null can't slip through into callback
  code that declares 'string | undefined'. Exhaustive 'never' guard
  also logs an unknown-variant warning for version-skew scenarios
  (older host receives a newer webview's message).
2026-04-20 19:13:25 +02:00
Alem Tuzlak f1bf3a02e7 fix(runtime): isolate debug broadcast, stop writing to broken streams, cover /connect agentId
Review-loop fixes on the runtime surface:

- sse-response.ts: wrap DebugEventBus.broadcast in try/catch inside the
  observer's next — a buggy subscriber used to propagate an exception
  that RxJS routed to `error`, killing the SSE stream for an unrelated
  reason. Logged via the existing logError helper instead.
- sse-response.ts: non-abort write failures no longer fall through
  silently. Previously streamClosed stayed false and the next event
  re-attempted a broken writer. Now logs + sets streamClosed.
- sse-connect-agent-id.test.ts: new unit test that feeds a synthetic
  observable into handleSseConnect and asserts the emitted envelope
  carries the route-resolved agentId ('weather-agent') rather than
  the literal 'connect'. Regression guard for the fix in 7f3a8c27c
  that the /run-based integration tests didn't cover.
- debug-events.suite.ts: replaced a version of this assertion that
  couldn't reliably drive /connect in the integration runtime with a
  pointer to the unit test above.
- fetch-router.ts: clarify the cpk-debug-events comment — the prefix
  is what guards against agent-name collision, not the ordering of
  router branches.
- debug-stream.ts (extension client): include the underlying JSON parse
  error message in the emitted error so a truncated SSE frame can be
  distinguished from a runtime/protocol version mismatch.
2026-04-20 19:12:50 +02:00
Alem Tuzlak 8f3c47e72a docs(vscode-extension): restructure as three-feature hub + refresh Hook Explorer page
Persona fix: the landing page at /vs-code-extension only documented the
A2UI catalog preview, so builders using CopilotKit hooks and runtime
debuggers never discovered their respective features. Restructured
into a three-section hub that surfaces Hook Explorer, A2UI Catalog,
and AG-UI Inspector side-by-side, with install steps at the top and
cross-links to the deep-dive pages.

/troubleshooting/hook-explorer refreshed end-to-end:
- Replaced stale TreeDataProvider description with the current webview
  sidebar + row-click-previews + '</>' go-to-source UX.
- Documented the inline '▶️ Preview Component' CodeLens.
- Expanded hook coverage table to include useComponent, useDefaultTool,
  useHumanInTheLoop, useInterrupt, useRenderCustomMessages,
  useRenderActivityMessage, useDefaultRenderTool, useLazyToolRenderer,
  useCopilotAuthenticatedAction_c, useRenderToolCall — all 15 render
  hooks covered with their preview shape.
- Added 'Behavior notes' section: auto-recovery on crash + reset on
  selection change, controls persistence, Tailwind + local CSS flow-
  through.
- Added imported-render support note.

/troubleshooting/event-inspector — added a back-link to Hook Explorer
at the bottom callout so the cross-link is bidirectional.
2026-04-20 18:45:36 +02:00
Alem Tuzlak 449f73675b chore(vscode-extension): reorder sidebar views — hooks first, then a2ui, then inspector
Puts the two most-used views up top and demotes the inspector to last.
No functional change; just the "views.copilotkit" ordering in the
extension manifest.
2026-04-20 18:39:56 +02:00
Alem Tuzlak dce4bd8f42 fix(vscode-extension): restore blob: in A2UI preview-panel CSP
Dropping 'blob:' from script-src in the prior review-response commit
broke the A2UI catalog preview: webview/App.tsx intentionally
URL.createObjectURLs the bundled IIFE and loads it via
'<script src=blob:…>', so the browser blocked every catalog load with
'Loading the script blob:vscode-webview://… violates Content Security
Policy directive'.

Re-add 'blob:' to preview-panel's script-src with a documented
rationale: the blob content originates from the trusted extension host
over postMessage, not from external input, so the general concern that
'blob: enables arbitrary-string JS' doesn't apply to this threat
model. The hook-preview panel still excludes 'blob:' because it uses
an inline nonce-gated <script> instead.
2026-04-20 18:36:10 +02:00
github-actions[bot] d842349270 style: auto-fix formatting 2026-04-20 16:06:27 +00:00
Alem Tuzlak c2c90e733b refactor(runtime): rename debug-events route to cpk-debug-events
Per PR review suggestion (14) — a cpk- prefix makes collision with a
user-named agent essentially impossible. The earlier change only
documented the route as reserved; renaming it removes the hazard.

Rename scope:
- URL path segment (/debug-events → /cpk-debug-events) in the router,
  handler switch arms, method-not-allowed check, and integration suite.
- RouteInfo union discriminator ('debug-events' → 'cpk-debug-events')
  in hooks.ts and its two consumers in fetch-handler.ts.
- VS Code DebugStream client URL.
- Docs page (event-inspector.mdx) — both the Callout and the Steps copy.

Left unchanged (internal names that describe the feature but aren't the
public route):
- packages/runtime/src/v2/runtime/handlers/handle-debug-events.ts
- packages/runtime/src/v2/runtime/core/debug-event-bus.ts
- packages/shared/src/debug-event-envelope.ts (and the DebugEventEnvelope
  type)
- 'debug-event' (singular) message type in the VS Code webview bridge —
  that's the extension host ↔ webview protocol, not the HTTP route.
2026-04-20 18:04:50 +02:00
Alem Tuzlak 7f3a8c27c7 fix: address PR review feedback (@ranst91)
Critical
- scripts/hooks/check-binaries.sh: restore showcase data-file exclusions
  (demo-content / search-index / starter-content >1 MB) that the inline
  refactor dropped; add 'set -eu' so silent shell failures don't hide
  policy violations.
- packages/vscode-extension/src/extension/preview-panel.ts: drop 'blob:'
  from CSP script-src — it lets arbitrary-string JS execute via Blob URL
  and defeats most of CSP's XSS protection.
- packages/vscode-extension/package.json: set private: true. The extension
  ships as a .vsix via vsce, not npm, and workspace:* devDependencies
  would break an accidental 'npm publish'.

Important
- runtime: forward the real agentId from handleConnectAgent into
  handleSseConnect / createSseEventResponse so DebugEventBus envelopes
  on /connect carry the actual agent name instead of the literal
  'connect'. Updates handle-connect.ts, sse/connect.ts.
- hooks/panel.ts CSP: narrow connect-src from 'https:' to just the
  Tailwind CDN. The preview path never drives a real CopilotKit runtime
  — all hook calls route through the stub — so there's no legitimate
  https: fetch to allow from inside bundled user code.
- extension/utils.ts getNonce(): switch to crypto.randomBytes. Math.random()
  is not acceptable for a value that gates inline-script execution.
- .github/workflows/vscode-extension.yml:
  * Build step uses 'nx run copilotkit-vscode-extension:build' instead
    of 'pnpm run build' (targeted build with Nx caching, not full
    monorepo rebuild).
  * Added explicit 'Type check' step (tsc --noEmit).
  * Added Lint step gated with continue-on-error until the Nx target
    exists, so a missing target doesn't break the pipeline.
  * Publish job now queries the Marketplace for the current published
    version and skips 'vsce publish' when the local package.json
    version matches — stops every docs/CI-only push to main from
    failing on duplicate-version errors.
- hooks/hook-scanner.ts: bound the synchronous walk at 20 000 files so a
  pathologically large workspace can't freeze the extension host; flag
  kept in module-level constant with a rationale comment.
- sse-response.ts: document that debugEventBus.broadcast intentionally
  runs before the stream-closed gate so debug subscribers see trailing
  events even after the SSE client disconnects.
- inspector-panel.ts: subscribe to DebugStream lazily on show() rather
  than in the constructor; unsubscribe on panel dispose. Avoids firing
  the event callback on every envelope when no panel is open.

Suggestions
- fetch-router.ts: document 'debug-events' as a reserved route so it
  can't be shadowed by an agent literally named 'debug-events'.
- activate.ts findValuePosition: add optional startOffset parameter,
  document the first-occurrence limitation + the follow-up path for
  per-fixture precision.
- activate-hook-explorer.ts isInsideWorkspace: fix JSDoc to reflect the
  code (root itself is excluded).
2026-04-20 17:56:09 +02:00