This PR:
- closes#3502
- extracts the useful dependency and Cloudflare config slice from
https://github.com/ComposioHQ/composio/pull/3503 onto a clean `next`
branch
- upgrades `vitest` and `@vitest/ui` through the workspace catalog to
resolve the critical advisory
- switches the Mastra provider test dependency back to the catalog
- migrates the Cloudflare Worker Vitest configs to the
`cloudflareTest()` plugin API
- preserves existing `COMPOSIO_BASE_URL` bindings that were dropped in
#3503
- keeps Vitest 4 compatibility fixes scoped to constructor mocks, spy
cleanup, and temp-root project detection
- leaves Node, `mise`, release docs, and Effect catalog versions
unchanged; the commit includes @Dotify71 as `Co-authored-by`
Co-authored-by: Dushyant Acharya <dushyantacharya873@gmail.com>
## Summary
Depends on #3492.
This completes the Phase 2 migration by removing the transitional
version-file layer and making `mise.toml` plus `mise.lock` the
repository toolchain source of truth. It also moves runtime test
matrices into `toolchain-versions.json`, so CI matrix changes are
explicit and reviewable without reintroducing `.nvmrc`, `.dvmrc`,
`.bun-version`, or `.python-version`.
The Node.js e2e matrix now starts at the latest Node 22 LTS line and
also covers the latest Node 24 and Node 25 lines. That removes Node 20
from the well-known e2e versions while keeping us covered on the
runtimes SDK users are moving toward.
## Rationale
Phase 1 introduced mise side by side with the existing version files to
keep the first PR low-risk. Phase 2 removes that compatibility layer so
there is one place to update tool versions. That avoids silent drift
between local setup, GitHub Actions, Docker E2E images, release docs,
and install-time checks.
The composite setup actions now install Node, Bun, Python, and uv
through mise by default, with explicit version overrides only where a
matrix needs them. New GitHub actions added in this PR are pinned by
release commit SHA and include the release version comment.
## What changed
- Deleted the transitional root/version files: `.nvmrc`, `.bun-version`,
`.dvmrc`, root `.python-version`, and `python/.python-version`.
- Removed `idiomatic_version_file_enable_tools` from `mise.toml` and
added a committed `mise.lock` for linux/macOS x64/arm64 tool resolution.
- Replaced `BYPASS_BUN_VERSION_CHECK` with `BYPASS_TOOLCHAIN_CHECK`, and
made Docker E2E image installs use that bypass because they receive
explicit build args instead of installing mise.
- Updated Node/Bun and Python/uv composite actions to default to mise,
remove `*-version-file` inputs, report resolved versions, and cache pnpm
after `corepack enable`.
- Centralized CI runtime matrices in `toolchain-versions.json` for TS
E2E, Python tests, and CLI npm fallback coverage.
- Updated the Node E2E matrix to `22.22.3`, `24.16.0`, and `25.9.0`,
removing Node 20 from the well-known runtime versions.
- Updated workflows, docs, E2E helpers, Dockerfiles, and release
guidance to reference `mise.toml` / `mise.lock`.
## Verification
- Verified latest Node 22/24/25 releases from the official Node dist
index: `22.22.3`, `24.16.0`, `25.9.0`
(https://nodejs.org/dist/index.json).
- `pnpm install --frozen-lockfile`
- `pnpm --filter @e2e-tests/utils typecheck`
- `pnpm --filter @e2e-tests/utils exec tsc --noEmit --target es2022
--module esnext --moduleResolution bundler --types bun
--resolveJsonModule --skipLibCheck --strict scripts/docker-build.ts`
- `bash -n ts/scripts/pre-install.sh && bun run
ts/scripts/pre-install/check-toolchain.ts && BYPASS_TOOLCHAIN_CHECK=1
bash ts/scripts/pre-install.sh`
- `pnpm exec prettier --check ...` on touched YAML/Markdown/TS/JSON
files
- `ruby -e "require \"yaml\"; ARGV.each { |f| YAML.load_file(f) }" ...`
on touched actions/workflows
- `mise lock --platform linux-x64,linux-arm64,macos-arm64,macos-x64 &&
git diff --exit-code mise.lock`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/utils typecheck`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/node-esm-basic
typecheck`
- `mise exec node@22.22.3 -- pnpm --filter @e2e-tests/node-cjs-basic
typecheck`
- `docker manifest inspect node:24.16.0-slim`
- `docker manifest inspect node:25.9.0-slim`
- `git diff --check`
This PR is **part 2 of 3** splitting
https://github.com/ComposioHQ/composio/pull/3505 to make the removal of
the old 2025 custom tools easier to review. It carries the
**TypeScript** slice.
- builds on top of https://github.com/ComposioHQ/composio/pull/3508
(stacked — review/merge the Python slice first; this PR's base is
`remove-py-custom-tools`)
- removes the legacy `composio.tools.createCustomTool(...)` in-memory
registry: the plural `CustomTools` model, registry wiring, legacy-only
tests/examples/`ts/docs` pages, and stale error/type exports
- preserves the 2026 tool-router APIs: `experimental_createTool`,
`experimental_createToolkit`, `ToolRouter`, `ToolRouterSession`, and
inline custom-tool execution
- regenerates the TypeScript SDK reference so raw tool listing no longer
describes the removed local registry and points to session-scoped custom
tools
- adds a `@composio/core` minor changeset
## Notes
- The committed SDK reference is **verified self-consistent**: `pnpm
--filter @composio/core generate:docs` reproduces it with zero diff.
- This slice is a byte-identical subset of #3505 — the three split
branches recombine to that PR's exact tree. See #3505 for the original
verification logs (`typecheck`, `test`, `lint`, `cf-workers` e2e); CI
re-runs per PR.
## Summary
Automatic tool file upload/download for `file_uploadable` fields is
**off by default** in TypeScript and Python. Callers must explicitly opt
in, and uploads from local paths are constrained by a fail-closed
allowlist.
## Changes
- **Removed (breaking):** `autoUploadDownloadFiles` (TS) /
`auto_upload_download_files` (Python) — the legacy default-on flag is
gone, not just deprecated.
- **New opt-in:** `dangerouslyAllowAutoUploadDownloadFiles` (TS) /
`dangerously_allow_auto_upload_download_files` (Python). When `true`,
`tools.get(...)` collapses `file_uploadable` schemas to `{ type:
'string', format: 'path' }` and the SDK stages local paths/URLs at
execute time.
- **New:** `fileUploadDirs?: string[] | false` — fail-closed allowlist
for local upload paths. `undefined` → `[<home>/.composio/temp]`; `false`
→ reject all local paths (URLs / `File` objects unaffected); explicit
`string[]` replaces the default. Components are matched on a path
boundary after `realpath`.
- **New:** `fileDownloadDir?: string` — directory where
`file_downloadable` results are staged.
- **New:** `beforeFileUpload` hook receives `source: 'path' | 'url' |
'file'` (TS) / `'path' | 'url'` (Python) so it can branch on input type.
- **New (TS):** when auto-upload is **off** and an LLM-driven
`tools.execute` is called against a tool with `file_uploadable` inputs,
the SDK emits a one-shot warning per tool slug pointing at
`composio.files.upload()` for manual staging.
## Migration
To restore previous behavior:
```ts
new Composio({
apiKey: process.env.COMPOSIO_API_KEY!,
dangerouslyAllowAutoUploadDownloadFiles: true,
// Optional: tighten the allowlist beyond the default ~/.composio/temp
fileUploadDirs: ['/srv/uploads'],
});
```
```python
Composio(api_key="...", dangerously_allow_auto_upload_download_files=True)
```
If you previously passed the legacy flag, remove it. There is no
transitional warning — TS and Python both reject the unknown property at
the type/keyword-arg level.
## Versioning
| Package | Bump |
| ------- | ---- |
| `@composio/core` | minor |
| `composio` (Python) | minor |
| Other `@composio/*` packages | patch (via changesets
`updateInternalDependencies: "patch"`) |
See
`docs/content/changelog/04-24-26-legacy-auto-upload-config-removal.mdx`
for the full migration writeup.
This PR:
- fixes the stale beta version expectation in `upgrade-binary.test.ts`
(\`0.2.18\` → \`0.2.19\`) that broke the "selects the latest prerelease"
test
- replaces live \`composio generate ts\` call in the
\`typescript-mjs-import-nodenext\` e2e suite with checked-in fixture
files, removing the \`COMPOSIO_API_KEY\` dependency
- adds \`mock-toolkits-server.ts\` — a deterministic mock HTTP server
for \`/api/v3/toolkits\` and \`/api/v3/toolkits/:slug\` endpoints
- migrates \`toolkits/list\`, \`toolkits/info\`, and \`toolkits/search\`
CLI e2e suites from live API calls to the mock server, removing the
\`COMPOSIO_USER_API_KEY\` requirement
- adds \`--add-host host.docker.internal:host-gateway\` to Docker e2e
runner so CLI containers can reach host-side mock servers
- closes
[PLEN-2012](https://linear.app/composio/issue/PLEN-2012/cli-fix-cli-e2e-tests)
All three failures are pre-existing on \`next\` — this PR makes CI green
again.
## Testing
```bash
pnpm --dir ts/packages/cli exec vitest run test/src/services/upgrade-binary.test.ts
pnpm typecheck
pnpm --dir ts/e2e-tests/_utils typecheck
pnpm --filter @e2e-tests/cli-toolkits-info typecheck
pnpm --filter @e2e-tests/cli-toolkits-list typecheck
pnpm --filter @e2e-tests/cli-toolkits-search typecheck
```
> **Stack:** 1/2 — followed by #3099 (org switch limit display feature)
---------
Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com>
Co-authored-by: Rahul Tarak <cryogenicplanet@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- replace runtime MCP SDK path resolution with static imports in the
structured-output helper
- ensure the helper works when shipped next to the standalone CLI binary
without repo-local node_modules
## Verification
- pnpm --filter @composio/cli run typecheck:src
- pnpm --filter @composio/cli test
test/src/services/run-subagent-acp.test.ts
- built and executed the bundled helper from a temp directory outside
the repo
## Summary
- Moved developer-oriented CLI commands from `manage` to the `dev`
namespace.
- Updated command registrations, help text, hints, and examples across
auth configs, connected accounts, toolkits, triggers, logs, tools, orgs,
and projects.
- Removed the old `manage` entrypoint and adjusted command routing and
error guidance to match the new structure.
- Updated the affected CLI tests to reflect the new command paths.
## Testing
- Not run (not requested).
- Updated command test snapshots/expectations in the CLI test suite to
match the renamed namespace.
- Verified help text and inline hints were rewritten from `composio
manage ...` to `composio dev ...` in the touched commands.
The download call can 404 immediately after upload due to API eventual
consistency. Add the same retry pattern already used for list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The E2E test for TypeScript .mjs import resolution was still using
the old `composio ts generate` command which no longer exists as a
top-level command after the generate restructure.
## Summary
Introduces a `composio manage` namespace that groups resource management
commands (toolkits, tools, auth-configs, connected-accounts, triggers,
logs, orgs, projects) under a single parent command. This declutters the
top-level CLI help and creates a clearer separation between everyday
commands (`init`, `login`, `generate`) and advanced resource management.
## Changes
- Created `manage/manage.cmd.ts` with all resource subcommands
registered under `composio manage`
- Removed individual top-level imports (toolkits, tools, auth-configs,
etc.) from `index.ts` and replaced with single `manageCmd` import
- Updated alias mapping (`ALIAS_TO_PARENT`) to route through `manage`
(e.g., `search` → `manage tools`, `link` → `manage connected-accounts`)
- Updated `parseExecuteInputHelpSlug` to account for the new `manage`
prefix in argv parsing
- Consolidated the root help advanced commands section to show a single
`manage` entry
## Type of change
- [x] Refactor/Chore
## How Has This Been Tested?
- Verified CLI help output displays correctly with the new `manage`
namespace
- Tested that aliases (`composio search`, `composio execute`, `composio
link`, `composio listen`) still resolve correctly through the `manage`
prefix
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [x] I updated documentation as needed
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com>
- Add session.customTools({ toolkit? }) and session.customToolkits() methods
returning registered tools with final slugs, schemas, and resolved toolkit
- Early slug length validation in createCustomTool (standalone + extension)
and createCustomToolkit (per tool), with buildCustomToolsMap as safety net
- Reject COMPOSIO_ prefix in CustomToolSlugSchema (prevents meta tool shadowing)
- Rename execute fn param from session → ctx everywhere (type def, docs, examples, tests)
- SessionContextImpl as singleton on ToolRouterSession (created once in constructor)
- Rename internal byPrefixed/byOriginal → byFinalSlug/byOriginalSlug
- Store resolved toolkit on map entries for session.customTools() lookups
- Add RegisteredCustomTool and RegisteredCustomToolkit types to Session interface
- JSDoc on extendsToolkit: must be a valid Composio toolkit slug
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove @composio/core/experimental as primary import path. Users import
experimental_createTool and experimental_createToolkit from @composio/core.
The /experimental sub-path re-exports with the same names for backward compat.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add WEATHER_CHAIN tool: local tool calls remote WEATHERMAP_WEATHER via
SessionContext.execute() — proves mixed local+remote in same session
- Add Zod validation failure test (wrong type → error, no crash)
- Add non-existent tool test (backend 400 → catchable error)
- Add STRICT_TOOL with z.number() schema for validation testing
- Switch from hackernews to weathermap toolkit (simpler, active connection)
- 12 test cases total, all passing against production API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove sessionId from public SessionContext interface (keep private in impl)
- Sort multi-execute merge: remote results first, local last (preserves remote file indexes)
- Add multi-execute test for non-prefixed local slug handling
- Tighten local_tools payload type from unknown to LocalToolDefinition[]
- Deduplicate test helpers (createSessionWithProvider/captureExecuteFn hoisted to top-level)
- Add E2E test suite for custom tools (Docker-based, hackernews no-auth toolkit)
- Fix JSDoc example: proxyExecute → session.execute()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The e2e tests run against a cached Docker image tagged by CLI version.
The image is only rebuilt on version bumps, so the ui.output('[]')
source change isn't reflected until the next release. Revert the e2e
assertion to match the currently built binary's behavior.
The source code change (outputting [] on no results) is correct and
will be verified after the next Docker image rebuild.
Replace inline magic numbers in formatToolkitsTable with a TOOLKITS_TABLE
constant, matching the convention used in logs-cmd/format.ts and
triggers/format.ts. Also adds truncation to name/slug/version columns.
The `toolkits list` command had two separate code paths producing
different JSON schemas depending on whether a user_id was resolved
(session format vs legacy format). This caused e2e test failures when
the test environment had a test_user_id configured, silently switching
to the session format which lacked catalog fields like latest_version.
Consolidate into a single path: always fetch from the catalog API
(which provides tools_count, triggers_count, latest_version), then
optionally enrich with session connection data when a user_id is
available. The output schema is now stable regardless of context.
Replace bare JSON.parse(sanitizeOutput(result.stdout)) with the new
parseJsonStdout helper so that CLI errors (e.g. 401) produce clear
messages instead of cryptic 'SyntaxError: JSON Parse error: Unexpected EOF'.
When the CLI errors out, stdout is empty and JSON.parse("") throws a
cryptic SyntaxError. The new helper surfaces the actual exit code and
stderr so the root cause is immediately visible in test output.
Thread `const F` through the runCmd overload so TypeScript infers
precise file keys from the `files` array literal, eliminating the
need for `?? ''` fallbacks when accessing captured file contents.
Extend the e2e test infrastructure to support CLI runtime tests alongside
Node.js and Deno. Add a Dockerfile.cli that builds the composio binary
and runs it in a scratch Debian container. Include the first CLI e2e test
for `composio version` with file capture support.
When Turbo runs 9 Node.js e2e test packages concurrently, each one
independently calls ensureNodeImage() which triggers a Docker build.
Nine concurrent builds saturate the CI runner (2 CPUs, 7GB RAM),
causing Docker container execution to time out at TIMEOUTS.FIXTURE.
Fix by pre-building the Docker image once in the CI workflow before
Turbo spawns the test packages. Also bump TIMEOUTS.FIXTURE from 60s
to 120s as a safety net for slow Docker operations under load.
Concurrent e2e test suites building the same Docker image can race,
causing "already exists" errors. Now ensureNodeImage/ensureDenoImage
gracefully handle this by rechecking image availability on failure.
Also bump openai-zod4-compat beforeAll timeout from 60s to 300s since
npm install inside Docker can exceed the FIXTURE timeout in CI.
bun:test's default beforeAll timeout is effectively unlimited for hooks,
not 5s as assumed. 15s was insufficient for Docker container startup in
CI, causing all fixture-based tests to time out. Bump to 60s.
Add FIXTURE: 15_000 timeout constant for beforeAll hooks that call
runFixture(). Bump LLM_SHORT from 15_000 to 30_000 for more headroom
on LLM calls. Apply TIMEOUTS.FIXTURE to all fixture-using beforeAll
hooks that previously relied on the implicit 5s bun:test default.
Remove the deprecated `nodeVersions` property from E2EConfig in favor of
the unified `versions.node` API. This completes the migration to the
multi-runtime API that supports both Node.js and Deno.
- Remove `nodeVersions` property from E2EConfig interface
- Remove legacy handling in `normalizeVersionConfig()`
- Update all 9 Node.js test files to use `versions: { node: [...] }`
- Update README.md and JSDoc documentation