test/release-workflow.test.ts pins the `rm -rf` block in
cli.install-health-check.yml against INSTALL.md's documented uninstall,
and the health check listed $HOME/.composio-canary inside that block.
The canary bin dir is the workflow's own isolation directory, not
something a user uninstalls, so INSTALL.md must not grow an entry for it.
Tear it down in a separate statement instead. The parser only reads the
backslash-continued block, so a single-line `rm -rf` is invisible to it
while the cleanup still runs before the install.
An installer-only change ran no lint or tests anywhere before landing:
Test Installation triggered on tag push, dispatch, and call only, and Build
CLI Binaries' push path filter did not cover install.sh or install/.
Add install.sh and install/** to that path filter, and trigger Test
Installation on pull requests touching the installer, its suites, or the
workflow itself. Only the ubuntu-only unit-test job (shellcheck plus the
install-sh-*.test.sh suites) runs there; the multi-OS matrix installs an
already-published release a pull request cannot produce, so it stays gated
off pull requests along with the summary that reports it.
The input let legs that install an older published release accept
install.sh's legacy PATH block. That case no longer exists: install.sh
always comes from this checkout, and delegated_setup_verified only trusts a
delegated `composio install --shell` when every target startup file matches
its own rendering byte for byte, rewriting the block inline otherwise. The
unconditional managed-block assertion is therefore valid on every leg, and
no run body ever read the env var it was wired into.
Keeps this branch's fixture-driven managed-block reconciler
(reconcileManagedPathBlock, pinned byte-for-byte against install.sh's awk
rewrite by test/managed-block-fixtures) and drops next's narrower
replaceManagedPathBlock/applyFileChanges pair, which it supersedes.
Adopts from next: the narrowed unsafe-path character set on both the TS and
sh sides, the removal of the $PATH-reachability write skip, the hedged
no-shell PATH message, and the COMPOSIO_BIN_DIR command documentation.
The shell-config check accepted the legacy install.sh block on every leg,
justified by a comment claiming no leg installs a binary built from this
checkout. Build CLI Binaries calls this workflow with the tag it just
released, so that leg does exercise the new binary — and a completely
broken `composio install` that fell through to install.sh's writer still
reported success.
Callers now declare built_from_this_checkout; those legs must show the
CLI-managed PATH line. promote-stable keeps the permissive check, since
it rebuilds the promoted beta's own commit, which can predate the writer.
Install the no-arg canary with COMPOSIO_BIN_DIR=$HOME/.composio-canary/bin,
a directory Ubuntu's ~/.profile never contributes, so the env -i login
probe passes only when the managed block itself makes composio
resolvable, and assert nothing lands in ~/.local/bin.
The /install/<shell> variant routes still 404 in production, so the
harness's prod mode now selects the shell with COMPOSIO_INSTALL_SHELL on
the base /install route, and the scheduled matrix gains a fish leg. The
Docker harness invocation stays in place; a workflow comment records how
to restore variant-route coverage once the routes ship.
The uninstall snippet now stages each startup-file rewrite in a 0600
mktemp file, promotes it only when the filter succeeds (preserving
symlinks, inode, owner, and mode), always cleans up, removes legacy
three-line blocks including the fish install-dir export, and deletes an
installer-created ~/.bash_profile left empty so bash regains its default
startup-file selection. A new suite extracts the snippet verbatim from
the docs and exercises it under sh and dash, wired into the install
script unit-test workflow.
Port the atomic replacement work from #4016: support files publish first,
release metadata next, the binary last, with aside/rollback recovery for
directory entries and preserved staging on failed restores.
The bash -ilc probe inherited the step PATH, which already contains
~/.local/bin via GITHUB_PATH and Ubuntu's skel ~/.profile, so a
regression in the bash login-file write could not turn the canary red.
Run the probe under env -i with a bare PATH, mirroring the harness's
assert_login_bash_path, and additionally assert the managed block in
the login-mode startup file the login shell actually reads.
The shell-config assertions only passed for binaries that write the new
CLI-managed PATH line, but every leg of this workflow installs a published
release binary: workflow_dispatch re-verification of existing releases,
workflow_call with the default 'latest', and promote-stable rebuilds of an
older beta all install pre-change binaries that write the legacy
COMPOSIO_INSTALL_DIR block (as does install.sh's own fallback). Accept
either working PATH layout, fail only when neither is present, and keep
rejecting a mixed state where the new PATH line coexists with a persisted
COMPOSIO_INSTALL_DIR.
Apply verified code-review findings: write through symlinked startup
files with preserved mode and a per-process tmp name; verify delegated
CLI setup actually reconciled the managed block before trusting exit 0;
make managed-block reconciliation assignment-aware so annotated blocks
never lose user content or PATH precedence; clean up the CLI's tmp file
when an atomic write fails; assert the auto contract in the install
health-check canary; recommend composio install --shell in generated
release docs; record the new default in the CLI changelog.
This PR:
- supersedes https://github.com/ComposioHQ/composio/pull/4010 and
credits @MGPOCKY for identifying the stale Cloudflare E2E Node override
- lets Cloudflare E2E resolve the exact Node.js version from mise.lock
through the shared setup action
- retains the release job's explicit Node.js 24.17.0 publishing pin and
corrects its outdated explanation
- verifies the release workflow guard, workflow YAML parsing,
formatting, and whitespace checks
Co-authored-by: MGPOCKY <kkm1447@naver.com>
Replace the base installer's --shell flag with a COMPOSIO_INSTALL_SHELL
environment variable, matching the COMPOSIO_INSTALL_VERSION precedent
and reading more naturally in the curl-pipe form:
curl -fsSL https://composio.dev/install | COMPOSIO_INSTALL_SHELL=zsh sh
The variable is validated before any network call. Shell variants set
it explicitly when invoking the base installer, so the route stays
authoritative over any inherited value. The composio install --shell
CLI flag and the delegation/fallback behavior are unchanged.
Teach install.sh a --shell <zsh|bash|fish> flag that performs the same
shell setup the /install/<shell> variants do: delegate to
'composio install --shell' when the installed CLI supports it, fall
back to writing the # Composio CLI PATH block inline otherwise.
The shell variants become thin wrappers that fetch the base installer
and append '--shell <name>' to the forwarded arguments, so the
delegation and fallback logic now lives in exactly one script. This
also removes the double-configuration hazard of a variant blindly
forwarding a user-supplied --shell.
Shell setup no longer depends on the composio.dev/install/<shell>
redirect rules existing: post-install guidance, docs, and release
notes now print 'curl -fsSL https://composio.dev/install | sh -s --
--shell <shell>', which works through the single existing redirect.
The variant scripts and their raw-URL preview commands keep working
for when the routes land.
Coverage: direct --shell delegation, fallback on unsupported or
failing CLI, missing and invalid values failing before any network
call, and a Docker e2e leg for the idempotent --shell bash flow.
This PR:
- fixes https://github.com/ComposioHQ/composio/issues/3932
- replaces the private CLI package semver with the non-release
`0.0.0-development` sentinel
- injects the exact GitHub release tag version into every standalone
binary and verifies it during the build
- makes every push to `next` a beta, with explicit semver selection for
intentional minor or major betas and stable releases only through beta
promotion
- resolves skill installation, setup repair, companion repair, and
upgrades from packaged `release-tag.txt` metadata
- adds regression coverage for release selection, compiled version
identity, and packaged-tag asset lookup; all 1,009 CLI tests and the
monorepo typecheck pass
- updates the direct CLI changelog and release guidance; no Changeset is
added because CLI packages are excluded from Changesets
This PR:
- fixes a regression introduced by
https://github.com/ComposioHQ/composio/pull/3956: fumadocs-openapi 11's
`groupBy: 'tag'` silently skips operations whose tag is not declared in
the document's top-level `tags` array, which 404'd all 16 Projects and
Organization Management operation pages (e.g.
`/reference/api-reference/projects/postProjectUsageSummary`) on both
v3.1 and v3, and dropped them from the sitemap and search index
- adds `declareOperationTags()` (`docs/lib/openapi-tags.ts`), applied at
spec load time in `lib/openapi.ts` (covers build-time-fetched specs) and
at sync time in `scripts/fetch-openapi.mjs`, which now also warns when
the upstream payload omits tags; the checked-in specs are normalized
accordingly (purely additive)
- adds CI guards in `tests/static/api-reference-routes.test.ts`: spec
invariants (every visible operation has a tag and `operationId`),
bidirectional spec-vs-generated-routes set equality through the
production loader path, a negative test pinning fumadocs' silent-drop
behavior (fails when upstream fixes it, signaling the workaround can be
retired), and validation that every `ApiEndpointsTable` quick-link href
resolves to a generated page
- extends `Docs - Check Links` with a nightly (02:30 UTC) + manual
external-URL sweep via a new `lint:links:external` script; the validator
only fails on evidence a link is dead (404/410 or repeated network
errors, with UA/timeout/GET-fallback/retry and per-URL caching) and
scheduled failures file a deduplicated tracking issue; PR runs keep the
fast internal-only check
- fixes six dead external links the first sweep found (moved Claude
Agent SDK docs, stale dashboard settings URL ×2, a `master`-branch path
now pinned to tag `0.5.0+post.1`, and two removed `ComposioHQ` example
repos whose mentions were dropped — their code is embedded in the pages
via `RepoBrowser`)
## Context
fumadocs-openapi 10 generated a page for any tag string found on an
operation; v11 requires the tag to be declared top-level and skips
silently otherwise (`preset-auto.js`: `builder.fromTagName(tag)` →
`continue`, no warning). The backend spec generator omits `Projects`,
`Organization Management`, and `Invite Codes` from `tags`, so their
operation pages vanished while the checked-in MDX tag landing pages kept
rendering with dead quick links. With the normalizer, the generated URL
set is byte-identical to the pre-#3956 set (234 routes, verified via
`getReferenceSource().getPages()` diff); no revert needed.
Existing checks missed this because `lint:links` only extracts markdown
links and `Card` hrefs (the dead links live in `ApiEndpointsTable`'s
array prop) and validates against the same loader that shrank, and the
integration suite samples fixed routes under tags that survived. The new
completeness guard derives expectations from the specs themselves, so
routine data syncs don't churn it.
This PR:
- fixes the `ts.build.yml` push trigger, which still pointed at
`master`: the repo's default branch is `next`, so the workflow has not
run on push since 2025-10-24 and never populated the turbo/pnpm caches
that PR runs restore from (GitHub cache isolation lets PRs read
base-branch caches, but not other PRs')
- fixes the same stale `master` push trigger in `py.check.yaml` (all
other workflows already list `next`)
- adds a `cache-save` input (default `'true'`, preserving current
behavior for every other consumer) to the `setup-node-pnpm-bun`
composite action, swapping `actions/cache` for `actions/cache/restore`
(same repo, same v6.1.0 SHA pin) when disabled
- wires `cache-save` in `ts.build.yml` so only push runs on `next`
persist caches: PR-scoped saves are invisible to other branches, so they
only cost post-job time and evict default-branch entries from the 10 GB
repo cache quota
## Context
Measured on run
[30364148082](https://github.com/ComposioHQ/composio/actions/runs/30364148082)
(PR run, ~90s wall time):
| Step | Time |
|---|---|
| Checkout | 5s |
| Setup Node.js, pnpm, Bun | 34s (mise 1s, setup-node 5s, setup-bun 2s,
pnpm 2s, **pnpm store restore 18s** for 658 MB, turbo restore 1s) |
| `pnpm install --frozen-lockfile` | 14s |
| `pnpm lint` | 1s |
| `pnpm run build:packages` | 24s, **0/19 turbo cache hits** |
| Post-job cache saves | ~11s (turbo save + a 658 MB pnpm store save
that failed with "Unable to reserve cache", racing the parallel ts.*
jobs on the same PR) |
The build restored a turbo cache only via the fallback restore-key
`Linux-turbo-build-` from an unrelated branch, hence 0 hits. Once push
runs fire on `next` again, every merge saves a fresh
`Linux-turbo-build-<sha>` cache that PR runs match through the
restore-key prefix, so unchanged packages become turbo hits (up to ~20s
off the build step) and the ~11s post-job save disappears from PR runs.
The per-commit key suffix is kept intentionally: the turbo cache
accumulates, so each default-branch save needs a fresh key and readers
match via the prefix (documented inline in the action).
This PR:
- replaces ESLint with oxlint across the pnpm workspace and the
Bun-based docs site, porting the rules to `.oxlintrc.json` /
`docs/.oxlintrc.json` with behavior parity (restricted-syntax selectors
kept via `oxlint-plugin-eslint`)
- migrates typecheck to TypeScript 7 (`typescript@^7.0.2` catalog) and
keeps a TS6 pin for JS compiler API consumers via a named `ts6` pnpm
catalog (`ts/scripts/validate-examples.ts`, the `@composio/cli` generate
pipeline). The CLI's `typescript` dependency rebinds only the
compiler-API import — its typecheck still runs the root TS7 `tsc`, since
the alias package only ships a `tsc6` bin (documented in
`ts/packages/cli/AGENTS.md`)
- removes the `paths` mappings that pointed `@composio/core` (and, in
`experimental`, `@composio/json-schema-to-zod` plus core-internal
`#`-imports) at sibling `src` directories: under TS7, tsdown's
tsgo-based dts step emitted stray `.d.ts` files next to those
out-of-root sources on every dependent package build. Workspace deps now
resolve through their built dist types, which turbo's `dependsOn:
^build` already guarantees exist — and which the deep-path exports
(`@composio/core/*`) always used anyway
- renames the cli boundary tooling `eslint-boundaries*` →
`lint-boundaries*` and hardens the scanner to reject `oxlint-disable`
spellings so the disable manifest cannot be bypassed
- rewrites inline `eslint-disable` comments to oxlint rule names
(comment-only; no runtime changes), and adds **one new** declared
boundary: `tool-file-uploads.ts` needs `no-restricted-imports` disabled
for `node:crypto` (MD5 for the presigned-upload checksum is not in Web
Crypto), because oxlint also catches dynamic `await import()` where
ESLint did not. The manifest grows 46 → 47 deliberately
- updates CI path filters, `turbo.jsonc` lint inputs, and the docs
typescript-check workflow (renamed to "Docs - Lint and TypeScript
Validation" since it now lints too); drops `eslint`,
`typescript-eslint`, `eslint-config-next`, and `globals` from the
dependency graphs
- ships no changeset: I built `@composio/core` and `@composio/anthropic`
on this branch and on the pre-migration base and diffed the emitted
`dist/**/*.d.mts`. The provider output is byte-identical. Core's output
is **semantically identical but not byte-identical**: TS7 changes quote
style (`"x"` → `'x'`), object-property and union-member ordering in
inferred types, and picks equivalent shorter re-export alias paths for
five signatures (e.g. `OpenAI.Beta.Threads.Runs.Run` →
`OpenAI.Beta.Threads.Run` — verified both names alias the same type in
the shipped typings). Chunk-name hashes shift as a consequence. No type
gains, losses, or shape changes; `attw` and `publint` pass on the TS7
build
## Context
First of a three-PR split of #3958. The type-safety refactors are
stacked on this branch and merge after it:
- docs: https://github.com/ComposioHQ/composio/pull/3967
- `@composio/core`: https://github.com/ComposioHQ/composio/pull/3968
curl install.sh is now the only CLI install channel.
- INSTALL.md: drop npm/pnpm/yarn section; Windows guidance is WSL
- install.sh: Windows error no longer advises the dead npm package
- build-cli-binaries.yml: strip npm section from generated release INSTALL.md
- cli.install-health-check.yml: drop stale npm dist-tag/Homebrew comment
- cli.test-installation.yml: delete no-op npm-fallback job and its
toolchain-versions feeder job; prune summary references
- delete cli.bump-homebrew-tap.yml + bump-homebrew-formula.py (automation
never fired: GITHUB_TOKEN-published releases suppress release-triggered
workflows and HOMEBREW_TAP_TOKEN is dead)
- ts/packages/cli/package.json: drop unused publishConfig (package is private)
- cli-release skill + CLI AGENTS.md: remove Homebrew steps from release docs
- toolchain-versions.json: drop now-unused node_install_compat matrix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PostHog's own term for the public write-only phc_* credential is the
project API key; the old name read like a secret. Covers the env var,
the build-time bake define, the baked constant, and the workflow env.
The GitHub repo variable itself must be renamed manually.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Summary
Implements the docs half of **PLEN-2793** — renders a typed public
reference for the payloads Composio delivers to customer webhook URLs,
under **API Reference → Webhook Events**.
Pairs with platform PR ComposioHQ/platform#11389, which generates the
spec.
## What's here
- **`docs/public/openapi-webhooks.json`** — the generated OpenAPI
**3.1** spec (top-level `webhooks`: `composio.trigger.message`,
`composio.connected_account.expired`, `composio.trigger.disabled`),
produced from the webhook payload Zod schemas in Apollo (SSOT). Finishes
the earlier untracked WIP: adds the missing `trigger.disabled` event and
reuses shared schemas as `$ref` (`WebhookEventEnvelope`,
`ConnectedAccountDetailed`).
- **`docs/lib/openapi.ts`** — adds the spec as a **second input** to the
v3.1 reference source. Fumadocs (`fumadocs-openapi`) renders the
`webhooks` block natively; operations group under the "Webhook Events"
tag at `api-reference/webhook-events/*`.
- **`webhook-events/index.mdx`** — landing page listing the three
events, cross-linked to the Webhook Subscriptions API and signature
verification.
## Why a separate 3.1 spec
`webhooks` is a 3.1-only top-level field; the main `openapi.json` is
3.0. A separate file keeps the main spec (and its sync pipeline)
untouched and avoids the docs' union-normalisation pass. See the
platform PR for the full rationale.
## Verified locally
- [x] `bun scripts/validate-links.ts` — **0 errors** (the generated
`handle_composio_*` webhook pages resolve; no collision with the
hand-authored `index.mdx`)
- [x] `bun test tests/static/` — 33 pass / 0 fail
- [x] `bun run types:check` — clean
## Notes
- Setup, subscription, and signature-verification docs already exist
(`setting-up-triggers/*`) and are cross-linked, not rewritten.
- Follow-up (optional): auto-sync the webhooks spec from Apollo on prod
deploy (currently committed by hand), mirroring the main-spec
`docs-update-data` pipeline.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: jkomyno <alberto@composio.dev>
This PR:
- splits https://github.com/ComposioHQ/composio/pull/3953 in two: this
PR carries every dependency and GitHub Actions bump **except** the docs
site, which follows in a stacked PR
- consolidates and supersedes Dependabot PRs #3915, #3916, and #3934
through #3942
- adopts TypeScript 7.0.2 for primary compilation while retaining the
`@typescript/typescript6` API lane that TypeScript-ESLint still
requires, following the upstream side-by-side guidance
- refreshes Python core and provider dependencies, lockfiles, and the
Ruff 0.16 lint configuration
- updates every GitHub Action with a verified newer official release,
including majors, while retaining immutable commit SHA pins and
migrating setup-uv cache pruning
- deletes four per-package `eslint.config.mjs` shims: under ESLint 10
the default per-file config lookup re-anchors the root config's globs
into each package, so `pnpm lint` stayed green while the CLI's
try/catch, `process.env` and node-builtin bans went unenforced
- bounds and documents the new `brace-expansion` and `@hono/node-server`
security overrides, raising the `@hono/node-server` floor to 2.0.10 to
clear GHSA-9mqv-5hh9-4cgg
- preserves intentional compatibility fixtures and lanes for AI SDK 6,
Zod 3, TypeScript 5.8, Mastra AI SDK 5, and Python provider constraints
## Context
The docs site is a separate Bun workspace with its own `bun.lock` and is
not a pnpm workspace member, so the two halves share no lockfile and no
build. Splitting them keeps the Fumadocs 11 migration (a breaking API
change with real refactoring) reviewable on its own, independently of
the mechanical version bumps here.
The `brace-expansion` override deliberately spans majors:
GHSA-mh99-v99m-4gvg (HIGH) is published as a single `<=5.0.7` range with
no 1.x or 2.x backport, so narrowing it to the 5.x line puts
`brace-expansion` 2.1.2 back under `core>minimatch>brace-expansion` and
`pnpm audit --prod --audit-level=high` exits 1. Verified both ways; the
trade-off it buys is recorded inline in `pnpm-workspace.yaml`.
Verified on this branch standalone: `pnpm install --frozen-lockfile`,
`pnpm lint`, `pnpm typecheck`, `pnpm build:packages`, `pnpm test` (963
tests, 26/26 tasks), and `pnpm audit --prod --audit-level=high`.