CR-loop final polish (non-behavioral):
- tsdown-exports.test.ts: the "maps over fallback-array targets" case left an
unspied console.warn (b.mjs has no adjacent declaration) leaking to stderr.
Wrap it in withWarnSpy and assert the warning fired — the declaration-less
element is reported, not silently dropped.
- tsdown-exports.d.mts / validate-package-exports-types.ts: cross-reference the
two hand-mirrored ExportsEntry definitions so they cannot drift silently.
No source behavior change; 36 tests pass, validate:exports exits 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CR-loop confirmation-round #4 findings:
- validator: `resolvesForMode` (renamed from `typesCoversMode`) now applies to
EVERY condition, not just `types`. A partial object under `node`/`default`
(active in both modes) no longer silently covers the mode it lacks —
resolution falls through to the sibling, catching the untyped-JS #3324 shape
there. This completes the per-mode model.
- helper: `withTypesConditions` throws on a non-object `exports` (bare string /
array) instead of iterating it into a corrupt map; `typedTarget` now warns
loudly when a JS target has no adjacent declaration (was silent, contradicting
the helper's own fail-loud contract); idempotency skips only the helper's own
`{ types: <string>, ... }` output, so a hand-authored types-first PARTIAL
object is normalized (its untyped sibling gets a `types`). UMD / `.d.mts` docs
corrected; `ctx.pkg: unknown` documented as intentional (weak-type constraint).
- tests: node/default partial fall-through regression; types-first-partial
normalization; a helper->validator round-trip; a console.warn assertion for
the missing-declaration path; split the untouched-target test into silent
(non-JS) and warning (JS) cases.
- react-native: dropped a pre-existing duplicate `@ag-ui/client` external.
Call sites: resolvesForMode (internal, walk + recursion; grep-confirmed no
`typesCoversMode` refs); withTypesConditions signature unchanged, and the new
throw/warn never fire on tsdown's real input (object map, packageJsonPath
present, dts:true).
36 tests pass; validator typechecks; validate:exports exits 0; native-loader
builds of react-core + react-native unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CR-loop confirmation-round #3 findings:
- validator: a `types` condition now "wins" a resolution mode only when it
actually covers that mode (new `typesCoversMode`). A partial object `types`
(e.g. only `import`) no longer silently covers `require` — resolution falls
through to the sibling, catching a real #3324 shape the checker previously
missed. normalizeExports doc + a "read or parse" message tidied.
- helper: idempotency now keys on the FIRST condition being `types` (its own
output shape) rather than mere presence, so a hand-authored `types`-last
entry is normalized instead of passed through — keeping helper output
consistent with what the validator accepts. JSDoc corrected (acts on every
condition target, requires a subpath map, only ADDS a missing `types`).
- tests: made the runtime-only test discriminating (a `browser`-only target
must not be flagged — the prior fixture couldn't catch a regression);
exercised `node`; added partial/well-formed object-`types`, top-level
fallback array, and types-last normalization cases.
Call sites: typesCoversMode (new internal, called by walk); walk/withTypes
signatures unchanged; isActiveCondition now also used by typesCoversMode.
32 tests pass; validator typechecks; real 25-package validate:exports exits 0;
native-loader react-core build unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CR-loop confirmation-round findings on the #3324 guard:
- validator: replace the single-`typesIndex` model with per-mode resolution.
import- and require-mode resolve independently (each picks the first present
of {types, <mode>, node, default} in object order), so a trailing
`default`/`node` shadowed by a typed `import` + `require` is no longer a false
positive, while a genuinely misordered/absent `types` is still flagged.
- helper: make `withTypesConditions` idempotent (skip an object that already
carries a `types` key, so re-application never re-nests `default`) and
optional-chain `ctx` so a missing context hits the fail-loud message.
- CI: run scripts/__tests__/tsdown-exports.test.ts in the guard workflow (the
helper is the mechanism that injects the types conditions, and its test ran
in NO workflow) and add it to the trigger `paths`; note the standalone gate
validates committed artifacts, not build output.
- tests: assert `types` is emitted FIRST via serialization (toEqual is
key-order-insensitive and missed a types-last regression); add idempotency and
trailing-default regression cases.
- react-native: document why its exports map is hand-maintained (no tsdown
`exports` hook) and guarded by validate:exports.
Call sites enumerated:
- walk / findExportsTypeViolations — internal to the validator + its tests;
signatures unchanged. JS_CONDITIONS removed (grep-confirmed no refs); replaced
by RESOLUTION_MODES + isActiveCondition.
- withTypesConditions — 13 tsdown configs via customExports; signature
unchanged, tsdown always supplies ctx.pkg.packageJsonPath and never re-applies
or emits null/array, so the new guards never fire on current input.
28 tests pass; validator typechecks; real 25-package validate:exports exits 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CR-loop findings on the #3324 regression guard:
- validator: normalize bare-string and conditions-only `exports` sugar to the
"." subpath (previously a false negative / false positive); flag a `types`
condition shadowed by an earlier import/require/node/default — a misordered
`types` is the exact #3324 failure a strict resolver hits; recurse into
object-valued `types`; ignore runtime-only conditions (browser/deno/...) so a
typed import/require sibling is not falsely flagged; attach the file path and
`cause` when a package.json fails to parse.
- helper: guard `null` (blocked subpath) and array (fallback) targets — the old
code crashed on null and corrupted arrays into objects; fail loud if
`packageJsonPath` is missing rather than silently emitting a types-less map.
- tests: hermetic fixture coverage for package discovery/filtering + the new
exports shapes, and a new tsdown-exports.test.ts covering the previously
untested `withTypesConditions` helper.
Call sites enumerated:
- withTypesConditions — 13 tsdown configs via customExports. tsdown always
supplies packageJsonPath and generates no null/array targets, so the new
throw/guards never fire on current input (verified: native-loader build of
react-core unchanged, exports byte-identical).
- findExportsTypeViolations / validateAllPackages — signature unchanged;
callers are the validator CLI and the tests. Real 25-package
`validate:exports` still exits 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to the .ts -> .mjs rename: update the validate-package-exports
workflow trigger paths and the validator's comment/error message that still
named scripts/tsdown-exports.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI build runners use a Node with native TypeScript stripping enabled
(process.features.typescript), so tsdown selects its native ESM config
loader. That loader cannot resolve the extensionless relative import
"../../scripts/tsdown-exports" in each tsdown.config.ts, so every package
build failed with "Cannot find module" — cascading into the unit, runtime,
and all integration jobs (which run the build first). Local builds used
tsdown's bundler loader instead, which is why this passed pre-push.
Ship the shared helper as scripts/tsdown-exports.mjs (real ESM) plus a
hand-written tsdown-exports.d.mts, imported with the explicit .mjs
extension. This resolves under the native loader, tsdown's bundler loader,
and tsc alike. The generated exports are unchanged — package.json maps stay
identical.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Under moduleResolution bundler/node16/nodenext, TypeScript ignores the
top-level "types" field once an "exports" map exists, so strict-exports
tooling (e.g. the Backstage CLI) resolves no type declarations and reports
every named export as "has no exported member". tsdown does not emit a
types condition in the exports map it generates.
Add one — first, per import/require, ESM to .d.mts and CJS to .d.cts — via
a shared withTypesConditions helper (scripts/tsdown-exports.ts) wired into
each tsdown config, and directly in the hand-maintained react-native map.
Add a regression guard, since attw and publint do NOT catch this (TS's
adjacent-file fallback masks it): scripts/validate-package-exports-types.ts,
unit + all-package tests, a validate:exports npm script, and a CI workflow
that fail if any publishable package's exports map lacks a types condition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renames the Bots SDK to the Channels SDK. Names only — no behavior change.
- 8 packages @copilotkit/bot* -> @copilotkit/channels* (git mv dirs, names,
workspace: cross-deps). Now includes @copilotkit/bot-intelligence ->
@copilotkit/channels-intelligence (landed on main via #5761; unpublished, so
renamed fresh with the family).
- release.config.json scope keys + versionSource; ReleaseScope union;
canary/stable-release/publish-release scope dropdowns; verify script
- examples/slack (Kite) + examples/teams: deps, jsxImportSource, imports
- showcase/shell-docs: content dirs docs/bots->docs/channels and
reference/bot->reference/channels, nav registry, redirects
createBot and other API names unchanged. Old @copilotkit/bot* to be deprecated
after the new packages publish (bot-intelligence was never published).
Re-derived onto latest main (was conflicting after #5761 landed).
Refs OSS-438
Brings the 499-commit-stale foundations branch up to date with main so #5761
has a clean diff and no stale reverts (e.g. forwardHeaders). Conflicts:
- CopilotThreadsDrawer.tsx: took main's (main renamed CopilotDrawer -> ThreadsDrawer
+ added the collapse feature; the branch's edit was a no-op import-type split).
- pnpm-lock.yaml: regenerated with the pinned pnpm 10.33.4 (adds @copilotkit/bot-intelligence).
Move the Intelligence-delivered managed-bot surface out of @copilotkit/bot into
its own package so the adapter, transports, contracts, and lifecycle ship
independently of bot core.
- New @copilotkit/bot-intelligence: intelligenceAdapter + DeliverySource/EgressSink
(+ in-memory impls) + placeholder contracts + startManagedBots/validation/
activation metadata. Production code imports only types from @copilotkit/bot
and @copilotkit/bot-ui.
- @copilotkit/bot keeps the generic PlatformCodec seam (moved to src/codec.ts) and
all core createBot changes (addAdapter, deferred store, id fields,
__managed/skipIngressDedup, exclusive guard). It now also exports the
FakeAdapter/FakeAgent test utilities for downstream adapter-package tests.
- Registered the new release scope: release.config.json, scripts/release/lib/
config.ts, and the canary/publish/stable release workflows.
Tests preserved: bot 150 + bot-intelligence 19 (= the prior 169); bot-slack 261.
Builds typecheck across bot/bot-intelligence/bot-slack/runtime; publint/attw/
oxlint/oxfmt clean.
The StateStore interface and the in-memory MemoryStore default remain;
durable backends can be reintroduced as a follow-up. Both adapter packages
were merged in #5613 but never published to npm, so removal is a clean
delete with no consumer impact.
- Delete packages/bot-store-redis and packages/bot-store-postgres.
- Revert the bot release scope and drift guard to bot + bot-ui.
- Strip the Redis dep, demo:restart script, restart demo, docker-compose,
and REDIS_URL env from examples/slack.
- Rewrite the bot persistence/transcripts docs around "MemoryStore default
+ implement the StateStore interface yourself for durability".
Adds a durable persistence layer for @copilotkit/bot, replacing the
in-memory-only ActionStore with a pluggable StateStore.
- StateStore interface (kv/list/lock/dedup/queue) with a shared
conformance suite; MemoryStore default plus @copilotkit/bot-store-redis
and @copilotkit/bot-store-postgres backends.
- createBot({ store }): typed per-thread state via Standard Schema,
action snapshots persisted through the store, per-conversation turn
lock (onLockConflict drop|force), and inbound-event dedup keyed on a
stable eventId. ActionStore is kept as a deprecated alias.
- Cross-platform transcripts (bot.transcripts + identity resolver) with
age-bounded retention (prune on append + filter on read), and
runAgent({ transcript: true }) to auto-inject history and capture the
reply.
- createBot({ components }) re-registers components so durable actions
re-fire after a restart; restart-durability demo in examples/slack.
- Dedup is marked seen only after the turn lock is acquired, so a turn
dropped on lock-conflict does not burn its eventId (no lost retries).
- Release lockstep: bot-store-redis/postgres version with bot + bot-ui.
## Summary
- remove the retired top-level `docs/` Next app and the disabled
docs-sync workflow/script
- add `docs -> showcase/shell-docs` as a top-level symlink for `cd docs`
muscle memory without restoring the old docs tree
- move the docs model allowlist into `showcase/shell-docs/` and retarget
docs validation/doctest extraction to shell-docs content
- update docs/agent guidance and CI path filters so `docs/` is treated
as an alias, not an active separate docs surface
- tighten the pre-commit package check so non-package docs/tooling
changes do not fan out into the full package matrix
## Validation
- `pnpm exec tsx scripts/validate-doc-model-names.ts`
- `pnpm exec tsx scripts/doc-tests/extract.ts`
- `pnpm exec vitest run
scripts/__tests__/validate-doc-model-names.test.ts
scripts/doc-tests/__tests__/extract.test.ts
showcase/harness/src/cli/eval/scope.test.ts`
- `pnpm exec oxlint showcase/harness/src/cli/eval/scope.test.ts
scripts/doc-tests/extract.ts`
- `git diff --cached --check` before follow-up commit
- `test "$(readlink docs)" = "showcase/shell-docs"`
- `test -f docs/package.json`
- `pnpm exec oxfmt --check .claude/docs/documentation.md
.claude/docs/hooks.md AGENTS.md CLAUDE.md CONTRIBUTING.md
showcase/shell-docs/README.md`
- commit hooks passed
## Notes
- historical docs remain recoverable from
`archive/docs-save-do-not-prune` and `archive/docs-retired-2026-06-17`
- I intentionally left Vercel/project teardown out of this PR; this is
repo cleanup only
The plugin version pins to packages/runtime/package.json, but plugin.json
(1.60.0) and marketplace.json (plugins[0] 1.60.0, metadata 1.57.3) had
rotted behind the runtime package (1.60.2), so check:plugin-skills was
failing on main.
handleVersionSync previously managed only plugin.json.version and
marketplace plugins[0].version, leaving marketplace metadata.version
unmanaged and free to drift independently. Extend it to track
metadata.version against the runtime version too, and re-run the sync to
bring all three fields to 1.60.2.
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.
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).
Conflict resolutions:
- contract test: keep the rollout's parameterized version and add
strands-python to migratedIntegrations/appRoots (60/60 passing) in
place of her bespoke MIGRATED_INSTANCES file
- parity manifest: rollout's version with strands' three threads-shield
allowances removed (mirrors the langgraph-fastapi migration); parity
verify green — strands now 88 tracked files, zero drift
- package-lock: regenerated at 1.59.3 (a2ui-renderer stays 1.56.5,
the family-wide pin shared with the north-star)
Also rides: her react-core A2UIMessageRenderer test flake fix
(act -> waitFor), kept intentionally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflict resolution: take the rollout's contract test and append the
agentcore describe block (CDK lambda runtime gate, Vite frontend with
import.meta.env gate, docker env wiring). Bump both agentcore
package.jsons 1.59.1 -> 1.59.3 + regen lockfiles. 54/54.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflict resolution: take the rollout's parameterized contract test and
append the a2a-a2ui bespoke tests (namespaced helper, 1.59.3 pins).
Bump a2a-a2ui @copilotkit/* 1.59.1 -> 1.59.3 + regen lockfile. 49/49.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- bump a2a-middleware, mcp-apps, agent-spec from 1.59.1 (their verified
pre-revert state) to 1.59.3 to match the starters
- regenerate package-lock.json for the 11 examples whose package.json
changed (drawer deps re-added on starters, version bumps on the three)
- update the migration contract test's version assertions to 1.59.3
(43/43 passing); oxfmt pass
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restores #5151 (north-star + batch 1 + crewai-flows + llamaindex),
#5196 (pydantic-ai), #5205 (a2a-middleware), #5211 (mcp-apps), reconciled
onto the current main baseline rather than the pre-revert tree:
- keep main's 1.59.3 pins, AGENT_URL normalization, default agent keys,
useConfigureSuggestions, available:false, useRenderTool
status/parameters API, call-time agent.state reads, and crewai-crews'
rebuilt page (not yet threads-migrated)
- graft the threads layer (drawer/gate/provider, env-gated route
intelligence block, next.config gate, env docs, drawer deps) on top
- drop threads-era sidebar suggestions props where main now registers
suggestions via useConfigureSuggestions (or omits them)
- fix the stale pydantic-ai doc link main reintroduced in ms-af-dotnet
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a pure builder that renders one concise #oss-alerts Slack message
per release from a unit-tested truth table: suppresses canary/dry-run
runs, gates npm/PyPI failure arms on event-derived release intent, and
pages on uncertain state. The CLI wrapper serializes env input to the
builder and writes the result to GITHUB_OUTPUT, failing loud on any
malformed or missing input.
Post-merge fix: add the missing examples/integrations/mcp-apps/.env.example
(+ .gitignore negation, crewai-flows precedent) — the contract test
'mcp-apps documents the local Intelligence environment' was failing
because the file was never added. 37/37 passing on the merged tree.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflict resolution: take main's 4-entry migratedIntegrations array and
keep the a2a-middleware-specific contract tests + helper (a2a-middleware
uses app/ root + custom chat, so it doesn't fit the parameterized
src/app contract). 31/31 passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>