This PR:
- follows up https://github.com/ComposioHQ/composio/pull/3943, replacing
its hardcoded message with a fix for the cause it worked around
- stops `install.sh` redirecting `composio install`'s stderr to a temp
file — that redirect is what silenced the command, since the CLI gates
every log, note and outro on stderr being a terminal, so the captured
file was always empty and the replay printed nothing
- probes `"$exe" --version` before delegating, so a binary that cannot
run still falls back to inline setup without spilling loader errors —
the reason the redirect existed in the first place
- makes `composio install` fall back to plain `ui.error` lines when
there is nothing to decorate, so container and CI installs that pipe the
session to a build log still get the report; interactive output is
unchanged. `canDecorate` is constant for a run, so each channel binds to
its decorated or plain form once rather than re-testing per message
- drops the unconditional "Composio was added to your PATH" line, which
printed on three paths where nothing was written: shell-not-detected and
unsafe-install-dir (both exit 0 after reporting manual setup), and the
inline fallback's unsupported-shell and unwritable-rc branches
- adds regression tests using the production `makeTerminalUI`
implementation with captured streams, so the real decoration gate is
exercised — the shared test double reports `canDecorate: false` but
prints everything anyway, which is why this went unnoticed through two
prior attempts
## Context
Measured against the released binary, `composio install` writes 0 bytes
when its stderr is not a terminal, and exits 0 without touching any rc
file when `$SHELL` is unset. Both were invisible to the installer:
| case | exit | stderr bytes | PATH block written |
| --- | --- | --- | --- |
| `2>file`, as `install.sh` did | 0 | 0 | yes |
| `$SHELL` unset | 0 | 0 | no |
| stderr on a terminal | 0 | full report | yes |
With the redirect gone, the delegated path prints what the user was
missing — `Updated ~/.zshrc` and `Restart your shell to apply changes` /
`source ~/.zshrc` — and the manual-setup text on the paths where PATH
genuinely was not touched. The closing block no longer needs a PATH
claim of its own, and the fallback keeps printing its own
`refresh_command`.
067c67b695 already tried to surface this
output by capturing it to a temp file and replaying it on success. That
replay has been a no-op for the same reason, so this guidance has never
reached a user since the delegation was introduced.
## How Has This Been Tested?
- new tests fail with `expected '' to contain 'PATH: will add'` (empty
output — the production bug) without the `install.cmd.ts` change, and
pass with it
- full CLI suite: 957 passed, 1 skipped; `pnpm typecheck` 14/14;
`validate:boundaries`, eslint and prettier clean, no new eslint disables
- released binary in a sandboxed `$HOME`: stderr to a file yields 0
bytes; stderr on a pty yields the full report
- CLI from source with stderr captured: 155 bytes of plain guidance
where it previously wrote nothing; decorated output on a terminal
unchanged
- `install.sh` driven through a harness built from the real script under
a pty: a working binary's stderr reaches the terminal, a broken binary's
loader noise stays suppressed and the fallback writes the PATH block and
prints `source ~/.zshrc`. The same harness against `next` shows the
swallow.
No changeset: `@composio/cli` is Changesets-ignored and `install.sh` is
not a published package. The CLI note went into `CHANGELOG.md` directly.
`install.sh` is served from `next`, so the installer half of this
reaches new installs on merge and works with already-released binaries.
The `install.cmd.ts` half only affects captured-stderr installs and
rides the next CLI release.
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>
The CLI's PATH-setup output is swallowed by the installer's stderr
capture, so first-time users were never told the PATH change only takes
effect in a new shell — they ran `composio --help` in the same terminal,
got "command not found", and concluded the install had failed to set up
PATH. State it explicitly in the closing message.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review follow-ups.
- install.sh ran `login --agent` without an origin marker while its `install`
and `setup` invocations both set one, so installer-driven agent logins were
indistinguishable from manual ones — the exact ambiguity this PR removes for
the other two.
- Hoist the release channel to a module constant; both inputs are constants, so
recomputing it per event was pointless.
- The changelog overstated the gap: a Homebrew user running `composio install`
by hand still emits install events, they just carry no installer origin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every CLI event now carries journey_stage (install|setup|login|connect|
execute|other) via an exhaustive event->stage map in events.ts, and
cli_channel (stable|beta) derived from the existing
inferSkillReleaseChannel(APP_VERSION). Both are applied by a single
buildEvent factory so no builder hand-writes them.
install.sh now sets COMPOSIO_CLI_INVOCATION_ORIGIN=installer on its
"$exe" install run (matching the setup run), so script installs are
distinguishable from a user manually running `composio install`.
npm and Homebrew installs never run install.sh, so the install stage
only covers install.sh installs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-lands 4e68e652 (reverted by 333d2296) and extends it:
Part 1 (re-land):
- Dedicated CLI_INSTALL_* / CLI_SETUP_* lifecycle families; 'setup' added
to KNOWN_COMMAND_TOKENS so it is no longer misattributed to
command_path='composio'
- Per-host CLI_PLUGIN_SETUP_SUCCEEDED / CLI_PLUGIN_UNINSTALL_SUCCEEDED
fired from installSetupTargets/uninstallSetupTargets
- install.sh auto-setup runs with COMPOSIO_CLI_INVOCATION_ORIGIN=installer
Part 2 (extensions, fired from inside setup.cmd.ts / setup.ts):
- CLI_SETUP_HOST_DETECTED per host after detection, with agent_host,
available, supported, host_version and normalized unsupported_reason_code
(codex_too_old | no_json_inspection | host_command_failed | unknown)
threaded through SetupTargetDetection
- CLI_PLUGIN_SETUP_FAILED per host (phase install|uninstall) tapped before
the existing mapError rethrow
- CLI_SETUP_CANCELLED (user declined confirm) and CLI_SETUP_SKIPPED
(--if-present with no supported host)
- stdout_is_tty added to the setup command properties
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
## Summary
- Resolve the default CLI install version from GitHub Releases instead
of git tags.
- Require the selected CLI release to include the current platform
archive asset and fall back to older stable CLI releases when the newest
release is missing that asset.
- Add a mocked install.sh regression test covering missing release
assets, ignored beta/provider releases, and tag-only versions with no
release.
## Tests
- `bash -n install.sh test/install-sh-release-resolution.test.sh`
- `pnpm run test:install-sh`
- `git diff --check`
- Parsed `.github/workflows/cli.test-installation.yml` with Ruby YAML
- Parsed `package.json` with Node JSON.parse
- Manual real install smoke test with temporary
HOME/COMPOSIO_INSTALL_DIR selected `@composio/cli@0.2.28`
## Notes
- This prevents the install health check from selecting tag-only
versions like `@composio/cli@0.2.29` when no GitHub release/asset exists
yet.
## Summary
- make `install.sh` choose the latest stable `@composio/cli@x.y.z` tag
by default instead of prerelease beta tags
- add a clearer `--agent` setup failure message for users already signed
in as a regular Composio user
## Tests
- `bash -n install.sh`
- verified the release-tag selection pipeline resolves
`@composio/cli@0.2.28` instead of `@composio/cli@0.2.28-beta.223`
## Summary
- add `composio signup`, `composio login --agent`, and `composio agent
signup` flows backed by agents.composio.dev
- make signup messaging explicit that `composio signup` creates/signs
into a Composio agent and that the flow is non-interactive
- add `composio agent login <composio_agent_key>` for restoring an
existing agent when the key was saved
- add `composio agent whoami`, `claim`, and JSON-only `inbox` commands
using the stored `~/.composio/agent.json` agent identity
- guard agent flows so a regular human CLI login cannot run `composio
agent ...` or overwrite itself with agent signup without logging out
first
- show expected agent-auth issues as a softer warning with next steps
instead of the global crash-style error panel
- warn and confirm before agent logout removes `~/.composio/agent.json`
/ `composio_agent_key`; `logout --force` skips the prompt
- update `install.sh --agent` to sign up/log in as an agent after
install
## Tests
- `pnpm --filter @composio/cli build`
- `pnpm --filter @composio/cli test --
test/src/commands/agent.cmd.test.ts`
- `pnpm --filter @composio/cli test --
test/src/commands/agent.cmd.test.ts test/src/commands/logout.cmd.test.ts
test/src/commands/login.cmd.test.ts`
- `pnpm lint` (passes with existing warnings only)
## CI
- GitHub checks are rerunning on the latest push.
## 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
- Hardened `composio run` subagent execution to preserve structured
output and recover more reliably when the primary prompt result is
malformed.
- Added a dedicated MCP helper for structured output so helper runs can
write results through a file-backed path instead of relying only on
stderr/stdout parsing.
- Propagated run log and artifact paths through helper context so
subagent logs land in the run log file consistently.
- Skipped zsh completion installation in `install.sh` and the CLI
installer to avoid broken completion wiring for zsh users.
- Refreshed the CLI lockfile and bundled the new MCP runtime dependency
into the CLI package.
## Testing
- `Not run`
## Summary
This changes `composio run` so an installed binary can recover missing
`run-subagent-*.mjs` companion modules at runtime instead of failing
immediately.
## What changed
- add run-time companion repair in `composio run`
- persist the installed release tag so `run` can fetch the matching
release asset when repair is needed
- update binary upgrade flow to keep that release metadata current
- add CLI coverage for companion install metadata and missing companion
detection
- include a patch changeset for `@composio/cli`
## Root cause
`composio run` launches a child Bun process that imports helper modules
from disk. If the installed binary was missing the companion `.mjs`
files, the command failed with `Cannot find module ...
run-subagent-shared.mjs` before any user code ran.
## Impact
- future CLI binaries with this change can self-heal missing companion
modules during `composio run`
- install and upgrade flows now record the release tag needed for
deterministic repair
- already-shipped older binaries still need one reinstall to get this
repair logic
## Validation
- `pnpm --filter @composio/cli test -- run.cmd.test.ts`
- `pnpm --filter @composio/cli run build:binary`
- verified a binary-only temp install containing just `composio` plus
`release-tag.txt`; `composio run 'console.log("healed")'` restored the
three companion modules and executed successfully
## What changed
- make `build:binary:cross` emit the `run-subagent-*.mjs` companion
modules alongside the compiled CLI binary
- update the `Build CLI Binaries` workflow to include those companion
modules in the published release archives
- make `install.sh` copy companion modules when they are present, while
remaining backward compatible with older archives that only contain
`composio`
- fix the CLI installation workflow assertions to match the actual
installer behavior and paths
## Why
`composio run` launches a separate Bun runtime that imports the
`run-subagent-*` helpers from disk. The main binary alone is not
sufficient. The previous release workflow zipped only the `composio`
binary, so prerelease assets installed successfully but failed at
runtime with missing-module errors.
The installation test workflow also had stale expectations for
`~/.composio/bin/composio` and `COMPOSIO_INSTALL`, which caused false
negatives even when installation itself succeeded.
## Impact
- newly built CLI release assets will contain the files required for
`composio run`
- `install.sh` will install sidecars for new releases and ignore them
for older releases
- the installation workflow will validate the real install layout
instead of the stale `bin/` path
## Validation
- `pnpm --filter @composio/cli run build:binary:cross --target
bun-darwin-arm64` from the existing checkout emitted:
- `dist/binaries/composio-darwin-aarch64`
- `dist/binaries/companions/run-subagent-shared.mjs`
- `dist/binaries/companions/run-subagent-acp.mjs`
- `dist/binaries/companions/run-subagent-legacy.mjs`
- simulated the GitHub Actions archive step and verified the zip
contains `composio` plus all three companion modules
- earlier local binary/package validation on the main fix branch
confirmed the extracted binary runs `composio run
'console.log("hello")'` successfully once those files are packaged
The install script accepts COMPOSIO_GITHUB_URL, COMPOSIO_GITHUB_OWNER,
and COMPOSIO_GITHUB_REPO from the environment to construct the download
URL. A malicious override could redirect the download to an attacker-
controlled server, bypassing checksum verification (since checksums.txt
is fetched from the same source).
Fix:
- Require COMPOSIO_GITHUB_URL to start with https://
- Require COMPOSIO_GITHUB_OWNER and COMPOSIO_GITHUB_REPO to match
safe identifier patterns (alphanumeric, hyphens, underscores, dots)
The install command writes COMPOSIO_INSTALL_DIR into shell rc files
(.zshrc, .bashrc, config.fish). Previously the value was unquoted,
allowing shell metacharacters (;, `, $, |, etc.) to inject arbitrary
commands that execute every time the user opens a terminal.
Fix:
- Quote the install directory value in all path blocks (bash, zsh, fish)
- Add isUnsafePath validation that rejects paths with metacharacters
- Quote the value in the manual setup note for unknown shells
- Quote the fish and zsh fallback paths in install.sh
- Add test for unsafe path rejection
- Replace 2>/dev/null with a temp file capture so the CLI's TerminalUI
output (written to stderr) is shown when the command succeeds, but
suppressed on failure to avoid noise.
- Move the "To get started" guidance block outside the if/else so it
always displays regardless of which code path ran.
grep -qF does substring matching, so the PATH marker "# Composio CLI"
would falsely match "# Composio CLI completions". Switch to grep -qxF
to require full-line matches, consistent with the TS fileContains logic.
- Add cross-compilation scripts (build-binary-cross.ts, build-all-binaries.ts)
using Bun's --target flag, enabling all platforms to build from ubuntu-latest
- Add package-binaries.ts and generate-checksums.ts for release artifact preparation
- Restructure CI workflow into build + release jobs; release job aggregates
artifacts and generates checksums.txt
- Simplify install.sh: use git ls-remote refspec filter for version detection,
add SHA-256 checksum verification with graceful fallback, use mktemp/trap
for temp file cleanup, remove dead musl detection code
- Add checksum verification to composio upgrade command via fetchChecksums
and verifyChecksum helpers in upgrade-binary.ts