Verify Marketplace credential expects an active Azure session via azure/login, but login was gated only on published==false. When dry_run=true and version is already published, the verify step ran without a session and failed. Widening the guard to include dry_run.
Split the runner image into three stages:
- frontend (node:22-slim) builds Next.js artifacts
- agent-builder (python:3.12.13) builds /opt/venv from requirements.txt
- runner (python:3.12.13-slim) installs Node.js + copies artifacts, with no
pip and no build-essential
Mirrors the pattern already used by showcase/starters/strands/Dockerfile.
Split the runner image into three stages:
- frontend (node:22-slim) builds Next.js artifacts
- agent-builder (python:3.12.13) builds /opt/venv from requirements.txt
- runner (python:3.12.13-slim) installs Node.js + copies artifacts, with no
pip and no build-essential
Mirrors the pattern already used by showcase/starters/pydantic-ai/Dockerfile.
Split the runner image into three stages:
- frontend (node:22-slim) builds Next.js artifacts
- agent-builder (python:3.12.13) builds /opt/venv from requirements.txt
- runner (python:3.12.13-slim) installs Node.js + copies artifacts, with no
pip and no build-essential
Mirrors the pattern already used by showcase/starters/ms-agent-python/Dockerfile.
Split the runner image into three stages:
- frontend (node:22-slim) builds Next.js artifacts
- agent-builder (python:3.12.13) builds /opt/venv from requirements.txt
- runner (python:3.12.13-slim) installs Node.js + copies artifacts, with no
pip and no build-essential
Mirrors the pattern already used by showcase/starters/llamaindex/Dockerfile.
## Summary
- Local `scripts/release/vscode-extension-release.sh` — bumps
`packages/vscode-extension/package.json`, commits, tags
`vscode-extension-v<ver>`, and pushes. Supports `patch` / `minor` /
`major` / explicit SemVer, plus `--dry-run`.
- `.github/workflows/publish-vscode-extension.yml` — tag-triggered
workflow that builds once, packages a single VSIX, and dual-publishes to
VS Code Marketplace + Open VSX. Partial-failure-aware.
- `packages/vscode-extension/RELEASING.md` — runbook covering
prerequisites, first-time Open VSX setup, cutting a release,
verification, and rollback.
## Why this shape
- **Independent of PR #3935.** The extension package itself lives on
#3935's branch and is not yet on `main`. This PR adds the release
*pipeline* only — the workflow references `packages/vscode-extension/`
which will be a valid path once #3935 merges.
- **Outside the existing npm release scope.** The monorepo's
`scripts/release/` pipeline (driven by `release.config.json` scopes
`monorepo` / `cli` / `angular`) is npm-only. VSIX publishing doesn't fit
that model, so this lives next to it as a sibling tag-triggered workflow
rather than being bolted onto `publish-release.ts`.
- **Immutable-artifact pattern.** `vsce package` runs once; the same
`.vsix` is uploaded as a workflow artifact *and* published to both
registries. No version arg is passed to `vsce publish` / `ovsx publish`
— `--packagePath` ensures we ship the exact bits we packaged.
- **Partial-failure visibility.** Both registry publishes use
`continue-on-error` with a final reconciliation step that fails the job
if either failed. You will never end up in \"Marketplace succeeded, Open
VSX silently skipped.\"
## One-time setup required before first CI publish
1. Create Open VSX account + personal access token at
<https://open-vsx.org/user-settings/tokens>.
2. Claim the publisher namespace (one-time): `npx --yes ovsx
create-namespace copilotkit -p <token>`
3. Add `OVSX_PAT` to GH repo → Settings → Environments → `production` →
Environment secrets.
4. Confirm `VSCE_PAT` is already in the same environment (used for the
manual v0.1.0 publish).
Until step 3 lands, tag pushes will fail loudly at the \"Publish to Open
VSX\" step with a clear error — no silent skip.
## Test plan
- [ ] Dry-run the local helper (already verified against the #3935
worktree): `scripts/release/vscode-extension-release.sh patch --dry-run`
previews `0.1.0 → 0.1.1`, `minor` previews `0.2.0`, explicit `1.2.3` is
honored.
- [ ] Once #3935 merges and an `OVSX_PAT` is set, maintainer runs
`scripts/release/vscode-extension-release.sh patch` on `main` and
watches
<https://github.com/CopilotKit/CopilotKit/actions/workflows/publish-vscode-extension.yml>.
- [ ] Workflow triggers on the `vscode-extension-v*` tag, builds,
packages, uploads artifact.
- [ ] VSIX published to both registries; listings update within minutes.
- [ ] `code --install-extension copilotkit.copilotkit-vscode-extension
--force` installs the new version.
## Caveats
- This PR will have a minor merge conflict with #3935 if #3935 adds its
own `RELEASING.md` (it does not today). Otherwise the paths are
disjoint: this PR only touches `scripts/release/`, `.github/workflows/`,
and creates a new file in `packages/vscode-extension/`.
- Azure DevOps long-lived Marketplace PATs retire on 2026-12-01 — OIDC
migration is out of scope for this PR and tracked separately in the
Notion playbook.
Split Python install into a dedicated agent-builder stage (python:3.12.13)
that produces /opt/venv, which the slim runner COPYs in. The runner no
longer runs pip install, so no compiler toolchain or build-essential bloats
the final image.
Preserves behavior: entrypoint.sh, port 10000, src/aimock_toggle.py,
shared_python/ -> /app/shared/python/ + PYTHONPATH. No image-level
NODE_ENV (entrypoint.sh scopes it to Next.js only).
Split Python install into a dedicated agent-builder stage (python:3.12.13)
that produces /opt/venv, which the slim runner COPYs in. The runner no
longer runs pip install, so no compiler toolchain or build-essential bloats
the final image.
Preserves behavior: entrypoint.sh, port 10000, ENV NODE_ENV=production,
shared_python/ -> /app/shared/python/ + PYTHONPATH.
Split Python install into a dedicated agent-builder stage (python:3.12.13)
that produces /opt/venv, which the slim runner COPYs in. The runner no
longer runs pip install, so no compiler toolchain or build-essential bloats
the final image.
Preserves behavior: entrypoint.sh, port 10000, ENV NODE_ENV=production,
shared_python/ -> /app/shared/python/ + PYTHONPATH.
Split Python install into a dedicated agent-builder stage (python:3.12.13)
that produces /opt/venv, which the slim runner COPYs in. The runner no
longer runs pip install, so no compiler toolchain or build-essential bloats
the final image.
Preserves behavior: entrypoint.sh, port 10000, ENV NODE_ENV=production,
shared_python/ -> /app/shared/python/ + PYTHONPATH.
The dry-run summary referenced scripts/release/vscode-extension-release.sh,
which was removed in 17c4daee3 (drop release helper script). Point
maintainers at the new CHANGELOG-edit flow instead.
Rewrites the 'Cutting a release' section to match the new
changelog-sync automation: maintainers prepend a CHANGELOG entry,
commit with any message, open a PR, and the sync workflow auto-bumps
package.json with 'chore: release vX.Y.Z'. Adds a manual escape hatch
for when the sync workflow is unavailable.
Other sections (Prerequisites, Open VSX setup, CI publish flow,
Rollback, Notes) are unchanged.
Adds .github/workflows/vscode-extension-changelog-sync.yml: on PRs that
touch packages/vscode-extension/CHANGELOG.md, read the top '## X.Y.Z'
entry and bump packages/vscode-extension/package.json to match via an
auto-committed 'chore: release vX.Y.Z' on the PR branch.
Collapses the release maintainer flow to a single CHANGELOG edit.
Forks are skipped (GITHUB_TOKEN can't push to fork branches). A
guardrail rejects CHANGELOG entries older than the current package.json
version (catches history edits vs. prepends).
Lets us validate the Marketplace-OIDC and Open VSX auth chains end-to-end
without actually publishing. workflow_dispatch now accepts a dry_run input
(default true); when set, the job runs checkout, Azure login,
vsce verify-pat, and a new Open VSX /api/user token introspection, then
stops before any publish, tag, release, or Slack success notify.
Push trigger is unchanged — dry_run is only meaningful for manual runs.
- Use slackapi/slack-github-action@v2.1.0 matching 8+ existing workflows
- Switch from SLACK_WEBHOOK to SLACK_WEBHOOK_OSS_ALERTS (the secret
actually wired up in the repo, routed to #oss-alerts)
- Guard with env.SLACK_WEBHOOK_OSS_ALERTS != '' for repo-fork safety
- Add failure-path notification with failed job + per-registry outcomes
+ run URL (follows memory rule: red alerts carry actionable detail)
- Expose publisher as a step output to construct Open VSX URL cleanly
(https://open-vsx.org/extension/<publisher>/<name>) instead of inline
tr substitution
Rewrite the 'Cutting a release' + 'CI publish flow' sections to describe
the aimock-pattern flow (hand-bump + PR-merge + self-gated CI publish)
and the new multi-bullet --summary/--type CLI. Retain the Open VSX
one-time-setup block, the transient-failure handling notes, verification
steps, rollback guidance, and ADO PAT retirement note.
Rewrite vscode-extension-release.sh to cut an aimock-style release commit
(bump package.json + prepend CHANGELOG.md section) without tagging or
pushing — CI now owns tag/release creation on main-push. Takes one or
more --summary bullets grouped by --type (Added/Changed/Fixed/Removed/
Deprecated/Security, Keep-a-Changelog style). Supports --dry-run.
Seed packages/vscode-extension/CHANGELOG.md with a retroactive v0.1.0
entry covering the three launch surfaces (A2UI Preview, Hook Explorer,
AG-UI Inspector) so the first real release has prior history to anchor
against and the GH Release step has notes to pull from.
Replace tag-triggered publish with push-to-main + version-on-Marketplace
self-gate, matching CopilotKit/aimock. CI reads version from package.json,
queries vsce show for that version, and no-ops if already published. On a
new version it builds once, dual-publishes (Marketplace + Open VSX with
the existing retry wrappers and idempotent 'already exists' handling),
tags vscode-extension-vX.Y.Z, cuts a GitHub Release from the CHANGELOG
section, and posts to SLACK_WEBHOOK if configured. Path-scoped to
packages/vscode-extension/** so unrelated pushes don't trigger the job.
Wrap both registry publish steps in a bash retry helper that retries up
to 5 times with staggered backoff (10s/20s/40s/60s/90s) on transient
conditions (5xx, timeouts, connection resets, DNS). Auth and validation
errors still fail fast with no retry.
Critically, 'version already exists' is treated as idempotent success:
if attempt N-1 landed on the registry but its response was lost to a
502 after commit, attempt N sees the already-published version and
short-circuits rather than failing the job.
Motivated by Open VSX /publish returning intermittent 502 Bad Gateway
errors from Eclipse Foundation infra. Each attempt is wrapped in
::group:: markers so per-attempt logs are collapsible in the Actions
UI. Reconciliation step updated to reflect retry semantics and to
tell the operator to rerun the job (not bump the version) on exhausted
retries. RELEASING.md gets a 'Transient registry failures' section
documenting the behavior for both CI and manual publish paths.
Covers prerequisites (VSCE_PAT + OVSX_PAT as production env secrets),
the one-time Open VSX namespace claim, how to cut a release via the
local helper script, the CI publish flow, verification URLs, rollback
guidance (registries are immutable, ship forward), and a note on the
2026-12-01 Azure DevOps PAT sunset.
Trigger: push of vscode-extension-v* tags.
Builds the extension once, packages a single VSIX, uploads it as a
workflow artifact, then publishes the same VSIX to the VS Code
Marketplace and Open VSX. Both registry publishes use continue-on-error
with a final reconciliation step so a partial failure is visible
instead of silently succeeding on one registry only.
Secrets VSCE_PAT and OVSX_PAT are read from the 'production'
environment so rotation and approval flow are scoped correctly.
Adds scripts/release/vscode-extension-release.sh for bumping
packages/vscode-extension, committing, tagging vscode-extension-v<ver>,
and pushing. The tag push fires the publish workflow.
Supports patch/minor/major and explicit SemVer, plus --dry-run for
preview without mutating anything. Exits early on dirty trees.
## Summary
Page-by-page content audit of `showcase/shell-docs/src/content/docs/`
MDX files to make the docs app production-ready. The audit checked
snippet wiring (`<Snippet region="...">` regions against
`demo-content.json`), internal link correctness, and MDX syntax.
**What was fixed:**
- **1 broken snippet region**: `generative-ui/a2ui/dynamic-schema.mdx`
Step 5 referenced `runtime-inject-tool`, which doesn't exist in the
`declarative-gen-ui` cell — would have rendered a `WarningBox` in
production. Replaced with a hardcoded code block.
- **1 MDX syntax error**: `frontend-actions.mdx` had a stray closing `
``` ` fence at end of file.
- **Internal links — `/docs/` prefix removed (14 files, ~30 links)**:
The docs app routing doesn't use a `/docs/` prefix. Links using
`/docs/<slug>` hit the reserved-slug guard in the `[framework]` route
and 404. All converted to `/<slug>`. Affected:
`generative-ui/index.mdx`, `generative-ui/tool-based.mdx`,
`learn/index.mdx`, `multi-agent/subagents.mdx`, `shared-state.mdx`,
`shared-state/streaming.mdx`, `shared-state/agent-readonly.mdx`, and all
5 `troubleshooting/` pages.
- **Internal links — `/unselected/` cleaned up (2 files)**:
`backend/copilot-runtime.mdx` and `backend/custom-agent.mdx` linked to
`/unselected/quickstart`; changed to `/quickstart`.
**What was audited and confirmed correct (no changes needed):**
All of `prebuilt-components/`, `custom-look-and-feel/` (slots, css,
headless-ui, reasoning-messages), `generative-ui/tool-rendering.mdx`,
`generative-ui/reasoning.mdx`, `generative-ui/mcp-apps.mdx`,
`generative-ui/open-generative-ui.mdx`,
`generative-ui/a2ui/fixed-schema.mdx`, `headless.mdx`,
`programmatic-control.mdx`, `shared-state/agent-readonly.mdx`,
`human-in-the-loop/` (all three pages), `multi-agent/subagents.mdx`, all
`backend/` pages, and all `learn/` sub-pages.
**Known remaining gaps (out of scope for this PR):**
- Several pages are stubs with hardcoded placeholder code instead of
live `<Snippet>` wiring: `generative-ui/display.mdx`,
`generative-ui/your-components/display-only.mdx`,
`generative-ui/your-components/interactive.mdx`
- `unselected/quickstart.mdx` has malformed content (raw JS import
identifiers leaked into the body)
- The `integrations/` subdirectory and `unselected/` directory were out
of scope
## Test plan
- [ ] Verify internal links in affected pages no longer 404 in the
shell-docs app
- [ ] Confirm `generative-ui/a2ui/dynamic-schema.mdx` Step 5 renders the
runtime code block instead of a WarningBox
- [ ] Confirm `frontend-actions.mdx` renders without a stray ` ``` ` at
the bottom
Widens CopilotChatView's autoScroll prop to accept "pin-to-bottom" |
"pin-to-send" | "none" | boolean. "pin-to-send" scrolls the latest
user message to ~16px from the top on send and maintains a dynamic
bottom spacer so the viewport doesn't chase the streaming response.
Boolean back-compat: true -> "pin-to-bottom", false -> "none".
There is no app/integrations/ route, so the reservation was causing
/integrations/... URLs to 404. Without it, these paths fall through to
UnscopedDocsPage via the non-integration fallthrough in [framework].
Strip snippet_framework: langgraph-python from frontmatter and
integration="langgraph-python" from all InlineDemo tags in the
main docs tree (27 files). On framework-scoped pages frameworkOverride
drives Snippet and InlineDemo; on unscoped pages FrameworkGuardedContent
already hides the body until a framework is selected, so no default
is needed.
buildNavTree now checks meta.root before including a subdirectory,
so unselected/ (and any other root:true directory) is excluded from
the main nav tree. This eliminates the flicker where SidebarLink
generated /langgraph-python/unselected/coding-agents and the
[framework] route had to server-redirect to the correct scoped URL.
On framework-scoped pages, MDX links like /quickstart rendered as plain
<a href="/quickstart"> causing RouterPivot redirect flicker. Override the
MDX `a` component when frameworkOverride is set to prepend the framework
prefix to root-relative internal links.
Next.js routes /quickstart to [framework]/[[...slug]] (dynamic segment
beats optional catch-all), where "quickstart" is not a registered
integration, causing notFound(). Fix by:
- Extracting the unscoped doc rendering logic into UnscopedDocsPage
- Falling through to it in [framework] when the slug is not a framework
- Simplifying [[...slug]]/page.tsx to handle only the root overview
SidebarLink now uses storedFramework as fallback so links on the
overview page go directly to /<framework>/<slug> without a RouterPivot
redirect. OverviewNavItem and section cards now use SidebarLink for the
same reason. FrameworkSelector "Clear selection" was navigating to
/docs/<slug> (broken); fixed to /<slug>. hrefFor now preserves the
current slug when switching frameworks from an unscoped page.