## Problem
The shell docs had several visual and docs-rendering issues: cramped
responsive spacing, rough hero setup controls, off-theme reference
cards, missing standard reference page actions, and hand-rendered prop
tables.
## Why
The docs should feel consistent across the root docs and reference
areas, especially around page chrome, mobile layouts, and API reference
tables.
## Fix
- Refined shell docs spacing across mobile, medium, and sidebar-adjacent
layouts.
- Redesigned the hero setup controls and `Start using agents` dropdown.
- Updated reference overview cards to match the docs theme.
- Restored standard reference page actions, including markdown/open
options.
- Swapped reference prop rendering to Fumadocs `TypeTable`.
- Fixed reference markdown routes for generated reference pages.
Validation:
- `npm --prefix showcase/shell-docs run lint`
- `npm --prefix showcase/shell-docs run typecheck`
- `npm --prefix showcase/shell-docs run build`
- Pre-commit hook passed
- Browser checks for hero dropdown, reference actions, markdown route,
and TypeTable styling
The 'Known gap' section predated the recording fix: the hook exists as
useLearnFromUserActionInCurrentThread and record-user-action.ts is now a
real adapter. Document the /annotate flow and the backend route
requirement (/connector/annotate) instead.
Dashboard, copilot chat panel, and the learning-mode recording vignette
(the violet glow shown while an officer demonstration is being recorded).
PNGs are LFS-tracked per the repo .gitattributes.
Replace the no-op recorder shim with a real adapter over the v2 hook
(renamed from useRecordUserActionInCurrentThread in #4839/#5073): call-site
{title, description, previousData, newData, metadata} maps to the hook's
{title, description, data: {previous, next, metadata}}, with threadId
sourced from the surrounding chat config provider.
Add an optional INTELLIGENCE_USER_ID / INTELLIGENCE_USER_NAME override to
identifyUser for backends that enforce org membership of the asserted user
(e.g. a local Intelligence stack with seeded fixture users); the default
remains the derived northwind-<role> identity. Documented in the README.
Verified end-to-end against Intelligence @ mme/learn-from-user-activity
(PUT /connector/annotate): record -> cpki.sl_annotations -> sl-worker
distill -> /project knowledge file -> recall via /mcp. Recording requires a
backend that exposes /connector/annotate; the OSS default path
(InMemoryAgentRunner, no INTELLIGENCE_* env) is unchanged.
## Summary
The beautiful-chat demo's "Calculator App (Open Generative UI)" pill
rendered a calculator whose "=" key was inert: the fixture's
`jsFunctions` called `Websandbox.connection.remote.evaluateExpression`,
a host-bridge function only the open-gen-ui-advanced demo registers —
beautiful-chat never does, so the call could never resolve. While fixing
it, review and live verification surfaced four more behavioral defects
in the same fixture family, all fixed here across all 18 integrations:
- **Self-contained evaluation**: `jsFunctions` now evaluates in-sandbox
via an allowlist-gated strict-mode `Function()` (digits/operators/`eE`
only; failures → `err`). No host bridge required.
- **Fixture shadowing**: the specific "with standard buttons" pair is
ordered before the generic "build a modern calculator" pair (aimock is
first-match-wins by load order), so the intended fixture actually serves
the pill.
- **Chained evaluation**: results in exponential notation (e.g.
`1.728e+18`) re-evaluate instead of wiping to `err` (regex allows `eE`).
- **Interleaved pills**: removed the thread-global `hasToolResult` gate
that made the calculator fall through to the live proxy (502) when
clicked after any tool-producing pill; toolCallId-anchored follow-ups
(ordered first) disambiguate legs instead.
- **Repeat clicks**: distinct `tool_call_id`s per click via
`sequenceIndex` variants + a non-sequenced fallback, fixing the
second-widget collapse (duplicate id collapsed both renders into one
slot, wiping state). Scoping caveats (per-X-Test-Id counters,
cross-integration co-increment, DEFAULT_TEST_ID degradation floor =
pre-fix behavior) are documented in the fixture comments and GOTCHAS.
Also: SUPERSEDED annotations on the unreachable recorded.json calculator
entries, GOTCHAS corrections (sequenceIndex scoping, hasToolResult
semantics, statelessness claim), and a routing-invariant unit test
pinning the entry ordering structurally and behaviorally for all 18
integrations (55 tests).
## Test plan
- [x] Local Playwright red-green on the built stack (langgraph-python):
broken "=" reproduced pre-fix; post-fix visual proof of render,
`7+8=15`, chained exponent math, calculator-after-dashboard interleave,
and two independent working widgets across repeat clicks
- [x] aimock version bisect (1.28.0/1.29.0/1.30.0) ruling out an aimock
regression before the fixture root-cause
- [x] `showcase/scripts` vitest suite: 51 files / 1899 tests green
(incl. new `calculator-fixture-routing.test.ts` 55/55, red-proofed via
mutation)
- [x] validate-parity 19/19; harness aimock-fixture-coverage 3/3;
oxfmt/oxlint/commitlint clean
- [ ] CI green on PR HEAD
Follow-ups (readonly-state matcher shadowing parity across 15
integrations, sibling-pill interleave gates, GOTCHAS accuracy pass,
aimock sequenceIndex scoping) are tracked in the showcase follow-up
ledger.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- structural + behavioral pins for all 18 integrations (four ordering invariants; click walk
_001->_002->_003->_003 with follow-ups mirroring the server match/increment flow)
- fail-loud guards against loader error-swallowing and vacuous ordering passes
- full production pill text
- oxfmt applied
- SUPERSEDED annotations on unreachable recorded calculator entries (load-order shadowing is
the only guarantee; model gate is not a safety net)
- GOTCHAS sequenceIndex rewritten to per-X-Test-Id semantics with co-increment/eviction caveats
- hasToolResult paragraph corrected (omission = no gate, thread-global predicate)
- statelessness claim reconciled with sequence counters
- replace Websandbox host-bridge evaluateExpression (never registered in beautiful-chat) with
in-sandbox allowlist-gated Function() eval
- reorder specific calculator pair before generic (first-match-wins)
- allow exponential notation (eE) so chained evaluation of large results works
- drop thread-global hasToolResult gate that broke the pill after other tool-producing pills,
reorder toolCallId follow-ups before leg-1
- mint distinct tool_call_ids per repeat click via sequenceIndex variants + non-sequenced
fallback (fixes second-widget collapse)
- restore google-adk trailing newline
- document ordering invariants, gate tradeoffs, and sequence-counter scoping caveats in
fixture comments
Verified via local Playwright red-green (render, 7+8=15, chained exponent, interleaved pills,
repeat clicks).
## What
Documentation for the new Slack bot stack (`@copilotkit/bot`,
`@copilotkit/bot-ui`, `@copilotkit/bot-slack` — live on npm at 0.0.1),
plus the reference-picker restructure.
### 1. Slack quickstart — `/slack`
Flat **Slack** entry at the top of the **Platforms** sidebar section
(above React Native), with a flat slug matching `/react-native`. Zero →
working bot:
- Create the Slack app **from the checked-in manifest**
(`examples/slack/slack-app-manifest.yaml`), with a callout to delete the
two `assistant:write` / `assistant_thread_started` lines if present
(Slack's validator rejects them without an `assistant_view` block;
conditional phrasing stays correct once `tyler/slack-example-standalone`
lands)
- Tokens (`xoxb-` from OAuth & Permissions after install; `xapp-`
app-level token with `connections:write`), Socket Mode = no public URL
- Gotcha callouts: `/invite` before `app_mention` fires; mention
autocomplete matches the bot **user's** Default username (propagates on
reinstall; full uninstall→reinstall rotates the `xoxb-` token); slash
commands silently dropped unless declared in the app config
- One-file bot (`createBot` + `slack()` + `onMention` →
`thread.runAgent()`, run with `tsx`), then interactive JSX (Button with
inline `onClick`), then `/agent` slash command via `runAgent({ prompt
})`
- ESM-only packaging + in-memory ActionStore restart caveat, and the
production bot/agent split via `AGENT_URL` (mirrors `examples/slack`)
### 2. "Bots" tab in the reference SDK picker
Per-symbol reference modeled on the React (V2) pages (Overview →
Import/Signature → PropertyReference props → Usage → Behavior →
Related), with the sidebar **grouped by package** — each package
separator carries its mark (CopilotKit kite / Slack logo):
- **`@copilotkit/bot`** (separator + kite mark) with collapsed
kind-folders:
- *Components* (13): Message, Header, Section, Markdown, Fields,
Context, Actions, Button, Select, Input, Image, Divider, Table — each
with props, usage, and its Block Kit mapping/budget
- *Functions* (5): createBot, defineBotTool, defineBotCommand,
renderToIR, bind
- *Classes* (1): Thread · *Types* (3): ActionStore, BotNode,
InteractionContext
- **`@copilotkit/bot-slack`** (separator + Slack mark) with a closed
**Core** folder: `slack()` (the adapter — `/reference/bot/slack`),
renderBlockKit (mapping + SLACK_LIMITS budgets), markdownToMrkdwn,
defaultSlackTools, defaultSlackContext, SanitizingHttpAgent
- Wiring follows the in-file recipe (`REFERENCE_VERSIONS += "bot"`, new
`functions`/`slack` subdirs, selector label, Bots card on `/reference`)
plus a bot-specific `buildBotPageTree` for the package-grouped sidebar
### 3. Picker labels + stale SDK pages
- Labels renamed to **React (V2)** / **React (V1)** (Core unchanged)
- Deleted the retired `/reference/sdk/` pages (LangGraph SDK ×2, CrewAI
SDK, CrewAIAgent, LangGraphAGUIAgent, Remote Endpoints);
search/sitemap/llms indexes are generated from the content tree, so they
de-index with the deletion; `sdk` dropped from the v2 subdir list; the
one inbound link retargeted to its `/reference/v1` copy
## Verification
- Every API name verified against package source (`src/index.ts`, type
declarations), not READMEs — caught two README-only patterns that don't
compile (`onClick` one-liners returning `MessageRef`; in-process
`BuiltInAgent` blocked by the `@ag-ui/client` 0.0.53/0.0.56 nominal
split, hence the loopback AG-UI pattern in the quickstart)
- All quickstart/reference snippets assembled into a scratch `.tsx`
project and **typechecked clean** against the built workspace packages
(strict, `jsxImportSource: "@copilotkit/bot-ui"`)
- `npm run build` (production) ✅ · `npm run typecheck` ✅ ·
`oxlint`/`oxfmt --check` on touched app files ✅ · internal link audit:
every `/reference/bot/*` and `/slack` link resolves ✅ · old routes
(`/reference/sdk/*`, `/platform/slack`,
`/reference/bot/functions/slack`) 404, new routes 200 on the dev server
✅
- **Third-party review round**: two independent reviewer agents — a
cold-read new-user pass on the quickstart (verdict: ~25–30% verbose →
trimmed ~26%, callouts 7→4, paste-along ambiguities fixed) and a
source-level correctness audit of all 29 reference pages (~280 claims; 8
errors found and corrected, incl. honest wording for action expiry, what
crosses the wire on a click, Input’s block-level placement, and bind()’s
v1 cold-path caveat). Two of the audit findings are SDK bugs, filed
separately: Input-inside-Actions silently dropped by the Slack renderer,
and bind() `boundArgs` written to the ActionStore but never consumed on
rehydration.
- `npm test`: 90/91 — the 1 failure (`framework-overview.test.tsx`,
"Start the quickstart" CTA copy) **pre-dates this branch** (hero copy
changed in #5248) and touches no file in this diff; flagged separately
## Reviewer checklist
- [ ] `/slack` — try the quickstart against a real workspace (manifest
paste, tokens, `npx tsx bot.tsx`)
- [ ] Sidebar: **Platforms** lists Slack (flat, above React Native);
reference picker shows React (V2) / React (V1) / Core (TypeScript) /
Bots
- [ ] Bots tab sidebar: `@copilotkit/bot` separator (kite mark) with
closed Components/Functions/Classes/Types folders, then
`@copilotkit/bot-slack` separator (16px Slack mark) with a closed Core
folder of the six adapter entries
- [ ] Spot-check API accuracy: Button, slack() (`/reference/bot/slack`),
Thread, ActionStore
- [ ] Manifest callout wording still correct if
`tyler/slack-example-standalone` merges first
- [ ] Comfortable deleting the six `/reference/sdk/` pages with no
redirects (they 404 now; only inbound link was retargeted)
- [ ] OK with the quickstart's single-process loopback pattern
(BuiltInAgent served over AG-UI on :8200) until the `@ag-ui/client`
version split is healed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- New Platforms entry: /platform/slack quickstart — manifest-based app
creation, Socket Mode tokens, minimal createBot bot run with tsx,
interactive JSX with inline onClick, slash commands, production split
- New "Bots" SDK tab in the reference picker with per-symbol pages for
@copilotkit/bot, @copilotkit/bot-ui, and @copilotkit/bot-slack
(Components / Functions / Classes / Types)
- Rename reference picker labels to React (V2) / React (V1)
- Remove the retired /reference/sdk pages (LangGraph/CrewAI SDK,
Remote Endpoints); search/sitemap/llms indexes derive from the
content tree, so they de-index with the deletion
- Retarget the one inbound link to its /reference/v1 copy
Co-Authored-By: Claude <noreply@anthropic.com>
pkg-pr-new publishes snapshot builds to pkg.pr.new, not the npm
registry, and uses no environment-scoped secrets or variables. The
job runs on every push/PR touching packages/**, so the npm
environment's tightened deployment-branch policy (main, canary/*,
release/publish/*) would block every snapshot publish. Removing the
environment association is a prerequisite for the policy.
actionlint over stable-release.yml, publish-release.yml, canary.yml,
and itself; shellcheck (severity warning) over scripts/release shell
scripts; and the release-scope-dropdown-sync job running
verify-release-scope-dropdowns.sh. Scope intentionally narrow to the
release pipelines to avoid drowning unrelated changes in lint noise.
Ported from ag-ui-protocol/ag-ui.
canary / publish: a workflow_dispatch orchestrator that mirrors the
dispatched ref to a unique short-lived canary/<slug>-<run_id>-<attempt>
branch via the GitHub API (devops-bot App token, app-id 1108748),
dispatches publish-release.yml on that ref with mode=prerelease, waits
for the delegated run (gh run watch + explicit conclusion check), and
deletes the ref afterward.
It does NOT publish to npm itself — publish-release.yml holds the
single npm OIDC trusted-publisher binding. Failure paths covered:
suffix validated before any side effect, ref kept when a dispatched
run was never located, ref deleted when the dispatch itself failed,
status-gated deletion + fresh cleanup token for cancellation/timeout
(90-min ceiling exceeds the 1h App-token TTL and queueing behind
publish-release's global concurrency group).
Ported from ag-ui-protocol/ag-ui PR #1914 with cpk adaptations
(scopes from release.config.json; dry_run -> dry-run input mapping).
Compares the workflow_dispatch scope choice dropdowns in
publish-release.yml, stable-release.yml, and canary.yml against the
authoritative .scopes keys in release.config.json, failing CI on drift.
Also validates that every explicitly-named arm in publish-release.yml's
notify-job npm-url case statement is a valid scope (catch-all makes
full coverage unnecessary). Parsers fail loud and distinct on shape
changes (anchored case detection, loose-vs-strict cross-check,
zero-options and zero-block guards) rather than silently passing.
Ported from ag-ui-protocol/ag-ui (PR #1914 wiring); config lives at
the repo root in CopilotKit.
Hotfix for the deployed Kite bot: every Linear-MCP run fails with
```
Agent error: Cannot set property protocolVersion of #<StreamableHTTPClientTransport> which has only a getter
```
**Root cause** — `@copilotkit/runtime@1.59.5` declares `@ai-sdk/mcp:
^1.0.21`. The standalone example lockfile (new in #5366) resolved
**1.0.47**, which (unlike the workspace-tested **1.0.21**) assigns
`transport.protocolVersion` after the server's initialize response — a
getter-only property on `@modelcontextprotocol/sdk@1.29.0`'s transport.
Verified by source diff of both published tarballs; the assignment
exists only in 1.0.47 (`dist/index.js:1950`).
**Fix** — `pnpm.overrides` pin to 1.0.21 in the example + regenerated
standalone lockfile (resolution verified). Workspace installs are
governed by the root manifest and unaffected.
**Upstream** — this combination breaks *any* fresh install of
`@copilotkit/runtime@1.59.5` that uses MCP; a proper compat fix in the
runtime package is filed separately.
Merging this auto-deploys the hosted bot (watch-path on
`examples/slack/**`) — live verification on Kite follows.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
@copilotkit/runtime@1.59.5 declares @ai-sdk/mcp ^1.0.21; fresh installs
resolve 1.0.47, whose MCP client assigns transport.protocolVersion after
the server's initialize response — a getter-only property on
@modelcontextprotocol/sdk@1.29.0's StreamableHTTPClientTransport. Every
MCP-enabled run then fails with:
TypeError: Cannot set property protocolVersion of
#<StreamableHTTPClientTransport> which has only a getter
The workspace-tested resolution was 1.0.21 (no such assignment — verified
by source diff of the published tarballs). Pin it via pnpm.overrides until
@copilotkit/runtime supports the newer client line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes [OSS-299](https://linear.app/copilotkit/issue/OSS-299).
Follow-up to #5248 (already merged).
## Problem
The `hero_command_copied` PostHog event added in #5248
(`showcase/shell-docs/src/components/hero-start-commands.tsx`) carries
no surface discriminator. `HeroStartActions` renders on **both** the
home hero and **every** framework landing hero:
- The **create** card embeds the framework in `command` (`--framework
langgraph-js`), so it's recoverable.
- The **onboard** card's command (`npx copilotkit@latest skills
onboard`) is byte-identical on every page — so onboard copies **cannot**
be attributed to a surface from the event alone.
Every sibling event in shell-docs already carries a "where" property —
`cli_command_copied` → `location: window.location.pathname`, the nav
events → `location`, `markdown_copied`/`open_in_llm_clicked` → `path`.
`hero_command_copied` was the only one without one.
## Fix
Add `location: window.location.pathname` to the `hero_command_copied`
payload, mirroring the `cli_command_copied` event the global
`<CopyTracker>` already emits for the same copy (verified: it
monkeypatches `navigator.clipboard.writeText`, which the hero calls).
The two paired events now join cleanly on the same dimension. Guarded
for SSR (`typeof window !== "undefined"`) to match the sibling.
## Test
Adds a colocated source-assertion guard test. shell-docs vitest runs in
the `node` environment (no jsdom/RTL), so this follows the suite's
existing convention (`readFileSync` + assertions, like
`brand-nav.test.tsx`) rather than introducing a behavioral render
harness.
```
✓ src/components/__tests__/hero-start-commands.test.tsx (3 tests)
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The Slack example is a **consumer** of the packages we shipped today,
but its `workspace:*` deps forced every deployment to rebuild the
monorepo (and fight nx inside builders — exit-130 city). This PR makes
the example what an example should be: installable and runnable anywhere
with zero monorepo context.
## Changes
- **`workspace:*` → published ranges** (`@copilotkit/bot*` `~0.0.1`,
`@copilotkit/runtime` `^1.59.5`). In-repo it now installs from the
registry like any user's project; `tsx` runs the source directly — there
is no build step anymore, anywhere.
- **Drop the private `@copilotkit/typescript-config` devDep**, inlining
the base compiler options into the example's `tsconfig.json` (identical
`tsc` behavior, verified).
- **Standalone `pnpm-lock.yaml`** inside `examples/slack` so isolated
installs (Railway `rootDirectory`, users copying the folder) are
reproducible. Root workspace installs ignore it.
- **Slack manifest fixes** (both variants): remove the `assistant:write`
scope + `assistant_thread_started` event — Slack's manifest validator
rejects them without an `assistant_view` feature block, and the bot
doesn't implement that surface; add the `/triage` slash command the bot
actually registers (previously had to be added by hand).
## Verification
- `slack-example` tests: **38/38** against the published packages
- Direct `tsc --noEmit`: clean
- Clean-room (gitless snapshot, isolated dir): install from registry →
runtime boots to `listening`, bot boots to a loud Slack auth failure on
dummy tokens (the correct failure)
- Live deploy validation on Railway follows this merge
(rootDirectory=/examples/slack, no build command)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Pin alignment fixes 9 validate-pins FAILs; ratchet the drift baseline
count and hash accordingly. Also tighten the _comment: document the exact
hash recipe (SHA-256 of the stderr-only [FAIL] lines, LC_ALL=C sort -u)
and correct baselineDemoCount semantics (exact expected demo count per
package; deviation either direction warns).
Align showcase integration requirements.txt files (strands,
langgraph-fastapi, langgraph-python, pydantic-ai, google-adk,
crewai-crews) to the fleet pin standard, including an accurate
typing_extensions comment in crewai-crews and a trailing newline in
langgraph-python.
Replace floating "beta" dist-tags with exact versions for @ag-ui/mastra,
@mastra/{client-js,core,libsql,memory}, and mastra in both the examples
and showcase mastra packages. Showcase mastra also raises its zod floor
^3.24.0 -> ^3.25.0. The examples mastra package additionally carries the
fleet-wide @ag-ui/client 0.0.55 bump and single-tree overrides here, since
its manifest mixes both changes.
Bring the starter agents' Python dependency pins (pyproject.toml + uv.lock
for adk, langgraph-fastapi, langgraph-python, pydantic-ai, strands-python;
requirements.txt + docker override for crewai-crews) in line with the
showcase fleet pin standard.
Bump @ag-ui/client 0.0.53 -> 0.0.55 across 8 starter example packages and
add npm overrides pinning @ag-ui/{client,core,encoder,proto} to 0.0.55 so
each install resolves a single @ag-ui tree. The mastra starter receives the
same bump alongside its dist-tag pin fixes in a separate commit.
- dependencies: workspace:* -> published ranges (@copilotkit/bot* ~0.0.1,
@copilotkit/runtime ^1.59.5) — the example is a consumer of the released
packages, installable and deployable with zero monorepo context
- drop the private @copilotkit/typescript-config devDep; inline the base
compiler options into tsconfig.json (verified identical tsc result)
- commit a standalone examples/slack/pnpm-lock.yaml for isolated installs
(root workspace installs ignore it)
- slack-app-manifest.{yaml,json}: remove assistant:write scope +
assistant_thread_started event (Slack rejects them without an
assistant_view feature block; the bot doesn't implement that surface),
add the /triage slash command the bot registers
Verified: slack-example tests 38/38 against the published packages; direct
tsc --noEmit clean; standalone install + runtime/bot boot exercised in a
gitless clean-room snapshot.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round-2 review fixes for the GITHUB_OUTPUT helper and the release scripts
that emit through it.
emitGithubOutputs (scripts/release/lib/github-output.ts):
- Replace the key newline/CR check with a full GitHub-Actions-safe charset
check: /^[A-Za-z_][A-Za-z0-9_-]*$/. A key containing "=" or whitespace
would silently corrupt the key=value line; rejecting up-front is
strictly safer. Value validation (single-line) is unchanged — "=" in
values is legal because GitHub splits on the first "=".
- Update the docblock accordingly.
prerelease.ts:
- Remove the dead `?? getCurrentVersion(scope)` fallback. The empty-list
guard above makes packages[0] guaranteed, and the fallback would have
masked a package.json missing its version field by emitting a version
divergent from what the loop publishes. Fail loudly with an explicit
exit instead.
- Drop the now-unused getCurrentVersion import.
- Add a comment above the dry-run emitGithubOutputs call explaining that
emitting in dry-run is safe — the publish workflow gates publish + the
verify guard on inputs.dry-run != true, so the dry-run emission only
serves local/e2e contract verification.
publish-release.ts:
- Hoist getPackagesForScope + empty-list guard above the prerelease-suffix
and registry checks. A misconfigured scope now fails with the clear
"no packages found" error instead of a misleading "not greater than
published" one. Loop is unchanged.
github-output.test.ts:
- Loosen the key-newline assertion from the JSON.stringify-coupled
/bad\\nkey/ to the stable /alphanumeric/ phrase from the new message.
- Add tests: "=" in key throws, space in key throws, empty key throws,
and "=" in value is accepted and written verbatim (note=a=b).
- Move vi.restoreAllMocks() to the top of afterEach so spies cannot leak
into env restore + rmSync cleanup.
Call sites audited:
- emitGithubOutputs: only ever called with {version, scope} (prerelease,
publish-release) — all valid under the new charset.
- publishVersion derivation: only used inside prerelease.ts main().
- getCurrentVersion: still imported by publish-release.ts, bump-prerelease.ts,
prepare-release.ts; only the prerelease.ts import was removed.
- getPackagesForScope hoist in publish-release.ts: `packages` was only
read inside the publish loop below; nothing earlier depended on it.
Hardens the new GITHUB_OUTPUT emission path so a malformed value can't smuggle
extra `key=value` lines into the workflow's step outputs, and so the workflow's
"Verify publish step emitted version" guard can't be fooled by a publish that
did nothing.
emitGithubOutputs now validates every key/value for `\n`/`\r` BEFORE the
GITHUB_OUTPUT early-return — a malformed value is a caller bug and should fail
loudly even when running locally. A multi-line value would need the heredoc
form, which this helper deliberately does not support.
prerelease.ts and publish-release.ts now fail loud when getPackagesForScope
returns an empty list. Without this, the new GITHUB_OUTPUT emission would make
the workflow's "Verify publish step emitted version" guard pass on a run that
published nothing — previously the missing output made such a run fail. The
guard runs BEFORE the dry-run branch in prerelease.ts. In publish-release.ts,
the inline iteration of getPackagesForScope(scope) is hoisted to a `packages`
const so the same guard fires before the publish loop.
The "no-op when GITHUB_OUTPUT is unset" test now spies on fs.appendFileSync
and asserts it wasn't called (the previous read of the unrelated temp file
was vacuously true). New tests cover newline/CR in value and newline in key.
The prerelease.ts usage string previously advertised `[--suffix <label>]`,
but the script never parses --suffix (suffix handling lives in
bump-prerelease.ts per the header comment). Removed.
Call sites enumerated:
- emitGithubOutputs: prerelease.ts (dry-run + post-publish), publish-release.ts
- getPackagesForScope: prerelease.ts, publish-release.ts (this commit);
bump-prerelease.ts, prepare-release.ts, versions.ts (not changed — out of
scope for this hardening)
Verification:
- npx vitest run --config scripts/release/vitest.config.mts → 91 passed
- Red-green for the newline validation: temporarily removed the validation,
the 3 new newline/CR tests failed (assertion: expected fn to throw); restored,
back to green.
- E2E: GITHUB_OUTPUT="$OUT" pnpm release:prerelease:dry succeeded and the
output file contained `version=1.59.5` and `scope=monorepo`.
Note: Fix 2's empty-list guard fires only on a misconfigured scope (no unit
test reachable — prerelease.ts is outside the vitest include glob and the
guard is boundary validation against a misconfigured scope, not a behavior
worth contriving a test harness for).
prerelease.ts published canaries successfully but never wrote the
version output the publish-release workflow's "Verify publish step
emitted version" guard reads, so every canary dispatch ended red after
a successful publish. Extract the GITHUB_OUTPUT append (previously
inline in publish-release.ts) into a shared lib/github-output.ts helper
and call it from both publish scripts.
Call-site enumeration:
- emitGithubOutputs: declared lib/github-output.ts; called from
prerelease.ts (dry-run path + after publish) and publish-release.ts
(replaces the inline appendFileSync block, same version=/scope= keys).
- No symbols removed; fs import in publish-release.ts still used (3
remaining call sites).
The hero_command_copied event fired by the landing-hero command cards carried
no surface discriminator. HeroStartActions renders on both the home hero and
every framework landing hero; the "onboard" card's command is byte-identical
on every page, so onboard copies could not be attributed to a surface from the
event alone (only the "create" card embeds the framework in `command`).
Add `location: window.location.pathname` to the payload, mirroring the
`cli_command_copied` event the global <CopyTracker> already emits for the same
copy so the two paired events join on the same dimension. Guarded for SSR to
match the sibling.
Adds a source-assertion guard test in the shell-docs node-env convention.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## What
Replaces the landing-page CTA with **three entry points**, framed by
situation, and renders the **identical action block on the home hero and
every framework landing hero**:
| | action |
|---|---|
| **New project** | `npx copilotkit create` |
| **Existing project** | `npx copilotkit skills onboard` |
| **Guided walkthrough** | **Quickstart** button (preserved from the
previous hero) |
- **Unified `<HeroStartActions>` block**: two equal-weight command cards
plus a quickstart row beneath, shared verbatim by the home hero and the
framework landing heroes (per review: the two surfaces previously
diverged).
- **Quickstart preserved** in its original accent treatment. On the home
hero it is the framework-picker dropdown (`<HeroQuickstartDropdown>`,
restored); on framework pages it links straight to that framework's
quickstart guide. The home hero also keeps the "Learn more about
building with agents" link in the same row.
- **Framework landing heroes** (e.g. `/langgraph-typescript`): the
create command **pre-fills the framework** via the CLI's `--framework`
flag (e.g. `--framework langgraph-js`).
**Framework-flag mapping**: docs slug to CLI `--framework` value,
verified against the CLI's `AGENT_FRAMEWORKS` enum
(`langgraph-typescript`→`langgraph-js`,
`langgraph-python`→`langgraph-py`, `google-adk`→`adk`,
`strands`→`aws-strands-py`,
`ms-agent-dotnet`→`microsoft-agent-framework-dotnet`, identical for
`mastra`/`pydantic-ai`/`llamaindex`/`agno`/`ag2`). Slugs with **no** 1:1
CLI template fall back to a bare `npx copilotkit create`, notably
`crewai-crews` (the CLI ships *CrewAI Flows*, not Crews), plus
`langgraph-fastapi`, `claude-sdk-*`, `langroid`, `spring-ai`,
`agent-spec`, `deepagents`. `skills onboard` has no framework flag, so
it is identical everywhere. Frameworks with bespoke setup (`a2a` `git
clone`, `ms-agent-dotnet`) keep the pre-cards layout: quickstart button
plus their own copy-command chip.
**Responsive, with all text always visible.** Commands **wrap, never
truncate**:
- Wraps happen at spaces only; every token is non-breaking, so
`--framework` can never split into a dangling `-` at a line edge.
- `text-wrap: balance` splits multi-line commands evenly, typically
right at the flag boundary (`npx copilotkit@latest create` /
`--framework langgraph-js`).
- The block caps at 740px with 12px mono, the narrowest cap where both
home commands fit one line with enough headroom to survive platform
mono-font width differences.
- Cards sit two-up from `sm` and stack below it; the grid (`min-w-0`,
`items-stretch`) keeps long commands inside their track and the card
pair equal-height.
## Screenshots
**Home**: two cards, quickstart dropdown, learn-more link

**Home, quickstart dropdown open** (framework picker preserved)

**Framework landing (LangGraph)**: same block, framework pre-filled,
create command balanced across two lines, quickstart links to the guide

**Worst case (Microsoft Agent Framework, Python)**: longest CLI flag
value, three balanced lines, fully readable

**Bespoke setup (A2A)**: quickstart button plus own command chip
(pre-cards layout preserved)

**Mobile (375px)**: cards stack, quickstart goes full-width
| home | framework |
|---|---|
| 
| 
|
## Telemetry
Both hero copy buttons are now explicitly instrumented: each click
captures **`hero_command_copied`** (`command_id`: `create` | `onboard`,
full `command` string, `clipboard_blocked`), so create-vs-onboard
funnels are queryable per landing page. The pre-existing global
`cli_command_copied` (fired by `CopyTracker` on any clipboard copy)
still fires for volume metrics; the new event uses a different name so
that funnel is not double-counted. Validated locally against a live
PostHog client: each click POSTs both events (plus `$autocapture`) to
`/ingest/e` with HTTP 200.
## Notes
- Both cards equal weight; accent only on hover. Copy rows copy on click
with `aria-live` feedback plus a clipboard-blocked fallback; cursor is
`pointer`.
- Removes `agent-start-prompt.tsx` and `hero-command-copy.tsx`.
`hero-quickstart-dropdown.tsx` is back (restored unchanged after review
feedback).
Bolt's App constructor schedules a background auth.test that can't be
awaited or error-handled - in unit tests it phoned home to api.slack.com
with dummy tokens, leaving ~15 unhandled invalid_auth rejections racing
the run's end (the unit (20.x) flake). deferInitialization: true makes
construction genuinely side-effect-free; start() runs app.init() first,
so auth/config errors surface to the caller, followed by the existing
awaited auth.test. Test fake App grows the matching init() stub.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary
- Live staging redeploy evidence (2026-06-10 16:37Z): 2/6 workers
completed the full SIGTERM → abandon → deregister sequence in **under 1
second**, while 4/6 were SIGKILLed mid-browser-teardown because
Railway's ~10s stop grace is shorter than the old 25s drain budget —
leaving 4 stale roster rows and a reclaim splash on every deploy.
- This PR makes abandon + deregister the **guarded, sub-second critical
path** and demotes teardown to best-effort within a composed <10s
budget, so a platform kill mid-teardown is harmless.
## Design
- `drainFleetWorker` ordering: drain → `registration.stop` → bounded
deregister → graced `worker.stop` → always-run pool shutdown, with
stop-error precedence (a pool-shutdown failure can never mask the stop
error).
- `DRAIN_DEREGISTER_TIMEOUT_MS` (3s) bounds the **whole registration
write chain**, so a hung—not failing—PocketBase cannot consume the kill
window; timeout degrades to the documented crash-path reclaim.
- `safeLog` guards every loop/stop/drain-path log: a throwing logger can
neither reject the worker loop's done-promise nor skip the roster delete
or teardown (abort-before-log in `requestDrain`; structural-caller
guards in `drainFleetWorker`).
- Drain-aware lease renewal (an abandoned job's lease lapses instead of
being re-extended), mid-drain claim skip (a claim won after the drain
decision is never run), and mid-report precision (a run that began
reporting is never logged as abandoned).
- Never-throws loop closure: loop-crash logging via `done.catch` +
`/health` 503, heartbeat and idle-poll sleep hardening with a non-busy
pacing floor, aggregate-key protocol-violation wrap.
- `WORKER_DRAIN_GRACE_MS` default 25s → 6s; the composed 3+6 < 10s
budget is **pinned by a test**; present-but-invalid overrides warn;
overrides at/above ~7s are documented as forfeiting the composed budget.
- Boot-failure teardown catches now log (no silent chromium stranding).
## Review
- 6 unbiased 7-agent CR rounds + 5 fix rounds; every behavioral change
red-green or mutation-proven; `Promise.race` loser semantics empirically
pinned by test.
- ~30 pre-existing harness findings deferred to the flap-fix follow-up
backlog (top of the next fleet-robustness PR: lease-renew
retry-on-throw, empty-registry guard/dispatch mismatch,
`registered`-flag refresh, worker `/health` async bind race, queue fetch
timeouts).
## Test plan
- [x] 2176/2176 vitest (32 new tests)
- [x] `tsc --noEmit` both configs
- [x] oxfmt clean
- [ ] CI green on this PR
🤖 Generated with [Claude Code](https://claude.com/claude-code)
LicenseMode was removed from license-verifier 0.3.0 and has no consumers
anywhere in the repo; the prior re-export was already uncompilable, so no
external consumer could exist either.
The paths entries pointed at sibling package sources, so the Angular
package's tsc run typechecked core and shared sources under Angular's
compiler settings — surfacing errors in files outside any Angular
change (reported on #5321). Resolve to the built declarations first,
same pattern as the Vue package; the src fallback remains for cold
checkouts.
@copilotkit/license-verifier dropped LicenseContextValue and
LicenseMode from its public API in 0.3.0, leaving shared re-exporting
two nonexistent members. tsdown's dts rollup never validated the
re-export, so the broken types shipped silently and check-types fails
on main. Define both types here — shared already owns the context
shape via createLicenseContextValue — using the definitions from
license-verifier 0.2.0. Also annotate the merged telemetry properties
record so string indexing typechecks.
A2UIViewer.tsx and theme/viewer-theme.ts were left behind by the
0.8 -> 0.9 migration: nothing imports them, they import @a2ui/lit
(no longer a dependency) and files that no longer exist, so
check-types fails on files no PR touches. Remove them along with the
now-inert @a2ui/lit external/global entries in tsdown.config.ts, and
underscore the unused type params kept on deprecated aliases for
call-site compatibility.
100% JSX bot at feature parity with the PoC example: issue/page cards,
tables, Chart.js charts, Mermaid diagrams, incident/status/links cards,
a confirm_write HITL gate, and /agent + /triage slash commands.
Registers examples/slack in the pnpm workspace.
The reusable mechanics (streaming, chunking, markdown-to-mrkdwn,
conversation store) live on in @copilotkit/bot-slack; UI authoring
moved from A2UI/defineSlackComponent to JSX -> IR -> Block Kit.
JSX -> Block Kit rendering with per-element budgets and degradation,
Socket Mode ingress, opaque-id interactions (ack within 3s, run async),
chat.update message streaming with chunking, accent attachments, and
sender-profile resolution. Preserves the PoC's streaming, chunking,
and mrkdwn mechanics behind the PlatformAdapter boundary.
createBot with handler registration (onMention/onMessage/onInterrupt/
onCommand), the agent run/tool/interrupt loop, content-stable JSX
action binding with cold-path rehydration from a pluggable ActionStore,
the PlatformAdapter boundary, capability-gated thread methods, one
shared BotToolContext, defineBotTool / defineBotCommand, and typed
interaction/interrupt handlers. Includes fake-adapter/fake-agent
testing utilities.
Pure JSX runtime (no React, no Slack) producing a BotNode IR tree.
Statically typed component props via a package-owned JSX namespace:
unknown attributes, bad values, and bad children are compile errors.
Components: Message, Header, Section, Markdown, Field, Context,
Actions, Button, Select, Input, Image, Divider; bind() escape hatch
for non-serializable handler captures.