Implement interactive terminal wizard for Seam integration setup - #2
Merged
Conversation
Move the Ink-based setup wizard implementation from seamapi/wizard-internal into src/lib verbatim, so the wizard lives in the published package instead of a separate internal repository. This commit is a pure move: no source edits. The only change is that wizard-internal's src/index.tsx becomes src/lib/render.tsx, since src/lib/index.ts is already this package's library entrypoint. Nothing here is wired up yet — the stubbed entrypoint still runs, and the following commits adapt the moved code to this repository's conventions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
The moved source is an Ink application, so add its runtime dependencies (Ink and its input components, React, open, and the Claude Agent SDK) alongside the React types and Ink testing library used for development. Teach the build, packaging, and test configuration about .tsx: exclude .test.tsx from the published build and include it in the Vitest run. The tsconfig already sets jsx: react-jsx, so no compiler option changes are needed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
This repository addresses modules under src/lib through the `lib/*` path alias rather than parent-relative specifiers: the alias is declared in tsconfig.json, mapped for tests in vitest.config.ts, rewritten at build time by tsc-alias, given its own import-sort group in eslint.config.ts, and enforced by import/no-relative-parent-imports. Point the step modules at lib/util/* instead of ../util/*. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
Wire the moved Ink application up to the package's public API, replacing the stub that printed "not implemented yet". The API is unchanged for consumers: the default export still takes `argv` and `commandName`, still handles `--help` itself, and now renders the wizard instead of returning. Turn the moved src/lib/render.tsx from a bin script with top-level side effects into an exported `renderApp` function, so importing the package never touches the terminal. Rendering full-screen and reprinting the transcript on the way out is unchanged, except that the transcript is now also reprinted when the app fails, and failures reject instead of quietly setting an exit code — the caller, e.g., src/bin/cli.ts, reports them. Add a `cwd` option for the project root the wizard sets up, defaulting to process.cwd() as the bin script previously hardcoded. The Seam CLI can now mount the wizard against an explicit directory, and it makes the entrypoint testable without touching the working tree. Replace the scaffold `todo` placeholder, its tests, and its example with the wizard itself: `npm run example -- wizard` mounts the package the way a consumer does. Switch help output from console.log to process.stdout, matching the renderer and dropping the no-console suppression. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
Apply this repository's Prettier configuration and the autofixable ESLint rules to the moved source: single quotes, no semicolons, and sorted import groups. No behavior changes — this is the mechanical part of the migration, kept separate so the substantive conformance changes that follow are reviewable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
…e rules
The migrated source was written against a looser configuration than this
repository's. Bring it into line, with no behavior changes:
- camelCase for local variables, parameters, and destructuring bindings.
Property names are left alone: the repo's camelcase rule sets
`properties: 'never'`, and these types mirror the Seam API wire format
and the on-disk .seam/onboarding.json record, so renaming them would
change the protocol. Snake_case properties destructured into locals are
aliased, e.g. `const { api_key: apiKey } = phase`.
- Replace `void (async () => {…})()` in the app's effects, which the
no-void rule rejects, with a named async function and an explicit
rejection handler that routes to the app's existing error phase. `void`
had turned an unexpected rejection into an unhandled rejection, so
failures that previously vanished are now shown to the user.
- Access environment variables and Record members by index, as
noPropertyAccessFromIndexSignature requires.
- Drop the unneeded default React imports in favor of named imports,
since the repo compiles with jsx: react-jsx and verbatimModuleSyntax.
- Omit Ink's `color` prop on non-cursor checkbox rows rather than passing
undefined, which exactOptionalPropertyTypes rejects. The rows still
inherit the terminal default.
- Brace multi-line conditionals for the curly rule, and drop a dead local.
`npm run lint` and `npm run typecheck` now pass over src.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
The migrated source checked that the app mounts via scripts/smoke.tsx, a standalone script run by its own npm script. It reported results with console calls, which the no-console rule rejects, and it sat outside the tsconfig, so it was never typechecked. Move that check into the test suite as src/lib/app.test.tsx, where it runs under `npm test` with the rest of the suite and is covered by lint and typecheck. The assertion is unchanged: render the app against a project root that does not exist with no key in the environment, which keeps the render offline, and confirm the first frame. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
The migrated source arrived with no unit tests. Cover the pure, non-UI modules that the wizard's behavior depends on, so the coverage report this repository already produces means something: - env-file: which key wins between the environment and each dotenv file, quote stripping, and the created/added/updated outcomes of upserting a variable without disturbing neighboring entries. - detect-project: SDK detection from project markers, including the ambiguous cases, package manager and installer detection, and the install command produced for each. - build-plan: goal composition for both modes, the agent hints contributed by each selected building block, and the on-disk onboarding record. Every test that touches the filesystem uses its own temporary directory, and those reading SEAM_API_KEY stub it, so the suite neither depends on nor leaks ambient state. The networked modules and the Ink components are left out: the app's render is covered by src/lib/app.test.tsx. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
Replace the placeholder description with what the wizard actually does, now that it is implemented: the steps it runs, that keys are never minted here, and that inference is routed through Seam so no developer Anthropic key is needed. Document the `cwd` option and what the entrypoint's promise means, the two environment variables that affect a run, and the src/lib layout including the lib/* alias and why the wire-format types keep snake_case properties. Note that `npm run wizard` sets up whichever project it runs in — that is this repository, which is rarely what you want — and show how to run it against a scratch project instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
The scaffold's landlubber examples harness does not fit this package. The wizard is a single interactive entrypoint that takes over the terminal, not a set of commands worth demonstrating one by one, and the README already shows the two lines a consumer needs to mount it. Remove the examples directory, the landlubber dependency, the example scripts, and the examples entries in the tsconfig include and the coverage exclude list. The examples were the only way to run the wizard against a directory other than this repository, so move that onto the development CLI as a '--cwd <path>' flag. Running the CLI from another directory is not an option: tsx resolves the tsconfig from the working directory, so the lib/* alias fails to resolve. The flag is consumed by the CLI and becomes the wizard's `cwd` option; every other argument is still forwarded untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
Document running it against a project with '--cwd' directly, rather than explaining the default of setting up this repository and working up to the flag from there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements a complete interactive terminal wizard that guides developers through setting up a Seam integration in their project. The wizard is a full-featured CLI application built with Ink (React for terminals) that handles project detection, authentication, SDK installation, and AI-powered integration code generation.
Key Changes
Core wizard application (
src/lib/app.tsx): Main state machine-driven Ink component that orchestrates the entire onboarding flow through multiple phases (init → method → browser/paste → verify → sdk → install → analyze → integrate → done)Project detection (
src/lib/steps/detect-project.ts): Detects JavaScript/TypeScript and Python projects, identifies package managers (npm, pnpm, yarn, bun) and Python installers (pip, poetry, uv)Authentication flow (
src/lib/steps/authenticate.ts,src/lib/steps/connect-web.ts): Supports three authentication methods:.env*filesProject analysis (
src/lib/steps/analyze-project.ts): Gathers project signals (dependencies, framework detection, README) and recommends integration approach via LLM with deterministic fallbackIntegration planning (
src/lib/steps/build-plan.ts): Defines core and common building blocks (access grants, webhooks, etc.) and composes agent goals from selected optionsAI-powered integration (
src/lib/steps/integrate.ts): Runs embedded Claude agent with file read/write tools and Seam MCP access to write integration code into the projectUI components (
src/lib/components/checkbox-list.tsx): Custom multi-select checkbox component for building block selectionUtility modules:
env-file.ts: Reads/writes.env*files for API key persistenceseam-api.ts: Minimal Seam API client for key validation and token exchangerun-install.ts: Streams command output for SDK/plugin installation progressRendering (
src/lib/render.tsx): Manages alternate screen buffer for full-screen terminal UITests: Comprehensive test coverage for project detection, build planning, and environment file handling
Documentation: Updated README with detailed description of wizard capabilities and flow
Notable Implementation Details
.seam/onboarding.jsonbefore agent execution for auditabilityhttps://claude.ai/code/session_01W1qhuuZQZnA1FB1fBSxrqx