Skip to content

feat(cli): introduce sdk commands - #106

Merged
bespoyasov merged 13 commits into
mainfrom
feat/sdk-commands
Oct 6, 2026
Merged

bespoyasov merged 13 commits into
mainfrom
feat/sdk-commands

Conversation

@bespoyasov

@bespoyasov bespoyasov commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Add confidence sdk install — detects the project framework and installs the matching Confidence SDK package (auto-runs the package manager for JS/Python/Go, prints manual instructions for Kotlin/Java/Swift)
  • Add confidence sdk setup — verifies plugin + MCP + auth prerequisites, then launches an AI chat session to configure the SDK in the project
  • Refactor ChatOpts to use userPrompt + systemPrompt instead of a single prompt — fixes Claude Code sessions launching without an initial user message
  • Follows existing CLI patterns: safely wrapper, ora spinners, shared --dir option hoisted to parent, --ide and --profile scoped to setup

Design notes

  • buildInstallCommand uses a switch with exhaustive checking (satisfies never) so new frameworks added to core will cause a compile error until handled
  • Package manager detection (npm/pnpm/yarn/bun) is based on lockfile presence in the target directory
  • sdk setup delegates to the IDE integration's launchChat rather than the quickstart TUI, since SDK setup is an AI-assisted flow
  • ChatOpts.userPrompt is passed as a positional arg to claude (user message), while systemPrompt uses --append-system-prompt; for Cursor/Codex both are concatenated into the single positional prompt

@bespoyasov
bespoyasov marked this pull request as ready for review October 6, 2026 09:13

@filipmyllari filipmyllari left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review notes (AI-assisted). Inline comments below, plus one that doesn't map to a single diff line:

  • Behaviour change — migrate (features/migrate/launch.ts + claude/chat.ts): the migration prompt used to go to Claude via --append-system-prompt and now goes as the positional user prompt, so confidence migrate starts the agent on its own straight away instead of waiting for the user's first message. That's probably intended, but it isn't mentioned in the PR description, and the quickstart path still uses systemPrompt. Please confirm both flows behave as expected.

case 'nextjs':
case 'node': {
const pm = detectProjectPM(dir);
return { type: 'auto', cmd: pm, args: ['add', fw.sdkPackage] };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pnpm add fails with ERR_PNPM_ADDING_TO_ROOT when dir is a pnpm workspace root, and yarn add behaves the same way in Yarn workspaces. Running confidence sdk install at the root of a monorepo will therefore fail. Either detect pnpm-workspace.yaml / workspaces and add -w, or tell the user to run the command from the package directory.

return { type: 'auto', cmd: pm, args: ['add', fw.sdkPackage] };
}
case 'python':
return { type: 'auto', cmd: 'pip', args: ['install', fw.sdkPackage] };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bare pip install targets whatever pip is first on PATH. If no venv is active, it fails under PEP 668 (externally-managed environment) or installs into the global environment. It also ignores poetry, uv and pipenv projects. Consider detecting pyproject.toml/poetry.lock/uv.lock and using python -m pip, or making Python a manual install.

` )`,
};
default: {
const _exhaustive: never = fw.id as never;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FrameworkConfig.id is typed as string, so the as never cast makes this exhaustiveness check do nothing. A new framework added to core will compile without errors and then throw Unknown framework at runtime. Type id as a union of the known IDs (or FrameworkId) and drop the cast.

}

export async function runSdkInstall(argv: Record<string, unknown>): Promise<void> {
const dir = (argv.dir as string | undefined) ?? process.cwd();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads argv.dir directly, while setup goes through resolveProjectDir(argv). That makes the two subcommands handle --dir differently (setup respects profile/flag resolution and resolves to an absolute path, install doesn't). Use resolveProjectDir here too.

` Maven:\n` +
` <dependency>\n` +
` <groupId>com.spotify.confidence</groupId>\n` +
` <artifactId>openfeature-provider</artifactId>\n` +

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Maven snippet hardcodes groupId/artifactId rather than deriving them from fw.sdkPackage, and it uses VERSION where the other snippets use <version>. It will drift if sdkPackage changes. Split fw.sdkPackage on :.

Comment thread packages/cli/src/features/sdk/setup.ts Outdated
import { resolveAuthToken } from '@features/mcp/index.js';

const SDK_SETUP_PROMPT = `Set up the Confidence SDK in this project.
Use the "analyze-project" skill from the Confidence plugin to determine the correct SDK, install it, and create a working configuration file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

analyze-project is the skill that proposes feature flag changes, which contradicts the next line ("Only set up the SDK"). The agent may still run its flag-proposal steps. Consider a dedicated SDK-setup skill, or point to getCodeSnippetAndSdkIntegrationTips from confidence-docs instead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to use getCodeSnippetAndSdkIntegrationTips instead; should be up-to-date and much smaller in token size than analyze-project skill

return {
type: 'manual',
snippet:
`Add the following to your app/build.gradle.kts:\n\n` +

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: this assumes the module is app/. Say "your module's build.gradle.kts" instead.

@bespoyasov

Copy link
Copy Markdown
Collaborator Author

Behaviour change — migrate (features/migrate/launch.ts + claude/chat.ts): the migration prompt used to go to Claude via --append-system-prompt and now goes as the positional user prompt, so confidence migrate starts the agent on its own straight away instead of waiting for the user's first message. That's probably intended, but it isn't mentioned in the PR description, and the quickstart path still uses systemPrompt. Please confirm both flows behave as expected.

Yup, in quickstart we offer to “chat about the made changes,” so the user will want to ask something of their own; in the migrate, we specifically show the initial message from the user to: 1. start the agent's thinking process and 2. show the user that the chat session is working instead of forcing them to ask something additionally

bespoyasov and others added 8 commits October 6, 2026 11:34
pnpm and yarn classic error when `add` runs at a workspace root without
an explicit flag (`-w` / `-W`). Detect workspace markers and inject the
flag automatically so `confidence sdk install` works from monorepo roots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract Node, Python, JVM, and native install builders into dedicated
files so each ecosystem's PM detection and command construction is
self-contained. Python now detects poetry/uv/pipenv and falls back to a
manual install for bare pip (avoids PEP 668 and global-install issues).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The `id` field was typed as `string`, making the `as never` cast in
exhaustive switches a no-op — new frameworks compiled without errors and
threw at runtime. Now `FrameworkId` is a union of known IDs so the
compiler catches missing cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align --dir handling with sdk setup by using the shared
resolveProjectDir helper instead of reading argv.dir directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Maven snippet hardcoded groupId and artifactId and used an
inconsistent VERSION placeholder. Split sdkPackage on ':' so the
snippet stays in sync if the package coordinates change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The prompt referenced the analyze-project skill, which proposes feature
flag changes — contradicting the "only set up the SDK" instruction.
Use getCodeSnippetAndSdkIntegrationTips from confidence-docs instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bespoyasov
bespoyasov merged commit 7506356 into main Oct 6, 2026
6 checks passed
@bespoyasov
bespoyasov deleted the feat/sdk-commands branch October 6, 2026 11:39
@github-actions github-actions Bot mentioned this pull request Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants