diff --git a/.claude/skills/wizard-architecture/SKILL.md b/.claude/skills/wizard-architecture/SKILL.md index 2b5348c..ffc79a1 100644 --- a/.claude/skills/wizard-architecture/SKILL.md +++ b/.claude/skills/wizard-architecture/SKILL.md @@ -16,6 +16,15 @@ The Confidence Wizard is a CLI tool for quickly setting up and integrating [Conf The project is organized into decoupled top-level concerns. Each has its own subdirectory and must not depend on the others' internals. +### Shared Kernel (`src/shared-kernel/`) + +Cross-domain vocabulary types that multiple domains depend on. Contains only type definitions — no runtime logic, no functions. + +- Types here form the ubiquitous language of the project: identifiers and enums that appear in function signatures across domain boundaries (e.g. `IdeId`, `OnboardingGoal`, `PluginInstallationMethod`, `DetectedProvider`). +- If a type is used by three or more domains, it belongs here. If it's used by only one domain, it stays in that domain's `types.ts`. +- The shared kernel depends on nothing in `src/`. Every other domain may import from it. +- Adding a new shared type: define in `types.ts`, re-export from `index.ts`. + ### 1. Commands (`src/commands/`) CLI command definitions using yargs. Each command is a self-contained module exporting a `Command` object. @@ -58,6 +67,16 @@ Terminal user interface built with Ink and React. Organized into: UI modules must not import from `src/commands/`. They may import from `src/frameworks/` only to read framework metadata for display. +### 6. Features (`src/features/`) + +Vertical feature slices that compose logic from multiple domains. Each feature gets its own subdirectory (e.g. `features/onboarding/`). + +- Currently: `onboarding/` — prompt builder for the project onboarding flow. +- Features may import from `src/lib/`, `src/shared-kernel/`, and (via type-only imports) from other domains. +- Features must not import from `src/ui/` or `src/commands/`. +- Each feature exports through a barrel `index.ts` with a compact public API. +- Adding a new feature: create a subdir under `features/`, add a barrel, document in this skill and CLAUDE.md. + ## Hard Constraints ### No product knowledge in the TUI @@ -76,14 +95,17 @@ All of this belongs in the Claude Code Skill and is delivered via Confidence MCP ### Dependency direction ``` -commands → ui, frameworks, lib -ui → lib, providers (and frameworks for display metadata only) -frameworks → lib -providers → lib -lib → nothing in src/ +commands → ui, features, frameworks, lib, shared-kernel +features → lib, shared-kernel +ui → features, lib, providers, shared-kernel (and frameworks for display metadata only) +frameworks → lib, shared-kernel +providers → lib, shared-kernel +integrations → lib, shared-kernel +lib → shared-kernel +shared-kernel → nothing in src/ ``` -No circular dependencies. No upward imports. If two domains need to communicate, it flows through `src/lib/` shared types. +No circular dependencies. No upward imports. Cross-domain vocabulary types live in `src/shared-kernel/`. Runtime utilities and session infrastructure live in `src/lib/`. Within the UI layer, the same principle applies at a finer grain: @@ -218,7 +240,7 @@ function applyStatuses(updated: Record) { ### Path Aliases -Use path aliases (`@commands/`, `@frameworks/`, `@integrations/`, `@providers/`, `@ui/`, `@lib/`) for all imports that cross top-level domain boundaries under `src/`. Keep relative imports for references within the same domain. +Use path aliases (`@commands/`, `@features/`, `@frameworks/`, `@integrations/`, `@providers/`, `@shared-kernel/`, `@ui/`, `@lib/`) for all imports that cross top-level domain boundaries under `src/`. Keep relative imports for references within the same domain. Aliases are configured in `tsconfig.build.json` (`paths`) and `vitest.config.ts` (`resolve.alias`). When adding a new top-level domain under `src/`, add its alias to both files. @@ -249,7 +271,7 @@ import { ScreenId } from '@lib/session.js'; - In `useEffect`, use named functions instead of anonymous lambdas for the effect callback. - Prefer `AbortController` for removing event listeners instead of manually calling `removeEventListener`. Pass `{ signal: controller.signal }` to `addEventListener` and call `controller.abort()` in cleanup. This avoids needing to keep a reference to the exact same handler function and scales cleanly when multiple listeners share a lifetime. - Prefer "UI as a function of state" — derive values from state and props in the render body rather than stashing them in refs. Resort to `useRef` only when there is no pure-function alternative (e.g. holding a DOM node, a timer ID, or an instance that must survive re-renders without triggering one). -- No ad-hoc union extensions at call sites. When a function parameter or callback needs a union type (e.g. `ChosenIde | 'skip'`), define a named type in the slice's `actions.ts` and reference it — don't write inline unions like `value: SomeType | 'extra'` in function signatures. Composition is fine (`type DetectedSelectValue = IdeSelectValue | 'continue'`), but it must be named and exported from `actions.ts`. +- No ad-hoc union extensions at call sites. When a function parameter or callback needs a union type (e.g. `IdeId | 'skip'`), define a named type in the slice's `actions.ts` and reference it — don't write inline unions like `value: SomeType | 'extra'` in function signatures. Composition is fine (`type DetectedSelectValue = IdeSelectValue | 'continue'`), but it must be named and exported from `actions.ts`. - In `switch` statements, the `default` case must use an exhaustive check via `satisfies never` to catch unhandled variants at compile time: ```ts default: { @@ -279,7 +301,7 @@ Never suppress, silence, or filter runtime warnings (e.g. `--no-warnings`, `--di When the project grows, new top-level concerns (e.g. `src/agent/` for agent harness logic, `src/detection/` for project analysis) follow the same pattern: - Own subdirectory under `src/` -- Shared types in `src/lib/` or own `types.ts` +- Cross-domain vocabulary types in `src/shared-kernel/types.ts`; domain-specific types in a local `types.ts` - Exported through a barrel `index.ts` - No circular dependencies with existing domains - Documented in this skill and CLAUDE.md diff --git a/.claude/skills/wizard-integrations/SKILL.md b/.claude/skills/wizard-integrations/SKILL.md index 87a3011..8d1cb3e 100644 --- a/.claude/skills/wizard-integrations/SKILL.md +++ b/.claude/skills/wizard-integrations/SKILL.md @@ -57,7 +57,7 @@ Each IDE owns the full implementation of all these methods. Shared helpers (`ver ### Shared types -`IdeId` is defined in `src/integrations/types.ts` — it belongs to the integrations module. `WizardSession` uses its own `ChosenIde` type (same string union, defined in `src/lib/session.ts`) to stay decoupled from the integrations module. This keeps the dependency direction clean: integrations never imports from lib/session for its own type definitions, and session never imports from integrations. +`IdeId` is defined in `src/integrations/types.ts` — it belongs to the integrations module. `WizardSession` uses its own `IdeId` type (same string union, defined in `src/lib/session.ts`) to stay decoupled from the integrations module. This keeps the dependency direction clean: integrations never imports from lib/session for its own type definitions, and session never imports from integrations. ### Orchestrators diff --git a/AGENTS.md b/AGENTS.md index 283a04d..a9e6ac7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,9 +4,11 @@ CLI wizard for setting up and integrating [Confidence](https://confidence.spotif ## Architecture -The project has five decoupled domains: +The project has five decoupled domains plus a shared kernel and a features layer: +- **`src/shared-kernel/`** — Cross-domain vocabulary types (`IdeId`, `OnboardingGoal`, `PluginInstallationMethod`, `DetectedProvider`). Type definitions only, no runtime logic. - **`src/commands/`** — CLI command definitions (yargs-based). Currently: default (launches TUI) and help. +- **`src/features/`** — Vertical feature slices. Currently: `onboarding/` (prompt builder for the onboarding flow). - **`src/frameworks/`** — Framework integration configs. One subdir per framework (react, nextjs, node). Each exports a `FrameworkConfig` with detection, SDK package, and docs URL. - **`src/integrations/`** — IDE integration strategies. One subdir per supported IDE (claude, cursor, codex). Each exports an `IdeIntegration` object implementing the strategy pattern. Also contains IDE-agnostic MCP, plugin, and chat-session logic. - **`src/providers/`** — Provider detection for competing feature flag platforms (Statsig, Eppo, PostHog, Optimizely). One subdir per provider. @@ -69,7 +71,7 @@ The stable `node-pty` release (v1.1.0) doesn't ship prebuilt binaries for Node.j ## Conventions -- Use path aliases (`@commands/`, `@frameworks/`, `@integrations/`, `@providers/`, `@ui/`, `@lib/`) for cross-domain imports. Keep relative imports within the same domain. +- Use path aliases (`@commands/`, `@features/`, `@frameworks/`, `@integrations/`, `@providers/`, `@shared-kernel/`, `@ui/`, `@lib/`) for cross-domain imports. Keep relative imports within the same domain. - Use `@inkjs/ui` components over standalone `ink-*` packages. - Screens go in `src/ui/tui/screens/` (as slices or flat files), reusable components in `components/`. - Shared modules (`hooks/`, `lib/`, `components/`) must never import from screen slices. If a type is needed by both, put it in `tui/lib/`. diff --git a/__tests__/lib/onboarding-prompt.test.ts b/__tests__/features/onboarding/build-prompt.test.ts similarity index 97% rename from __tests__/lib/onboarding-prompt.test.ts rename to __tests__/features/onboarding/build-prompt.test.ts index 1f50419..83b0910 100644 --- a/__tests__/lib/onboarding-prompt.test.ts +++ b/__tests__/features/onboarding/build-prompt.test.ts @@ -1,4 +1,4 @@ -import { buildOnboardingPrompt } from '@lib/onboarding-prompt/index.js'; +import { buildOnboardingPrompt } from '@features/onboarding/index.js'; describe('buildOnboardingPrompt', () => { const baseOpts = { diff --git a/__tests__/lib/report-templates.test.ts b/__tests__/features/onboarding/report-templates.test.ts similarity index 96% rename from __tests__/lib/report-templates.test.ts rename to __tests__/features/onboarding/report-templates.test.ts index b07ece5..d7ffec3 100644 --- a/__tests__/lib/report-templates.test.ts +++ b/__tests__/features/onboarding/report-templates.test.ts @@ -1,5 +1,5 @@ -import { buildReportTemplate } from '@lib/onboarding-prompt/report-templates.js'; -import type { OnboardingGoal } from '@lib/session.js'; +import { buildReportTemplate } from '@features/onboarding/report-templates.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; function fileEntries(goals: OnboardingGoal[]): string[] { const { start } = buildReportTemplate(goals); diff --git a/__tests__/lib/tool-vars.test.ts b/__tests__/features/onboarding/tool-vars.test.ts similarity index 87% rename from __tests__/lib/tool-vars.test.ts rename to __tests__/features/onboarding/tool-vars.test.ts index c7deb5c..5d20b0b 100644 --- a/__tests__/lib/tool-vars.test.ts +++ b/__tests__/features/onboarding/tool-vars.test.ts @@ -1,8 +1,8 @@ -import { skillInvocation, referenceInstruction } from '@lib/onboarding-prompt/tool-vars.js'; -import type { ChosenIde } from '@lib/session.js'; +import { skillInvocation, referenceInstruction } from '@features/onboarding/tool-vars.js'; +import type { IdeId } from '@shared-kernel/types.js'; describe('skillInvocation', () => { - it.each<{ ide: ChosenIde; expected: string }>([ + it.each<{ ide: IdeId; expected: string }>([ { ide: 'claude', expected: '/confidence:analyze-project' }, { ide: 'codex', expected: '$analyze-project' }, { ide: 'cursor', expected: '/analyze-project' }, @@ -14,7 +14,7 @@ describe('skillInvocation', () => { describe('referenceInstruction', () => { describe('when method is cli', () => { - it.each<{ ide: ChosenIde; expected: string }>([ + it.each<{ ide: IdeId; expected: string }>([ { ide: 'claude', expected: 'Invoke the `/confidence:analyze-project` skill as a **methodology reference**', @@ -34,7 +34,7 @@ describe('referenceInstruction', () => { }); describe('when method is download', () => { - it.each<{ ide: ChosenIde; expected: string }>([ + it.each<{ ide: IdeId; expected: string }>([ { ide: 'claude', expected: 'Read `.claude/skills/analyze-project/SKILL.md` as a **methodology reference**', diff --git a/__tests__/ui/screens/ConnectToolsScreen.auth.test.tsx b/__tests__/ui/screens/ConnectToolsScreen.auth.test.tsx index 182e5ed..d5d33c8 100644 --- a/__tests__/ui/screens/ConnectToolsScreen.auth.test.tsx +++ b/__tests__/ui/screens/ConnectToolsScreen.auth.test.tsx @@ -14,11 +14,11 @@ import { ConnectToolsScreen } from '@ui/tui/screens/connect-tools/index.js'; import { ScreenId } from '@lib/session.js'; import { persistMcpPreference, clearMcpPreference, MCP_SERVERS } from '@integrations/index.js'; import type { McpServerName } from '@integrations/index.js'; -import type { ChosenIde } from '@lib/session.js'; +import type { IdeId } from '@shared-kernel/types.js'; import { server } from '../../msw/server.js'; type IntegrationTestCase = { - ide: ChosenIde; + ide: IdeId; }; describe('ConnectToolsScreen', () => { @@ -201,7 +201,7 @@ type McpConfigOpts = { token?: string; }; -function writeMcpConfig(projectDir: string, ide: ChosenIde, opts?: McpConfigOpts): void { +function writeMcpConfig(projectDir: string, ide: IdeId, opts?: McpConfigOpts): void { switch (ide) { case 'claude': return writeJsonMcpConfig(join(projectDir, '.mcp.json'), opts); diff --git a/__tests__/ui/testing-framework/ink/render.tsx b/__tests__/ui/testing-framework/ink/render.tsx index 378ed60..dd16438 100644 --- a/__tests__/ui/testing-framework/ink/render.tsx +++ b/__tests__/ui/testing-framework/ink/render.tsx @@ -5,8 +5,8 @@ import { WizardRouter } from '@ui/tui/router.js'; import { SCREEN_TRANSITIONS } from '@ui/tui/screen-transitions.js'; import { RouterContext } from '@ui/tui/hooks/useRouter.js'; import { App } from '@ui/tui/App.js'; -import type { AuthState, OnboardingGoal, ScreenId } from '@lib/session.js'; -import type { ChosenIde } from '@lib/session.js'; +import type { IdeId, OnboardingGoal } from '@shared-kernel/types.js'; +import type { AuthState, ScreenId } from '@lib/session.js'; // ink-testing-library's Stdout provides columns (100) but not rows, // so useTerminalSize defaults to 24 — below SHORT_THRESHOLD (28). @@ -20,8 +20,8 @@ type RenderOptions = StoreOptions & { screen?: ScreenId; authState?: AuthState; - ide?: ChosenIde; - plugins?: ChosenIde[]; + ide?: IdeId; + plugins?: IdeId[]; framework?: string; diff --git a/src/lib/onboarding-prompt/index.ts b/src/features/onboarding/build-prompt.ts similarity index 93% rename from src/lib/onboarding-prompt/index.ts rename to src/features/onboarding/build-prompt.ts index ba0562c..e6bed28 100644 --- a/src/lib/onboarding-prompt/index.ts +++ b/src/features/onboarding/build-prompt.ts @@ -1,6 +1,5 @@ -import type { PluginInstallationMethod } from '@integrations/types.js'; -import type { ChosenIde, OnboardingGoal } from '../session.js'; -import { addIf } from '../prompt-utils.js'; +import type { IdeId, OnboardingGoal, PluginInstallationMethod } from '@shared-kernel/types.js'; +import { addIf } from '@lib/prompt-utils.js'; import { buildToolVars } from './tool-vars.js'; import { preflight } from './sections/preflight.js'; import { scaffold } from './sections/scaffold.js'; @@ -13,7 +12,7 @@ import { summary, rules } from './sections/summary.js'; type PromptOptions = { framework: string; projectDir: string; - ide?: ChosenIde; + ide?: IdeId; isEmptyProject?: boolean; goals?: OnboardingGoal[]; hasProviders?: boolean; diff --git a/src/features/onboarding/index.ts b/src/features/onboarding/index.ts new file mode 100644 index 0000000..f11bbdf --- /dev/null +++ b/src/features/onboarding/index.ts @@ -0,0 +1,3 @@ +export { buildOnboardingPrompt } from './build-prompt.js'; +export type { ReportTemplate } from './report-templates.js'; +export { skillInvocation, referenceInstruction } from './tool-vars.js'; diff --git a/src/lib/onboarding-prompt/report-templates.ts b/src/features/onboarding/report-templates.ts similarity index 98% rename from src/lib/onboarding-prompt/report-templates.ts rename to src/features/onboarding/report-templates.ts index 4fc5ac6..b1746b4 100644 --- a/src/lib/onboarding-prompt/report-templates.ts +++ b/src/features/onboarding/report-templates.ts @@ -1,4 +1,4 @@ -import type { OnboardingGoal } from '../session.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; export type ReportTemplate = { start: string; end: string }; diff --git a/src/lib/onboarding-prompt/sections/event-tracking.ts b/src/features/onboarding/sections/event-tracking.ts similarity index 82% rename from src/lib/onboarding-prompt/sections/event-tracking.ts rename to src/features/onboarding/sections/event-tracking.ts index b6d03b9..aa20619 100644 --- a/src/lib/onboarding-prompt/sections/event-tracking.ts +++ b/src/features/onboarding/sections/event-tracking.ts @@ -1,5 +1,4 @@ -import type { PluginInstallationMethod } from '@integrations/types.js'; -import type { ChosenIde } from '../../session.js'; +import type { IdeId, PluginInstallationMethod } from '@shared-kernel/types.js'; import { loadStep } from '../steps/load.js'; import { referenceInstruction } from '../tool-vars.js'; @@ -7,7 +6,7 @@ export function instrumentEvents( framework: string, step: number, isEmptyProject: boolean, - ide: ChosenIde, + ide: IdeId, pluginInstallMethod?: PluginInstallationMethod | null, ): string { return loadStep('instrument-events.md', { diff --git a/src/lib/onboarding-prompt/sections/integrate.ts b/src/features/onboarding/sections/integrate.ts similarity index 95% rename from src/lib/onboarding-prompt/sections/integrate.ts rename to src/features/onboarding/sections/integrate.ts index 9a2f5fb..6e397ad 100644 --- a/src/lib/onboarding-prompt/sections/integrate.ts +++ b/src/features/onboarding/sections/integrate.ts @@ -1,5 +1,4 @@ -import type { PluginInstallationMethod } from '@integrations/types.js'; -import type { ChosenIde } from '../../session.js'; +import type { IdeId, PluginInstallationMethod } from '@shared-kernel/types.js'; import { loadStep } from '../steps/load.js'; import { referenceInstruction } from '../tool-vars.js'; @@ -7,7 +6,7 @@ export function integrateViaSkill( framework: string, step: number, isEmptyProject: boolean, - ide: ChosenIde, + ide: IdeId, pluginInstallMethod?: PluginInstallationMethod | null, ): string { const needsReactGotchas = /react|nextjs|next/i.test(framework); diff --git a/src/lib/onboarding-prompt/sections/preflight.ts b/src/features/onboarding/sections/preflight.ts similarity index 77% rename from src/lib/onboarding-prompt/sections/preflight.ts rename to src/features/onboarding/sections/preflight.ts index 8e48904..859971f 100644 --- a/src/lib/onboarding-prompt/sections/preflight.ts +++ b/src/features/onboarding/sections/preflight.ts @@ -1,4 +1,4 @@ -import { CONFIDENCE_DOCS_URL } from '../../constants.js'; +import { CONFIDENCE_DOCS_URL } from '@lib/constants.js'; import { loadStep } from '../steps/load.js'; export function preflight(toolVars: Record): string { diff --git a/src/lib/onboarding-prompt/sections/recording.ts b/src/features/onboarding/sections/recording.ts similarity index 92% rename from src/lib/onboarding-prompt/sections/recording.ts rename to src/features/onboarding/sections/recording.ts index 5c87ba4..8567b3e 100644 --- a/src/lib/onboarding-prompt/sections/recording.ts +++ b/src/features/onboarding/sections/recording.ts @@ -1,4 +1,4 @@ -import { CONFIDENCE_DOCS_URL } from '../../constants.js'; +import { CONFIDENCE_DOCS_URL } from '@lib/constants.js'; import { loadStep } from '../steps/load.js'; export function determineRecordingSDK( diff --git a/src/lib/onboarding-prompt/sections/report.ts b/src/features/onboarding/sections/report.ts similarity index 90% rename from src/lib/onboarding-prompt/sections/report.ts rename to src/features/onboarding/sections/report.ts index c620570..6be9768 100644 --- a/src/lib/onboarding-prompt/sections/report.ts +++ b/src/features/onboarding/sections/report.ts @@ -1,5 +1,5 @@ -import type { OnboardingGoal } from '../../session.js'; -import { CONFIDENCE_DOCS_URL } from '../../constants.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; +import { CONFIDENCE_DOCS_URL } from '@lib/constants.js'; import { buildReportTemplate } from '../report-templates.js'; import { loadStep } from '../steps/load.js'; diff --git a/src/lib/onboarding-prompt/sections/scaffold.ts b/src/features/onboarding/sections/scaffold.ts similarity index 100% rename from src/lib/onboarding-prompt/sections/scaffold.ts rename to src/features/onboarding/sections/scaffold.ts diff --git a/src/lib/onboarding-prompt/sections/summary.ts b/src/features/onboarding/sections/summary.ts similarity index 100% rename from src/lib/onboarding-prompt/sections/summary.ts rename to src/features/onboarding/sections/summary.ts diff --git a/src/lib/onboarding-prompt/steps/determine-recording-sdk.md b/src/features/onboarding/steps/determine-recording-sdk.md similarity index 100% rename from src/lib/onboarding-prompt/steps/determine-recording-sdk.md rename to src/features/onboarding/steps/determine-recording-sdk.md diff --git a/src/lib/onboarding-prompt/steps/generate-report.md b/src/features/onboarding/steps/generate-report.md similarity index 100% rename from src/lib/onboarding-prompt/steps/generate-report.md rename to src/features/onboarding/steps/generate-report.md diff --git a/src/lib/onboarding-prompt/steps/instrument-events.md b/src/features/onboarding/steps/instrument-events.md similarity index 100% rename from src/lib/onboarding-prompt/steps/instrument-events.md rename to src/features/onboarding/steps/instrument-events.md diff --git a/src/lib/onboarding-prompt/steps/integrate-recording.md b/src/features/onboarding/steps/integrate-recording.md similarity index 100% rename from src/lib/onboarding-prompt/steps/integrate-recording.md rename to src/features/onboarding/steps/integrate-recording.md diff --git a/src/lib/onboarding-prompt/steps/integrate-via-skill.md b/src/features/onboarding/steps/integrate-via-skill.md similarity index 100% rename from src/lib/onboarding-prompt/steps/integrate-via-skill.md rename to src/features/onboarding/steps/integrate-via-skill.md diff --git a/src/lib/onboarding-prompt/steps/load.ts b/src/features/onboarding/steps/load.ts similarity index 89% rename from src/lib/onboarding-prompt/steps/load.ts rename to src/features/onboarding/steps/load.ts index f7572a9..0b64ee3 100644 --- a/src/lib/onboarding-prompt/steps/load.ts +++ b/src/features/onboarding/steps/load.ts @@ -1,7 +1,7 @@ import { readFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { interpolate } from '../../prompt-utils.js'; +import { interpolate } from '@lib/prompt-utils.js'; const STEPS_DIR = dirname(fileURLToPath(import.meta.url)); diff --git a/src/lib/onboarding-prompt/steps/preflight.md b/src/features/onboarding/steps/preflight.md similarity index 100% rename from src/lib/onboarding-prompt/steps/preflight.md rename to src/features/onboarding/steps/preflight.md diff --git a/src/lib/onboarding-prompt/steps/rules.md b/src/features/onboarding/steps/rules.md similarity index 100% rename from src/lib/onboarding-prompt/steps/rules.md rename to src/features/onboarding/steps/rules.md diff --git a/src/lib/onboarding-prompt/steps/scaffold.md b/src/features/onboarding/steps/scaffold.md similarity index 100% rename from src/lib/onboarding-prompt/steps/scaffold.md rename to src/features/onboarding/steps/scaffold.md diff --git a/src/lib/onboarding-prompt/steps/summary.md b/src/features/onboarding/steps/summary.md similarity index 100% rename from src/lib/onboarding-prompt/steps/summary.md rename to src/features/onboarding/steps/summary.md diff --git a/src/lib/onboarding-prompt/tool-vars.ts b/src/features/onboarding/tool-vars.ts similarity index 75% rename from src/lib/onboarding-prompt/tool-vars.ts rename to src/features/onboarding/tool-vars.ts index 4515d23..ad1537b 100644 --- a/src/lib/onboarding-prompt/tool-vars.ts +++ b/src/features/onboarding/tool-vars.ts @@ -1,34 +1,33 @@ -import type { PluginInstallationMethod } from '@integrations/types.js'; -import type { ChosenIde } from '../session.js'; -import { PLUGIN_NAME } from '../constants.js'; +import type { IdeId, PluginInstallationMethod } from '@shared-kernel/types.js'; +import { PLUGIN_NAME } from '@lib/constants.js'; type ToolFormatter = (server: string, tool: string) => string; -const TOOL_FORMATTERS: Record = { +const TOOL_FORMATTERS: Record = { claude: (server, tool) => `mcp__${server}__${tool}`, codex: (server, tool) => `${server}:${tool}`, cursor: (server, tool) => `mcp__${server}__${tool}`, }; -const SKILL_INVOCATIONS: Record string> = { +const SKILL_INVOCATIONS: Record string> = { claude: (skill) => `/${PLUGIN_NAME}:${skill}`, codex: (skill) => `$${skill}`, cursor: (skill) => `/${skill}`, }; -const SKILLS_DIRS: Record = { +const SKILLS_DIRS: Record = { claude: '.claude/skills', cursor: '.cursor/skills', codex: '.agents/skills', }; -export function skillInvocation(skillName: string, ide: ChosenIde): string { +export function skillInvocation(skillName: string, ide: IdeId): string { return SKILL_INVOCATIONS[ide](skillName); } export function referenceInstruction( skillName: string, - ide: ChosenIde, + ide: IdeId, method?: PluginInstallationMethod | null, ): string { return method === 'cli' @@ -36,7 +35,7 @@ export function referenceInstruction( : `Read \`${SKILLS_DIRS[ide]}/${skillName}/SKILL.md\` as a **methodology reference**`; } -export function buildToolVars(ide: ChosenIde): Record { +export function buildToolVars(ide: IdeId): Record { const fmt = TOOL_FORMATTERS[ide]; const flags = (tool: string) => fmt('confidence-flags', tool); const docs = (tool: string) => fmt('confidence-docs', tool); diff --git a/src/integrations/chat.ts b/src/integrations/chat.ts index 0fe60d8..2c18933 100644 --- a/src/integrations/chat.ts +++ b/src/integrations/chat.ts @@ -1,4 +1,4 @@ -import type { IdeId } from './types.js'; +import type { IdeId } from '@shared-kernel/types.js'; import type { WizardSession } from '@lib/session.js'; import { getIntegration } from './registry.js'; diff --git a/src/integrations/claude/plugins.ts b/src/integrations/claude/plugins.ts index 344d7bd..538eb39 100644 --- a/src/integrations/claude/plugins.ts +++ b/src/integrations/claude/plugins.ts @@ -2,7 +2,7 @@ import { execFile as execFileCb } from 'node:child_process'; import { resolve } from 'node:path'; import { promisify } from 'node:util'; import { PLUGIN_NAME } from '@lib/constants.js'; -import type { PluginInstallationMethod } from '../types.js'; +import type { PluginInstallationMethod } from '@shared-kernel/types.js'; import { hasDownloadedSkills } from '../skills/local.js'; import { skillsDir } from './paths.js'; diff --git a/src/integrations/codex/plugins.ts b/src/integrations/codex/plugins.ts index 8cf6bb6..0e6365e 100644 --- a/src/integrations/codex/plugins.ts +++ b/src/integrations/codex/plugins.ts @@ -1,7 +1,7 @@ import { execFile as execFileCb } from 'node:child_process'; import { promisify } from 'node:util'; import { PLUGIN_MARKETPLACE_REPO, PLUGIN_MARKETPLACE_NAME, PLUGIN_NAME } from '@lib/constants.js'; -import type { PluginInstallationMethod } from '../types.js'; +import type { PluginInstallationMethod } from '@shared-kernel/types.js'; import { hasDownloadedSkills } from '../skills/local.js'; import { skillsDir } from './paths.js'; diff --git a/src/integrations/cursor/plugins.ts b/src/integrations/cursor/plugins.ts index fe2b5d9..6028d3f 100644 --- a/src/integrations/cursor/plugins.ts +++ b/src/integrations/cursor/plugins.ts @@ -1,7 +1,7 @@ import { execFile as execFileCb } from 'node:child_process'; import { promisify } from 'node:util'; import { PLUGIN_REPO_URL } from '@lib/constants.js'; -import type { PluginInstallationMethod } from '../types.js'; +import type { PluginInstallationMethod } from '@shared-kernel/types.js'; import { hasDownloadedSkills } from '../skills/local.js'; import { skillsDir } from './paths.js'; diff --git a/src/integrations/index.ts b/src/integrations/index.ts index 115674c..425bea4 100644 --- a/src/integrations/index.ts +++ b/src/integrations/index.ts @@ -1,10 +1,8 @@ export type { - IdeId, IdeIntegration, McpConnectOpts, OnboardingOpts, OnboardingCallbacks, - PluginInstallationMethod, InstalledPlugin, } from './types.js'; diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 1be08c7..63f271e 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -1,4 +1,4 @@ -import type { IdeId } from './types.js'; +import type { IdeId } from '@shared-kernel/types.js'; import type { IdeIntegration } from './types.js'; import { claudeIntegration } from './claude/index.js'; import { cursorIntegration } from './cursor/index.js'; diff --git a/src/integrations/skills/plugin.ts b/src/integrations/skills/plugin.ts index 199dd3f..ab2803a 100644 --- a/src/integrations/skills/plugin.ts +++ b/src/integrations/skills/plugin.ts @@ -1,4 +1,5 @@ -import type { IdeId, PluginInstallationMethod, InstalledPlugin } from '../types.js'; +import type { IdeId, PluginInstallationMethod } from '@shared-kernel/types.js'; +import type { InstalledPlugin } from '../types.js'; import { getIntegration, getIntegrations } from '../registry.js'; import { downloadSkills } from './local.js'; diff --git a/src/integrations/types.ts b/src/integrations/types.ts index 259ec67..bb8bd47 100644 --- a/src/integrations/types.ts +++ b/src/integrations/types.ts @@ -1,9 +1,7 @@ import type { ChildProcess } from 'node:child_process'; +import type { IdeId, PluginInstallationMethod } from '@shared-kernel/types.js'; import type { McpServerName, McpServerStatus } from './mcp/servers.js'; -export type IdeId = 'claude' | 'cursor' | 'codex'; - -export type PluginInstallationMethod = 'cli' | 'download'; export type InstalledPlugin = { ide: IdeId; via: PluginInstallationMethod; diff --git a/src/lib/session.ts b/src/lib/session.ts index a8ce569..f8d3e8d 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -1,43 +1,132 @@ import { randomUUID } from 'node:crypto'; -import type { DetectedProvider } from '@providers/types.js'; -import type { PluginInstallationMethod } from '@integrations/types.js'; - -export type ChosenIde = 'claude' | 'cursor' | 'codex'; - -export type OnboardingGoal = 'feature-flags' | 'session-recordings' | 'event-tracking'; - -export type FrameworkSource = 'detected' | 'selected'; - -export type DebugEntry = { - screen: ScreenId; - input: string; - output: string; -}; +import type { + IdeId, + OnboardingGoal, + PluginInstallationMethod, + DetectedProvider, +} from '@shared-kernel/types.js'; export type WizardSession = { + /** + * Unique identifier for this wizard run. + * @default crypto.randomUUID() + */ sessionId: string; + /** + * Screen the wizard is currently displaying. + * @default ScreenId.Welcome + */ currentScreen: ScreenId; + /** + * Detected or user-selected framework identifier. + * @default null + * @example "react", "nextjs", "node" + */ framework: string | null; + /** + * How the framework value was obtained — auto-detected or manually selected. + * @default null + */ frameworkSource: FrameworkSource | null; + /** + * Screens the user has already passed through in this session. + * @default new Set() + */ completedScreens: Set; + /** + * Chronological log of user interactions, used by the debug overlay. + * @default [] + */ debugLog: DebugEntry[]; + /** + * When true, all side effects (auth, installs, onboarding) are simulated. + * @default false + */ dryRun: boolean; + /** + * When true, the debug log overlay is visible. + * @default false + */ debug: boolean; + /** + * Absolute path to the project being onboarded. + * @default process.cwd() + */ projectDir: string; + /** + * Results of prerequisite checks keyed by check name. + * @default {} + * @example { "node": { name: "node", found: true, version: "24.1.0" } } + */ systemChecks: Record; + /** + * Current authentication state and credentials. + * @default { status: 'idle' } + */ authState: AuthState; - ide: ChosenIde | null; - pluginTargets: ChosenIde[]; + /** + * IDE the user chose for the onboarding flow. + * @default null + */ + ide: IdeId | null; + /** + * IDEs that received plugin installations during this session. + * @default [] + */ + pluginTargets: IdeId[]; + /** + * How plugins were installed — via CLI marketplace or local download. + * @default null + */ pluginInstallMethod: PluginInstallationMethod | null; + /** + * MCP server names that were successfully connected. + * @default [] + * @see {@link ScreenId.ConnectTools} + */ connectedMcps: string[]; + /** + * Whether the project directory was empty at the start of onboarding. + * @default false + */ isEmptyProject: boolean; + /** + * Competing feature-flag providers found in the project's dependencies. + * @default [] + */ detectedProviders: DetectedProvider[]; + /** + * Goals the user selected for the onboarding session. + * @default [] + */ onboardingGoals: OnboardingGoal[]; + /** + * Latest status line emitted by the onboarding process. + * @default "" + */ onboardingStatus: string; + /** + * Path to the generated quickstart report, relative to the project dir. + * @default null + * @example "CONFIDENCE_QUICKSTART.md" + */ reportFile: string | null; + /** + * Human-readable summaries of files created or modified during onboarding. + * @default [] + * @example ["Added @spotify-confidence/sdk", "Created confidence.config.ts"] + */ codeChanges: string[]; }; +export type FrameworkSource = 'detected' | 'selected'; + +export type DebugEntry = { + screen: ScreenId; + input: string; + output: string; +}; + export type CheckResult = { name: string; found: boolean; diff --git a/src/providers/index.ts b/src/providers/index.ts index d5d8e9c..9f66de0 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -1,11 +1,12 @@ -import type { ProviderConfig, DetectedProvider } from './types.js'; +import type { DetectedProvider } from '@shared-kernel/types.js'; +import type { ProviderConfig } from './types.js'; import { readNpmDeps, readPypiDeps, readGoModDeps } from './deps/index.js'; import { eppoProvider } from './eppo/index.js'; import { optimizelyProvider } from './optimizely/index.js'; import { posthogProvider } from './posthog/index.js'; import { statsigProvider } from './statsig/index.js'; -export type { ProviderConfig, DetectedProvider } from './types.js'; +export type { ProviderConfig } from './types.js'; const PROVIDERS: ProviderConfig[] = [ eppoProvider, diff --git a/src/providers/types.ts b/src/providers/types.ts index a9575e6..04c3499 100644 --- a/src/providers/types.ts +++ b/src/providers/types.ts @@ -1,4 +1,4 @@ -export type ProviderId = 'eppo' | 'optimizely' | 'posthog' | 'statsig'; +import type { ProviderId } from '@shared-kernel/types.js'; export type ProviderConfig = { id: ProviderId; @@ -10,5 +10,3 @@ export type ProviderConfig = { gomod?: string[]; }; }; - -export type DetectedProvider = Pick; diff --git a/src/shared-kernel/index.ts b/src/shared-kernel/index.ts new file mode 100644 index 0000000..24c9299 --- /dev/null +++ b/src/shared-kernel/index.ts @@ -0,0 +1,7 @@ +export type { + IdeId, + OnboardingGoal, + PluginInstallationMethod, + ProviderId, + DetectedProvider, +} from './types.js'; diff --git a/src/shared-kernel/types.ts b/src/shared-kernel/types.ts new file mode 100644 index 0000000..86dd871 --- /dev/null +++ b/src/shared-kernel/types.ts @@ -0,0 +1,13 @@ +export type IdeId = 'claude' | 'cursor' | 'codex'; + +export type OnboardingGoal = 'feature-flags' | 'session-recordings' | 'event-tracking'; + +export type PluginInstallationMethod = 'cli' | 'download'; + +export type ProviderId = 'eppo' | 'optimizely' | 'posthog' | 'statsig'; + +export type DetectedProvider = { + id: ProviderId; + name: string; + skillName: string; +}; diff --git a/src/ui/tui/screens/connect-tools/useMcpConnect.ts b/src/ui/tui/screens/connect-tools/useMcpConnect.ts index eb3bb46..44b048f 100644 --- a/src/ui/tui/screens/connect-tools/useMcpConnect.ts +++ b/src/ui/tui/screens/connect-tools/useMcpConnect.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; +import type { IdeId } from '@shared-kernel/types.js'; import { - type IdeId, type McpServer, type McpServerName, type McpServerStatus, diff --git a/src/ui/tui/screens/done/DoneScreen.tsx b/src/ui/tui/screens/done/DoneScreen.tsx index ba96d69..643c6ef 100644 --- a/src/ui/tui/screens/done/DoneScreen.tsx +++ b/src/ui/tui/screens/done/DoneScreen.tsx @@ -13,7 +13,7 @@ import { useIsShort } from '@ui/tui/hooks/useIsShort.js'; import { doneOptions } from './actions.js'; import { useScreenDescription } from './useScreenDescription.js'; import { useSkippedOnboarding } from './useSkippedOnboarding.js'; -import { useChosenIdeName } from './useChosenIdeName.js'; +import { useIdeIdName } from './useIdeIdName.js'; const MAX_SHOWN_CHANGES = 5; @@ -22,7 +22,7 @@ export function DoneScreen() { const { reportFile, codeChanges, projectDir } = useSession(); const skipped = useSkippedOnboarding(); - const ideName = useChosenIdeName(); + const ideName = useIdeIdName(); const description = useScreenDescription(); const isShort = useIsShort(); diff --git a/src/ui/tui/screens/done/useChosenIdeName.ts b/src/ui/tui/screens/done/useIdeIdName.ts similarity index 83% rename from src/ui/tui/screens/done/useChosenIdeName.ts rename to src/ui/tui/screens/done/useIdeIdName.ts index 7b14adc..527ded4 100644 --- a/src/ui/tui/screens/done/useChosenIdeName.ts +++ b/src/ui/tui/screens/done/useIdeIdName.ts @@ -1,7 +1,7 @@ import { getIntegration } from '@integrations/index.js'; import { useSession } from '@ui/tui/store.js'; -export function useChosenIdeName() { +export function useIdeIdName() { const { ide } = useSession(); return ide ? getIntegration(ide).name : null; } diff --git a/src/ui/tui/screens/done/useScreenDescription.ts b/src/ui/tui/screens/done/useScreenDescription.ts index 0a1b8a2..1a11fa0 100644 --- a/src/ui/tui/screens/done/useScreenDescription.ts +++ b/src/ui/tui/screens/done/useScreenDescription.ts @@ -1,12 +1,12 @@ import { useSession } from '../../store.js'; -import { useChosenIdeName } from './useChosenIdeName.js'; +import { useIdeIdName } from './useIdeIdName.js'; import { useSkippedOnboarding } from './useSkippedOnboarding.js'; export function useScreenDescription() { const { detectedProviders, pluginTargets } = useSession(); const skipped = useSkippedOnboarding(); - const ideName = useChosenIdeName(); + const ideName = useIdeIdName(); const hasPlugins = pluginTargets.length > 0; const hasProviders = detectedProviders.length > 0; diff --git a/src/ui/tui/screens/install-plugins/InstallPluginsScreen.tsx b/src/ui/tui/screens/install-plugins/InstallPluginsScreen.tsx index cb0df50..79f4ef0 100644 --- a/src/ui/tui/screens/install-plugins/InstallPluginsScreen.tsx +++ b/src/ui/tui/screens/install-plugins/InstallPluginsScreen.tsx @@ -4,7 +4,8 @@ import { Colors, Icons } from '../../styles.js'; import { MainLayout } from '../../components/MainLayout.js'; import { TaskList } from '../../components/TaskList.js'; import { buildWizardTasks } from '../../lib/wizard-tasks.js'; -import { type IdeId, getIntegrations } from '@integrations/index.js'; +import type { IdeId } from '@shared-kernel/types.js'; +import { getIntegrations } from '@integrations/index.js'; import { PLUGIN_REPO_URL } from '@lib/constants.js'; import { ScreenId } from '@lib/session.js'; import { useAutoAdvance } from '../../hooks/useAutoAdvance.js'; diff --git a/src/ui/tui/screens/install-plugins/actions.ts b/src/ui/tui/screens/install-plugins/actions.ts index 07d6b7d..65d69f4 100644 --- a/src/ui/tui/screens/install-plugins/actions.ts +++ b/src/ui/tui/screens/install-plugins/actions.ts @@ -1,11 +1,11 @@ -import type { ChosenIde } from '@lib/session.js'; +import type { IdeId } from '@shared-kernel/types.js'; import type { PromptOption } from '../../components/PromptPanel.js'; -export type IdeSelectValue = ChosenIde; +export type IdeSelectValue = IdeId; export type DetectedSelectValue = IdeSelectValue | 'continue'; -export const IDE_SELECT_OPTIONS: PromptOption[] = [ +export const IDE_SELECT_OPTIONS: PromptOption[] = [ { label: 'Claude Code', value: 'claude' }, { label: 'Cursor', value: 'cursor' }, { label: 'Codex', value: 'codex' }, diff --git a/src/ui/tui/screens/install-plugins/telemetry-events.ts b/src/ui/tui/screens/install-plugins/telemetry-events.ts index fac5bdf..049c95b 100644 --- a/src/ui/tui/screens/install-plugins/telemetry-events.ts +++ b/src/ui/tui/screens/install-plugins/telemetry-events.ts @@ -1,4 +1,4 @@ -import type { PluginInstallationMethod } from '@integrations/types.js'; +import type { PluginInstallationMethod } from '@shared-kernel/types.js'; import type { TelemetryEvent } from '@lib/telemetry.js'; export function pluginsAlreadyDetected(): TelemetryEvent { diff --git a/src/ui/tui/screens/install-plugins/useInitialDetection.ts b/src/ui/tui/screens/install-plugins/useInitialDetection.ts index f548a79..3b8a1aa 100644 --- a/src/ui/tui/screens/install-plugins/useInitialDetection.ts +++ b/src/ui/tui/screens/install-plugins/useInitialDetection.ts @@ -1,18 +1,18 @@ import { useCallback, useEffect, useState } from 'react'; import { type InstalledPlugin, detectInstalledPlugins } from '@integrations/index.js'; -import type { ChosenIde } from '@lib/session.js'; +import type { IdeId } from '@shared-kernel/types.js'; import { useSession, store } from '../../store.js'; import type { PluginPhase } from './usePluginInstall.js'; export type InitialDetection = { phase: PluginPhase; - detected: ChosenIde[]; + detected: IdeId[]; }; export function useInitialDetection(): InitialDetection { const session = useSession(); const [phase, setPhase] = useState(session.dryRun ? 'choose-ide' : 'detecting'); - const [detected, setDetected] = useState([]); + const [detected, setDetected] = useState([]); const applyResults = useCallback(function applyResults(found: InstalledPlugin[]) { const ides = found.map((d) => d.ide); diff --git a/src/ui/tui/screens/install-plugins/usePluginInstall.ts b/src/ui/tui/screens/install-plugins/usePluginInstall.ts index c5c5fc7..ea2c271 100644 --- a/src/ui/tui/screens/install-plugins/usePluginInstall.ts +++ b/src/ui/tui/screens/install-plugins/usePluginInstall.ts @@ -1,7 +1,6 @@ import { useState } from 'react'; -import type { IdeId } from '@integrations/index.js'; +import type { IdeId } from '@shared-kernel/types.js'; import { prepareIde, installPlugin } from '@integrations/index.js'; -import type { ChosenIde } from '@lib/session.js'; import { track } from '@lib/telemetry.js'; import { $session, store } from '../../store.js'; import { useInitialDetection } from './useInitialDetection.js'; @@ -12,7 +11,7 @@ export type PluginPhase = export type PluginInstallState = { phase: PluginPhase; - detected: ChosenIde[]; + detected: IdeId[]; error: string | null; selectIde: (ide: IdeId) => void; }; diff --git a/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx b/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx index 181f1ba..7883c06 100644 --- a/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx +++ b/src/ui/tui/screens/onboard-project/components/OnboardingLeftPanel.tsx @@ -3,7 +3,7 @@ import { Spinner } from '@inkjs/ui'; import { Colors, Emoji, Icons } from '../../../styles.js'; import { StatusFeed } from '../../../components/StatusFeed.js'; import { TipCard } from '../../../components/TipCard.js'; -import type { OnboardingGoal } from '@lib/session.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; import type { OnboardingPhase } from '../useOnboardingProcess.js'; import type { StatusLine } from '../../../lib/status-line.js'; import type { Tip } from '../../../lib/tips.js'; diff --git a/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts b/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts index eb7d470..569fa12 100644 --- a/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts +++ b/src/ui/tui/screens/onboard-project/useOnboardingProcess.ts @@ -1,9 +1,10 @@ import { useCallback, useRef, useState } from 'react'; import { type ChildProcess } from 'node:child_process'; -import { buildOnboardingPrompt } from '@lib/onboarding-prompt/index.js'; +import { buildOnboardingPrompt } from '@features/onboarding/index.js'; import { detectFramework } from '@frameworks/index.js'; -import { ScreenId, type OnboardingGoal } from '@lib/session.js'; -import { type IdeId, getIntegration, normalizeStatusLine } from '@integrations/index.js'; +import type { IdeId, OnboardingGoal } from '@shared-kernel/types.js'; +import { ScreenId } from '@lib/session.js'; +import { getIntegration, normalizeStatusLine } from '@integrations/index.js'; import { useLogger } from '../../hooks/useLog.js'; import { $session, store, isStaleSession } from '../../store.js'; import { useInitialOnboarding } from './useInitialOnboarding.js'; diff --git a/src/ui/tui/screens/select-goal/actions.ts b/src/ui/tui/screens/select-goal/actions.ts index 1030700..177e7f2 100644 --- a/src/ui/tui/screens/select-goal/actions.ts +++ b/src/ui/tui/screens/select-goal/actions.ts @@ -1,4 +1,4 @@ -import type { OnboardingGoal } from '@lib/session.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; import type { PromptOption } from '../../components/PromptPanel.js'; const BASE_GOALS: PromptOption[] = [ diff --git a/src/ui/tui/screens/select-goal/useGoalSelection.ts b/src/ui/tui/screens/select-goal/useGoalSelection.ts index b62de43..da3f545 100644 --- a/src/ui/tui/screens/select-goal/useGoalSelection.ts +++ b/src/ui/tui/screens/select-goal/useGoalSelection.ts @@ -1,4 +1,4 @@ -import type { OnboardingGoal } from '@lib/session.js'; +import type { OnboardingGoal } from '@shared-kernel/types.js'; import { ScreenId } from '@lib/session.js'; import { BROWSER_PLATFORMS } from '@lib/sdk-options.js'; import { track } from '@lib/telemetry.js'; diff --git a/src/ui/tui/store.ts b/src/ui/tui/store.ts index 066bdfd..8aa6fa6 100644 --- a/src/ui/tui/store.ts +++ b/src/ui/tui/store.ts @@ -1,18 +1,20 @@ import { atom } from 'nanostores'; import { useStore } from '@nanostores/react'; +import type { + IdeId, + OnboardingGoal, + PluginInstallationMethod, + DetectedProvider, +} from '@shared-kernel/types.js'; import { type WizardSession, type CheckResult, type AuthState, type DebugEntry, type FrameworkSource, - type OnboardingGoal, ScreenId, createSession, } from '@lib/session.js'; -import type { ChosenIde } from '@lib/session.js'; -import type { PluginInstallationMethod } from '@integrations/types.js'; -import type { DetectedProvider } from '@providers/types.js'; export type StoreOptions = { dryRun?: boolean; @@ -75,12 +77,12 @@ export const store = { authState, }), - setIde: (ide: ChosenIde): void => + setIde: (ide: IdeId): void => updateSession({ ide, }), - setPluginTargets: (plugins: ChosenIde[]): void => + setPluginTargets: (plugins: IdeId[]): void => updateSession({ pluginTargets: plugins, }), diff --git a/tsconfig.build.json b/tsconfig.build.json index 0cae768..9d9273d 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -15,9 +15,11 @@ "rootDir": ".", "paths": { "@commands/*": ["./src/commands/*"], + "@features/*": ["./src/features/*"], "@frameworks/*": ["./src/frameworks/*"], "@integrations/*": ["./src/integrations/*"], "@providers/*": ["./src/providers/*"], + "@shared-kernel/*": ["./src/shared-kernel/*"], "@ui/*": ["./src/ui/*"], "@lib/*": ["./src/lib/*"] } diff --git a/tsdown.config.ts b/tsdown.config.ts index bd7a454..fe40c03 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'tsdown'; import { copyFileSync, mkdirSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; -const STEPS_SRC = 'src/lib/onboarding-prompt/steps'; +const STEPS_SRC = 'src/features/onboarding/steps'; const STEPS_DIST = 'dist/bin'; export default defineConfig({ diff --git a/vitest.config.ts b/vitest.config.ts index 8ffe454..7369bcf 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -6,9 +6,11 @@ export default defineConfig({ resolve: { alias: { '@commands': new URL('./src/commands', import.meta.url).pathname, + '@features': new URL('./src/features', import.meta.url).pathname, '@frameworks': new URL('./src/frameworks', import.meta.url).pathname, '@integrations': new URL('./src/integrations', import.meta.url).pathname, '@providers': new URL('./src/providers', import.meta.url).pathname, + '@shared-kernel': new URL('./src/shared-kernel', import.meta.url).pathname, '@ui': new URL('./src/ui', import.meta.url).pathname, '@lib': new URL('./src/lib', import.meta.url).pathname, },