Skip to content

Commit 1cc2ec6

Browse files
fix: decouple skill build scripts from @composio/core (#3133)
## Summary - Skill build/validate scripts were failing in CI because they transitively imported `@composio/core` via `src/constants.ts`, which isn't built when the binary release workflow runs. - Extracts `CLI_EXPERIMENTAL_FEATURES` (and `CLI_RELEASE_CHANNELS`/`CliReleaseChannel`) into a standalone `src/experimental-features.ts` with zero external dependencies. - Adds `MULTI_ACCOUNT` experimental feature flag that gates `--account` on execute/listen and `--alias` on link. When disabled (default on stable), these flags are silently ignored and hidden from help. Beta builds enable them by default. - Skill builder now includes `--account`/`--alias` documentation only in beta channel builds. ## Test plan - [x] `pnpm run validate:skills` passes - [x] `pnpm turbo typecheck --filter=@composio/cli` passes - [x] Binary build and runtime verified - [x] Stable help hides `--account`/`--alias` flags - [x] Beta skill output includes multi-account flags, stable does not - [ ] CI `Build CLI Binaries` workflow should now pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c465415 commit 1cc2ec6

File tree

8 files changed

+93
-18
lines changed

8 files changed

+93
-18
lines changed

ts/packages/cli/skills-src/composio-cli/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from 'node:fs';
22
import * as path from 'node:path';
3-
import { CLI_EXPERIMENTAL_FEATURES } from '../../src/constants';
3+
import { CLI_EXPERIMENTAL_FEATURES } from '../../src/experimental-features';
44
import { composioDevReference } from './references/composio-dev';
55
import { powerUserExamplesReference } from './references/power-user-examples';
66
import { troubleshootingReference } from './references/troubleshooting';
@@ -72,6 +72,12 @@ const commands: SkillCommand[] = [
7272
name: '`--parallel`',
7373
description: 'Execute multiple independent tool calls in the same invocation.',
7474
},
75+
{
76+
name: '`--account`',
77+
description:
78+
'Select which connected account to use by alias, word_id, or account id when multiple accounts exist for the same toolkit.',
79+
features: [CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT],
80+
},
7581
],
7682
examples: [
7783
{
@@ -125,6 +131,14 @@ const commands: SkillCommand[] = [
125131
code: 'composio link gmail\ncomposio link googlecalendar --no-browser',
126132
},
127133
],
134+
flags: [
135+
{
136+
name: '`--alias`',
137+
description:
138+
'Assign an alias to the connected account. Required when creating an additional account for the same toolkit.',
139+
features: [CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT],
140+
},
141+
],
128142
notes: ['Retry the original `execute` command after linking succeeds.'],
129143
},
130144
{
@@ -152,6 +166,11 @@ const commands: SkillCommand[] = [
152166
name: '`--timeout` and `--max-events`',
153167
description: 'Stop long-running listeners cleanly.',
154168
},
169+
{
170+
name: '`--account`',
171+
description: 'Select which connected account to use by alias, word_id, or account id.',
172+
features: [CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT],
173+
},
155174
],
156175
notes: [
157176
'`composio artifacts cwd` shows the current artifact root when saved payloads need inspection.',

ts/packages/cli/skills-src/composio-cli/reference-schema.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CLI_EXPERIMENTAL_FEATURES, type CliReleaseChannel } from '../../src/constants';
1+
import { CLI_EXPERIMENTAL_FEATURES, type CliReleaseChannel } from '../../src/experimental-features';
22

33
export type SkillReleaseChannel = CliReleaseChannel;
44

@@ -51,6 +51,7 @@ export const resolveSkillBuildContext = (channel: SkillReleaseChannel): SkillBui
5151
channel,
5252
experimentalFeatures: {
5353
[CLI_EXPERIMENTAL_FEATURES.LISTEN]: channel === 'beta',
54+
[CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT]: channel === 'beta',
5455
},
5556
});
5657

ts/packages/cli/src/commands/connected-accounts/commands/connected-accounts.link.cmd.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
groupCachedConnectedAccountsByToolkit,
2424
resolveDefaultConnectedAccountsByToolkit,
2525
} from 'src/services/connected-account-selection';
26+
import { ComposioCliUserConfig } from 'src/services/cli-user-config';
27+
import { CLI_EXPERIMENTAL_FEATURES } from 'src/constants';
2628

2729
const toolkit = Args.text({ name: 'toolkit' }).pipe(
2830
Args.withDescription('Toolkit slug to link (e.g. "github", "gmail")'),
@@ -619,6 +621,13 @@ const runConnectedAccountsLink = (params: {
619621
Effect.gen(function* () {
620622
if (!(yield* requireAuth)) return;
621623

624+
const cliConfig = yield* ComposioCliUserConfig;
625+
const aliasOption = cliConfig.isExperimentalFeatureEnabled(
626+
CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT
627+
)
628+
? params.alias
629+
: Option.none<string>();
630+
622631
const ui = yield* TerminalUI;
623632
const clientSingleton = yield* ComposioClientSingleton;
624633
const projectContext = yield* ProjectContext;
@@ -675,7 +684,7 @@ const runConnectedAccountsLink = (params: {
675684
requestedUserId: params.userId,
676685
projectName: params.projectName,
677686
noWait: params.noWait,
678-
alias: params.alias,
687+
alias: aliasOption,
679688
ui,
680689
clientSingleton,
681690
projectContext,
@@ -758,7 +767,7 @@ const runConnectedAccountsLink = (params: {
758767
const { connectedAccountId: connAccountId, redirectUrl } = validatedLink.value;
759768
const canContinue = yield* ensureAliasForAdditionalAccount({
760769
ui,
761-
alias: params.alias,
770+
alias: aliasOption,
762771
connectedAccountId: connAccountId,
763772
existingAccounts,
764773
scopeDescription: `user "${resolvedUserId.value}" in toolkit "${toolkitSlug}"`,
@@ -769,7 +778,7 @@ const runConnectedAccountsLink = (params: {
769778
ui,
770779
client,
771780
connectedAccountId: connAccountId,
772-
alias: params.alias,
781+
alias: aliasOption,
773782
});
774783

775784
if (params.noWait) {

ts/packages/cli/src/commands/listen.cmd.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
} from 'src/services/connected-account-selection';
2323
import { parseJsonIsh } from 'src/utils/parse-json-ish';
2424
import { toolkitFromToolSlug } from 'src/utils/toolkit-from-tool-slug';
25+
import { ComposioCliUserConfig } from 'src/services/cli-user-config';
26+
import { CLI_EXPERIMENTAL_FEATURES } from 'src/constants';
2527
import { matchesTriggerListenFilters } from './triggers/filter';
2628
import { parseTriggerListenEvent } from './triggers/parse';
2729

@@ -396,6 +398,12 @@ export const listenCmd = Command.make(
396398
orgId: resolvedProject.orgId,
397399
projectId: resolvedProject.projectId,
398400
});
401+
const cliConfig = yield* ComposioCliUserConfig;
402+
const accountSelector = cliConfig.isExperimentalFeatureEnabled(
403+
CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT
404+
)
405+
? account
406+
: Option.none<string>();
399407
const {
400408
listeningToProjectEvent,
401409
createParams,
@@ -410,7 +418,7 @@ export const listenCmd = Command.make(
410418
timeout,
411419
stream,
412420
maxEvents,
413-
account,
421+
account: accountSelector,
414422
client,
415423
resolvedProject,
416424
});

ts/packages/cli/src/commands/tools/commands/tools.execute.cmd.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ import {
6060
normalizeCliError,
6161
} from 'src/services/composio-error-overrides';
6262
import * as constants from 'src/constants';
63+
import { ComposioCliUserConfig } from 'src/services/cli-user-config';
64+
import { CLI_EXPERIMENTAL_FEATURES } from 'src/constants';
6365

6466
const slug = Args.text({ name: 'slug' }).pipe(
6567
Args.withDescription('Tool slug (e.g. "GITHUB_CREATE_ISSUE")')
@@ -1009,12 +1011,18 @@ const resolveExecuteContext = (params: RunToolsExecuteParams) =>
10091011
orgId: resolvedProject.orgId,
10101012
projectId: resolvedProject.projectId,
10111013
});
1014+
const cliConfig = yield* ComposioCliUserConfig;
1015+
const accountSelector = cliConfig.isExperimentalFeatureEnabled(
1016+
CLI_EXPERIMENTAL_FEATURES.MULTI_ACCOUNT
1017+
)
1018+
? params.account
1019+
: Option.none<string>();
10121020
const toolkitSlug = toolkitFromToolSlug(params.slug);
10131021
const selectedConnectedAccountId = yield* resolveExplicitConnectedAccount({
10141022
client,
10151023
toolkitSlug,
10161024
userId: resolvedUserId.value,
1017-
selector: params.account,
1025+
selector: accountSelector,
10181026
});
10191027
const args = Option.isSome(params.file)
10201028
? yield* getOrFetchToolInputDefinition(params.slug, {

ts/packages/cli/src/constants.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,8 @@ export const GITHUB_REPO = {
8686
API_BASE_URL: 'https://api.github.com',
8787
} as const;
8888

89-
export const CLI_EXPERIMENTAL_FEATURES = {
90-
LISTEN: 'listen',
91-
} as const;
92-
93-
export const CLI_RELEASE_CHANNELS = ['stable', 'beta'] as const;
94-
95-
export type CliReleaseChannel = (typeof CLI_RELEASE_CHANNELS)[number];
89+
export {
90+
CLI_EXPERIMENTAL_FEATURES,
91+
CLI_RELEASE_CHANNELS,
92+
type CliReleaseChannel,
93+
} from './experimental-features';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Map of experimental feature flags used to gate CLI commands and skill output.
3+
*
4+
* Extracted into its own module so that the skill build/validate scripts
5+
* (`skills-src/`) can import it without pulling in `@composio/core` (which
6+
* requires a prior build step).
7+
*/
8+
export const CLI_EXPERIMENTAL_FEATURES = {
9+
LISTEN: 'listen',
10+
MULTI_ACCOUNT: 'multi_account',
11+
} as const;
12+
13+
export const CLI_RELEASE_CHANNELS = ['stable', 'beta'] as const;
14+
15+
export type CliReleaseChannel = (typeof CLI_RELEASE_CHANNELS)[number];

ts/packages/cli/test/__utils__/services/test-layer.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Layer,
1212
Logger,
1313
LogLevel,
14+
Option,
1415
Schedule,
1516
String,
1617
} from 'effect';
@@ -39,7 +40,8 @@ import type { TriggerInstanceItem } from 'src/models/triggers';
3940
import type { AuthConfigCreateResponse, LinkCreateResponse } from 'src/services/composio-clients';
4041
import type { ToolkitVersionSpec } from 'src/effects/toolkit-version-overrides';
4142
import { ComposioUserContextLive } from 'src/services/user-context';
42-
import { ComposioCliUserConfigLive } from 'src/services/cli-user-config';
43+
import { ComposioCliUserConfig } from 'src/services/cli-user-config';
44+
import { CliUserConfig } from 'src/models/cli-user-config';
4345
import { UpgradeBinary } from 'src/services/upgrade-binary';
4446
import { NodeOs } from 'src/services/node-os';
4547
import { TriggersRealtime } from 'src/services/triggers-realtime';
@@ -800,9 +802,24 @@ export const TestLayer = (input?: TestLiveInput) =>
800802
Layer.merge(BunFileSystem.layer, NodeOsTest)
801803
);
802804

803-
const ComposioCliUserConfigTest = Layer.provideMerge(
804-
ComposioCliUserConfigLive,
805-
Layer.mergeAll(BunFileSystem.layer, NodeOsTest)
805+
const ComposioCliUserConfigTest = Layer.succeed(
806+
ComposioCliUserConfig,
807+
ComposioCliUserConfig.of({
808+
data: {
809+
channel: 'beta',
810+
experimentalFeatures: {},
811+
artifactDirectory: undefined,
812+
experimentalSubagentTarget: 'auto',
813+
},
814+
raw: CliUserConfig.make({
815+
experimentalFeatures: {},
816+
artifactDirectory: Option.none(),
817+
experimentalSubagent: Option.none(),
818+
}),
819+
channel: 'beta',
820+
isExperimentalFeatureEnabled: () => true,
821+
update: () => Effect.void,
822+
})
806823
);
807824

808825
const UpgradeBinaryTest = Layer.provide(

0 commit comments

Comments
 (0)