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>
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.
# Description
Adds a `pnpm.overrides` entry pinning `protobufjs` to **7.5.5** to patch
a critical RCE flagged by Socket.dev:
| Socket alert | CVE | GHSA | Severity | Patched in |
|---|---|---|---|---|
| `SOCKET-COMPOSIO-1686` | `CVE-2026-41242` |
[`GHSA-xq3m-2v4x-88gg`](https://github.com/advisories/GHSA-xq3m-2v4x-88gg)
| Critical | `protobufjs@7.5.5` |
### Why an override
`protobufjs@7.5.4` is pulled in transitively by `@google/genai` (via
`google-auth-library`) — there are no direct imports of `protobufjs` in
`ts/packages/`. The cleanest, minimal-risk fix is a `pnpm.overrides`
pin: 7.5.4 -> 7.5.5 is a patch-only release containing the RCE fix.
This is the same override pattern hermes uses for its security-pinned
deps.
# How did I test this PR
- `BYPASS_BUN_VERSION_CHECK=1 pnpm install --lockfile-only` regenerated
`pnpm-lock.yaml`. Both `protobufjs@7.5.4` references now resolve to
`7.5.5`.
- `grep -rn "from ['\"]protobufjs" ts/packages/` confirms zero direct
imports — pure lockfile change.
- Relying on CI for lint / typecheck / unit-test coverage on the
lockfile bump.
---
Origin: cron-f7c85f82906b /
[zen-cron-6352a6575b74](https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-cron-6352a6575b74)
Triggered by: saransh@composio.dev | Source: Socket.dev Vulnerability
Auto-Fix
Session:
https://zen-api-production-4c98.up.railway.app/dashboard/#/chat/zen-cron-6352a6575b74
Aligns the TypeScript SDK with the experimental wire shape used by
Shared Connections. The flat accountType / aclConfigForShared options
on connectedAccounts.link() and session.authorize() have moved under a
single experimental block, and connectedAccounts.updateAcl() has moved
off the class onto a top-level experimental_updateAcl(composio, id, opts)
export — same precedent as experimental_createTool /
experimental_createToolkit.
The experimental namespace is the signal that the shape may change in
future releases. Pinning a SHARED connection in a session config and
direct execute by connectedAccountId are unchanged — only the
connection-create / patch / authorize surfaces are namespaced.
Also surfaces the accountType filter on connectedAccounts.list() so
SHARED connections can be listed without dropping to the raw client.
The wire keeps this as a flat query param, so the SDK keeps it flat too.
@composio/client bumped from 0.1.0-alpha.71 -> 0.1.0-alpha.72 so the
generated typed client carries the Experimental namespaces for
link.create, toolRouter.session.link, and connectedAccounts.patch.
Caller migration:
// before
await composio.connectedAccounts.link('user_id', 'auth_config_id', {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
});
await composio.connectedAccounts.updateAcl('ca_abc', { allowAllUsers: true });
await session.authorize('github', {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
});
// after
await composio.connectedAccounts.link('user_id', 'auth_config_id', {
experimental: {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
},
});
await experimental_updateAcl(composio, 'ca_abc', { allowAllUsers: true });
await session.authorize('github', {
experimental: {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
},
});
// new — list SHARED connections
const shared = await composio.connectedAccounts.list({
accountType: 'SHARED',
userIds: ['user_creator'],
});
Tests cover: experimental block forwarding (link + authorize), no-op
when omitted, empty-array preservation, typed error mapping for the
PRIVATE-with-ACL case, experimental_updateAcl body construction +
deny-list handling + ValidationError when no fields are provided, and
list(accountType: 'SHARED') flat-filter delegation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Now that #77 in composio-base-ts merged and @composio/client@0.1.0-alpha.71 is
published with account_type + acl_config_for_shared in the typed surface,
all the forward-compat shims come out.
Removed:
- AclConfigWireShape, LinkCreateBodyWithAcl, ConnectedAccountPatchBodyWithAcl
local types
- 3x `as unknown as Parameters<typeof X>[N]` casts in ConnectedAccounts.ts +
ToolRouterSession.ts
Now uses the generated types directly:
- ConnectedAccountPatchParams, ConnectedAccountPatchResponse from
@composio/client/resources/connected-accounts
- LinkCreateParams + LinkCreateParams.ACLConfigForShared from
@composio/client/resources/link
- SessionLinkParams + SessionLinkParams.ACLConfigForShared from
@composio/client/resources/tool-router/session/session
Review fixes from #3392 multi-agent review:
- P1-1: moved orphaned JSDoc back onto ComposioLegacyConnectedAccountsEndpoint-
RetiredError (was stranded above ComposioSharedAccessDeniedError)
- P1-2: added empty-array footgun warning to updateAcl() JSDoc — passing
`notAllowedUserIds: []` silently clears the deny list
- P1-3: changeset reconciled with PR body (Python ships as separate PR)
- P2-9: updateAcl() returns ConnectedAccountPatchResponse instead of void,
matching sibling update()/refresh() ergonomics
- P2-11: clarifying JSDoc on update() pointing at updateAcl() and noting the
pre-existing "alias/credentials" doc is inaccurate (this PR doesn't fix it)
- P3-12: callbackUrl/alias guards normalized to `!== undefined` (was a mix
of `&&` and `!= null`) — empty strings now propagate correctly
- P3-17: refine-guard comment on UpdateConnectedAccountAclParamsSchema noting
ZodEffects doesn't expose .shape
P2-6/P2-7: typed error mapping for ComposioAclOnlyForSharedError (400)
wired at three call sites:
- ConnectedAccounts.link() — wraps existing
ComposioFailedToCreateConnectedAccountLink catch
- ConnectedAccounts.updateAcl() — new catch with rethrow fallback
- ToolRouterSession.authorize() — new catch with rethrow fallback
Substring match on `'acl_config_for_shared is only valid on SHARED'` —
verified against apps/apollo/src/lib/connected_accounts/createConnectedAccount.ts
in hermes#9902. ComposioSharedAccessDeniedError and
ComposioSharedConnectionNotAccessibleError remain exported but not yet
thrown — they'll be wrapped when Tools.execute() and ToolRouterSession.create()
error-mapping lands in a follow-up.
Tests: 12 new behaviour tests in test/connectedAccounts/connectedAccounts.test.ts
covering link() ACL forwarding (5), updateAcl() body construction + empty-object
refine + AclOnlyForShared mapping (6), and link() error-mapping fallback (1).
911 tests pass (up from 899).
Verified: pnpm typecheck clean, pnpm build clean (publint + attw clean).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- bump generated TS client to @composio/client 0.1.0-alpha.69 and Python
client to composio-client 1.36.0
- page through ToolRouter session tools in TS/Python using the generated
v3.1 cursor response
- accept generated connected account status REVOKED and fail connection
waits immediately for terminal states
## Validation
- pnpm --filter @composio/core typecheck
- pnpm --filter @composio/core test -- test/tools/tools.test.ts
test/models/toolRouter.test.ts
test/connectedAccounts/connectedAccounts.test.ts
test/connectedAccounts/connectionRequest.test.ts
- uv run --frozen ruff check python/composio/core/models/tools.py
python/tests/test_tool_execution.py
- uv run --frozen pytest
python/tests/test_tool_execution.py::TestToolExecution::test_get_raw_tool_router_meta_tools_fetches_all_pages
python/tests/test_tool_router.py
Note: pnpm install --frozen-lockfile hits the repo preinstall Bun guard
locally because this machine has Bun 1.2.10 and the branch expects
1.3.10; dependency sync was completed with --ignore-scripts for local
verification.
## Summary
Composio tools whose JSON Schema uses internal `$ref` pointers
(`#/$defs/...` or the legacy `#/definitions/...`) used to lose all type
information when wrapped by `MastraProvider.wrapTool`. The schema would
silently round-trip `raw → applyCompatLayer → convertSchemaToZod (drops
$ref → permissive anyOf) → zodToJsonSchema (no recovery)`. Customers
reported the user-visible surface as *"schema validation error: can't
resolve reference"* — AJV (bundled inside `@mastra/schema-compat`)
refusing to compile the schema downstream when validating tool input.
This PR pre-processes the schema with a new `dereferenceJsonSchema`
utility from `@composio/core` *before* it reaches
`@mastra/schema-compat`, preserving the type information from
`$defs`/`definitions` and avoiding the AJV failure entirely.
Closes
[PLEN-2244](https://linear.app/composio/issue/PLEN-2244/mastra-provider-schema-validation-error-cant-resolve-reference).
## What changed
- **`@composio/core`** — new `dereferenceJsonSchema(schema)` helper (and
`JsonSchemaRefResolutionError`):
- walks the schema reflectively (no JSON-Schema-keyword allow-list, so
future applicators are covered automatically),
- inlines internal `$ref` pointers transitively, with a 100-hop depth
cap,
- shallow-merges sibling keywords next to `$ref` per Draft 2020-12
semantics (siblings win on collision — preserves caller's `description`
/ `default` / `title`),
- breaks recursive cycles with `{ type: 'object', additionalProperties:
true }` (matches upstream guidance in
[mastra-ai/mastra#15341](https://github.com/mastra-ai/mastra/issues/15341)),
- strips `$defs` / `definitions` from the returned root once everything
reachable is inlined,
- leaves external (`http://`/`https://`) `$ref` pointers untouched so
callers can still forward them,
- throws `JsonSchemaRefResolutionError` on malformed pointers, missing
targets, and over-cap chains.
- **`@composio/mastra`** — `wrapTool` now runs `dereferenceJsonSchema`
over both `inputParameters` and `outputParameters` before calling
`applyCompatLayer`.
- **`@mastra/schema-compat`** floor bumped to `^1.2.9` so consumers
automatically pick up upstream [PR
#15400](https://github.com/mastra-ai/mastra/pull/15400)'s
recursive-`$ref` handling and [PR
#14530](https://github.com/mastra-ai/mastra/pull/14530)'s Draft-2020-12
AJV switch.
- Changeset: `.changeset/fix-mastra-ref-dereference.md` (patch bump for
`@composio/core` and `@composio/mastra`).
## Test plan
Red → green TDD across two commits — the `test:` commit reproduces
PLEN-2244 against the real `@mastra/schema-compat` (no `vi.mock`), the
`fix:` commit makes the regression tests pass.
- [x] `ts/packages/core/test/utils/jsonSchema.test.ts` — 14 unit tests
for `dereferenceJsonSchema` covering: basic resolution, chained refs,
container coverage (items / oneOf / anyOf / allOf / not /
additionalProperties / patternProperties / prefixItems), legacy
`definitions` (Draft 7), `$defs`/`definitions` mixed transitively,
sibling-keyword merge per Draft 2020-12, cycle break,
`$defs`/`definitions` strip, missing-target error, depth-cap error,
external `$ref` preserved, no input mutation, JSON Pointer escape
decoding (`~0`/`~1`), array-index pointers.
- [x] `ts/packages/providers/mastra/test/mastra-ref.test.ts` — un-mocked
integration tests against real `@mastra/schema-compat`: wrapping does
not throw, type info from `$defs` survives the round-trip (the `id`
field stays `type: 'string'` instead of degrading to permissive
`anyOf`), same for Draft-7 `definitions` on output schema, no remaining
`$ref` in the produced schemas.
- [x] `pnpm --filter @composio/core test` — 852/852 green.
- [x] `pnpm --filter @composio/mastra test` — 43/43 green (39 legacy + 4
new).
- [x] `pnpm --filter @composio/core --filter @composio/mastra typecheck`
— clean.
- [x] Existing `mastra.test.ts` (which mocks `@mastra/schema-compat`) is
**untouched** and still green.
- [x] Secret-hygiene scan: `git diff next..HEAD | grep -E
'sk-[A-Za-z0-9_-]{20,}|OPENAI_API_KEY=[A-Za-z]'` returns empty.
## Why it's a Mastra-only fix
The Mastra path is unique in routing JSON Schema through
`@mastra/schema-compat`, which embeds AJV. Sibling providers (`openai`,
`anthropic`, `vercel`, `langchain`, `google`, `llamaindex`) forward
Composio's JSON Schema through `@composio/json-schema-to-zod`, which
silently no-ops on unknown nodes. They are not affected today; expanding
pre-processing across providers is a separate PR if it ever becomes
needed.
## Caveats
- The cycle-break sentinel weakens type information for genuinely
recursive tool schemas. This is the same trade-off Mastra itself made in
[#15341](https://github.com/mastra-ai/mastra/issues/15341); without it
the agent crashes entirely.
- External `$ref` (`http://`/`https://`) is intentionally left
untouched. If a real customer schema ever needs them resolved, that's an
incremental follow-up that calls into
`@apidevtools/json-schema-ref-parser` only when needed.
- The cycle-break currently uses a single sentinel for any cycle; if
review prefers the higher-fidelity "keep first expansion, only break on
the recursion edge" pattern (mentioned in the research as a refinement),
that's a small follow-up.
## Summary
- Broaden the Beeper iMessage macOS build patch so BetterSwiftAX
`kAX...` constants compile on GitHub `macos-15`/`macos-15-intel`.
- Pin the fixed `platform-imessage` submodule source and add Swift 6.2 /
Peekaboo dependency patching for the CLI binary workflow.
- Package and verify macOS local-tool sidecars plus `release-tag.txt` in
CLI release zips.
- Fix installed beta metadata/upgrade behavior so `--version`, update
checks, and beta-default experimental flags use the installed release
tag.
- Let `LOCAL_*` execution bypass remote auth/project/schema validation.
- Add runtime self-heal for missing installed `local-tools-binaries`: if
an old upgrader installs the fixed beta binary without sidecars, first
local-tool execution downloads the matching release zip, verifies
checksum when available, and restores the sidecars.
## Validation
- `pnpm --filter @composio/cli-local-tools build:beeper-imessage --
--target darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:beeper-imessage --
--target darwin-x64`
- `pnpm --filter @composio/cli-local-tools build:peekaboo -- --target
darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:peekaboo -- --target
darwin-x64`
- `pnpm --filter @composio/cli-local-tools typecheck:tsc`
- `pnpm --filter @composio/cli-local-tools test`
- `pnpm --filter @composio/cli typecheck:tsc`
- `pnpm --filter @composio/cli build:binary`
- Targeted CLI tests for execute/config/upgrade/version/update-check
paths.
- Packaged binary smoke test confirmed bundled Beeper sidecar works.
- Repair smoke test: copied only the new `composio` binary plus
`release-tag.txt` into a temp install with no `local-tools-binaries`;
`execute LOCAL_BEEPER_IMESSAGE_VERSION -d '{}'` restored sidecars from
`@composio/cli@0.2.29-beta.235` and succeeded.
## Release workflow
- Beta build run `25405049712` succeeded for commit
`9d0910c909b7b257d0f17b6d082980952d1e6c59` and published
`@composio/cli@0.2.29-beta.235`.
- This PR now includes one follow-up commit (`2c32cff4c`) to cover the
old-upgrader/missing-sidecars incremental upgrade path; normal branch CI
and beta build run `25406984535` are running again.
## Summary
- Add experimental CLI local tools behind `local_tools` (beta-on,
stable-off unless `composio config experimental local_tools on`).
- Add reusable `@composio/cli-local-tools` package: declarations,
metadata, readiness, command/MCP/native/FFI runtimes, bundled-binary
resolution, and Tool Router search/execute/schema integration.
- Add first-class local toolkits for:
- `BEEPER_IMESSAGE` backed by `imessage-cli` from the ComposioHQ
`platform-imessage` fork.
- `CHROME_DEVTOOLS` backed by the official `chrome-devtools-mcp@0.24.0`
npm/npx package.
- `PEEKABOO` backed by upstream Peekaboo CLI.
- Remove generated native executables from git: Beeper and Peekaboo
binaries are now ignored, pinned via git submodules, and generated
during CLI binary release jobs.
- Update CLI binary workflow so Linux artifacts skip native sidecars,
while macOS artifacts run on macOS runners and build only the matching
`darwin-x64` or `darwin-arm64` Beeper/Peekaboo sidecars before
packaging.
## Native binary policy
- No generated `imessage-cli` or `peekaboo` binary blobs are committed
in this PR history.
- Beeper source is pinned as
`ts/packages/cli-local-tools/vendor/platform-imessage` at
`364445a1b3089ad9fe293d5951efe160c5677c42` from
`https://github.com/ComposioHQ/platform-imessage`.
- Peekaboo source is pinned as
`ts/packages/cli-local-tools/vendor/peekaboo` at
`31e66e8d02656141d18f60bf3b46b24c2b9bc785` from
`https://github.com/steipete/Peekaboo`.
- Build commands:
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-x64`
- Chrome DevTools is an npm/npx integration and is pinned as a dev
dependency (`chrome-devtools-mcp@0.24.0`) instead of using native
sidecars.
## Validation
- `pnpm --filter @composio/cli-local-tools build:local-tool-binaries --
--target darwin-arm64`
- `pnpm --filter @composio/cli-local-tools build:peekaboo -- --target
darwin-x64`
- `pnpm --filter @composio/cli-local-tools build:beeper-imessage --
--target darwin-x64`
- `pnpm --filter @composio/cli-local-tools typecheck:tsc`
- `pnpm --filter @composio/cli-local-tools test`
- `COMPOSIO_REAL_LOCAL_TOOLS_TESTS=1 pnpm --filter
@composio/cli-local-tools test -- src/toolkits/beeper-imessage.test.ts
src/toolkits/peekaboo.test.ts`
- `pnpm --filter @composio/cli typecheck:tsc`
- `pnpm --filter @composio/cli build`
- `COMPOSIO_CACHE_DIR=<tmp-config-with-local_tools-enabled> bun
ts/packages/cli/dist/bin.mjs local-tools doctor --json`
- `pnpm turbo build`
- Verified rewritten branch has no >1MB objects relative to
`origin/next` and no native executable paths in the PR diff.
## Notes / risks
- Beeper iMessage and Peekaboo are macOS-only and depend on local
permissions.
- Peekaboo requires macOS 15+; GUI tools require Screen Recording,
Accessibility, and sometimes Automation.
- Beeper send/reaction behavior can still depend on upstream Messages
automation reliability.
- Chrome DevTools can inspect/modify browser contents; avoid sensitive
browser sessions.
Composio tools whose JSON Schema uses internal `$ref` pointers (`#/$defs/...`
or the legacy `#/definitions/...`) used to lose all type information when
wrapped by `MastraProvider.wrapTool`. The schema went through:
raw JSON Schema (with $ref) → applyCompatLayer
→ convertSchemaToZod (silently drops $ref, becomes a permissive anyOf)
→ zodToJsonSchema (no way to recover the lost types)
Customers reported this surface as "schema validation error: can't resolve
reference" — AJV (bundled inside @mastra/schema-compat) refusing to compile
the schema downstream when validating tool input.
Fix: pre-process the schema with a new `dereferenceJsonSchema` helper before
handing it to `applyCompatLayer`. The helper:
- walks the schema reflectively (no JSON-Schema-keyword allow-list, so future
applicators are covered automatically),
- inlines internal `$ref` pointers transitively, with a 100-hop depth cap,
- shallow-merges sibling keywords next to `$ref` per Draft 2020-12 semantics
(siblings win on collision — preserves caller's `description`/`default`),
- breaks cycles with `{ type: 'object', additionalProperties: true }`,
matching upstream guidance in mastra-ai/mastra#15341,
- strips `$defs`/`definitions` from the returned root once everything
reachable is inlined,
- leaves external (`http://`/`https://`) `$ref` pointers untouched,
- throws `JsonSchemaRefResolutionError` on malformed pointers, missing
targets, or chains over the cap.
Bumps the `@mastra/schema-compat` dependency floor to `^1.2.9` so users also
pick up upstream PR #15400's recursive-`$ref` handling.
The new red regression tests (committed in 5300bf8ba) now pass.
Expose `workbench.sandboxSize` (TypeScript) / `workbench.sandbox_size`
(Python) on `ToolRouter.create()` so callers can pick the workbench
sandbox compute tier (`standard`, `medium`, `large`, `xlarge`).
Optional; the server defaults to `standard` (1 vCPU / 1 GB) when
omitted, so existing callers keep current behavior.
- Bump stainless clients to pick up the field on the wire:
- `@composio/client` 0.1.0-alpha.66 -> 0.1.0-alpha.67
- `composio-client` 1.33.0 -> 1.34.0
- TS: extend `ToolRouterCreateSessionConfigSchema.workbench` with
`sandboxSize` and forward it as snake_case `sandbox_size`. Export
`SandboxSize` type and `SandboxSizeSchema` zod enum.
- Python: extend `ToolRouterWorkbenchConfig` TypedDict with
`sandbox_size` and forward it on the create payload. Export
`SandboxSize` literal alias.
- Changeset: `@composio/core` patch.
- Tests: cover the snake_case forwarding and zod enum rejection.
Docs (Configuring Sessions / Workbench / changelog) are split into a
separate PR so they can land alongside the SDK release.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
## Summary
- Wire `@composio/cli-keyring` into `ComposioUserContext` so the API key
lives in the macOS Keychain / Linux Secret Service instead of plaintext
`~/.composio/user_data.json`
- **Read precedence**: env var (`COMPOSIO_USER_API_KEY`) > OS keyring >
legacy plaintext
- **One-shot migration**: on first run after upgrade, if the keyring is
empty but `user_data.json` has an `api_key`, copy it to the keyring and
strip it from JSON
- **In-process memoization**: keyring read happens once at layer build
(~1.4ms), held in closure for the rest of the process
- **`dangerouslySaveApiKeyInUserConfig`**: opt-in escape hatch in
`~/.composio/config.json` for headless Linux / containers / CI where the
keyring is unavailable
- **`ctx.data` is now a getter**: fixes a pre-existing bug where
mutations via `login()`/`update()` were invisible through the stale
snapshot
- **In-memory mock keyring** for test isolation — tests never touch the
real keychain
## Files changed
| file | what |
|---|---|
| `ts/packages/cli/package.json` | Add `@composio/cli-keyring` workspace
dep |
| `ts/packages/cli/src/models/cli-user-config.ts` |
`dangerously_save_api_key_in_user_config` schema field |
| `ts/packages/cli/src/services/cli-user-config.ts` | Surface new field
on `CliUserConfigResolved` |
| `ts/packages/cli/src/services/user-context.ts` | Keyring-first
read/write/migrate/fallback chain |
| `ts/packages/cli/src/cli-main.ts` | Wire `KeyringLive` into layer
composition |
| `ts/packages/cli-keyring/src/stores/macos-security-ffi.ts` | Fix:
writes via subprocess `-A`, cleanup dead ACL builder code, add base64
encoding |
| `ts/packages/cli/test/__utils__/services/test-layer.ts` | In-memory
mock keyring for test isolation |
| `ts/packages/cli/test/src/commands/login.cmd.test.ts` | Update
assertion: api_key no longer in JSON after login |
## Verified end-to-end
```
$ ./dist/composio version
INFO: Composio API key migrated from user_data.json to the OS keyring
0.2.22
$ cat ~/.composio/user_data.json # no api_key
{"base_url":"...","web_url":"...","org_id":"...","test_user_id":"..."}
$ # Rebuild binary (new hash) → read from keychain → no dialog
$ ./dist/composio whoami
{"email":"rahul@composio.dev",...}
```
## Test plan
- [x] 676 CLI tests passing (676 passed, 1 skipped)
- [x] Login test updated: asserts `api_key` absent from JSON + present
via `ctx.data.apiKey`
- [x] In-memory mock keyring — no real keychain access in tests
- [x] Binary build + FFI roundtrip verified
- [x] Rebuild with new hash → no keychain dialog (allow-any ACL via
`-A`)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
**Stack: 2/2** — base PR: `cli/keyring-package` (#3201)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bump @composio/client to 0.1.0-alpha.66 (TS) and composio-client to 1.33.0 (Python)
- Use SDK types directly: ConnectedAccountPatchResponse, SessionCreateParams.MultiAccount
- Move alias into connection param for initiate() (now in SDK's ConnectedAccountCreateParams.Connection)
- Simplify link(), authorize() methods — remove inline type casts, use SDK params directly
- Remove custom UpdateConnectedAccountResponse Zod schema (replaced by SDK type)
- Update tests for new alias location in create params
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Zen Agent <zen@composio.dev>
Previous lockfile was corrupted by local pnpm 9.5.0 — missing overrides
section and wrong pnpmfileChecksum. Regenerated with pnpm 10.28.0
(matching CI's packageManager version).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Bump @composio/client to 0.1.0-alpha.63 (adds connectedAccounts.patch)
- Replace raw client.patch() cast with typed client.connectedAccounts.patch()
- Keep minimal casts for alias on create/link (not yet in client types)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Zen Agent <zen@composio.dev>
## Summary
- Add `tsgo`-based `typecheck` scripts and matching `typecheck:tsc`
fallback scripts across the TypeScript packages.
- Wire the new `typecheck:tsc` task into Turbo so package-level
typecheck checks can run consistently.
- Update workspace and lockfile metadata to include
`@typescript/native-preview` and the new toolchain wiring.
- Remove redundant `baseUrl` settings from package tsconfig files where
they are no longer needed.
## Testing
- Not run (changes are limited to package scripts, tsconfig wiring, and
lockfile updates).
- Not run: `pnpm typecheck:tsc`
- Not run: `pnpm build`
- Not run: package-specific `typecheck` / `typecheck:tsc` commands in
`ts/packages/cli`, `ts/packages/core`, `ts/packages/json-schema-to-zod`,
and `ts/packages/providers/mastra`.
## Summary
- bundle the shipped `composio run` companion services with direct
`Bun.build(..., target: "bun")` output instead of reusing the shared
`dist` graph
- rebuild the Claude ACP support files as Bun-bundled runtime assets and
invalidate the cached adapter layout so stale raw files are not reused
- add runtime validation for shipped support files, wire the MCP helper
through the workspace `@composio/json-schema-to-zod` package, and cover
the static-import expectation in tests
## Why
Standalone binaries were still relying on external runtime dependencies
from companion support files. On a clean machine this surfaced as
failures like `Cannot find package 'decompress'` from the generated
companion modules. The fix is to make every shipped support file
self-contained for Bun and package exactly that tree into the binary
archives.
## Validation
- `pnpm run typecheck`
- `pnpm exec vitest run
test/src/services/run-subagent-output-mcp.test.ts
test/src/services/run-subagent-acp.test.ts`
- `pnpm run build:binary:all`
- `pnpm run build:binary:package`
- unpacked `dist/binaries/composio-darwin-aarch64.zip` and verified
`experimental_subAgent(..., { target: "codex", schema: ... })`
- unpacked `dist/binaries/composio-darwin-aarch64.zip` and verified
`experimental_subAgent(..., { target: "claude", schema: ... })`
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- harden `composio run` sub-agent structured output by adding an
MCP-backed `submit_structured_output` tool, permissive ACP approval, and
a repair turn when the agent answers with prose
- route all `run` helper logs into the per-run `artifacts/run.log`,
print `RUN_LOG_FILE=...` before execution starts, and include
`logFilePath` on `subAgent()` responses
- keep the run artifact directory and `~/.composio` accessible to
sub-agents and cover the new behavior with focused CLI/ACP tests
## Verification
- `pnpm --filter @composio/cli typecheck:src`
- `pnpm --filter @composio/cli test test/src/commands/run.cmd.test.ts
test/src/services/run-subagent-acp.test.ts`
- `pnpm --filter @composio/cli exec tsdown --config-loader unrun`
- `pnpm --filter @composio/cli run build:binary`
- manual `./ts/packages/cli/dist/composio run ...` checks against both
`target: "claude"` and `target: "codex"`
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- Adds a new ACP execution path for `subAgent()` in the CLI `run`
command, with fallback to the legacy CLI-based implementation when ACP
is unavailable.
- Introduces shared subagent helpers plus separate ACP and legacy
service modules to keep the invocation logic isolated.
- Adds `--acp-only` to force ACP usage and fail instead of falling back.
- Updates binary build output so the CLI ships the companion modules
needed by the `run` command in both source and compiled forms.
- Bumps CLI dependencies to include ACP packages used by the new
execution path.
## Testing
- `pnpm test ts/packages/cli/test/src/commands/run.cmd.test.ts`
- `pnpm test ts/packages/cli/test/src/services/run-subagent-acp.test.ts`
- Not run: full repository build or end-to-end CLI validation.
## Summary
- Adds a new `composio proxy` command plus `run`/consumer flow updates
to make local execution and debugging easier.
- Improves CLI UX across root help, command hints, input validation, and
hidden debug handling.
- Introduces experimental custom tools and toolkits support in the
TypeScript SDK, with docs and examples.
- Refreshes release metadata, changelog, and related docs for the new
CLI and SDK behavior.
- Updates tests and snapshots to cover the new command flows and
validation paths.
## Testing
- Not run (changes reviewed from diff and existing test coverage updated
in the branch).
- Updated/added CLI tests for `proxy`, `run`, `tools.execute`,
`tools.info`, `tools.list`, `tools.search`, and related command flows.
- Updated snapshot coverage for root help and command output changes.
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
This PR continues the consumer CLI work by making the top-level workflow
more coherent around `search`, `link`, `tools`, `execute`, and `run`,
while moving developer-oriented workflows under a dedicated `dev`
namespace.
The main theme is to make the CLI easier for an agent or user to use
directly:
- discover tools semantically with `search`
- inspect toolkit-specific tools with `tools`
- try `execute` earlier, with fast schema-aware failure messages
- use `run` for programmatic multi-step flows without dropping into bash
- keep developer/project scaffolding under `dev`
## What Changed
### Consumer command UX
- added top-level `run` for inline Bun ESNext TS/JS or file execution
- added injected global helpers inside `run`
- `execute(slug, data?)`
- `search(query, options?)`
- updated root help text to better explain the intended flow and
encourage trying `execute` early
- clarified `search` as semantic search across toolkits/apps
- moved `tools list` and `tools info` to top level
- made `tools list` explicitly per-toolkit and non-semantic
- updated `tools info` to give a short summary plus a cached schema
reference instead of dumping raw detail
- cleaned up stale help/hints that still referenced removed command
paths
### New `dev` namespace
- introduced `composio dev ...` for developer/project workflows
- moved developer-focused flows under `dev`, including:
- local init
- playground-user execution
- trigger listening
- logs
- updated help copy so `manage` no longer claims to own `tools` or
`logs`
- reframed `dev` as the place for local scaffolding and project-building
workflows
### Execute improvements
- added schema-aware validation for `execute`
- cached tool definitions under `~/.composio/tool_definitions/`
- stored resolved version metadata with cached schemas
- added version freshness checks and stale-cache refresh behavior
- added a 12-hour version-check window to avoid refetching every
invocation
- invalidated stale cache entries when execution failures indicate the
schema may no longer be trustworthy
- improved validation errors to point at the cached schema file and give
more actionable guidance
- added `--get-schema` to fetch/cache the schema and print a compact
inspection hint
- added `--dry-run` to validate/preview execute calls without running
the remote action
- allowed `-d/--data` to accept JSON, JS-style object literals, `@file`,
or stdin
- added large-output handling that spills very large tool responses to
`/tmp/composio/...` and returns a file reference
### `run` improvements
- defaulted `run` to inline code, with `-f/--file` for file mode
- clarified in help that `run` uses Bun ESNext TS/JS, not Node/CJS
assumptions
- documented the injected helpers and when to use them
- made `run --dry-run` forward preview behavior through injected
`execute(...)`
- wired `run` to reuse consumer auth state and resolved consumer user
context for helper calls
- added AST-aware execute prewarming so static `execute("TOOL", ...)`
calls can prime schema/cache work
### Hint graph and debug tooling
- centralized command hints/examples in a shared registry
- added linked command relationships so hints can be maintained as a
graph instead of scattered hardcoded strings
- added support for variant nodes such as `root.execute.getSchema`
- added a hidden graph dump path for local iteration:
- `composio debug generate-graph`
- hid local-only debug controls from help output while keeping them
usable:
- `--perf-debug`
- `--tool-debug`
### Internal cleanup
- updated many runtime hints to point at current commands instead of
removed paths
- aligned login/whoami/project/toolkit/log output hints with the new
command structure
- refreshed tests and snapshots for the new top-level layout and command
descriptions
## Verification
Ran:
- `pnpm --dir ts/packages/cli build:binary`
- `pnpm --dir ts/packages/cli typecheck`
- `./ts/packages/cli/dist/composio --help`
## Notes
This PR is intentionally focused on the CLI flow and help/hint surface.
It sets up a cleaner split between consumer-facing actions and
developer/project workflows, while also making `execute` and `run` much
more usable for agents.
- Bump @composio/client to 0.1.0-alpha.62 (adds proxyExecute, custom tool types)
- Replace hand-rolled CustomToolDefinition/CustomToolkitDefinition with
SessionCreateParams.Experimental.CustomTool/CustomToolkit from client
- Type experimentalPayload as SessionCreateParams['experimental'] instead
of Record<string, unknown>
- Replace raw .post() hack in SessionContext/ToolRouterSession proxyExecute
with official client.toolRouter.session.proxyExecute()
- proxyParamsTransform now returns official ClientProxyExecuteParams type
- Add ToolRouterSessionProxyExecuteResponse (status, data, headers, binaryData)
matching ToolProxyResponse from client — consistent with tools.proxyExecute()
- Build CustomToolsMap from API response slug/original_slug mapping instead
of computing LOCAL_ prefix client-side
- Add custom-tools.ts example showing standalone, extension (with proxyExecute),
and toolkit tools with OpenAI Agents
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The lockfile was regenerated by pnpm 9.5.0 which stripped the overrides
section, causing CI failures. Restored from next and manually added the
custom-tools workspace entry.
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>
Add `composio triggers listen` with realtime channel auth, filtering, raw JSON output, and optional webhook forwarding/output file sinks so trigger events can be inspected and integrated locally with signed verification headers.
Co-authored-by: Cursor <cursoragent@cursor.com>
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.
- Disable check_broken_links.yml (fern-specific)
- Update claude-code-doc-review.yml to use new docs/ path
- Remove fern from pnpm-workspace.yaml
- Regenerate pnpm-lock.yaml without fern workspaces
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>