diff --git a/.claude/skills/adding-framework-support/SKILL.md b/.claude/skills/adding-framework-support/SKILL.md index a7ec93fc1..03cab45b7 100644 --- a/.claude/skills/adding-framework-support/SKILL.md +++ b/.claude/skills/adding-framework-support/SKILL.md @@ -20,33 +20,33 @@ creating its own runner or changing existing routing defaults. ## Extend the framework configuration -Start with [FrameworkConfig](../../../src/lib/framework-config.ts) and a nearby -example under [src/frameworks](../../../src/frameworks/). Framework-specific -detection, context, environment conventions, and UI metadata belong here. -Integration instructions and examples belong in context-mill. - -1. Add the integration to [Integration](../../../src/lib/constants.ts). Its - order controls first-match detection and the framework picker. Keep specific - frameworks before language fallbacks and generic Node last; preserve the - overlap rules in the - [detection checks](../../../src/lib/detection/__tests__/framework.test.ts). -2. Add the config under `src/frameworks//-wizard-agent.ts`. Use a +Start with [FrameworkConfig](../../../src/store/framework-config.ts) and a +nearby example under [src/store/frameworks](../../../src/store/frameworks/). +Framework-specific detection, context, environment conventions, and UI metadata +belong here. Integration instructions and examples belong in context-mill. + +1. Add the integration to [Integration](../../../src/store/shared/constants.ts). + Its order controls first-match detection and the framework picker. Keep + specific frameworks before language fallbacks and generic Node last; preserve + the overlap rules in the + [detection checks](../../../src/store/detection/__tests__/framework.test.ts). +2. Add the config under `src/store/frameworks//-wizard-agent.ts`. Use a `type` for framework context so it satisfies `Record`. Export the config; the integration program already supplies execution. -3. Import the config into [FRAMEWORK_REGISTRY](../../../src/lib/registry.ts). +3. Import the config into [FRAMEWORK_REGISTRY](../../../src/store/registry.ts). The display label comes from `metadata.name`. Read the current interface for the complete required fields. In particular, `detection.detectPackageManager` is required: reuse an adapter from -[package-manager detection](../../../src/lib/detection/package-manager.ts). Use -`metadata.setup.questions` for unresolved project variants; `gatherContext` +[package-manager detection](../../../src/store/detection/package-manager.ts). +Use `metadata.setup.questions` for unresolved project variants; `gatherContext` collects framework context. Optional notices and extra MCP servers also belong in metadata. Use `usesPackageJson: false` for frameworks without a package.json dependency. Their required `getVersion` callback can return `undefined`. Minimum-version checking requires both `minimumVersion` and `getInstalledVersion`; unknown -versions pass. [Context detection](../../../src/lib/detection/context.ts) +versions pass. [Context detection](../../../src/store/detection/context.ts) returns unsupported-version data for the integration UI rather than aborting itself. @@ -54,15 +54,15 @@ itself. | Starting point | Pattern to reuse | | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| [Next.js](../../../src/frameworks/nextjs/) | `hasDeclaredDependency` from `utils/package-json`, `tryGetPackageJson` from `utils/setup-utils`, and router setup questions | -| [Django](../../../src/frameworks/django/) | Python project files, context gathering, and Python package-manager detection | -| [Laravel](../../../src/frameworks/laravel/) | Composer and framework-specific filesystem signals | -| [Rails](../../../src/frameworks/rails/) | Gemfile detection and Ruby conventions | +| [Next.js](../../../src/store/frameworks/nextjs/) | `hasDeclaredDependency` from `utils/package-json`, `tryGetPackageJson` from `utils/setup-utils`, and router setup questions | +| [Django](../../../src/store/frameworks/django/) | Python project files, context gathering, and Python package-manager detection | +| [Laravel](../../../src/store/frameworks/laravel/) | Composer and framework-specific filesystem signals | +| [Rails](../../../src/store/frameworks/rails/) | Gemfile detection and Ruby conventions | -Use [bounded filesystem helpers](../../../src/utils/bounded-fs.ts) for project -scans and reads. They bound traversal and skip dependency/build directories; add -framework-specific exclusions with `extraIgnore`. Keep complex parsers and -detectors beside the config so they can be checked independently. +Use [bounded filesystem helpers](../../../src/store/shared/bounded-fs.ts) for +project scans and reads. They bound traversal and skip dependency/build +directories; add framework-specific exclusions with `extraIgnore`. Keep complex +parsers and detectors beside the config so they can be checked independently. ## Complete the content side @@ -71,7 +71,7 @@ matching integration reference and task-skill variants for the framework. A registry entry alone does not provide integration knowledge. The orchestrator resolves framework variants from the skill menu and rejects missing task variants; see the -[orchestrator runner](../../../src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts). +[orchestrator runner](../../../src/agent/runner/sequence/orchestrator/orchestrator-runner.ts). Keep project-specific facts in configuration and reusable integration guidance in that content. Model IDs, reasoning efforts, and gateway-required system @@ -88,7 +88,7 @@ content-mill variants. For an end-to-end run, use a disposable test app and the [exploration guide](../exploring-the-wizard/SKILL.md). For prompt, environment-upload, or outro changes, inspect the current -[integration program](../../../src/lib/programs/posthog-integration/) and the +[integration program](../../../src/store/programs/posthog-integration/) and the selected sequence. Some fields remain in the interface without a current consumer: `getOutroNextSteps` is not used by the integration outro. Linear post-run/outro hooks are not shared by the orchestrator; see the diff --git a/.claude/skills/adding-skill-program/SKILL.md b/.claude/skills/adding-skill-program/SKILL.md index 883d63108..ddbc1952a 100644 --- a/.claude/skills/adding-skill-program/SKILL.md +++ b/.claude/skills/adding-skill-program/SKILL.md @@ -21,9 +21,8 @@ guide owns the fallback criteria and gateway model/effort/system-prompt contract. These are contribution defaults. Current runtime -[bindings](../../../src/lib/agent/runner/switchboard/index.ts) still default -many programs to Anthropic plus linear; documentation changes do not migrate -them. +[bindings](../../../src/agent/runner/switchboard/index.ts) still default many +programs to Anthropic plus linear; documentation changes do not migrate them. ## Choose the contribution surface @@ -31,11 +30,11 @@ them. can express the workflow. [Context-mill](https://github.com/PostHog/context-mill) owns skill content and `cliEntries`. A new skill-backed child of an existing family ships through - context-mill; inspect - [family dispatch](../../../src/lib/programs/dispatch-family.ts). Unpromoted - skills run through [the skill command](../../../src/commands/skill.ts). + context-mill; inspect [family dispatch](../../../src/cli/dispatch-family.ts). + Unpromoted skills run through + [the skill command](../../../src/cli/commands/skill.ts). - **Native program:** use a - [ProgramConfig](../../../src/lib/programs/program-step.ts) when the wizard + [ProgramConfig](../../../src/store/programs/program-step.ts) when the wizard needs its own flow, screens, detection, composition, or other native behavior. Keep product instructions in context-mill. @@ -45,32 +44,33 @@ is `id`, not the retired `flowKey`. ## Build a native orchestrator program -Use [metrics](../../../src/lib/programs/metrics/) as the current Pi/orchestrator -example and read the +Use [metrics](../../../src/store/programs/metrics/) as the current +Pi/orchestrator example and read the [runner architecture](../wizard-development/references/ARCHITECTURE.md) when changing execution behavior. -1. Add the program config under `src/lib/programs//`. Set `agentFlow` when - its content-mill flow differs from `id`; setting it explicitly also documents - the content dependency. Keep a `run` definition so the outer runner executes - agent work. +1. Add the program config under `src/store/programs//`. Set `agentFlow` + when its content-mill flow differs from `id`; setting it explicitly also + documents the content dependency. Keep a `run` definition so the outer runner + executes agent work. 2. Supply the flow's seed and task prompts in context-mill, including the task dependencies and applicable skill variants. The - [orchestrator](../../../src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts) + [orchestrator](../../../src/agent/runner/sequence/orchestrator/orchestrator-runner.ts) loads `agentFlow ?? id`, requires a seed prompt, and checks task-skill variants before running. `run.skillId` alone does not define this flow. 3. Register the config in - [PROGRAM_REGISTRY](../../../src/lib/programs/program-registry.ts) and add its - Pi/orchestrator entry to - [PROGRAM_BINDINGS](../../../src/lib/agent/runner/switchboard/index.ts). - [Existing binding checks](../../../src/lib/agent/runner/__tests__/switchboard.test.ts) + [PROGRAM_REGISTRY](../../../src/store/programs/program-registry.ts) and add + its Pi/orchestrator entry to + [PROGRAM_BINDINGS](../../../src/agent/runner/switchboard/index.ts). + [Existing binding checks](../../../src/agent/runner/__tests__/switchboard.test.ts) enforce coverage; `ProgramId` currently widens to `string`. 4. For a standalone native command, create a command module with - [nativeCommandFactory](../../../src/commands/factories/native-command-factory.ts) + [nativeCommandFactory](../../../src/cli/commands/factories/native-command-factory.ts) and register it in [bin.ts](../../../bin.ts). A native family child uses the handlers in family dispatch. Program registration derives screen sequences and store lookup, not the top-level CLI `.use()` chain. -5. Check [program OAuth scopes](../../../src/lib/oauth/program-scopes.ts) +5. Check + [program OAuth scopes](../../../src/store/services/oauth/program-scopes.ts) against the tools the program needs; add scopes only when the base set is insufficient. @@ -82,53 +82,51 @@ or changing gateway-required prompt material. ## Simple linear programs and existing flows For a very simple linear flow, use -[createSkillProgram](../../../src/lib/programs/agent-skill/index.ts) to +[createSkillProgram](../../../src/store/programs/agent-skill/index.ts) to configure installation of one skill. Register the native program as above with an explicit Pi/linear binding; the factory does not select a sequence. Read `SkillProgramOptions` for required fields; -[audit](../../../src/lib/programs/audit/) demonstrates factory customization and -a dynamic `run(session)` that seeds a ledger. -[Revenue analytics](../../../src/lib/programs/revenue-analytics/) builds its +[audit](../../../src/store/programs/audit/) demonstrates factory customization +and a dynamic `run(session)` that seeds a ledger. +[Revenue analytics](../../../src/store/programs/revenue-analytics/) builds its config directly and adds prerequisite detection. `ProgramRun.customPrompt`, `abortCases`, `postRun`, and `buildOutroData` are -consumed by the -[linear sequence](../../../src/lib/agent/runner/sequence/linear.ts). `postRun` -runs after success; `buildOutroData` receives session and credentials, with host -information inside credentials. The orchestrator currently uses its own task -prompts, failure handling, and outro, and does not invoke those hooks. Check -this limitation before migrating a linear flow; setting an orchestrator binding -does not preserve these behaviors automatically. +consumed by the [linear sequence](../../../src/agent/runner/sequence/linear.ts). +`postRun` runs after success; `buildOutroData` receives session and credentials, +with host information inside credentials. The orchestrator currently uses its +own task prompts, failure handling, and outro, and does not invoke those hooks. +Check this limitation before migrating a linear flow; setting an orchestrator +binding does not preserve these behaviors automatically. ## Screens, prerequisites, and composition -Reuse [AGENT_SKILL_STEPS](../../../src/lib/programs/agent-skill/steps.ts): +Reuse [AGENT_SKILL_STEPS](../../../src/store/programs/agent-skill/steps.ts): intro, health check, auth, run, outro, and keep-skills. Auth also applies the -shared [AI opt-in gate](../../../src/lib/programs/ai-opt-in-gate.ts) for agent +shared [AI opt-in gate](../../../src/store/programs/ai-opt-in-gate.ts) for agent programs. Override `screenId`, not `screen`, when adapting a step. New screens -need an entry in [ScreenId](../../../src/ui/tui/screen-sequences.ts), a -component, and registration in -[screen-registry](../../../src/ui/tui/screen-registry.tsx). Follow -[ink-tui](../ink-tui/SKILL.md) for rendering and store usage. +need an entry in [ScreenId](../../../src/tui/screen-sequences.ts), a component, +and registration in [screen-registry](../../../src/tui/screen-registry.tsx). +Follow [ink-tui](../ink-tui/SKILL.md) for rendering and store usage. Use a headless step's `onReady` for session-dependent detection, then render structured `frameworkContext.detectError` data in the intro. `onInit` runs when the TUI starts rendering with its initial session; `onReady` runs after the real -session is assigned. See [store hooks](../../../src/ui/tui/store.ts) and -[run-wizard](../../../src/lib/runners/run-wizard.ts). The -[noninteractive runner](../../../src/lib/runners/run-non-interactive.ts) also +session is assigned. See [store hooks](../../../src/store/state/store.ts) and +[run-wizard](../../../src/cli/runners/run-wizard.ts). The +[noninteractive runner](../../../src/cli/runners/run-non-interactive.ts) also walks `onReady` by default; set `ciPreRun` only when it needs a different prerequisite strategy. `requires` currently records metadata; it does not execute or enforce prior programs. Compose real work through `ProgramStep.run`, with `onRunPrep` and `targetDir` when needed. The -[integration run step](../../../src/lib/programs/posthog-integration/index.ts) -and [self-driving](../../../src/lib/programs/self-driving/) demonstrate this. +[integration run step](../../../src/store/programs/posthog-integration/index.ts) +and [self-driving](../../../src/store/programs/self-driving/) demonstrate this. Composed sub-runs are structurally linear; orchestrators cannot nest. A host run step without `run` can also set `targetDir` and `onRunPrep` to scope the program's own agent to a picked project and keep its sequence, as -[error-tracking](../../../src/lib/programs/error-tracking/) does. +[error-tracking](../../../src/store/programs/error-tracking/) does. ## Validate the affected path diff --git a/.claude/skills/exploring-the-wizard/SKILL.md b/.claude/skills/exploring-the-wizard/SKILL.md index 50dbc7160..4310f08d1 100644 --- a/.claude/skills/exploring-the-wizard/SKILL.md +++ b/.claude/skills/exploring-the-wizard/SKILL.md @@ -114,7 +114,7 @@ MCP snapshots are plain `.txt`; the CI snapshot route writes colored `.ans` frames. Keep the screen path and failure evidence with the snapshots. Do not stop a progressing run at an invented turn count: the MCP exposes no turn limit; Pi's continuation and tool-call guards are described in its -[harness README](../../../src/lib/agent/runner/harness/pi/README.md). +[harness README](../../../src/agent/runner/harness/pi/README.md). ## Sweep the workbench @@ -129,5 +129,5 @@ The shared log is `/tmp/posthog-wizard.log`. Record its byte count before a run and read from that count plus one afterward. Run sweeps serially so their logs remain attributable. `read_state` omits `frameworkContext`; an empty `setupQuestions` list alone does not prove a router mode. When necessary, -inspect the detector under [`src/frameworks/`](../../../src/frameworks/) against +inspect the detector under [`src/store/frameworks/`](../../../src/store/frameworks/) against the same fixture. diff --git a/.claude/skills/ink-tui/SKILL.md b/.claude/skills/ink-tui/SKILL.md index 590640ee6..d8e900b27 100644 --- a/.claude/skills/ink-tui/SKILL.md +++ b/.claude/skills/ink-tui/SKILL.md @@ -34,13 +34,13 @@ conventions rather than copying upstream component manuals. ## Add a screen -1. Create a component in [screens](../../../src/ui/tui/screens/). +1. Create a component in [screens](../../../src/tui/screens/). 2. Add its `ScreenId` in - [screen-sequences.ts](../../../src/ui/tui/screen-sequences.ts). + [screen-sequences.ts](../../../src/tui/screen-sequences.ts). 3. Register the component in - [screen-registry.tsx](../../../src/ui/tui/screen-registry.tsx). + [screen-registry.tsx](../../../src/tui/screen-registry.tsx). 4. Reference it through `screenId` in the owning - [program's steps](../../../src/lib/programs/), with the appropriate + [program's steps](../../../src/store/programs/), with the appropriate visibility, completion, and gate predicates. Screen sequences derive from program steps. Do not hand-maintain a second @@ -49,27 +49,28 @@ service wiring depends on the screen's needs; `App` remains the shared shell. ## Preserve the UI boundary -Business logic calls [WizardUI](../../../src/ui/wizard-ui.ts) through -[getUI](../../../src/ui/index.ts). Screens use -[WizardStore](../../../src/ui/tui/store.ts) setters for reactive changes. The -router resolves program screens from session predicates; overlays interrupt that -resolution. Local state is appropriate for presentation details such as tab +Business logic calls [WizardUI](../../../src/store/ui/wizard-ui.ts) through +[getUI](../../../src/store/ui/index.ts). Screens use +[WizardStore](../../../src/store/state/store.ts) setters for reactive changes. +The router resolves program screens from session predicates; overlays interrupt +that resolution. Local state is appropriate for presentation details such as tab selection, not wizard progression. For new state, first decide whether it belongs in -[WizardSession](../../../src/lib/wizard-session.ts) or display-only store state. -Use an explicit setter that notifies subscribers. When business logic needs the -operation, extend `WizardUI`, [InkUI](../../../src/ui/tui/ink-ui.ts), and -[LoggingUI](../../../src/ui/logging-ui.ts) together. Reuse existing enums and -union types rather than introducing competing status vocabularies. +[WizardSession](../../../src/store/session/wizard-session.ts) or display-only +store state. Use an explicit setter that notifies subscribers. When business +logic needs the operation, extend `WizardUI`, +[InkUI](../../../src/store/ui/store-ui.ts), and +[LoggingUI](../../../src/tui/console/logging-ui.ts) together. Reuse existing +enums and union types rather than introducing competing status vocabularies. ## Reuse and check -Compose existing primitives and use [styles.ts](../../../src/ui/tui/styles.ts) -for shared colors, icons, and alignment. Export new public primitives from -[primitives/index.ts](../../../src/ui/tui/primitives/index.ts), add a realistic -[playground demo](../../../src/ui/tui/playground/demos/), and register it in -[PlaygroundApp.tsx](../../../src/ui/tui/playground/PlaygroundApp.tsx). +Compose existing primitives and use [styles.ts](../../../src/tui/styles.ts) for +shared colors, icons, and alignment. Export new public primitives from +[primitives/index.ts](../../../src/tui/primitives/index.ts), add a realistic +[playground demo](../../../src/tui/playground/demos/), and register it in +[PlaygroundApp.tsx](../../../src/tui/playground/PlaygroundApp.tsx). Run `pnpm try --playground` to inspect primitives. Use [exploring-the-wizard](../exploring-the-wizard/SKILL.md) when exercising actual diff --git a/.claude/skills/ink-tui/references/ARCHITECTURE.md b/.claude/skills/ink-tui/references/ARCHITECTURE.md index fdf59395c..d07484ae0 100644 --- a/.claude/skills/ink-tui/references/ARCHITECTURE.md +++ b/.claude/skills/ink-tui/references/ARCHITECTURE.md @@ -2,14 +2,14 @@ ## Ownership -| Surface | Owns | -| ----------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| [WizardSession](../../../../src/lib/wizard-session.ts) | Run configuration, decisions, credentials, and lifecycle state | -| [ProgramStep](../../../../src/lib/programs/program-step.ts) | Screens, visibility/completion predicates, gates, and initialization hooks | -| [screen-sequences.ts](../../../../src/ui/tui/screen-sequences.ts) | `ScreenId`, `Screen`, `Sequence`, and the derived `PROGRAM_SEQUENCES` | -| [WizardRouter](../../../../src/ui/tui/router.ts) | Resolution and the `Overlay` stack | -| [WizardStore](../../../../src/ui/tui/store.ts) | Reactive state, gate promises, display observations, and pending interactions | -| [WizardUI](../../../../src/ui/wizard-ui.ts) | Typed operations available to business logic | +| Surface | Owns | +| ---------------------------------------------------------------- | ----------------------------------------------------------------------------- | +| [WizardSession](../../../../src/store/session/wizard-session.ts) | Run configuration, decisions, credentials, and lifecycle state | +| [ProgramStep](../../../../src/store/programs/program-step.ts) | Screens, visibility/completion predicates, gates, and initialization hooks | +| [screen-sequences.ts](../../../../src/tui/screen-sequences.ts) | `ScreenId`, `Screen`, `Sequence`, and the derived `PROGRAM_SEQUENCES` | +| [WizardRouter](../../../../src/tui/router.ts) | Resolution and the `Overlay` stack | +| [WizardStore](../../../../src/store/state/store.ts) | Reactive state, gate promises, display observations, and pending interactions | +| [WizardUI](../../../../src/store/ui/wizard-ui.ts) | Typed operations available to business logic | ## Program screens @@ -17,14 +17,14 @@ entries: `id`, `show`, and `isComplete`. Completion defaults to the step's `gate` when no separate `isComplete` is provided. Steps without a screen are omitted, and the exit screen is appended. The projection applies -[withAiOptInGate](../../../../src/lib/programs/ai-opt-in-gate.ts) consistently +[withAiOptInGate](../../../../src/store/programs/ai-opt-in-gate.ts) consistently with store gate creation. `WizardRouter.resolve(session)` first checks the overlay stack, then returns the first visible, incomplete screen. It also handles the failed-authentication outro case. Follow this method and the -[router tests](../../../../src/ui/tui/__tests__/router.test.ts) for exact -behavior; there is no program cursor or `next()` API. +[router tests](../../../../src/store/__tests__/flow-resolution.test.ts) for +exact behavior; there is no program cursor or `next()` API. The screen sequence is a presentation projection of the program. It is distinct from the agent execution sequence selected by the runner; see @@ -40,13 +40,13 @@ Read `ProgramStep` before adding asynchronous work: assigned. Reserve it for work independent of that session. - `onReady` runs after the real session is assigned and is awaited in order. -[The store](../../../../src/ui/tui/store.ts) derives gate promises from the +[The store](../../../../src/store/state/store.ts) derives gate promises from the program. `getGate(stepId)` resolves once: a predicate becoming false later does not close it again. A missing gate returns a resolved promise. `waitUntil(predicate)` evaluates live state at the await point; use that distinction when a decision can change after startup. -[startTUI](../../../../src/ui/tui/start-tui.ts) invokes `runInitHooks` after +[startTUI](../../../../src/tui/start-tui.ts) invokes `runInitHooks` after rendering starts. Merely constructing a store for a test or playground does not start those effects. @@ -62,9 +62,9 @@ separate store atoms. Reuse the existing setters (`pushStatus`, `syncTodos`, `setEventPlan`) for those updates. Do not mutate session fields behind the store after attaching the session. -[InkUI](../../../../src/ui/tui/ink-ui.ts) translates `getUI()` calls into store -operations. Business logic should use this interface rather than import the -store; screens can use the store directly. +[InkUI](../../../../src/store/ui/store-ui.ts) translates `getUI()` calls into +store operations. Business logic should use this interface rather than import +the store; screens can use the store directly. ## Interaction requests and overlays @@ -75,12 +75,12 @@ Their cancellation methods settle pending requests and dismiss the corresponding overlay. Use the established methods rather than pushing a question overlay without its pending state or promise. -Read [WizardAskScreen](../../../../src/ui/tui/screens/WizardAskScreen.tsx), -[TaskNoticeScreen](../../../../src/ui/tui/screens/TaskNoticeScreen.tsx), and the +Read [WizardAskScreen](../../../../src/tui/screens/WizardAskScreen.tsx), +[TaskNoticeScreen](../../../../src/tui/screens/TaskNoticeScreen.tsx), and the matching store methods before changing their lifecycle. -[LoggingUI](../../../../src/ui/logging-ui.ts) rejects question requests, -declines optional task notices, and leaves the manual-auth-code promise pending; -it cannot collect terminal input. +[LoggingUI](../../../../src/tui/console/logging-ui.ts) rejects question +requests, declines optional task notices, and leaves the manual-auth-code +promise pending; it cannot collect terminal input. `Overlay` lives in the router; `ScreenName` is `ScreenId | Overlay`. Store `pushOverlay`/`popOverlay` wrappers notify subscribers and preserve transition @@ -89,17 +89,17 @@ actual overlay values from the enum; health checks are program screens. ## Components and services -[App](../../../../src/ui/tui/App.tsx) creates the service bundle and screen +[App](../../../../src/tui/App.tsx) creates the service bundle and screen registry, then renders -[ScreenContainer](../../../../src/ui/tui/primitives/ScreenContainer.tsx). The +[ScreenContainer](../../../../src/tui/primitives/ScreenContainer.tsx). The registry injects services where needed, such as the -[MCP installer](../../../../src/ui/tui/services/mcp-installer.ts). Prefer this +[MCP installer](../../../../src/tui/services/mcp-installer.ts). Prefer this boundary when a screen needs external operations rather than coupling a new component to step internals. `ScreenContainer` owns transitions, shared keyboard hints, viewport handling, and -[ScreenErrorBoundary](../../../../src/ui/tui/primitives/ScreenErrorBoundary.tsx). +[ScreenErrorBoundary](../../../../src/tui/primitives/ScreenErrorBoundary.tsx). The boundary records an error outro and run phase on render failure. When changing completion predicates, verify that failure and dismissal remain reachable; the boundary does not replace those predicates. diff --git a/.claude/skills/ink-tui/references/PATTERNS.md b/.claude/skills/ink-tui/references/PATTERNS.md index 3f530e742..e6b692b9b 100644 --- a/.claude/skills/ink-tui/references/PATTERNS.md +++ b/.claude/skills/ink-tui/references/PATTERNS.md @@ -3,14 +3,14 @@ Use existing screens and demos as examples; their props stay checked with the codebase. -| Task | Start here | -| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | -| Compose a run screen with conditional event-plan tab | [RunScreen](../../../../src/ui/tui/screens/RunScreen.tsx) | -| Build a program intro | [IntroScreenLayout](../../../../src/ui/tui/screens/IntroScreenLayout.tsx) | -| Compose a learning deck | [LearnCard](../../../../src/ui/tui/components/LearnCard.tsx), [LearnDeckDemo](../../../../src/ui/tui/playground/demos/LearnDeckDemo.tsx) | -| Compare layout primitives | [LayoutDemo](../../../../src/ui/tui/playground/demos/LayoutDemo.tsx) | -| Exercise picker and confirmation controls | [InputDemo](../../../../src/ui/tui/playground/demos/InputDemo.tsx) | -| Add an interaction modal | [WizardAskScreen](../../../../src/ui/tui/screens/WizardAskScreen.tsx), [AskModalDemo](../../../../src/ui/tui/playground/demos/AskModalDemo.tsx) | +| Task | Start here | +| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Compose a run screen with conditional event-plan tab | [RunScreen](../../../../src/tui/screens/RunScreen.tsx) | +| Build a program intro | [IntroScreenLayout](../../../../src/tui/screens/IntroScreenLayout.tsx) | +| Compose a learning deck | [LearnCard](../../../../src/tui/components/LearnCard.tsx), [LearnDeckDemo](../../../../src/tui/playground/demos/LearnDeckDemo.tsx) | +| Compare layout primitives | [LayoutDemo](../../../../src/tui/playground/demos/LayoutDemo.tsx) | +| Exercise picker and confirmation controls | [InputDemo](../../../../src/tui/playground/demos/InputDemo.tsx) | +| Add an interaction modal | [WizardAskScreen](../../../../src/tui/screens/WizardAskScreen.tsx), [AskModalDemo](../../../../src/tui/playground/demos/AskModalDemo.tsx) | ## Keep progression in session state @@ -21,14 +21,14 @@ through its session predicate and explicit setter. Do not create a parallel ## Keyboard handling -Use [useKeyBindings](../../../../src/ui/tui/hooks/useKeyBindings.ts) for visible +Use [useKeyBindings](../../../../src/tui/hooks/useKeyBindings.ts) for visible shortcuts: it couples handlers to labels in the shared hints bar. -[KeyboardHintsDemo](../../../../src/ui/tui/playground/demos/KeyboardHintsDemo.tsx) +[KeyboardHintsDemo](../../../../src/tui/playground/demos/KeyboardHintsDemo.tsx) shows the pattern. Reuse its `KeyMatch` vocabulary and choose a distinct registration id for each mounted control. For an ordinary-key dismissal, use -[useDismissOnAnyKey](../../../../src/ui/tui/hooks/useDismissOnAnyKey.ts). It +[useDismissOnAnyKey](../../../../src/tui/hooks/useDismissOnAnyKey.ts). It ignores Ctrl/Meta combinations so the global Ctrl+T HUD shortcut does not also dismiss the screen. @@ -43,11 +43,11 @@ handlers will receive the same key. Visible text belongs inside Ink `Text`. Reuse the shared color/alignment constants and the relevant primitive's border treatment. Use -[useStdoutDimensions](../../../../src/ui/tui/hooks/useStdoutDimensions.ts) when +[useStdoutDimensions](../../../../src/tui/hooks/useStdoutDimensions.ts) when layout must update on terminal resize; reading `useStdout` alone does not subscribe. Account for the shell's title, hints, tabs, status expansion, and optional HUD rather than allocating the full terminal height to screen content. -Write diagnostics through [logToFile](../../../../src/utils/debug.ts), which -uses the configured wizard log destination. Avoid introducing a separate +Write diagnostics through [logToFile](../../../../src/store/shared/debug.ts), +which uses the configured wizard log destination. Avoid introducing a separate hardcoded temporary log or writing debug lines into the live TUI. diff --git a/.claude/skills/ink-tui/references/PRIMITIVES.md b/.claude/skills/ink-tui/references/PRIMITIVES.md index 66c066cdc..92a88ead1 100644 --- a/.claude/skills/ink-tui/references/PRIMITIVES.md +++ b/.claude/skills/ink-tui/references/PRIMITIVES.md @@ -1,35 +1,35 @@ # Wizard primitives -Use [primitives/index.ts](../../../../src/ui/tui/primitives/index.ts) for public +Use [primitives/index.ts](../../../../src/tui/primitives/index.ts) for public exports and each source file for its current props. Shared styling lives in -[styles.ts](../../../../src/ui/tui/styles.ts). +[styles.ts](../../../../src/tui/styles.ts). ## Choose an existing component -| Need | Component and behavior | -| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| App shell | [ScreenContainer](../../../../src/ui/tui/primitives/ScreenContainer.tsx): title, screen transitions, hints, token HUD, viewport guard, and error boundary | -| Small-terminal notice | [ViewportTooSmall](../../../../src/ui/tui/primitives/ViewportTooSmall.tsx): minimum dimensions and wrapping for the shared guard | -| Tabs and status | [TabContainer](../../../../src/ui/tui/primitives/TabContainer.tsx): local active tab, arrow navigation, optional expandable status | -| Single/multiple choice | [PickerMenu](../../../../src/ui/tui/primitives/PickerMenu.tsx): columns, paging, filtering, and confirm-button interaction | -| Categorized choices | [GroupedPickerMenu](../../../../src/ui/tui/primitives/GroupedPickerMenu.tsx): category headers, scrolling, and multi-select | -| Multi-select submission | [ConfirmButton](../../../../src/ui/tui/primitives/ConfirmButton.tsx): bordered submit row with focus and optional count | -| Continue/cancel | [ConfirmationInput](../../../../src/ui/tui/primitives/ConfirmationInput.tsx): text choices, left/right focus, enter activates, escape cancels | -| Prompt heading | [PromptLabel](../../../../src/ui/tui/primitives/PromptLabel.tsx) | -| Task progress | [ProgressList](../../../../src/ui/tui/primitives/ProgressList.tsx): active labels, completion count, and skipped-task handling | -| Loading state | [LoadingBox](../../../../src/ui/tui/primitives/LoadingBox.tsx) | -| Planned events | [EventPlanViewer](../../../../src/ui/tui/primitives/EventPlanViewer.tsx) | -| Two panes | [SplitView](../../../../src/ui/tui/primitives/SplitView.tsx): equal-width panes with a gap | -| Aligned content | [CardLayout](../../../../src/ui/tui/primitives/CardLayout.tsx): horizontal/vertical alignment | -| Divider | [Divider](../../../../src/ui/tui/primitives/Divider.tsx): measures width on mount | -| Modal layout | [ModalOverlay](../../../../src/ui/tui/primitives/ModalOverlay.tsx): presentation for interrupt screens | -| Terminal links | [LinkText](../../../../src/ui/tui/primitives/LinkText.tsx) and [link helpers](../../../../src/ui/tui/primitives/link-helpers.ts) | -| Log tail | [LogViewer](../../../../src/ui/tui/primitives/LogViewer.tsx): bounded tail reads and throttled file watching | -| HN feed | [HNViewer](../../../../src/ui/tui/primitives/HNViewer.tsx): fetches stories and handles its navigation | -| Progressive content | [ContentSequencer](../../../../src/ui/tui/primitives/ContentSequencer.tsx): renders blocks from [content-types.ts](../../../../src/ui/tui/primitives/content-types.ts) | -| Screen transition | [DissolveTransition](../../../../src/ui/tui/primitives/DissolveTransition.tsx): shared wipe animation | -| Shared hints | [KeyboardHintsBar](../../../../src/ui/tui/primitives/KeyboardHintsBar.tsx): renders registered bindings | -| Render failure | [ScreenErrorBoundary](../../../../src/ui/tui/primitives/ScreenErrorBoundary.tsx) | +| Need | Component and behavior | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| App shell | [ScreenContainer](../../../../src/tui/primitives/ScreenContainer.tsx): title, screen transitions, hints, token HUD, viewport guard, and error boundary | +| Small-terminal notice | [ViewportTooSmall](../../../../src/tui/primitives/ViewportTooSmall.tsx): minimum dimensions and wrapping for the shared guard | +| Tabs and status | [TabContainer](../../../../src/tui/primitives/TabContainer.tsx): local active tab, arrow navigation, optional expandable status | +| Single/multiple choice | [PickerMenu](../../../../src/tui/primitives/PickerMenu.tsx): columns, paging, filtering, and confirm-button interaction | +| Categorized choices | [GroupedPickerMenu](../../../../src/tui/primitives/GroupedPickerMenu.tsx): category headers, scrolling, and multi-select | +| Multi-select submission | [ConfirmButton](../../../../src/tui/primitives/ConfirmButton.tsx): bordered submit row with focus and optional count | +| Continue/cancel | [ConfirmationInput](../../../../src/tui/primitives/ConfirmationInput.tsx): text choices, left/right focus, enter activates, escape cancels | +| Prompt heading | [PromptLabel](../../../../src/tui/primitives/PromptLabel.tsx) | +| Task progress | [ProgressList](../../../../src/tui/primitives/ProgressList.tsx): active labels, completion count, and skipped-task handling | +| Loading state | [LoadingBox](../../../../src/tui/primitives/LoadingBox.tsx) | +| Planned events | [EventPlanViewer](../../../../src/tui/primitives/EventPlanViewer.tsx) | +| Two panes | [SplitView](../../../../src/tui/primitives/SplitView.tsx): equal-width panes with a gap | +| Aligned content | [CardLayout](../../../../src/tui/primitives/CardLayout.tsx): horizontal/vertical alignment | +| Divider | [Divider](../../../../src/tui/primitives/Divider.tsx): measures width on mount | +| Modal layout | [ModalOverlay](../../../../src/tui/primitives/ModalOverlay.tsx): presentation for interrupt screens | +| Terminal links | [LinkText](../../../../src/tui/primitives/LinkText.tsx) and [link helpers](../../../../src/tui/primitives/link-helpers.ts) | +| Log tail | [LogViewer](../../../../src/tui/primitives/LogViewer.tsx): bounded tail reads and throttled file watching | +| HN feed | [HNViewer](../../../../src/tui/primitives/HNViewer.tsx): fetches stories and handles its navigation | +| Progressive content | [ContentSequencer](../../../../src/tui/primitives/ContentSequencer.tsx): renders blocks from [content-types.ts](../../../../src/tui/primitives/content-types.ts) | +| Screen transition | [DissolveTransition](../../../../src/tui/primitives/DissolveTransition.tsx): shared wipe animation | +| Shared hints | [KeyboardHintsBar](../../../../src/tui/primitives/KeyboardHintsBar.tsx): renders registered bindings | +| Render failure | [ScreenErrorBoundary](../../../../src/tui/primitives/ScreenErrorBoundary.tsx) | The directory also contains internal block renderers and layout helpers. Prefer the public exports for composition; read the implementation before depending on @@ -45,9 +45,9 @@ where space is text input. Use these controls for new multi-select surfaces so submission behavior and keyboard hints stay consistent. See -[InputDemo](../../../../src/ui/tui/playground/demos/InputDemo.tsx) for realistic +[InputDemo](../../../../src/tui/playground/demos/InputDemo.tsx) for realistic props and the -[picker tests](../../../../src/ui/tui/__tests__/picker-filter.test.ts) for +[picker tests](../../../../src/tui/__tests__/picker-filter.test.ts) for filtering behavior. ## Extend the catalog @@ -57,6 +57,6 @@ infrastructure primitives may own state, subscriptions, or file/network I/O; that is not a reason to put program-specific behavior in a new primitive. Export a public component from the barrel, add a -[playground demo](../../../../src/ui/tui/playground/demos/), and register it in -[PlaygroundApp](../../../../src/ui/tui/playground/PlaygroundApp.tsx). Run +[playground demo](../../../../src/tui/playground/demos/), and register it in +[PlaygroundApp](../../../../src/tui/playground/PlaygroundApp.tsx). Run `pnpm try --playground` to review its actual terminal output. diff --git a/.claude/skills/ink-tui/references/TERMINAL-COMPAT.md b/.claude/skills/ink-tui/references/TERMINAL-COMPAT.md index f8b30a438..416a5039e 100644 --- a/.claude/skills/ink-tui/references/TERMINAL-COMPAT.md +++ b/.claude/skills/ink-tui/references/TERMINAL-COMPAT.md @@ -2,32 +2,32 @@ ## Startup and exit -[startTUI](../../../../src/ui/tui/start-tui.ts) creates the store, installs +[startTUI](../../../../src/tui/start-tui.ts) creates the store, installs `InkUI`, renders the app, and starts program initialization. -[terminal.ts](../../../../src/ui/tui/terminal.ts) owns the alternate screen -buffer and black background shared with the playground. Reuse this lifecycle. +[terminal.ts](../../../../src/tui/terminal.ts) owns the alternate screen buffer +and black background shared with the playground. Reuse this lifecycle. Cleanup unmounts Ink, restores the terminal, and prints the -[exit line](../../../../src/ui/tui/exit-line.ts). Ink teardown on Ctrl+C is +[exit line](../../../../src/tui/exit-line.ts). Ink teardown on Ctrl+C is followed by analytics shutdown and process exit so background handles do not leave a process running without its interface. ## Dimensions and resizing -[useStdoutDimensions](../../../../src/ui/tui/hooks/useStdoutDimensions.ts) +[useStdoutDimensions](../../../../src/tui/hooks/useStdoutDimensions.ts) subscribes to resize events and supplies fallback dimensions when a stream has none. -[ScreenContainer](../../../../src/ui/tui/primitives/ScreenContainer.tsx) centers +[ScreenContainer](../../../../src/tui/primitives/ScreenContainer.tsx) centers and caps content width. On a real TTY, it shows -[ViewportTooSmall](../../../../src/ui/tui/primitives/ViewportTooSmall.tsx) below +[ViewportTooSmall](../../../../src/tui/primitives/ViewportTooSmall.tsx) below the minimum dimensions declared there. The underlying screen stays mounted and is hidden from layout, preserving input state and avoiding repeated mount effects. Its input handlers still run; the guard does not pause the wizard. Piped stdout does not activate this resize notice. Use -[ViewportGuardDemo](../../../../src/ui/tui/playground/demos/ViewportGuardDemo.tsx) +[ViewportGuardDemo](../../../../src/tui/playground/demos/ViewportGuardDemo.tsx) to inspect the guard. For a layout change, inspect the affected screen near the minimum size and at a wider size, including expanded status or the HUD if those share its available height. @@ -35,20 +35,20 @@ share its available height. ## Noninteractive execution Mode selection belongs to command/runner entry points. The -[default integration command](../../../../src/commands/basic-integration/index.ts) +[default integration command](../../../../src/cli/commands/basic-integration/index.ts) routes explicit CI/headless requests separately and rejects a detected noninteractive environment for the ordinary interactive path. -[Environment detection](../../../../src/utils/environment.ts) checks +[Environment detection](../../../../src/store/shared/environment.ts) checks stdout/stderr TTY state outside development mode; checking stdin alone does not describe this command's behavior. `--ci` is a development/test path. The separate experimental headless contract -is defined in [headless-mode.ts](../../../../src/lib/headless-mode.ts); keep its -hidden flag out of user-facing guidance. Other commands can have their own -fallback, such as -[MCP TUI availability](../../../../src/commands/mcp/tui-availability.ts). +is defined in [headless-mode.ts](../../../../src/store/shared/headless-mode.ts); +keep its hidden flag out of user-facing guidance. Other commands can have their +own fallback, such as +[MCP TUI availability](../../../../src/cli/commands/mcp/tui-availability.ts). Do not add an automatic default-answer or Inquirer fallback in a screen. -Noninteractive behavior belongs in [LoggingUI](../../../../src/ui/logging-ui.ts) -and the command/runner contract, including explicit handling of interactions -that cannot be answered. +Noninteractive behavior belongs in +[LoggingUI](../../../../src/tui/console/logging-ui.ts) and the command/runner +contract, including explicit handling of interactions that cannot be answered. diff --git a/.claude/skills/wizard-development/SKILL.md b/.claude/skills/wizard-development/SKILL.md index 3ee4f261d..a751e2a78 100644 --- a/.claude/skills/wizard-development/SKILL.md +++ b/.claude/skills/wizard-development/SKILL.md @@ -17,16 +17,16 @@ Ask who owns the concern and what they should need to understand to change it. Product knowledge belongs behind typed configuration boundaries; runner and UI infrastructure should consume those boundaries. -| Concern | Owner | -| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Framework detection, context, env conventions | [FrameworkConfig](../../../src/lib/framework-config.ts) and [framework configs](../../../src/frameworks/) | -| Integration instructions and orchestrator flows/tasks | [context-mill](https://github.com/PostHog/context-mill) | -| Programs, steps, prerequisites and outcomes | [programs](../../../src/lib/programs/) | -| Sequence, harness, model and effort selection | [switchboard](../../../src/lib/agent/runner/switchboard/) | -| Local tool permissions and scanner adapters | [agent-interface](../../../src/lib/agent/agent-interface.ts), [YARA hooks](../../../src/lib/yara-hooks.ts), [Pi security](../../../src/lib/agent/runner/harness/pi/security.ts) | -| Scanner rules | [warlock](https://github.com/PostHog/warlock) | -| Token admission and budgets | [PostHog mint endpoint](https://github.com/PostHog/posthog/blob/master/posthog/llm/wizard_gateway_token.py) and [ai-gateway](https://github.com/PostHog/ai-gateway) | -| Screen resolution and rendering | [TUI](../../../src/ui/tui/) through [WizardUI](../../../src/ui/wizard-ui.ts) | +| Concern | Owner | +| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Framework detection, context, env conventions | [FrameworkConfig](../../../src/store/framework-config.ts) and [framework configs](../../../src/frameworks/) | +| Integration instructions and orchestrator flows/tasks | [context-mill](https://github.com/PostHog/context-mill) | +| Programs, steps, prerequisites and outcomes | [programs](../../../src/store/programs/) | +| Sequence, harness, model and effort selection | [switchboard](../../../src/agent/runner/switchboard/) | +| Local tool permissions and scanner adapters | [agent-interface](../../../src/agent/agent-interface.ts), [YARA hooks](../../../src/store/security/yara-hooks.ts), [Pi security](../../../src/agent/runner/harness/pi/security.ts) | +| Scanner rules | [warlock](https://github.com/PostHog/warlock) | +| Token admission and budgets | [PostHog mint endpoint](https://github.com/PostHog/posthog/blob/master/posthog/llm/wizard_gateway_token.py) and [ai-gateway](https://github.com/PostHog/ai-gateway) | +| Screen resolution and rendering | [TUI](../../../src/tui/) through [WizardUI](../../../src/store/ui/wizard-ui.ts) | ## Execution policy and model admission @@ -34,7 +34,7 @@ infrastructure should consume those boundaries. are separate: Pi supports gateway-backed Anthropic and OpenAI transports. - **Prefer orchestration.** A seed agent plans work, then task agents execute focused conversations. Start from - [metrics](../../../src/lib/programs/metrics/) and its context-mill flow. + [metrics](../../../src/store/programs/metrics/) and its context-mill flow. - **Linear is for very simple tasks and legacy support.** Composed program sub-runs are also structurally clamped to linear; orchestration cannot nest through that seam. @@ -43,18 +43,18 @@ infrastructure should consume those boundaries. new Anthropic models. Existing routing has not all migrated: -[DEFAULT_BINDING](../../../src/lib/agent/runner/switchboard/index.ts) still -selects Anthropic + linear, with per-program and flag overrides. Set new -bindings explicitly. Migrating an existing program requires checking its flow, -tasks, and lifecycle hooks; changing the default constant alone is insufficient. -Both harnesses implement `run` and `runTask`. +[DEFAULT_BINDING](../../../src/agent/runner/switchboard/index.ts) still selects +Anthropic + linear, with per-program and flag overrides. Set new bindings +explicitly. Migrating an existing program requires checking its flow, tasks, and +lifecycle hooks; changing the default constant alone is insufficient. Both +harnesses implement `run` and `runTask`. Adding a model or effort is a cross-repository change: 1. Define the Wizard model ID and capabilities in - [constants](../../../src/lib/constants.ts) and - [models](../../../src/lib/agent/runner/switchboard/models.ts); select it - through the switchboard or supported context-mill stage metadata. + [constants](../../../src/store/shared/constants.ts) and + [models](../../../src/agent/runner/switchboard/models.ts); select it through + the switchboard or supported context-mill stage metadata. 2. Check the PostHog mint's `WIZARD_MODEL_ALLOWLIST` and allowed efforts. The token's policy is enforced by the gateway; a local constant or CLI override cannot authorize a model. @@ -65,7 +65,7 @@ Adding a model or effort is a cross-repository change: 4. Verify the chosen harness transport and effective effort with the same admission policy used by the target environment. -Local [commandments](../../../src/lib/agent/runner/switchboard/commandments.ts) +Local [commandments](../../../src/agent/runner/switchboard/commandments.ts) provide runtime and tool guidance. They do not replace the gateway's required safety prompt. Keep gateway policy owned there rather than copying it into skills. Do not infer per-model effort authorization merely from the local @@ -94,7 +94,7 @@ only when it gives a real owner a smaller, reusable boundary. ## Lifecycle and security -[runner/index.ts](../../../src/lib/agent/runner/index.ts) bootstraps, resolves a +[runner/index.ts](../../../src/agent/runner/index.ts) bootstraps, resolves a binding, and dispatches to a sequence. `agent-runner.ts` is a compatibility re-export, not the implementation. Sequences own their lifecycle; harnesses own SDK calls. `ProgramRun.postRun`, `buildOutroData`, `customPrompt`, and @@ -109,11 +109,11 @@ than assuming every rejection terminates the run. New scanner rules belong in warlock; changes to how a match is handled belong in Wizard. User-provided secrets should travel through -[secret-vault](../../../src/lib/secret-vault.ts) references. Tool +[secret-vault](../../../src/store/session/secret-vault.ts) references. Tool implementations resolve values host-side where they are used; they must not return the raw value to the model. Inspect the -[wizard-tools](../../../src/lib/wizard-tools/) implementations and the Pi -adapter when extending this shared tool surface. +[wizard-tools](../../../src/store/tools/) implementations and the Pi adapter +when extending this shared tool surface. ## Verification and maintenance diff --git a/.claude/skills/wizard-development/references/ARCHITECTURE.md b/.claude/skills/wizard-development/references/ARCHITECTURE.md index bb99255f3..98c560a44 100644 --- a/.claude/skills/wizard-development/references/ARCHITECTURE.md +++ b/.claude/skills/wizard-development/references/ARCHITECTURE.md @@ -8,27 +8,28 @@ description: ## Runner and lifecycle -[run-wizard.ts](../../../../src/lib/runners/run-wizard.ts) owns the program's +[run-wizard.ts](../../../../src/cli/runners/run-wizard.ts) owns the program's interactive lifecycle: create the session and TUI, assign the session, run readiness hooks, and traverse steps and gates. -[store.ts](../../../../src/ui/tui/store.ts) runs `onInit` when the TUI starts; -`onReady` runs after the real session is assigned. Keep session-dependent -detection in `onReady`. Noninteractive execution has its own lifecycle in -[run-non-interactive.ts](../../../../src/lib/runners/run-non-interactive.ts). - -[runner/index.ts](../../../../src/lib/agent/runner/index.ts) resolves a -program's `run` definition, calls shared bootstrap, selects a binding, -dispatches the sequence, and flushes the scanner report on cleanup. The old -[agent-runner.ts](../../../../src/lib/agent/agent-runner.ts) is a compatibility +[store.ts](../../../../src/store/state/store.ts) runs `onInit` when the TUI +starts; `onReady` runs after the real session is assigned. Keep +session-dependent detection in `onReady`. Noninteractive execution has its own +lifecycle in +[run-non-interactive.ts](../../../../src/cli/runners/run-non-interactive.ts). + +[runner/index.ts](../../../../src/agent/runner/index.ts) resolves a program's +`run` definition, calls shared bootstrap, selects a binding, dispatches the +sequence, and flushes the scanner report on cleanup. The old +[agent-runner.ts](../../../../src/agent/runner/index.ts) is a compatibility export. -| Layer | Source and responsibility | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Bootstrap | [shared/bootstrap.ts](../../../../src/lib/agent/runner/shared/bootstrap.ts): shared health/settings/auth/flag and MCP setup | -| Switchboard | [switchboard/index.ts](../../../../src/lib/agent/runner/switchboard/index.ts): resolve sequence, harness, model and effort override | -| Linear sequence | [sequence/linear.ts](../../../../src/lib/agent/runner/sequence/linear.ts): one conversation, skill/prompt assembly, post-run hooks and outro | -| Orchestrator | [orchestrator-runner.ts](../../../../src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts): seed plan, task queue, focused conversations, handoffs and completion | -| Harness | [harness/types.ts](../../../../src/lib/agent/runner/harness/types.ts): SDK boundary, implemented by Pi and Anthropic | +| Layer | Source and responsibility | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Bootstrap | [shared/bootstrap.ts](../../../../src/agent/runner/shared/bootstrap.ts): shared health/settings/auth/flag and MCP setup | +| Switchboard | [switchboard/index.ts](../../../../src/agent/runner/switchboard/index.ts): resolve sequence, harness, model and effort override | +| Linear sequence | [sequence/linear.ts](../../../../src/agent/runner/sequence/linear.ts): one conversation, skill/prompt assembly, post-run hooks and outro | +| Orchestrator | [orchestrator-runner.ts](../../../../src/agent/runner/sequence/orchestrator/orchestrator-runner.ts): seed plan, task queue, focused conversations, handoffs and completion | +| Harness | [harness/types.ts](../../../../src/agent/runner/harness/types.ts): SDK boundary, implemented by Pi and Anthropic | The contribution policy is [Pi by default, orchestration preferred](../SKILL.md#execution-policy-and-model-admission). @@ -40,7 +41,7 @@ route. ### Configuration hooks -Read [ProgramRun](../../../../src/lib/agent/runner/shared/types.ts) for exact +Read [ProgramRun](../../../../src/agent/runner/shared/types.ts) for exact signatures. | Surface | Current consumer | @@ -54,7 +55,7 @@ signatures. Do not migrate a linear program merely by changing its binding if it depends on these hooks. Inspect the orchestrator's flow and completion path instead. -[Metrics](../../../../src/lib/programs/metrics/) is a current Pi/orchestrator +[Metrics](../../../../src/store/programs/metrics/) is a current Pi/orchestrator example. Native command modules still need registration in [bin.ts](../../../../bin.ts); screen sequences derive from the program registry. @@ -70,25 +71,25 @@ binding and stamping a trace of the selected precedence rungs. - Sequence: composed linear clamp, development CLI override, `runTask` capability clamp, program flag route, sequence experiment, binding/default. -[Harness](../../../../src/lib/agent/runner/switchboard/harness.ts) and -[sequence](../../../../src/lib/agent/runner/switchboard/sequence.ts) contain the +[Harness](../../../../src/agent/runner/switchboard/harness.ts) and +[sequence](../../../../src/agent/runner/switchboard/sequence.ts) contain the exact chains. Published builds omit CLI overrides. `RUN_SURFACE` can disable harness experiments; static bindings and harness capabilities also affect resolution. Composed sub-runs remain linear even when a CLI override requests orchestration. Effort resolves in two stages: the binding supplies an override, then -[modelCapabilities](../../../../src/lib/agent/runner/switchboard/models.ts) -applies capabilities and defaults. All selected models and efforts must also be -admitted by the minted token and gateway. Local routing cannot bypass that -external policy; see the +[modelCapabilities](../../../../src/agent/runner/switchboard/models.ts) applies +capabilities and defaults. All selected models and efforts must also be admitted +by the minted token and gateway. Local routing cannot bypass that external +policy; see the [model admission checklist](../SKILL.md#execution-policy-and-model-admission). Flags belong in -[switchboard/flags](../../../../src/lib/agent/runner/switchboard/flags/). +[switchboard/flags](../../../../src/agent/runner/switchboard/flags/). Experiments declare their program scope; malformed payloads yield no experiment route. Reuse the -[switchboard tests](../../../../src/lib/agent/runner/__tests__/switchboard.test.ts) +[switchboard tests](../../../../src/agent/runner/__tests__/switchboard.test.ts) and experiment tests to check full bindings and isolation of unrelated programs. Do not add a second flag-reading path inside a harness or sequence. @@ -99,17 +100,17 @@ Wizard's local tool boundary separately restricts operations on the user's project. Local commandments provide model guidance; they are not an enforcement mechanism. -- [agent-interface.ts](../../../../src/lib/agent/agent-interface.ts) configures - the Anthropic SDK's tool permissions, sandbox, and gateway transport. -- [yara-hooks.ts](../../../../src/lib/yara-hooks.ts) adapts warlock scans to SDK - tool hooks. -- [Pi security](../../../../src/lib/agent/runner/harness/pi/security.ts) adapts +- [agent-interface.ts](../../../../src/agent/agent-interface.ts) configures the + Anthropic SDK's tool permissions, sandbox, and gateway transport. +- [yara-hooks.ts](../../../../src/store/security/yara-hooks.ts) adapts warlock + scans to SDK tool hooks. +- [Pi security](../../../../src/agent/runner/harness/pi/security.ts) adapts shared permissions and scanning to Pi tool-call/result events, including blocking, violation latching, and tool-call limits. -- [Pi harness](../../../../src/lib/agent/runner/harness/pi/) explicitly supplies +- [Pi harness](../../../../src/agent/runner/harness/pi/) explicitly supplies tools, scrubs shell environments, and disables project-controlled extensions/context loading. -- [triage-provider.ts](../../../../src/lib/agent/triage-provider.ts) supplies +- [triage-provider.ts](../../../../src/agent/triage-provider.ts) supplies gateway-backed classification for scanner findings. Scanner rules live in [warlock](https://github.com/PostHog/warlock); Wizard owns @@ -119,44 +120,44 @@ terminates the run. Check each adapter's state machine when changing rejection handling. Preserve useful rejection diagnostics without logging secret content. Both SDK paths use a scoped gateway token minted through -[gateway-session.ts](../../../../src/lib/gateway-session.ts), not the user's raw -OAuth credential as a model API key. Rejection and refresh behavior belong at -that seam; do not restore a legacy-gateway fallback to bypass admission. +[gateway-session.ts](../../../../src/agent/gateway/gateway-session.ts), not the +user's raw OAuth credential as a model API key. Rejection and refresh behavior +belong at that seam; do not restore a legacy-gateway fallback to bypass +admission. ### Secret vault: keeping values out of the model -[secret-vault.ts](../../../../src/lib/secret-vault.ts) stores user-provided -values in memory and returns opaque references. Sensitive `wizard_ask` answers -become `secret:` refs; `set_env_values` resolves the ref host-side when -writing. Follow [wizard-tools](../../../../src/lib/wizard-tools/) and the Pi -adapters when adding a secret-consuming tool. Return references and metadata to -the agent, never the raw value. References are session-scoped, not durable -credentials. +[secret-vault.ts](../../../../src/store/session/secret-vault.ts) stores +user-provided values in memory and returns opaque references. Sensitive +`wizard_ask` answers become `secret:` refs; `set_env_values` resolves the +ref host-side when writing. Follow [wizard-tools](../../../../src/store/tools/) +and the Pi adapters when adding a secret-consuming tool. Return references and +metadata to the agent, never the raw value. References are session-scoped, not +durable credentials. ## UI state and agent output -Business logic uses [WizardUI](../../../../src/ui/wizard-ui.ts) through -`getUI()`. [InkUI](../../../../src/ui/tui/ink-ui.ts) updates the TUI store; -[LoggingUI](../../../../src/ui/logging-ui.ts) is available for noninteractive -callers that select it. A missing TTY does not automatically mean an arbitrary -caller uses LoggingUI; snapshot CI drives Ink in a PTY. `requestQuestion` and -task notices are supported interactions, not console prompts to invent in -business logic. +Business logic uses [WizardUI](../../../../src/store/ui/wizard-ui.ts) through +`getUI()`. [InkUI](../../../../src/store/ui/store-ui.ts) updates the TUI store; +[LoggingUI](../../../../src/tui/console/logging-ui.ts) is available for +noninteractive callers that select it. A missing TTY does not automatically mean +an arbitrary caller uses LoggingUI; snapshot CI drives Ink in a PTY. +`requestQuestion` and task notices are supported interactions, not console +prompts to invent in business logic. Harness adapters translate SDK messages, status markers, task updates and tool activity into WizardUI calls. Anthropic message processing lives in -[agent-interface.ts](../../../../src/lib/agent/agent-interface.ts); Pi uses its -own session event handlers. Orchestrated tasks also have queue and handoff -state. Do not assume all harness output passes through `handleSDKMessage`. +[agent-interface.ts](../../../../src/agent/agent-interface.ts); Pi uses its own +session event handlers. Orchestrated tasks also have queue and handoff state. Do +not assume all harness output passes through `handleSDKMessage`. Session changes go through explicit store setters. They emit updates, re-evaluate gates, detect transitions, and refresh rendering. The -[router](../../../../src/ui/tui/router.ts) resolves overlays first, then the -first visible incomplete screen from -[screen-sequences.ts](../../../../src/ui/tui/screen-sequences.ts). Those -sequences are projected from registered program steps. Change the -state/predicate that represents progress rather than adding imperative -navigation. +[router](../../../../src/tui/router.ts) resolves overlays first, then the first +visible incomplete screen from +[screen-sequences.ts](../../../../src/tui/screen-sequences.ts). Those sequences +are projected from registered program steps. Change the state/predicate that +represents progress rather than adding imperative navigation. ## MCP and instrumentation @@ -165,7 +166,7 @@ separate surfaces. The Anthropic SDK's MCP integration and Pi's adapter expose them differently; inspect the selected harness rather than assuming identical tool names or discovery. Context-mill supplies skills and flow/task prompts. -[Middleware](../../../../src/lib/middleware/) provides opt-in message/phase +[Middleware](../../../../src/agent/middleware/) provides opt-in message/phase instrumentation. The linear sequence creates the benchmark pipeline; there is no pipeline construction in the compatibility `agent-runner.ts`. Inspect the actual consumer before extending instrumentation to another sequence or harness. diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 184dc942a..d0e75dfac 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -8,6 +8,10 @@ module.exports = { plugins: ['@typescript-eslint'], parserOptions: { tsconfigRootDir: __dirname, + // The whole-tree config, not the composite surface projects: those resolve + // cross-surface imports through built declarations, so lint would see + // `any` until `tsc -b` has run. Boundaries are enforced by tsc -b and the + // architecture suite, not by lint's type information. project: ['./tsconfig.json'], }, ignorePatterns: [ @@ -19,6 +23,7 @@ module.exports = { 'assets/**', 'scripts/**', 'coverage/**', + '**/coverage/**', // Standalone jest-based package, linted/typechecked in its own context and // outside the root tsconfig the parser uses (parserOptions.project). 'e2e-tests/**', @@ -30,6 +35,112 @@ module.exports = { 'prettier', ], overrides: [ + // Surface boundaries. The matrix and public entries live in + // src/__tests__/architecture/import-boundaries.test.ts; these mirror it + // for editor feedback. Tests may reach into internals. + { + files: ['src/store/**/*.ts', 'src/store/**/*.tsx'], + excludedFiles: ['**/__tests__/**'], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: ['ink', 'react', '@inkjs/ui', 'ink-testing-library'], + patterns: [ + '@agent', + '@agent/*', + '@tui', + '@tui/*', + '@cli/*', + 'react/*', + ], + }, + ], + }, + }, + { + files: ['src/agent/**/*.ts', 'src/agent/**/*.tsx'], + excludedFiles: ['**/__tests__/**'], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: ['ink', 'react', '@inkjs/ui', 'ink-testing-library'], + patterns: [ + '@tui', + '@tui/*', + '@cli/*', + 'react/*', + '@store/*', + '!@store/types', + '!@store/programs', + ], + }, + ], + }, + }, + { + files: ['src/tui/**/*.ts', 'src/tui/**/*.tsx'], + excludedFiles: ['**/__tests__/**'], + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + '@agent', + '@agent/*', + '@cli/*', + '@store/*', + '!@store/types', + '!@store/programs', + ], + }, + ], + }, + }, + { + files: ['src/tui/console/**/*.ts'], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: ['ink', 'react', '@inkjs/ui', 'ink-testing-library'], + patterns: [ + '@agent', + '@agent/*', + '@cli/*', + 'react/*', + '@store/*', + '!@store/types', + '!@store/programs', + ], + }, + ], + }, + }, + { + files: ['bin.ts', 'src/cli/**/*.ts', 'src/cli/**/*.tsx'], + excludedFiles: ['**/__tests__/**'], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: ['ink', 'react', '@inkjs/ui', 'ink-testing-library'], + patterns: [ + 'react/*', + '@store/*', + '!@store/types', + '!@store/programs', + '@agent/*', + '!@agent/types', + '@tui/*', + '!@tui/types', + '!@tui/console', + ], + }, + ], + }, + }, { files: [ '*.test.js', diff --git a/.github/workflows/surfaces.yml b/.github/workflows/surfaces.yml index 546b9c9ea..173edd1d5 100644 --- a/.github/workflows/surfaces.yml +++ b/.github/workflows/surfaces.yml @@ -46,6 +46,7 @@ jobs: cache: 'pnpm' - run: pnpm install --frozen-lockfile - run: node scripts/generate-version.cjs + - run: pnpm typecheck:${{ matrix.project }} - run: pnpm test:${{ matrix.project }} --coverage - uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # pin@v5.3.1 with: diff --git a/.gitignore b/.gitignore index 3519c1fda..df829c4d1 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,8 @@ plugins e2e-tests/fixtures/.tracking/* # Generated at build time by scripts/generate-version.js -src/lib/version.ts +src/store/shared/version.ts # Re-include src/lib explicitly: a user-global ignore pattern like `lib/` # would otherwise silently drop new source files under src/lib from commits. !src/lib/ +.tsbuild/ diff --git a/AGENTS.md b/AGENTS.md index bf6620e5c..31ceaa57f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,7 +19,7 @@ configuration surfaces. Each domain has a dedicated boundary: -- **Frameworks** → `FrameworkConfig` in `src/frameworks//` +- **Frameworks** → `FrameworkConfig` in `src/store/frameworks//` - **Integration knowledge** → markdown skills in the [context-mill](https://github.com/PostHog/context-mill) repo - **Security policy** → YARA-X rules in the @@ -30,8 +30,15 @@ Each domain has a dedicated boundary: [ai-gateway](https://github.com/PostHog/ai-gateway). To disable scanning in the field without a release, see the kill-switch runbook: `docs/runbooks/warlock-kill-switch.md`. ONLY USE THIS IF ABSOLUTELY NECESSARY. -- **Programs** → step arrays in `src/lib/programs/` -- **TUI** → screen components and primitives in `src/ui/tui/` +- **Programs** → step arrays in `src/store/programs/` +- **TUI** → screen components and primitives in `src/tui/` + +The tree is three surfaces plus a composition root: `src/store` (state and +contracts), `src/agent` (one agent run), `src/tui` (rendering), `src/cli` +(argv and wiring). Surfaces import each other only through `@store`, +`@store/types`, `@store/programs`, `@agent`, `@agent/types`, `@tui`, +`@tui/types`, and `@tui/console`; `src/__tests__/architecture` enforces it. +Each surface's `README.md` lists what it owns and may import. Adding a new concern means finding the narrowest existing surface, not adding logic to the runner. Keep changes local to the boundary that owns them. @@ -110,7 +117,7 @@ aliases. A skill and a command are the **same machinery** — a context-mill skill becomes a command when its `cli:` block sets `role: command`. So `wizard audit events` _is_ the `audit-events` skill, just promoted. `wizard skill ` -([`skill.ts`](src/commands/skill.ts)) runs a skill that **wasn't** promoted. +([`skill.ts`](src/cli/commands/skill.ts)) runs a skill that **wasn't** promoted. Two surfaces, one mechanism. So `wizard audit ` is choosing an audit area — it is **not** asking for a skill name, despite `wizard audit --help` @@ -119,15 +126,17 @@ confuse it with the top-level `wizard skill` command. ### Where the surface is defined (source of truth) -- **Registration:** [`bin.ts`](bin.ts) — the `.use()` chain wires each command. -- **Command shape:** [`src/commands/command.ts`](src/commands/command.ts) — the +- **Registration:** [`src/cli/main.ts`](src/cli/main.ts) — the `.use()` chain + wires each command. [`bin.ts`](bin.ts) runs the Node preflight, then imports + it. +- **Command shape:** [`src/cli/commands/command.ts`](src/cli/commands/command.ts) — the `Command` interface every command implements. - **Flat native commands** (e.g. `revenue-analytics`, `upload-source-maps`) are built with `nativeCommandFactory` - ([`src/commands/factories/native-command-factory.ts`](src/commands/factories/native-command-factory.ts)). + ([`src/cli/commands/factories/native-command-factory.ts`](src/cli/commands/factories/native-command-factory.ts)). - **Family commands** (e.g. `audit`) resolve subcommands at runtime against the `cliEntries` in `skill-menu.json`. Logic lives in - [`src/lib/programs/dispatch-family.ts`](src/lib/programs/dispatch-family.ts). + [`src/cli/dispatch-family.ts`](src/cli/dispatch-family.ts). Adding a skill-backed subcommand is a **context-mill** release, not a wizard change. @@ -145,7 +154,7 @@ confuse it with the top-level `wizard skill` command. Give the `Command.name` an array of `[newName, ...legacyNames]`. yargs treats the extra entries as aliases. See -[`src/commands/upload-sourcemaps.ts`](src/commands/upload-sourcemaps.ts). +[`src/cli/commands/upload-sourcemaps.ts`](src/cli/commands/upload-sourcemaps.ts). Reserve aliases for names that external callers (users' scripts) may still use — when the only caller is one we control, update the caller instead. @@ -156,6 +165,9 @@ pnpm install # Install dependencies pnpm try --install-dir= # Run the wizard locally against a test project pnpm build # Compile TypeScript pnpm test # Unit tests (builds first) +pnpm test: # One Vitest project: store, agent, tui, cli, harness, arch +pnpm typecheck # tsc -b over the surface projects (tsconfig.solution.json) +pnpm typecheck: # One surface project pnpm test:watch # Unit tests in watch mode pnpm test:e2e # End-to-end tests pnpm lint # Prettier + ESLint checks diff --git a/README.md b/README.md index c66cefffb..481d49d9d 100644 --- a/README.md +++ b/README.md @@ -155,14 +155,14 @@ route review to their owning team instead. | Path | Owning team | |---|---| | `*` (everything else, including all other programs) | `@PostHog/team-wizard-docs` | -| `src/lib/agent/` | `@PostHog/team-wizard-docs` | -| `src/lib/programs/posthog-integration/` | `@PostHog/team-wizard-docs` | -| `src/lib/programs/error-tracking-upload-source-maps/` | `@PostHog/team-error-tracking` | -| `src/lib/programs/mcp-analytics/` | `@PostHog/team-mcp-analytics` | -| `src/lib/programs/revenue-analytics/` | `@PostHog/team-web-analytics` | -| `src/lib/programs/self-driving/` | `@PostHog/team-self-driving` | -| `src/lib/programs/warehouse-source/` | `@PostHog/team-warehouse-sources` | -| `src/lib/programs/web-analytics-doctor/` | `@PostHog/team-web-analytics` | +| `src/agent/` | `@PostHog/team-wizard-docs` | +| `src/store/programs/posthog-integration/` | `@PostHog/team-wizard-docs` | +| `src/store/programs/error-tracking-upload-source-maps/` | `@PostHog/team-error-tracking` | +| `src/store/programs/mcp-analytics/` | `@PostHog/team-mcp-analytics` | +| `src/store/programs/revenue-analytics/` | `@PostHog/team-web-analytics` | +| `src/store/programs/self-driving/` | `@PostHog/team-self-driving` | +| `src/store/programs/warehouse-source/` | `@PostHog/team-warehouse-sources` | +| `src/store/programs/web-analytics-doctor/` | `@PostHog/team-web-analytics` | Ownership is by directory. Programs not listed above (`agent-skill`, `audit`, `events-audit`, `mcp`, `migration`, `posthog-doctor`, @@ -270,10 +270,10 @@ dashboard:write insight:write notebook:write event_definition:write health_issue:read wizard_session:read wizard_session:write ``` -The source of truth is `WIZARD_OAUTH_SCOPES` in `src/lib/constants.ts`, which +The source of truth is `WIZARD_OAUTH_SCOPES` in `src/store/shared/constants.ts`, which documents why each scope is needed — if this block drifts, trust the code. Some programs request more on top (`PROGRAM_SCOPE_ADDITIONS` in -`src/lib/oauth/program-scopes.ts`); the default integration flow adds +`src/store/services/oauth/program-scopes.ts`); the default integration flow adds `integration:read` and `external_data_source:read` / `external_data_source:write`. @@ -281,7 +281,7 @@ Some programs request more on top (`PROGRAM_SCOPE_ADDITIONS` in The wizard's OAuth app on the PostHog side caps the scopes its tokens may carry (`OAuthApplication.scopes`). Any scope requested in this repo (see -`src/lib/oauth/program-scopes.ts`) must be grantable under that ceiling, or +`src/store/services/oauth/program-scopes.ts`) must be grantable under that ceiling, or `/authorize` drops it and the call that needs it 403s. **A granted token can be narrower than the request even with a correct @@ -291,7 +291,7 @@ are clamped silently (`clamp_scopes_to_ceiling`) — neither path errors; `/oauth/token` just returns a smaller `scope`. So never assume the token carries what was requested: the token response's `scope` field is the truth. The wizard diffs granted vs requested at login (`missingOAuthScopes` in -`src/utils/oauth.ts`), warns the user which permissions are missing, and emits +`src/store/shared/oauth.ts`), warns the user which permissions are missing, and emits `wizard: oauth grant narrowed` so narrowed runs are countable in analytics. The diff also rides on the session (`credentials.missingScopes`), so when a run does fail on a scope-gated step, the error names the missing permission @@ -396,7 +396,7 @@ and set up the general flow of the application. ## Analytics Did you know you can capture PostHog events even for smaller, supporting -products like a command line tool? `src/utils/analytics.ts` is a great example +products like a command line tool? `src/store/shared/analytics.ts` is a great example of how to do it. This file wraps `posthog-node` with some convenience functions to set up an @@ -450,14 +450,14 @@ orchestrates that journey, but the raw value should _never_ enter the LLM conversation, where it would be sent to the model provider, written to transcripts, and captured in logs. -`src/lib/secret-vault.ts` is a small, reusable pattern for exactly this. It's a +`src/store/session/secret-vault.ts` is a small, reusable pattern for exactly this. It's a session-scoped, in-memory vault: a tool that handles a secret calls `put()` to store the raw value and hands the agent an opaque `secret:` reference instead. The agent passes that ref between tools as if it were the value; the host resolves it back to the real secret only at the last moment, inside the process, when it writes the file. -Two tools in `src/lib/wizard-tools.ts` form the ends of that pipe: +Two tools in `src/store/tools/tools.ts` form the ends of that pipe: - `wizard_ask` with `sensitive: true` vaults the user's typed answer and returns `{ secretRef: "secret:..." }` to the agent rather than the string. @@ -503,11 +503,11 @@ Path aliases defined in `tsconfig.build.json`, resolved by tsdown: | Alias | Maps to | |---|---| | `@env` | `src/env.ts` | -| `@lib/*` | `src/lib/*` | -| `@utils/*` | `src/utils/*` | -| `@ui/*` | `src/ui/*` | -| `@steps/*` | `src/steps/*` | -| `@frameworks/*` | `src/frameworks/*` | +| `@store`, `@store/types`, `@store/programs` | `src/store/{index,types,programs/index}.ts` | +| `@agent`, `@agent/types` | `src/agent/{index,types}.ts` | +| `@tui`, `@tui/types`, `@tui/console` | `src/tui/{index,types,console/index}.ts` | +| `@cli/*` | `src/cli/*` (composition root, internal) | +| `@store/*`, `@agent/*`, `@tui/*` | surface internals; tests only, never across surfaces | ## Running locally @@ -605,7 +605,7 @@ To make your version of a tool usable with a one-line `npx` command: # Health checks -`src/lib/health-checks/` checks skills download origins before the wizard runs. +`src/store/health-checks/` checks skills download origins before the wizard runs. The entry point is `evaluateWizardReadiness()`, which only blocks on skill downloads: | Decision | Meaning | @@ -645,7 +645,7 @@ gateway URL and reports an unavailable gateway through the existing error path. `skillsOrigin` is one entry covering two origins: skills are published to GitHub Releases and an AWS mirror under the same filenames, and downloads fail -over between them (`src/lib/fetch-retry.ts`). Both are probed in parallel, so +over between them (`src/store/fetch-retry.ts`). Both are probed in parallel, so the key only reports **Down** when neither origin answers — a GitHub Releases outage on its own doesn't block a run, including a 403 or 404, which is as often about the origin (expired asset redirect, blocked region, a publish that diff --git a/__mocks__/forbidden-ink.ts b/__mocks__/forbidden-ink.ts new file mode 100644 index 000000000..366c18b69 --- /dev/null +++ b/__mocks__/forbidden-ink.ts @@ -0,0 +1,8 @@ +/** + * Alias target for `ink` in every Vitest project except tui and harness. The + * store, agent, and cli surfaces are Ink free; a test that loads Ink there + * fails at import time instead of silently rendering nothing. + */ +throw new Error( + 'ink loaded outside the tui surface. Only src/tui may import Ink; see src/__tests__/architecture.', +); diff --git a/bin.ts b/bin.ts index b30137d41..19b32de88 100644 --- a/bin.ts +++ b/bin.ts @@ -1,8 +1,6 @@ #!/usr/bin/env node import { satisfies } from 'semver'; import { Agent, setGlobalDispatcher } from 'undici'; -import { ErrorCodes } from './src/lib/errors/codes.js'; -import { emitWizardError } from './src/lib/errors/emit.js'; // Keep in sync with `engines.node` in package.json. npx does not enforce // engines, so this preflight is the only thing standing between an old Node @@ -23,8 +21,6 @@ const NODE_VERSION_RANGE = '>=22.22.0'; */ setGlobalDispatcher(new Agent({ allowH2: false })); -// Have to run this above the other imports because they are importing clack that -// has the problematic imports. if (!satisfies(process.version, NODE_VERSION_RANGE)) { // eslint-disable-next-line no-console console.log( @@ -42,10 +38,13 @@ if (!satisfies(process.version, NODE_VERSION_RANGE)) { `Then run the wizard again. Stuck? Email wizard@posthog.com and we'll help.`, ].join('\n'), ); - emitWizardError({ - code: ErrorCodes.CliNodeVersion, - message: `Node ${process.version} is below the required range ${NODE_VERSION_RANGE}`, - }); + // Same line emitWizardError prints; inlined so no surface loads before this check. + process.stderr.write( + `phw-error: ${JSON.stringify({ + code: 'PHW_CLI_NODE_VERSION', + message: `Node ${process.version} is below the required range ${NODE_VERSION_RANGE}`, + })}\n`, + ); process.exit(1); } @@ -65,61 +64,5 @@ if (process.env.NODE_ENV === 'test') { })(); } -import { Wizard } from './src/wizard'; -import { basicIntegrationCommand } from './src/commands/basic-integration'; -import { mcpCommand } from './src/commands/mcp'; -import { mcpAnalyticsCommand } from './src/commands/mcp-analytics'; -import { replayVisionCommand } from './src/commands/replay-vision'; -import { aiObservabilityCommand } from './src/commands/ai-observability'; -import { metricsCommand } from './src/commands/metrics'; -import { auditCommand } from './src/commands/audit'; -import { doctorCommand } from './src/commands/doctor'; -import { migrateCommand } from './src/commands/migrate'; -import { revenueCommand } from './src/commands/revenue'; -import { warehouseCommand } from './src/commands/warehouse'; -import { selfDrivingCommand } from './src/commands/self-driving'; -import { slackCommand } from './src/commands/slack'; -import { uploadSourcemapsCommand } from './src/commands/upload-sourcemaps'; -import { errorTrackingCommand } from './src/commands/error-tracking'; -import { skillCommand } from './src/commands/skill'; -import { cliCommand } from './src/commands/cli'; -import { recoverOrphanedSettingsBackups } from './src/lib/claude-settings'; -import { setUI } from './src/ui'; -import { LoggingUI } from './src/ui/tui/console/logging-ui'; - -// The entry point owns the default renderer; @ui ships with none. -setUI(new LoggingUI()); - -// Heal any .claude/settings backup a previous interrupted run left orphaned, -// before anything else reads Claude settings — conflict detection, OAuth, and -// the agent all need to see the user's real settings file. The install dir is -// read directly from argv/env because yargs hasn't parsed yet. -recoverOrphanedSettingsBackups(resolveInstallDir()); - -function resolveInstallDir(): string { - const args = process.argv.slice(2); - const flagIndex = args.indexOf('--install-dir'); - if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1]; - const inline = args.find((a) => a.startsWith('--install-dir=')); - if (inline) return inline.slice('--install-dir='.length); - return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd(); -} - -Wizard.use(basicIntegrationCommand) - .use(mcpCommand) - .use(mcpAnalyticsCommand) - .use(replayVisionCommand) - .use(aiObservabilityCommand) - .use(metricsCommand) - .use(cliCommand) - .use(auditCommand) - .use(doctorCommand) - .use(migrateCommand) - .use(revenueCommand) - .use(warehouseCommand) - .use(selfDrivingCommand) - .use(slackCommand) - .use(uploadSourcemapsCommand) - .use(errorTrackingCommand) - .use(skillCommand) - .init(); +// Surfaces load only after the preflight passed. +await import('./src/cli/main.js'); diff --git a/docs/benchmarking.md b/docs/benchmarking.md index 87d7f9225..e5fadf4f7 100644 --- a/docs/benchmarking.md +++ b/docs/benchmarking.md @@ -102,7 +102,7 @@ Everything below ships in this repo (`wizard/`) and its workbench orchestrator on pi, per-task models from context-mill frontmatter; off → the linear anthropic default). Per-stage variations ride `wizard-orchestrator-override` payloads (`{stage: {model?, effort?}}`, - variant keys in `wizard/src/lib/agent/runner/switchboard/flags/schemes.ts`). + variant keys in `wizard/src/agent/runner/switchboard/flags/schemes.ts`). The baseline is `{"wizard-orchestrator":"false"}` — never an empty override, or live remote flags leak into the baseline. diff --git a/docs/error-catalog.md b/docs/error-catalog.md index dc1d90bdb..517a40e9e 100644 --- a/docs/error-catalog.md +++ b/docs/error-catalog.md @@ -6,12 +6,12 @@ machine-readable code so the backend, the web UI, and sandbox supervisors can classify failures without parsing human-readable messages. - **Source of truth for codes:** - [`src/lib/errors/codes.ts`](../src/lib/errors/codes.ts) + [`src/store/shared/errors/codes.ts`](../src/store/shared/errors/codes.ts) - **Source of truth for metadata (group, retry advice, description):** - [`src/lib/errors/catalog.ts`](../src/lib/errors/catalog.ts) + [`src/store/shared/errors/catalog.ts`](../src/store/shared/errors/catalog.ts) - **Consumers:** `wizardAbort()` - ([`src/utils/wizard-abort.ts`](../src/utils/wizard-abort.ts)), the task stream - ([`src/lib/task-stream/`](../src/lib/task-stream/)), and non-interactive hosts + ([`src/store/shared/wizard-abort.ts`](../src/store/shared/wizard-abort.ts)), the task stream + ([`src/store/task-stream/`](../src/store/task-stream/)), and non-interactive hosts reading stderr. ## Stability contract @@ -117,7 +117,7 @@ guarantee. Program detect steps write `{ kind, ...detail }` into `session.frameworkContext.detectError`. `detectErrorCode()` -([`src/lib/errors/detect-map.ts`](../src/lib/errors/detect-map.ts)) maps `kind` +([`src/store/shared/errors/detect-map.ts`](../src/store/shared/errors/detect-map.ts)) maps `kind` → code, and the whole object — `kind` included — rides along as `OutroData.errorDetail`. @@ -140,7 +140,7 @@ Two rules make the detect group safe for automated retry policy: ## Auth classification Gateway 401s are classified at the abort site by `classifyAuthFailure()` -([`src/lib/errors/auth.ts`](../src/lib/errors/auth.ts)) with priority: +([`src/store/shared/errors/auth.ts`](../src/store/shared/errors/auth.ts)) with priority: stored-login conflict → settings conflict → key-type → missing scope → region mismatch → invalid/expired. Inputs are best-effort from the run context; the classifier degrades to `PHW_AUTH_INVALID_OR_EXPIRED` when no distinguishing diff --git a/docs/local-dev.md b/docs/local-dev.md index 10e11ba7b..65734d9a7 100644 --- a/docs/local-dev.md +++ b/docs/local-dev.md @@ -170,7 +170,7 @@ skills url, MCP url, and PostHog host together. ## Implementation -`src/lib/local-dev.ts` defines the endpoints and precedence. Downstream code +`src/store/local-dev.ts` defines the endpoints and precedence. Downstream code reads the resolved targets. The three service flags have no yargs default. An absent flag is `undefined` diff --git a/docs/runbooks/agentic-monorepo-detection.md b/docs/runbooks/agentic-monorepo-detection.md index 36fbd8664..cbb112085 100644 --- a/docs/runbooks/agentic-monorepo-detection.md +++ b/docs/runbooks/agentic-monorepo-detection.md @@ -35,10 +35,10 @@ it. - Only non-interactive basic-integration runs — headless and `--ci`. Interactive runs have their own detect step and never enter it. -- Phase: `scopeInstallDirToProject` in `src/lib/detection/project-scope.ts`, +- Phase: `scopeInstallDirToProject` in `src/store/detection/project-scope.ts`, called from the top of `ciPreRun` in - `src/lib/programs/posthog-integration/index.ts`. -- Detector: `detectProjectsWithAgent` in `src/lib/detection/agentic.ts`; + `src/store/programs/posthog-integration/index.ts`. +- Detector: `detectProjectsWithAgent` in `src/store/detection/agentic.ts`; self-driving uses the same detector with its own chooser. - Each run fires one `wizard: agentic detection` event tagged with the outcome (`flag-off | error | timeout | no-project | recommended | first-instrumentable`). diff --git a/docs/runbooks/aio-capture.md b/docs/runbooks/aio-capture.md index 667208d3c..a74f29c9f 100644 --- a/docs/runbooks/aio-capture.md +++ b/docs/runbooks/aio-capture.md @@ -76,7 +76,7 @@ dev-only concern. - **`agents-platform` harness** — placeholder today (`README` only). When it lands, whoever builds it needs to add a third transform + wire point in - `src/lib/agent/aio-capture.ts`. Search for `captureFromPiMessageEndEvent` + `src/agent/aio-capture.ts`. Search for `captureFromPiMessageEndEvent` for the pattern. - **Non-assistant messages** — user turns, tool results, and system messages don't get their own `$ai_generation`. Tool calls ride as content blocks diff --git a/docs/runbooks/warlock-kill-switch.md b/docs/runbooks/warlock-kill-switch.md index 7b0189767..509386f7b 100644 --- a/docs/runbooks/warlock-kill-switch.md +++ b/docs/runbooks/warlock-kill-switch.md @@ -63,7 +63,7 @@ Narrower is better — keep the security net on for users who aren't affected. ## Timing & reach - The flag is read **once at run start** - ([`agent-runner.ts`](../../src/lib/agent/agent-runner.ts), + ([`agent-runner.ts`](../../src/agent/runner/index.ts), `getAllFlagsForWizard()`), so a change takes effect on the **next** run — not on runs already in flight. Wizard runs are short-lived, so "next run" is effectively seconds to minutes. @@ -90,11 +90,11 @@ is a **local tool only** — it is per-machine and is **not** the incident lever One feature flag, read at run start, gates the two hooks Warlock registers. - **Flag key:** `wizard-warlock-disabled` — - [`src/lib/constants.ts`](../../src/lib/constants.ts) + [`src/store/shared/constants.ts`](../../src/store/shared/constants.ts) (`WIZARD_WARLOCK_DISABLED_FLAG_KEY`). - **Decision helper:** `isWarlockDisabled(flags)` in - [`src/lib/agent/agent-interface.ts`](../../src/lib/agent/agent-interface.ts) — - pure, unit-tested. + [`src/agent/agent-interface.ts`](../../src/agent/agent-interface.ts) — pure, + unit-tested. - **The gate:** at hook registration in the same file, when disabled the Pre/PostToolUse YARA hooks are registered as empty arrays (`[]`) instead of `createPreToolUseYaraHooks()` / `createPostToolUseYaraHooks()`. The SDK then @@ -114,7 +114,7 @@ exact string `'true'`. Everything else leaves Warlock **ON**: A network blip must never silently disable a security control. This is pinned by unit tests in -[`src/lib/__tests__/agent-interface.test.ts`](../../src/lib/__tests__/agent-interface.test.ts) +[`src/agent/__tests__/agent-interface.test.ts`](../../src/agent/__tests__/agent-interface.test.ts) (`describe('isWarlockDisabled (kill switch)')`). --- @@ -146,5 +146,6 @@ unit tests in - Scanner engine & rules: the [warlock](https://github.com/PostHog/warlock) sibling repo. -- Hook wiring: [`src/lib/yara-hooks.ts`](../../src/lib/yara-hooks.ts). +- Hook wiring: + [`src/store/security/yara-hooks.ts`](../../src/store/security/yara-hooks.ts). - Feedback / questions: wizard@posthog.com. diff --git a/src/ui/tui/__tests__/__snapshots__/keyboard-equivalence.test.tsx.snap b/e2e-harness/__tests__/__snapshots__/keyboard-equivalence.test.tsx.snap similarity index 100% rename from src/ui/tui/__tests__/__snapshots__/keyboard-equivalence.test.tsx.snap rename to e2e-harness/__tests__/__snapshots__/keyboard-equivalence.test.tsx.snap diff --git a/e2e-harness/__tests__/e2e-flow-snapshot.test.ts b/e2e-harness/__tests__/e2e-flow-snapshot.test.ts index 13335afd7..72ac75930 100644 --- a/e2e-harness/__tests__/e2e-flow-snapshot.test.ts +++ b/e2e-harness/__tests__/e2e-flow-snapshot.test.ts @@ -13,25 +13,28 @@ * Update goldens with `jest -u` after an intentional flow change. */ -import { WizardStore } from '@ui/tui/store'; -import { InkUI } from '@ui/tui/ink-ui'; -import { setUI } from '@ui/index'; -import { buildSession, RunPhase } from '@lib/wizard-session'; -import { Integration } from '@lib/constants'; -import { HostResolution } from '@lib/host-resolution'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { WizardReadiness } from '@lib/health-checks/readiness'; +import { WizardStore } from '@store/state/store'; +import { StoreUI } from '@store/ui/store-ui'; +import { setUI } from '@store/ui'; +import { buildSession, RunPhase } from '@store/session/wizard-session'; +import { Integration } from '@store/shared/constants'; +import { HostResolution } from '@store/host-resolution'; +import { FRAMEWORK_REGISTRY } from '@store/registry'; +import { WizardReadiness } from '@store/health-checks/readiness'; import { Program, getProgramConfig, type ProgramId, -} from '@lib/programs/program-registry'; -import { ScreenId } from '@ui/tui/router'; -import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@lib/programs/self-driving/detect'; -import { WizardCiDriver } from '../wizard-ci-driver'; -import { decideE2eAction, type WizardE2eProfile } from '../e2e-profile'; -import { profileFor } from '../profiles'; -import { flowFor } from '@lib/programs/flow-for'; +} from '@store/programs/program-registry'; +import { ScreenId } from '@tui/router'; +import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@store/programs/self-driving/detect'; +import { WizardCiDriver } from '@e2e-harness/wizard-ci-driver'; +import { + decideE2eAction, + type WizardE2eProfile, +} from '@e2e-harness/e2e-profile'; +import { profileFor } from '@e2e-harness/profiles'; +import { flowFor } from '@store/programs/flow-for'; /** * Walk a program flow offline using an e2e profile, injecting the external @@ -49,7 +52,7 @@ function traceFlow( params?: Record; }> { const store = new WizardStore(flowFor(program).flow); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); const session = buildSession({ installDir: '/tmp/e2e-snap', ci: true }); if (integration) { session.integration = integration; diff --git a/e2e-harness/__tests__/e2e-profile-ask.test.ts b/e2e-harness/__tests__/e2e-profile-ask.test.ts index 5bc8fdf97..6a9a2ed5f 100644 --- a/e2e-harness/__tests__/e2e-profile-ask.test.ts +++ b/e2e-harness/__tests__/e2e-profile-ask.test.ts @@ -7,8 +7,8 @@ * froze, so a workbench run can rely on it. */ -import { Overlay, ScreenId } from '@ui/tui/router'; -import type { AskQuestion } from '@lib/wizard-session'; +import { Overlay, ScreenId } from '@tui/router'; +import type { AskQuestion } from '@store/session/wizard-session'; import { DEFAULT_E2E_PROFILE, E2E_ANSWER_SENTINEL, @@ -16,10 +16,10 @@ import { answerQuestions, decideE2eAction, type WizardE2eProfile, -} from '../e2e-profile'; -import { profileFor, resolveE2eProfile } from '../profiles'; -import { Program } from '@lib/programs/program-registry'; -import type { CiState } from '../wizard-ci-driver'; +} from '@e2e-harness/e2e-profile'; +import { profileFor, resolveE2eProfile } from '@e2e-harness/profiles'; +import { Program } from '@store/programs/program-registry'; +import type { CiState } from '@e2e-harness/wizard-ci-driver'; const text = (id: string, prompt = id): AskQuestion => ({ id, diff --git a/e2e-harness/__tests__/e2e-result.test.ts b/e2e-harness/__tests__/e2e-result.test.ts index cb03ec971..2e00f93b2 100644 --- a/e2e-harness/__tests__/e2e-result.test.ts +++ b/e2e-harness/__tests__/e2e-result.test.ts @@ -11,19 +11,19 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; -import { OutroKind, RunPhase } from '@lib/wizard-session'; -import type { AskQuestion, WizardSession } from '@lib/wizard-session'; -import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@lib/programs/warehouse-source/detect'; -import { Overlay } from '@ui/tui/router'; +import { OutroKind, RunPhase } from '@store/session/wizard-session'; +import type { AskQuestion, WizardSession } from '@store/session/wizard-session'; +import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@store/programs/warehouse-source/detect'; +import { Overlay } from '@tui/router'; import { E2eRunRecorder, abortReasonFrom, buildE2eResult, detectedSourcesFrom, readReportFile, -} from '../e2e-result'; -import { DEFAULT_E2E_PROFILE, decideE2eAction } from '../e2e-profile'; -import type { CiState } from '../wizard-ci-driver'; +} from '@e2e-harness/e2e-result'; +import { DEFAULT_E2E_PROFILE, decideE2eAction } from '@e2e-harness/e2e-profile'; +import type { CiState } from '@e2e-harness/wizard-ci-driver'; const SECRET = 'sk_live_do_not_leak_9f2b'; diff --git a/src/ui/tui/__tests__/keyboard-equivalence.test.tsx b/e2e-harness/__tests__/keyboard-equivalence.test.tsx similarity index 87% rename from src/ui/tui/__tests__/keyboard-equivalence.test.tsx rename to e2e-harness/__tests__/keyboard-equivalence.test.tsx index 115411b09..1c4bb9d51 100644 --- a/src/ui/tui/__tests__/keyboard-equivalence.test.tsx +++ b/e2e-harness/__tests__/keyboard-equivalence.test.tsx @@ -11,35 +11,33 @@ import { RunPhase, McpOutcome, type ProgramId, -} from '../store'; -import { ScreenId, Overlay } from '../router'; -import { InkUI } from '../ink-ui'; -import { setUI } from '@ui/index'; +} from '@store/state/store'; +import { ScreenId, Overlay } from '@tui/router'; +import { StoreUI } from '@store/ui/store-ui'; +import { setUI } from '@store/ui'; import { buildSession, OutroKind, type WizardSession, -} from '@lib/wizard-session'; -import { Integration } from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { HostResolution } from '@lib/host-resolution'; -import { WizardReadiness } from '@lib/health-checks/readiness'; -import { SOURCE_MAPS_CONTEXT_KEYS } from '@lib/programs/error-tracking-upload-source-maps/detect'; -import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@lib/programs/self-driving/detect'; -import { ScreenContainer } from '../primitives/ScreenContainer'; +} from '@store/session/wizard-session'; +import { Integration } from '@store/shared/constants'; +import { FRAMEWORK_REGISTRY } from '@store/registry'; +import { HostResolution } from '@store/host-resolution'; +import { WizardReadiness } from '@store/health-checks/readiness'; +import { SOURCE_MAPS_CONTEXT_KEYS } from '@store/programs/error-tracking-upload-source-maps/detect'; +import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@store/programs/self-driving/detect'; +import { ScreenContainer } from '@tui/primitives/ScreenContainer'; import { createScreens, createServices, type ScreenServices, -} from '../screen-registry'; +} from '@tui/screen-registry'; import { ACTION_REGISTRY } from '@e2e-harness/action-registry'; -import { flowFor } from '@lib/programs/flow-for'; -import { UiStore } from '../ui-store'; +import { flowFor } from '@store/programs/flow-for'; +import { UiStore } from '@tui/ui-store'; -vi.mock('ink', () => - vi.importActual('../../../../node_modules/ink/build/index.js'), -); -vi.mock('@utils/analytics', () => ({ +vi.mock('ink', () => vi.importActual('../../node_modules/ink/build/index.js')); +vi.mock('@store/shared/analytics', () => ({ analytics: { capture: vi.fn(), wizardCapture: vi.fn(), @@ -49,31 +47,31 @@ vi.mock('@utils/analytics', () => ({ }, sessionProperties: vi.fn(() => ({})), })); -vi.mock('@utils/links', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/links', async (importOriginal) => ({ + ...(await importOriginal()), openTrackedLink: vi.fn(), })); -vi.mock('@utils/clipboard', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/clipboard', async (importOriginal) => ({ + ...(await importOriginal()), copyToClipboard: vi.fn().mockResolvedValue(false), openInBrowser: vi.fn().mockResolvedValue(false), })); vi.mock('opn', () => ({ default: vi.fn() })); -vi.mock('@lib/api', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/api', async (importOriginal) => ({ + ...(await importOriginal()), fetchSlackConnected: vi.fn().mockResolvedValue(false), fetchUserData: vi.fn(() => new Promise(() => undefined)), })); -vi.mock('@lib/wizard-tools', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/tools/tools', async (importOriginal) => ({ + ...(await importOriginal()), fetchSkillMenu: vi.fn(() => new Promise(() => undefined)), })); -vi.mock('@utils/setup-utils', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/setup-utils', async (importOriginal) => ({ + ...(await importOriginal()), getOrAskForProjectData: vi.fn(() => new Promise(() => undefined)), })); -vi.mock('@utils/wizard-abort', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/wizard-abort', async (importOriginal) => ({ + ...(await importOriginal()), wizardAbort: vi.fn().mockResolvedValue(undefined), })); @@ -363,7 +361,7 @@ const PAIRS: Pair[] = [ function makeStore(pair: Pair): WizardStore { const store = new WizardStore(flowFor(pair.program).flow); store.version = '0.0.0-test'; - setUI(new InkUI(store)); + setUI(new StoreUI(store)); const session = buildSession({ installDir: '/app', ci: false }); const integration = pair.integration ?? Integration.javascriptNode; session.integration = integration; diff --git a/e2e-harness/__tests__/wizard-ci-driver.test.ts b/e2e-harness/__tests__/wizard-ci-driver.test.ts index 01127030d..cfadd18cf 100644 --- a/e2e-harness/__tests__/wizard-ci-driver.test.ts +++ b/e2e-harness/__tests__/wizard-ci-driver.test.ts @@ -9,27 +9,37 @@ * through the driver. */ -import { WizardStore } from '@ui/tui/store'; -import { InkUI } from '@ui/tui/ink-ui'; -import { setUI } from '@ui/index'; -import { buildSession, RunPhase, McpOutcome } from '@lib/wizard-session'; -import { HostResolution } from '@lib/host-resolution'; -import { Integration } from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { WizardReadiness } from '@lib/health-checks/readiness'; -import { ScreenId, Overlay } from '@ui/tui/router'; -import { Program } from '@lib/programs/program-registry'; -import { WizardCiDriver, UnknownActionError } from '../wizard-ci-driver'; -import { ACTION_REGISTRY, NO_ACTION_SCREENS } from '../action-registry'; -import { SOURCE_MAPS_CONTEXT_KEYS } from '@lib/programs/error-tracking-upload-source-maps/index'; -import { OutroKind } from '@lib/wizard-session'; -import { flowFor } from '@lib/programs/flow-for'; +import { WizardStore } from '@store/state/store'; +import { StoreUI } from '@store/ui/store-ui'; +import { setUI } from '@store/ui'; +import { + buildSession, + RunPhase, + McpOutcome, +} from '@store/session/wizard-session'; +import { HostResolution } from '@store/host-resolution'; +import { Integration } from '@store/shared/constants'; +import { FRAMEWORK_REGISTRY } from '@store/registry'; +import { WizardReadiness } from '@store/health-checks/readiness'; +import { ScreenId, Overlay } from '@tui/router'; +import { Program } from '@store/programs/program-registry'; +import { + WizardCiDriver, + UnknownActionError, +} from '@e2e-harness/wizard-ci-driver'; +import { + ACTION_REGISTRY, + NO_ACTION_SCREENS, +} from '@e2e-harness/action-registry'; +import { SOURCE_MAPS_CONTEXT_KEYS } from '@store/programs/error-tracking-upload-source-maps'; +import { OutroKind } from '@store/session/wizard-session'; +import { flowFor } from '@store/programs/flow-for'; function freshStore(): WizardStore { const store = new WizardStore(flowFor(Program.PostHogIntegration).flow); - // Headless: a real store + InkUI (which only forwards to the store), no Ink + // Headless: a real store + StoreUI (which only forwards to the store), no Ink // render. setUI so any getUI() path the store touches resolves. - setUI(new InkUI(store)); + setUI(new StoreUI(store)); const session = buildSession({ installDir: '/tmp/ci-driver-test', ci: true, // OAuth-bypass + ai-opt-in auto-consent semantics @@ -49,7 +59,7 @@ const cleanReadiness = { describe('WizardCiDriver — full integration flow', () => { it('lets a failed run exit or continue to MCP', () => { const store = freshStore(); - const ui = new InkUI(store); + const ui = new StoreUI(store); const driver = new WizardCiDriver(store); store.setCredentials({ accessToken: 'phx_secret_should_not_leak', @@ -201,7 +211,7 @@ describe('WizardCiDriver — wizard_ask overlay', () => { describe('WizardCiDriver — self-driving integration check', () => { function selfDrivingStore(): WizardStore { const store = new WizardStore(flowFor(Program.SelfDriving).flow); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); store.session = buildSession({ installDir: '/tmp/ci-driver-sd', ci: true }); return store; } @@ -243,7 +253,7 @@ describe('WizardCiDriver — source-maps project pick', () => { const store = new WizardStore( flowFor(Program.ErrorTrackingUploadSourceMaps).flow, ); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); store.session = buildSession({ installDir: '/tmp/ci-driver-sm', ci: true }); return store; } diff --git a/e2e-harness/action-registry.ts b/e2e-harness/action-registry.ts index 63c48870c..00d346777 100644 --- a/e2e-harness/action-registry.ts +++ b/e2e-harness/action-registry.ts @@ -12,18 +12,18 @@ * actions speak only in store setters and generic params. */ -import type { WizardStore } from '@ui/tui/store'; -import { ScreenId, Overlay, type ScreenName } from '@ui/tui/router'; -import { McpOutcome, OutroKind } from '@lib/wizard-session'; -import type { AskAnswers } from '@lib/wizard-session'; +import type { WizardStore } from '@store/state/store'; +import { ScreenId, Overlay, type ScreenName } from '@tui/router'; +import { McpOutcome, OutroKind } from '@store/session/wizard-session'; +import type { AskAnswers } from '@store/session/wizard-session'; import { SOURCE_MAPS_CONTEXT_KEYS, VARIANT_DISPLAY_NAME, -} from '@lib/programs/error-tracking-upload-source-maps/index'; +} from '@store/programs/error-tracking-upload-source-maps'; import { GITHUB_REQUIRED_BODY, GITHUB_REQUIRED_MESSAGE, -} from '@lib/programs/self-driving/detect'; +} from '@store/programs/self-driving/detect'; /** One commit action legal on a given screen. */ export interface DriverAction { diff --git a/e2e-harness/e2e-profile.ts b/e2e-harness/e2e-profile.ts index 051fab496..9ea905962 100644 --- a/e2e-harness/e2e-profile.ts +++ b/e2e-harness/e2e-profile.ts @@ -7,9 +7,9 @@ * make. Add a program's profile to {@link ./profiles} to make it e2e-drivable. */ -import { ScreenId, Overlay, type ScreenName } from '@ui/tui/router'; -import type { AskAnswers, AskQuestion } from '@lib/wizard-session'; -import type { CiState } from './wizard-ci-driver.js'; +import { ScreenId, Overlay, type ScreenName } from '@tui/router'; +import type { AskAnswers, AskQuestion } from '@store/session/wizard-session'; +import type { CiState } from '@e2e-harness/wizard-ci-driver'; /** Which option to pick for a setup disambiguation question. */ export type SetupChoice = 'first' | 'last'; diff --git a/e2e-harness/e2e-result.ts b/e2e-harness/e2e-result.ts index e34a52dfd..d3d245fb6 100644 --- a/e2e-harness/e2e-result.ts +++ b/e2e-harness/e2e-result.ts @@ -21,10 +21,10 @@ import fs from 'fs'; import path from 'path'; -import { OutroKind, type WizardSession } from '@lib/wizard-session'; -import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@lib/programs/warehouse-source/detect'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; -import type { E2eDecisionReport } from './e2e-profile.js'; +import { OutroKind, type WizardSession } from '@store/session/wizard-session'; +import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@store/programs/warehouse-source/detect'; +import type { DetectedSource } from '@store/services/warehouse-sources/types'; +import type { E2eDecisionReport } from '@e2e-harness/e2e-profile'; /** One `wizard_ask` batch the run was shown. */ export interface E2eAskRecord { diff --git a/e2e-harness/profiles.ts b/e2e-harness/profiles.ts index 3cc126d33..38f8271f7 100644 --- a/e2e-harness/profiles.ts +++ b/e2e-harness/profiles.ts @@ -11,23 +11,23 @@ * so `decideE2eAction` stays a pure function of (state, profile). */ -import { Program, type ProgramId } from '@lib/programs/program-registry'; +import { Program, type ProgramId } from '@store/programs/program-registry'; import { DEFAULT_E2E_PROFILE, DEFAULT_E2E_VARIATION, type AskAnswerRule, type WizardE2eProfile, type WizardE2eVariation, -} from './e2e-profile.js'; -import posthogIntegrationE2e from '@lib/programs/posthog-integration/test/e2e.json'; -import aiObservabilityE2e from '@lib/programs/ai-observability/test/e2e.json'; -import metricsE2e from '@lib/programs/metrics/test/e2e.json'; -import replayVisionE2e from '@lib/programs/replay-vision/test/e2e.json'; -import selfDrivingE2e from '@lib/programs/self-driving/test/e2e.json'; -import sourceMapsE2e from '@lib/programs/error-tracking-upload-source-maps/test/e2e.json'; -import errorTrackingE2e from '@lib/programs/error-tracking/test/e2e.json'; -import warehouseSourceE2e from '@lib/programs/warehouse-source/test/e2e.json'; -import auditE2e from '@lib/programs/audit/test/e2e.json'; +} from '@e2e-harness/e2e-profile'; +import posthogIntegrationE2e from '@store/programs/posthog-integration/test/e2e.json'; +import aiObservabilityE2e from '@store/programs/ai-observability/test/e2e.json'; +import metricsE2e from '@store/programs/metrics/test/e2e.json'; +import replayVisionE2e from '@store/programs/replay-vision/test/e2e.json'; +import selfDrivingE2e from '@store/programs/self-driving/test/e2e.json'; +import sourceMapsE2e from '@store/programs/error-tracking-upload-source-maps/test/e2e.json'; +import errorTrackingE2e from '@store/programs/error-tracking/test/e2e.json'; +import warehouseSourceE2e from '@store/programs/warehouse-source/test/e2e.json'; +import auditE2e from '@store/programs/audit/test/e2e.json'; const PROFILES: Partial> = { [Program.PostHogIntegration]: diff --git a/e2e-harness/tsconfig.json b/e2e-harness/tsconfig.json new file mode 100644 index 000000000..49053280f --- /dev/null +++ b/e2e-harness/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "outDir": "../.tsbuild/harness" + }, + "include": [ + "**/*", + "../scripts/**/*", + "../__mocks__/**/*", + "../vitest.config.ts", + "../tsdown.config.ts", + "../types/**/*.d.ts", + "../vitest.shared.ts", + "../src/store/vitest.config.ts", + "../src/agent/vitest.config.ts", + "../src/tui/vitest.config.ts", + "../src/cli/vitest.config.ts", + "../src/__tests__/architecture/vitest.config.ts" + ], + "references": [ + { + "path": "../tsconfig.env.json" + }, + { + "path": "../src/store" + }, + { + "path": "../src/agent" + }, + { + "path": "../src/tui" + }, + { + "path": "../src/cli" + } + ] +} diff --git a/e2e-harness/vitest.config.ts b/e2e-harness/vitest.config.ts new file mode 100644 index 000000000..7041faeac --- /dev/null +++ b/e2e-harness/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineProject } from 'vitest/config'; +import { surfaceProject } from '../vitest.shared.js'; + +export default defineProject( + surfaceProject({ + name: 'harness', + imports: ['env', 'store', 'agent', 'tui', 'cli', 'harness'], + ink: 'mock', + }), +); diff --git a/e2e-harness/wizard-ci-driver.ts b/e2e-harness/wizard-ci-driver.ts index 79a5873fb..c068d95e9 100644 --- a/e2e-harness/wizard-ci-driver.ts +++ b/e2e-harness/wizard-ci-driver.ts @@ -18,10 +18,13 @@ * the driver issues the final commit directly instead. */ -import type { WizardStore } from '@ui/tui/store'; -import type { ScreenName } from '@ui/tui/router'; -import type { PendingQuestion, RunPhase } from '@lib/wizard-session'; -import { actionsForScreen, MissingParamError } from './action-registry.js'; +import type { WizardStore } from '@store/state/store'; +import type { ScreenName } from '@tui/router'; +import type { PendingQuestion, RunPhase } from '@store/session/wizard-session'; +import { + actionsForScreen, + MissingParamError, +} from '@e2e-harness/action-registry'; /** A setup question projected for the harness (no `detect` fn, no closures). */ export interface SetupQuestionView { diff --git a/e2e-tests/jest.config.ts b/e2e-tests/jest.config.ts index 4ac6c40e2..bd26bee37 100644 --- a/e2e-tests/jest.config.ts +++ b/e2e-tests/jest.config.ts @@ -14,6 +14,24 @@ const config: JestConfig = { '^.+\\.tsx?$': 'ts-jest', }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + // The wizard sources use ESM-style relative `.js` specifiers and the + // surface aliases from ../tsconfig.build.json; jest resolves neither. + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + '^@env$': '/../src/env.ts', + '^@store$': '/../src/store/index.ts', + '^@store/types$': '/../src/store/types.ts', + '^@store/programs$': '/../src/store/programs/index.ts', + '^@store/(.*)$': '/../src/store/$1', + '^@agent$': '/../src/agent/index.ts', + '^@agent/types$': '/../src/agent/types.ts', + '^@agent/(.*)$': '/../src/agent/$1', + '^@tui$': '/../src/tui/index.ts', + '^@tui/types$': '/../src/tui/types.ts', + '^@tui/console$': '/../src/tui/console/index.ts', + '^@tui/(.*)$': '/../src/tui/$1', + '^@cli/(.*)$': '/../src/cli/$1', + }, verbose: true, setupFilesAfterEnv: ['/mocks/setup.ts'], globalSetup: '/global-setup.ts', diff --git a/e2e-tests/mocks/handlers.ts b/e2e-tests/mocks/handlers.ts index 5cf864edf..f22ea9e96 100644 --- a/e2e-tests/mocks/handlers.ts +++ b/e2e-tests/mocks/handlers.ts @@ -1,6 +1,6 @@ import { http, HttpResponse, passthrough } from 'msw'; -import { getCloudUrl } from '../../src/utils/urls'; -import { DEFAULT_HOST_URL } from '../../src/lib/constants'; +import { getCloudUrl } from '../../src/store/shared/urls'; +import { DEFAULT_HOST_URL } from '../../src/store/shared/constants'; import { fixtureTracker } from './fixture-tracker'; export const shouldRecord = process.env.RECORD_FIXTURES === 'true'; diff --git a/package.json b/package.json index fb34428d9..cbd055d2a 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,13 @@ "build:watch:ci": "WIZARD_BUILD_NODE_ENV=ci tsdown --watch", "build": "tsdown", "build:ci": "WIZARD_BUILD_NODE_ENV=ci pnpm build", - "typecheck": "tsc --noEmit", + "typecheck": "tsc -b tsconfig.solution.json", + "typecheck:store": "tsc -b src/store", + "typecheck:agent": "tsc -b src/agent", + "typecheck:tui": "tsc -b src/tui", + "typecheck:cli": "tsc -b src/cli", + "typecheck:harness": "tsc -b e2e-harness", + "typecheck:arch": "tsc -b src/__tests__/architecture", "postbuild": "chmod +x ./dist/bin.js && cp -r scripts/** dist && rm -f dist/*.no-jest.* && pnpm test:smoke && pnpm test:warlock", "test:smoke": "bash ./scripts/smoke-test.sh", "test:warlock": "tsx scripts/warlock-smoke-test.ts", diff --git a/scripts/__fixtures__/chunk-manifest.ci.json b/scripts/__fixtures__/chunk-manifest.ci.json index e2c426171..49af3ed2a 100644 --- a/scripts/__fixtures__/chunk-manifest.ci.json +++ b/scripts/__fixtures__/chunk-manifest.ci.json @@ -1,430 +1,252 @@ { "add-mcp-server-to-clients.js": { "sources": [ - "src/steps/add-mcp-server-to-clients/MCPClient.ts", - "src/steps/add-mcp-server-to-clients/clients/claude-code.ts", - "src/steps/add-mcp-server-to-clients/clients/claude-web.ts", - "src/steps/add-mcp-server-to-clients/clients/codex.ts", - "src/steps/add-mcp-server-to-clients/clients/cursor.ts", - "src/steps/add-mcp-server-to-clients/clients/opencode.ts", - "src/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts", - "src/steps/add-mcp-server-to-clients/clients/zed.ts", - "src/steps/add-mcp-server-to-clients/index.ts", - "src/steps/add-mcp-server-to-clients/plugin-client.ts" + "src/store/agent-protocol/agent-signals.ts", + "src/store/api.ts", + "src/store/host-resolution.ts", + "src/store/services/oauth/program-scopes.ts", + "src/store/services/steps/add-mcp-server-to-clients/MCPClient.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/claude-code.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/claude-web.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/codex.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/cursor.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/opencode.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/zed.ts", + "src/store/services/steps/add-mcp-server-to-clients/defaults.ts", + "src/store/services/steps/add-mcp-server-to-clients/index.ts", + "src/store/services/steps/add-mcp-server-to-clients/plugin-client.ts", + "src/store/services/steps/add-mcp-server-to-clients/results.ts", + "src/store/shared/bounded-fs.ts", + "src/store/shared/errors/agent-map.ts", + "src/store/shared/errors/auth.ts", + "src/store/shared/errors/catalog.ts", + "src/store/shared/errors/codes.ts", + "src/store/shared/errors/detect-map.ts", + "src/store/shared/errors/emit.ts", + "src/store/shared/errors/run-failure.ts", + "src/store/shared/errors/sanitize.ts", + "src/store/shared/errors/skill-map.ts", + "src/store/shared/links.ts", + "src/store/shared/oauth-errors.ts", + "src/store/shared/oauth.ts", + "src/store/shared/package-manager.ts", + "src/store/shared/project-resolution.ts", + "src/store/shared/provisioning.ts", + "src/store/shared/semver.ts", + "src/store/shared/setup-utils.ts", + "src/store/shared/telemetry.ts", + "src/store/shared/urls.ts", + "src/store/shared/wizard-abort.ts" ], "imports": [ - "analytics.js", - "debug.js", - "defaults.js", - "rolldown-runtime.js", - "telemetry.js", - "ui.js" - ] - }, - "agent-interface.js": { - "sources": [ - "src/lib/agent-env-isolation.ts", - "src/lib/agent/agent-interface.ts", - "src/lib/agent/agent-phase.ts", - "src/lib/agent/bash-fence.ts", - "src/lib/agent/commandments.ts", - "src/lib/agent/output-signals.ts", - "src/lib/agent/runner/harness/pi/gateway.ts", - "src/lib/agent/runner/harness/pi/runtime-notes.ts", - "src/lib/agent/runner/switchboard/commandments.ts", - "src/lib/agent/stored-login.ts", - "src/lib/agent/triage-provider.ts", - "src/lib/auth-session-state.ts", - "src/lib/claude-settings.ts", - "src/lib/fetch-retry.ts", - "src/lib/safe-tools.ts", - "src/lib/secret-vault.ts", - "src/lib/wizard-ask-bridge.ts", - "src/lib/wizard-tools/handoff.ts", - "src/lib/wizard-tools/mcp.ts", - "src/lib/wizard-tools/tools.ts", - "src/utils/custom-headers.ts", - "src/utils/env-scan.ts" - ], - "imports": [ - "analytics.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", - "queue-tools.js", - "rolldown-runtime.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" - ] - }, - "agent-prompt-loader.js": { - "sources": [ - "src/lib/agent/agent-prompt-loader.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "debug.js", - "queue-tools.js" + "analytics.js" ] }, - "agent-runner.js": { - "sources": [ - "src/lib/agent/agent-prompt.ts", - "src/lib/agent/agent-runner.ts", - "src/lib/agent/runner/harness/anthropic/index.ts", - "src/lib/agent/runner/index.ts", - "src/lib/agent/runner/sequence/linear.ts", - "src/lib/agent/runner/sequence/orchestrator/executor.ts", - "src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts", - "src/lib/agent/runner/sequence/orchestrator/run-metrics.ts", - "src/lib/agent/runner/sequence/orchestrator/seeded-deps.ts", - "src/lib/agent/runner/shared/bootstrap.ts", - "src/lib/agent/runner/shared/errors.ts", - "src/lib/agent/runner/switchboard/flags/index.ts", - "src/lib/agent/runner/switchboard/flags/orchestrator.ts", - "src/lib/agent/runner/switchboard/flags/schemes.ts", - "src/lib/agent/runner/switchboard/flags/self-driving.ts", - "src/lib/agent/runner/switchboard/harness.ts", - "src/lib/agent/runner/switchboard/index.ts", - "src/lib/agent/runner/switchboard/sequence.ts", - "src/lib/middleware/benchmark.ts", - "src/lib/middleware/benchmarks/cache-tracker.ts", - "src/lib/middleware/benchmarks/compaction-tracker.ts", - "src/lib/middleware/benchmarks/context-size-tracker.ts", - "src/lib/middleware/benchmarks/cost-tracker.ts", - "src/lib/middleware/benchmarks/duration-tracker.ts", - "src/lib/middleware/benchmarks/index.ts", - "src/lib/middleware/benchmarks/json-writer.ts", - "src/lib/middleware/benchmarks/summary.ts", - "src/lib/middleware/benchmarks/token-tracker.ts", - "src/lib/middleware/benchmarks/turn-counter.ts", - "src/lib/middleware/config.ts", - "src/lib/middleware/phase-detector.ts", - "src/lib/middleware/pipeline.ts", - "src/lib/programs/audit/ledger-watcher.ts", - "src/utils/terminal-bell.ts" + "agent.js": { + "sources": [ + "src/agent/agent-prompt.ts", + "src/agent/detection/agentic.ts", + "src/agent/mcp-prompt-streaming.ts", + "src/agent/middleware/benchmark.ts", + "src/agent/middleware/benchmarks/cache-tracker.ts", + "src/agent/middleware/benchmarks/compaction-tracker.ts", + "src/agent/middleware/benchmarks/context-size-tracker.ts", + "src/agent/middleware/benchmarks/cost-tracker.ts", + "src/agent/middleware/benchmarks/duration-tracker.ts", + "src/agent/middleware/benchmarks/index.ts", + "src/agent/middleware/benchmarks/json-writer.ts", + "src/agent/middleware/benchmarks/summary.ts", + "src/agent/middleware/benchmarks/token-tracker.ts", + "src/agent/middleware/benchmarks/turn-counter.ts", + "src/agent/middleware/config.ts", + "src/agent/middleware/phase-detector.ts", + "src/agent/middleware/pipeline.ts", + "src/agent/runner/harness/anthropic/index.ts", + "src/agent/runner/index.ts", + "src/agent/runner/sequence/linear.ts", + "src/agent/runner/sequence/orchestrator/executor.ts", + "src/agent/runner/sequence/orchestrator/orchestrator-runner.ts", + "src/agent/runner/sequence/orchestrator/run-metrics.ts", + "src/agent/runner/sequence/orchestrator/seeded-deps.ts", + "src/agent/runner/shared/bootstrap.ts", + "src/agent/runner/shared/errors.ts", + "src/agent/runner/switchboard/flags/index.ts", + "src/agent/runner/switchboard/flags/orchestrator.ts", + "src/agent/runner/switchboard/flags/schemes.ts", + "src/agent/runner/switchboard/flags/self-driving.ts", + "src/agent/runner/switchboard/harness.ts", + "src/agent/runner/switchboard/index.ts", + "src/agent/runner/switchboard/sequence.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "agent-prompt-loader.js", "analytics.js", - "constants.js", - "debug.js", - "environment.js", - "errors.js", - "file-watcher.js", - "gateway-session.js", - "package-manager.js", "pi.js", + "programs.js", "queue-tools.js", - "readiness.js", - "registry.js", - "rolldown-runtime.js", - "setup-utils.js", - "token-pricing.js", - "ui.js", - "version.js", - "wizard-abort.js", - "yara-hooks.js" + "store.js" ] }, - "analytics.js": { - "sources": [ - "src/utils/analytics.ts", - "src/utils/ci-flag-overrides.ts" - ], - "imports": [ - "constants.js", - "debug.js", - "version.js", - "wizard-session.js" - ] - }, - "api.js": { - "sources": [ - "src/lib/api.ts" - ], - "imports": [ - "analytics.js", - "constants.js", - "rolldown-runtime.js" - ] - }, - "bin.js": { + "agent-interface.js": { "sources": [ - "bin.ts", - "src/commands/ai-observability.ts", - "src/commands/audit.ts", - "src/commands/basic-integration/index.ts", - "src/commands/basic-integration/skill.ts", - "src/commands/cli/add.ts", - "src/commands/cli/index.ts", - "src/commands/command.ts", - "src/commands/doctor.ts", - "src/commands/error-tracking.ts", - "src/commands/factories/family-command-factory.ts", - "src/commands/factories/family-picker.tsx", - "src/commands/factories/native-command-factory.ts", - "src/commands/factories/shared.ts", - "src/commands/mcp-analytics.ts", - "src/commands/mcp/add.ts", - "src/commands/mcp/index.ts", - "src/commands/mcp/remove.ts", - "src/commands/mcp/tui-availability.ts", - "src/commands/mcp/tutorial.ts", - "src/commands/metrics.ts", - "src/commands/migrate.ts", - "src/commands/provision.ts", - "src/commands/replay-vision.ts", - "src/commands/revenue.ts", - "src/commands/self-driving.ts", - "src/commands/skill-program-options.ts", - "src/commands/skill.ts", - "src/commands/slack.ts", - "src/commands/upload-sourcemaps.ts", - "src/commands/warehouse.ts", - "src/lib/programs/ai-opt-in-gate.ts", - "src/lib/programs/dispatch-family.ts", - "src/lib/programs/flow-for.ts", - "src/lib/programs/run-config.ts", - "src/lib/runners/resolve-no-telemetry.ts", - "src/lib/runners/run-non-interactive.ts", - "src/lib/runners/run-wizard-ci.ts", - "src/lib/runners/run-wizard-headless.ts", - "src/lib/runners/run-wizard.ts", - "src/ui/mint-failure.ts", - "src/ui/tui/hooks/keyboard-hints-utils.ts", - "src/ui/tui/hooks/useKeyBindings.ts", - "src/ui/tui/hooks/useKeyboardHints.tsx", - "src/ui/tui/hooks/useStdoutDimensions.ts", - "src/ui/tui/primitives/ConfirmButton.tsx", - "src/ui/tui/primitives/PickerMenu.tsx", - "src/ui/tui/primitives/PromptLabel.tsx", - "src/ui/tui/primitives/content-types.ts", - "src/ui/tui/primitives/layout-helpers.ts", - "src/ui/tui/primitives/picker-filter.ts", - "src/ui/tui/styles.ts", - "src/wizard.ts" + "src/agent/agent-interface.ts", + "src/agent/bash-fence.ts", + "src/agent/commandments.ts", + "src/agent/gateway/gateway-session.ts", + "src/agent/output-signals.ts", + "src/agent/runner/harness/pi/gateway.ts", + "src/agent/runner/harness/pi/runtime-notes.ts", + "src/agent/runner/switchboard/commandments.ts", + "src/agent/stored-login.ts", + "src/agent/tools/mcp.ts", + "src/agent/triage-provider.ts" ], "imports": [ "add-mcp-server-to-clients.js", - "agent-interface.js", - "agent-runner.js", "analytics.js", - "api.js", - "ci-install.js", - "constants.js", - "debug.js", - "env-api-key.js", - "environment.js", - "errors.js", - "file.js", - "gateway-session.js", - "headless-ui.js", - "interactive.js", - "local-dev.js", - "logging-ui.js", - "non-interactive.js", - "playground.js", - "posthog.js", - "provisioning.js", - "run-failure.js", - "setup-utils.js", - "start-tui.js", - "store.js", - "task-stream.js", - "telemetry.js", - "token-pricing.js", - "ui.js", - "version.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "queue-tools.js", + "store.js" ] }, - "bounded-fs.js": { + "agent-prompt-loader.js": { "sources": [ - "src/utils/bounded-fs.ts" + "src/agent/agent-prompt-loader.ts" ], "imports": [ "analytics.js", - "debug.js" - ] - }, - "ci-install.js": { - "sources": [ - "src/commands/basic-integration/ci-install.ts" - ], - "imports": [ - "bin.js", - "errors.js", - "logging-ui.js", - "provisioning.js", - "run-failure.js", - "ui.js" - ] - }, - "constants.js": { - "sources": [ - "src/lib/constants.ts" - ], - "imports": [ - "local-dev.js", - "version.js" - ] - }, - "debug.js": { - "sources": [], - "imports": [ - "debug.js" - ] - }, - "defaults.js": { - "sources": [ - "src/steps/add-mcp-server-to-clients/defaults.ts", - "src/steps/add-mcp-server-to-clients/results.ts" - ], - "imports": [] - }, - "endpoints.js": { - "sources": [ - "src/lib/health-checks/endpoints.ts" - ], - "imports": [ - "constants.js", - "debug.js" - ] - }, - "env-api-key.js": { - "sources": [ - "src/utils/env-api-key.ts" - ], - "imports": [ - "bounded-fs.js", - "rolldown-runtime.js" - ] - }, - "environment.js": { - "sources": [ - "src/utils/environment.ts" - ], - "imports": [ - "rolldown-runtime.js" + "queue-tools.js", + "store.js" ] }, - "errors.js": { - "sources": [ - "src/lib/agent-signals.ts", - "src/lib/errors/agent-map.ts", - "src/lib/errors/auth.ts", - "src/lib/errors/catalog.ts", - "src/lib/errors/codes.ts", - "src/lib/errors/detect-map.ts", - "src/lib/errors/emit.ts", - "src/lib/errors/run-failure.ts", - "src/lib/errors/sanitize.ts", - "src/lib/errors/skill-map.ts" - ], - "imports": [] - }, - "file.js": { + "analytics.js": { "sources": [ - "src/lib/task-stream/destinations/file.ts" + "src/env.ts", + "src/store/local-dev.ts", + "src/store/session/wizard-session.ts", + "src/store/shared/analytics.ts", + "src/store/shared/ci-flag-overrides.ts", + "src/store/shared/constants.ts", + "src/store/shared/debug.ts", + "src/store/shared/paths.ts", + "src/store/shared/version.ts", + "src/store/ui/index.ts", + "src/store/ui/null-ui.ts" ], "imports": [ - "debug.js" + "analytics.js" ] }, - "file-watcher.js": { + "bin.js": { "sources": [ - "src/lib/file-watcher.ts" + "bin.ts" ], "imports": [ - "debug.js" + "main.js" ] }, - "gateway-session.js": { + "ci-install.js": { "sources": [ - "src/lib/gateway-session.ts" + "src/cli/commands/basic-integration/ci-install.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "debug.js", - "endpoints.js", - "errors.js", - "wizard-abort.js" + "console.js", + "runners.js", + "store.js" ] }, - "headless-ui.js": { + "console.js": { "sources": [ - "src/ui/tui/console/headless-ui.ts" + "src/tui/console/headless-ui.ts", + "src/tui/console/logging-ui.ts" ], "imports": [ - "logging-ui.js" + "analytics.js", + "store.js" ] }, "interactive.js": { "sources": [ - "src/commands/basic-integration/interactive.ts" - ], - "imports": [ - "bin.js", - "run-failure.js" - ] - }, - "local-dev.js": { - "sources": [ - "src/lib/local-dev.ts" - ], - "imports": [] - }, - "logging-ui.js": { - "sources": [ - "src/ui/tui/console/logging-ui.ts" + "src/cli/commands/basic-integration/interactive.ts" + ], + "imports": [ + "runners.js", + "store.js" + ] + }, + "main.js": { + "sources": [ + "src/cli/commands/ai-observability.ts", + "src/cli/commands/audit.ts", + "src/cli/commands/basic-integration/index.ts", + "src/cli/commands/basic-integration/skill.ts", + "src/cli/commands/cli/add.ts", + "src/cli/commands/cli/index.ts", + "src/cli/commands/command.ts", + "src/cli/commands/doctor.ts", + "src/cli/commands/error-tracking.ts", + "src/cli/commands/factories/family-command-factory.ts", + "src/cli/commands/factories/native-command-factory.ts", + "src/cli/commands/factories/shared.ts", + "src/cli/commands/mcp-analytics.ts", + "src/cli/commands/mcp/add.ts", + "src/cli/commands/mcp/index.ts", + "src/cli/commands/mcp/remove.ts", + "src/cli/commands/mcp/tui-availability.ts", + "src/cli/commands/mcp/tutorial.ts", + "src/cli/commands/metrics.ts", + "src/cli/commands/migrate.ts", + "src/cli/commands/provision.ts", + "src/cli/commands/replay-vision.ts", + "src/cli/commands/revenue.ts", + "src/cli/commands/self-driving.ts", + "src/cli/commands/skill-program-options.ts", + "src/cli/commands/skill.ts", + "src/cli/commands/slack.ts", + "src/cli/commands/upload-sourcemaps.ts", + "src/cli/commands/warehouse.ts", + "src/cli/dispatch-family.ts", + "src/cli/main.ts", + "src/cli/wizard.ts" ], "imports": [ - "constants.js", - "readiness.js" + "add-mcp-server-to-clients.js", + "agent.js", + "analytics.js", + "ci-install.js", + "console.js", + "interactive.js", + "non-interactive.js", + "playground.js", + "runners.js", + "store.js", + "tui.js" ] }, "mcp.js": { "sources": [ - "src/lib/agent/runner/harness/pi/mcp.ts" + "src/agent/runner/harness/pi/mcp.ts" ], "imports": [ - "debug.js", - "version.js" - ] - }, - "mcp-prompt-streaming.js": { - "sources": [ - "src/lib/agent/mcp-prompt-streaming.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "constants.js", - "debug.js", - "gateway-session.js" + "analytics.js" ] }, "non-interactive.js": { "sources": [ - "src/commands/basic-integration/non-interactive.ts" + "src/cli/commands/basic-integration/non-interactive.ts" ], "imports": [ - "errors.js", - "ui.js" + "add-mcp-server-to-clients.js", + "analytics.js" ] }, "orchestrator-tools.js": { "sources": [ - "src/lib/agent/runner/harness/pi/orchestrator-tools.ts" + "src/agent/runner/harness/pi/orchestrator-tools.ts" ], "imports": [ "analytics.js", @@ -432,673 +254,342 @@ ] }, "package-json.js": { - "sources": [ - "src/utils/package-json.ts" - ], - "imports": [ - "rolldown-runtime.js" - ] - }, - "package-manager.js": { - "sources": [ - "src/frameworks/python/utils.ts", - "src/lib/detection/package-manager.ts" - ], + "sources": [], "imports": [ - "setup-utils.js" + "package-json.js" ] }, "pi.js": { "sources": [ - "src/lib/agent/aio-capture.ts", - "src/lib/agent/runner/harness/pi/completion.ts", - "src/lib/agent/runner/harness/pi/index.ts" + "src/agent/aio-capture.ts", + "src/agent/runner/harness/pi/completion.ts", + "src/agent/runner/harness/pi/index.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "analytics.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", "mcp.js", "security.js", + "store.js", "subagent.js", "task.js", "tasks.js", - "tools.js", - "ui.js", - "version.js", - "yara-hooks.js" + "tools.js" ] }, "playground.js": { "sources": [ - "src/commands/basic-integration/playground.ts", - "src/ui/tui/playground/PlaygroundApp.tsx", - "src/ui/tui/playground/demos/AiOptInDemo.tsx", - "src/ui/tui/playground/demos/AskModalDemo.tsx", - "src/ui/tui/playground/demos/AuditChecksDemo.tsx", - "src/ui/tui/playground/demos/DoctorReportDemo.tsx", - "src/ui/tui/playground/demos/EndScreensDemo.tsx", - "src/ui/tui/playground/demos/HealthCheckDemo.tsx", - "src/ui/tui/playground/demos/InputDemo.tsx", - "src/ui/tui/playground/demos/KeyboardHintsDemo.tsx", - "src/ui/tui/playground/demos/LayoutDemo.tsx", - "src/ui/tui/playground/demos/LearnDeckDemo.tsx", - "src/ui/tui/playground/demos/LogDemo.tsx", - "src/ui/tui/playground/demos/McpDemo.tsx", - "src/ui/tui/playground/demos/McpSuggestedPromptsDemo.tsx", - "src/ui/tui/playground/demos/ModalDemo.tsx", - "src/ui/tui/playground/demos/ProgressDemo.tsx", - "src/ui/tui/playground/demos/RunScreenDemo.tsx", - "src/ui/tui/playground/demos/ViewportGuardDemo.tsx", - "src/ui/tui/playground/demos/WelcomeDemo.tsx", - "src/ui/tui/playground/start-playground.ts" - ], - "imports": [ - "bin.js", - "debug.js", - "readiness.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "terminal.js", - "version.js" - ] - }, - "posthog.js": { - "sources": [ - "src/lib/task-stream/destinations/posthog.ts" + "src/cli/commands/basic-integration/playground.ts" ], "imports": [ - "debug.js" + "analytics.js", + "tui.js" ] }, - "provisioning.js": { + "programs.js": { "sources": [ - "src/utils/provisioning.ts", - "src/utils/urls.ts" + "src/store/programs/ai-opt-in-gate.ts", + "src/store/programs/audit/ledger-watcher.ts", + "src/store/programs/error-tracking-upload-source-maps/detect-agentic.ts", + "src/store/programs/flow-for.ts", + "src/store/programs/run-config.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "constants.js", - "debug.js", - "rolldown-runtime.js" + "store.js" ] }, "queue-tools.js": { "sources": [ - "src/lib/agent/runner/sequence/orchestrator/queue-tools.ts", - "src/lib/agent/runner/sequence/orchestrator/queue.ts", - "src/lib/agent/runner/switchboard/models.ts", - "src/utils/atomic-ledger.ts" + "src/agent/runner/sequence/orchestrator/queue-tools.ts", + "src/agent/runner/sequence/orchestrator/queue.ts", + "src/agent/runner/switchboard/models.ts" ], "imports": [ "analytics.js", - "constants.js" - ] - }, - "readiness.js": { - "sources": [ - "src/lib/health-checks/readiness.ts" - ], - "imports": [ - "debug.js", - "endpoints.js" + "store.js" ] }, - "registry.js": { + "runners.js": { "sources": [ - "src/frameworks/android/android-wizard-agent.ts", - "src/frameworks/android/utils.ts", - "src/frameworks/angular/angular-wizard-agent.ts", - "src/frameworks/angular/utils.ts", - "src/frameworks/astro/astro-wizard-agent.ts", - "src/frameworks/astro/utils.ts", - "src/frameworks/django/django-wizard-agent.ts", - "src/frameworks/django/utils.ts", - "src/frameworks/elixir/elixir-wizard-agent.ts", - "src/frameworks/fastapi/fastapi-wizard-agent.ts", - "src/frameworks/fastapi/utils.ts", - "src/frameworks/flask/flask-wizard-agent.ts", - "src/frameworks/flask/utils.ts", - "src/frameworks/flutter/flutter-wizard-agent.ts", - "src/frameworks/go/go-wizard-agent.ts", - "src/frameworks/java/java-wizard-agent.ts", - "src/frameworks/javascript-node/javascript-node-wizard-agent.ts", - "src/frameworks/javascript-web/javascript-web-wizard-agent.ts", - "src/frameworks/javascript-web/utils.ts", - "src/frameworks/kmp/kmp-wizard-agent.ts", - "src/frameworks/laravel/laravel-wizard-agent.ts", - "src/frameworks/laravel/utils.ts", - "src/frameworks/nextjs/nextjs-wizard-agent.ts", - "src/frameworks/nextjs/utils.ts", - "src/frameworks/nuxt/nuxt-wizard-agent.ts", - "src/frameworks/python/python-wizard-agent.ts", - "src/frameworks/rails/rails-wizard-agent.ts", - "src/frameworks/rails/utils.ts", - "src/frameworks/react-native/react-native-wizard-agent.ts", - "src/frameworks/react-native/utils.ts", - "src/frameworks/react-router/react-router-wizard-agent.ts", - "src/frameworks/react-router/utils.ts", - "src/frameworks/ruby/ruby-wizard-agent.ts", - "src/frameworks/ruby/utils.ts", - "src/frameworks/rust/rust-wizard-agent.ts", - "src/frameworks/svelte/svelte-wizard-agent.ts", - "src/frameworks/swift/swift-wizard-agent.ts", - "src/frameworks/swift/utils.ts", - "src/frameworks/tanstack-router/tanstack-router-wizard-agent.ts", - "src/frameworks/tanstack-router/utils.ts", - "src/frameworks/tanstack-start/tanstack-start-wizard-agent.ts", - "src/frameworks/tanstack-start/utils.ts", - "src/frameworks/vue/vue-wizard-agent.ts", - "src/lib/framework-config.ts", - "src/lib/registry.ts" + "src/cli/runners/resolve-no-telemetry.ts", + "src/cli/runners/run-non-interactive.ts", + "src/cli/runners/run-wizard-ci.ts", + "src/cli/runners/run-wizard-headless.ts", + "src/cli/runners/run-wizard.ts" ], "imports": [ - "bounded-fs.js", - "package-json.js", - "package-manager.js", - "rolldown-runtime.js", - "setup-utils.js", - "ui.js" - ] - }, - "rolldown-runtime.js": { - "sources": [], - "imports": [] - }, - "run-failure.js": { - "sources": [ - "src/lib/detection/project-scope.ts", - "src/lib/programs/agent-skill/index.ts", - "src/lib/programs/agent-skill/steps.ts", - "src/lib/programs/ai-observability/index.ts", - "src/lib/programs/audit/detect.ts", - "src/lib/programs/audit/index.ts", - "src/lib/programs/audit/seed.ts", - "src/lib/programs/error-tracking-upload-source-maps/detect.ts", - "src/lib/programs/error-tracking-upload-source-maps/index.ts", - "src/lib/programs/error-tracking-upload-source-maps/prompt.ts", - "src/lib/programs/error-tracking-upload-source-maps/steps.ts", - "src/lib/programs/error-tracking/detect-agentic.ts", - "src/lib/programs/error-tracking/index.ts", - "src/lib/programs/events-audit/index.ts", - "src/lib/programs/events-audit/seed.ts", - "src/lib/programs/events-audit/steps.ts", - "src/lib/programs/mcp-analytics/index.ts", - "src/lib/programs/mcp/index.ts", - "src/lib/programs/metrics/index.ts", - "src/lib/programs/migration/index.ts", - "src/lib/programs/migration/steps.ts", - "src/lib/programs/posthog-doctor/fetch.ts", - "src/lib/programs/posthog-doctor/index.ts", - "src/lib/programs/posthog-doctor/kind-metadata.ts", - "src/lib/programs/posthog-doctor/steps.ts", - "src/lib/programs/posthog-doctor/types.ts", - "src/lib/programs/posthog-integration/handoff.ts", - "src/lib/programs/posthog-integration/index.ts", - "src/lib/programs/posthog-integration/steps.ts", - "src/lib/programs/program-registry.ts", - "src/lib/programs/replay-vision/index.ts", - "src/lib/programs/revenue-analytics/detect.ts", - "src/lib/programs/revenue-analytics/index.ts", - "src/lib/programs/revenue-analytics/steps.ts", - "src/lib/programs/self-driving/detect-agentic.ts", - "src/lib/programs/self-driving/detect.ts", - "src/lib/programs/self-driving/index.ts", - "src/lib/programs/self-driving/prompt.ts", - "src/lib/programs/self-driving/step-keys.ts", - "src/lib/programs/self-driving/steps.ts", - "src/lib/programs/shared/health-check-step.ts", - "src/lib/programs/shared/posthog-cli-preinstall.ts", - "src/lib/programs/slack/index.ts", - "src/lib/programs/warehouse-source/index.ts", - "src/lib/programs/warehouse-source/steps.ts", - "src/lib/programs/web-analytics-doctor/detect.ts", - "src/lib/programs/web-analytics-doctor/index.ts", - "src/lib/programs/web-analytics-doctor/steps.ts", - "src/lib/run-failure.ts", - "src/steps/install-cli-steering/index.ts", - "src/ui/tui/programs/self-driving/content/pricing.ts" - ], - "imports": [ - "agent-interface.js", + "add-mcp-server-to-clients.js", + "agent.js", "analytics.js", - "api.js", - "constants.js", - "debug.js", - "errors.js", - "package-json.js", - "provisioning.js", - "queue-tools.js", - "readiness.js", - "registry.js", - "setup-utils.js", - "steps.js", - "telemetry.js", - "token-pricing.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "console.js", + "programs.js", + "store.js", + "tui.js" ] }, "security.js": { "sources": [ - "src/lib/agent/runner/harness/pi/security.ts" + "src/agent/runner/harness/pi/security.ts" ], "imports": [ "agent-interface.js", "analytics.js", - "debug.js", - "yara-hooks.js" - ] - }, - "setup-utils.js": { - "sources": [ - "src/lib/host-resolution.ts", - "src/lib/oauth/program-scopes.ts", - "src/utils/oauth-errors.ts", - "src/utils/oauth.ts", - "src/utils/package-manager.ts", - "src/utils/project-resolution.ts", - "src/utils/semver.ts", - "src/utils/setup-utils.ts" - ], - "imports": [ - "analytics.js", - "api.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "local-dev.js", - "provisioning.js", - "rolldown-runtime.js", - "telemetry.js", - "ui.js", - "wizard-abort.js" - ] - }, - "start-tui.js": { - "sources": [ - "src/lib/programs/error-tracking-upload-source-maps/detect-agentic.ts", - "src/lib/wizard-spellbook.ts", - "src/steps/add-mcp-server-to-clients/browser-client.ts", - "src/steps/add-mcp-server-to-clients/login-client.ts", - "src/ui/store-ui.ts", - "src/ui/tui/App.tsx", - "src/ui/tui/components/PrivacyPanel.tsx", - "src/ui/tui/exit-line.ts", - "src/ui/tui/hooks/useGithubConnection.ts", - "src/ui/tui/posthog-integration-intro.ts", - "src/ui/tui/screen-registry.tsx", - "src/ui/tui/screens/AgentSkillIntroScreen.tsx", - "src/ui/tui/screens/AiObservabilityIntroScreen.tsx", - "src/ui/tui/screens/AuthErrorScreen.tsx", - "src/ui/tui/screens/AuthScreen.tsx", - "src/ui/tui/screens/ErrorTrackingDetectScreen.tsx", - "src/ui/tui/screens/ErrorTrackingIntroScreen.tsx", - "src/ui/tui/screens/ExitScreen.tsx", - "src/ui/tui/screens/IntroScreenLayout.tsx", - "src/ui/tui/screens/KeepSkillsScreen.tsx", - "src/ui/tui/screens/ManagedSettingsScreen.tsx", - "src/ui/tui/screens/ManualAuthCodeScreen.tsx", - "src/ui/tui/screens/MetricsIntroScreen.tsx", - "src/ui/tui/screens/MigrationIntroScreen.tsx", - "src/ui/tui/screens/MintFailureScreen.tsx", - "src/ui/tui/screens/PortConflictScreen.tsx", - "src/ui/tui/screens/PostHogIntegrationIntroScreen.tsx", - "src/ui/tui/screens/RevenueIntroScreen.tsx", - "src/ui/tui/screens/RunScreen.tsx", - "src/ui/tui/screens/SelfDrivingGitHubScreen.tsx", - "src/ui/tui/screens/SelfDrivingHandoffScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntegrationCheckScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntegrationDetectScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntroScreen.tsx", - "src/ui/tui/screens/SessionTimeoutScreen.tsx", - "src/ui/tui/screens/SettingsOverrideScreen.tsx", - "src/ui/tui/screens/SetupScreen.tsx", - "src/ui/tui/screens/SourceMapsDetectScreen.tsx", - "src/ui/tui/screens/SourceMapsIntroScreen.tsx", - "src/ui/tui/screens/SourceMapsOutroScreen.tsx", - "src/ui/tui/screens/TaskNoticeScreen.tsx", - "src/ui/tui/screens/WarehouseIntroScreen.tsx", - "src/ui/tui/screens/WizardAskScreen.tsx", - "src/ui/tui/screens/audit/AuditAreaPane.tsx", - "src/ui/tui/screens/audit/AuditChecksOutroSection.tsx", - "src/ui/tui/screens/audit/AuditIntroScreen.tsx", - "src/ui/tui/screens/audit/AuditOutroScreen.tsx", - "src/ui/tui/screens/audit/AuditRunScreen.tsx", - "src/ui/tui/screens/audit/PendingChecksList.tsx", - "src/ui/tui/screens/audit/slides/events-audit/createDashboard.tsx", - "src/ui/tui/screens/audit/slides/events-audit/detectSdk.tsx", - "src/ui/tui/screens/audit/slides/events-audit/enrichSites.tsx", - "src/ui/tui/screens/audit/slides/events-audit/index.ts", - "src/ui/tui/screens/audit/slides/events-audit/queryVolume.tsx", - "src/ui/tui/screens/audit/slides/events-audit/scanSites.tsx", - "src/ui/tui/screens/audit/slides/events-audit/uploadNotebook.tsx", - "src/ui/tui/screens/audit/slides/events-audit/writeReport.tsx", - "src/ui/tui/screens/doctor/DoctorIntroScreen.tsx", - "src/ui/tui/screens/doctor/DoctorReportScreen.tsx", - "src/ui/tui/screens/health/HealthCheckScreen.tsx", - "src/ui/tui/services/coding-agent-launcher.ts", - "src/ui/tui/services/mcp-installer.ts", - "src/ui/tui/services/mcp-suggested-prompts-services.ts", - "src/ui/tui/start-tui.ts", - "src/utils/clipboard.ts" - ], - "imports": [ - "add-mcp-server-to-clients.js", - "agent-interface.js", - "analytics.js", - "api.js", - "bin.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "defaults.js", - "errors.js", - "mcp-prompt-streaming.js", - "provisioning.js", - "readiness.js", - "registry.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "telemetry.js", - "terminal.js", - "token-pricing.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "store.js" ] }, "steps.js": { "sources": [ - "src/steps/upload-environment-variables/EnvironmentProvider.ts", - "src/steps/upload-environment-variables/index.ts", - "src/steps/upload-environment-variables/providers/vercel.ts" + "src/store/services/steps/upload-environment-variables/EnvironmentProvider.ts", + "src/store/services/steps/upload-environment-variables/index.ts", + "src/store/services/steps/upload-environment-variables/providers/vercel.ts" ], "imports": [ - "analytics.js", - "telemetry.js", - "ui.js" + "add-mcp-server-to-clients.js", + "analytics.js" ] }, "store.js": { - "sources": [ - "src/lib/flow-resolution.ts", - "src/ui/tui/store.ts" - ], + "sources": [], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "debug.js", - "readiness.js", - "rolldown-runtime.js", - "run-failure.js", - "token-pricing.js", - "wizard-session.js", - "wizard-ui.js" + "store.js" ] }, "subagent.js": { "sources": [ - "src/lib/agent/runner/harness/pi/subagent.ts" + "src/agent/runner/harness/pi/subagent.ts" ], "imports": [ - "debug.js" + "analytics.js" ] }, "task.js": { "sources": [ - "src/lib/agent/runner/harness/pi/task.ts" + "src/agent/runner/harness/pi/task.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "agent-prompt-loader.js", "analytics.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", "mcp.js", "orchestrator-tools.js", "pi.js", "queue-tools.js", "security.js", - "tools.js", - "ui.js", - "yara-hooks.js" - ] - }, - "task-stream.js": { - "sources": [ - "src/lib/task-stream/audit-areas.ts", - "src/lib/task-stream/event-plan-watcher.ts", - "src/lib/task-stream/task-stream-push.ts" - ], - "imports": [ - "debug.js", - "errors.js", - "file-watcher.js", - "file.js", - "posthog.js" + "store.js", + "tools.js" ] }, "tasks.js": { "sources": [ - "src/lib/agent/runner/harness/pi/tasks.ts" - ], - "imports": [ - "ui.js" - ] - }, - "telemetry.js": { - "sources": [ - "src/telemetry.ts", - "src/utils/links.ts" + "src/agent/runner/harness/pi/tasks.ts" ], "imports": [ "analytics.js" ] }, - "terminal.js": { - "sources": [ - "src/lib/mcp-project-profile.ts", - "src/lib/mcp-role-prompts.copy.json", - "src/lib/mcp-role-prompts.ts", - "src/lib/mcp-seed-events.ts", - "src/ui/tui/components/LearnCard.tsx", - "src/ui/tui/components/PhaseVisuals.tsx", - "src/ui/tui/components/ServiceHealthList.tsx", - "src/ui/tui/components/StatusPeekTrigger.tsx", - "src/ui/tui/components/TipsCard.tsx", - "src/ui/tui/components/TitleBar.tsx", - "src/ui/tui/components/TokenCostHud.tsx", - "src/ui/tui/components/visualizer/CrateStack.tsx", - "src/ui/tui/components/visualizer/DashboardGrid.tsx", - "src/ui/tui/components/visualizer/DiffCascade.tsx", - "src/ui/tui/components/visualizer/LibraryShelf.tsx", - "src/ui/tui/components/visualizer/MatrixRain.tsx", - "src/ui/tui/components/visualizer/Tumblers.tsx", - "src/ui/tui/components/visualizer/grid.ts", - "src/ui/tui/components/visualizer/palette.ts", - "src/ui/tui/components/visualizer/panel.tsx", - "src/ui/tui/constants.ts", - "src/ui/tui/hooks/useDismissOnAnyKey.ts", - "src/ui/tui/hooks/useTick.ts", - "src/ui/tui/hooks/useUiStore.ts", - "src/ui/tui/primitives/CardLayout.tsx", - "src/ui/tui/primitives/ConfirmationInput.tsx", - "src/ui/tui/primitives/ContentSequencer.tsx", - "src/ui/tui/primitives/DissolveTransition.tsx", - "src/ui/tui/primitives/Divider.tsx", - "src/ui/tui/primitives/EventPlanViewer.tsx", - "src/ui/tui/primitives/GroupedPickerMenu.tsx", - "src/ui/tui/primitives/HNViewer.tsx", - "src/ui/tui/primitives/KeyboardHintsBar.tsx", - "src/ui/tui/primitives/LinesBlock.tsx", - "src/ui/tui/primitives/LinkText.tsx", - "src/ui/tui/primitives/LoadingBox.tsx", - "src/ui/tui/primitives/LogViewer.tsx", - "src/ui/tui/primitives/ModalOverlay.tsx", - "src/ui/tui/primitives/NodeBlock.tsx", - "src/ui/tui/primitives/ProgressList.tsx", - "src/ui/tui/primitives/ScreenContainer.tsx", - "src/ui/tui/primitives/ScreenErrorBoundary.tsx", - "src/ui/tui/primitives/SplitView.tsx", - "src/ui/tui/primitives/TabContainer.tsx", - "src/ui/tui/primitives/TextBlock.tsx", - "src/ui/tui/primitives/ViewportTooSmall.tsx", - "src/ui/tui/primitives/link-helpers.ts", - "src/ui/tui/primitives/text-helpers.ts", - "src/ui/tui/programs/agent-skill/content/index.tsx", - "src/ui/tui/programs/error-tracking-upload-source-maps/content/index.tsx", - "src/ui/tui/programs/error-tracking/content/index.tsx", - "src/ui/tui/programs/error-tracking/content/tips.ts", - "src/ui/tui/programs/migration/content/free-tier.tsx", - "src/ui/tui/programs/migration/content/index.tsx", - "src/ui/tui/programs/migration/content/pricing-structure.tsx", - "src/ui/tui/programs/migration/content/vendor-stack.tsx", - "src/ui/tui/programs/posthog-integration/content/data-flow.tsx", - "src/ui/tui/programs/posthog-integration/content/funnel.tsx", - "src/ui/tui/programs/posthog-integration/content/index.tsx", - "src/ui/tui/programs/posthog-integration/content/line-chart.tsx", - "src/ui/tui/programs/posthog-integration/content/product-suite.tsx", - "src/ui/tui/programs/presentation.ts", - "src/ui/tui/programs/self-driving/content/index.tsx", - "src/ui/tui/programs/self-driving/content/pipeline-diagram.tsx", - "src/ui/tui/programs/self-driving/content/tips.ts", - "src/ui/tui/screens/AiOptInRequiredScreen.tsx", - "src/ui/tui/screens/McpScreen.tsx", - "src/ui/tui/screens/McpSuggestedPromptsScreen.tsx", - "src/ui/tui/screens/OutroScreen.tsx", - "src/ui/tui/screens/SkillSourceInfo.tsx", - "src/ui/tui/screens/SlackConnectScreen.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/AuditChecksViewer.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/CheckRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/DetailRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Footer.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Header.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Legend.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/layout.ts", - "src/ui/tui/screens/audit/AuditChecksViewer/sort.ts", - "src/ui/tui/screens/audit/slides/eventCapture.tsx", - "src/ui/tui/screens/audit/slides/identification.tsx", - "src/ui/tui/screens/audit/slides/index.ts", - "src/ui/tui/screens/audit/slides/installation.tsx", - "src/ui/tui/screens/audit/slides/liveData.tsx", - "src/ui/tui/screens/audit/slides/shared.tsx", - "src/ui/tui/screens/audit/slides/uploadNotebook.tsx", - "src/ui/tui/screens/audit/slides/writeReport.tsx", - "src/ui/tui/screens/doctor/IssueTable.tsx", - "src/ui/tui/terminal.ts", - "src/ui/tui/ui-store.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "api.js", - "bin.js", - "constants.js", - "debug.js", - "defaults.js", - "readiness.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "telemetry.js", - "token-pricing.js", - "yara-hooks.js" - ] - }, - "token-pricing.js": { - "sources": [ - "src/lib/agent/runner/shared/authenticate.ts", - "src/lib/ask-policy.ts", - "src/lib/detection/agentic.ts", - "src/lib/detection/context.ts", - "src/lib/detection/features.ts", - "src/lib/detection/framework.ts", - "src/lib/programs/posthog-integration/detect.ts", - "src/lib/programs/shared/package-scanning.ts", - "src/lib/programs/warehouse-source/detect.ts", - "src/lib/token-pricing.ts", - "src/lib/warehouse-sources/detect.ts", - "src/lib/warehouse-sources/registry.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "errors.js", - "package-manager.js", - "registry.js", - "setup-utils.js", - "ui.js", - "wizard-session.js" - ] - }, "tools.js": { "sources": [ - "src/lib/agent/runner/harness/pi/tools.ts" + "src/agent/runner/harness/pi/tools.ts" ], "imports": [ - "agent-interface.js", "analytics.js", - "debug.js", - "package-manager.js", "pi.js", - "queue-tools.js", - "yara-hooks.js" - ] - }, - "ui.js": { - "sources": [ - "src/ui/index.ts", - "src/ui/null-ui.ts" - ], - "imports": [] - }, - "version.js": { - "sources": [ - "src/lib/version.ts" - ], - "imports": [] - }, - "wizard-abort.js": { - "sources": [ - "src/utils/wizard-abort.ts" + "store.js" + ] + }, + "tui.js": { + "sources": [ + "src/tui/App.tsx", + "src/tui/components/LearnCard.tsx", + "src/tui/components/PhaseVisuals.tsx", + "src/tui/components/PrivacyPanel.tsx", + "src/tui/components/ServiceHealthList.tsx", + "src/tui/components/StatusPeekTrigger.tsx", + "src/tui/components/TipsCard.tsx", + "src/tui/components/TitleBar.tsx", + "src/tui/components/TokenCostHud.tsx", + "src/tui/components/visualizer/CrateStack.tsx", + "src/tui/components/visualizer/DashboardGrid.tsx", + "src/tui/components/visualizer/DiffCascade.tsx", + "src/tui/components/visualizer/LibraryShelf.tsx", + "src/tui/components/visualizer/MatrixRain.tsx", + "src/tui/components/visualizer/Tumblers.tsx", + "src/tui/components/visualizer/grid.ts", + "src/tui/components/visualizer/palette.ts", + "src/tui/components/visualizer/panel.tsx", + "src/tui/constants.ts", + "src/tui/exit-line.ts", + "src/tui/family-picker.tsx", + "src/tui/hooks/keyboard-hints-utils.ts", + "src/tui/hooks/useDismissOnAnyKey.ts", + "src/tui/hooks/useGithubConnection.ts", + "src/tui/hooks/useKeyBindings.ts", + "src/tui/hooks/useKeyboardHints.tsx", + "src/tui/hooks/useStdoutDimensions.ts", + "src/tui/hooks/useTick.ts", + "src/tui/hooks/useUiStore.ts", + "src/tui/mint-failure.ts", + "src/tui/playground/PlaygroundApp.tsx", + "src/tui/playground/demos/AiOptInDemo.tsx", + "src/tui/playground/demos/AskModalDemo.tsx", + "src/tui/playground/demos/AuditChecksDemo.tsx", + "src/tui/playground/demos/DoctorReportDemo.tsx", + "src/tui/playground/demos/EndScreensDemo.tsx", + "src/tui/playground/demos/HealthCheckDemo.tsx", + "src/tui/playground/demos/InputDemo.tsx", + "src/tui/playground/demos/KeyboardHintsDemo.tsx", + "src/tui/playground/demos/LayoutDemo.tsx", + "src/tui/playground/demos/LearnDeckDemo.tsx", + "src/tui/playground/demos/LogDemo.tsx", + "src/tui/playground/demos/McpDemo.tsx", + "src/tui/playground/demos/McpSuggestedPromptsDemo.tsx", + "src/tui/playground/demos/ModalDemo.tsx", + "src/tui/playground/demos/ProgressDemo.tsx", + "src/tui/playground/demos/RunScreenDemo.tsx", + "src/tui/playground/demos/ViewportGuardDemo.tsx", + "src/tui/playground/demos/WelcomeDemo.tsx", + "src/tui/playground/start-playground.ts", + "src/tui/posthog-integration-intro.ts", + "src/tui/primitives/CardLayout.tsx", + "src/tui/primitives/ConfirmButton.tsx", + "src/tui/primitives/ConfirmationInput.tsx", + "src/tui/primitives/ContentSequencer.tsx", + "src/tui/primitives/DissolveTransition.tsx", + "src/tui/primitives/Divider.tsx", + "src/tui/primitives/EventPlanViewer.tsx", + "src/tui/primitives/GroupedPickerMenu.tsx", + "src/tui/primitives/HNViewer.tsx", + "src/tui/primitives/KeyboardHintsBar.tsx", + "src/tui/primitives/LinesBlock.tsx", + "src/tui/primitives/LinkText.tsx", + "src/tui/primitives/LoadingBox.tsx", + "src/tui/primitives/LogViewer.tsx", + "src/tui/primitives/ModalOverlay.tsx", + "src/tui/primitives/NodeBlock.tsx", + "src/tui/primitives/PickerMenu.tsx", + "src/tui/primitives/ProgressList.tsx", + "src/tui/primitives/PromptLabel.tsx", + "src/tui/primitives/ScreenContainer.tsx", + "src/tui/primitives/ScreenErrorBoundary.tsx", + "src/tui/primitives/SplitView.tsx", + "src/tui/primitives/TabContainer.tsx", + "src/tui/primitives/TextBlock.tsx", + "src/tui/primitives/ViewportTooSmall.tsx", + "src/tui/primitives/content-types.ts", + "src/tui/primitives/layout-helpers.ts", + "src/tui/primitives/link-helpers.ts", + "src/tui/primitives/picker-filter.ts", + "src/tui/primitives/text-helpers.ts", + "src/tui/programs/agent-skill/content/index.tsx", + "src/tui/programs/error-tracking-upload-source-maps/content/index.tsx", + "src/tui/programs/error-tracking/content/index.tsx", + "src/tui/programs/error-tracking/content/tips.ts", + "src/tui/programs/migration/content/free-tier.tsx", + "src/tui/programs/migration/content/index.tsx", + "src/tui/programs/migration/content/pricing-structure.tsx", + "src/tui/programs/migration/content/vendor-stack.tsx", + "src/tui/programs/posthog-integration/content/data-flow.tsx", + "src/tui/programs/posthog-integration/content/funnel.tsx", + "src/tui/programs/posthog-integration/content/index.tsx", + "src/tui/programs/posthog-integration/content/line-chart.tsx", + "src/tui/programs/posthog-integration/content/product-suite.tsx", + "src/tui/programs/presentation.ts", + "src/tui/programs/self-driving/content/index.tsx", + "src/tui/programs/self-driving/content/pipeline-diagram.tsx", + "src/tui/programs/self-driving/content/tips.ts", + "src/tui/screen-registry.tsx", + "src/tui/screens/AgentSkillIntroScreen.tsx", + "src/tui/screens/AiObservabilityIntroScreen.tsx", + "src/tui/screens/AiOptInRequiredScreen.tsx", + "src/tui/screens/AuthErrorScreen.tsx", + "src/tui/screens/AuthScreen.tsx", + "src/tui/screens/ErrorTrackingDetectScreen.tsx", + "src/tui/screens/ErrorTrackingIntroScreen.tsx", + "src/tui/screens/ExitScreen.tsx", + "src/tui/screens/IntroScreenLayout.tsx", + "src/tui/screens/KeepSkillsScreen.tsx", + "src/tui/screens/ManagedSettingsScreen.tsx", + "src/tui/screens/ManualAuthCodeScreen.tsx", + "src/tui/screens/McpScreen.tsx", + "src/tui/screens/McpSuggestedPromptsScreen.tsx", + "src/tui/screens/MetricsIntroScreen.tsx", + "src/tui/screens/MigrationIntroScreen.tsx", + "src/tui/screens/MintFailureScreen.tsx", + "src/tui/screens/OutroScreen.tsx", + "src/tui/screens/PortConflictScreen.tsx", + "src/tui/screens/PostHogIntegrationIntroScreen.tsx", + "src/tui/screens/RevenueIntroScreen.tsx", + "src/tui/screens/RunScreen.tsx", + "src/tui/screens/SelfDrivingGitHubScreen.tsx", + "src/tui/screens/SelfDrivingHandoffScreen.tsx", + "src/tui/screens/SelfDrivingIntegrationCheckScreen.tsx", + "src/tui/screens/SelfDrivingIntegrationDetectScreen.tsx", + "src/tui/screens/SelfDrivingIntroScreen.tsx", + "src/tui/screens/SessionTimeoutScreen.tsx", + "src/tui/screens/SettingsOverrideScreen.tsx", + "src/tui/screens/SetupScreen.tsx", + "src/tui/screens/SkillSourceInfo.tsx", + "src/tui/screens/SlackConnectScreen.tsx", + "src/tui/screens/SourceMapsDetectScreen.tsx", + "src/tui/screens/SourceMapsIntroScreen.tsx", + "src/tui/screens/SourceMapsOutroScreen.tsx", + "src/tui/screens/TaskNoticeScreen.tsx", + "src/tui/screens/WarehouseIntroScreen.tsx", + "src/tui/screens/WizardAskScreen.tsx", + "src/tui/screens/audit/AuditAreaPane.tsx", + "src/tui/screens/audit/AuditChecksOutroSection.tsx", + "src/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/AuditChecksViewer.tsx", + "src/tui/screens/audit/AuditChecksViewer/CheckRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/DetailRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/Footer.tsx", + "src/tui/screens/audit/AuditChecksViewer/Header.tsx", + "src/tui/screens/audit/AuditChecksViewer/Legend.tsx", + "src/tui/screens/audit/AuditChecksViewer/layout.ts", + "src/tui/screens/audit/AuditChecksViewer/sort.ts", + "src/tui/screens/audit/AuditIntroScreen.tsx", + "src/tui/screens/audit/AuditOutroScreen.tsx", + "src/tui/screens/audit/AuditRunScreen.tsx", + "src/tui/screens/audit/PendingChecksList.tsx", + "src/tui/screens/audit/slides/eventCapture.tsx", + "src/tui/screens/audit/slides/events-audit/createDashboard.tsx", + "src/tui/screens/audit/slides/events-audit/detectSdk.tsx", + "src/tui/screens/audit/slides/events-audit/enrichSites.tsx", + "src/tui/screens/audit/slides/events-audit/index.ts", + "src/tui/screens/audit/slides/events-audit/queryVolume.tsx", + "src/tui/screens/audit/slides/events-audit/scanSites.tsx", + "src/tui/screens/audit/slides/events-audit/uploadNotebook.tsx", + "src/tui/screens/audit/slides/events-audit/writeReport.tsx", + "src/tui/screens/audit/slides/identification.tsx", + "src/tui/screens/audit/slides/index.ts", + "src/tui/screens/audit/slides/installation.tsx", + "src/tui/screens/audit/slides/liveData.tsx", + "src/tui/screens/audit/slides/shared.tsx", + "src/tui/screens/audit/slides/uploadNotebook.tsx", + "src/tui/screens/audit/slides/writeReport.tsx", + "src/tui/screens/doctor/DoctorIntroScreen.tsx", + "src/tui/screens/doctor/DoctorReportScreen.tsx", + "src/tui/screens/doctor/IssueTable.tsx", + "src/tui/screens/health/HealthCheckScreen.tsx", + "src/tui/services/coding-agent-launcher.ts", + "src/tui/services/mcp-installer.ts", + "src/tui/services/mcp-suggested-prompts-services.ts", + "src/tui/start-tui.ts", + "src/tui/styles.ts", + "src/tui/terminal.ts", + "src/tui/ui-store.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "debug.js", - "errors.js", - "ui.js" - ] - }, - "wizard-session.js": { - "sources": [], - "imports": [ - "wizard-session.js" - ] - }, - "wizard-ui.js": { - "sources": [ - "src/ui/wizard-ui.ts" - ], - "imports": [] - }, - "yara-hooks.js": { - "sources": [], - "imports": [ - "yara-hooks.js" + "programs.js", + "store.js" ] } } diff --git a/scripts/__fixtures__/chunk-manifest.prod.json b/scripts/__fixtures__/chunk-manifest.prod.json index a451e3364..49af3ed2a 100644 --- a/scripts/__fixtures__/chunk-manifest.prod.json +++ b/scripts/__fixtures__/chunk-manifest.prod.json @@ -1,430 +1,252 @@ { "add-mcp-server-to-clients.js": { "sources": [ - "src/steps/add-mcp-server-to-clients/MCPClient.ts", - "src/steps/add-mcp-server-to-clients/clients/claude-code.ts", - "src/steps/add-mcp-server-to-clients/clients/claude-web.ts", - "src/steps/add-mcp-server-to-clients/clients/codex.ts", - "src/steps/add-mcp-server-to-clients/clients/cursor.ts", - "src/steps/add-mcp-server-to-clients/clients/opencode.ts", - "src/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts", - "src/steps/add-mcp-server-to-clients/clients/zed.ts", - "src/steps/add-mcp-server-to-clients/index.ts", - "src/steps/add-mcp-server-to-clients/plugin-client.ts" + "src/store/agent-protocol/agent-signals.ts", + "src/store/api.ts", + "src/store/host-resolution.ts", + "src/store/services/oauth/program-scopes.ts", + "src/store/services/steps/add-mcp-server-to-clients/MCPClient.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/claude-code.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/claude-web.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/codex.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/cursor.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/opencode.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts", + "src/store/services/steps/add-mcp-server-to-clients/clients/zed.ts", + "src/store/services/steps/add-mcp-server-to-clients/defaults.ts", + "src/store/services/steps/add-mcp-server-to-clients/index.ts", + "src/store/services/steps/add-mcp-server-to-clients/plugin-client.ts", + "src/store/services/steps/add-mcp-server-to-clients/results.ts", + "src/store/shared/bounded-fs.ts", + "src/store/shared/errors/agent-map.ts", + "src/store/shared/errors/auth.ts", + "src/store/shared/errors/catalog.ts", + "src/store/shared/errors/codes.ts", + "src/store/shared/errors/detect-map.ts", + "src/store/shared/errors/emit.ts", + "src/store/shared/errors/run-failure.ts", + "src/store/shared/errors/sanitize.ts", + "src/store/shared/errors/skill-map.ts", + "src/store/shared/links.ts", + "src/store/shared/oauth-errors.ts", + "src/store/shared/oauth.ts", + "src/store/shared/package-manager.ts", + "src/store/shared/project-resolution.ts", + "src/store/shared/provisioning.ts", + "src/store/shared/semver.ts", + "src/store/shared/setup-utils.ts", + "src/store/shared/telemetry.ts", + "src/store/shared/urls.ts", + "src/store/shared/wizard-abort.ts" ], "imports": [ - "analytics.js", - "debug.js", - "defaults.js", - "rolldown-runtime.js", - "telemetry.js", - "ui.js" - ] - }, - "agent-interface.js": { - "sources": [ - "src/lib/agent-env-isolation.ts", - "src/lib/agent/agent-interface.ts", - "src/lib/agent/agent-phase.ts", - "src/lib/agent/bash-fence.ts", - "src/lib/agent/commandments.ts", - "src/lib/agent/output-signals.ts", - "src/lib/agent/runner/harness/pi/gateway.ts", - "src/lib/agent/runner/harness/pi/runtime-notes.ts", - "src/lib/agent/runner/switchboard/commandments.ts", - "src/lib/agent/stored-login.ts", - "src/lib/agent/triage-provider.ts", - "src/lib/auth-session-state.ts", - "src/lib/claude-settings.ts", - "src/lib/fetch-retry.ts", - "src/lib/safe-tools.ts", - "src/lib/secret-vault.ts", - "src/lib/wizard-ask-bridge.ts", - "src/lib/wizard-tools/handoff.ts", - "src/lib/wizard-tools/mcp.ts", - "src/lib/wizard-tools/tools.ts", - "src/utils/custom-headers.ts", - "src/utils/env-scan.ts" - ], - "imports": [ - "analytics.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", - "queue-tools.js", - "rolldown-runtime.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" - ] - }, - "agent-prompt-loader.js": { - "sources": [ - "src/lib/agent/agent-prompt-loader.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "debug.js", - "queue-tools.js" + "analytics.js" ] }, - "agent-runner.js": { - "sources": [ - "src/lib/agent/agent-prompt.ts", - "src/lib/agent/agent-runner.ts", - "src/lib/agent/runner/harness/anthropic/index.ts", - "src/lib/agent/runner/index.ts", - "src/lib/agent/runner/sequence/linear.ts", - "src/lib/agent/runner/sequence/orchestrator/executor.ts", - "src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts", - "src/lib/agent/runner/sequence/orchestrator/run-metrics.ts", - "src/lib/agent/runner/sequence/orchestrator/seeded-deps.ts", - "src/lib/agent/runner/shared/bootstrap.ts", - "src/lib/agent/runner/shared/errors.ts", - "src/lib/agent/runner/switchboard/flags/index.ts", - "src/lib/agent/runner/switchboard/flags/orchestrator.ts", - "src/lib/agent/runner/switchboard/flags/schemes.ts", - "src/lib/agent/runner/switchboard/flags/self-driving.ts", - "src/lib/agent/runner/switchboard/harness.ts", - "src/lib/agent/runner/switchboard/index.ts", - "src/lib/agent/runner/switchboard/sequence.ts", - "src/lib/middleware/benchmark.ts", - "src/lib/middleware/benchmarks/cache-tracker.ts", - "src/lib/middleware/benchmarks/compaction-tracker.ts", - "src/lib/middleware/benchmarks/context-size-tracker.ts", - "src/lib/middleware/benchmarks/cost-tracker.ts", - "src/lib/middleware/benchmarks/duration-tracker.ts", - "src/lib/middleware/benchmarks/index.ts", - "src/lib/middleware/benchmarks/json-writer.ts", - "src/lib/middleware/benchmarks/summary.ts", - "src/lib/middleware/benchmarks/token-tracker.ts", - "src/lib/middleware/benchmarks/turn-counter.ts", - "src/lib/middleware/config.ts", - "src/lib/middleware/phase-detector.ts", - "src/lib/middleware/pipeline.ts", - "src/lib/programs/audit/ledger-watcher.ts", - "src/utils/terminal-bell.ts" + "agent.js": { + "sources": [ + "src/agent/agent-prompt.ts", + "src/agent/detection/agentic.ts", + "src/agent/mcp-prompt-streaming.ts", + "src/agent/middleware/benchmark.ts", + "src/agent/middleware/benchmarks/cache-tracker.ts", + "src/agent/middleware/benchmarks/compaction-tracker.ts", + "src/agent/middleware/benchmarks/context-size-tracker.ts", + "src/agent/middleware/benchmarks/cost-tracker.ts", + "src/agent/middleware/benchmarks/duration-tracker.ts", + "src/agent/middleware/benchmarks/index.ts", + "src/agent/middleware/benchmarks/json-writer.ts", + "src/agent/middleware/benchmarks/summary.ts", + "src/agent/middleware/benchmarks/token-tracker.ts", + "src/agent/middleware/benchmarks/turn-counter.ts", + "src/agent/middleware/config.ts", + "src/agent/middleware/phase-detector.ts", + "src/agent/middleware/pipeline.ts", + "src/agent/runner/harness/anthropic/index.ts", + "src/agent/runner/index.ts", + "src/agent/runner/sequence/linear.ts", + "src/agent/runner/sequence/orchestrator/executor.ts", + "src/agent/runner/sequence/orchestrator/orchestrator-runner.ts", + "src/agent/runner/sequence/orchestrator/run-metrics.ts", + "src/agent/runner/sequence/orchestrator/seeded-deps.ts", + "src/agent/runner/shared/bootstrap.ts", + "src/agent/runner/shared/errors.ts", + "src/agent/runner/switchboard/flags/index.ts", + "src/agent/runner/switchboard/flags/orchestrator.ts", + "src/agent/runner/switchboard/flags/schemes.ts", + "src/agent/runner/switchboard/flags/self-driving.ts", + "src/agent/runner/switchboard/harness.ts", + "src/agent/runner/switchboard/index.ts", + "src/agent/runner/switchboard/sequence.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "agent-prompt-loader.js", "analytics.js", - "constants.js", - "debug.js", - "environment.js", - "errors.js", - "file-watcher.js", - "gateway-session.js", - "package-manager.js", "pi.js", + "programs.js", "queue-tools.js", - "readiness.js", - "registry.js", - "rolldown-runtime.js", - "setup-utils.js", - "token-pricing.js", - "ui.js", - "version.js", - "wizard-abort.js", - "yara-hooks.js" + "store.js" ] }, - "analytics.js": { - "sources": [ - "src/utils/analytics.ts", - "src/utils/ci-flag-overrides.ts" - ], - "imports": [ - "constants.js", - "debug.js", - "version.js", - "wizard-session.js" - ] - }, - "api.js": { - "sources": [ - "src/lib/api.ts" - ], - "imports": [ - "analytics.js", - "constants.js", - "rolldown-runtime.js" - ] - }, - "bin.js": { + "agent-interface.js": { "sources": [ - "bin.ts", - "src/commands/ai-observability.ts", - "src/commands/audit.ts", - "src/commands/basic-integration/index.ts", - "src/commands/basic-integration/skill.ts", - "src/commands/cli/add.ts", - "src/commands/cli/index.ts", - "src/commands/command.ts", - "src/commands/doctor.ts", - "src/commands/error-tracking.ts", - "src/commands/factories/family-command-factory.ts", - "src/commands/factories/family-picker.tsx", - "src/commands/factories/native-command-factory.ts", - "src/commands/factories/shared.ts", - "src/commands/mcp-analytics.ts", - "src/commands/mcp/add.ts", - "src/commands/mcp/index.ts", - "src/commands/mcp/remove.ts", - "src/commands/mcp/tui-availability.ts", - "src/commands/mcp/tutorial.ts", - "src/commands/metrics.ts", - "src/commands/migrate.ts", - "src/commands/provision.ts", - "src/commands/replay-vision.ts", - "src/commands/revenue.ts", - "src/commands/self-driving.ts", - "src/commands/skill-program-options.ts", - "src/commands/skill.ts", - "src/commands/slack.ts", - "src/commands/upload-sourcemaps.ts", - "src/commands/warehouse.ts", - "src/lib/programs/ai-opt-in-gate.ts", - "src/lib/programs/dispatch-family.ts", - "src/lib/programs/flow-for.ts", - "src/lib/programs/run-config.ts", - "src/lib/runners/resolve-no-telemetry.ts", - "src/lib/runners/run-non-interactive.ts", - "src/lib/runners/run-wizard-ci.ts", - "src/lib/runners/run-wizard-headless.ts", - "src/lib/runners/run-wizard.ts", - "src/ui/mint-failure.ts", - "src/ui/tui/hooks/keyboard-hints-utils.ts", - "src/ui/tui/hooks/useKeyBindings.ts", - "src/ui/tui/hooks/useKeyboardHints.tsx", - "src/ui/tui/hooks/useStdoutDimensions.ts", - "src/ui/tui/primitives/ConfirmButton.tsx", - "src/ui/tui/primitives/PickerMenu.tsx", - "src/ui/tui/primitives/PromptLabel.tsx", - "src/ui/tui/primitives/content-types.ts", - "src/ui/tui/primitives/layout-helpers.ts", - "src/ui/tui/primitives/picker-filter.ts", - "src/ui/tui/styles.ts", - "src/wizard.ts" + "src/agent/agent-interface.ts", + "src/agent/bash-fence.ts", + "src/agent/commandments.ts", + "src/agent/gateway/gateway-session.ts", + "src/agent/output-signals.ts", + "src/agent/runner/harness/pi/gateway.ts", + "src/agent/runner/harness/pi/runtime-notes.ts", + "src/agent/runner/switchboard/commandments.ts", + "src/agent/stored-login.ts", + "src/agent/tools/mcp.ts", + "src/agent/triage-provider.ts" ], "imports": [ "add-mcp-server-to-clients.js", - "agent-interface.js", - "agent-runner.js", "analytics.js", - "api.js", - "ci-install.js", - "constants.js", - "debug.js", - "env-api-key.js", - "environment.js", - "errors.js", - "file.js", - "gateway-session.js", - "headless-ui.js", - "interactive.js", - "local-dev.js", - "logging-ui.js", - "non-interactive.js", - "playground.js", - "posthog.js", - "provisioning.js", - "run-failure.js", - "setup-utils.js", - "start-tui.js", - "store.js", - "task-stream.js", - "telemetry.js", - "token-pricing.js", - "ui.js", - "version.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "queue-tools.js", + "store.js" ] }, - "bounded-fs.js": { + "agent-prompt-loader.js": { "sources": [ - "src/utils/bounded-fs.ts" + "src/agent/agent-prompt-loader.ts" ], "imports": [ "analytics.js", - "debug.js" - ] - }, - "ci-install.js": { - "sources": [ - "src/commands/basic-integration/ci-install.ts" - ], - "imports": [ - "bin.js", - "errors.js", - "logging-ui.js", - "provisioning.js", - "run-failure.js", - "ui.js" - ] - }, - "constants.js": { - "sources": [ - "src/lib/constants.ts" - ], - "imports": [ - "local-dev.js", - "version.js" - ] - }, - "debug.js": { - "sources": [], - "imports": [ - "debug.js" - ] - }, - "defaults.js": { - "sources": [ - "src/steps/add-mcp-server-to-clients/defaults.ts", - "src/steps/add-mcp-server-to-clients/results.ts" - ], - "imports": [] - }, - "endpoints.js": { - "sources": [ - "src/lib/health-checks/endpoints.ts" - ], - "imports": [ - "constants.js", - "debug.js" - ] - }, - "env-api-key.js": { - "sources": [ - "src/utils/env-api-key.ts" - ], - "imports": [ - "bounded-fs.js", - "rolldown-runtime.js" - ] - }, - "environment.js": { - "sources": [ - "src/utils/environment.ts" - ], - "imports": [ - "rolldown-runtime.js" + "queue-tools.js", + "store.js" ] }, - "errors.js": { - "sources": [ - "src/lib/agent-signals.ts", - "src/lib/errors/agent-map.ts", - "src/lib/errors/auth.ts", - "src/lib/errors/catalog.ts", - "src/lib/errors/codes.ts", - "src/lib/errors/detect-map.ts", - "src/lib/errors/emit.ts", - "src/lib/errors/run-failure.ts", - "src/lib/errors/sanitize.ts", - "src/lib/errors/skill-map.ts" - ], - "imports": [] - }, - "file.js": { + "analytics.js": { "sources": [ - "src/lib/task-stream/destinations/file.ts" + "src/env.ts", + "src/store/local-dev.ts", + "src/store/session/wizard-session.ts", + "src/store/shared/analytics.ts", + "src/store/shared/ci-flag-overrides.ts", + "src/store/shared/constants.ts", + "src/store/shared/debug.ts", + "src/store/shared/paths.ts", + "src/store/shared/version.ts", + "src/store/ui/index.ts", + "src/store/ui/null-ui.ts" ], "imports": [ - "debug.js" + "analytics.js" ] }, - "file-watcher.js": { + "bin.js": { "sources": [ - "src/lib/file-watcher.ts" + "bin.ts" ], "imports": [ - "debug.js" + "main.js" ] }, - "gateway-session.js": { + "ci-install.js": { "sources": [ - "src/lib/gateway-session.ts" + "src/cli/commands/basic-integration/ci-install.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "debug.js", - "endpoints.js", - "errors.js", - "wizard-abort.js" + "console.js", + "runners.js", + "store.js" ] }, - "headless-ui.js": { + "console.js": { "sources": [ - "src/ui/tui/console/headless-ui.ts" + "src/tui/console/headless-ui.ts", + "src/tui/console/logging-ui.ts" ], "imports": [ - "logging-ui.js" + "analytics.js", + "store.js" ] }, "interactive.js": { "sources": [ - "src/commands/basic-integration/interactive.ts" - ], - "imports": [ - "bin.js", - "run-failure.js" - ] - }, - "local-dev.js": { - "sources": [ - "src/lib/local-dev.ts" - ], - "imports": [] - }, - "logging-ui.js": { - "sources": [ - "src/ui/tui/console/logging-ui.ts" + "src/cli/commands/basic-integration/interactive.ts" + ], + "imports": [ + "runners.js", + "store.js" + ] + }, + "main.js": { + "sources": [ + "src/cli/commands/ai-observability.ts", + "src/cli/commands/audit.ts", + "src/cli/commands/basic-integration/index.ts", + "src/cli/commands/basic-integration/skill.ts", + "src/cli/commands/cli/add.ts", + "src/cli/commands/cli/index.ts", + "src/cli/commands/command.ts", + "src/cli/commands/doctor.ts", + "src/cli/commands/error-tracking.ts", + "src/cli/commands/factories/family-command-factory.ts", + "src/cli/commands/factories/native-command-factory.ts", + "src/cli/commands/factories/shared.ts", + "src/cli/commands/mcp-analytics.ts", + "src/cli/commands/mcp/add.ts", + "src/cli/commands/mcp/index.ts", + "src/cli/commands/mcp/remove.ts", + "src/cli/commands/mcp/tui-availability.ts", + "src/cli/commands/mcp/tutorial.ts", + "src/cli/commands/metrics.ts", + "src/cli/commands/migrate.ts", + "src/cli/commands/provision.ts", + "src/cli/commands/replay-vision.ts", + "src/cli/commands/revenue.ts", + "src/cli/commands/self-driving.ts", + "src/cli/commands/skill-program-options.ts", + "src/cli/commands/skill.ts", + "src/cli/commands/slack.ts", + "src/cli/commands/upload-sourcemaps.ts", + "src/cli/commands/warehouse.ts", + "src/cli/dispatch-family.ts", + "src/cli/main.ts", + "src/cli/wizard.ts" ], "imports": [ - "constants.js", - "readiness.js" + "add-mcp-server-to-clients.js", + "agent.js", + "analytics.js", + "ci-install.js", + "console.js", + "interactive.js", + "non-interactive.js", + "playground.js", + "runners.js", + "store.js", + "tui.js" ] }, "mcp.js": { "sources": [ - "src/lib/agent/runner/harness/pi/mcp.ts" + "src/agent/runner/harness/pi/mcp.ts" ], "imports": [ - "debug.js", - "version.js" - ] - }, - "mcp-prompt-streaming.js": { - "sources": [ - "src/lib/agent/mcp-prompt-streaming.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "constants.js", - "debug.js", - "gateway-session.js" + "analytics.js" ] }, "non-interactive.js": { "sources": [ - "src/commands/basic-integration/non-interactive.ts" + "src/cli/commands/basic-integration/non-interactive.ts" ], "imports": [ - "errors.js", - "ui.js" + "add-mcp-server-to-clients.js", + "analytics.js" ] }, "orchestrator-tools.js": { "sources": [ - "src/lib/agent/runner/harness/pi/orchestrator-tools.ts" + "src/agent/runner/harness/pi/orchestrator-tools.ts" ], "imports": [ "analytics.js", @@ -432,678 +254,342 @@ ] }, "package-json.js": { - "sources": [ - "src/utils/package-json.ts" - ], - "imports": [ - "rolldown-runtime.js" - ] - }, - "package-manager.js": { - "sources": [ - "src/frameworks/python/utils.ts", - "src/lib/detection/package-manager.ts" - ], + "sources": [], "imports": [ - "setup-utils.js" + "package-json.js" ] }, "pi.js": { "sources": [ - "src/lib/agent/aio-capture.ts", - "src/lib/agent/runner/harness/pi/completion.ts", - "src/lib/agent/runner/harness/pi/index.ts" + "src/agent/aio-capture.ts", + "src/agent/runner/harness/pi/completion.ts", + "src/agent/runner/harness/pi/index.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "analytics.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", "mcp.js", "security.js", + "store.js", "subagent.js", "task.js", "tasks.js", - "tools.js", - "ui.js", - "version.js", - "yara-hooks.js" + "tools.js" ] }, "playground.js": { "sources": [ - "src/commands/basic-integration/playground.ts", - "src/ui/tui/playground/PlaygroundApp.tsx", - "src/ui/tui/playground/demos/AiOptInDemo.tsx", - "src/ui/tui/playground/demos/AskModalDemo.tsx", - "src/ui/tui/playground/demos/AuditChecksDemo.tsx", - "src/ui/tui/playground/demos/DoctorReportDemo.tsx", - "src/ui/tui/playground/demos/EndScreensDemo.tsx", - "src/ui/tui/playground/demos/HealthCheckDemo.tsx", - "src/ui/tui/playground/demos/InputDemo.tsx", - "src/ui/tui/playground/demos/KeyboardHintsDemo.tsx", - "src/ui/tui/playground/demos/LayoutDemo.tsx", - "src/ui/tui/playground/demos/LearnDeckDemo.tsx", - "src/ui/tui/playground/demos/LogDemo.tsx", - "src/ui/tui/playground/demos/McpDemo.tsx", - "src/ui/tui/playground/demos/McpSuggestedPromptsDemo.tsx", - "src/ui/tui/playground/demos/ModalDemo.tsx", - "src/ui/tui/playground/demos/ProgressDemo.tsx", - "src/ui/tui/playground/demos/RunScreenDemo.tsx", - "src/ui/tui/playground/demos/ViewportGuardDemo.tsx", - "src/ui/tui/playground/demos/WelcomeDemo.tsx", - "src/ui/tui/playground/start-playground.ts" - ], - "imports": [ - "bin.js", - "debug.js", - "readiness.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "terminal.js", - "version.js" - ] - }, - "posthog.js": { - "sources": [ - "src/lib/task-stream/destinations/posthog.ts" + "src/cli/commands/basic-integration/playground.ts" ], "imports": [ - "debug.js" + "analytics.js", + "tui.js" ] }, - "provisioning.js": { + "programs.js": { "sources": [ - "src/utils/provisioning.ts", - "src/utils/urls.ts" + "src/store/programs/ai-opt-in-gate.ts", + "src/store/programs/audit/ledger-watcher.ts", + "src/store/programs/error-tracking-upload-source-maps/detect-agentic.ts", + "src/store/programs/flow-for.ts", + "src/store/programs/run-config.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "constants.js", - "debug.js", - "rolldown-runtime.js" + "store.js" ] }, "queue-tools.js": { "sources": [ - "src/lib/agent/runner/sequence/orchestrator/queue-tools.ts", - "src/lib/agent/runner/sequence/orchestrator/queue.ts", - "src/lib/agent/runner/switchboard/models.ts", - "src/utils/atomic-ledger.ts" + "src/agent/runner/sequence/orchestrator/queue-tools.ts", + "src/agent/runner/sequence/orchestrator/queue.ts", + "src/agent/runner/switchboard/models.ts" ], "imports": [ "analytics.js", - "constants.js" - ] - }, - "readiness.js": { - "sources": [ - "src/lib/health-checks/readiness.ts" - ], - "imports": [ - "debug.js", - "endpoints.js" + "store.js" ] }, - "registry.js": { + "runners.js": { "sources": [ - "src/frameworks/android/android-wizard-agent.ts", - "src/frameworks/android/utils.ts", - "src/frameworks/angular/angular-wizard-agent.ts", - "src/frameworks/angular/utils.ts", - "src/frameworks/astro/astro-wizard-agent.ts", - "src/frameworks/astro/utils.ts", - "src/frameworks/django/django-wizard-agent.ts", - "src/frameworks/django/utils.ts", - "src/frameworks/elixir/elixir-wizard-agent.ts", - "src/frameworks/fastapi/fastapi-wizard-agent.ts", - "src/frameworks/fastapi/utils.ts", - "src/frameworks/flask/flask-wizard-agent.ts", - "src/frameworks/flask/utils.ts", - "src/frameworks/flutter/flutter-wizard-agent.ts", - "src/frameworks/go/go-wizard-agent.ts", - "src/frameworks/java/java-wizard-agent.ts", - "src/frameworks/javascript-node/javascript-node-wizard-agent.ts", - "src/frameworks/javascript-web/javascript-web-wizard-agent.ts", - "src/frameworks/javascript-web/utils.ts", - "src/frameworks/kmp/kmp-wizard-agent.ts", - "src/frameworks/laravel/laravel-wizard-agent.ts", - "src/frameworks/laravel/utils.ts", - "src/frameworks/nextjs/nextjs-wizard-agent.ts", - "src/frameworks/nextjs/utils.ts", - "src/frameworks/nuxt/nuxt-wizard-agent.ts", - "src/frameworks/python/python-wizard-agent.ts", - "src/frameworks/rails/rails-wizard-agent.ts", - "src/frameworks/rails/utils.ts", - "src/frameworks/react-native/react-native-wizard-agent.ts", - "src/frameworks/react-native/utils.ts", - "src/frameworks/react-router/react-router-wizard-agent.ts", - "src/frameworks/react-router/utils.ts", - "src/frameworks/ruby/ruby-wizard-agent.ts", - "src/frameworks/ruby/utils.ts", - "src/frameworks/rust/rust-wizard-agent.ts", - "src/frameworks/svelte/svelte-wizard-agent.ts", - "src/frameworks/swift/swift-wizard-agent.ts", - "src/frameworks/swift/utils.ts", - "src/frameworks/tanstack-router/tanstack-router-wizard-agent.ts", - "src/frameworks/tanstack-router/utils.ts", - "src/frameworks/tanstack-start/tanstack-start-wizard-agent.ts", - "src/frameworks/tanstack-start/utils.ts", - "src/frameworks/vue/vue-wizard-agent.ts", - "src/lib/framework-config.ts", - "src/lib/registry.ts" + "src/cli/runners/resolve-no-telemetry.ts", + "src/cli/runners/run-non-interactive.ts", + "src/cli/runners/run-wizard-ci.ts", + "src/cli/runners/run-wizard-headless.ts", + "src/cli/runners/run-wizard.ts" ], "imports": [ - "bounded-fs.js", - "package-json.js", - "package-manager.js", - "rolldown-runtime.js", - "setup-utils.js", - "ui.js" - ] - }, - "rolldown-runtime.js": { - "sources": [], - "imports": [] - }, - "run-failure.js": { - "sources": [ - "src/lib/detection/project-scope.ts", - "src/lib/programs/agent-skill/index.ts", - "src/lib/programs/agent-skill/steps.ts", - "src/lib/programs/ai-observability/index.ts", - "src/lib/programs/audit/detect.ts", - "src/lib/programs/audit/index.ts", - "src/lib/programs/audit/seed.ts", - "src/lib/programs/error-tracking-upload-source-maps/detect.ts", - "src/lib/programs/error-tracking-upload-source-maps/index.ts", - "src/lib/programs/error-tracking-upload-source-maps/prompt.ts", - "src/lib/programs/error-tracking-upload-source-maps/steps.ts", - "src/lib/programs/error-tracking/detect-agentic.ts", - "src/lib/programs/error-tracking/index.ts", - "src/lib/programs/events-audit/index.ts", - "src/lib/programs/events-audit/seed.ts", - "src/lib/programs/events-audit/steps.ts", - "src/lib/programs/mcp-analytics/index.ts", - "src/lib/programs/mcp/index.ts", - "src/lib/programs/metrics/index.ts", - "src/lib/programs/migration/index.ts", - "src/lib/programs/migration/steps.ts", - "src/lib/programs/posthog-doctor/fetch.ts", - "src/lib/programs/posthog-doctor/index.ts", - "src/lib/programs/posthog-doctor/kind-metadata.ts", - "src/lib/programs/posthog-doctor/steps.ts", - "src/lib/programs/posthog-doctor/types.ts", - "src/lib/programs/posthog-integration/handoff.ts", - "src/lib/programs/posthog-integration/index.ts", - "src/lib/programs/posthog-integration/steps.ts", - "src/lib/programs/program-registry.ts", - "src/lib/programs/replay-vision/index.ts", - "src/lib/programs/revenue-analytics/detect.ts", - "src/lib/programs/revenue-analytics/index.ts", - "src/lib/programs/revenue-analytics/steps.ts", - "src/lib/programs/self-driving/detect-agentic.ts", - "src/lib/programs/self-driving/detect.ts", - "src/lib/programs/self-driving/index.ts", - "src/lib/programs/self-driving/prompt.ts", - "src/lib/programs/self-driving/step-keys.ts", - "src/lib/programs/self-driving/steps.ts", - "src/lib/programs/shared/health-check-step.ts", - "src/lib/programs/shared/posthog-cli-preinstall.ts", - "src/lib/programs/slack/index.ts", - "src/lib/programs/warehouse-source/index.ts", - "src/lib/programs/warehouse-source/steps.ts", - "src/lib/programs/web-analytics-doctor/detect.ts", - "src/lib/programs/web-analytics-doctor/index.ts", - "src/lib/programs/web-analytics-doctor/steps.ts", - "src/lib/run-failure.ts", - "src/steps/install-cli-steering/index.ts", - "src/ui/tui/programs/self-driving/content/pricing.ts" - ], - "imports": [ - "agent-interface.js", + "add-mcp-server-to-clients.js", + "agent.js", "analytics.js", - "api.js", - "constants.js", - "debug.js", - "errors.js", - "package-json.js", - "provisioning.js", - "queue-tools.js", - "readiness.js", - "registry.js", - "setup-utils.js", - "steps.js", - "telemetry.js", - "token-pricing.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "console.js", + "programs.js", + "store.js", + "tui.js" ] }, "security.js": { "sources": [ - "src/lib/agent/runner/harness/pi/security.ts" + "src/agent/runner/harness/pi/security.ts" ], "imports": [ "agent-interface.js", "analytics.js", - "debug.js", - "yara-hooks.js" - ] - }, - "setup-utils.js": { - "sources": [ - "src/lib/host-resolution.ts", - "src/lib/oauth/program-scopes.ts", - "src/utils/oauth-errors.ts", - "src/utils/oauth.ts", - "src/utils/package-manager.ts", - "src/utils/project-resolution.ts", - "src/utils/semver.ts", - "src/utils/setup-utils.ts" - ], - "imports": [ - "analytics.js", - "api.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "local-dev.js", - "provisioning.js", - "rolldown-runtime.js", - "telemetry.js", - "ui.js", - "wizard-abort.js" - ] - }, - "start-tui.js": { - "sources": [ - "src/lib/programs/error-tracking-upload-source-maps/detect-agentic.ts", - "src/lib/wizard-spellbook.ts", - "src/steps/add-mcp-server-to-clients/browser-client.ts", - "src/steps/add-mcp-server-to-clients/login-client.ts", - "src/ui/store-ui.ts", - "src/ui/tui/App.tsx", - "src/ui/tui/components/PrivacyPanel.tsx", - "src/ui/tui/exit-line.ts", - "src/ui/tui/hooks/useGithubConnection.ts", - "src/ui/tui/posthog-integration-intro.ts", - "src/ui/tui/screen-registry.tsx", - "src/ui/tui/screens/AgentSkillIntroScreen.tsx", - "src/ui/tui/screens/AiObservabilityIntroScreen.tsx", - "src/ui/tui/screens/AuthErrorScreen.tsx", - "src/ui/tui/screens/AuthScreen.tsx", - "src/ui/tui/screens/ErrorTrackingDetectScreen.tsx", - "src/ui/tui/screens/ErrorTrackingIntroScreen.tsx", - "src/ui/tui/screens/ExitScreen.tsx", - "src/ui/tui/screens/IntroScreenLayout.tsx", - "src/ui/tui/screens/KeepSkillsScreen.tsx", - "src/ui/tui/screens/ManagedSettingsScreen.tsx", - "src/ui/tui/screens/ManualAuthCodeScreen.tsx", - "src/ui/tui/screens/MetricsIntroScreen.tsx", - "src/ui/tui/screens/MigrationIntroScreen.tsx", - "src/ui/tui/screens/MintFailureScreen.tsx", - "src/ui/tui/screens/PortConflictScreen.tsx", - "src/ui/tui/screens/PostHogIntegrationIntroScreen.tsx", - "src/ui/tui/screens/RevenueIntroScreen.tsx", - "src/ui/tui/screens/RunScreen.tsx", - "src/ui/tui/screens/SelfDrivingGitHubScreen.tsx", - "src/ui/tui/screens/SelfDrivingHandoffScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntegrationCheckScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntegrationDetectScreen.tsx", - "src/ui/tui/screens/SelfDrivingIntroScreen.tsx", - "src/ui/tui/screens/SessionTimeoutScreen.tsx", - "src/ui/tui/screens/SettingsOverrideScreen.tsx", - "src/ui/tui/screens/SetupScreen.tsx", - "src/ui/tui/screens/SourceMapsDetectScreen.tsx", - "src/ui/tui/screens/SourceMapsIntroScreen.tsx", - "src/ui/tui/screens/SourceMapsOutroScreen.tsx", - "src/ui/tui/screens/TaskNoticeScreen.tsx", - "src/ui/tui/screens/WarehouseIntroScreen.tsx", - "src/ui/tui/screens/WizardAskScreen.tsx", - "src/ui/tui/screens/audit/AuditAreaPane.tsx", - "src/ui/tui/screens/audit/AuditChecksOutroSection.tsx", - "src/ui/tui/screens/audit/AuditIntroScreen.tsx", - "src/ui/tui/screens/audit/AuditOutroScreen.tsx", - "src/ui/tui/screens/audit/AuditRunScreen.tsx", - "src/ui/tui/screens/audit/PendingChecksList.tsx", - "src/ui/tui/screens/audit/slides/events-audit/createDashboard.tsx", - "src/ui/tui/screens/audit/slides/events-audit/detectSdk.tsx", - "src/ui/tui/screens/audit/slides/events-audit/enrichSites.tsx", - "src/ui/tui/screens/audit/slides/events-audit/index.ts", - "src/ui/tui/screens/audit/slides/events-audit/queryVolume.tsx", - "src/ui/tui/screens/audit/slides/events-audit/scanSites.tsx", - "src/ui/tui/screens/audit/slides/events-audit/uploadNotebook.tsx", - "src/ui/tui/screens/audit/slides/events-audit/writeReport.tsx", - "src/ui/tui/screens/doctor/DoctorIntroScreen.tsx", - "src/ui/tui/screens/doctor/DoctorReportScreen.tsx", - "src/ui/tui/screens/health/HealthCheckScreen.tsx", - "src/ui/tui/services/coding-agent-launcher.ts", - "src/ui/tui/services/mcp-installer.ts", - "src/ui/tui/services/mcp-suggested-prompts-services.ts", - "src/ui/tui/start-tui.ts", - "src/utils/clipboard.ts" - ], - "imports": [ - "add-mcp-server-to-clients.js", - "agent-interface.js", - "analytics.js", - "api.js", - "bin.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "defaults.js", - "errors.js", - "mcp-prompt-streaming.js", - "provisioning.js", - "readiness.js", - "registry.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "telemetry.js", - "terminal.js", - "token-pricing.js", - "ui.js", - "wizard-abort.js", - "wizard-session.js", - "yara-hooks.js" + "store.js" ] }, "steps.js": { "sources": [ - "src/steps/upload-environment-variables/EnvironmentProvider.ts", - "src/steps/upload-environment-variables/index.ts", - "src/steps/upload-environment-variables/providers/vercel.ts" + "src/store/services/steps/upload-environment-variables/EnvironmentProvider.ts", + "src/store/services/steps/upload-environment-variables/index.ts", + "src/store/services/steps/upload-environment-variables/providers/vercel.ts" ], "imports": [ - "analytics.js", - "telemetry.js", - "ui.js" + "add-mcp-server-to-clients.js", + "analytics.js" ] }, "store.js": { - "sources": [ - "src/lib/flow-resolution.ts", - "src/ui/tui/store.ts" - ], + "sources": [], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "debug.js", - "readiness.js", - "rolldown-runtime.js", - "run-failure.js", - "token-pricing.js", - "wizard-session.js", - "wizard-ui.js" + "store.js" ] }, "subagent.js": { "sources": [ - "src/lib/agent/runner/harness/pi/subagent.ts" + "src/agent/runner/harness/pi/subagent.ts" ], "imports": [ - "debug.js" + "analytics.js" ] }, "task.js": { "sources": [ - "src/lib/agent/runner/harness/pi/task.ts" + "src/agent/runner/harness/pi/task.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "agent-interface.js", "agent-prompt-loader.js", "analytics.js", - "constants.js", - "debug.js", - "errors.js", - "gateway-session.js", "mcp.js", "orchestrator-tools.js", "pi.js", "queue-tools.js", "security.js", - "tools.js", - "ui.js", - "yara-hooks.js" - ] - }, - "task-stream.js": { - "sources": [ - "src/lib/task-stream/audit-areas.ts", - "src/lib/task-stream/event-plan-watcher.ts", - "src/lib/task-stream/task-stream-push.ts" - ], - "imports": [ - "debug.js", - "errors.js", - "file-watcher.js", - "file.js", - "posthog.js" + "store.js", + "tools.js" ] }, "tasks.js": { "sources": [ - "src/lib/agent/runner/harness/pi/tasks.ts" - ], - "imports": [ - "ui.js" - ] - }, - "telemetry.js": { - "sources": [ - "src/telemetry.ts", - "src/utils/links.ts" + "src/agent/runner/harness/pi/tasks.ts" ], "imports": [ "analytics.js" ] }, - "terminal.js": { - "sources": [ - "src/lib/mcp-project-profile.ts", - "src/lib/mcp-role-prompts.copy.json", - "src/lib/mcp-role-prompts.ts", - "src/lib/mcp-seed-events.ts", - "src/ui/tui/components/LearnCard.tsx", - "src/ui/tui/components/PhaseVisuals.tsx", - "src/ui/tui/components/ServiceHealthList.tsx", - "src/ui/tui/components/StatusPeekTrigger.tsx", - "src/ui/tui/components/TipsCard.tsx", - "src/ui/tui/components/TitleBar.tsx", - "src/ui/tui/components/TokenCostHud.tsx", - "src/ui/tui/components/visualizer/CrateStack.tsx", - "src/ui/tui/components/visualizer/DashboardGrid.tsx", - "src/ui/tui/components/visualizer/DiffCascade.tsx", - "src/ui/tui/components/visualizer/LibraryShelf.tsx", - "src/ui/tui/components/visualizer/MatrixRain.tsx", - "src/ui/tui/components/visualizer/Tumblers.tsx", - "src/ui/tui/components/visualizer/grid.ts", - "src/ui/tui/components/visualizer/palette.ts", - "src/ui/tui/components/visualizer/panel.tsx", - "src/ui/tui/constants.ts", - "src/ui/tui/hooks/useDismissOnAnyKey.ts", - "src/ui/tui/hooks/useTick.ts", - "src/ui/tui/hooks/useUiStore.ts", - "src/ui/tui/primitives/CardLayout.tsx", - "src/ui/tui/primitives/ConfirmationInput.tsx", - "src/ui/tui/primitives/ContentSequencer.tsx", - "src/ui/tui/primitives/DissolveTransition.tsx", - "src/ui/tui/primitives/Divider.tsx", - "src/ui/tui/primitives/EventPlanViewer.tsx", - "src/ui/tui/primitives/GroupedPickerMenu.tsx", - "src/ui/tui/primitives/HNViewer.tsx", - "src/ui/tui/primitives/KeyboardHintsBar.tsx", - "src/ui/tui/primitives/LinesBlock.tsx", - "src/ui/tui/primitives/LinkText.tsx", - "src/ui/tui/primitives/LoadingBox.tsx", - "src/ui/tui/primitives/LogViewer.tsx", - "src/ui/tui/primitives/ModalOverlay.tsx", - "src/ui/tui/primitives/NodeBlock.tsx", - "src/ui/tui/primitives/ProgressList.tsx", - "src/ui/tui/primitives/ScreenContainer.tsx", - "src/ui/tui/primitives/ScreenErrorBoundary.tsx", - "src/ui/tui/primitives/SplitView.tsx", - "src/ui/tui/primitives/TabContainer.tsx", - "src/ui/tui/primitives/TextBlock.tsx", - "src/ui/tui/primitives/ViewportTooSmall.tsx", - "src/ui/tui/primitives/link-helpers.ts", - "src/ui/tui/primitives/text-helpers.ts", - "src/ui/tui/programs/agent-skill/content/index.tsx", - "src/ui/tui/programs/error-tracking-upload-source-maps/content/index.tsx", - "src/ui/tui/programs/error-tracking/content/index.tsx", - "src/ui/tui/programs/error-tracking/content/tips.ts", - "src/ui/tui/programs/migration/content/free-tier.tsx", - "src/ui/tui/programs/migration/content/index.tsx", - "src/ui/tui/programs/migration/content/pricing-structure.tsx", - "src/ui/tui/programs/migration/content/vendor-stack.tsx", - "src/ui/tui/programs/posthog-integration/content/data-flow.tsx", - "src/ui/tui/programs/posthog-integration/content/funnel.tsx", - "src/ui/tui/programs/posthog-integration/content/index.tsx", - "src/ui/tui/programs/posthog-integration/content/line-chart.tsx", - "src/ui/tui/programs/posthog-integration/content/product-suite.tsx", - "src/ui/tui/programs/presentation.ts", - "src/ui/tui/programs/self-driving/content/index.tsx", - "src/ui/tui/programs/self-driving/content/pipeline-diagram.tsx", - "src/ui/tui/programs/self-driving/content/tips.ts", - "src/ui/tui/screens/AiOptInRequiredScreen.tsx", - "src/ui/tui/screens/McpScreen.tsx", - "src/ui/tui/screens/McpSuggestedPromptsScreen.tsx", - "src/ui/tui/screens/OutroScreen.tsx", - "src/ui/tui/screens/SkillSourceInfo.tsx", - "src/ui/tui/screens/SlackConnectScreen.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/AuditChecksViewer.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/CheckRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/DetailRow.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Footer.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Header.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/Legend.tsx", - "src/ui/tui/screens/audit/AuditChecksViewer/layout.ts", - "src/ui/tui/screens/audit/AuditChecksViewer/sort.ts", - "src/ui/tui/screens/audit/slides/eventCapture.tsx", - "src/ui/tui/screens/audit/slides/identification.tsx", - "src/ui/tui/screens/audit/slides/index.ts", - "src/ui/tui/screens/audit/slides/installation.tsx", - "src/ui/tui/screens/audit/slides/liveData.tsx", - "src/ui/tui/screens/audit/slides/shared.tsx", - "src/ui/tui/screens/audit/slides/uploadNotebook.tsx", - "src/ui/tui/screens/audit/slides/writeReport.tsx", - "src/ui/tui/screens/doctor/IssueTable.tsx", - "src/ui/tui/terminal.ts", - "src/ui/tui/ui-store.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "api.js", - "bin.js", - "constants.js", - "debug.js", - "defaults.js", - "readiness.js", - "run-failure.js", - "setup-utils.js", - "store.js", - "telemetry.js", - "token-pricing.js", - "yara-hooks.js" - ] - }, - "token-pricing.js": { - "sources": [ - "src/lib/agent/runner/shared/authenticate.ts", - "src/lib/ask-policy.ts", - "src/lib/detection/agentic.ts", - "src/lib/detection/context.ts", - "src/lib/detection/features.ts", - "src/lib/detection/framework.ts", - "src/lib/programs/posthog-integration/detect.ts", - "src/lib/programs/shared/package-scanning.ts", - "src/lib/programs/warehouse-source/detect.ts", - "src/lib/token-pricing.ts", - "src/lib/warehouse-sources/detect.ts", - "src/lib/warehouse-sources/registry.ts" - ], - "imports": [ - "agent-interface.js", - "analytics.js", - "bounded-fs.js", - "constants.js", - "debug.js", - "errors.js", - "package-manager.js", - "registry.js", - "setup-utils.js", - "ui.js", - "wizard-session.js" - ] - }, "tools.js": { "sources": [ - "src/lib/agent/runner/harness/pi/tools.ts" + "src/agent/runner/harness/pi/tools.ts" ], "imports": [ - "agent-interface.js", "analytics.js", - "debug.js", - "package-manager.js", "pi.js", - "queue-tools.js", - "yara-hooks.js" - ] - }, - "ui.js": { - "sources": [ - "src/ui/index.ts", - "src/ui/null-ui.ts" - ], - "imports": [] - }, - "version.js": { - "sources": [ - "src/lib/version.ts" - ], - "imports": [] - }, - "wizard-abort.js": { - "sources": [], - "imports": [ - "wizard-abort.js" - ] - }, - "wizard-session.js": { - "sources": [], - "imports": [ - "wizard-session.js" - ] - }, - "wizard-ui.js": { - "sources": [ - "src/ui/wizard-ui.ts" - ], - "imports": [] - }, - "yara-hooks.js": { - "sources": [ - "src/lib/programs/audit/types.ts", - "src/lib/programs/events-audit/constants.ts", - "src/lib/programs/posthog-integration/constants.ts", - "src/lib/skill-install.ts", - "src/lib/yara-hooks.ts", - "src/lib/yara-policy.ts" + "store.js" + ] + }, + "tui.js": { + "sources": [ + "src/tui/App.tsx", + "src/tui/components/LearnCard.tsx", + "src/tui/components/PhaseVisuals.tsx", + "src/tui/components/PrivacyPanel.tsx", + "src/tui/components/ServiceHealthList.tsx", + "src/tui/components/StatusPeekTrigger.tsx", + "src/tui/components/TipsCard.tsx", + "src/tui/components/TitleBar.tsx", + "src/tui/components/TokenCostHud.tsx", + "src/tui/components/visualizer/CrateStack.tsx", + "src/tui/components/visualizer/DashboardGrid.tsx", + "src/tui/components/visualizer/DiffCascade.tsx", + "src/tui/components/visualizer/LibraryShelf.tsx", + "src/tui/components/visualizer/MatrixRain.tsx", + "src/tui/components/visualizer/Tumblers.tsx", + "src/tui/components/visualizer/grid.ts", + "src/tui/components/visualizer/palette.ts", + "src/tui/components/visualizer/panel.tsx", + "src/tui/constants.ts", + "src/tui/exit-line.ts", + "src/tui/family-picker.tsx", + "src/tui/hooks/keyboard-hints-utils.ts", + "src/tui/hooks/useDismissOnAnyKey.ts", + "src/tui/hooks/useGithubConnection.ts", + "src/tui/hooks/useKeyBindings.ts", + "src/tui/hooks/useKeyboardHints.tsx", + "src/tui/hooks/useStdoutDimensions.ts", + "src/tui/hooks/useTick.ts", + "src/tui/hooks/useUiStore.ts", + "src/tui/mint-failure.ts", + "src/tui/playground/PlaygroundApp.tsx", + "src/tui/playground/demos/AiOptInDemo.tsx", + "src/tui/playground/demos/AskModalDemo.tsx", + "src/tui/playground/demos/AuditChecksDemo.tsx", + "src/tui/playground/demos/DoctorReportDemo.tsx", + "src/tui/playground/demos/EndScreensDemo.tsx", + "src/tui/playground/demos/HealthCheckDemo.tsx", + "src/tui/playground/demos/InputDemo.tsx", + "src/tui/playground/demos/KeyboardHintsDemo.tsx", + "src/tui/playground/demos/LayoutDemo.tsx", + "src/tui/playground/demos/LearnDeckDemo.tsx", + "src/tui/playground/demos/LogDemo.tsx", + "src/tui/playground/demos/McpDemo.tsx", + "src/tui/playground/demos/McpSuggestedPromptsDemo.tsx", + "src/tui/playground/demos/ModalDemo.tsx", + "src/tui/playground/demos/ProgressDemo.tsx", + "src/tui/playground/demos/RunScreenDemo.tsx", + "src/tui/playground/demos/ViewportGuardDemo.tsx", + "src/tui/playground/demos/WelcomeDemo.tsx", + "src/tui/playground/start-playground.ts", + "src/tui/posthog-integration-intro.ts", + "src/tui/primitives/CardLayout.tsx", + "src/tui/primitives/ConfirmButton.tsx", + "src/tui/primitives/ConfirmationInput.tsx", + "src/tui/primitives/ContentSequencer.tsx", + "src/tui/primitives/DissolveTransition.tsx", + "src/tui/primitives/Divider.tsx", + "src/tui/primitives/EventPlanViewer.tsx", + "src/tui/primitives/GroupedPickerMenu.tsx", + "src/tui/primitives/HNViewer.tsx", + "src/tui/primitives/KeyboardHintsBar.tsx", + "src/tui/primitives/LinesBlock.tsx", + "src/tui/primitives/LinkText.tsx", + "src/tui/primitives/LoadingBox.tsx", + "src/tui/primitives/LogViewer.tsx", + "src/tui/primitives/ModalOverlay.tsx", + "src/tui/primitives/NodeBlock.tsx", + "src/tui/primitives/PickerMenu.tsx", + "src/tui/primitives/ProgressList.tsx", + "src/tui/primitives/PromptLabel.tsx", + "src/tui/primitives/ScreenContainer.tsx", + "src/tui/primitives/ScreenErrorBoundary.tsx", + "src/tui/primitives/SplitView.tsx", + "src/tui/primitives/TabContainer.tsx", + "src/tui/primitives/TextBlock.tsx", + "src/tui/primitives/ViewportTooSmall.tsx", + "src/tui/primitives/content-types.ts", + "src/tui/primitives/layout-helpers.ts", + "src/tui/primitives/link-helpers.ts", + "src/tui/primitives/picker-filter.ts", + "src/tui/primitives/text-helpers.ts", + "src/tui/programs/agent-skill/content/index.tsx", + "src/tui/programs/error-tracking-upload-source-maps/content/index.tsx", + "src/tui/programs/error-tracking/content/index.tsx", + "src/tui/programs/error-tracking/content/tips.ts", + "src/tui/programs/migration/content/free-tier.tsx", + "src/tui/programs/migration/content/index.tsx", + "src/tui/programs/migration/content/pricing-structure.tsx", + "src/tui/programs/migration/content/vendor-stack.tsx", + "src/tui/programs/posthog-integration/content/data-flow.tsx", + "src/tui/programs/posthog-integration/content/funnel.tsx", + "src/tui/programs/posthog-integration/content/index.tsx", + "src/tui/programs/posthog-integration/content/line-chart.tsx", + "src/tui/programs/posthog-integration/content/product-suite.tsx", + "src/tui/programs/presentation.ts", + "src/tui/programs/self-driving/content/index.tsx", + "src/tui/programs/self-driving/content/pipeline-diagram.tsx", + "src/tui/programs/self-driving/content/tips.ts", + "src/tui/screen-registry.tsx", + "src/tui/screens/AgentSkillIntroScreen.tsx", + "src/tui/screens/AiObservabilityIntroScreen.tsx", + "src/tui/screens/AiOptInRequiredScreen.tsx", + "src/tui/screens/AuthErrorScreen.tsx", + "src/tui/screens/AuthScreen.tsx", + "src/tui/screens/ErrorTrackingDetectScreen.tsx", + "src/tui/screens/ErrorTrackingIntroScreen.tsx", + "src/tui/screens/ExitScreen.tsx", + "src/tui/screens/IntroScreenLayout.tsx", + "src/tui/screens/KeepSkillsScreen.tsx", + "src/tui/screens/ManagedSettingsScreen.tsx", + "src/tui/screens/ManualAuthCodeScreen.tsx", + "src/tui/screens/McpScreen.tsx", + "src/tui/screens/McpSuggestedPromptsScreen.tsx", + "src/tui/screens/MetricsIntroScreen.tsx", + "src/tui/screens/MigrationIntroScreen.tsx", + "src/tui/screens/MintFailureScreen.tsx", + "src/tui/screens/OutroScreen.tsx", + "src/tui/screens/PortConflictScreen.tsx", + "src/tui/screens/PostHogIntegrationIntroScreen.tsx", + "src/tui/screens/RevenueIntroScreen.tsx", + "src/tui/screens/RunScreen.tsx", + "src/tui/screens/SelfDrivingGitHubScreen.tsx", + "src/tui/screens/SelfDrivingHandoffScreen.tsx", + "src/tui/screens/SelfDrivingIntegrationCheckScreen.tsx", + "src/tui/screens/SelfDrivingIntegrationDetectScreen.tsx", + "src/tui/screens/SelfDrivingIntroScreen.tsx", + "src/tui/screens/SessionTimeoutScreen.tsx", + "src/tui/screens/SettingsOverrideScreen.tsx", + "src/tui/screens/SetupScreen.tsx", + "src/tui/screens/SkillSourceInfo.tsx", + "src/tui/screens/SlackConnectScreen.tsx", + "src/tui/screens/SourceMapsDetectScreen.tsx", + "src/tui/screens/SourceMapsIntroScreen.tsx", + "src/tui/screens/SourceMapsOutroScreen.tsx", + "src/tui/screens/TaskNoticeScreen.tsx", + "src/tui/screens/WarehouseIntroScreen.tsx", + "src/tui/screens/WizardAskScreen.tsx", + "src/tui/screens/audit/AuditAreaPane.tsx", + "src/tui/screens/audit/AuditChecksOutroSection.tsx", + "src/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/AuditChecksViewer.tsx", + "src/tui/screens/audit/AuditChecksViewer/CheckRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/DetailRow.tsx", + "src/tui/screens/audit/AuditChecksViewer/Footer.tsx", + "src/tui/screens/audit/AuditChecksViewer/Header.tsx", + "src/tui/screens/audit/AuditChecksViewer/Legend.tsx", + "src/tui/screens/audit/AuditChecksViewer/layout.ts", + "src/tui/screens/audit/AuditChecksViewer/sort.ts", + "src/tui/screens/audit/AuditIntroScreen.tsx", + "src/tui/screens/audit/AuditOutroScreen.tsx", + "src/tui/screens/audit/AuditRunScreen.tsx", + "src/tui/screens/audit/PendingChecksList.tsx", + "src/tui/screens/audit/slides/eventCapture.tsx", + "src/tui/screens/audit/slides/events-audit/createDashboard.tsx", + "src/tui/screens/audit/slides/events-audit/detectSdk.tsx", + "src/tui/screens/audit/slides/events-audit/enrichSites.tsx", + "src/tui/screens/audit/slides/events-audit/index.ts", + "src/tui/screens/audit/slides/events-audit/queryVolume.tsx", + "src/tui/screens/audit/slides/events-audit/scanSites.tsx", + "src/tui/screens/audit/slides/events-audit/uploadNotebook.tsx", + "src/tui/screens/audit/slides/events-audit/writeReport.tsx", + "src/tui/screens/audit/slides/identification.tsx", + "src/tui/screens/audit/slides/index.ts", + "src/tui/screens/audit/slides/installation.tsx", + "src/tui/screens/audit/slides/liveData.tsx", + "src/tui/screens/audit/slides/shared.tsx", + "src/tui/screens/audit/slides/uploadNotebook.tsx", + "src/tui/screens/audit/slides/writeReport.tsx", + "src/tui/screens/doctor/DoctorIntroScreen.tsx", + "src/tui/screens/doctor/DoctorReportScreen.tsx", + "src/tui/screens/doctor/IssueTable.tsx", + "src/tui/screens/health/HealthCheckScreen.tsx", + "src/tui/services/coding-agent-launcher.ts", + "src/tui/services/mcp-installer.ts", + "src/tui/services/mcp-suggested-prompts-services.ts", + "src/tui/start-tui.ts", + "src/tui/styles.ts", + "src/tui/terminal.ts", + "src/tui/ui-store.ts" ], "imports": [ + "add-mcp-server-to-clients.js", "analytics.js", - "bounded-fs.js", - "debug.js", - "ui.js" + "programs.js", + "store.js" ] } } diff --git a/scripts/check-screens.tsx b/scripts/check-screens.tsx index bfc2871b5..36c0cbab7 100644 --- a/scripts/check-screens.tsx +++ b/scripts/check-screens.tsx @@ -10,12 +10,12 @@ import React from 'react'; import { render } from 'ink-testing-library'; import { Box } from 'ink'; -import { AuthErrorScreen } from '@ui/tui/screens/AuthErrorScreen'; -import { ProgressList } from '@ui/tui/primitives/ProgressList'; -import { ManagedSettingsScreen } from '@ui/tui/screens/ManagedSettingsScreen'; -import { SettingsOverrideScreen } from '@ui/tui/screens/SettingsOverrideScreen'; -import { WizardAskScreen } from '@ui/tui/screens/WizardAskScreen'; -import type { SettingsConflict } from '@lib/agent/agent-interface'; +import { AuthErrorScreen } from '@tui/screens/AuthErrorScreen'; +import { ProgressList } from '@tui/primitives/ProgressList'; +import { ManagedSettingsScreen } from '@tui/screens/ManagedSettingsScreen'; +import { SettingsOverrideScreen } from '@tui/screens/SettingsOverrideScreen'; +import { WizardAskScreen } from '@tui/screens/WizardAskScreen'; +import type { SettingsConflict } from '@store/types'; function fakeStore(session: Record): any { return { diff --git a/scripts/generate-version.cjs b/scripts/generate-version.cjs index 486932d39..013eaeb38 100644 --- a/scripts/generate-version.cjs +++ b/scripts/generate-version.cjs @@ -6,6 +6,6 @@ const pkg = JSON.parse( ); const output = `// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '${pkg.version}';\n`; fs.writeFileSync( - path.join(__dirname, '..', 'src', 'lib', 'version.ts'), + path.join(__dirname, '..', 'src', 'store', 'shared', 'version.ts'), output, ); diff --git a/scripts/mcp-install-smoke-test.ts b/scripts/mcp-install-smoke-test.ts index 13140d317..633a57f3a 100644 --- a/scripts/mcp-install-smoke-test.ts +++ b/scripts/mcp-install-smoke-test.ts @@ -15,7 +15,7 @@ import * as os from 'node:os'; import * as path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { HEADLESS_FLAG } from '../src/lib/headless-mode'; +import { HEADLESS_FLAG } from '@store/shared/headless-mode'; const PROVIDERS = ['claude-code', 'codex'] as const; type Provider = (typeof PROVIDERS)[number]; diff --git a/scripts/tui-host.no-jest.ts b/scripts/tui-host.no-jest.ts index 358bd3589..a45d72fe8 100644 --- a/scripts/tui-host.no-jest.ts +++ b/scripts/tui-host.no-jest.ts @@ -16,35 +16,39 @@ import fs from 'fs'; import net from 'net'; import { spawnSync } from 'child_process'; -import { startTUI } from '@ui/tui/start-tui'; -import { VERSION } from '@lib/version'; +import { startTUI } from '@tui/start-tui'; +import { setDetectionAgent } from '@store/detection/agentic'; +import { setMcpPromptRunner } from '@store/agent-protocol/mcp-prompt'; +import { detectProjectsWithAgent } from '@agent/detection/agentic'; +import { runMcpPromptViaSdk } from '@agent/mcp-prompt-streaming'; +import { VERSION } from '@store/shared/version'; import { Program, getProgramConfig, type ProgramId, -} from '@lib/programs/program-registry'; -import type { Harness, Sequence } from '@lib/constants'; -import { buildSession } from '@lib/wizard-session'; -import { initLocalDev } from '@lib/local-dev'; -import { configureGatewayFromCIEnvironment } from '@lib/gateway-session'; -import { runAgent } from '@lib/agent/agent-runner'; -import { runConfigFor } from '@lib/programs/run-config'; -import { TaskStreamPush, createFileDestination } from '@lib/task-stream/index'; -import { getAuditChecks } from '@lib/programs/audit/types'; -import { authenticate } from '@lib/agent/runner/shared/authenticate'; -import { getOrAskForProjectData } from '@utils/setup-utils'; -import { logToFile } from '@utils/debug'; +} from '@store/programs/program-registry'; +import type { Harness, Sequence } from '@store/shared/constants'; +import { buildSession } from '@store/session/wizard-session'; +import { initLocalDev } from '@store/local-dev'; +import { configureGatewayFromCIEnvironment } from '@agent/gateway/gateway-session'; +import { runAgent } from '@agent'; +import { runConfigFor } from '@store/programs/run-config'; +import { TaskStreamPush, createFileDestination } from '@store/task-stream'; +import { getAuditChecks } from '@store/programs/audit/types'; +import { authenticate } from '@store/services/authenticate'; +import { getOrAskForProjectData } from '@store/shared/setup-utils'; +import { logToFile } from '@store/shared/debug'; import { join } from 'path'; -import { detectFramework } from '@lib/detection/index'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import type { Integration } from '@lib/constants'; -import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@lib/programs/self-driving/detect'; -import { ERROR_TRACKING_PROJECT_PATH_KEY } from '@lib/programs/error-tracking/detect-agentic'; +import { detectFramework } from '@store/detection'; +import { FRAMEWORK_REGISTRY } from '@store/registry'; +import type { Integration } from '@store/shared/constants'; +import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '@store/programs/self-driving/detect'; +import { ERROR_TRACKING_PROJECT_PATH_KEY } from '@store/programs/error-tracking/detect-agentic'; import { detectSourceMapsPrerequisites, SOURCE_MAPS_CONTEXT_KEYS, -} from '@lib/programs/error-tracking-upload-source-maps/index'; -import { ScreenId, Overlay } from '@ui/tui/router'; +} from '@store/programs/error-tracking-upload-source-maps'; +import { ScreenId, Overlay } from '@tui/router'; import { WizardCiDriver } from '@e2e-harness/wizard-ci-driver'; import { decideE2eAction, @@ -222,6 +226,8 @@ async function main() { localPosthog: envFlag('POSTHOG_WIZARD_LOCAL_POSTHOG'), }); + setDetectionAgent(detectProjectsWithAgent); + setMcpPromptRunner({ runMcpPrompt: runMcpPromptViaSdk }); const { store } = startTUI(VERSION, programId); store.session = buildSession({ installDir: process.env.APP_DIR!, diff --git a/scripts/warlock-smoke-test.ts b/scripts/warlock-smoke-test.ts index 089e4110d..c73bae47a 100644 --- a/scripts/warlock-smoke-test.ts +++ b/scripts/warlock-smoke-test.ts @@ -11,8 +11,8 @@ import { scan, CATEGORIES, type Category } from '@posthog/warlock'; import fs from 'fs'; import os from 'os'; import path from 'path'; -import { scanVerdict } from '../src/lib/yara-policy'; -import { scanInstalledSkill } from '../src/lib/yara-hooks'; +import { scanVerdict } from '@store/security/yara-policy'; +import { scanInstalledSkill } from '@store/security/yara-hooks'; // Assembled at runtime so no scannable secret literal is committed. const fakeStripeKey = 'sk_' + 'live_' + '5'.repeat(24); diff --git a/src/__tests__/architecture/__snapshots__/boundary-contracts.test.ts.snap b/src/__tests__/architecture/__snapshots__/boundary-contracts.test.ts.snap new file mode 100644 index 000000000..971f551b1 --- /dev/null +++ b/src/__tests__/architecture/__snapshots__/boundary-contracts.test.ts.snap @@ -0,0 +1,485 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`boundary contracts > agent consumes exactly the recorded names from other surfaces 1`] = ` +{ + "@store": [ + "ADDITIONAL_FEATURE_PROMPTS", + "AGENT_ERROR_CODE", + "AUDIT_ADD_CHECKS_DESCRIPTION", + "AUDIT_ADD_CHECKS_PARAM_DESCRIPTION", + "AUDIT_RESOLVE_CHECKS_DESCRIPTION", + "AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION", + "AUDIT_SEED_CHECKS_DESCRIPTION", + "AUDIT_SEED_CHECKS_PARAM_DESCRIPTION", + "AUDIT_STATUSES", + "AWS_SKILLS_BASE_URL", + "AgentErrorType", + "AgentSignals", + "CHECK_ENV_KEYS_DESCRIPTION", + "CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION", + "CallType", + "DEFAULT_AGENT_MODEL", + "DEFAULT_ASK_MAX_QUESTIONS", + "ENV_FILE_PATH_DESCRIPTION", + "ErrorCodes", + "FRAMEWORK_REGISTRY", + "GPT5_6_LUNA_MODEL", + "GPT5_6_SOL_MODEL", + "GPT5_6_TERRA_MODEL", + "HAIKU_MODEL", + "HAIKU_TRIAGE_MODEL", + "Harness", + "LINTING_TOOLS", + "LONGER_ASK_TIMEOUT_MS", + "OutroKind", + "POSTHOG_DOCS_URL", + "PUBLISH_HANDOFF_CONTENT_DESCRIPTION", + "PUBLISH_HANDOFF_DESCRIPTION", + "PUBLISH_HANDOFF_TOOL_NAME", + "REMARK_INSTRUCTION", + "RESUME_INSTRUCTION", + "SERVER_NAME", + "SERVICE_LABELS", + "SIGNUP_WIZARD_READINESS_CONFIG", + "SONNET_5_MODEL", + "Sequence", + "ServiceHealthStatus", + "VERSION", + "WIZARD_ASK_KIND_DESCRIPTION", + "WIZARD_ASK_SENSITIVE_DESCRIPTION", + "WIZARD_ASK_SUBJECT_DESCRIPTION", + "WIZARD_ASK_TOOL_DESCRIPTION", + "WIZARD_BENCHMARK_FILE", + "WIZARD_CONTACT_EMAIL", + "WIZARD_LOG_FILE", + "WIZARD_ORCHESTRATOR_FLAG_KEY", + "WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY", + "WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY", + "WIZARD_REMARK_EVENT_NAME", + "WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY", + "WIZARD_TOOL_NAMES", + "WIZARD_USER_AGENT", + "WizardError", + "WizardReadiness", + "addAuditChecks", + "analytics", + "authenticate", + "backupAndFixClaudeSettings", + "checkAllSettingsConflicts", + "checkEnvKeys", + "checkLlmGatewayHealth", + "ciExcludedTaskTypes", + "classifyAuthFailure", + "classifySettingsConflicts", + "classifyToolToStage", + "coerceAgenticReport", + "computeTokenCostUsd", + "configureLogFile", + "createAskAccounting", + "createCustomHeaders", + "createPostToolUseYaraHooks", + "createPreToolUseYaraHooks", + "createRepeatBlockTracker", + "createSecretVault", + "createWizardAskBridge", + "debug", + "deriveReportJson", + "describeAskCancellation", + "detectNodePackageManagers", + "downloadSkill", + "enableDebugLogs", + "ensureGitignoreCoverage", + "evaluateWizardReadiness", + "fetchSkillMenu", + "fetchWithRetry", + "flushScanReport", + "formatScanReport", + "formatYaraAbortMessage", + "getBlockingServiceKeys", + "getLogFilePath", + "getSkillsBaseUrl", + "getUI", + "initLogFile", + "installSkillById", + "isFullyCancelled", + "isGrantRevoked", + "isNonInteractiveEnvironment", + "isSkillInstallCommand", + "isTemplateEnvFileName", + "isWizardDocumentationPath", + "legacyKeyNameRefusal", + "logToFile", + "makeMutex", + "manifestGlob", + "mcpUrlFor", + "mergeEnvValues", + "normaliseAskSubject", + "prewarmYaraScanner", + "publishBlockingMatch", + "publishHandoff", + "recordExternalScan", + "refreshAccessTokenIfNeeded", + "registerCleanup", + "repeatBlockReason", + "resolveAskQuestionKinds", + "resolveAuditChecks", + "resolveEnvPath", + "resolveEnvSecretRefs", + "restoreClaudeSettings", + "ringTerminalBell", + "sanitizeAgentSubprocessEnv", + "scanAndTriage", + "scanVerdict", + "seedAuditChecks", + "shouldDisableAsk", + "skillErrorCode", + "templateEnvWriteRefusal", + "vaultSensitiveAnswers", + "wizardAbort", + "wizardUserAgentForProgram", + "writeJsonAtomic", + "writeScanReport", + ], + "@store/programs": [ + "AUDIT_CHECKS_FILE", + "maybeStampAiSdkDetected", + "startAuditLedgerWatcher", + ], + "@store/types": [ + "AbortCase", + "AdditionalFeature", + "AgentChunk", + "AgentSignal", + "AgenticDetectOptions", + "AgenticDetectionReport", + "ApiProject", + "AuditCheck", + "AuditStatus", + "CloudRegion", + "Credentials", + "DetectTarget", + "Harness", + "HostResolution", + "InstallSkillResult", + "Integration", + "PackageManagerDetector", + "ProgramId", + "ProgramRun", + "ProgramRunConfig", + "PromptContext", + "RepeatBlockTracker", + "ScanContext", + "SecretVault", + "Sequence", + "SettingsConflict", + "SettingsConflictSource", + "SkillEntry", + "SpinnerHandle", + "TaskNotice", + "TokenUsageDelta", + "WizardAskBridge", + "WizardRunOptions", + "WizardSession", + ], +} +`; + +exports[`boundary contracts > cli consumes exactly the recorded names from other surfaces 1`] = ` +{ + "@agent": [ + "configureGatewayFromCIEnvironment", + "detectProjectsWithAgent", + "runAgent", + "runMcpPromptViaSdk", + ], + "@store": [ + "ApiError", + "CLI_STEERING_TARGETS", + "ErrorCodes", + "Harness", + "OutroKind", + "POSTHOG_DOCS_URL", + "POSTHOG_LOCAL_URL", + "PostHogDestination", + "RunPhase", + "Sequence", + "TaskStreamPush", + "VERSION", + "WIZARD_TOOL_NAMES", + "WizardError", + "WizardStore", + "addMCPServerToClientsStep", + "analytics", + "authenticate", + "buildSession", + "checkLocalServices", + "classifyRunFailure", + "configureLogFileFromEnvironment", + "createFileDestination", + "detectErrorCode", + "detectTargets", + "emitWizardError", + "fetchSkillMenu", + "findTarget", + "getLocalDev", + "getLogFilePath", + "getOrAskForProjectData", + "getSkillsBaseUrl", + "getUI", + "headlessOption", + "initLocalDev", + "installOrUpdatePostHogCli", + "installSteeringSnippet", + "isHeadless", + "isNonInteractiveEnvironment", + "isRunFailure", + "localMcpSkillsNotice", + "logToFile", + "provisionNewAccount", + "readApiKeyFromEnv", + "readEnvironment", + "recoverOrphanedSettingsBackups", + "regionOption", + "removeMCPServerFromClientsStep", + "runCleanups", + "setDetectionAgent", + "setEntryCommand", + "setMcpPromptRunner", + "setUI", + "wizardAbort", + ], + "@store/programs": [ + "AUDIT_CHECKS_FILE", + "Program", + "agentSkillConfig", + "aiObservabilityConfig", + "auditConfig", + "createSkillProgram", + "errorTrackingConfig", + "errorTrackingUploadSourceMapsConfig", + "fetchHealthIssues", + "flowFor", + "getAuditChecks", + "getKindMeta", + "getProgramConfig", + "maybeStampAiSdkDetected", + "mcpAnalyticsConfig", + "metricsConfig", + "migrationConfig", + "posthogDoctorConfig", + "posthogIntegrationConfig", + "replayVisionConfig", + "revenueAnalyticsConfig", + "runConfigFor", + "selfDrivingConfig", + "warehouseSourceConfig", + "webAnalyticsDoctorConfig", + ], + "@store/types": [ + "CliEntry", + "CliSteeringTarget", + "CloudRegion", + "ErrorCode", + "Harness", + "OutroData", + "ProgramConfig", + "ProvisioningResult", + "RunPhase", + "Sequence", + "TaskStreamPush", + "WizardSession", + "WizardStore", + ], + "@tui": [ + "createFamilyPickerDefault", + "startPlayground", + "startTUI", + ], + "@tui/console": [ + "HeadlessUI", + "LoggingUI", + ], + "@tui/types": [ + "TuiHandle", + ], +} +`; + +exports[`boundary contracts > tui consumes exactly the recorded names from other surfaces 1`] = ` +{ + "@store": [ + "ADDITIONAL_FEATURE_LABELS", + "ALL_FEATURE_VALUES", + "AVAILABLE_FEATURES", + "AdditionalFeature", + "AgentPhase", + "ApiError", + "CONTEXT_MILL_RELEASES_URL", + "CONTEXT_MILL_URL", + "DiscoveredFeature", + "ErrorCodes", + "FOLLOW_UP_EXIT_SENTINEL", + "FRAMEWORK_REGISTRY", + "GITHUB_SKILLS_BASE_URL", + "HostResolution", + "Integration", + "Interrupt", + "MAX_STATUS_MESSAGES", + "McpClientStatus", + "McpOutcome", + "OAUTH_PORTS", + "OAUTH_TIMEOUT_MS", + "OutroKind", + "POSTHOG_APP_URL", + "POSTHOG_DOCS_URL", + "POSTHOG_ORG_AI_SETTINGS_URL", + "POSTHOG_PRIVACY_URL", + "POSTHOG_TERMS_URL", + "RunPhase", + "SERVICE_LABELS", + "SIGNUP_WIZARD_READINESS_CONFIG", + "ScanConsent", + "ServiceHealthStatus", + "StoreUI", + "TAILORED_ROLES", + "TaskStatus", + "WIZARD_LOG_FILE", + "WizardReadiness", + "WizardStore", + "analytics", + "assembleProfile", + "copyToClipboard", + "degradedProfile", + "downloadSkill", + "extractOAuthCode", + "fetchGithubConnected", + "fetchSkillMenu", + "fetchSlackConnected", + "fetchUserData", + "formatCostUsd", + "formatTokenCount", + "getBlockingServiceKeys", + "getFollowUps", + "getGeneratedQuests", + "getInstalledClients", + "getIntegrationAuthorizeUrl", + "getLogFilePath", + "getMcpPromptRunner", + "getOrAskForProjectData", + "getRoleGreeting", + "getRolePrompts", + "getSeedOfferGreeting", + "getSkillsBaseUrl", + "getSlackAppCard", + "getSupportedClients", + "getSupportedPluginClients", + "getTutorialPicker", + "installPlugins", + "isAllFeaturesSelected", + "isBrowserFinishable", + "isKnownCloudHost", + "isLoginCapable", + "isOk", + "isPluginCapable", + "isRunFailure", + "logToFile", + "namesWithStatus", + "openInBrowser", + "openTrackedLink", + "probeProjectData", + "redactSecrets", + "relativeToInstallDir", + "removeMCPServer", + "requestDeepLink", + "seedDemoEvents", + "seededProfile", + "setUI", + "startFileWatcher", + "summarizeFailure", + "toClientResult", + "totalTokenCount", + "withUtm", + "wizardAbort", + "writeWizardSpellbook", + ], + "@store/programs": [ + "AUDIT_REPORT_FILE", + "AUDIT_SEVERITY_STYLE", + "ERROR_TRACKING_PROJECT_PATH_KEY", + "GITHUB_REQUIRED_BODY", + "GITHUB_REQUIRED_MESSAGE", + "MANUAL_SDK_VARIANTS", + "NO_DEFAULT_LIMIT", + "POSTHOG_SDKS", + "PRICING_LONG", + "PRICING_SHORT", + "PROGRAM_REGISTRY", + "Program", + "REPLAY_VISION_SUPPORTED", + "SELF_DRIVING_INTEGRATE_PATH_KEY", + "SETUP_REPORT_FILE", + "SOURCE_MAPS_CONTEXT_KEYS", + "STRIPE_SDKS", + "VARIANT_DISPLAY_NAME", + "detectErrorTrackingProjects", + "detectSelfDrivingIntegrationProjects", + "detectSourceMapsProjects", + "fetchHealthIssues", + "flowFor", + "getAuditChecks", + "getCommandPath", + "getDetectedWarehouseSources", + "getKindMeta", + "getLaunchablePrograms", + "getProgramConfig", + ], + "@store/types": [ + "AgentChunk", + "AllServicesHealth", + "ApiUser", + "AskAnswers", + "AskQuestion", + "AuditCheck", + "AuditStatus", + "AuthErrorDetail", + "CloudRegion", + "Credentials", + "DetectedProject", + "DetectionReport", + "ErrorTrackingDetectionReport", + "ErrorTrackingProject", + "FileWatcherHandle", + "FileWatcherOptions", + "HealthCheckKey", + "HealthIssue", + "HealthIssueSeverity", + "Integration", + "IntegrationDetectionReport", + "IntegrationProject", + "McpClientResult", + "McpPromptRequest", + "OutroData", + "PendingQuestion", + "PlannedEvent", + "ProgramId", + "ProjectDataProfile", + "PromptOption", + "RevenueDetectError", + "RoleGreeting", + "SelfDrivingDetectError", + "SettingsConflict", + "SetupQuestion", + "SkillEntry", + "SpinnerHandle", + "TaskNotice", + "TokenUsageDelta", + "TokenUsageSnapshot", + "WarehouseDetectError", + "WizardReadinessResult", + "WizardSession", + "WizardSpellbook", + "WizardStore", + "WizardUI", + ], +} +`; diff --git a/src/__tests__/architecture/boundary-contracts.test.ts b/src/__tests__/architecture/boundary-contracts.test.ts new file mode 100644 index 000000000..ba06863e5 --- /dev/null +++ b/src/__tests__/architecture/boundary-contracts.test.ts @@ -0,0 +1,70 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(HERE, '../../..'); + +const CONSUMERS: ReadonlyArray = [ + ['agent', ['src/agent']], + ['tui', ['src/tui']], + ['cli', ['src/cli', 'bin.ts']], +]; +const PUBLIC = /^@(store|agent|tui)(\/(types|programs|console))?$/; +const NAMED_IMPORT = + /^(?:import|export)\s+(?:type\s+)?\{([^}]*)\}\s*from\s*['"]([^'"]+)['"]/gm; +const DYNAMIC = + /const\s*\{([^}]*)\}\s*=\s*await\s+import\(\s*['"]([^'"]+)['"]\s*\)/g; + +function files(root: string, into: string[]): void { + const abs = path.join(REPO_ROOT, root); + if (fs.statSync(abs).isFile()) { + into.push(abs); + return; + } + for (const entry of fs.readdirSync(abs, { withFileTypes: true })) { + if (entry.name === '__tests__' || entry.name === 'testing') continue; + const p = path.join(abs, entry.name); + if (entry.isDirectory()) files(path.relative(REPO_ROOT, p), into); + else if (/\.tsx?$/.test(entry.name) && !/\.d\.ts$/.test(entry.name)) + into.push(p); + } +} + +/** Names a surface pulls from each public entry of another surface. */ +function consumed(roots: string[]): Record { + const list: string[] = []; + for (const r of roots) files(r, list); + const out = new Map>(); + const add = (spec: string, names: string) => { + if (!PUBLIC.test(spec)) return; + const set = out.get(spec) ?? new Set(); + for (const raw of names.split(',')) { + const name = raw + .trim() + .replace(/^type\s+/, '') + .replace(/\s+as\s+.*$/, ''); + if (name) set.add(name); + } + out.set(spec, set); + }; + for (const file of list) { + const text = fs.readFileSync(file, 'utf8'); + for (const m of text.matchAll(NAMED_IMPORT)) add(m[2], m[1]); + for (const m of text.matchAll(DYNAMIC)) add(m[2], m[1]); + } + return Object.fromEntries( + [...out] + .sort(([a], [b]) => a.localeCompare(b)) + .map(([spec, names]) => [spec, [...names].sort()]), + ); +} + +describe('boundary contracts', () => { + it.each(CONSUMERS)( + '%s consumes exactly the recorded names from other surfaces', + (_name, roots) => { + expect(consumed(roots)).toMatchSnapshot(); + }, + ); +}); diff --git a/src/__tests__/architecture/import-boundaries.test.ts b/src/__tests__/architecture/import-boundaries.test.ts index 09639c6e5..54f07dbf1 100644 --- a/src/__tests__/architecture/import-boundaries.test.ts +++ b/src/__tests__/architecture/import-boundaries.test.ts @@ -7,37 +7,27 @@ export type Surface = 'env' | 'store' | 'agent' | 'tui' | 'cli' | 'harness'; const HERE = path.dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = path.resolve(HERE, '../../..'); +/** Build and test configuration at the repo root; not surface code. */ +const TOOLING_FILES = new Set([ + 'vitest.config.ts', + 'vitest.shared.ts', + 'tsdown.config.ts', +]); + const SURFACE_RULES: ReadonlyArray boolean]> = [ ['env', (p) => p === 'src/env.ts'], - [ - 'agent', - (p) => - p.startsWith('src/lib/agent/') || - p.startsWith('src/lib/middleware/') || - p === 'src/lib/gateway-session.ts' || - p === 'src/lib/yara-hooks.ts' || - p === 'src/lib/yara-policy.ts' || - p === 'src/lib/wizard-tools/mcp.ts', - ], - [ - 'tui', - (p) => - p.startsWith('src/ui/tui/') || - p === 'src/commands/factories/family-picker.tsx', - ], - [ - 'cli', - (p) => - p === 'bin.ts' || - p === 'src/wizard.ts' || - p === 'src/telemetry.ts' || - p.startsWith('src/commands/') || - p.startsWith('src/lib/runners/'), - ], + ['agent', (p) => p.startsWith('src/agent/')], + ['tui', (p) => p.startsWith('src/tui/')], + ['cli', (p) => p === 'bin.ts' || p.startsWith('src/cli/')], [ 'harness', - (p) => p.startsWith('e2e-harness/') || p.startsWith('scripts/'), + (p) => + p.startsWith('e2e-harness/') || + p.startsWith('e2e-tests/') || + p.startsWith('scripts/') || + TOOLING_FILES.has(p) || + p.endsWith('/vitest.config.ts'), ], ]; @@ -62,6 +52,27 @@ export const ALLOWED_IMPORTS: Record< const TUI_ONLY_PACKAGES = ['ink', 'react', '@inkjs/ui', 'ink-testing-library']; +/** The only files another surface may import. Everything else is internal. */ +export const PUBLIC_ENTRIES: Record< + 'store' | 'agent' | 'tui', + readonly string[] +> = { + store: [ + 'src/store/index.ts', + 'src/store/types.ts', + 'src/store/programs/index.ts', + 'src/store/control/index.ts', + ], + agent: ['src/agent/index.ts', 'src/agent/types.ts'], + tui: ['src/tui/index.ts', 'src/tui/types.ts', 'src/tui/console/index.ts'], +}; + +/** The msw hook behind `NODE_ENV === 'test'`; tsdown inlines it away in published builds. */ +const TEST_ONLY_EDGES = new Set(['bin.ts -> e2e-tests/mocks/server.ts']); + +/** Console renderers ship in headless builds and must stay Ink free. */ +const INK_FREE_PREFIX = 'src/tui/console/'; + const SKIP_DIRS = new Set([ '__tests__', '__mocks__', @@ -195,6 +206,7 @@ function collectFiles(absDir: string, into: string[]): void { if (!/\.tsx?$/.test(entry.name)) continue; if (/\.d\.ts$/.test(entry.name) || /\.test\.tsx?$/.test(entry.name)) continue; + if (entry.name === 'vitest.config.ts') continue; into.push(toRepoRelative(abs)); } } @@ -289,7 +301,7 @@ function analyze(): Analysis { if (base === null) { const tuiOnly = TUI_ONLY_PACKAGES.includes(spec) || spec.startsWith('react/'); - if (tuiOnly && from !== 'tui') { + if (tuiOnly && (from !== 'tui' || file.startsWith(INK_FREE_PREFIX))) { violations.set(`${file} -> pkg:${spec}`, 'ink-outside-tui'); } continue; @@ -306,9 +318,18 @@ function analyze(): Analysis { edges.add(key); const to = classifySurface(target); - if (to === 'harness') violations.set(key, 'harness'); - else if (!allowed.includes(to)) + if (to === 'harness') { + if (!TEST_ONLY_EDGES.has(key)) violations.set(key, 'harness'); + } else if (!allowed.includes(to)) violations.set(key, `matrix:${from}->${to}`); + else if ( + to !== from && + (to === 'store' || to === 'agent' || to === 'tui') && + !PUBLIC_ENTRIES[to].includes(target) + ) + violations.set(key, `deep:${from}->${to}`); + else if (/\/testing\//.test(target) && !/\/testing\//.test(file)) + violations.set(key, 'testing-in-shipped-code'); } } @@ -324,12 +345,6 @@ function analyze(): Analysis { const analysis = analyze(); -const known = ( - JSON.parse( - fs.readFileSync(path.join(HERE, 'known-violations.json'), 'utf8'), - ) as { violations: string[] } -).violations; - if (process.env.PRINT_VIOLATIONS) { const byRule = new Map(); const byImporter = new Map(); @@ -354,13 +369,6 @@ if (process.env.PRINT_VIOLATIONS) { .map(([file, count]) => ` ${file}: ${count}`), ]; process.stderr.write(`${lines.join('\n')}\n`); - process.stderr.write( - `${JSON.stringify( - { violations: analysis.violations.map((v) => v.key) }, - null, - 2, - )}\n`, - ); } describe('import boundaries', () => { @@ -368,20 +376,9 @@ describe('import boundaries', () => { expect(analysis.unresolved).toEqual([]); }); - it('introduces no violation outside known-violations.json', () => { - const knownSet = new Set(known); - const added = analysis.violations - .filter(({ key }) => !knownSet.has(key)) - .map(({ key, rule }) => `${key} [${rule}]`); - expect(added).toEqual([]); - }); - - it('keeps known-violations.json free of stale entries', () => { - const current = new Set(analysis.violations.map((v) => v.key)); - const stale = known.filter((key) => !current.has(key)); + it('crosses surfaces only through public entries, in the allowed direction', () => { expect( - stale, - 'stale entries, delete them from known-violations.json', + analysis.violations.map(({ key, rule }) => `${key} [${rule}]`), ).toEqual([]); }); }); @@ -389,23 +386,19 @@ describe('import boundaries', () => { describe('surface classification', () => { it('maps representative paths to their surface', () => { expect(classifySurface('src/env.ts')).toBe('env'); - expect(classifySurface('src/utils/analytics.ts')).toBe('store'); - expect(classifySurface('src/lib/agent/agent-runner.ts')).toBe('agent'); - expect(classifySurface('src/ui/tui/App.tsx')).toBe('tui'); + expect(classifySurface('src/store/shared/analytics.ts')).toBe('store'); + expect(classifySurface('src/agent/agent-runner.ts')).toBe('agent'); + expect(classifySurface('src/tui/App.tsx')).toBe('tui'); expect(classifySurface('bin.ts')).toBe('cli'); expect(classifySurface('e2e-harness/e2e-profile.ts')).toBe('harness'); - expect(classifySurface('src/lib/wizard-tools/mcp.ts')).toBe('agent'); - expect(classifySurface('src/lib/wizard-tools/tools.ts')).toBe('store'); - expect(classifySurface('src/commands/factories/family-picker.tsx')).toBe( - 'tui', - ); + expect(classifySurface('src/agent/tools/mcp.ts')).toBe('agent'); + expect(classifySurface('src/store/tools/tools.ts')).toBe('store'); + expect(classifySurface('src/tui/family-picker.tsx')).toBe('tui'); expect( - classifySurface( - 'src/ui/tui/programs/posthog-integration/content/index.tsx', - ), + classifySurface('src/tui/programs/posthog-integration/content/index.tsx'), ).toBe('tui'); expect( - classifySurface('src/lib/programs/posthog-integration/index.ts'), + classifySurface('src/store/programs/posthog-integration/index.ts'), ).toBe('store'); }); }); diff --git a/src/__tests__/architecture/known-violations.json b/src/__tests__/architecture/known-violations.json deleted file mode 100644 index 0409c46d1..000000000 --- a/src/__tests__/architecture/known-violations.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "violations": [ - "src/commands/factories/family-picker.tsx -> src/commands/command.ts", - "src/env.ts -> src/lib/headless-mode.ts", - "src/lib/agent/mcp-prompt-streaming.ts -> src/ui/tui/services/mcp-suggested-prompts-services.ts", - "src/lib/detection/agentic.ts -> src/lib/agent/agent-interface.ts", - "src/lib/detection/project-scope.ts -> src/lib/agent/runner/shared/authenticate.ts", - "src/lib/programs/dispatch-family.ts -> src/commands/command.ts", - "src/lib/programs/dispatch-family.ts -> src/commands/factories/shared.ts", - "src/lib/programs/self-driving/index.ts -> src/ui/tui/programs/self-driving/content/pricing.ts", - "src/lib/task-stream/event-plan-watcher.ts -> src/ui/tui/store.ts", - "src/lib/task-stream/task-stream-push.ts -> src/ui/tui/store.ts", - "src/lib/wizard-tools/index.ts -> src/lib/wizard-tools/mcp.ts", - "src/lib/wizard-tools/tools.ts -> src/lib/yara-hooks.ts", - "src/steps/add-mcp-server-to-clients/index.ts -> src/telemetry.ts", - "src/steps/add-or-update-environment-variables.ts -> src/telemetry.ts", - "src/steps/run-prettier.ts -> src/telemetry.ts", - "src/steps/upload-environment-variables/index.ts -> src/telemetry.ts", - "src/ui/store-ui.ts -> src/ui/tui/store.ts", - "src/ui/tui/components/PhaseVisuals.tsx -> src/lib/agent/agent-phase.ts", - "src/ui/tui/playground/demos/RunScreenDemo.tsx -> src/lib/agent/agent-phase.ts", - "src/ui/tui/services/mcp-suggested-prompts-services.ts -> src/lib/agent/mcp-prompt-streaming.ts", - "src/utils/package-manager.ts -> src/telemetry.ts", - "src/utils/setup-utils.ts -> src/telemetry.ts" - ] -} diff --git a/src/__tests__/architecture/project-configs.test.ts b/src/__tests__/architecture/project-configs.test.ts new file mode 100644 index 000000000..7beb2a081 --- /dev/null +++ b/src/__tests__/architecture/project-configs.test.ts @@ -0,0 +1,72 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import { ALLOWED_IMPORTS, type Surface } from './import-boundaries.test.js'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(HERE, '../../..'); + +/** Compiler project per surface; env is the shared root file. */ +const PROJECTS: Record, string> = { + env: 'tsconfig.env.json', + store: 'src/store/tsconfig.json', + agent: 'src/agent/tsconfig.json', + tui: 'src/tui/tsconfig.json', + cli: 'src/cli/tsconfig.json', +}; + +function referencesOf(configRel: string): string[] { + const abs = path.join(REPO_ROOT, configRel); + const cfg = JSON.parse(fs.readFileSync(abs, 'utf8')) as { + references?: Array<{ path: string }>; + }; + return (cfg.references ?? []).map((r) => + path + .relative(REPO_ROOT, path.resolve(path.dirname(abs), r.path)) + .split(path.sep) + .join('/'), + ); +} + +function projectDir(configRel: string): string { + return configRel.endsWith('.json') && !configRel.includes('/') + ? configRel + : path.dirname(configRel); +} + +describe('tsconfig project references', () => { + it.each(Object.keys(PROJECTS) as Array)( + '%s references exactly the surfaces it may import', + (surface) => { + const expected = ALLOWED_IMPORTS[surface] + .filter((s) => s !== surface) + .map((s) => projectDir(PROJECTS[s as keyof typeof PROJECTS])) + .sort(); + expect(referencesOf(PROJECTS[surface]).sort()).toEqual(expected); + }, + ); + + it.each(['store', 'agent', 'tui', 'cli'] as const)( + '%s Vitest project resolves only the surfaces it may import', + (surface) => { + const text = fs.readFileSync( + path.join(REPO_ROOT, `src/${surface}/vitest.config.ts`), + 'utf8', + ); + const match = /imports:\s*\[([^\]]*)\]/.exec(text); + const imports = (match?.[1] ?? '') + .split(',') + .map((s) => s.trim().replace(/['"]/g, '')) + .filter(Boolean) + .sort(); + expect(imports).toEqual([...ALLOWED_IMPORTS[surface]].sort()); + }, + ); + + it('the solution lists every project', () => { + const refs = referencesOf('tsconfig.solution.json'); + for (const p of Object.values(PROJECTS)) { + expect(refs).toContain(projectDir(p)); + } + }); +}); diff --git a/src/__tests__/architecture/shape-files.test.ts b/src/__tests__/architecture/shape-files.test.ts new file mode 100644 index 000000000..83edacbfe --- /dev/null +++ b/src/__tests__/architecture/shape-files.test.ts @@ -0,0 +1,41 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(HERE, '../../..'); + +const SHAPE_FILES = [ + 'src/store/types.ts', + 'src/agent/types.ts', + 'src/tui/types.ts', + 'src/cli/types.ts', +]; + +/** Every import or export with a module specifier, with its leading keywords. */ +function moduleStatements(source: string): string[] { + return [ + ...source.matchAll(/^(import|export)\b[^;]*?\bfrom\s*['"][^'"]+['"]/gm), + ].map((m) => m[0].replace(/\s+/g, ' ')); +} + +describe('shape files', () => { + it.each(SHAPE_FILES)('%s has zero runtime imports', (file) => { + const source = fs.readFileSync(path.join(REPO_ROOT, file), 'utf8'); + const runtime = moduleStatements(source).filter( + (s) => !/^(import|export) type\b/.test(s), + ); + expect(runtime).toEqual([]); + }); + + it.each(SHAPE_FILES)('%s imports only shape files and @env', (file) => { + const source = fs.readFileSync(path.join(REPO_ROOT, file), 'utf8'); + const own = file.split('/')[1]; + const foreign = [...source.matchAll(/from\s*['"]([^'"]+)['"]/g)] + .map((m) => m[1]) + .filter((spec) => !spec.startsWith('.')) + .filter((spec) => spec !== '@env' && spec !== `@${own}/types`) + .filter((spec) => !/^@(store|agent|tui)\/types$/.test(spec)); + expect(foreign).toEqual([]); + }); +}); diff --git a/src/__tests__/architecture/startup-graph.test.ts b/src/__tests__/architecture/startup-graph.test.ts new file mode 100644 index 000000000..b9421600d --- /dev/null +++ b/src/__tests__/architecture/startup-graph.test.ts @@ -0,0 +1,106 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(HERE, '../../..'); + +const STATIC_IMPORT = + /^\s*(?:import|export)\s+(?:type\s+)?[^'"]*?from\s*['"]([^'"]+)['"]/gm; +const BARE_IMPORT = /^\s*import\s*['"]([^'"]+)['"]/gm; + +const ALIASES: ReadonlyArray = [ + [/^@env$/, 'src/env.ts'], + [/^@store$/, 'src/store/index.ts'], + [/^@store\/types$/, 'src/store/types.ts'], + [/^@store\/programs$/, 'src/store/programs/index.ts'], + [/^@agent$/, 'src/agent/index.ts'], + [/^@agent\/types$/, 'src/agent/types.ts'], + [/^@tui$/, 'src/tui/index.ts'], + [/^@tui\/types$/, 'src/tui/types.ts'], + [/^@tui\/console$/, 'src/tui/console/index.ts'], + [/^@(store|agent|tui|cli)\/(.+)$/, 'src/$1/$2'], +]; + +function resolveFile(spec: string, from: string): string | null { + let base: string | null = null; + if (spec.startsWith('.')) base = path.resolve(path.dirname(from), spec); + else { + for (const [pattern, target] of ALIASES) { + if (pattern.test(spec)) { + base = path.join(REPO_ROOT, spec.replace(pattern, target)); + break; + } + } + } + if (base === null) return null; + const stem = base.replace(/\.js$/, ''); + for (const candidate of [ + `${stem}.ts`, + `${stem}.tsx`, + path.join(stem, 'index.ts'), + path.join(stem, 'index.tsx'), + base, + ]) { + if (fs.statSync(candidate, { throwIfNoEntry: false })?.isFile()) + return candidate; + } + return null; +} + +/** Static import closure: every module Node evaluates before main.ts runs. */ +function staticClosure(entry: string): { + files: Set; + packages: Set; +} { + const files = new Set(); + const packages = new Set(); + const queue = [path.join(REPO_ROOT, entry)]; + while (queue.length) { + const file = queue.pop(); + if (!file || files.has(file)) continue; + files.add(file); + const text = fs.readFileSync(file, 'utf8'); + // Type-only imports are erased; they never load a module. + const specs = [...text.matchAll(STATIC_IMPORT)] + .filter((m) => !/^\s*(import|export)\s+type\b/.test(m[0])) + .map((m) => m[1]) + .concat([...text.matchAll(BARE_IMPORT)].map((m) => m[1])); + for (const spec of specs) { + const resolved = resolveFile(spec, file); + if (resolved) queue.push(resolved); + else if (!spec.startsWith('.')) packages.add(spec); + } + } + return { files, packages }; +} + +const closure = staticClosure('src/cli/main.ts'); +const rel = (abs: string) => + path.relative(REPO_ROOT, abs).split(path.sep).join('/'); + +describe('cli startup graph', () => { + it('reaches the tui only through its Ink-free console renderers', () => { + const tui = [...closure.files] + .map(rel) + .filter( + (f) => f.startsWith('src/tui/') && !f.startsWith('src/tui/console/'), + ); + expect(tui).toEqual([]); + }); + + it('loads neither Ink nor React before a command runs', () => { + const ui = [...closure.packages].filter( + (p) => + ['ink', 'react', '@inkjs/ui'].includes(p) || p.startsWith('react/'), + ); + expect(ui).toEqual([]); + }); + + it('does not load the agent runner before a command runs', () => { + const agent = [...closure.files] + .map(rel) + .filter((f) => f.startsWith('src/agent/')); + expect(agent).toEqual([]); + }); +}); diff --git a/src/__tests__/architecture/store-boundary-members.test.ts b/src/__tests__/architecture/store-boundary-members.test.ts new file mode 100644 index 000000000..cf6f74cef --- /dev/null +++ b/src/__tests__/architecture/store-boundary-members.test.ts @@ -0,0 +1,62 @@ +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import * as ts from 'typescript'; +import { STORE_BOUNDARY_MEMBERS } from '@store'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(HERE, '../../..'); +const CONSUMER = /\/(src\/(tui|cli)|e2e-harness|scripts)\/|\/bin\.ts$/; + +/** Every WizardStore member the other surfaces reach, from the type checker. */ +function usedMembers(): string[] { + const cfg = ts.getParsedCommandLineOfConfigFile( + path.join(REPO_ROOT, 'tsconfig.json'), + {}, + { + ...ts.sys, + onUnRecoverableConfigFileDiagnostic: (d) => { + throw new Error(ts.flattenDiagnosticMessageText(d.messageText, '\n')); + }, + }, + ); + if (!cfg) throw new Error('tsconfig.json did not parse'); + const roots = cfg.fileNames.filter( + (f) => CONSUMER.test(f) && !/__tests__|\.test\.tsx?$/.test(f), + ); + const program = ts.createProgram(roots, cfg.options); + const checker = program.getTypeChecker(); + const rootSet = new Set(roots); + const used = new Set(); + + const isStore = (node: ts.Node): boolean => { + const type = checker.getTypeAtLocation(node); + const parts = type.isUnion() ? type.types : [type]; + return parts.some((t) => t.getSymbol()?.getName() === 'WizardStore'); + }; + const visit = (node: ts.Node): void => { + if (ts.isPropertyAccessExpression(node) && isStore(node.expression)) { + used.add(node.name.text); + } else if ( + ts.isVariableDeclaration(node) && + node.initializer && + ts.isObjectBindingPattern(node.name) && + isStore(node.initializer) + ) { + for (const el of node.name.elements) { + const key = el.propertyName ?? el.name; + if (ts.isIdentifier(key)) used.add(key.text); + } + } + ts.forEachChild(node, visit); + }; + for (const sf of program.getSourceFiles()) { + if (rootSet.has(sf.fileName)) visit(sf); + } + return [...used].sort(); +} + +describe('WizardStore boundary', () => { + it('STORE_BOUNDARY_MEMBERS is exactly what tui, cli, and the harness use', () => { + expect(usedMembers()).toEqual([...STORE_BOUNDARY_MEMBERS].sort()); + }, 120_000); +}); diff --git a/src/__tests__/architecture/tsconfig.json b/src/__tests__/architecture/tsconfig.json new file mode 100644 index 000000000..e7f4e4a18 --- /dev/null +++ b/src/__tests__/architecture/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../../.tsbuild/architecture" + }, + "include": ["**/*", "../../../types/**/*.d.ts"], + "references": [ + { + "path": "../../../tsconfig.env.json" + }, + { + "path": "../../store" + } + ], + "exclude": ["vitest.config.ts"] +} diff --git a/src/__tests__/architecture/vitest.config.ts b/src/__tests__/architecture/vitest.config.ts new file mode 100644 index 000000000..659d4e7fb --- /dev/null +++ b/src/__tests__/architecture/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineProject } from 'vitest/config'; +import { surfaceProject } from '../../../vitest.shared.js'; + +export default defineProject( + surfaceProject({ + name: 'architecture', + imports: ['env', 'store'], + ink: 'forbidden', + include: ['**/*.test.ts'], + }), +); diff --git a/src/agent/README.md b/src/agent/README.md new file mode 100644 index 000000000..7a189021a --- /dev/null +++ b/src/agent/README.md @@ -0,0 +1,33 @@ +# agent + +Runs exactly one independent agent run per `runAgent` call. + +## Owns + +- `runner/`: bootstrap, switchboard, sequences (linear, orchestrator), + harnesses. +- `gateway/`: gateway session and mint. `middleware/`: run middleware. +- `tools/`: MCP facade over the store's tool behavior. +- `detection/`: the agentic detection run the store's contract asks for. +- Prompt assembly, output signals, security adapters. + +## Never contains + +Ink, screens, program definitions, or session mutation outside `WizardUI`. + +## May import + +`@env`, `@store`, `@store/types`, `@store/programs`, and its own files. + +## Public entries + +`index.ts` (`runAgent`, `detectProjectsWithAgent`, `runMcpPromptViaSdk`, +`configureGatewayFromCIEnvironment`) and `types.ts`. + +## Tests + +`pnpm test:agent` and `pnpm typecheck:agent`. `vitest.config.ts` resolves +`@env`, `@store`, and `@agent`; `ink` throws. `testing/fake-harness.ts` records +run and task inputs behind the `AgentHarness` interface. +`__tests__/contract.test.ts` pins that both harnesses and the fake implement +`AgentHarness` and that `runAgent` is the `RunAgent` entry the cli calls. diff --git a/src/lib/agent/__tests__/__snapshots__/commandments.test.ts.snap b/src/agent/__tests__/__snapshots__/commandments.test.ts.snap similarity index 100% rename from src/lib/agent/__tests__/__snapshots__/commandments.test.ts.snap rename to src/agent/__tests__/__snapshots__/commandments.test.ts.snap diff --git a/src/lib/__tests__/agent-interface.test.ts b/src/agent/__tests__/agent-interface.test.ts similarity index 97% rename from src/lib/__tests__/agent-interface.test.ts rename to src/agent/__tests__/agent-interface.test.ts index 181382b56..15f67cae7 100644 --- a/src/lib/__tests__/agent-interface.test.ts +++ b/src/agent/__tests__/agent-interface.test.ts @@ -8,25 +8,25 @@ import { buildAuthErrorContext, buildAgentEnv, reportMcpSetup, -} from '@lib/agent/agent-interface'; -import { AgentOutputSignals } from '@lib/agent/output-signals'; -import { RESUME_INSTRUCTION } from '@lib/agent-signals'; -import { analytics } from '@utils/analytics'; -import { wizardAbort } from '@utils/wizard-abort'; -import { Sequence } from '@lib/constants'; -import type { WizardRunOptions } from '@utils/types'; -import type { SpinnerHandle } from '@ui'; +} from '../agent-interface.js'; +import { AgentOutputSignals } from '../output-signals.js'; +import { RESUME_INSTRUCTION } from '@store/agent-protocol/agent-signals'; +import { analytics } from '@store/shared/analytics'; +import { wizardAbort } from '@store/shared/wizard-abort'; +import { Sequence } from '@store/shared/constants'; +import type { WizardRunOptions } from '@store/shared/types'; +import type { SpinnerHandle } from '@store/ui'; import { AdditionalFeature, ADDITIONAL_FEATURE_PROMPTS, -} from '@lib/wizard-session'; +} from '@store/session/wizard-session'; // Mock dependencies -vi.mock('../../utils/analytics'); -vi.mock('../../utils/debug'); +vi.mock('@store/shared/analytics'); +vi.mock('@store/shared/debug'); // wizardAbort exits the process; the 401 tests below need it to just reject. -vi.mock('@utils/wizard-abort', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/wizard-abort', async (importOriginal) => ({ + ...(await importOriginal()), wizardAbort: vi.fn(), })); @@ -69,7 +69,7 @@ const mockUIInstance = { addTokenUsage: vi.fn(), setFinalTokenCostUsd: vi.fn(), }; -vi.mock('../../ui', () => ({ +vi.mock('@store/ui', () => ({ getUI: () => mockUIInstance, })); diff --git a/src/lib/agent/__tests__/agent-prompt-loader.test.ts b/src/agent/__tests__/agent-prompt-loader.test.ts similarity index 99% rename from src/lib/agent/__tests__/agent-prompt-loader.test.ts rename to src/agent/__tests__/agent-prompt-loader.test.ts index ab23e6a49..d7d7581ee 100644 --- a/src/lib/agent/__tests__/agent-prompt-loader.test.ts +++ b/src/agent/__tests__/agent-prompt-loader.test.ts @@ -16,9 +16,9 @@ import { type AgentPrompt, type AgentRegistry, type OrchestratorPromptContext, -} from '../agent-prompt-loader'; -import { QueueStore } from '@lib/agent/runner/sequence/orchestrator/queue'; -import { HostResolution } from '@lib/host-resolution'; +} from '../agent-prompt-loader.js'; +import { QueueStore } from '../runner/sequence/orchestrator/queue.js'; +import { HostResolution } from '@store/host-resolution'; function tmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'agent-loader-test-')); diff --git a/src/lib/agent/__tests__/agent-prompt.test.ts b/src/agent/__tests__/agent-prompt.test.ts similarity index 91% rename from src/lib/agent/__tests__/agent-prompt.test.ts rename to src/agent/__tests__/agent-prompt.test.ts index 2ee6bfdb9..69b580b67 100644 --- a/src/lib/agent/__tests__/agent-prompt.test.ts +++ b/src/agent/__tests__/agent-prompt.test.ts @@ -1,6 +1,6 @@ -import { assemblePrompt, type PromptContext } from '@lib/agent/agent-prompt'; -import type { ProgramRun } from '@lib/agent/agent-runner'; -import { HostResolution } from '@lib/host-resolution'; +import { assemblePrompt, type PromptContext } from '../agent-prompt.js'; +import type { ProgramRun } from '@store/types'; +import { HostResolution } from '@store/host-resolution'; function makeRunDef(overrides: Partial = {}): ProgramRun { return { diff --git a/src/lib/agent/__tests__/aio-capture.test.ts b/src/agent/__tests__/aio-capture.test.ts similarity index 99% rename from src/lib/agent/__tests__/aio-capture.test.ts rename to src/agent/__tests__/aio-capture.test.ts index 042f1e2d3..e883219aa 100644 --- a/src/lib/agent/__tests__/aio-capture.test.ts +++ b/src/agent/__tests__/aio-capture.test.ts @@ -1,4 +1,4 @@ -import { createAioCapture } from '@lib/agent/aio-capture'; +import { createAioCapture } from '../aio-capture.js'; const RUN_TAGS = { program_id: 'posthog-integration', diff --git a/src/agent/__tests__/auth-error-context.test.ts b/src/agent/__tests__/auth-error-context.test.ts new file mode 100644 index 000000000..580a5b4b5 --- /dev/null +++ b/src/agent/__tests__/auth-error-context.test.ts @@ -0,0 +1,75 @@ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('@store/shared/analytics', () => ({ + analytics: { captureException: vi.fn(), wizardCapture: vi.fn() }, +})); + +import { buildAuthErrorContext } from '../agent-interface.js'; + +let home: string; +let project: string; + +function write(dir: string, name: string, contents: string): void { + const claudeDir = path.join(dir, '.claude'); + fs.mkdirSync(claudeDir, { recursive: true }); + fs.writeFileSync(path.join(claudeDir, name), contents); +} + +beforeEach(() => { + home = fs.mkdtempSync(path.join(os.tmpdir(), 'wizard-home-')); + project = fs.mkdtempSync(path.join(os.tmpdir(), 'wizard-proj-')); +}); + +afterEach(() => { + fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(project, { recursive: true, force: true }); +}); + +describe('buildAuthErrorContext', () => { + it('reports no conflict and a default region when nothing overrides auth', () => { + const ctx = buildAuthErrorContext( + project, + 'https://ai-gateway.us.posthog.com', + home, + ); + + expect(ctx.hasSettingsConflict).toBe(false); + expect(ctx.conflicts).toEqual([]); + expect(ctx.conflictSources).toEqual([]); + expect(ctx.conflictKeys).toEqual([]); + expect(ctx.region).toBe('us'); + }); + + it('summarises conflicts and dedupes keys for telemetry', () => { + write(home, 'settings.json', JSON.stringify({ apiKeyHelper: 'x' })); + write(project, 'settings.json', JSON.stringify({ apiKeyHelper: 'y' })); + + const ctx = buildAuthErrorContext( + project, + 'https://ai-gateway.eu.posthog.com', + home, + ); + + expect(ctx.hasSettingsConflict).toBe(true); + expect(ctx.conflictSources).toEqual( + expect.arrayContaining(['user', 'project']), + ); + expect(ctx.conflictKeys).toEqual(['apiKeyHelper']); + expect(ctx.region).toBe('eu'); + }); + + it('derives the region from the gateway url', () => { + expect( + buildAuthErrorContext(project, 'https://ai-gateway.eu.posthog.com', home) + .region, + ).toBe('eu'); + expect( + buildAuthErrorContext(project, 'http://localhost:3308/wizard', home) + .region, + ).toBe('local'); + expect(buildAuthErrorContext(project, '', home).region).toBe('us'); + }); +}); diff --git a/src/lib/agent/__tests__/bash-fence-python.test.ts b/src/agent/__tests__/bash-fence-python.test.ts similarity index 98% rename from src/lib/agent/__tests__/bash-fence-python.test.ts rename to src/agent/__tests__/bash-fence-python.test.ts index 1a45587a4..a6023537d 100644 --- a/src/lib/agent/__tests__/bash-fence-python.test.ts +++ b/src/agent/__tests__/bash-fence-python.test.ts @@ -1,4 +1,4 @@ -import { evaluateBashCommand } from '@lib/agent/bash-fence'; +import { evaluateBashCommand } from '../bash-fence.js'; /** * The fence and the pi runtime notes have to agree: the notes tell the agent to diff --git a/src/lib/agent/__tests__/commandments.test.ts b/src/agent/__tests__/commandments.test.ts similarity index 96% rename from src/lib/agent/__tests__/commandments.test.ts rename to src/agent/__tests__/commandments.test.ts index b00a74a4f..79cafefda 100644 --- a/src/lib/agent/__tests__/commandments.test.ts +++ b/src/agent/__tests__/commandments.test.ts @@ -1,6 +1,6 @@ -import { WIZARD_COMMANDMENTS } from '@lib/agent/commandments'; -import { assembleCommandments } from '@lib/agent/runner/switchboard/commandments'; -import { Harness, Sequence } from '@lib/constants'; +import { WIZARD_COMMANDMENTS } from '../commandments.js'; +import { assembleCommandments } from '../runner/switchboard/commandments.js'; +import { Harness, Sequence } from '@store/shared/constants'; const global = WIZARD_COMMANDMENTS.join('\n'); diff --git a/src/agent/__tests__/contract.test.ts b/src/agent/__tests__/contract.test.ts new file mode 100644 index 000000000..1c4410e20 --- /dev/null +++ b/src/agent/__tests__/contract.test.ts @@ -0,0 +1,31 @@ +import { expectTypeOf } from 'vitest'; +import { anthropicBackend } from '../runner/harness/anthropic/index.js'; +import { piBackend } from '../runner/harness/pi/index.js'; +import type { AgentHarness } from '../runner/harness/types.js'; +import { runAgent } from '../runner/index.js'; +import { FakeAgentHarness } from '../testing/fake-harness.js'; +import type { RunAgent } from '../types.js'; + +describe('agent contract', () => { + it('both harnesses and the fake implement AgentHarness', () => { + expectTypeOf(piBackend).toMatchTypeOf(); + expectTypeOf(anthropicBackend).toMatchTypeOf(); + expectTypeOf().toMatchTypeOf(); + expect(piBackend.name).not.toBe(anthropicBackend.name); + }); + + it('runAgent is the surface entry the cli calls', () => { + expectTypeOf(runAgent).toEqualTypeOf(); + }); + + it('the fake records one independent run per call', async () => { + const fake = new FakeAgentHarness(piBackend.name, { error: undefined }); + const inputs = { marker: 'a' } as unknown as Parameters< + AgentHarness['run'] + >[0]; + await fake.run(inputs); + await fake.run(inputs); + expect(fake.runs).toHaveLength(2); + expect(fake.tasks).toHaveLength(0); + }); +}); diff --git a/src/lib/__tests__/gateway-session.test.ts b/src/agent/__tests__/gateway-session.test.ts similarity index 96% rename from src/lib/__tests__/gateway-session.test.ts rename to src/agent/__tests__/gateway-session.test.ts index ce0966fc5..076e58626 100644 --- a/src/lib/__tests__/gateway-session.test.ts +++ b/src/agent/__tests__/gateway-session.test.ts @@ -9,24 +9,25 @@ import { isPastRefresh, isTrustedGatewayUrl, resetGatewaySession, -} from '@lib/gateway-session'; -import type { HostResolution } from '@lib/host-resolution'; -import { ErrorCodes } from '@lib/errors'; -import { WizardError } from '@utils/wizard-abort'; -import { analytics } from '@utils/analytics'; -import { logToFile } from '@utils/debug'; -import { checkLlmGatewayHealth } from '@lib/health-checks/endpoints'; -import { ServiceHealthStatus } from '@lib/health-checks/types'; - -vi.mock('@lib/health-checks/endpoints', () => ({ +} from '../gateway/gateway-session.js'; +import type { HostResolution } from '@store/host-resolution'; +import { ErrorCodes } from '@store/shared/errors'; +import { classifyRunFailure } from '@store/shared/errors/run-failure'; +import { WizardError } from '@store/shared/wizard-abort'; +import { analytics } from '@store/shared/analytics'; +import { logToFile } from '@store/shared/debug'; +import { checkLlmGatewayHealth } from '@store/health-checks/endpoints'; +import { ServiceHealthStatus } from '@store/health-checks/types'; + +vi.mock('@store/health-checks/endpoints', () => ({ checkLlmGatewayHealth: vi.fn(), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); -vi.mock('@utils/debug', () => ({ logToFile: vi.fn() })); +vi.mock('@store/shared/debug', () => ({ logToFile: vi.fn() })); // logToFile is variadic, so a leak in any argument is a leak. Rendered every way the // sink might: JSON (which invokes getters and toJSON), an Error's stack, and inspect. @@ -120,7 +121,7 @@ describe('gatewayAuth', () => { vi.stubEnv('NODE_ENV', 'production'); vi.resetModules(); try { - const prod = await import('@lib/gateway-session'); + const prod = await import('../gateway/gateway-session.js'); expect(() => prod.configureGatewayCredentialsForCI( 'token', @@ -869,3 +870,17 @@ describe('isTrustedGatewayUrl', () => { ).toBe(true); }); }); + +describe('GatewayMintRefused', () => { + it('classifies as its own coded run failure', () => { + expect( + classifyRunFailure( + new GatewayMintRefused(403, 'This account is blocked.', 'blocked'), + ), + ).toEqual({ + code: ErrorCodes.GatewayMintRefused, + message: 'This account is blocked.', + coded: true, + }); + }); +}); diff --git a/src/lib/agent/__tests__/output-signals.test.ts b/src/agent/__tests__/output-signals.test.ts similarity index 97% rename from src/lib/agent/__tests__/output-signals.test.ts rename to src/agent/__tests__/output-signals.test.ts index cb6870e66..476b432ff 100644 --- a/src/lib/agent/__tests__/output-signals.test.ts +++ b/src/agent/__tests__/output-signals.test.ts @@ -1,5 +1,8 @@ -import { AgentOutputSignals } from '@lib/agent/output-signals'; -import { AgentSignals, REMARK_INSTRUCTION } from '@lib/agent-signals'; +import { AgentOutputSignals } from '../output-signals.js'; +import { + AgentSignals, + REMARK_INSTRUCTION, +} from '@store/agent-protocol/agent-signals'; describe('REMARK_INSTRUCTION', () => { it('carries the marker but no literal placeholder a model could echo', () => { diff --git a/src/lib/agent/__tests__/run-tags.test.ts b/src/agent/__tests__/run-tags.test.ts similarity index 94% rename from src/lib/agent/__tests__/run-tags.test.ts rename to src/agent/__tests__/run-tags.test.ts index b255653f7..b7744359b 100644 --- a/src/lib/agent/__tests__/run-tags.test.ts +++ b/src/agent/__tests__/run-tags.test.ts @@ -1,5 +1,5 @@ -import { buildRunTags } from '@lib/agent/agent-interface'; -import { CallType } from '@lib/constants'; +import { buildRunTags } from '../agent-interface.js'; +import { CallType } from '@store/shared/constants'; describe('buildRunTags', () => { it('carries the run identifiers as gateway trace tags', () => { diff --git a/src/lib/agent/__tests__/stored-login.test.ts b/src/agent/__tests__/stored-login.test.ts similarity index 98% rename from src/lib/agent/__tests__/stored-login.test.ts rename to src/agent/__tests__/stored-login.test.ts index 6ef5b14e8..4494b39ee 100644 --- a/src/lib/agent/__tests__/stored-login.test.ts +++ b/src/agent/__tests__/stored-login.test.ts @@ -6,10 +6,10 @@ import { createIsolatedAgentConfigDir, detectStoredClaudeLogin, hasStoredClaudeLogin, -} from '../stored-login'; +} from '../stored-login.js'; vi.mock('node:child_process', () => ({ spawnSync: vi.fn() })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); diff --git a/src/lib/agent/__tests__/triage-provider.test.ts b/src/agent/__tests__/triage-provider.test.ts similarity index 96% rename from src/lib/agent/__tests__/triage-provider.test.ts rename to src/agent/__tests__/triage-provider.test.ts index d51d82b9e..19e2aee1f 100644 --- a/src/lib/agent/__tests__/triage-provider.test.ts +++ b/src/agent/__tests__/triage-provider.test.ts @@ -1,12 +1,12 @@ import { completeSimple } from '@earendil-works/pi-ai'; -import { createTriageLLMProvider } from '@lib/agent/triage-provider'; +import { createTriageLLMProvider } from '../triage-provider.js'; import { CallType, GPT5_6_LUNA_MODEL, HAIKU_TRIAGE_MODEL, Harness, -} from '@lib/constants'; -import { triageModelFor } from '@lib/agent/runner/switchboard/models'; +} from '@store/shared/constants'; +import { triageModelFor } from '../runner/switchboard/models.js'; vi.mock('@earendil-works/pi-ai', () => ({ completeSimple: vi.fn() })); const complete = vi.mocked(completeSimple); diff --git a/src/lib/agent/__tests__/tutorial-run-tags.test.ts b/src/agent/__tests__/tutorial-run-tags.test.ts similarity index 92% rename from src/lib/agent/__tests__/tutorial-run-tags.test.ts rename to src/agent/__tests__/tutorial-run-tags.test.ts index e0d2c2b3f..07ffe5fdd 100644 --- a/src/lib/agent/__tests__/tutorial-run-tags.test.ts +++ b/src/agent/__tests__/tutorial-run-tags.test.ts @@ -7,9 +7,9 @@ * tests pin the tags so that can't silently return. */ -import { buildTutorialRunTags } from '@lib/agent/mcp-prompt-streaming'; -import { buildAgentEnv } from '@lib/agent/agent-interface'; -import { analytics } from '@utils/analytics'; +import { buildTutorialRunTags } from '../mcp-prompt-streaming.js'; +import { buildAgentEnv } from '../agent-interface.js'; +import { analytics } from '@store/shared/analytics'; describe('buildTutorialRunTags', () => { it('tags the run with the program its spend belongs to', () => { diff --git a/src/lib/agent/__tests__/variant-gating.test.ts b/src/agent/__tests__/variant-gating.test.ts similarity index 88% rename from src/lib/agent/__tests__/variant-gating.test.ts rename to src/agent/__tests__/variant-gating.test.ts index 1734e1446..13561aa74 100644 --- a/src/lib/agent/__tests__/variant-gating.test.ts +++ b/src/agent/__tests__/variant-gating.test.ts @@ -1,4 +1,4 @@ -import { isOrchestratorEnabled } from '@lib/agent/runner/switchboard'; +import { isOrchestratorEnabled } from '../runner/switchboard/index.js'; describe('isOrchestratorEnabled', () => { it('is true only when the wizard-orchestrator flag is true', () => { diff --git a/src/lib/__tests__/wizard-can-use-tool.test.ts b/src/agent/__tests__/wizard-can-use-tool.test.ts similarity index 99% rename from src/lib/__tests__/wizard-can-use-tool.test.ts rename to src/agent/__tests__/wizard-can-use-tool.test.ts index 26272ea66..9f23681fc 100644 --- a/src/lib/__tests__/wizard-can-use-tool.test.ts +++ b/src/agent/__tests__/wizard-can-use-tool.test.ts @@ -1,11 +1,11 @@ -import { wizardCanUseTool } from '@lib/agent/agent-interface'; +import { wizardCanUseTool } from '../agent-interface.js'; -vi.mock('../../utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), }, })); -vi.mock('../../utils/debug'); +vi.mock('@store/shared/debug'); describe('wizardCanUseTool — wizard_ask pending guard', () => { for (const tool of ['Write', 'Edit'] as const) { diff --git a/src/lib/agent/agent-interface.ts b/src/agent/agent-interface.ts similarity index 97% rename from src/lib/agent/agent-interface.ts rename to src/agent/agent-interface.ts index cd41e82b4..7d7ea8683 100644 --- a/src/lib/agent/agent-interface.ts +++ b/src/agent/agent-interface.ts @@ -6,15 +6,14 @@ import path from 'path'; import * as os from 'os'; import { createRequire } from 'node:module'; -import { getUI, type SpinnerHandle } from '@ui'; -import type { TokenUsageDelta } from '@ui/wizard-ui'; -import { debug, logToFile, initLogFile, getLogFilePath } from '@utils/debug'; -import type { WizardRunOptions } from '@utils/types'; -import { analytics } from '@utils/analytics'; -import { isTemplateEnvFileName } from '@utils/env-scan'; -import { runtimeEnv } from '@env'; -import type { AioCapture } from '@lib/agent/aio-capture'; import { + getUI, + debug, + logToFile, + initLogFile, + getLogFilePath, + analytics, + isTemplateEnvFileName, Harness, CallType, Sequence, @@ -22,59 +21,60 @@ import { wizardUserAgentForProgram, DEFAULT_AGENT_MODEL, AWS_SKILLS_BASE_URL, -} from '@lib/constants'; -import { - type AdditionalFeature, ADDITIONAL_FEATURE_PROMPTS, -} from '@lib/wizard-session'; -import { wizardAbort, WizardError } from '@utils/wizard-abort'; -import { createCustomHeaders } from '@utils/custom-headers'; -import type { HostResolution } from '@lib/host-resolution'; -import { - buildWizardPropertiesBlob, - gatewayAuth, - isPastRefresh, - type GatewayAuth, -} from '@lib/gateway-session'; -import { evaluateBashCommand } from './bash-fence'; -import { createWizardToolsServer, WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import { + wizardAbort, + WizardError, + createCustomHeaders, + WIZARD_TOOL_NAMES, createPreToolUseYaraHooks, createPostToolUseYaraHooks, prewarmYaraScanner, -} from '@lib/yara-hooks'; -import { createTriageLLMProvider } from './triage-provider'; -import type { LLMProvider } from '@posthog/warlock'; -import { assembleCommandments } from './runner/switchboard/commandments'; -import { classifyToolToStage } from './agent-phase'; -import type { PackageManagerDetector } from '@lib/detection/package-manager'; -import { + classifyToolToStage, AgentSignals, AgentErrorType, REMARK_INSTRUCTION, RESUME_INSTRUCTION, -} from '@lib/agent-signals'; -import { classifyAuthFailure } from '@lib/errors'; -import { isGrantRevoked } from '@lib/auth-session-state'; -import { AgentOutputSignals } from './output-signals'; + classifyAuthFailure, + isGrantRevoked, + checkAllSettingsConflicts, + sanitizeAgentSubprocessEnv, +} from '@store'; +import type { + SpinnerHandle, + TokenUsageDelta, + WizardRunOptions, + AdditionalFeature, + HostResolution, + PackageManagerDetector, + SettingsConflict, + SettingsConflictSource, +} from '@store/types'; +import { runtimeEnv } from '@env'; +import type { AioCapture } from './aio-capture.js'; +import { + buildWizardPropertiesBlob, + gatewayAuth, + isPastRefresh, + type GatewayAuth, +} from './gateway/gateway-session.js'; +import { evaluateBashCommand } from './bash-fence.js'; +import { createWizardToolsServer } from './tools/mcp.js'; +import { createTriageLLMProvider } from './triage-provider.js'; +import type { LLMProvider } from '@posthog/warlock'; +import { assembleCommandments } from './runner/switchboard/commandments.js'; +import { AgentOutputSignals } from './output-signals.js'; // Signal vocabulary and the output parser live in dedicated modules; re-export // so existing importers of these from agent-interface keep working. -export { AgentSignals, AgentErrorType } from '@lib/agent-signals'; -export type { AgentSignal } from '@lib/agent-signals'; -export { AgentOutputSignals } from './output-signals'; -import { - checkAllSettingsConflicts, - type SettingsConflict, - type SettingsConflictSource, -} from '@lib/claude-settings'; +export { AgentSignals, AgentErrorType } from '@store'; +export type { AgentSignal } from '@store/types'; +export { AgentOutputSignals } from './output-signals.js'; import { detectStoredClaudeLogin, hasStoredClaudeLogin, claudeConfigDir, createIsolatedAgentConfigDir, -} from './stored-login'; -import { sanitizeAgentSubprocessEnv } from '@lib/agent-env-isolation'; +} from './stored-login.js'; // Dynamic import cache for ESM module let _sdkModule: any = null; @@ -217,7 +217,7 @@ export type AgentConfig = { */ modelOverride?: string; /** Bridge that drives the `wizard_ask` overlay. Omit in non-interactive hosts. */ - askBridge?: import('@lib/wizard-ask-bridge').WizardAskBridge; + askBridge?: import('@store/types').WizardAskBridge; /** Per-run cap on `wizard_ask` invocations. Defaults to 10. */ askMaxQuestions?: number; /** Extra tools added on top of BASE_ALLOWED_TOOLS for this run. */ @@ -228,15 +228,13 @@ export type AgentConfig = { * Read accessor for the active pending question. Used by canUseTool to * block Write/Edit while the overlay is open (defense in depth). */ - getPendingQuestion?: () => - | import('@lib/wizard-session').PendingQuestion - | null; + getPendingQuestion?: () => import('@store/types').PendingQuestion | null; /** * Orchestrator queue context. Present only when the `wizard-orchestrator` * flag routes the run here; threaded into wizard-tools so the orchestrator * tools register. */ - orchestrator?: import('@lib/agent/runner/sequence/orchestrator/queue-tools').OrchestratorToolsContext; + orchestrator?: import('./runner/sequence/orchestrator/queue-tools.js').OrchestratorToolsContext; /** * Optional AIO capture — mirrors each assistant SDK message into the * authenticated project as `$ai_generation`. No-op instance when @@ -328,9 +326,7 @@ type AgentRunConfig = { * Read accessor for the active pending question. canUseTool reads this * to block Write/Edit while the overlay is open. */ - getPendingQuestion?: () => - | import('@lib/wizard-session').PendingQuestion - | null; + getPendingQuestion?: () => import('@store/types').PendingQuestion | null; /** * The orchestrator owns the TUI task panel (it renders its queue), so its * runs suppress the agent's own TaskCreate/TaskUpdate rendering. Set from @@ -414,7 +410,7 @@ export function buildAgentEnv( } // Re-export for backwards compatibility — canonical source is skill-install.ts -export { isSkillInstallCommand } from '@lib/skill-install'; +export { isSkillInstallCommand } from '@store'; /** * Permission hook that allows only safe commands. Bash commands are gated by diff --git a/src/lib/agent/agent-prompt-loader.ts b/src/agent/agent-prompt-loader.ts similarity index 98% rename from src/lib/agent/agent-prompt-loader.ts rename to src/agent/agent-prompt-loader.ts index c69d8fc87..b74023baa 100644 --- a/src/lib/agent/agent-prompt-loader.ts +++ b/src/agent/agent-prompt-loader.ts @@ -18,17 +18,19 @@ import type { QueueStore, QueuedTask, -} from './runner/sequence/orchestrator/queue'; -import type { ResolvedTask } from './runner/sequence/orchestrator/executor'; -import type { HostResolution } from '@lib/host-resolution'; +} from './runner/sequence/orchestrator/queue.js'; +import type { ResolvedTask } from './runner/sequence/orchestrator/executor.js'; +import type { HostResolution } from '@store/types'; import { isThinkingLevel, type ThinkingLevel, -} from './runner/switchboard/models'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; -import { fetchWithRetry } from '@lib/fetch-retry'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools/tools'; +} from './runner/switchboard/models.js'; +import { + logToFile, + analytics, + fetchWithRetry, + WIZARD_TOOL_NAMES, +} from '@store'; /** * The basics the client injects around every agent-prompt body. The `/agents/` diff --git a/src/lib/agent/agent-prompt.ts b/src/agent/agent-prompt.ts similarity index 96% rename from src/lib/agent/agent-prompt.ts rename to src/agent/agent-prompt.ts index 8e684322b..3ffe7dbb5 100644 --- a/src/lib/agent/agent-prompt.ts +++ b/src/agent/agent-prompt.ts @@ -7,7 +7,7 @@ * 3. Skill prompt — "follow SKILL.md" instructions (if a skill was installed) */ -import type { ProgramRun, PromptContext } from '@lib/program-run'; +import type { ProgramRun, PromptContext } from '@store/types'; export type { PromptContext }; diff --git a/src/lib/agent/aio-capture.ts b/src/agent/aio-capture.ts similarity index 99% rename from src/lib/agent/aio-capture.ts rename to src/agent/aio-capture.ts index ad37d252f..45f834c47 100644 --- a/src/lib/agent/aio-capture.ts +++ b/src/agent/aio-capture.ts @@ -24,8 +24,7 @@ * the main agent flow. Losing an AIO event must never break a run. */ -import { logToFile } from '@utils/debug'; -import { VERSION } from '@lib/version'; +import { logToFile, VERSION } from '@store'; /** Conversation turn shape both harnesses normalize to. Matches Anthropic * message role/content conventions, which is also what AIO's Conversation diff --git a/src/lib/agent/bash-fence.ts b/src/agent/bash-fence.ts similarity index 99% rename from src/lib/agent/bash-fence.ts rename to src/agent/bash-fence.ts index 1264b11af..c77803f28 100644 --- a/src/lib/agent/bash-fence.ts +++ b/src/agent/bash-fence.ts @@ -13,7 +13,7 @@ * (`npx ` downloads and runs it), and shell injection. Matching is * token-exact per manager — keyword prefixes admitted `npm publish` via `pub`. */ -import { LINTING_TOOLS } from '@lib/safe-tools'; +import { LINTING_TOOLS } from '@store'; export type BashFenceDecision = | { allowed: true } diff --git a/src/lib/agent/commandments.ts b/src/agent/commandments.ts similarity index 100% rename from src/lib/agent/commandments.ts rename to src/agent/commandments.ts diff --git a/src/lib/detection/agentic.ts b/src/agent/detection/agentic.ts similarity index 55% rename from src/lib/detection/agentic.ts rename to src/agent/detection/agentic.ts index aac8d282a..9c79801f2 100644 --- a/src/lib/detection/agentic.ts +++ b/src/agent/detection/agentic.ts @@ -1,16 +1,7 @@ /** - * Agentic project detection. - * - * A reusable detection tool that drives a Haiku agent over the repo: it finds - * project roots, resolves monorepo/workspace markers, reads package manifests, - * classifies each project against a caller-supplied set of targets, and reports - * which projects already have a PostHog SDK installed. - * - * Product-knowledge-free by design — the caller passes the targets to classify - * into (e.g. source-map skill variants) and maps the result back. Sits next to - * the other detection tools (framework, features, package-manager) so it's - * discoverable. Runs AFTER auth: it uses the same agent loop every program - * uses, which needs credentials. + * Agentic project detection: drives the wizard's agent loop on HAIKU_MODEL to + * scan a repo and return the structured report the store's detection + * contract describes. Installed into the store by the entry point. */ import { @@ -18,119 +9,25 @@ import { runAgent as executeAgent, buildRunTags, AgentSignals, -} from '@lib/agent/agent-interface'; -import { isAbsolute, resolve, sep } from 'path'; -import { detectNodePackageManagers } from './package-manager.js'; -import { CallType, getSkillsBaseUrl, HAIKU_MODEL } from '@lib/constants'; -import { analytics } from '@utils/analytics'; -import type { WizardSession } from '@lib/wizard-session'; -import type { WizardRunOptions } from '@utils/types'; -import type { SpinnerHandle } from '@ui'; - -/** A category the agent classifies each project into (id the agent returns). */ -export type DetectTarget = { id: string; name: string }; - -/** One project the agent found in the repo. */ -export type AgenticProject = { - /** Path relative to the working directory ("." for the repo root). */ - path: string; - /** Human-readable framework the agent detected (e.g. "Next.js"). */ - framework: string; - /** A target id when the project matches one of the supplied targets, else null. */ - targetId: string | null; - /** Whether a PostHog SDK is already installed in this project. */ - hasPostHog: boolean; - /** True on the one project picked as the main user-facing app; only present when the scan set `recommend`. */ - recommended?: boolean; -}; - -export type AgenticDetectionReport = { - repoType: 'monorepo' | 'single'; - projects: AgenticProject[]; -}; - -/** Streaming progress callback — one short activity line per agent step. */ -export type DetectEvent = (line: string) => void; - -/** - * Every project-manifest / workspace-marker filename the wizard's frameworks - * are identified by. One brace-expansion Glob over all of these locates every - * project root in the repo in a single call, regardless of language. - * - * Counterpart: POSTHOG_MANIFESTS in @lib/programs/self-driving/detect (SDK - * grep); keep the two in sync. - */ -export const PROJECT_MANIFESTS: readonly string[] = [ - // JS/TS + workspace markers - 'package.json', - 'pnpm-workspace.yaml', - 'turbo.json', - 'nx.json', - 'lerna.json', - // Python - 'requirements.txt', - 'pyproject.toml', - 'setup.py', - 'Pipfile', - 'manage.py', - // Ruby / PHP - 'Gemfile', - 'composer.json', - // Java - 'pom.xml', - // Rust - 'Cargo.toml', - // Elixir - 'mix.exs', - // Go - 'go.mod', - // .NET: no framework targets yet, but found so - // an existing PostHog SDK is reported (feeds self-driving's "continue" path). - '*.csproj', - // Mobile / native - 'Package.swift', - 'Podfile', - 'project.yml', - 'project.pbxproj', - 'pubspec.yaml', - 'build.gradle', - 'build.gradle.kts', - 'settings.gradle', - 'settings.gradle.kts', - // Gradle version catalog (holds dependency coordinates). - 'gradle/libs.versions.toml', -]; - -/** The single brace-expansion glob covering every supported manifest. */ -export function manifestGlob(): string { - return `**/{${PROJECT_MANIFESTS.join(',')}}`; -} - -export type AgenticDetectOptions = { - /** - * Categories to classify each project into. Order matters: list targets by - * priority, most specific first. When a project could match more than one, - * the agent keeps the earliest — so the caller encodes precedence purely - * through ordering (e.g. a bundler target before a generic framework target). - */ - targets: readonly DetectTarget[]; - /** The program this scan bills to. Required, not optional: the scan drives a - * real agent through the gateway, and a caller that forgets leaves that - * spend unattributed. */ - programId: string; - /** One short clause describing what the scan is for (frames the prompt). */ - purpose?: string; - /** Ask the agent to label exactly one project `recommended` (the main client app). Off by default. */ - recommend?: boolean; - /** - * Target ids whose technologies co-occur in one manifest (e.g. the JS - * family). Among these, the enumeration's priority winner overrides the - * model's pick; elsewhere a valid pick always wins — see coerceAgenticReport. - */ - rerankIds?: readonly string[]; - /** Streaming activity callback for the UI. */ - onEvent?: DetectEvent; -}; +} from '../agent-interface.js'; +import { + detectNodePackageManagers, + CallType, + getSkillsBaseUrl, + HAIKU_MODEL, + analytics, + coerceAgenticReport, + deriveReportJson, + manifestGlob, +} from '@store'; +import type { + WizardSession, + WizardRunOptions, + SpinnerHandle, + AgenticDetectOptions, + AgenticDetectionReport, + DetectTarget, +} from '@store/types'; function buildPrompt( cwd: string, @@ -194,104 +91,6 @@ function buildPrompt( * one-line assembly's `projects` merge the same way. `repoType` is * approximated from the count — it only feeds telemetry and display. */ -export function deriveReportJson(text: string): unknown | null { - const byPath = new Map>(); - for (const line of text.split('\n')) { - const start = line.indexOf('{'); - const end = line.lastIndexOf('}'); - if (start === -1 || end <= start) continue; - let parsed: unknown; - try { - parsed = JSON.parse(line.slice(start, end + 1)); - } catch { - continue; // not JSON — prose, shape echoes, pretty-printed fragments - } - const obj = (parsed ?? {}) as Record; - const candidates = Array.isArray(obj.projects) ? obj.projects : [obj]; - for (const candidate of candidates) { - const p = (candidate ?? {}) as Record; - if (typeof p.path === 'string') byPath.set(p.path, p); - } - } - if (byPath.size === 0) return null; - const projects = [...byPath.values()]; - return { repoType: projects.length > 1 ? 'monorepo' : 'single', projects }; -} - -/** - * Clamp an agent-reported project path to a safe repo-relative dir. The path - * is LLM output: absolute paths or `..` segments could steer later phases - * (e.g. integrate-run's targetDir) outside the repo, so they clamp to '.'. - */ -function coercePath(raw: unknown): string { - if (typeof raw !== 'string' || raw.length === 0) return '.'; - if (isAbsolute(raw) || raw.split(/[\\/]/).includes('..')) return '.'; - return raw; -} - -/** Resolve an agent-reported path to an absolute dir clamped to the root — the caller-side counterpart of coercePath. */ -export function resolveProjectDir(installDir: string, rel: unknown): string { - if (typeof rel !== 'string' || rel === '.') return installDir; - const root = resolve(installDir); - const dir = resolve(root, rel); - return dir === root || dir.startsWith(root + sep) ? dir : root; -} - -/** - * Validate the agent's raw JSON into a report, clamping each targetId to the - * supplied set and each path to a repo-relative dir. Exported for testing. - * `recommended` is stripped unless requested; at most one (the first) survives. - */ -export function coerceAgenticReport( - parsed: unknown, - validTargetIds: readonly string[], - options?: { recommend?: boolean; rerankIds?: readonly string[] }, -): AgenticDetectionReport { - const recommend = options?.recommend === true; - const rerankIds = options?.rerankIds ?? []; - const obj = (parsed ?? {}) as Record; - const repoType = obj.repoType === 'monorepo' ? 'monorepo' : 'single'; - const rawProjects = Array.isArray(obj.projects) ? obj.projects : []; - let recommendedSeen = false; - const projects: AgenticProject[] = rawProjects.map((raw) => { - const p = (raw ?? {}) as Record; - // Trust the model's pick; an invalid one falls back to the enumeration's - // highest-priority member (validTargetIds IS the priority order). The - // winner overrides a valid pick only when both sit in rerankIds — stacks - // that co-occur in one manifest, where a misordered enumeration is the - // common miss. Elsewhere enumerations are padded across exclusive stacks - // (a Flutter app listing react-native) and must not beat a correct pick. - const pick = - typeof p.targetId === 'string' && validTargetIds.includes(p.targetId) - ? p.targetId - : null; - const enumerated = Array.isArray(p.matchingTargets) - ? validTargetIds.find((id) => - (p.matchingTargets as unknown[]).includes(id), - ) ?? null - : null; - const targetId = - pick === null - ? enumerated - : enumerated !== null && - rerankIds.includes(enumerated) && - rerankIds.includes(pick) - ? enumerated - : pick; - const recommended = recommend && !recommendedSeen && p.recommended === true; - recommendedSeen ||= recommended; - return { - path: coercePath(p.path), - framework: typeof p.framework === 'string' ? p.framework : 'Unknown', - targetId, - hasPostHog: p.hasPostHog === true, - ...(recommend ? { recommended } : {}), - }; - }); - return { repoType, projects }; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any function formatToolUse(block: any): string { const name = typeof block?.name === 'string' ? block.name : 'tool'; const input = (block?.input ?? {}) as Record; diff --git a/src/lib/gateway-session.ts b/src/agent/gateway/gateway-session.ts similarity index 97% rename from src/lib/gateway-session.ts rename to src/agent/gateway/gateway-session.ts index 577753df2..2bcac8311 100644 --- a/src/lib/gateway-session.ts +++ b/src/agent/gateway/gateway-session.ts @@ -7,15 +7,16 @@ */ import { readFileSync } from 'node:fs'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; -import { WizardError } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; -import type { HostResolution } from '@lib/host-resolution'; -import { checkLlmGatewayHealth } from '@lib/health-checks/endpoints'; -import { ServiceHealthStatus } from '@lib/health-checks/types'; +import { + logToFile, + analytics, + WizardError, + ErrorCodes, + checkLlmGatewayHealth, + ServiceHealthStatus, +} from '@store'; +import type { HostResolution, CloudRegion } from '@store/types'; import { IS_PRODUCTION_BUILD, runtimeEnv } from '@env'; -import type { CloudRegion } from '@utils/types'; export interface GatewayAuth { /** Base URL for model calls (no `/v1`; transports append their route). */ diff --git a/src/agent/index.ts b/src/agent/index.ts index 00b26d0da..b6ef3ee56 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -1,2 +1,5 @@ -/** Public runtime API of the agent surface. Populated by the surface split. */ -export {}; +/** Public runtime API of the agent surface. */ +export { detectProjectsWithAgent } from './detection/agentic.js'; +export { configureGatewayFromCIEnvironment } from './gateway/gateway-session.js'; +export { runMcpPromptViaSdk } from './mcp-prompt-streaming.js'; +export { runAgent } from './runner/index.js'; diff --git a/src/lib/agent/mcp-prompt-streaming.ts b/src/agent/mcp-prompt-streaming.ts similarity index 96% rename from src/lib/agent/mcp-prompt-streaming.ts rename to src/agent/mcp-prompt-streaming.ts index f0f6e87a9..bdb6d3418 100644 --- a/src/lib/agent/mcp-prompt-streaming.ts +++ b/src/agent/mcp-prompt-streaming.ts @@ -12,15 +12,17 @@ * `for await (...)` and render as they arrive. */ -import type { AgentChunk } from '@ui/tui/services/mcp-suggested-prompts-services'; -import type { Credentials } from '@lib/wizard-session'; -import { DEFAULT_AGENT_MODEL, WIZARD_USER_AGENT } from '@lib/constants'; -import { logToFile } from '@utils/debug'; -import { gatewayAuth } from '@lib/gateway-session'; -import { buildAgentEnv, buildRunTags } from '@lib/agent/agent-interface'; -import { sanitizeAgentSubprocessEnv } from '@lib/agent-env-isolation'; -import { createIsolatedAgentConfigDir } from '@lib/agent/stored-login'; -import { analytics } from '@utils/analytics'; +import type { AgentChunk, Credentials } from '@store/types'; +import { + DEFAULT_AGENT_MODEL, + WIZARD_USER_AGENT, + logToFile, + sanitizeAgentSubprocessEnv, + analytics, +} from '@store'; +import { gatewayAuth } from './gateway/gateway-session.js'; +import { buildAgentEnv, buildRunTags } from './agent-interface.js'; +import { createIsolatedAgentConfigDir } from './stored-login.js'; // Cached SDK module — first call pays the dynamic-import cost; later // calls reuse the same module. diff --git a/src/lib/middleware/benchmark.ts b/src/agent/middleware/benchmark.ts similarity index 84% rename from src/lib/middleware/benchmark.ts rename to src/agent/middleware/benchmark.ts index 20017ad75..27b02326f 100644 --- a/src/lib/middleware/benchmark.ts +++ b/src/agent/middleware/benchmark.ts @@ -7,15 +7,14 @@ * pipeline.finalize(resultMessage, durationMs); */ -import { getUI, type SpinnerHandle } from '@ui'; -import { logToFile, getLogFilePath, configureLogFile } from '@utils/debug'; -import { MiddlewarePipeline } from './pipeline'; -import { PhaseDetector } from './phase-detector'; -import { loadBenchmarkConfig } from './config'; -import { createPluginsFromConfig } from './benchmarks'; -import type { BenchmarkConfig } from './config'; -import type { WizardRunOptions } from '@utils/types'; -import { AgentSignals } from '@lib/agent/agent-interface'; +import { getUI, logToFile, getLogFilePath, configureLogFile } from '@store'; +import type { SpinnerHandle, WizardRunOptions } from '@store/types'; +import { MiddlewarePipeline } from './pipeline.js'; +import { PhaseDetector } from './phase-detector.js'; +import { loadBenchmarkConfig } from './config.js'; +import { createPluginsFromConfig } from './benchmarks/index.js'; +import type { BenchmarkConfig } from './config.js'; +import { AgentSignals } from '../agent-interface.js'; // ── Types ────────────────────────────────────────────────────────────── diff --git a/src/lib/middleware/benchmarks/cache-tracker.ts b/src/agent/middleware/benchmarks/cache-tracker.ts similarity index 97% rename from src/lib/middleware/benchmarks/cache-tracker.ts rename to src/agent/middleware/benchmarks/cache-tracker.ts index 047efc3a8..b2744222a 100644 --- a/src/lib/middleware/benchmarks/cache-tracker.ts +++ b/src/agent/middleware/benchmarks/cache-tracker.ts @@ -8,8 +8,8 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import type { TurnData } from './turn-counter'; +} from '../types.js'; +import type { TurnData } from './turn-counter.js'; /** Matches SDK usage.cache_creation (ephemeral 5m vs 1h for pricing). */ export interface CacheCreationBreakdown { diff --git a/src/lib/middleware/benchmarks/compaction-tracker.ts b/src/agent/middleware/benchmarks/compaction-tracker.ts similarity index 94% rename from src/lib/middleware/benchmarks/compaction-tracker.ts rename to src/agent/middleware/benchmarks/compaction-tracker.ts index bb16fb6e5..42ead3a20 100644 --- a/src/lib/middleware/benchmarks/compaction-tracker.ts +++ b/src/agent/middleware/benchmarks/compaction-tracker.ts @@ -9,9 +9,9 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import { logToFile } from '@utils/debug'; -import { AgentSignals } from '@lib/agent/agent-interface'; +} from '../types.js'; +import { logToFile } from '@store'; +import { AgentSignals } from '../../agent-interface.js'; export interface CompactionData { phaseCompactions: number; diff --git a/src/lib/middleware/benchmarks/context-size-tracker.ts b/src/agent/middleware/benchmarks/context-size-tracker.ts similarity index 96% rename from src/lib/middleware/benchmarks/context-size-tracker.ts rename to src/agent/middleware/benchmarks/context-size-tracker.ts index f51f0f441..b4d1d99be 100644 --- a/src/lib/middleware/benchmarks/context-size-tracker.ts +++ b/src/agent/middleware/benchmarks/context-size-tracker.ts @@ -10,8 +10,8 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import type { TokenData } from './token-tracker'; +} from '../types.js'; +import type { TokenData } from './token-tracker.js'; export interface ContextSizeData { /** Per-phase context size snapshots */ diff --git a/src/lib/middleware/benchmarks/cost-tracker.ts b/src/agent/middleware/benchmarks/cost-tracker.ts similarity index 94% rename from src/lib/middleware/benchmarks/cost-tracker.ts rename to src/agent/middleware/benchmarks/cost-tracker.ts index b65b4f5a0..1cd5386ff 100644 --- a/src/lib/middleware/benchmarks/cost-tracker.ts +++ b/src/agent/middleware/benchmarks/cost-tracker.ts @@ -2,10 +2,10 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import { computeTokenCostUsd } from '@lib/token-pricing'; -import type { TokenData } from './token-tracker'; -import type { CacheData } from './cache-tracker'; +} from '../types.js'; +import { computeTokenCostUsd } from '@store'; +import type { TokenData } from './token-tracker.js'; +import type { CacheData } from './cache-tracker.js'; export interface CostData { totalCost: number; diff --git a/src/lib/middleware/benchmarks/duration-tracker.ts b/src/agent/middleware/benchmarks/duration-tracker.ts similarity index 97% rename from src/lib/middleware/benchmarks/duration-tracker.ts rename to src/agent/middleware/benchmarks/duration-tracker.ts index 84427273c..caad0fa50 100644 --- a/src/lib/middleware/benchmarks/duration-tracker.ts +++ b/src/agent/middleware/benchmarks/duration-tracker.ts @@ -6,7 +6,7 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; +} from '../types.js'; export interface DurationData { phaseSnapshots: Array<{ diff --git a/src/lib/middleware/benchmarks/index.ts b/src/agent/middleware/benchmarks/index.ts similarity index 74% rename from src/lib/middleware/benchmarks/index.ts rename to src/agent/middleware/benchmarks/index.ts index 470dbd82b..a7c93c5e4 100644 --- a/src/lib/middleware/benchmarks/index.ts +++ b/src/agent/middleware/benchmarks/index.ts @@ -5,20 +5,17 @@ * from a BenchmarkConfig. */ -import type { - Middleware, - MiddlewareFactoryOptions, -} from '@lib/middleware/types'; -import type { BenchmarkConfig } from '@lib/middleware/config'; -import { TurnCounterPlugin } from './turn-counter'; -import { TokenTrackerPlugin } from './token-tracker'; -import { CacheTrackerPlugin } from './cache-tracker'; -import { CompactionTrackerPlugin } from './compaction-tracker'; -import { ContextSizeTrackerPlugin } from './context-size-tracker'; -import { CostTrackerPlugin } from './cost-tracker'; -import { DurationTrackerPlugin } from './duration-tracker'; -import { SummaryPlugin } from './summary'; -import { JsonWriterPlugin } from './json-writer'; +import type { Middleware, MiddlewareFactoryOptions } from '../types.js'; +import type { BenchmarkConfig } from '../config.js'; +import { TurnCounterPlugin } from './turn-counter.js'; +import { TokenTrackerPlugin } from './token-tracker.js'; +import { CacheTrackerPlugin } from './cache-tracker.js'; +import { CompactionTrackerPlugin } from './compaction-tracker.js'; +import { ContextSizeTrackerPlugin } from './context-size-tracker.js'; +import { CostTrackerPlugin } from './cost-tracker.js'; +import { DurationTrackerPlugin } from './duration-tracker.js'; +import { SummaryPlugin } from './summary.js'; +import { JsonWriterPlugin } from './json-writer.js'; type PluginFactory = (opts: MiddlewareFactoryOptions) => Middleware; diff --git a/src/lib/middleware/benchmarks/json-writer.ts b/src/agent/middleware/benchmarks/json-writer.ts similarity index 89% rename from src/lib/middleware/benchmarks/json-writer.ts rename to src/agent/middleware/benchmarks/json-writer.ts index 253225335..ec688e1d3 100644 --- a/src/lib/middleware/benchmarks/json-writer.ts +++ b/src/agent/middleware/benchmarks/json-writer.ts @@ -6,22 +6,21 @@ */ import fs from 'fs'; -import { getUI } from '@ui'; -import { logToFile } from '@utils/debug'; -import { AgentSignals } from '@lib/agent/agent-interface'; +import { getUI, logToFile } from '@store'; +import { AgentSignals } from '../../agent-interface.js'; import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import type { TokenData } from './token-tracker'; -import type { CacheData } from './cache-tracker'; -import type { TurnData } from './turn-counter'; -import type { CostData } from './cost-tracker'; -import type { DurationData } from './duration-tracker'; -import type { CompactionData } from './compaction-tracker'; -import type { ContextSizeData } from './context-size-tracker'; -import type { BenchmarkData, StepUsage } from '@lib/middleware/benchmark'; +} from '../types.js'; +import type { TokenData } from './token-tracker.js'; +import type { CacheData } from './cache-tracker.js'; +import type { TurnData } from './turn-counter.js'; +import type { CostData } from './cost-tracker.js'; +import type { DurationData } from './duration-tracker.js'; +import type { CompactionData } from './compaction-tracker.js'; +import type { ContextSizeData } from './context-size-tracker.js'; +import type { BenchmarkData, StepUsage } from '../benchmark.js'; /** * Sum token usage across all models from the SDK's modelUsage field. diff --git a/src/lib/middleware/benchmarks/summary.ts b/src/agent/middleware/benchmarks/summary.ts similarity index 89% rename from src/lib/middleware/benchmarks/summary.ts rename to src/agent/middleware/benchmarks/summary.ts index 45c3b0a8e..ae49d3902 100644 --- a/src/lib/middleware/benchmarks/summary.ts +++ b/src/agent/middleware/benchmarks/summary.ts @@ -1,17 +1,18 @@ -import { getUI, type SpinnerHandle } from '@ui'; -import { AgentSignals } from '@lib/agent/agent-interface'; +import { getUI } from '@store'; +import type { SpinnerHandle } from '@store/types'; +import { AgentSignals } from '../../agent-interface.js'; import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import type { TokenData } from './token-tracker'; -import type { TurnData } from './turn-counter'; -import type { CostData } from './cost-tracker'; -import type { DurationData } from './duration-tracker'; -import type { CompactionData } from './compaction-tracker'; -import type { ContextSizeData } from './context-size-tracker'; -import type { CacheData } from './cache-tracker'; +} from '../types.js'; +import type { TokenData } from './token-tracker.js'; +import type { TurnData } from './turn-counter.js'; +import type { CostData } from './cost-tracker.js'; +import type { DurationData } from './duration-tracker.js'; +import type { CompactionData } from './compaction-tracker.js'; +import type { ContextSizeData } from './context-size-tracker.js'; +import type { CacheData } from './cache-tracker.js'; function fmtDuration(ms: number): string { const s = Math.round(ms / 1000); diff --git a/src/lib/middleware/benchmarks/token-tracker.ts b/src/agent/middleware/benchmarks/token-tracker.ts similarity index 97% rename from src/lib/middleware/benchmarks/token-tracker.ts rename to src/agent/middleware/benchmarks/token-tracker.ts index e709bc75b..2546eda0b 100644 --- a/src/lib/middleware/benchmarks/token-tracker.ts +++ b/src/agent/middleware/benchmarks/token-tracker.ts @@ -11,8 +11,8 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; -import type { TurnData } from './turn-counter'; +} from '../types.js'; +import type { TurnData } from './turn-counter.js'; export interface TokenData { phaseInput: number; diff --git a/src/lib/middleware/benchmarks/turn-counter.ts b/src/agent/middleware/benchmarks/turn-counter.ts similarity index 98% rename from src/lib/middleware/benchmarks/turn-counter.ts rename to src/agent/middleware/benchmarks/turn-counter.ts index 0012f8595..2a1baa2d6 100644 --- a/src/lib/middleware/benchmarks/turn-counter.ts +++ b/src/agent/middleware/benchmarks/turn-counter.ts @@ -10,7 +10,7 @@ import type { Middleware, MiddlewareContext, MiddlewareStore, -} from '@lib/middleware/types'; +} from '../types.js'; export interface TurnData { /** Whether the current message is a duplicate of the last processed turn */ diff --git a/src/lib/middleware/config.ts b/src/agent/middleware/config.ts similarity index 94% rename from src/lib/middleware/config.ts rename to src/agent/middleware/config.ts index 5d45af984..774b1055a 100644 --- a/src/lib/middleware/config.ts +++ b/src/agent/middleware/config.ts @@ -7,10 +7,9 @@ import fs from 'fs'; import path from 'path'; -import { logToFile } from '@utils/debug'; -import { AgentSignals } from '@lib/agent/agent-interface'; +import { logToFile, WIZARD_BENCHMARK_FILE, WIZARD_LOG_FILE } from '@store'; +import { AgentSignals } from '../agent-interface.js'; import { runtimeEnv } from '@env'; -import { WIZARD_BENCHMARK_FILE, WIZARD_LOG_FILE } from '@utils/paths'; export interface BenchmarkConfig { /** Enable/disable individual metric plugins */ diff --git a/src/agent/middleware/index.ts b/src/agent/middleware/index.ts new file mode 100644 index 000000000..43876e882 --- /dev/null +++ b/src/agent/middleware/index.ts @@ -0,0 +1,19 @@ +/** + * Middleware system for wizard agent runs. + */ + +export { MiddlewarePipeline } from './pipeline.js'; +export { PhaseDetector } from './phase-detector.js'; +export type { + Middleware, + MiddlewareContext, + MiddlewareStore, +} from './types.js'; + +export { loadBenchmarkConfig, getDefaultConfig } from './config.js'; +export type { BenchmarkConfig } from './config.js'; + +export { createBenchmarkPipeline } from './benchmark.js'; +export type { BenchmarkData, StepUsage } from './benchmark.js'; + +export { createPluginsFromConfig } from './benchmarks/index.js'; diff --git a/src/lib/middleware/phase-detector.ts b/src/agent/middleware/phase-detector.ts similarity index 100% rename from src/lib/middleware/phase-detector.ts rename to src/agent/middleware/phase-detector.ts diff --git a/src/lib/middleware/pipeline.ts b/src/agent/middleware/pipeline.ts similarity index 97% rename from src/lib/middleware/pipeline.ts rename to src/agent/middleware/pipeline.ts index d1316e9e7..71ce3159f 100644 --- a/src/lib/middleware/pipeline.ts +++ b/src/agent/middleware/pipeline.ts @@ -5,13 +5,13 @@ * while internally dispatching to an ordered list of middleware plugins. */ -import { PhaseDetector } from './phase-detector'; +import { PhaseDetector } from './phase-detector.js'; import type { Middleware, MiddlewareContext, MiddlewareStore, SDKMessage, -} from './types'; +} from './types.js'; export class MiddlewarePipeline { private middlewares: Middleware[]; diff --git a/src/lib/middleware/types.ts b/src/agent/middleware/types.ts similarity index 97% rename from src/lib/middleware/types.ts rename to src/agent/middleware/types.ts index ea1715700..92768932a 100644 --- a/src/lib/middleware/types.ts +++ b/src/agent/middleware/types.ts @@ -5,7 +5,7 @@ * and can publish data to a shared store for downstream middleware to read. */ -import type { SpinnerHandle } from '@ui'; +import type { SpinnerHandle } from '@store/types'; export type SDKMessage = any; diff --git a/src/lib/agent/output-signals.ts b/src/agent/output-signals.ts similarity index 98% rename from src/lib/agent/output-signals.ts rename to src/agent/output-signals.ts index c8df7aed6..03383105c 100644 --- a/src/lib/agent/output-signals.ts +++ b/src/agent/output-signals.ts @@ -12,7 +12,7 @@ * hooks' onTerminate callback (`yaraViolationReason` in runAgent) instead. */ -import { AgentSignals, REMARK_INSTRUCTION } from '@lib/agent-signals'; +import { AgentSignals, REMARK_INSTRUCTION } from '@store'; /** * Single source of truth for the substrings runAgent scans agent output for. diff --git a/src/lib/agent/runner/README.md b/src/agent/runner/README.md similarity index 100% rename from src/lib/agent/runner/README.md rename to src/agent/runner/README.md diff --git a/src/lib/agent/runner/__tests__/switchboard.test.ts b/src/agent/runner/__tests__/switchboard.test.ts similarity index 98% rename from src/lib/agent/runner/__tests__/switchboard.test.ts rename to src/agent/runner/__tests__/switchboard.test.ts index 5386fc312..e14bc92d4 100644 --- a/src/lib/agent/runner/__tests__/switchboard.test.ts +++ b/src/agent/runner/__tests__/switchboard.test.ts @@ -10,7 +10,7 @@ * asserted directly. */ import { describe, it, expect } from 'vitest'; -import { PROGRAM_REGISTRY } from '@lib/programs/program-registry'; +import { PROGRAM_REGISTRY } from '@store/programs/program-registry'; import { DEFAULT_AGENT_MODEL, GPT5_6_LUNA_MODEL, @@ -21,13 +21,13 @@ import { Harness, Sequence, WIZARD_ORCHESTRATOR_FLAG_KEY, -} from '@lib/constants'; +} from '@store/shared/constants'; import { PROGRAM_BINDINGS, DEFAULT_BINDING, resolveBinding, type SwitchboardCtx, -} from '@lib/agent/runner/switchboard'; +} from '../switchboard/index.js'; import { modelCapabilities, MINT_ALLOWED_EFFORTS, @@ -35,8 +35,8 @@ import { requireKnownModel, TRIAGE_MODELS, VALID_MODELS, -} from '@lib/agent/runner/switchboard/models'; -import { runBindingCases } from '@lib/agent/runner/switchboard/flags/__tests__/binding-cases'; +} from '../switchboard/models.js'; +import { runBindingCases } from '../switchboard/flags/__tests__/binding-cases.js'; const PROGRAM_IDS = PROGRAM_REGISTRY.map((c) => c.id); const DEFAULT_RESOLVED = { diff --git a/src/lib/agent/runner/harness/agents-platform/README.md b/src/agent/runner/harness/agents-platform/README.md similarity index 100% rename from src/lib/agent/runner/harness/agents-platform/README.md rename to src/agent/runner/harness/agents-platform/README.md diff --git a/src/lib/agent/runner/harness/anthropic/README.md b/src/agent/runner/harness/anthropic/README.md similarity index 100% rename from src/lib/agent/runner/harness/anthropic/README.md rename to src/agent/runner/harness/anthropic/README.md diff --git a/src/lib/agent/runner/harness/anthropic/index.ts b/src/agent/runner/harness/anthropic/index.ts similarity index 92% rename from src/lib/agent/runner/harness/anthropic/index.ts rename to src/agent/runner/harness/anthropic/index.ts index 4f5e449ec..dab756068 100644 --- a/src/lib/agent/runner/harness/anthropic/index.ts +++ b/src/agent/runner/harness/anthropic/index.ts @@ -1,21 +1,24 @@ // Supported legacy SDK fallback; both this adapter and Pi implement run and runTask. -import { getUI } from '@ui'; -import { Harness } from '@lib/constants'; +import { + getUI, + Harness, + getLogFilePath, + logToFile, + detectNodePackageManagers, +} from '@store'; import { initializeAgent, runAgent as executeAgent, -} from '@lib/agent/agent-interface'; -import { createAioCapture } from '@lib/agent/aio-capture'; -import { getLogFilePath, logToFile } from '@utils/debug'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { sessionToOptions } from '@lib/agent/runner/shared/bootstrap'; +} from '../../../agent-interface.js'; +import { createAioCapture } from '../../../aio-capture.js'; +import { sessionToOptions } from '../../shared/bootstrap.js'; import type { AgentResult, AgentHarness, BackendRunInputs, TaskRunInputs, -} from '../types'; +} from '../types.js'; export const anthropicBackend: AgentHarness = { name: Harness.anthropic, diff --git a/src/lib/agent/runner/harness/pi/README.md b/src/agent/runner/harness/pi/README.md similarity index 100% rename from src/lib/agent/runner/harness/pi/README.md rename to src/agent/runner/harness/pi/README.md diff --git a/src/lib/agent/runner/harness/pi/__tests__/completion.test.ts b/src/agent/runner/harness/pi/__tests__/completion.test.ts similarity index 93% rename from src/lib/agent/runner/harness/pi/__tests__/completion.test.ts rename to src/agent/runner/harness/pi/__tests__/completion.test.ts index 43eae2772..4d57bf33c 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/completion.test.ts +++ b/src/agent/runner/harness/pi/__tests__/completion.test.ts @@ -1,5 +1,5 @@ -import { completionFailure, runErrorType } from '../completion'; -import { AgentErrorType } from '@lib/agent-signals'; +import { completionFailure, runErrorType } from '../completion.js'; +import { AgentErrorType } from '@store/agent-protocol/agent-signals'; describe('completionFailure', () => { it('fails a no-op run (zero tool calls) as NO_PROGRESS', () => { diff --git a/src/lib/agent/runner/harness/pi/__tests__/env-lockdown.test.ts b/src/agent/runner/harness/pi/__tests__/env-lockdown.test.ts similarity index 96% rename from src/lib/agent/runner/harness/pi/__tests__/env-lockdown.test.ts rename to src/agent/runner/harness/pi/__tests__/env-lockdown.test.ts index 1034e0bca..751de8ef9 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/env-lockdown.test.ts +++ b/src/agent/runner/harness/pi/__tests__/env-lockdown.test.ts @@ -4,7 +4,7 @@ * drops everything else — the leak that exposed the test key before. */ -import { buildScrubbedEnv } from '..'; +import { buildScrubbedEnv } from '../index.js'; describe('buildScrubbedEnv', () => { const saved = { ...process.env }; diff --git a/src/lib/agent/runner/harness/pi/__tests__/gateway.test.ts b/src/agent/runner/harness/pi/__tests__/gateway.test.ts similarity index 98% rename from src/lib/agent/runner/harness/pi/__tests__/gateway.test.ts rename to src/agent/runner/harness/pi/__tests__/gateway.test.ts index c68420193..bfcfefb0a 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/gateway.test.ts +++ b/src/agent/runner/harness/pi/__tests__/gateway.test.ts @@ -4,8 +4,8 @@ import { isGatewayAuthRejection, withGatewayRemint, GATEWAY_PROVIDER, -} from '../gateway'; -import type { GatewayAuth } from '@lib/gateway-session'; +} from '../gateway.js'; +import type { GatewayAuth } from '../../../../gateway/gateway-session.js'; describe('buildGatewayProvider effort', () => { const base = { diff --git a/src/lib/agent/runner/harness/pi/__tests__/security.test.ts b/src/agent/runner/harness/pi/__tests__/security.test.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/__tests__/security.test.ts rename to src/agent/runner/harness/pi/__tests__/security.test.ts index f73405721..915f6c28c 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/security.test.ts +++ b/src/agent/runner/harness/pi/__tests__/security.test.ts @@ -10,10 +10,10 @@ import { overwriteShrinkReason, MAX_TOOL_CALLS, type PiExtensionApiLike, -} from '../security'; -import { analytics } from '@utils/analytics'; +} from '../security.js'; +import { analytics } from '@store/shared/analytics'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn() }, })); diff --git a/src/lib/agent/runner/harness/pi/__tests__/status-line.test.ts b/src/agent/runner/harness/pi/__tests__/status-line.test.ts similarity index 92% rename from src/lib/agent/runner/harness/pi/__tests__/status-line.test.ts rename to src/agent/runner/harness/pi/__tests__/status-line.test.ts index 12309fff1..97338801d 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/status-line.test.ts +++ b/src/agent/runner/harness/pi/__tests__/status-line.test.ts @@ -5,8 +5,8 @@ */ import { describe, it, expect } from 'vitest'; -import { AgentSignals } from '@lib/agent-signals'; -import { lastStatusLine } from '..'; +import { AgentSignals } from '@store/agent-protocol/agent-signals'; +import { lastStatusLine } from '../index.js'; const S = AgentSignals.STATUS; // '[STATUS]' diff --git a/src/lib/agent/runner/harness/pi/__tests__/task-tools.test.ts b/src/agent/runner/harness/pi/__tests__/task-tools.test.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/__tests__/task-tools.test.ts rename to src/agent/runner/harness/pi/__tests__/task-tools.test.ts index f55a98995..e8c0b34a4 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/task-tools.test.ts +++ b/src/agent/runner/harness/pi/__tests__/task-tools.test.ts @@ -9,7 +9,7 @@ import { allowedOrchestratorTools, allowedPiWizardTools, fenceDisallowList, -} from '../task'; +} from '../task.js'; describe('allowedPiWizardTools', () => { const always = ['check_env_keys', 'set_env_values', 'detect_package_manager']; diff --git a/src/lib/agent/runner/harness/pi/__tests__/tools.test.ts b/src/agent/runner/harness/pi/__tests__/tools.test.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/__tests__/tools.test.ts rename to src/agent/runner/harness/pi/__tests__/tools.test.ts index c3ef60dc1..d60432630 100644 --- a/src/lib/agent/runner/harness/pi/__tests__/tools.test.ts +++ b/src/agent/runner/harness/pi/__tests__/tools.test.ts @@ -12,10 +12,10 @@ import { describe, it, expect, vi } from 'vitest'; import { CANCELLED_SENTINEL, type WizardAskBridge, -} from '@lib/wizard-ask-bridge'; -import { createWizardPiTools } from '../tools'; -import { evaluateToolCall } from '../security'; -import { allowedPiCodingTools, allowedOrchestratorTools } from '../task'; +} from '@store/session/wizard-ask-bridge'; +import { createWizardPiTools } from '../tools.js'; +import { evaluateToolCall } from '../security.js'; +import { allowedPiCodingTools, allowedOrchestratorTools } from '../task.js'; import { ASK_BATCH_THRESHOLD, ASK_CANCELLED_NOTE, @@ -24,7 +24,7 @@ import { WIZARD_ASK_SENSITIVE_DESCRIPTION, WIZARD_ASK_SUBJECT_DESCRIPTION, WIZARD_ASK_TOOL_DESCRIPTION, -} from '@lib/wizard-tools/tools'; +} from '@store/tools/tools'; const SECRET = 'phx_live_zendesk_token_123'; diff --git a/src/lib/agent/runner/harness/pi/completion.ts b/src/agent/runner/harness/pi/completion.ts similarity index 95% rename from src/lib/agent/runner/harness/pi/completion.ts rename to src/agent/runner/harness/pi/completion.ts index a4fed8aa4..17bb7059e 100644 --- a/src/lib/agent/runner/harness/pi/completion.ts +++ b/src/agent/runner/harness/pi/completion.ts @@ -1,4 +1,4 @@ -import { AgentErrorType } from '@lib/agent-signals'; +import { AgentErrorType } from '@store'; /** Which completion guard should fail a pi run, or undefined for a clean finish. */ export function completionFailure(args: { diff --git a/src/lib/agent/runner/harness/pi/gateway.ts b/src/agent/runner/harness/pi/gateway.ts similarity index 98% rename from src/lib/agent/runner/harness/pi/gateway.ts rename to src/agent/runner/harness/pi/gateway.ts index c827bcfcb..25b0fc6bb 100644 --- a/src/lib/agent/runner/harness/pi/gateway.ts +++ b/src/agent/runner/harness/pi/gateway.ts @@ -10,11 +10,11 @@ import { buildWizardPropertiesBlob, isPastRefresh, type GatewayAuth, -} from '@lib/gateway-session'; +} from '../../../gateway/gateway-session.js'; import { modelCapabilities, type ThinkingLevel, -} from '../../switchboard/models'; +} from '../../switchboard/models.js'; /** Provider registered on the in-memory registry for this run. */ export const GATEWAY_PROVIDER = 'posthog-gateway'; diff --git a/src/lib/agent/runner/harness/pi/index.ts b/src/agent/runner/harness/pi/index.ts similarity index 96% rename from src/lib/agent/runner/harness/pi/index.ts rename to src/agent/runner/harness/pi/index.ts index 8c6badb5b..449cc7a35 100644 --- a/src/lib/agent/runner/harness/pi/index.ts +++ b/src/agent/runner/harness/pi/index.ts @@ -14,35 +14,40 @@ import fs from 'fs'; import path from 'path'; -import { getUI } from '@ui'; -import { getLogFilePath, logToFile } from '@utils/debug'; import { + getUI, + getLogFilePath, + logToFile, Harness, Sequence, WIZARD_REMARK_EVENT_NAME, WIZARD_USER_AGENT, -} from '@lib/constants'; -import { analytics } from '@utils/analytics'; -import { AgentErrorType } from '@lib/agent/agent-interface'; -import { AgentSignals, REMARK_INSTRUCTION } from '@lib/agent-signals'; -import { AgentOutputSignals } from '@lib/agent/output-signals'; -import { assembleCommandments } from '../../switchboard/commandments'; -import { gatewayAuth, type GatewayAuth } from '@lib/gateway-session'; + analytics, + AgentSignals, + REMARK_INSTRUCTION, +} from '@store'; +import { AgentErrorType } from '../../../agent-interface.js'; +import { AgentOutputSignals } from '../../../output-signals.js'; +import { assembleCommandments } from '../../switchboard/commandments.js'; +import { + gatewayAuth, + type GatewayAuth, +} from '../../../gateway/gateway-session.js'; import { buildGatewayProvider, GATEWAY_PROVIDER, withGatewayRemint, -} from './gateway'; -import { createAioCapture } from '@lib/agent/aio-capture'; +} from './gateway.js'; +import { createAioCapture } from '../../../aio-capture.js'; import type { AgentResult, AgentHarness, BackendRunInputs, TaskRunInputs, -} from '../types'; -import type { BootstrapResult } from '@lib/agent/runner/shared/types'; -import type { TaskStore } from './tasks'; -import { completionFailure, runErrorType } from './completion'; +} from '../types.js'; +import type { BootstrapResult } from '../../shared/types.js'; +import type { TaskStore } from './tasks.js'; +import { completionFailure, runErrorType } from './completion.js'; /** Injects the MCP server `instructions` pi-mcp-adapter drops (project env, skill steer, tool domains) into the system prompt, falling back to a bootstrap-derived project block when the warm-connect captured none. */ function piMcpContext( @@ -304,7 +309,7 @@ export const piBackend: AgentHarness = { // flips it; the security gate reads it to block Write/Edit meanwhile. const askState = { pending: false }; - const { createSecurityExtension } = await import('./security'); + const { createSecurityExtension } = await import('./security.js'); const security = createSecurityExtension({ disallowedTools: programConfig.disallowedTools, getWizardAskPending: () => askState.pending, @@ -315,7 +320,7 @@ export const piBackend: AgentHarness = { // Pay warlock's WASM-init + rule-compile cost now, off the tool-call // path, so the first scanned call doesn't eat cold-start latency. - const { prewarmYaraScanner } = await import('@lib/yara-hooks'); + const { prewarmYaraScanner } = await import('@store'); void prewarmYaraScanner(); // Wire the real PostHog MCP into pi (#10): load pi's MCP adapter and point @@ -334,7 +339,7 @@ export const piBackend: AgentHarness = { // failed handshake never registered. `task.ts` has always done this. let posthogMcp = false; try { - const { setupPostHogMcp, fetchInstructions } = await import('./mcp'); + const { setupPostHogMcp, fetchInstructions } = await import('./mcp.js'); // Overlaps the network handshake with the adapter's jiti load. const instructionsPromise = fetchInstructions( boot.credentials.host.mcpUrl, @@ -386,9 +391,9 @@ export const piBackend: AgentHarness = { // the code changes. Loaded lazily — it pulls in typebox (ESM), which must // stay out of the static module graph so CommonJS unit tests can load the // backend seam without parsing it. - const { createWizardPiTools } = await import('./tools'); - const { createWizardPiTaskTools } = await import('./tasks'); - const { createDispatchAgentTool } = await import('./subagent'); + const { createWizardPiTools } = await import('./tools.js'); + const { createWizardPiTaskTools } = await import('./tasks.js'); + const { createDispatchAgentTool } = await import('./subagent.js'); // Created once so the run loop can read the store for the completion guard. const wizardTaskTools = createWizardPiTaskTools(); // The one bash the agent (and its subagents) may use: every subprocess it @@ -680,7 +685,7 @@ export const piBackend: AgentHarness = { // task.ts pulls in typebox (ESM), which must stay out of the static module // graph so CommonJS unit tests can load the backend seam without parsing it. async runTask(inputs: TaskRunInputs): Promise { - const { runPiTask } = await import('./task'); + const { runPiTask } = await import('./task.js'); return runPiTask(inputs); }, }; diff --git a/src/lib/agent/runner/harness/pi/mcp.ts b/src/agent/runner/harness/pi/mcp.ts similarity index 97% rename from src/lib/agent/runner/harness/pi/mcp.ts rename to src/agent/runner/harness/pi/mcp.ts index eeaa3607a..ce4c59e56 100644 --- a/src/lib/agent/runner/harness/pi/mcp.ts +++ b/src/agent/runner/harness/pi/mcp.ts @@ -7,8 +7,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; import { createJiti } from 'jiti'; -import { VERSION } from '@lib/version'; -import { logToFile } from '@utils/debug'; +import { VERSION, logToFile } from '@store'; const MCP_TOKEN_ENV = 'POSTHOG_MCP_TOKEN'; diff --git a/src/lib/agent/runner/harness/pi/orchestrator-tools.ts b/src/agent/runner/harness/pi/orchestrator-tools.ts similarity index 98% rename from src/lib/agent/runner/harness/pi/orchestrator-tools.ts rename to src/agent/runner/harness/pi/orchestrator-tools.ts index 83ebbadc3..6340d514e 100644 --- a/src/lib/agent/runner/harness/pi/orchestrator-tools.ts +++ b/src/agent/runner/harness/pi/orchestrator-tools.ts @@ -13,7 +13,7 @@ import { Type } from 'typebox'; import { defineTool } from '@earendil-works/pi-coding-agent'; import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; -import { analytics } from '@utils/analytics'; +import { analytics } from '@store'; import { applyComplete, applyEnqueue, @@ -26,8 +26,8 @@ import { type CompleteArgs, type EnqueueArgs, type OrchestratorToolsContext, -} from '../../sequence/orchestrator/queue-tools'; -import { NotNeededReason } from '../../sequence/orchestrator/queue'; +} from '../../sequence/orchestrator/queue-tools.js'; +import { NotNeededReason } from '../../sequence/orchestrator/queue.js'; function text(s: string): { content: [{ type: 'text'; text: string }]; diff --git a/src/lib/agent/runner/harness/pi/runtime-notes.ts b/src/agent/runner/harness/pi/runtime-notes.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/runtime-notes.ts rename to src/agent/runner/harness/pi/runtime-notes.ts index 0d9dabfa3..502f8dfc3 100644 --- a/src/lib/agent/runner/harness/pi/runtime-notes.ts +++ b/src/agent/runner/harness/pi/runtime-notes.ts @@ -12,7 +12,7 @@ * resolved sequence calls for — shared notes always, mode notes by sequence, and * capability notes only when the task actually holds that tool. */ -import { Sequence } from '@lib/constants'; +import { Sequence } from '@store'; const HEADER = [ '## This runtime', diff --git a/src/lib/agent/runner/harness/pi/security.ts b/src/agent/runner/harness/pi/security.ts similarity index 98% rename from src/lib/agent/runner/harness/pi/security.ts rename to src/agent/runner/harness/pi/security.ts index 0ff5c811c..638bd6a02 100644 --- a/src/lib/agent/runner/harness/pi/security.ts +++ b/src/agent/runner/harness/pi/security.ts @@ -20,22 +20,19 @@ import fs from 'fs'; import path from 'path'; import type { LLMProvider, ScanMatch } from '@posthog/warlock'; -import { wizardCanUseTool } from '@lib/agent/agent-interface'; +import { wizardCanUseTool } from '../../../agent-interface.js'; import { createRepeatBlockTracker, isWizardDocumentationPath, recordExternalScan, repeatBlockReason, scanAndTriage, - type RepeatBlockTracker, -} from '@lib/yara-hooks'; -import { publishBlockingMatch, scanVerdict, - type ScanContext, -} from '@lib/yara-policy'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; + logToFile, + analytics, +} from '@store'; +import type { RepeatBlockTracker, ScanContext } from '@store/types'; /** warlock ScanMatch → the report shape `recordExternalScan` expects. */ function toReportViolation(m: ScanMatch) { diff --git a/src/lib/agent/runner/harness/pi/subagent.ts b/src/agent/runner/harness/pi/subagent.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/subagent.ts rename to src/agent/runner/harness/pi/subagent.ts index 1f5e7f7d6..e859126a6 100644 --- a/src/lib/agent/runner/harness/pi/subagent.ts +++ b/src/agent/runner/harness/pi/subagent.ts @@ -16,7 +16,7 @@ import { Type } from 'typebox'; import { defineTool } from '@earendil-works/pi-coding-agent'; import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; -import { logToFile } from '@utils/debug'; +import { logToFile } from '@store'; /** * Read-only built-ins a subagent may use. bash is supplied separately as the diff --git a/src/lib/agent/runner/harness/pi/task.ts b/src/agent/runner/harness/pi/task.ts similarity index 95% rename from src/lib/agent/runner/harness/pi/task.ts rename to src/agent/runner/harness/pi/task.ts index 7c1acf79f..f873f54ed 100644 --- a/src/lib/agent/runner/harness/pi/task.ts +++ b/src/agent/runner/harness/pi/task.ts @@ -16,42 +16,45 @@ * Loaded lazily from `index.ts` (typebox/ESM constraint, same as tools.ts). */ -import { getUI } from '@ui'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; import { + getUI, + logToFile, + analytics, Harness, Sequence, WIZARD_REMARK_EVENT_NAME, WIZARD_USER_AGENT, -} from '@lib/constants'; + REMARK_INSTRUCTION, +} from '@store'; import { allowsPostHogMcp, queueTools, renderToolInventory, -} from '@lib/agent/agent-prompt-loader'; -import { AgentErrorType } from '@lib/agent/agent-interface'; -import { REMARK_INSTRUCTION } from '@lib/agent-signals'; -import { AgentOutputSignals } from '@lib/agent/output-signals'; -import { TaskStatus } from '../../sequence/orchestrator/queue'; -import type { OrchestratorToolsContext } from '../../sequence/orchestrator/queue-tools'; -import type { AgentResult, TaskRunInputs } from '../types'; -import { gatewayAuth, type GatewayAuth } from '@lib/gateway-session'; +} from '../../../agent-prompt-loader.js'; +import { AgentErrorType } from '../../../agent-interface.js'; +import { AgentOutputSignals } from '../../../output-signals.js'; +import { TaskStatus } from '../../sequence/orchestrator/queue.js'; +import type { OrchestratorToolsContext } from '../../sequence/orchestrator/queue-tools.js'; +import type { AgentResult, TaskRunInputs } from '../types.js'; +import { + gatewayAuth, + type GatewayAuth, +} from '../../../gateway/gateway-session.js'; import { buildGatewayProvider, GATEWAY_PROVIDER, withGatewayRemint, -} from './gateway'; -import { runErrorType } from './completion'; -import { assembleCommandments } from '../../switchboard/commandments'; +} from './gateway.js'; +import { runErrorType } from './completion.js'; +import { assembleCommandments } from '../../switchboard/commandments.js'; import { applyOutroMarkers, buildScrubbedEnv, extractText, lastStatusLine, withMode, -} from './index'; -import { createAioCapture } from '@lib/agent/aio-capture'; +} from './index.js'; +import { createAioCapture } from '../../../aio-capture.js'; /** wizard tool vocabulary → the pi tool definitions it unlocks. */ const CODING_TOOL_MAP: Record = { @@ -276,13 +279,13 @@ export async function runPiTask(inputs: TaskRunInputs): Promise { // The same fail-closed fence as the linear run, with the task's disallow // list layered in (both the wizard-vocabulary and pi-short names). - const { createSecurityExtension } = await import('./security'); + const { createSecurityExtension } = await import('./security.js'); const security = createSecurityExtension({ disallowedTools: fenceDisallowList(disallowedTools), triageProvider: boot.triageProvider, getWizardAskPending: () => askState.pending, }); - const { prewarmYaraScanner } = await import('@lib/yara-hooks'); + const { prewarmYaraScanner } = await import('@store'); void prewarmYaraScanner(); // PostHog MCP, for the tasks whose prompt requests it. Tasks that never @@ -294,7 +297,7 @@ export async function runPiTask(inputs: TaskRunInputs): Promise { let posthogMcp = false; if (allowsPostHogMcp(allowedTools)) { try { - const { setupPostHogMcp } = await import('./mcp'); + const { setupPostHogMcp } = await import('./mcp.js'); const mcp = await setupPostHogMcp({ mcpUrl: boot.credentials.host.mcpUrl, accessToken: boot.credentials.accessToken, @@ -362,7 +365,7 @@ export async function runPiTask(inputs: TaskRunInputs): Promise { // Wizard env + package-manager tools are always on — their handlers are // fenced, and init/build tasks depend on them. publish_handoff rides // along (store-only handler) so the report task can publish the handoff. - const { createWizardPiTools } = await import('./tools'); + const { createWizardPiTools } = await import('./tools.js'); const wizardToolNames = allowedPiWizardTools(allowedTools); const wizardTools = createWizardPiTools({ workingDirectory: dir, @@ -377,7 +380,9 @@ export async function runPiTask(inputs: TaskRunInputs): Promise { }, }).filter((t) => wizardToolNames.has(t.name)); - const { createPiOrchestratorTools } = await import('./orchestrator-tools'); + const { createPiOrchestratorTools } = await import( + './orchestrator-tools.js' + ); const queueTools = createPiOrchestratorTools(orchestrator).filter((t) => orchestratorTools.has(t.name), ); diff --git a/src/lib/agent/runner/harness/pi/tasks.ts b/src/agent/runner/harness/pi/tasks.ts similarity index 99% rename from src/lib/agent/runner/harness/pi/tasks.ts rename to src/agent/runner/harness/pi/tasks.ts index e12f66e1e..4f4a7967c 100644 --- a/src/lib/agent/runner/harness/pi/tasks.ts +++ b/src/agent/runner/harness/pi/tasks.ts @@ -9,7 +9,7 @@ import { Type } from 'typebox'; import { defineTool } from '@earendil-works/pi-coding-agent'; import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; -import { getUI } from '@ui'; +import { getUI } from '@store'; export type TaskStatus = 'pending' | 'in_progress' | 'completed'; export interface TaskEntry { diff --git a/src/lib/agent/runner/harness/pi/tools.ts b/src/agent/runner/harness/pi/tools.ts similarity index 97% rename from src/lib/agent/runner/harness/pi/tools.ts rename to src/agent/runner/harness/pi/tools.ts index b194cc79a..5ae177532 100644 --- a/src/lib/agent/runner/harness/pi/tools.ts +++ b/src/agent/runner/harness/pi/tools.ts @@ -16,9 +16,9 @@ import path from 'path'; import { Type } from 'typebox'; import { defineTool } from '@earendil-works/pi-coding-agent'; import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; -import { analytics } from '@utils/analytics'; -import { logToFile } from '@utils/debug'; import { + analytics, + logToFile, AUDIT_ADD_CHECKS_DESCRIPTION, AUDIT_ADD_CHECKS_PARAM_DESCRIPTION, AUDIT_RESOLVE_CHECKS_DESCRIPTION, @@ -52,24 +52,24 @@ import { WIZARD_ASK_SENSITIVE_DESCRIPTION, WIZARD_ASK_SUBJECT_DESCRIPTION, WIZARD_ASK_TOOL_DESCRIPTION, -} from '@lib/wizard-tools/tools'; -import type { LLMProvider } from '@posthog/warlock'; -import { isFullyCancelled, type WizardAskBridge } from '@lib/wizard-ask-bridge'; -import { + isFullyCancelled, PUBLISH_HANDOFF_CONTENT_DESCRIPTION, PUBLISH_HANDOFF_DESCRIPTION, PUBLISH_HANDOFF_TOOL_NAME, publishHandoff, -} from '@lib/wizard-tools/handoff'; -import { createSecretVault } from '@lib/secret-vault'; -import { AUDIT_CHECKS_FILE } from '@lib/programs/audit/types'; -import type { AuditCheck, AuditStatus } from '@lib/programs/audit/types'; -import { makeMutex } from '@utils/atomic-ledger'; -import { withMode } from './index'; -import { + createSecretVault, + makeMutex, detectNodePackageManagers, - type PackageManagerDetector, -} from '@lib/detection/package-manager'; +} from '@store'; +import type { LLMProvider } from '@posthog/warlock'; +import type { + WizardAskBridge, + AuditCheck, + AuditStatus, + PackageManagerDetector, +} from '@store/types'; +import { AUDIT_CHECKS_FILE } from '@store/programs'; +import { withMode } from './index.js'; function text(s: string): { content: [{ type: 'text'; text: string }]; diff --git a/src/lib/agent/runner/harness/types.ts b/src/agent/runner/harness/types.ts similarity index 87% rename from src/lib/agent/runner/harness/types.ts rename to src/agent/runner/harness/types.ts index f5fa53099..ab30310d4 100644 --- a/src/lib/agent/runner/harness/types.ts +++ b/src/agent/runner/harness/types.ts @@ -15,22 +15,18 @@ * rather than silently downgrading. */ -import type { WizardSession } from '@lib/wizard-session'; -import type { AdditionalFeature } from '@lib/wizard-session'; -import type { Harness } from '@lib/constants'; -import type { ProgramRunConfig } from '@lib/program-run'; -import type { SpinnerHandle } from '@ui'; -import type { WizardAskBridge } from '@lib/wizard-ask-bridge'; -import type { AgentErrorType } from '@lib/agent/agent-interface'; -import type { OrchestratorToolsContext } from '@lib/agent/runner/sequence/orchestrator/queue-tools'; import type { - EffortLevel, - ThinkingLevel, -} from '@lib/agent/runner/switchboard/models'; -import type { - ProgramRun, - BootstrapResult, -} from '@lib/agent/runner/shared/types'; + WizardSession, + AdditionalFeature, + Harness, + ProgramRunConfig, + SpinnerHandle, + WizardAskBridge, +} from '@store/types'; +import type { AgentErrorType } from '../../agent-interface.js'; +import type { OrchestratorToolsContext } from '../sequence/orchestrator/queue-tools.js'; +import type { EffortLevel, ThinkingLevel } from '../switchboard/models.js'; +import type { ProgramRun, BootstrapResult } from '../shared/types.js'; /** The benchmark/telemetry hook threaded through a run, if enabled. */ export interface RunMiddleware { diff --git a/src/lib/agent/runner/index.ts b/src/agent/runner/index.ts similarity index 91% rename from src/lib/agent/runner/index.ts rename to src/agent/runner/index.ts index f9ee5f3f8..a48098a96 100644 --- a/src/lib/agent/runner/index.ts +++ b/src/agent/runner/index.ts @@ -16,27 +16,26 @@ * [skill install] → agent init → prompt → run → errors → [postRun] → outro */ -import type { WizardSession } from '../../wizard-session'; -import { analytics } from '@utils/analytics'; +import type { WizardSession, ProgramRunConfig } from '@store/types'; import { + analytics, Sequence, WIZARD_ORCHESTRATOR_FLAG_KEY, WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY, -} from '@lib/constants'; -import { logToFile } from '@utils/debug'; -import { getUI } from '../../../ui'; -import type { ProgramRunConfig } from '@lib/program-run'; -import type { ProgramRun, BootstrapResult } from './shared/types'; -import { bootstrapProgram } from './shared/bootstrap'; + logToFile, + getUI, + flushScanReport, + registerCleanup, +} from '@store'; +import type { ProgramRun, BootstrapResult } from './shared/types.js'; +import { bootstrapProgram } from './shared/bootstrap.js'; import { getSequence, resolveBinding, type ProgramBinding, type SwitchboardCtx, -} from './switchboard'; -import { flushScanReport } from '../../yara-hooks'; -import { startAuditLedgerWatcher } from '../../programs/audit/ledger-watcher'; -import { registerCleanup } from '../../../utils/wizard-abort'; +} from './switchboard/index.js'; +import { startAuditLedgerWatcher } from '@store/programs'; export type { ProgramRun, @@ -45,8 +44,8 @@ export type { AbortCase, PromptContext, Credentials, -} from './shared/types'; -export { shouldDisableAsk } from './shared/bootstrap'; +} from './shared/types.js'; +export { shouldDisableAsk } from './shared/bootstrap.js'; /** * Resolve a ProgramRunConfig's agent run definition and execute the pipeline. diff --git a/src/lib/agent/runner/sequence/README.md b/src/agent/runner/sequence/README.md similarity index 100% rename from src/lib/agent/runner/sequence/README.md rename to src/agent/runner/sequence/README.md diff --git a/src/lib/agent/runner/sequence/linear.ts b/src/agent/runner/sequence/linear.ts similarity index 92% rename from src/lib/agent/runner/sequence/linear.ts rename to src/agent/runner/sequence/linear.ts index e7654ac62..13f416489 100644 --- a/src/lib/agent/runner/sequence/linear.ts +++ b/src/agent/runner/sequence/linear.ts @@ -5,33 +5,31 @@ * program-level static metadata (tool allow/disallow lists, etc.). */ -import type { WizardSession } from '../../../wizard-session'; -import { OutroKind } from '../../../wizard-session'; -import { getUI } from '../../../../ui'; -import { AgentErrorType, AgentSignals } from '../../agent-interface'; -import { restoreClaudeSettings } from '@lib/claude-settings'; -import { logToFile } from '../../../../utils/debug'; -import { createBenchmarkPipeline } from '../../../middleware/benchmark'; +import type { WizardSession, ProgramRunConfig } from '@store/types'; import { + OutroKind, + getUI, + restoreClaudeSettings, + logToFile, wizardAbort, WizardError, registerCleanup, -} from '../../../../utils/wizard-abort'; -import { ErrorCodes, AGENT_ERROR_CODE } from '@lib/errors'; -import { analytics } from '../../../../utils/analytics'; -import { + ErrorCodes, + AGENT_ERROR_CODE, + analytics, formatScanReport, formatYaraAbortMessage, writeScanReport, -} from '../../../yara-hooks'; -import { installSkillById } from '../../../wizard-tools'; -import { createWizardAskBridge } from '../../../wizard-ask-bridge'; -import type { ProgramRunConfig } from '@lib/program-run'; -import { assemblePrompt } from '../../agent-prompt'; -import type { ProgramRun, BootstrapResult } from '../shared/types'; -import { abortOnInstallFailure } from '../shared/errors'; -import { shouldDisableAsk, sessionToOptions } from '../shared/bootstrap'; -import { resolveHarness, getHarness } from '../switchboard'; + installSkillById, + createWizardAskBridge, +} from '@store'; +import { AgentErrorType, AgentSignals } from '../../agent-interface.js'; +import { createBenchmarkPipeline } from '../../middleware/benchmark.js'; +import { assemblePrompt } from '../../agent-prompt.js'; +import type { ProgramRun, BootstrapResult } from '../shared/types.js'; +import { abortOnInstallFailure } from '../shared/errors.js'; +import { shouldDisableAsk, sessionToOptions } from '../shared/bootstrap.js'; +import { resolveHarness, getHarness } from '../switchboard/index.js'; export async function runLinearProgram( session: WizardSession, diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts similarity index 90% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts index 49e60ce34..074e31483 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/completed-seeded-types.test.ts @@ -9,15 +9,12 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); -import { - QueueStore, - SkipReason, -} from '@lib/agent/runner/sequence/orchestrator/queue'; -import { completedSeededTypes } from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +import { QueueStore, SkipReason } from '../queue.js'; +import { completedSeededTypes } from '../orchestrator-runner.js'; describe('completedSeededTypes', () => { let dir: string; diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/executor.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/executor.test.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/executor.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/executor.test.ts index f83794ad8..ea1183a59 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/executor.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/executor.test.ts @@ -6,16 +6,13 @@ import { TaskStatus, type QueuedTask, type TaskHandoff, -} from '@lib/agent/runner/sequence/orchestrator/queue'; -import { - drainQueue, - type RunTask, -} from '@lib/agent/runner/sequence/orchestrator/executor'; +} from '../queue.js'; +import { drainQueue, type RunTask } from '../executor.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { captureException: vi.fn(), wizardCapture: vi.fn() }, })); -import { analytics } from '@utils/analytics'; +import { analytics } from '@store/shared/analytics'; const HANDOFF: TaskHandoff = { goals: 'g', did: 'd', forNextAgent: 'n' }; diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts similarity index 96% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts index 62b147804..5e0ad62e2 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/handoff-schema-parity.test.ts @@ -10,11 +10,11 @@ import { HANDOFF_FIELDS, HANDOFF_SHAPE_KEYS, type OrchestratorToolsContext, -} from '../queue-tools'; +} from '../queue-tools.js'; import { createPiOrchestratorTools, PI_HANDOFF_PARAM_KEYS, -} from '../../../harness/pi/orchestrator-tools'; +} from '../../../harness/pi/orchestrator-tools.js'; describe('complete_task handoff schema', () => { it('exposes the same fields on both harnesses', () => { diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts similarity index 88% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts index 85e130bce..8073e5db3 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/optional-tasks.test.ts @@ -3,12 +3,12 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); -import { QueueStore } from '@lib/agent/runner/sequence/orchestrator/queue'; -import { drainVerdict } from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +import { QueueStore } from '../queue.js'; +import { drainVerdict } from '../orchestrator-runner.js'; describe('drainVerdict', () => { let dir: string; diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts similarity index 96% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts index 3ee223d9e..531acef6b 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/queue-tools.test.ts @@ -2,14 +2,10 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { z } from 'zod'; -import { analytics } from '@utils/analytics'; -import { - NotNeededReason, - QueueStore, - SkipReason, -} from '@lib/agent/runner/sequence/orchestrator/queue'; +import { analytics } from '@store/shared/analytics'; +import { NotNeededReason, QueueStore, SkipReason } from '../queue.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn() }, })); import { @@ -22,12 +18,9 @@ import { ENQUEUE_MODEL_DESCRIPTION, NOT_NEEDED_REASON_ASK, type OrchestratorToolsContext, -} from '@lib/agent/runner/sequence/orchestrator/queue-tools'; -import { PI_COMPLETE_PARAM_KEYS } from '@lib/agent/runner/harness/pi/orchestrator-tools'; -import { - isValidModel, - VALID_MODELS, -} from '@lib/agent/runner/switchboard/models'; +} from '../queue-tools.js'; +import { PI_COMPLETE_PARAM_KEYS } from '../../../harness/pi/orchestrator-tools.js'; +import { isValidModel, VALID_MODELS } from '../../../switchboard/models.js'; function tmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'queue-tools-test-')); diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/queue.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/queue.test.ts similarity index 99% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/queue.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/queue.test.ts index cb306ef5b..2fc5c0692 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/queue.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/queue.test.ts @@ -11,9 +11,9 @@ import { type QueuedTask, type TaskHandoff, type TransitionEvent, -} from '@lib/agent/runner/sequence/orchestrator/queue'; +} from '../queue.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { captureException: vi.fn(), wizardCapture: vi.fn() }, })); diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts index da82af353..7579a71e4 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/run-metrics.test.ts @@ -1,4 +1,4 @@ -import { RunMetrics } from '@lib/agent/runner/sequence/orchestrator/run-metrics'; +import { RunMetrics } from '../run-metrics.js'; describe('RunMetrics', () => { it('reports time to first start and first completion from run start', () => { diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts similarity index 94% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts index d2379b32c..70731f199 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/seeded-decline-skip.test.ts @@ -10,10 +10,10 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@ui', () => ({ +vi.mock('@store/ui', () => ({ getUI: () => ({ showTaskNotice: vi.fn(), cancelTaskNotice: vi.fn() }), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), setTag: vi.fn(), @@ -25,14 +25,14 @@ vi.mock('@utils/analytics', () => ({ import { skipDeclinedSeededTasks, type SeededConsent, -} from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +} from '../orchestrator-runner.js'; import { QueueStore, SkipReason, TaskStatus, type TransitionEvent, type QueuedTask, -} from '@lib/agent/runner/sequence/orchestrator/queue'; +} from '../queue.js'; const KEPT: SeededConsent = { keep: true, timedOut: false, errored: false }; const DECLINED: SeededConsent = { diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts similarity index 98% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts index 2a3069188..a3151612b 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/seeded-deps.test.ts @@ -10,18 +10,12 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); -import { - QueueStore, - type QueuedTask, -} from '@lib/agent/runner/sequence/orchestrator/queue'; -import { - deferSeededTasks, - seededDependencies, -} from '@lib/agent/runner/sequence/orchestrator/seeded-deps'; +import { QueueStore, type QueuedTask } from '../queue.js'; +import { deferSeededTasks, seededDependencies } from '../seeded-deps.js'; const SINKS = ['report']; diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts index 9372bfc1d..e17c3b558 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/sink-closure.test.ts @@ -7,23 +7,20 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn() }, })); -import { - QueueStore, - SkipReason, -} from '@lib/agent/runner/sequence/orchestrator/queue'; -import { displayOrder } from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +import { QueueStore, SkipReason } from '../queue.js'; +import { displayOrder } from '../orchestrator-runner.js'; import { applyEnqueue, checkEnqueueGuards, dependencyClosure, uncoveredBySink, type OrchestratorToolsContext, -} from '@lib/agent/runner/sequence/orchestrator/queue-tools'; -import { seededDependencies } from '@lib/agent/runner/sequence/orchestrator/seeded-deps'; +} from '../queue-tools.js'; +import { seededDependencies } from '../seeded-deps.js'; const VALID = ['warehouse', 'install', 'capture', 'report']; const SINKS = ['report']; diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts similarity index 98% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts index 6a04c2ab8..883c2cd85 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/skill-sweep.test.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { promoteReferenceSkill, sweepRunInstalledSkills, -} from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +} from '../orchestrator-runner.js'; function makeSkill(root: string, id: string, wizardMarked: boolean): string { const dir = path.join(root, id); diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts similarity index 98% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts index c6acf1014..85383b089 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/task-notice-timeout.test.ts @@ -7,7 +7,7 @@ * the run — so the offer is made at seed time, and only the work it gates is * deferred to the end of the queue. */ -import type { TaskNotice } from '@lib/wizard-session'; +import type { TaskNotice } from '@store/session/wizard-session'; // Hoisted: `vi.mock` factories are lifted above the imports, so the analytics // factory would otherwise read these before they exist. @@ -19,10 +19,10 @@ const { showTaskNotice, cancelTaskNotice, wizardCapture, captureException } = captureException: vi.fn(), })); -vi.mock('@ui', () => ({ +vi.mock('@store/ui', () => ({ getUI: () => ({ showTaskNotice, cancelTaskNotice }), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture, setTag: vi.fn(), @@ -36,7 +36,7 @@ import { consentSkipReason, offerSeededTask, TASK_NOTICE_TIMEOUT_MS, -} from '@lib/agent/runner/sequence/orchestrator/orchestrator-runner'; +} from '../orchestrator-runner.js'; const NOTICE: TaskNotice = { title: 'Connect your data sources', diff --git a/src/lib/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts b/src/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts rename to src/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts index b3f302b37..b3ead9dcf 100644 --- a/src/lib/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts +++ b/src/agent/runner/sequence/orchestrator/__tests__/variant-resolution.test.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; -import { resolveSkillVariantId } from '../orchestrator-runner'; -import { Integration } from '@lib/constants'; -import { expandBundleEntry } from '@lib/wizard-tools'; -import type { SkillEntry } from '@lib/wizard-tools'; +import { resolveSkillVariantId } from '../orchestrator-runner.js'; +import { Integration } from '@store/shared/constants'; +import { expandBundleEntry } from '@store/tools'; +import type { SkillEntry } from '@store/tools'; // Pinned from the real built skill-menu.json, so this suite tests the actual cross-repo contract. const INTEGRATION_ENTRIES = [ diff --git a/src/lib/agent/runner/sequence/orchestrator/executor.ts b/src/agent/runner/sequence/orchestrator/executor.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/executor.ts rename to src/agent/runner/sequence/orchestrator/executor.ts index 616d29442..ccec96d85 100644 --- a/src/lib/agent/runner/sequence/orchestrator/executor.ts +++ b/src/agent/runner/sequence/orchestrator/executor.ts @@ -9,9 +9,8 @@ * The drain loop is independent of how a task actually runs. `runTask` is * injected: the real one spins up a fresh agent, the tests use a fake. */ -import { analytics } from '@utils/analytics'; -import { logToFile } from '@utils/debug'; -import { TaskStatus, type QueueStore, type QueuedTask } from './queue'; +import { analytics, logToFile } from '@store'; +import { TaskStatus, type QueueStore, type QueuedTask } from './queue.js'; /** Per-task agent configuration the resolver produces from a task's type. * The model is resolved separately (per-harness profile), not here. */ diff --git a/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts b/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts rename to src/agent/runner/sequence/orchestrator/orchestrator-runner.ts index 0e981e2cd..ff41d7dec 100644 --- a/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts +++ b/src/agent/runner/sequence/orchestrator/orchestrator-runner.ts @@ -22,54 +22,51 @@ import { import * as path from 'path'; import { OutroKind, - type TaskNotice, - type WizardSession, -} from '@lib/wizard-session'; -import { POSTHOG_DOCS_URL, WIZARD_CONTACT_EMAIL, - type Integration, -} from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { + FRAMEWORK_REGISTRY, installSkillById, fetchSkillMenu, - type SkillEntry, -} from '@lib/wizard-tools'; -import { getUI } from '@ui'; -import { analytics } from '@utils/analytics'; -import { ciExcludedTaskTypes } from '@utils/ci-flag-overrides'; -import { logToFile } from '@utils/debug'; -import { ringTerminalBell } from '@utils/terminal-bell'; -import { wizardAbort, WizardError } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; -import type { ProgramRunConfig } from '@lib/program-run'; -import type { BootstrapResult, ProgramRun } from '../../shared/types'; + getUI, + analytics, + ciExcludedTaskTypes, + logToFile, + ringTerminalBell, + wizardAbort, + WizardError, + ErrorCodes, + createWizardAskBridge, + LONGER_ASK_TIMEOUT_MS, +} from '@store'; +import type { + TaskNotice, + WizardSession, + Integration, + SkillEntry, + ProgramRunConfig, +} from '@store/types'; +import type { BootstrapResult, ProgramRun } from '../../shared/types.js'; import { areSeededTasksEnabled, getHarness, resolveHarness, resolveStageOverrides, type HarnessPick, -} from '../../switchboard'; -import { isValidModel, requireKnownModel } from '../../switchboard/models'; -import type { AgentHarness } from '../../harness/types'; +} from '../../switchboard/index.js'; +import { isValidModel, requireKnownModel } from '../../switchboard/models.js'; +import type { AgentHarness } from '../../harness/types.js'; import { QueueStore, QUEUE_DIR_NAME, SkipReason, TaskStatus, type QueuedTask, -} from './queue'; -import { drainQueue, type RunTask } from './executor'; -import { RunMetrics } from './run-metrics'; -import { dependencyClosure, uncoveredBySink } from './queue-tools'; -import { deferSeededTasks } from './seeded-deps'; -import { - createWizardAskBridge, - LONGER_ASK_TIMEOUT_MS, -} from '@lib/wizard-ask-bridge'; -import { shouldDisableAsk } from '../../shared/bootstrap'; +} from './queue.js'; +import { drainQueue, type RunTask } from './executor.js'; +import { RunMetrics } from './run-metrics.js'; +import { dependencyClosure, uncoveredBySink } from './queue-tools.js'; +import { deferSeededTasks } from './seeded-deps.js'; +import { shouldDisableAsk } from '../../shared/bootstrap.js'; import { agentRunTools, assembleSeedPrompt, @@ -81,7 +78,7 @@ import { ASK_TOOL, type AgentPrompt, type OrchestratorPromptContext, -} from '@lib/agent/agent-prompt-loader'; +} from '../../../agent-prompt-loader.js'; /** Docs page (`django.md`, `nuxt-js-3-6.md`) — steps start with a digit, agent artifacts (`SKILL.md`, `EXAMPLE*`, `COMMANDMENTS.md`) have uppercase. */ const isDocPage = (name: string): boolean => diff --git a/src/lib/agent/runner/sequence/orchestrator/queue-tools.ts b/src/agent/runner/sequence/orchestrator/queue-tools.ts similarity index 99% rename from src/lib/agent/runner/sequence/orchestrator/queue-tools.ts rename to src/agent/runner/sequence/orchestrator/queue-tools.ts index 2e2955823..7bc04d5e3 100644 --- a/src/lib/agent/runner/sequence/orchestrator/queue-tools.ts +++ b/src/agent/runner/sequence/orchestrator/queue-tools.ts @@ -7,11 +7,8 @@ * `buildOrchestratorTools` wraps them in the SDK `tool()` shape. */ import { z } from 'zod'; -import { analytics } from '@utils/analytics'; -import { - isValidModel, - VALID_MODELS, -} from '@lib/agent/runner/switchboard/models'; +import { analytics } from '@store'; +import { isValidModel, VALID_MODELS } from '../../switchboard/models.js'; import { isNotNeededReason, NotNeededReason, @@ -20,7 +17,7 @@ import { type QueueStore, type QueuedTask, type TaskHandoff, -} from './queue'; +} from './queue.js'; /** * The `complete_task` `notNeededReason` description, shared by both harnesses' diff --git a/src/lib/agent/runner/sequence/orchestrator/queue.ts b/src/agent/runner/sequence/orchestrator/queue.ts similarity index 99% rename from src/lib/agent/runner/sequence/orchestrator/queue.ts rename to src/agent/runner/sequence/orchestrator/queue.ts index 5896ef07e..7cca69703 100644 --- a/src/lib/agent/runner/sequence/orchestrator/queue.ts +++ b/src/agent/runner/sequence/orchestrator/queue.ts @@ -14,8 +14,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { randomUUID } from 'crypto'; -import { writeJsonAtomic } from '@utils/atomic-ledger'; -import { analytics } from '@utils/analytics'; +import { writeJsonAtomic, analytics } from '@store'; export const TaskStatus = { Pending: 'pending', diff --git a/src/lib/agent/runner/sequence/orchestrator/run-metrics.ts b/src/agent/runner/sequence/orchestrator/run-metrics.ts similarity index 100% rename from src/lib/agent/runner/sequence/orchestrator/run-metrics.ts rename to src/agent/runner/sequence/orchestrator/run-metrics.ts diff --git a/src/lib/agent/runner/sequence/orchestrator/seeded-deps.ts b/src/agent/runner/sequence/orchestrator/seeded-deps.ts similarity index 97% rename from src/lib/agent/runner/sequence/orchestrator/seeded-deps.ts rename to src/agent/runner/sequence/orchestrator/seeded-deps.ts index 396c58083..216165ff2 100644 --- a/src/lib/agent/runner/sequence/orchestrator/seeded-deps.ts +++ b/src/agent/runner/sequence/orchestrator/seeded-deps.ts @@ -17,8 +17,8 @@ * Pure and store-reading only — the runner applies what this returns, and the * queue enforces the DAG. */ -import type { QueuedTask, QueueStore } from './queue'; -import { dependencyClosure } from './queue-tools'; +import type { QueuedTask, QueueStore } from './queue.js'; +import { dependencyClosure } from './queue-tools.js'; export interface SeededDepsResult { /** Ids the seeded task should be made to wait for. */ diff --git a/src/lib/agent/runner/shared/bootstrap.ts b/src/agent/runner/shared/bootstrap.ts similarity index 90% rename from src/lib/agent/runner/shared/bootstrap.ts rename to src/agent/runner/shared/bootstrap.ts index 4924a61a1..63880ad4b 100644 --- a/src/lib/agent/runner/shared/bootstrap.ts +++ b/src/agent/runner/shared/bootstrap.ts @@ -7,40 +7,45 @@ * effects. Returns the values the arms still need. */ -import type { WizardSession } from '@lib/wizard-session'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; -import { authenticate, refreshAccessTokenIfNeeded } from './authenticate'; -import { maybeStampAiSdkDetected } from '@lib/programs/posthog-integration/detect'; -import { createTriageLLMProvider } from '@lib/agent/triage-provider'; -import { gatewayAuth } from '@lib/gateway-session'; -import { resolveHarness } from '../switchboard'; -import { buildRunTags } from '@lib/agent/agent-interface'; +import type { + WizardSession, + WizardRunOptions, + ProgramRunConfig, +} from '@store/types'; import { + analytics, + getUI, + authenticate, + refreshAccessTokenIfNeeded, checkAllSettingsConflicts, backupAndFixClaudeSettings, classifySettingsConflicts, -} from '@lib/claude-settings'; -import { evaluateWizardReadiness, WizardReadiness, SIGNUP_WIZARD_READINESS_CONFIG, getBlockingServiceKeys, SERVICE_LABELS, -} from '@lib/health-checks/readiness'; -import { enableDebugLogs, logToFile, initLogFile } from '@utils/debug'; -import { wizardAbort } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; -import { isNonInteractiveEnvironment } from '@utils/environment'; -import { CallType, getSkillsBaseUrl, IS_DEV } from '@lib/constants'; -import { VERSION } from '@lib/version'; -import { mcpUrlFor } from '@lib/host-resolution'; -import type { WizardRunOptions } from '@utils/types'; -import type { ProgramRunConfig } from '@lib/program-run'; -import { shouldDisableAsk } from '@lib/ask-policy'; + enableDebugLogs, + logToFile, + initLogFile, + wizardAbort, + ErrorCodes, + isNonInteractiveEnvironment, + CallType, + getSkillsBaseUrl, + VERSION, + mcpUrlFor, + shouldDisableAsk, +} from '@store'; +import { maybeStampAiSdkDetected } from '@store/programs'; +import { createTriageLLMProvider } from '../../triage-provider.js'; +import { gatewayAuth } from '../../gateway/gateway-session.js'; +import { resolveHarness } from '../switchboard/index.js'; +import { buildRunTags } from '../../agent-interface.js'; +import { IS_DEV } from '@env'; export { shouldDisableAsk }; -import type { ProgramRun, BootstrapResult } from './types'; +import type { ProgramRun, BootstrapResult } from './types.js'; // ── Helpers ────────────────────────────────────────────────────────── diff --git a/src/lib/agent/runner/shared/errors.ts b/src/agent/runner/shared/errors.ts similarity index 86% rename from src/lib/agent/runner/shared/errors.ts rename to src/agent/runner/shared/errors.ts index 376cb45d4..320b9216b 100644 --- a/src/lib/agent/runner/shared/errors.ts +++ b/src/agent/runner/shared/errors.ts @@ -2,9 +2,8 @@ * Shared error helpers for the runner pipeline. */ -import type { InstallSkillResult } from '@lib/wizard-tools'; -import { skillErrorCode } from '@lib/errors'; -import { wizardAbort, WizardError } from '@utils/wizard-abort'; +import type { InstallSkillResult } from '@store/types'; +import { skillErrorCode, wizardAbort, WizardError } from '@store'; export async function abortOnInstallFailure( integrationLabel: string, diff --git a/src/lib/agent/runner/shared/types.ts b/src/agent/runner/shared/types.ts similarity index 91% rename from src/lib/agent/runner/shared/types.ts rename to src/agent/runner/shared/types.ts index 830c43a8d..8020ebcec 100644 --- a/src/lib/agent/runner/shared/types.ts +++ b/src/agent/runner/shared/types.ts @@ -3,8 +3,7 @@ * `@lib/program-run`; the agent re-exports it for its own modules. */ -import type { Credentials } from '@lib/wizard-session'; -import type { ApiProject } from '@lib/api'; +import type { Credentials, ApiProject } from '@store/types'; import type { LLMProvider } from '@posthog/warlock'; export type { @@ -13,7 +12,7 @@ export type { AbortCase, ProgramRun, ProgramRunConfig, -} from '@lib/program-run'; +} from '@store/types'; /** * Result of the shared bootstrap, consumed by both the linear and the diff --git a/src/lib/agent/runner/switchboard/commandments.ts b/src/agent/runner/switchboard/commandments.ts similarity index 97% rename from src/lib/agent/runner/switchboard/commandments.ts rename to src/agent/runner/switchboard/commandments.ts index 8cc9aed08..74b88a54d 100644 --- a/src/lib/agent/runner/switchboard/commandments.ts +++ b/src/agent/runner/switchboard/commandments.ts @@ -12,9 +12,12 @@ * an import cycle. */ -import { Harness, Sequence } from '@lib/constants'; -import { WIZARD_COMMANDMENTS } from '@lib/agent/commandments'; -import { piRuntimeNotes, type RuntimeCaps } from '../harness/pi/runtime-notes'; +import { Harness, Sequence } from '@store'; +import { WIZARD_COMMANDMENTS } from '../../commandments.js'; +import { + piRuntimeNotes, + type RuntimeCaps, +} from '../harness/pi/runtime-notes.js'; // ── Sequence axis ─────────────────────────────────────────────────────── diff --git a/src/lib/agent/runner/switchboard/flags/__tests__/binding-cases.ts b/src/agent/runner/switchboard/flags/__tests__/binding-cases.ts similarity index 91% rename from src/lib/agent/runner/switchboard/flags/__tests__/binding-cases.ts rename to src/agent/runner/switchboard/flags/__tests__/binding-cases.ts index ebddc32e2..8e4241f12 100644 --- a/src/lib/agent/runner/switchboard/flags/__tests__/binding-cases.ts +++ b/src/agent/runner/switchboard/flags/__tests__/binding-cases.ts @@ -4,13 +4,13 @@ * `runBindingCases` turns a table into `it` blocks — specs stay declarative. */ import { describe, it, expect } from 'vitest'; -import { GPT5_6_SOL_MODEL, Harness, Sequence } from '@lib/constants'; +import { GPT5_6_SOL_MODEL, Harness, Sequence } from '@store/shared/constants'; import { resolveBinding, type SwitchboardCtx, type SwitchboardTrace, -} from '@lib/agent/runner/switchboard'; -import type { EffortLevel } from '@lib/agent/runner/switchboard/models'; +} from '../../index.js'; +import type { EffortLevel } from '../../models.js'; /** The complete resolved binding — every axis stated, nothing implicit. */ export interface ExpectedBinding { diff --git a/src/lib/agent/runner/switchboard/flags/__tests__/flags.test.ts b/src/agent/runner/switchboard/flags/__tests__/flags.test.ts similarity index 97% rename from src/lib/agent/runner/switchboard/flags/__tests__/flags.test.ts rename to src/agent/runner/switchboard/flags/__tests__/flags.test.ts index f0540ab5b..5b784d335 100644 --- a/src/lib/agent/runner/switchboard/flags/__tests__/flags.test.ts +++ b/src/agent/runner/switchboard/flags/__tests__/flags.test.ts @@ -3,8 +3,8 @@ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { join, dirname } from 'node:path'; import { describe, it, expect, vi } from 'vitest'; -import { PROGRAM_REGISTRY } from '@lib/programs/program-registry'; -import * as constants from '@lib/constants'; +import { PROGRAM_REGISTRY } from '@store/programs/program-registry'; +import * as constants from '@store/shared/constants'; import { DEFAULT_AGENT_MODEL, GPT5_6_SOL_MODEL, @@ -14,19 +14,19 @@ import { WIZARD_ORCHESTRATOR_FLAG_KEY, WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY, WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY, -} from '@lib/constants'; +} from '@store/shared/constants'; import { areSeededTasksEnabled, resolveBinding, resolveStageOverrides, type SwitchboardCtx, -} from '@lib/agent/runner/switchboard'; +} from '../../index.js'; import { ORCHESTRATOR_SEQUENCE_ROUTE, ORCHESTRATOR_HARNESS_ROUTE, -} from '@lib/agent/runner/switchboard/flags/orchestrator'; -import { SELF_DRIVING_EXPERIMENT } from '@lib/agent/runner/switchboard/flags/self-driving'; -import { runBindingCases } from './binding-cases'; +} from '../orchestrator.js'; +import { SELF_DRIVING_EXPERIMENT } from '../self-driving.js'; +import { runBindingCases } from './binding-cases.js'; const envState = vi.hoisted(() => ({ runSurface: 'local' as 'cloud' | 'local', diff --git a/src/lib/agent/runner/switchboard/flags/index.ts b/src/agent/runner/switchboard/flags/index.ts similarity index 88% rename from src/lib/agent/runner/switchboard/flags/index.ts rename to src/agent/runner/switchboard/flags/index.ts index b9d3d03a2..4d0bccbee 100644 --- a/src/lib/agent/runner/switchboard/flags/index.ts +++ b/src/agent/runner/switchboard/flags/index.ts @@ -5,15 +5,14 @@ * shapes and resolution. */ import { RUN_SURFACE } from '@env'; -import { logToFile } from '@utils/debug'; -import type { Sequence } from '@lib/constants'; -import type { ProgramId } from '@lib/programs/program-registry'; +import { logToFile } from '@store'; +import type { Sequence, ProgramId } from '@store/types'; import { ORCHESTRATOR_HARNESS_ROUTE, ORCHESTRATOR_SEQUENCE_ROUTE, ORCHESTRATOR_STAGE_OVERRIDES, -} from './orchestrator'; -import { SELF_DRIVING_EXPERIMENT } from './self-driving'; +} from './orchestrator.js'; +import { SELF_DRIVING_EXPERIMENT } from './self-driving.js'; import { routeFromConfigFlag, stageOverridesFromPayload, @@ -21,7 +20,7 @@ import { type HarnessExperiment, type SequenceExperiment, type StageOverride, -} from './schemes'; +} from './schemes.js'; /** Every experiment on each axis. An experiment routes ONLY by being listed here, and only for the programs it declares. */ export const HARNESS_EXPERIMENTS: readonly HarnessExperiment[] = [ @@ -74,11 +73,14 @@ export function resolveStageOverrides( return overrides; } -export { isOrchestratorEnabled, areSeededTasksEnabled } from './orchestrator'; +export { + isOrchestratorEnabled, + areSeededTasksEnabled, +} from './orchestrator.js'; export type { ConfigFlag, FlagRoute, HarnessExperiment, SequenceExperiment, StageOverride, -} from './schemes'; +} from './schemes.js'; diff --git a/src/lib/agent/runner/switchboard/flags/orchestrator.ts b/src/agent/runner/switchboard/flags/orchestrator.ts similarity index 98% rename from src/lib/agent/runner/switchboard/flags/orchestrator.ts rename to src/agent/runner/switchboard/flags/orchestrator.ts index 544e00b83..eed87724a 100644 --- a/src/lib/agent/runner/switchboard/flags/orchestrator.ts +++ b/src/agent/runner/switchboard/flags/orchestrator.ts @@ -5,8 +5,8 @@ import { WIZARD_ORCHESTRATOR_FLAG_KEY, WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY, WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY, -} from '@lib/constants'; -import type { HarnessExperiment, SequenceExperiment } from './schemes'; +} from '@store'; +import type { HarnessExperiment, SequenceExperiment } from './schemes.js'; export const ORCHESTRATOR_SEQUENCE_ROUTE: SequenceExperiment = { programs: ['posthog-integration'], diff --git a/src/lib/agent/runner/switchboard/flags/schemes.ts b/src/agent/runner/switchboard/flags/schemes.ts similarity index 97% rename from src/lib/agent/runner/switchboard/flags/schemes.ts rename to src/agent/runner/switchboard/flags/schemes.ts index f55f30141..019aeac34 100644 --- a/src/lib/agent/runner/switchboard/flags/schemes.ts +++ b/src/agent/runner/switchboard/flags/schemes.ts @@ -12,10 +12,10 @@ import { Harness, Sequence, SONNET_5_MODEL, -} from '@lib/constants'; -import type { ProgramId } from '@lib/programs/program-registry'; -import { logToFile } from '@utils/debug'; -import type { EffortLevel } from '../models'; + logToFile, +} from '@store'; +import type { ProgramId } from '@store/types'; +import type { EffortLevel } from '../models.js'; // ── Shared vocabulary ───────────────────────────────────────────────────── diff --git a/src/lib/agent/runner/switchboard/flags/self-driving.ts b/src/agent/runner/switchboard/flags/self-driving.ts similarity index 78% rename from src/lib/agent/runner/switchboard/flags/self-driving.ts rename to src/agent/runner/switchboard/flags/self-driving.ts index beb34ea90..a874e0e4f 100644 --- a/src/lib/agent/runner/switchboard/flags/self-driving.ts +++ b/src/agent/runner/switchboard/flags/self-driving.ts @@ -6,8 +6,8 @@ * Routes: ONLY `self-driving` — any axis the payload pins. A missing or * invalid payload keeps the non-flagged binding default. */ -import { WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY } from '@lib/constants'; -import type { HarnessExperiment } from './schemes'; +import { WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY } from '@store'; +import type { HarnessExperiment } from './schemes.js'; export const SELF_DRIVING_EXPERIMENT: HarnessExperiment = { program: 'self-driving', diff --git a/src/lib/agent/runner/switchboard/harness.ts b/src/agent/runner/switchboard/harness.ts similarity index 91% rename from src/lib/agent/runner/switchboard/harness.ts rename to src/agent/runner/switchboard/harness.ts index 8710a166f..ca83bcaeb 100644 --- a/src/lib/agent/runner/switchboard/harness.ts +++ b/src/agent/runner/switchboard/harness.ts @@ -3,12 +3,11 @@ */ import { IS_PRODUCTION_BUILD } from '@env'; -import { Harness } from '@lib/constants'; -import { logToFile } from '@utils/debug'; -import { anthropicBackend } from '../harness/anthropic'; -import { piBackend } from '../harness/pi'; -import type { AgentHarness } from '../harness/types'; -import { resolveFlagRoute } from './flags'; +import { Harness, logToFile } from '@store'; +import { anthropicBackend } from '../harness/anthropic/index.js'; +import { piBackend } from '../harness/pi/index.js'; +import type { AgentHarness } from '../harness/types.js'; +import { resolveFlagRoute } from './flags/index.js'; import { DEFAULT_BINDING, PROGRAM_BINDINGS, @@ -16,7 +15,7 @@ import { type HarnessPick, type Middleware, type SwitchboardCtx, -} from '.'; +} from './index.js'; export const HARNESS_OPTIONS: Partial> = { [Harness.anthropic]: anthropicBackend, diff --git a/src/lib/agent/runner/switchboard/index.ts b/src/agent/runner/switchboard/index.ts similarity index 96% rename from src/lib/agent/runner/switchboard/index.ts rename to src/agent/runner/switchboard/index.ts index f6d641a66..7bcbe2ab8 100644 --- a/src/lib/agent/runner/switchboard/index.ts +++ b/src/agent/runner/switchboard/index.ts @@ -6,11 +6,11 @@ import { GPT5_6_TERRA_MODEL, Harness, Sequence, -} from '@lib/constants'; -import type { ProgramId } from '@lib/programs/program-registry'; -import { resolveHarness } from './harness'; -import type { EffortLevel } from './models'; -import { resolveSequence } from './sequence'; +} from '@store'; +import type { ProgramId } from '@store/types'; +import { resolveHarness } from './harness.js'; +import type { EffortLevel } from './models.js'; +import { resolveSequence } from './sequence.js'; // ── Shared machinery ──────────────────────────────────────────────────── @@ -179,15 +179,15 @@ export function resolveBinding( } // ── Unified re-export surface ─────────────────────────────────────────── -export { HARNESS_OPTIONS, getHarness, resolveHarness } from './harness'; +export { HARNESS_OPTIONS, getHarness, resolveHarness } from './harness.js'; export { SEQUENCE_OPTIONS, getSequence, resolveSequence, type SequenceRunner, -} from './sequence'; +} from './sequence.js'; export { isOrchestratorEnabled, areSeededTasksEnabled, resolveStageOverrides, -} from './flags'; +} from './flags/index.js'; diff --git a/src/lib/agent/runner/switchboard/models.ts b/src/agent/runner/switchboard/models.ts similarity index 99% rename from src/lib/agent/runner/switchboard/models.ts rename to src/agent/runner/switchboard/models.ts index ab8d4b202..2ed82ff62 100644 --- a/src/lib/agent/runner/switchboard/models.ts +++ b/src/agent/runner/switchboard/models.ts @@ -7,7 +7,7 @@ import { GPT5_6_TERRA_MODEL, HAIKU_TRIAGE_MODEL, Harness, -} from '@lib/constants'; +} from '@store'; /** Reasoning effort, mapped by each harness to its provider transport. */ const THINKING_LEVELS = [ diff --git a/src/lib/agent/runner/switchboard/sequence.ts b/src/agent/runner/switchboard/sequence.ts similarity index 93% rename from src/lib/agent/runner/switchboard/sequence.ts rename to src/agent/runner/switchboard/sequence.ts index ff8b415a6..3350c13b4 100644 --- a/src/lib/agent/runner/switchboard/sequence.ts +++ b/src/agent/runner/switchboard/sequence.ts @@ -4,26 +4,24 @@ */ import { IS_PRODUCTION_BUILD } from '@env'; -import { Sequence } from '@lib/constants'; -import { logToFile } from '@utils/debug'; +import { Sequence, logToFile } from '@store'; import { isOrchestratorEnabled, resolveFlagRoute, resolveFlagSequence, -} from './flags'; -import { getHarness, resolveHarness } from './harness'; -import type { WizardSession } from '@lib/wizard-session'; -import type { ProgramRunConfig } from '@lib/program-run'; -import type { ProgramRun, BootstrapResult } from '../shared/types'; -import { runLinearProgram } from '../sequence/linear'; -import { runOrchestrator } from '../sequence/orchestrator/orchestrator-runner'; +} from './flags/index.js'; +import { getHarness, resolveHarness } from './harness.js'; +import type { WizardSession, ProgramRunConfig } from '@store/types'; +import type { ProgramRun, BootstrapResult } from '../shared/types.js'; +import { runLinearProgram } from '../sequence/linear.js'; +import { runOrchestrator } from '../sequence/orchestrator/orchestrator-runner.js'; import { DEFAULT_BINDING, PROGRAM_BINDINGS, runChain, type Middleware, type SwitchboardCtx, -} from '.'; +} from './index.js'; // ── Registry ──────────────────────────────────────────────────────────── diff --git a/src/lib/agent/stored-login.ts b/src/agent/stored-login.ts similarity index 98% rename from src/lib/agent/stored-login.ts rename to src/agent/stored-login.ts index 3a9ca812f..dd09baa70 100644 --- a/src/lib/agent/stored-login.ts +++ b/src/agent/stored-login.ts @@ -22,8 +22,7 @@ import * as fs from 'fs'; import * as os from 'os'; import path from 'path'; import { spawnSync } from 'node:child_process'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; +import { logToFile, analytics } from '@store'; /** macOS keychain service name Claude Code stores its login under. */ const KEYCHAIN_SERVICE = 'Claude Code-credentials'; diff --git a/src/agent/testing/fake-harness.ts b/src/agent/testing/fake-harness.ts new file mode 100644 index 000000000..ceb86bc5a --- /dev/null +++ b/src/agent/testing/fake-harness.ts @@ -0,0 +1,28 @@ +import type { Harness } from '@store/types'; +import type { + AgentHarness, + AgentResult, + BackendRunInputs, + TaskRunInputs, +} from '../runner/harness/types.js'; + +/** Records every run and task input; returns the scripted result. */ +export class FakeAgentHarness implements AgentHarness { + readonly runs: BackendRunInputs[] = []; + readonly tasks: TaskRunInputs[] = []; + + constructor( + readonly name: Harness, + private readonly result: AgentResult = {}, + ) {} + + run(inputs: BackendRunInputs): Promise { + this.runs.push(inputs); + return Promise.resolve(this.result); + } + + runTask(inputs: TaskRunInputs): Promise { + this.tasks.push(inputs); + return Promise.resolve(this.result); + } +} diff --git a/src/lib/wizard-tools/mcp.ts b/src/agent/tools/mcp.ts similarity index 97% rename from src/lib/wizard-tools/mcp.ts rename to src/agent/tools/mcp.ts index 4ad43e235..464c60399 100644 --- a/src/lib/wizard-tools/mcp.ts +++ b/src/agent/tools/mcp.ts @@ -11,29 +11,16 @@ import path from 'path'; import fs from 'fs'; import { z } from 'zod'; -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; -import { makeMutex } from '@utils/atomic-ledger'; -import type { PackageManagerDetector } from '../detection/package-manager'; -import { - AUDIT_CHECKS_FILE, - type AuditCheck, - type AuditStatus, -} from '../programs/audit/types'; -import { type WizardAskBridge, isFullyCancelled } from '../wizard-ask-bridge'; import { + logToFile, + analytics, + makeMutex, + isFullyCancelled, PUBLISH_HANDOFF_CONTENT_DESCRIPTION, PUBLISH_HANDOFF_DESCRIPTION, PUBLISH_HANDOFF_TOOL_NAME, publishHandoff, -} from './handoff'; -import { createSecretVault, type SecretVault } from '../secret-vault'; -import { - buildOrchestratorTools, - type OrchestratorToolsContext, -} from '../agent/runner/sequence/orchestrator/queue-tools'; -import type { LLMProvider } from '@posthog/warlock'; -import { + createSecretVault, DEFAULT_ASK_MAX_QUESTIONS, CHECK_ENV_KEYS_DESCRIPTION, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION, @@ -56,7 +43,6 @@ import { templateEnvWriteRefusal, legacyKeyNameRefusal, vaultSensitiveAnswers, - type SkillEntry, AUDIT_ADD_CHECKS_DESCRIPTION, AUDIT_ADD_CHECKS_PARAM_DESCRIPTION, AUDIT_RESOLVE_CHECKS_DESCRIPTION, @@ -68,7 +54,21 @@ import { WIZARD_ASK_SENSITIVE_DESCRIPTION, WIZARD_ASK_SUBJECT_DESCRIPTION, WIZARD_ASK_TOOL_DESCRIPTION, -} from './tools'; +} from '@store'; +import type { + PackageManagerDetector, + AuditCheck, + AuditStatus, + WizardAskBridge, + SecretVault, + SkillEntry, +} from '@store/types'; +import { AUDIT_CHECKS_FILE } from '@store/programs'; +import { + buildOrchestratorTools, + type OrchestratorToolsContext, +} from '../runner/sequence/orchestrator/queue-tools.js'; +import type { LLMProvider } from '@posthog/warlock'; const auditCheckSchema = z.object({ id: z.string().min(1), diff --git a/src/lib/agent/triage-provider.ts b/src/agent/triage-provider.ts similarity index 95% rename from src/lib/agent/triage-provider.ts rename to src/agent/triage-provider.ts index dfb03861d..5694f5456 100644 --- a/src/lib/agent/triage-provider.ts +++ b/src/agent/triage-provider.ts @@ -5,16 +5,15 @@ * transport, reasoning effort and trace headers come from one place. */ -import { Harness } from '@lib/constants'; -import { logToFile } from '@utils/debug'; +import { Harness, logToFile } from '@store'; import { buildGatewayModel, gatewayApiFor, -} from '@lib/agent/runner/harness/pi/gateway'; +} from './runner/harness/pi/gateway.js'; import { modelCapabilities, triageModelFor, -} from '@lib/agent/runner/switchboard/models'; +} from './runner/switchboard/models.js'; import type { LLMProvider } from '@posthog/warlock'; const TRIAGE_MAX_TOKENS = 16_384; diff --git a/src/agent/tsconfig.json b/src/agent/tsconfig.json new file mode 100644 index 000000000..0e302c6e2 --- /dev/null +++ b/src/agent/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../.tsbuild/agent" + }, + "include": ["**/*", "../../types/**/*.d.ts"], + "references": [ + { + "path": "../../tsconfig.env.json" + }, + { + "path": "../store" + } + ], + "exclude": ["vitest.config.ts"] +} diff --git a/src/agent/types.ts b/src/agent/types.ts index e2742b91f..59c0fde4d 100644 --- a/src/agent/types.ts +++ b/src/agent/types.ts @@ -1,2 +1,19 @@ -/** Shape of the agent surface. Populated by the surface split (P1 to P3). */ -export {}; +/** Shape of the agent surface. Type-only re-exports keep it free of runtime imports. */ +import type { runAgent } from './runner/index.js'; + +/** One independent agent run. */ +export type RunAgent = typeof runAgent; +export type { BootstrapResult } from './runner/shared/types.js'; +export type { + AgentHarness, + AgentResult, + BackendRunInputs, + RunMiddleware, + TaskRunInputs, +} from './runner/harness/types.js'; +export type { + HarnessPick, + ProgramBinding, + SwitchboardCtx, + SwitchboardTrace, +} from './runner/switchboard/index.js'; diff --git a/src/agent/vitest.config.ts b/src/agent/vitest.config.ts new file mode 100644 index 000000000..d758f0006 --- /dev/null +++ b/src/agent/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineProject } from 'vitest/config'; +import { surfaceProject } from '../../vitest.shared.js'; + +export default defineProject( + surfaceProject({ + name: 'agent', + imports: ['env', 'store', 'agent'], + ink: 'forbidden', + }), +); diff --git a/src/cli/README.md b/src/cli/README.md new file mode 100644 index 000000000..b89be84d7 --- /dev/null +++ b/src/cli/README.md @@ -0,0 +1,32 @@ +# cli + +Composition root. Parses argv, selects a surface, and forwards to the three +surfaces' public entries. Holds no domain logic. + +## Owns + +- `main.ts`: installs `LoggingUI`, the detection agent, and the MCP prompt + runner, then registers every command. `bin.ts` imports it after the Node + preflight. +- `wizard.ts`, `commands/`: yargs surface. `runners/`: TUI and headless runners + that sequence independent agent runs and pass context between them. + +## May import + +Every surface, but only through `@store`, `@store/types`, `@store/programs`, +`@agent`, `@agent/types`, `@tui`, `@tui/types`, and `@tui/console`. + +## Tests + +`pnpm test:cli` and `pnpm typecheck:cli`. `vitest.config.ts` resolves every +surface; `ink` throws, so a command that loads the TUI eagerly fails here. +`testing/fake-surfaces.ts` provides `fakeRunAgent` (typed `RunAgent`) and +`fakeStartTUI` (a real store behind `StoreUI`). `__tests__/contract.test.ts` +pins unique command names and aliases and the fakes' types. + +## Typecheck layout + +`tsconfig.solution.json` lists the composite projects (`tsconfig.env.json`, +`src//tsconfig.json`, `src/__tests__/architecture`, `e2e-harness`); +`pnpm typecheck` runs `tsc -b` on it so a forbidden import fails to compile. The +root `tsconfig.json` is the whole-tree view for tsx, editors, and Vitest. diff --git a/src/__tests__/basic-integration-cli.test.ts b/src/cli/__tests__/basic-integration-cli.test.ts similarity index 91% rename from src/__tests__/basic-integration-cli.test.ts rename to src/cli/__tests__/basic-integration-cli.test.ts index 470122d69..d7c0f2d7d 100644 --- a/src/__tests__/basic-integration-cli.test.ts +++ b/src/cli/__tests__/basic-integration-cli.test.ts @@ -1,6 +1,6 @@ -import { basicIntegrationCommand } from '../commands/basic-integration'; -import { HEADLESS_FLAG } from '../lib/headless-mode'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { basicIntegrationCommand } from '../commands/basic-integration/index.js'; +import { HEADLESS_FLAG } from '@store/shared/headless-mode'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; describe('basic-integration parsing (end-to-end yargs)', () => { test('parses flags into camelCased argv keys', async () => { diff --git a/src/cli/__tests__/bin-preflight.test.ts b/src/cli/__tests__/bin-preflight.test.ts new file mode 100644 index 000000000..fa4b771b2 --- /dev/null +++ b/src/cli/__tests__/bin-preflight.test.ts @@ -0,0 +1,23 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import { describe, expect, it } from 'vitest'; +import { ErrorCodes } from '@store'; +import { PHW_ERROR_PREFIX } from '@store/shared/errors/emit'; + +const HERE = path.dirname(fileURLToPath(import.meta.url)); +const source = fs.readFileSync(path.resolve(HERE, '../../../bin.ts'), 'utf8'); + +describe('bin.ts preflight', () => { + it('loads no surface before the Node version check', () => { + const statics = + source.match(/^import .* from '(@|\.\/src\/)[^']*';$/gm) ?? []; + expect(statics).toEqual([]); + expect(source).toContain("await import('./src/cli/main.js')"); + }); + + it('prints the same machine readable line as emitWizardError', () => { + expect(source).toContain(`${PHW_ERROR_PREFIX} \${JSON.stringify({`); + expect(source).toContain(`code: '${ErrorCodes.CliNodeVersion}'`); + }); +}); diff --git a/src/__tests__/cli.test.ts b/src/cli/__tests__/cli.test.ts similarity index 94% rename from src/__tests__/cli.test.ts rename to src/cli/__tests__/cli.test.ts index 2b8a723f7..e3316ba2a 100644 --- a/src/__tests__/cli.test.ts +++ b/src/cli/__tests__/cli.test.ts @@ -18,7 +18,7 @@ const { mockStreamAttach, mockStreamShutdown, mockStreamDestinations } = // destinations, not about whether a stream exists. mockStreamDestinations: vi.fn(), })); -vi.mock('../lib/task-stream/index', () => ({ +vi.mock('@store/task-stream/task-stream-push', () => ({ // shutdown() hardcodes a resolved Promise (not a bare vi.fn) so the // interactive runWizard's dangling SIGTERM handler — which calls // shutdown().catch() and outlives these tests — never hits undefined.catch. @@ -34,16 +34,20 @@ vi.mock('../lib/task-stream/index', () => ({ return Promise.resolve(); } }, +})); +vi.mock('@store/task-stream/destinations/posthog', () => ({ PostHogDestination: class { readonly name = 'posthog'; }, +})); +vi.mock('@store/task-stream/destinations/file', () => ({ createFileDestination: (value: unknown) => value === undefined || value === null || value === false ? null : { name: 'file', path: '/tmp/task-stream.jsonl' }, })); -vi.mock('../ui/tui/store', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/state/store', async (importOriginal) => ({ + ...(await importOriginal()), WizardStore: class { session: unknown; setRunPhase = vi.fn(); @@ -55,14 +59,15 @@ vi.mock('../ui/tui/store', async (importOriginal) => ({ vi.mock('semver', () => ({ satisfies: () => true })); // importOriginal keeps real exports (e.g. RunPhase) while overriding // buildSession — vitest throws on access to exports a partial mock omits. -vi.mock('../lib/wizard-session', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/session/wizard-session', async (importOriginal) => ({ + ...(await importOriginal()), buildSession: mockBuildSessionCli, })); -vi.mock('../utils/provisioning', () => ({ +vi.mock('@store/shared/provisioning', () => ({ provisionNewAccount: mockProvisionNewAccountCli, })); -vi.mock('../ui/tui/start-tui', () => ({ +vi.mock('@tui', () => ({ + setAgentBridge: vi.fn(), startTUI: () => ({ unmount: vi.fn(), store: { @@ -75,7 +80,7 @@ vi.mock('../ui/tui/start-tui', () => ({ }, }), })); -vi.mock('../lib/programs/posthog-integration/index', () => ({ +vi.mock('@store/programs/posthog-integration', () => ({ posthogIntegrationConfig: { id: 'posthog-integration', steps: [], @@ -88,32 +93,33 @@ vi.mock('../lib/programs/posthog-integration/index', () => ({ run: () => Promise.resolve(), }, })); -vi.mock('../utils/environment', () => ({ +vi.mock('@store/shared/environment', () => ({ isNonInteractiveEnvironment: () => false, readEnvironment: () => ({}), })); // CI-path dynamic imports need mocks to prevent unhandled rejections -vi.mock('../utils/env-api-key', () => ({ +vi.mock('@store/shared/env-api-key', () => ({ readApiKeyFromEnv: () => undefined, })); -vi.mock('../utils/debug', () => ({ +vi.mock('@store/shared/debug', () => ({ configureLogFileFromEnvironment: vi.fn(), logToFile: vi.fn(), })); -vi.mock('../lib/registry', () => ({ FRAMEWORK_REGISTRY: {} })); -vi.mock('../lib/detection/index', () => ({ +vi.mock('@store/registry', () => ({ FRAMEWORK_REGISTRY: {} })); +vi.mock('@store/detection', () => ({ detectFramework: vi.fn().mockResolvedValue(null), gatherFrameworkContext: vi.fn().mockResolvedValue({}), })); -vi.mock('../utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { setTag: vi.fn() }, })); -vi.mock('../utils/wizard-abort', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/wizard-abort', async (importOriginal) => ({ + ...(await importOriginal()), wizardAbort: vi.fn(), })); -vi.mock('../lib/agent/agent-runner', () => ({ +vi.mock('@agent', () => ({ runAgent: vi.fn().mockResolvedValue(undefined), + detectProjectsWithAgent: vi.fn(), })); describe('CLI argument parsing', () => { @@ -172,7 +178,7 @@ describe('CLI argument parsing', () => { try { // vi.resetModules() (afterEach) clears the registry, so this re-evaluates // bin.ts fresh on every call — the vitest equivalent of isolateModules. - await import('../../bin'); + await import('../../../bin.js'); } catch { // process.exit mock throws to halt handler execution } @@ -285,7 +291,7 @@ describe('CLI argument parsing', () => { // from a buildSession arg — so assert the URL the run would actually fetch. async function skillsBaseUrl(): Promise<{ actual: string; local: string }> { const { getSkillsBaseUrl, LOCAL_SKILLS_BASE_URL } = await import( - '../lib/constants' + '@store/shared/constants' ); return { actual: getSkillsBaseUrl(), local: LOCAL_SKILLS_BASE_URL }; } @@ -325,7 +331,7 @@ describe('CLI argument parsing', () => { // A global `local` would silently erase `--local` from // `wizard mcp add --help`; a global's `hidden` beats a command-level one. test('no global option is named `local`', async () => { - const { GLOBAL_OPTIONS } = await import('../wizard'); + const { GLOBAL_OPTIONS } = await import('../wizard.js'); expect(Object.keys(GLOBAL_OPTIONS)).not.toContain('local'); }); }); @@ -444,7 +450,7 @@ describe('CLI argument parsing', () => { '/tmp/test', ]); - const { analytics } = await import('../utils/analytics'); + const { analytics } = await import('@store/shared/analytics'); expect(analytics.setTag).toHaveBeenCalledWith('build', 'ci'); }); @@ -527,7 +533,7 @@ describe('CLI argument parsing', () => { '/tmp/test', ]); - const { analytics } = await import('../utils/analytics'); + const { analytics } = await import('@store/shared/analytics'); expect(analytics.setTag).toHaveBeenCalledWith('build', 'headless'); expect(analytics.setTag).not.toHaveBeenCalledWith('build', 'ci'); }); @@ -544,7 +550,7 @@ describe('CLI argument parsing', () => { '/tmp/test', ]); - const { analytics } = await import('../utils/analytics'); + const { analytics } = await import('@store/shared/analytics'); expect(analytics.setTag).toHaveBeenCalledWith('build', 'headless'); expect(analytics.setTag).not.toHaveBeenCalledWith('build', 'ci'); }); diff --git a/src/cli/__tests__/contract.test.ts b/src/cli/__tests__/contract.test.ts new file mode 100644 index 000000000..76a1d363c --- /dev/null +++ b/src/cli/__tests__/contract.test.ts @@ -0,0 +1,70 @@ +import { expectTypeOf } from 'vitest'; +import type { RunAgent } from '@agent/types'; +import { Program } from '@store/programs'; +import type { TuiHandle } from '@tui/types'; +import { commandKeys } from '../commands/command.js'; +import { fakeRunAgent, fakeStartTUI } from '../testing/fake-surfaces.js'; +import type { Command } from '../types.js'; +import { basicIntegrationCommand } from '../commands/basic-integration/index.js'; +import { mcpCommand } from '../commands/mcp/index.js'; +import { mcpAnalyticsCommand } from '../commands/mcp-analytics.js'; +import { replayVisionCommand } from '../commands/replay-vision.js'; +import { aiObservabilityCommand } from '../commands/ai-observability.js'; +import { metricsCommand } from '../commands/metrics.js'; +import { auditCommand } from '../commands/audit.js'; +import { doctorCommand } from '../commands/doctor.js'; +import { migrateCommand } from '../commands/migrate.js'; +import { revenueCommand } from '../commands/revenue.js'; +import { warehouseCommand } from '../commands/warehouse.js'; +import { selfDrivingCommand } from '../commands/self-driving.js'; +import { slackCommand } from '../commands/slack.js'; +import { uploadSourcemapsCommand } from '../commands/upload-sourcemaps.js'; +import { errorTrackingCommand } from '../commands/error-tracking.js'; +import { skillCommand } from '../commands/skill.js'; +import { cliCommand } from '../commands/cli/index.js'; + +/** Every command main.ts registers. */ +const COMMANDS: readonly Command[] = [ + basicIntegrationCommand, + mcpCommand, + mcpAnalyticsCommand, + replayVisionCommand, + aiObservabilityCommand, + metricsCommand, + cliCommand, + auditCommand, + doctorCommand, + migrateCommand, + revenueCommand, + warehouseCommand, + selfDrivingCommand, + slackCommand, + uploadSourcemapsCommand, + errorTrackingCommand, + skillCommand, +]; + +describe('cli contract', () => { + it('registers commands with unique names and aliases', () => { + const keys = COMMANDS.flatMap((c) => commandKeys(c.name)); + expect(new Set(keys).size).toBe(keys.length); + }); + + it('every command has a description and a handler or children', () => { + for (const c of COMMANDS) { + expect(c.description.length, String(c.name)).toBeGreaterThan(0); + expect( + typeof c.handler === 'function' || (c.children?.length ?? 0) > 0, + String(c.name), + ).toBe(true); + } + }); + + it('the fakes match the surface entry types', () => { + const { runAgent } = fakeRunAgent(); + expectTypeOf(runAgent).toEqualTypeOf(); + const tui = fakeStartTUI(Program.PostHogIntegration); + expectTypeOf(tui).toMatchTypeOf(); + expect(tui.store.currentScreen).toBe('intro'); + }); +}); diff --git a/src/__tests__/headless-scope.test.ts b/src/cli/__tests__/headless-scope.test.ts similarity index 80% rename from src/__tests__/headless-scope.test.ts rename to src/cli/__tests__/headless-scope.test.ts index e6d974a31..3db06885b 100644 --- a/src/__tests__/headless-scope.test.ts +++ b/src/cli/__tests__/headless-scope.test.ts @@ -1,9 +1,9 @@ -import { auditCommand } from '../commands/audit'; -import { basicIntegrationCommand } from '../commands/basic-integration'; -import { revenueCommand } from '../commands/revenue'; -import { HEADLESS_FLAG } from '../lib/headless-mode'; -import { GLOBAL_OPTIONS } from '../wizard'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { auditCommand } from '../commands/audit.js'; +import { basicIntegrationCommand } from '../commands/basic-integration/index.js'; +import { revenueCommand } from '../commands/revenue.js'; +import { HEADLESS_FLAG } from '@store/shared/headless-mode'; +import { GLOBAL_OPTIONS } from '../wizard.js'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; // The experimental headless flag is scoped to exactly two surfaces — the base // integration flow (`wizard`) and `wizard audit` — rather than being a global diff --git a/src/__tests__/helpers/parse-command.no-jest.ts b/src/cli/__tests__/helpers/parse-command.no-jest.ts similarity index 95% rename from src/__tests__/helpers/parse-command.no-jest.ts rename to src/cli/__tests__/helpers/parse-command.no-jest.ts index 621c94560..b75c5fd3a 100644 --- a/src/__tests__/helpers/parse-command.no-jest.ts +++ b/src/cli/__tests__/helpers/parse-command.no-jest.ts @@ -1,7 +1,7 @@ import yargs from 'yargs'; import type { Arguments } from 'yargs'; -import { GLOBAL_OPTIONS } from '../../wizard'; -import { toCommandModule, type Command } from '../../commands/command'; +import { GLOBAL_OPTIONS } from '../../wizard.js'; +import { toCommandModule, type Command } from '../../commands/command.js'; /** * Parse an argv string through a command's real yargs configuration (global diff --git a/src/__tests__/mcp-cli.test.ts b/src/cli/__tests__/mcp-cli.test.ts similarity index 83% rename from src/__tests__/mcp-cli.test.ts rename to src/cli/__tests__/mcp-cli.test.ts index e9b41f8b3..26a7546ce 100644 --- a/src/__tests__/mcp-cli.test.ts +++ b/src/cli/__tests__/mcp-cli.test.ts @@ -11,37 +11,30 @@ const { mockBuildSessionMcp, mockStartTUIMcp, mockReadApiKeyFromEnvMcp } = mockReadApiKeyFromEnvMcp: vi.fn(() => undefined as string | undefined), })); -vi.mock('@lib/wizard-session', () => ({ +vi.mock('@store/session/wizard-session', async (importOriginal) => ({ + ...(await importOriginal()), buildSession: mockBuildSessionMcp, - // analytics.ts imports this for sessionProperties(); unused by this - // suite's assertions, stubbed only so the mocked module still satisfies - // the real module's exports. - reportableDiscoveredFeatures: () => undefined, - reportablePosthogSdkDetected: () => undefined, })); -vi.mock('@ui/tui/start-tui', () => ({ +vi.mock('@tui', () => ({ startTUI: mockStartTUIMcp, })); -vi.mock('@utils/env-api-key', () => ({ +vi.mock('@store/shared/env-api-key', () => ({ readApiKeyFromEnv: mockReadApiKeyFromEnvMcp, })); -vi.mock('@lib/programs/program-registry', () => ({ +vi.mock('@store/programs', () => ({ Program: { McpAdd: 'mcp-add', McpRemove: 'mcp-remove', McpTutorial: 'mcp-tutorial', }, - PROGRAM_REGISTRY: [], - getSubcommandPrograms: () => [], - getProgramConfig: () => ({}), })); import type { Arguments } from 'yargs'; -import { mcpAddCommand } from '../commands/mcp/add'; -import { mcpRemoveCommand } from '../commands/mcp/remove'; -import { mcpTutorialCommand } from '../commands/mcp/tutorial'; -import { mcpCommand } from '../commands/mcp'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { mcpAddCommand } from '../commands/mcp/add.js'; +import { mcpRemoveCommand } from '../commands/mcp/remove.js'; +import { mcpTutorialCommand } from '../commands/mcp/tutorial.js'; +import { mcpCommand } from '../commands/mcp/index.js'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; function makeArgv(extra: Record = {}): Arguments { return { _: [], $0: 'wizard', ...extra } as Arguments; diff --git a/src/cli/__tests__/metrics-command.test.ts b/src/cli/__tests__/metrics-command.test.ts new file mode 100644 index 000000000..f3778a1d5 --- /dev/null +++ b/src/cli/__tests__/metrics-command.test.ts @@ -0,0 +1,10 @@ +import { metricsConfig } from '@store/programs'; +import { metricsCommand } from '../commands/metrics.js'; + +describe('metrics command', () => { + it('is exposed as a yargs command via nativeCommandFactory', () => { + expect(metricsCommand.name).toBe('metrics'); + expect(metricsCommand.description).toBe(metricsConfig.description); + expect(typeof metricsCommand.handler).toBe('function'); + }); +}); diff --git a/src/__tests__/programs-cli.test.ts b/src/cli/__tests__/programs-cli.test.ts similarity index 90% rename from src/__tests__/programs-cli.test.ts rename to src/cli/__tests__/programs-cli.test.ts index 89a972809..1c4c58eb8 100644 --- a/src/__tests__/programs-cli.test.ts +++ b/src/cli/__tests__/programs-cli.test.ts @@ -3,13 +3,13 @@ const { mockRunWizard, mockRunWizardCI } = vi.hoisted(() => ({ mockRunWizardCI: vi.fn(), })); -vi.mock('@lib/runners', () => ({ +vi.mock('../runners/index.js', () => ({ runWizard: mockRunWizard, runWizardCI: mockRunWizardCI, })); -vi.mock('@lib/wizard-tools', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('@store/tools', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, fetchSkillMenu: vi.fn(), @@ -18,23 +18,20 @@ vi.mock('@lib/wizard-tools', async (importOriginal) => { import type { Arguments } from 'yargs'; import type { MockedFunction } from 'vitest'; -import { auditCommand } from '../commands/audit'; -import { migrateCommand } from '../commands/migrate'; -import { mcpAnalyticsCommand } from '../commands/mcp-analytics'; -import { replayVisionCommand } from '../commands/replay-vision'; -import { revenueCommand } from '../commands/revenue'; -import { warehouseCommand } from '../commands/warehouse'; -import { uploadSourcemapsCommand } from '../commands/upload-sourcemaps'; -import { selfDrivingCommand } from '../commands/self-driving'; -import { - dispatchFamily, - pickerChildrenToShow, -} from '@lib/programs/dispatch-family'; -import type { Command } from '../commands/command'; -import { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools'; -import { auditConfig } from '@lib/programs/audit/index'; -import { webAnalyticsDoctorConfig } from '@lib/programs/web-analytics-doctor/index'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { auditCommand } from '../commands/audit.js'; +import { migrateCommand } from '../commands/migrate.js'; +import { mcpAnalyticsCommand } from '../commands/mcp-analytics.js'; +import { replayVisionCommand } from '../commands/replay-vision.js'; +import { revenueCommand } from '../commands/revenue.js'; +import { warehouseCommand } from '../commands/warehouse.js'; +import { uploadSourcemapsCommand } from '../commands/upload-sourcemaps.js'; +import { selfDrivingCommand } from '../commands/self-driving.js'; +import { dispatchFamily, pickerChildrenToShow } from '../dispatch-family.js'; +import type { Command } from '../commands/command.js'; +import { fetchSkillMenu, type CliEntry } from '@store/tools'; +import { auditConfig } from '@store/programs/audit'; +import { webAnalyticsDoctorConfig } from '@store/programs/web-analytics-doctor'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; const mockFetchSkillMenu = fetchSkillMenu as MockedFunction< typeof fetchSkillMenu diff --git a/src/__tests__/provision-cli.test.ts b/src/cli/__tests__/provision-cli.test.ts similarity index 91% rename from src/__tests__/provision-cli.test.ts rename to src/cli/__tests__/provision-cli.test.ts index d1b561ba4..f317894da 100644 --- a/src/__tests__/provision-cli.test.ts +++ b/src/cli/__tests__/provision-cli.test.ts @@ -5,16 +5,16 @@ const { mockProvisionNewAccountSubcmd } = vi.hoisted(() => ({ })); vi.mock('semver', () => ({ satisfies: () => true })); -vi.mock('../utils/provisioning', () => ({ +vi.mock('@store/shared/provisioning', () => ({ provisionNewAccount: mockProvisionNewAccountSubcmd, })); // Same supporting mocks as src/__tests__/cli.test.ts — bin.ts imports these // at module load regardless of which subcommand yargs dispatches. -vi.mock('../lib/wizard-session', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/session/wizard-session', async (importOriginal) => ({ + ...(await importOriginal()), buildSession: vi.fn((args: Record) => args), })); -vi.mock('../ui/tui/start-tui', () => ({ +vi.mock('@tui', () => ({ startTUI: () => ({ unmount: vi.fn(), store: { @@ -27,7 +27,7 @@ vi.mock('../ui/tui/start-tui', () => ({ }, }), })); -vi.mock('../lib/programs/posthog-integration/index', () => ({ +vi.mock('@store/programs/posthog-integration', () => ({ posthogIntegrationConfig: { id: 'posthog-integration', steps: [], @@ -40,35 +40,36 @@ vi.mock('../lib/programs/posthog-integration/index', () => ({ run: () => Promise.resolve(), }, })); -vi.mock('../utils/environment', () => ({ +vi.mock('@store/shared/environment', () => ({ isNonInteractiveEnvironment: () => false, readEnvironment: () => ({}), })); -vi.mock('../utils/env-api-key', () => ({ +vi.mock('@store/shared/env-api-key', () => ({ readApiKeyFromEnv: () => undefined, })); -vi.mock('../utils/debug', () => ({ +vi.mock('@store/shared/debug', () => ({ configureLogFileFromEnvironment: vi.fn(), logToFile: vi.fn(), })); -vi.mock('../lib/registry', () => ({ FRAMEWORK_REGISTRY: {} })); -vi.mock('../lib/detection/index', () => ({ +vi.mock('@store/registry', () => ({ FRAMEWORK_REGISTRY: {} })); +vi.mock('@store/detection', () => ({ detectFramework: vi.fn().mockResolvedValue(null), gatherFrameworkContext: vi.fn().mockResolvedValue({}), })); -vi.mock('../utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { setTag: vi.fn() }, })); -vi.mock('../utils/wizard-abort', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('@store/shared/wizard-abort', async (importOriginal) => ({ + ...(await importOriginal()), wizardAbort: vi.fn(), })); -vi.mock('../lib/agent/agent-runner', () => ({ +vi.mock('@agent', () => ({ runAgent: vi.fn().mockResolvedValue(undefined), + detectProjectsWithAgent: vi.fn(), })); -import { provisionCommand } from '../commands/provision'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { provisionCommand } from '../commands/provision.js'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; describe('provision parsing (end-to-end yargs)', () => { test('parses --email and --region', async () => { @@ -184,7 +185,7 @@ describe('wizard provision subcommand', () => { // vi.resetModules() re-evaluates bin.ts fresh on each call — the vitest // equivalent of jest.isolateModules. vi.resetModules(); - await import('../../bin'); + await import('../../../bin.js'); } catch { // bin.ts dispatch can reject on some parse paths; the run's effect is // asserted via the mocks after settle(). diff --git a/src/__tests__/skill-cli.test.ts b/src/cli/__tests__/skill-cli.test.ts similarity index 89% rename from src/__tests__/skill-cli.test.ts rename to src/cli/__tests__/skill-cli.test.ts index 7acc361ab..3b1d46212 100644 --- a/src/__tests__/skill-cli.test.ts +++ b/src/cli/__tests__/skill-cli.test.ts @@ -1,19 +1,19 @@ import type { Arguments } from 'yargs'; -vi.mock('../commands/basic-integration/skill', () => ({ +vi.mock('../commands/basic-integration/skill.js', () => ({ runSkillMode: vi.fn(), })); -vi.mock('@lib/wizard-tools', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('@store/tools/tools', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, fetchSkillMenu: vi.fn() }; }); -import { runSkillMode } from '../commands/basic-integration/skill'; -import { fetchSkillMenu } from '@lib/wizard-tools'; -import { analytics } from '@utils/analytics'; -import { skillCommand } from '../commands/skill'; -import { parseCommand } from './helpers/parse-command.no-jest'; +import { runSkillMode } from '../commands/basic-integration/skill.js'; +import { fetchSkillMenu } from '@store/tools/tools'; +import { analytics } from '@store/shared/analytics'; +import { skillCommand } from '../commands/skill.js'; +import { parseCommand } from './helpers/parse-command.no-jest.js'; function makeArgv(extra: Record = {}): Arguments { return { _: [], $0: 'wizard', ...extra } as Arguments; diff --git a/src/__tests__/wizard.test.ts b/src/cli/__tests__/wizard.test.ts similarity index 84% rename from src/__tests__/wizard.test.ts rename to src/cli/__tests__/wizard.test.ts index 0b76ff294..163c061e8 100644 --- a/src/__tests__/wizard.test.ts +++ b/src/cli/__tests__/wizard.test.ts @@ -1,13 +1,13 @@ -import { commandKeys, type Command } from '../commands/command'; -import { basicIntegrationCommand } from '../commands/basic-integration'; -import { mcpCommand } from '../commands/mcp'; -import { auditCommand } from '../commands/audit'; -import { doctorCommand } from '../commands/doctor'; -import { migrateCommand } from '../commands/migrate'; -import { replayVisionCommand } from '../commands/replay-vision'; -import { revenueCommand } from '../commands/revenue'; -import { uploadSourcemapsCommand } from '../commands/upload-sourcemaps'; -import { skillCommand } from '../commands/skill'; +import { commandKeys, type Command } from '../commands/command.js'; +import { basicIntegrationCommand } from '../commands/basic-integration/index.js'; +import { mcpCommand } from '../commands/mcp/index.js'; +import { auditCommand } from '../commands/audit.js'; +import { doctorCommand } from '../commands/doctor.js'; +import { migrateCommand } from '../commands/migrate.js'; +import { replayVisionCommand } from '../commands/replay-vision.js'; +import { revenueCommand } from '../commands/revenue.js'; +import { uploadSourcemapsCommand } from '../commands/upload-sourcemaps.js'; +import { skillCommand } from '../commands/skill.js'; const cmd = (name: string | readonly string[]): Command => ({ name, diff --git a/src/commands/ai-observability.ts b/src/cli/commands/ai-observability.ts similarity index 84% rename from src/commands/ai-observability.ts rename to src/cli/commands/ai-observability.ts index abf436c45..4876d71a7 100644 --- a/src/commands/ai-observability.ts +++ b/src/cli/commands/ai-observability.ts @@ -1,7 +1,7 @@ -import { aiObservabilityConfig } from '@lib/programs/ai-observability/index'; +import { aiObservabilityConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard ai-observability` — flat skill command, wire AI Observability into a diff --git a/src/commands/audit.ts b/src/cli/commands/audit.ts similarity index 86% rename from src/commands/audit.ts rename to src/cli/commands/audit.ts index e838bbe28..a0163cd25 100644 --- a/src/commands/audit.ts +++ b/src/cli/commands/audit.ts @@ -1,7 +1,7 @@ -import { auditConfig } from '@lib/programs/audit/index'; +import { auditConfig } from '@store/programs'; -import type { Command } from './command'; -import { familyCommandFactory } from './factories/family-command-factory'; +import type { Command } from './command.js'; +import { familyCommandFactory } from './factories/family-command-factory.js'; /** * The `wizard audit` family. diff --git a/src/commands/basic-integration/__tests__/ci-install.test.ts b/src/cli/commands/basic-integration/__tests__/ci-install.test.ts similarity index 95% rename from src/commands/basic-integration/__tests__/ci-install.test.ts rename to src/cli/commands/basic-integration/__tests__/ci-install.test.ts index 934adab68..eb9a7b210 100644 --- a/src/commands/basic-integration/__tests__/ci-install.test.ts +++ b/src/cli/commands/basic-integration/__tests__/ci-install.test.ts @@ -1,4 +1,4 @@ -import { keyPrefixWarning } from '../ci-install'; +import { keyPrefixWarning } from '../ci-install.js'; /** * `--ci` and headless accept the same credentials: a personal API key and a diff --git a/src/commands/basic-integration/ci-install.ts b/src/cli/commands/basic-integration/ci-install.ts similarity index 92% rename from src/commands/basic-integration/ci-install.ts rename to src/cli/commands/basic-integration/ci-install.ts index 3956ef0ca..dbdac2fd8 100644 --- a/src/commands/basic-integration/ci-install.ts +++ b/src/cli/commands/basic-integration/ci-install.ts @@ -1,12 +1,20 @@ import type { Arguments } from 'yargs'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { API_KEY_HINT, runWizardCI, runWizardHeadless } from '@lib/runners'; -import type { NonInteractiveMode } from '@lib/runners'; -import { provisionNewAccount } from '@utils/provisioning'; -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; -import { ErrorCodes, type ErrorCode } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; +import { + getUI, + setUI, + provisionNewAccount, + ErrorCodes, + emitWizardError, +} from '@store'; +import { LoggingUI } from '@tui/console'; +import { + API_KEY_HINT, + runWizardCI, + runWizardHeadless, +} from '../../runners/index.js'; +import type { NonInteractiveMode } from '../../runners/index.js'; +import { posthogIntegrationConfig } from '@store/programs'; +import type { ErrorCode } from '@store/types'; type Options = Arguments & { region?: string; diff --git a/src/commands/basic-integration/index.ts b/src/cli/commands/basic-integration/index.ts similarity index 85% rename from src/commands/basic-integration/index.ts rename to src/cli/commands/basic-integration/index.ts index 0d1aa8739..84cbaf0a6 100644 --- a/src/commands/basic-integration/index.ts +++ b/src/cli/commands/basic-integration/index.ts @@ -1,8 +1,12 @@ -import { isNonInteractiveEnvironment } from '@utils/environment'; -import { setEntryCommand } from '@utils/links'; -import { headlessOption, isHeadless, regionOption } from '@lib/headless-mode'; -import { provisionCommand } from '../provision'; -import type { Command } from '../command'; +import { + isNonInteractiveEnvironment, + setEntryCommand, + headlessOption, + isHeadless, + regionOption, +} from '@store'; +import { provisionCommand } from '../provision.js'; +import type { Command } from '../command.js'; export const basicIntegrationCommand: Command = { name: ['$0'], @@ -57,22 +61,22 @@ export const basicIntegrationCommand: Command = { // functions end-to-end, so headless can diverge later without touching // the CI path or its callers. if (isHeadless(argv)) { - const { runHeadlessInstall } = await import('./ci-install'); + const { runHeadlessInstall } = await import('./ci-install.js'); return runHeadlessInstall(argv); } if (argv.ci) { - const { runCIInstall } = await import('./ci-install'); + const { runCIInstall } = await import('./ci-install.js'); return runCIInstall(argv); } if (isNonInteractiveEnvironment()) { - const { failNonInteractive } = await import('./non-interactive'); + const { failNonInteractive } = await import('./non-interactive.js'); return failNonInteractive(); } if (argv.playground) { - const { runPlayground } = await import('./playground'); + const { runPlayground } = await import('./playground.js'); return runPlayground(); } - const { runInteractive } = await import('./interactive'); + const { runInteractive } = await import('./interactive.js'); runInteractive(argv); })(); }, diff --git a/src/commands/basic-integration/interactive.ts b/src/cli/commands/basic-integration/interactive.ts similarity index 63% rename from src/commands/basic-integration/interactive.ts rename to src/cli/commands/basic-integration/interactive.ts index ee143f5d9..1c6299e1b 100644 --- a/src/commands/basic-integration/interactive.ts +++ b/src/cli/commands/basic-integration/interactive.ts @@ -1,6 +1,6 @@ import type { Arguments } from 'yargs'; -import { runWizard } from '@lib/runners'; -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; +import { runWizard } from '../../runners/index.js'; +import { posthogIntegrationConfig } from '@store/programs'; /** Default flow: run the posthog-integration program through the TUI. */ export function runInteractive(argv: Arguments): void { diff --git a/src/commands/basic-integration/non-interactive.ts b/src/cli/commands/basic-integration/non-interactive.ts similarity index 85% rename from src/commands/basic-integration/non-interactive.ts rename to src/cli/commands/basic-integration/non-interactive.ts index 02a47675c..c6ffb2d77 100644 --- a/src/commands/basic-integration/non-interactive.ts +++ b/src/cli/commands/basic-integration/non-interactive.ts @@ -1,6 +1,4 @@ -import { getUI } from '@ui'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; +import { getUI, ErrorCodes, emitWizardError } from '@store'; /** Print the "needs a TTY" error and exit. Used when no `--ci` flag and no TTY. */ export function failNonInteractive(): void { diff --git a/src/cli/commands/basic-integration/playground.ts b/src/cli/commands/basic-integration/playground.ts new file mode 100644 index 000000000..d2bd94228 --- /dev/null +++ b/src/cli/commands/basic-integration/playground.ts @@ -0,0 +1,7 @@ +import { VERSION } from '@store'; + +/** Launch the TUI primitives playground. */ +export async function runPlayground(): Promise { + const { startPlayground } = await import('@tui'); + startPlayground(VERSION); +} diff --git a/src/commands/basic-integration/skill.ts b/src/cli/commands/basic-integration/skill.ts similarity index 80% rename from src/commands/basic-integration/skill.ts rename to src/cli/commands/basic-integration/skill.ts index a4a2bc088..100693e39 100644 --- a/src/commands/basic-integration/skill.ts +++ b/src/cli/commands/basic-integration/skill.ts @@ -1,7 +1,7 @@ import type { Arguments } from 'yargs'; -import { POSTHOG_DOCS_URL } from '@lib/constants'; -import { runWizard, runWizardCI } from '@lib/runners'; -import { createSkillProgram } from '@lib/programs/agent-skill/index'; +import { POSTHOG_DOCS_URL } from '@store'; +import { runWizard, runWizardCI } from '../../runners/index.js'; +import { createSkillProgram } from '@store/programs'; /** Run an arbitrary context-mill skill by id (`wizard skill `, headless with `--ci`). */ export function runSkillMode(argv: Arguments): void { diff --git a/src/commands/cli/__tests__/add.test.ts b/src/cli/commands/cli/__tests__/add.test.ts similarity index 92% rename from src/commands/cli/__tests__/add.test.ts rename to src/cli/commands/cli/__tests__/add.test.ts index 44f3914cd..a5a24e72d 100644 --- a/src/commands/cli/__tests__/add.test.ts +++ b/src/cli/commands/cli/__tests__/add.test.ts @@ -21,7 +21,7 @@ const { }, })); -vi.mock('@steps/install-cli-steering', () => ({ +vi.mock('@store/services/steps/install-cli-steering', () => ({ CLI_STEERING_TARGETS: [ { id: 'codex', @@ -40,18 +40,18 @@ vi.mock('@steps/install-cli-steering', () => ({ installOrUpdatePostHogCli: mockCliAddInstallOrUpdatePostHogCli, installSteeringSnippet: mockCliAddInstallSteeringSnippet, })); -vi.mock('@ui', () => ({ +vi.mock('@store/ui', () => ({ getUI: () => mockCliAddUi, setUI: mockCliAddSetUI, })); -vi.mock('@ui/tui/console/logging-ui', () => ({ +vi.mock('@tui/console/logging-ui', () => ({ LoggingUI: vi.fn(), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: mockCliAddWizardCapture }, })); -import { cliAddCommand } from '../add'; +import { cliAddCommand } from '../add.js'; describe('cli add command', () => { const originalExit = process.exit; diff --git a/src/commands/cli/add.ts b/src/cli/commands/cli/add.ts similarity index 96% rename from src/commands/cli/add.ts rename to src/cli/commands/cli/add.ts index e500d7044..fc961f257 100644 --- a/src/commands/cli/add.ts +++ b/src/cli/commands/cli/add.ts @@ -1,18 +1,19 @@ import * as path from 'node:path'; import * as readline from 'node:readline/promises'; import type { Arguments } from 'yargs'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { analytics } from '@utils/analytics'; import { + getUI, + setUI, + analytics, CLI_STEERING_TARGETS, - type CliSteeringTarget, detectTargets, findTarget, installOrUpdatePostHogCli, installSteeringSnippet, -} from '@steps/install-cli-steering'; -import type { Command } from '../command'; +} from '@store'; +import { LoggingUI } from '@tui/console'; +import type { CliSteeringTarget } from '@store/types'; +import type { Command } from '../command.js'; export const cliAddCommand: Command = { name: 'add', diff --git a/src/commands/cli/index.ts b/src/cli/commands/cli/index.ts similarity index 61% rename from src/commands/cli/index.ts rename to src/cli/commands/cli/index.ts index 8e06b39ce..f44b3d7ac 100644 --- a/src/commands/cli/index.ts +++ b/src/cli/commands/cli/index.ts @@ -1,5 +1,5 @@ -import { cliAddCommand } from './add'; -import type { Command } from '../command'; +import { cliAddCommand } from './add.js'; +import type { Command } from '../command.js'; export const cliCommand: Command = { name: 'cli', diff --git a/src/commands/command.ts b/src/cli/commands/command.ts similarity index 98% rename from src/commands/command.ts rename to src/cli/commands/command.ts index 4f7c4c1ca..937ba11c0 100644 --- a/src/commands/command.ts +++ b/src/cli/commands/command.ts @@ -5,7 +5,7 @@ import type { Options, PositionalOptions, } from 'yargs'; -import { setEntryCommand } from '@utils/links'; +import { setEntryCommand } from '@store'; export interface Command { /** Yargs command name. Use `['$0']` for the default command. */ diff --git a/src/commands/doctor.ts b/src/cli/commands/doctor.ts similarity index 83% rename from src/commands/doctor.ts rename to src/cli/commands/doctor.ts index a663eaad2..6db0d18a6 100644 --- a/src/commands/doctor.ts +++ b/src/cli/commands/doctor.ts @@ -1,16 +1,19 @@ -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { readApiKeyFromEnv } from '@utils/env-api-key'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; -import { runWizard } from '@lib/runners'; +import { + getUI, + setUI, + readApiKeyFromEnv, + ErrorCodes, + emitWizardError, +} from '@store'; +import { LoggingUI } from '@tui/console'; +import { runWizard } from '../runners/index.js'; import { posthogDoctorConfig, fetchHealthIssues, getKindMeta, -} from '@lib/programs/posthog-doctor/index'; -import { skillProgramOptions } from './skill-program-options'; -import type { Command } from './command'; +} from '@store/programs'; +import { skillProgramOptions } from './skill-program-options.js'; +import type { Command } from './command.js'; export const doctorCommand: Command = { name: 'doctor', @@ -53,7 +56,7 @@ async function runDoctorCI(options: Record): Promise { getUI().log.info('Running posthog-doctor in CI mode'); try { - const { getOrAskForProjectData } = await import('@utils/setup-utils'); + const { getOrAskForProjectData } = await import('@store'); const { host, accessToken, projectId } = await getOrAskForProjectData({ signup: false, ci: true, @@ -87,7 +90,7 @@ async function runDoctorCI(options: Record): Promise { } process.exit(1); } catch (error) { - const { ApiError } = await import('@lib/api'); + const { ApiError } = await import('@store'); const message = error instanceof ApiError && error.statusCode === 401 ? 'Your PostHog API key is invalid or expired.' diff --git a/src/commands/error-tracking.ts b/src/cli/commands/error-tracking.ts similarity index 81% rename from src/commands/error-tracking.ts rename to src/cli/commands/error-tracking.ts index 3db0b2816..1d152e0ec 100644 --- a/src/commands/error-tracking.ts +++ b/src/cli/commands/error-tracking.ts @@ -1,7 +1,7 @@ -import { errorTrackingConfig } from '@lib/programs/error-tracking/index'; +import { errorTrackingConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard error-tracking` — flat skill command, set up error tracking today. diff --git a/src/cli/commands/factories/__tests__/audit-family.test.ts b/src/cli/commands/factories/__tests__/audit-family.test.ts new file mode 100644 index 000000000..ba6971da6 --- /dev/null +++ b/src/cli/commands/factories/__tests__/audit-family.test.ts @@ -0,0 +1,16 @@ +import { auditCommand } from '../../audit.js'; + +describe('auditCommand', () => { + it('wires interactiveDefault for the bare `wizard audit` invocation', () => { + expect(typeof auditCommand.interactiveDefault).toBe('function'); + }); + + it('routes leaves through a runtime handler (no static yargs children)', () => { + // Skill-backed audit leaves resolve via `dispatchFamily` at runtime + // against `cliEntries` in `skill-menu.json`, not via baked yargs + // children. So `auditCommand.children` is intentionally empty; the + // `[skill]` positional + handler is the routing surface. + expect(auditCommand.children).toBeUndefined(); + expect(typeof auditCommand.handler).toBe('function'); + }); +}); diff --git a/src/commands/factories/__tests__/native-command-factory.test.ts b/src/cli/commands/factories/__tests__/native-command-factory.test.ts similarity index 94% rename from src/commands/factories/__tests__/native-command-factory.test.ts rename to src/cli/commands/factories/__tests__/native-command-factory.test.ts index 9539cc3bd..42abb8e82 100644 --- a/src/commands/factories/__tests__/native-command-factory.test.ts +++ b/src/cli/commands/factories/__tests__/native-command-factory.test.ts @@ -3,16 +3,16 @@ const { mockRunWizard, mockRunWizardCI } = vi.hoisted(() => ({ mockRunWizardCI: vi.fn(), })); -vi.mock('@lib/runners', () => ({ +vi.mock('../../../runners/index.js', () => ({ runWizard: mockRunWizard, runWizardCI: mockRunWizardCI, })); import type { Arguments } from 'yargs'; -import type { ProgramConfig } from '@lib/programs/program-step'; +import type { ProgramConfig } from '@store/programs/program-step'; -import { nativeCommandFactory } from '../native-command-factory'; +import { nativeCommandFactory } from '../native-command-factory.js'; function makeArgv(extra: Record = {}): Arguments { return { _: [], $0: 'wizard', ...extra } as Arguments; diff --git a/src/commands/factories/family-command-factory.ts b/src/cli/commands/factories/family-command-factory.ts similarity index 91% rename from src/commands/factories/family-command-factory.ts rename to src/cli/commands/factories/family-command-factory.ts index 3fea1c7ea..a3d73eea5 100644 --- a/src/commands/factories/family-command-factory.ts +++ b/src/cli/commands/factories/family-command-factory.ts @@ -1,17 +1,15 @@ import type { Arguments } from 'yargs'; -import type { ProgramConfig } from '@lib/programs/program-step'; +import type { ProgramConfig } from '@store/types'; import { buildFamilyPickerChildren, dispatchFamily, pickerChildrenToShow, -} from '@lib/programs/dispatch-family'; -import { getSkillsBaseUrl } from '@lib/constants'; -import { fetchSkillMenu } from '@lib/wizard-tools'; +} from '../../dispatch-family.js'; +import { getSkillsBaseUrl, fetchSkillMenu } from '@store'; -import type { Command } from '../command'; -import { createFamilyPickerDefault } from './family-picker'; -import { mergeCommandOptions, runCommandHandler } from './shared'; +import type { Command } from '../command.js'; +import { mergeCommandOptions, runCommandHandler } from './shared.js'; export interface FamilyCommandFactoryOpts { /** The family's CLI name (e.g. 'audit'). */ @@ -61,6 +59,7 @@ export function familyCommandFactory({ await Promise.resolve(toShow[0].handler(argv)); return; } + const { createFamilyPickerDefault } = await import('@tui'); const picker = createFamilyPickerDefault(`wizard ${family}`, toShow); await picker(argv); }; diff --git a/src/commands/factories/native-command-factory.ts b/src/cli/commands/factories/native-command-factory.ts similarity index 84% rename from src/commands/factories/native-command-factory.ts rename to src/cli/commands/factories/native-command-factory.ts index d9fd65a22..35bf34539 100644 --- a/src/commands/factories/native-command-factory.ts +++ b/src/cli/commands/factories/native-command-factory.ts @@ -1,8 +1,8 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; +import type { ProgramConfig } from '@store/types'; -import type { Command } from '../command'; +import type { Command } from '../command.js'; -import { dispatchProgram, mergeCommandOptions } from './shared'; +import { dispatchProgram, mergeCommandOptions } from './shared.js'; export interface NativeCommandFactoryOpts { /** Subcommands nested under this command. */ diff --git a/src/commands/factories/shared.ts b/src/cli/commands/factories/shared.ts similarity index 86% rename from src/commands/factories/shared.ts rename to src/cli/commands/factories/shared.ts index 0cda49719..97c775ee5 100644 --- a/src/commands/factories/shared.ts +++ b/src/cli/commands/factories/shared.ts @@ -1,12 +1,14 @@ import type { Arguments, Options } from 'yargs'; -import { runWizard, runWizardCI, runWizardHeadless } from '@lib/runners'; -import { isHeadless } from '@lib/headless-mode'; -import type { ProgramConfig } from '@lib/programs/program-step'; +import { + runWizard, + runWizardCI, + runWizardHeadless, +} from '../../runners/index.js'; +import { isHeadless, ErrorCodes, emitWizardError } from '@store'; +import type { ProgramConfig } from '@store/types'; -import { skillProgramOptions } from '../skill-program-options'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; +import { skillProgramOptions } from '../skill-program-options.js'; /** * Dispatch a parsed yargs invocation to the wizard runner. Applies the diff --git a/src/commands/mcp-analytics.ts b/src/cli/commands/mcp-analytics.ts similarity index 79% rename from src/commands/mcp-analytics.ts rename to src/cli/commands/mcp-analytics.ts index 6d49b114e..b83d8e660 100644 --- a/src/commands/mcp-analytics.ts +++ b/src/cli/commands/mcp-analytics.ts @@ -1,7 +1,7 @@ -import { mcpAnalyticsConfig } from '@lib/programs/mcp-analytics/index'; +import { mcpAnalyticsConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard mcp-analytics` — flat skill command, instrument-an-MCP-server today. diff --git a/src/commands/mcp/add.ts b/src/cli/commands/mcp/add.ts similarity index 80% rename from src/commands/mcp/add.ts rename to src/cli/commands/mcp/add.ts index 49c91827b..b90eb4846 100644 --- a/src/commands/mcp/add.ts +++ b/src/cli/commands/mcp/add.ts @@ -1,11 +1,9 @@ import type { Arguments } from 'yargs'; -import { setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { headlessOption, isHeadless } from '@lib/headless-mode'; -import { Program } from '@lib/programs/program-registry'; -import { VERSION } from '@lib/version'; -import type { Command } from '../command'; -import { isTUIUnavailable } from './tui-availability'; +import { setUI, headlessOption, isHeadless, VERSION } from '@store'; +import { LoggingUI } from '@tui/console'; +import { Program } from '@store/programs'; +import type { Command } from '../command.js'; +import { isTUIUnavailable } from './tui-availability.js'; export const mcpAddCommand: Command = { name: 'add', @@ -34,7 +32,7 @@ export const mcpAddCommand: Command = { function runMcpAdd(argv: Arguments): void { const features = parseFeatures(argv.features); void (async () => { - const { readApiKeyFromEnv } = await import('@utils/env-api-key'); + const { readApiKeyFromEnv } = await import('@store'); const apiKey = (argv.apiKey as string | undefined) || readApiKeyFromEnv(); const debug = argv.debug as boolean | undefined; const localMcp = argv.local as boolean | undefined; @@ -50,8 +48,8 @@ function runMcpAdd(argv: Arguments): void { } try { - const { startTUI } = await import('@ui/tui/start-tui'); - const { buildSession } = await import('@lib/wizard-session'); + const { startTUI } = await import('@tui'); + const { buildSession } = await import('@store'); const tui = startTUI(VERSION, Program.McpAdd); tui.store.session = buildSession({ debug, @@ -73,9 +71,7 @@ async function runHeadlessAdd(args: { apiKey?: string; }): Promise { setUI(new LoggingUI()); - const { addMCPServerToClientsStep } = await import( - '@steps/add-mcp-server-to-clients/index' - ); + const { addMCPServerToClientsStep } = await import('@store'); // Never forwards `ci`: headless implies session.ci elsewhere, and the step // reads that as "skip MCP entirely" — the opposite of what we're here to do. const { installed, failed } = await addMCPServerToClientsStep(args); diff --git a/src/cli/commands/mcp/index.ts b/src/cli/commands/mcp/index.ts new file mode 100644 index 000000000..dbe8ce792 --- /dev/null +++ b/src/cli/commands/mcp/index.ts @@ -0,0 +1,10 @@ +import { mcpAddCommand } from './add.js'; +import { mcpRemoveCommand } from './remove.js'; +import { mcpTutorialCommand } from './tutorial.js'; +import type { Command } from '../command.js'; + +export const mcpCommand: Command = { + name: 'mcp', + description: 'MCP server management commands', + children: [mcpAddCommand, mcpRemoveCommand, mcpTutorialCommand], +}; diff --git a/src/commands/mcp/remove.ts b/src/cli/commands/mcp/remove.ts similarity index 73% rename from src/commands/mcp/remove.ts rename to src/cli/commands/mcp/remove.ts index 47ea3dddc..32191169d 100644 --- a/src/commands/mcp/remove.ts +++ b/src/cli/commands/mcp/remove.ts @@ -1,11 +1,9 @@ import type { Arguments } from 'yargs'; -import { setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { headlessOption, isHeadless } from '@lib/headless-mode'; -import { Program } from '@lib/programs/program-registry'; -import { VERSION } from '@lib/version'; -import type { Command } from '../command'; -import { isTUIUnavailable } from './tui-availability'; +import { setUI, headlessOption, isHeadless, VERSION } from '@store'; +import { LoggingUI } from '@tui/console'; +import { Program } from '@store/programs'; +import type { Command } from '../command.js'; +import { isTUIUnavailable } from './tui-availability.js'; export const mcpRemoveCommand: Command = { name: 'remove', @@ -35,8 +33,8 @@ function runMcpRemove(argv: Arguments): void { } try { - const { startTUI } = await import('@ui/tui/start-tui'); - const { buildSession } = await import('@lib/wizard-session'); + const { startTUI } = await import('@tui'); + const { buildSession } = await import('@store'); const tui = startTUI(VERSION, Program.McpRemove); tui.store.session = buildSession({ debug, @@ -55,8 +53,6 @@ function runMcpRemove(argv: Arguments): void { /** No exit code on an empty result: nothing to remove is the requested end state. */ async function runHeadlessRemove(local?: boolean): Promise { setUI(new LoggingUI()); - const { removeMCPServerFromClientsStep } = await import( - '@steps/add-mcp-server-to-clients/index' - ); + const { removeMCPServerFromClientsStep } = await import('@store'); await removeMCPServerFromClientsStep({ local }); } diff --git a/src/commands/mcp/tui-availability.ts b/src/cli/commands/mcp/tui-availability.ts similarity index 100% rename from src/commands/mcp/tui-availability.ts rename to src/cli/commands/mcp/tui-availability.ts diff --git a/src/commands/mcp/tutorial.ts b/src/cli/commands/mcp/tutorial.ts similarity index 73% rename from src/commands/mcp/tutorial.ts rename to src/cli/commands/mcp/tutorial.ts index 5f300e07f..716c926bc 100644 --- a/src/commands/mcp/tutorial.ts +++ b/src/cli/commands/mcp/tutorial.ts @@ -1,11 +1,8 @@ import type { Arguments } from 'yargs'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { Program } from '@lib/programs/program-registry'; -import { VERSION } from '@lib/version'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; -import type { Command } from '../command'; +import { getUI, setUI, VERSION, ErrorCodes, emitWizardError } from '@store'; +import { LoggingUI } from '@tui/console'; +import { Program } from '@store/programs'; +import type { Command } from '../command.js'; export const mcpTutorialCommand: Command = { name: 'tutorial', @@ -27,8 +24,8 @@ function runMcpTutorial(argv: Arguments): void { const localMcp = argv.local as boolean | undefined; try { - const { startTUI } = await import('@ui/tui/start-tui'); - const { buildSession } = await import('@lib/wizard-session'); + const { startTUI } = await import('@tui'); + const { buildSession } = await import('@store'); const tui = startTUI(VERSION, Program.McpTutorial); tui.store.session = buildSession({ debug, diff --git a/src/commands/metrics.ts b/src/cli/commands/metrics.ts similarity index 84% rename from src/commands/metrics.ts rename to src/cli/commands/metrics.ts index a889bd24c..7796d2cc8 100644 --- a/src/commands/metrics.ts +++ b/src/cli/commands/metrics.ts @@ -1,7 +1,7 @@ -import { metricsConfig } from '@lib/programs/metrics/index'; +import { metricsConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard metrics` — flat skill command, wire PostHog application metrics diff --git a/src/commands/migrate.ts b/src/cli/commands/migrate.ts similarity index 84% rename from src/commands/migrate.ts rename to src/cli/commands/migrate.ts index e7389efcf..5a952e19e 100644 --- a/src/commands/migrate.ts +++ b/src/cli/commands/migrate.ts @@ -1,7 +1,7 @@ -import { migrationConfig } from '@lib/programs/migration/index'; +import { migrationConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard migrate` — flat skill command, Statsig today. diff --git a/src/commands/provision.ts b/src/cli/commands/provision.ts similarity index 91% rename from src/commands/provision.ts rename to src/cli/commands/provision.ts index a113e8829..ecfebfec5 100644 --- a/src/commands/provision.ts +++ b/src/cli/commands/provision.ts @@ -1,8 +1,8 @@ import type { Arguments } from 'yargs'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import type { ProvisioningResult } from '@utils/provisioning'; -import type { Command } from './command'; +import { getUI, setUI } from '@store'; +import { LoggingUI } from '@tui/console'; +import type { ProvisioningResult } from '@store/types'; +import type { Command } from './command.js'; export const provisionCommand: Command = { name: 'provision', @@ -66,7 +66,7 @@ async function provision({ jsonMode, }: ProvisionArgs): Promise { try { - const { provisionNewAccount } = await import('@utils/provisioning'); + const { provisionNewAccount } = await import('@store'); if (!jsonMode) { getUI().log.info(`Provisioning account for ${email} in ${region}...`); } diff --git a/src/commands/replay-vision.ts b/src/cli/commands/replay-vision.ts similarity index 80% rename from src/commands/replay-vision.ts rename to src/cli/commands/replay-vision.ts index 10e8e2db9..c26857456 100644 --- a/src/commands/replay-vision.ts +++ b/src/cli/commands/replay-vision.ts @@ -1,7 +1,7 @@ -import { replayVisionConfig } from '@lib/programs/replay-vision/index'; +import { replayVisionConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard replay-vision` — flat skill command, set up Replay vision today. diff --git a/src/commands/revenue.ts b/src/cli/commands/revenue.ts similarity index 72% rename from src/commands/revenue.ts rename to src/cli/commands/revenue.ts index a41f6af09..652a862a9 100644 --- a/src/commands/revenue.ts +++ b/src/cli/commands/revenue.ts @@ -1,7 +1,7 @@ -import { revenueAnalyticsConfig } from '@lib/programs/revenue-analytics/index'; +import { revenueAnalyticsConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard revenue-analytics` — flat skill command, Stripe today. diff --git a/src/commands/self-driving.ts b/src/cli/commands/self-driving.ts similarity index 88% rename from src/commands/self-driving.ts rename to src/cli/commands/self-driving.ts index 5f38f40e4..48953163a 100644 --- a/src/commands/self-driving.ts +++ b/src/cli/commands/self-driving.ts @@ -1,7 +1,7 @@ -import { runWizard, runWizardCI } from '@lib/runners'; -import { selfDrivingConfig } from '@lib/programs/self-driving/index'; -import { skillProgramOptions } from './skill-program-options'; -import type { Command } from './command'; +import { runWizard, runWizardCI } from '../runners/index.js'; +import { selfDrivingConfig } from '@store/programs'; +import { skillProgramOptions } from './skill-program-options.js'; +import type { Command } from './command.js'; export const selfDrivingCommand: Command = { name: 'self-driving', diff --git a/src/commands/skill-program-options.ts b/src/cli/commands/skill-program-options.ts similarity index 100% rename from src/commands/skill-program-options.ts rename to src/cli/commands/skill-program-options.ts diff --git a/src/commands/skill.ts b/src/cli/commands/skill.ts similarity index 92% rename from src/commands/skill.ts rename to src/cli/commands/skill.ts index 102eff5f8..a7a0736e0 100644 --- a/src/commands/skill.ts +++ b/src/cli/commands/skill.ts @@ -1,15 +1,18 @@ import type { Arguments } from 'yargs'; -import { getSkillsBaseUrl } from '@lib/constants'; -import { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools'; -import { analytics } from '@utils/analytics'; +import { + getSkillsBaseUrl, + fetchSkillMenu, + analytics, + ErrorCodes, + emitWizardError, +} from '@store'; +import type { CliEntry } from '@store/types'; -import { runSkillMode } from './basic-integration/skill'; -import { skillProgramOptions } from './skill-program-options'; -import { runCommandHandler } from './factories/shared'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; -import type { Command } from './command'; +import { runSkillMode } from './basic-integration/skill.js'; +import { skillProgramOptions } from './skill-program-options.js'; +import { runCommandHandler } from './factories/shared.js'; +import type { Command } from './command.js'; /** Read the `` positional (yargs camelCases the hyphenated key). */ function readSkillName(argv: Arguments): string { diff --git a/src/commands/slack.ts b/src/cli/commands/slack.ts similarity index 73% rename from src/commands/slack.ts rename to src/cli/commands/slack.ts index 1b7f3735f..69b3892bd 100644 --- a/src/commands/slack.ts +++ b/src/cli/commands/slack.ts @@ -1,11 +1,8 @@ import type { Arguments } from 'yargs'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import { Program } from '@lib/programs/program-registry'; -import { VERSION } from '@lib/version'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; -import type { Command } from './command'; +import { getUI, setUI, VERSION, ErrorCodes, emitWizardError } from '@store'; +import { LoggingUI } from '@tui/console'; +import { Program } from '@store/programs'; +import type { Command } from './command.js'; export const slackCommand: Command = { name: 'slack', @@ -27,8 +24,8 @@ function runSlackConnect(argv: Arguments): void { const debug = argv.debug as boolean | undefined; try { - const { startTUI } = await import('@ui/tui/start-tui'); - const { buildSession } = await import('@lib/wizard-session'); + const { startTUI } = await import('@tui'); + const { buildSession } = await import('@store'); const tui = startTUI(VERSION, Program.SlackConnect); tui.store.session = buildSession({ debug, diff --git a/src/commands/upload-sourcemaps.ts b/src/cli/commands/upload-sourcemaps.ts similarity index 73% rename from src/commands/upload-sourcemaps.ts rename to src/cli/commands/upload-sourcemaps.ts index 22e6f96c1..47ba9e9ff 100644 --- a/src/commands/upload-sourcemaps.ts +++ b/src/cli/commands/upload-sourcemaps.ts @@ -1,7 +1,7 @@ -import { runWizard, runWizardCI } from '@lib/runners'; -import { errorTrackingUploadSourceMapsConfig } from '@lib/programs/error-tracking-upload-source-maps/index'; -import { skillProgramOptions } from './skill-program-options'; -import type { Command } from './command'; +import { runWizard, runWizardCI } from '../runners/index.js'; +import { errorTrackingUploadSourceMapsConfig } from '@store/programs'; +import { skillProgramOptions } from './skill-program-options.js'; +import type { Command } from './command.js'; export const uploadSourcemapsCommand: Command = { // Must match ProgramConfig.command; legacy alias kept for #489 regression. diff --git a/src/commands/warehouse.ts b/src/cli/commands/warehouse.ts similarity index 71% rename from src/commands/warehouse.ts rename to src/cli/commands/warehouse.ts index b6c53e0df..fee1c9441 100644 --- a/src/commands/warehouse.ts +++ b/src/cli/commands/warehouse.ts @@ -1,7 +1,7 @@ -import { warehouseSourceConfig } from '@lib/programs/warehouse-source/index'; +import { warehouseSourceConfig } from '@store/programs'; -import type { Command } from './command'; -import { nativeCommandFactory } from './factories/native-command-factory'; +import type { Command } from './command.js'; +import { nativeCommandFactory } from './factories/native-command-factory.js'; /** * `wizard warehouse` — detect and connect a data warehouse source. diff --git a/src/lib/programs/dispatch-family.ts b/src/cli/dispatch-family.ts similarity index 89% rename from src/lib/programs/dispatch-family.ts rename to src/cli/dispatch-family.ts index a730d8198..98ba1ae04 100644 --- a/src/lib/programs/dispatch-family.ts +++ b/src/cli/dispatch-family.ts @@ -1,19 +1,23 @@ import type { Arguments } from 'yargs'; -import { auditConfig } from '@lib/programs/audit/index'; -import { AUDIT_CHECKS_FILE } from '@lib/programs/audit/types'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import { agentSkillConfig } from '@lib/programs/program-registry'; -import { webAnalyticsDoctorConfig } from '@lib/programs/web-analytics-doctor/index'; -import type { ProgramConfig } from '@lib/programs/program-step'; -import { getSkillsBaseUrl } from '@lib/constants'; -import { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools'; -import { analytics } from '@utils/analytics'; +import { + auditConfig, + AUDIT_CHECKS_FILE, + agentSkillConfig, + webAnalyticsDoctorConfig, +} from '@store/programs'; +import { + WIZARD_TOOL_NAMES, + getSkillsBaseUrl, + fetchSkillMenu, + analytics, + ErrorCodes, + emitWizardError, +} from '@store'; +import type { ProgramConfig, CliEntry } from '@store/types'; -import { dispatchProgram } from '../../commands/factories/shared'; -import type { Command } from '../../commands/command'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; +import { dispatchProgram } from './commands/factories/shared.js'; +import type { Command } from './commands/command.js'; /** * Capture a CLI dispatch error, flush analytics, and exit. The wizard never diff --git a/src/cli/main.ts b/src/cli/main.ts new file mode 100644 index 000000000..bdedaf416 --- /dev/null +++ b/src/cli/main.ts @@ -0,0 +1,79 @@ +/** + * Composition root: installs the default renderer and the agent seams, then + * registers every command and hands argv to yargs. bin.ts imports this after + * its Node preflight. + */ +import { + setUI, + setDetectionAgent, + setMcpPromptRunner, + recoverOrphanedSettingsBackups, +} from '@store'; +import { Wizard } from './wizard.js'; +import { basicIntegrationCommand } from './commands/basic-integration/index.js'; +import { mcpCommand } from './commands/mcp/index.js'; +import { mcpAnalyticsCommand } from './commands/mcp-analytics.js'; +import { replayVisionCommand } from './commands/replay-vision.js'; +import { aiObservabilityCommand } from './commands/ai-observability.js'; +import { metricsCommand } from './commands/metrics.js'; +import { auditCommand } from './commands/audit.js'; +import { doctorCommand } from './commands/doctor.js'; +import { migrateCommand } from './commands/migrate.js'; +import { revenueCommand } from './commands/revenue.js'; +import { warehouseCommand } from './commands/warehouse.js'; +import { selfDrivingCommand } from './commands/self-driving.js'; +import { slackCommand } from './commands/slack.js'; +import { uploadSourcemapsCommand } from './commands/upload-sourcemaps.js'; +import { errorTrackingCommand } from './commands/error-tracking.js'; +import { skillCommand } from './commands/skill.js'; +import { cliCommand } from './commands/cli/index.js'; +import { LoggingUI } from '@tui/console'; + +// The entry point owns the default renderer; @ui ships with none. +setUI(new LoggingUI()); +// The store and the TUI never import the agent; the entry point installs it, +// lazily, so `--version` and `--help` never load the SDK or Ink. +setDetectionAgent(async (session, options) => { + const { detectProjectsWithAgent } = await import('@agent'); + return detectProjectsWithAgent(session, options); +}); +setMcpPromptRunner({ + runMcpPrompt: async function* (args) { + const { runMcpPromptViaSdk } = await import('@agent'); + yield* runMcpPromptViaSdk(args); + }, +}); + +// Heal any .claude/settings backup a previous interrupted run left orphaned, +// before anything else reads Claude settings — conflict detection, OAuth, and +// the agent all need to see the user's real settings file. The install dir is +// read directly from argv/env because yargs hasn't parsed yet. +recoverOrphanedSettingsBackups(resolveInstallDir()); + +function resolveInstallDir(): string { + const args = process.argv.slice(2); + const flagIndex = args.indexOf('--install-dir'); + if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1]; + const inline = args.find((a) => a.startsWith('--install-dir=')); + if (inline) return inline.slice('--install-dir='.length); + return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd(); +} + +Wizard.use(basicIntegrationCommand) + .use(mcpCommand) + .use(mcpAnalyticsCommand) + .use(replayVisionCommand) + .use(aiObservabilityCommand) + .use(metricsCommand) + .use(cliCommand) + .use(auditCommand) + .use(doctorCommand) + .use(migrateCommand) + .use(revenueCommand) + .use(warehouseCommand) + .use(selfDrivingCommand) + .use(slackCommand) + .use(uploadSourcemapsCommand) + .use(errorTrackingCommand) + .use(skillCommand) + .init(); diff --git a/src/lib/runners/__tests__/mint-recovery.test.ts b/src/cli/runners/__tests__/mint-recovery.test.ts similarity index 70% rename from src/lib/runners/__tests__/mint-recovery.test.ts rename to src/cli/runners/__tests__/mint-recovery.test.ts index fc5fe36b3..be4ffc62c 100644 --- a/src/lib/runners/__tests__/mint-recovery.test.ts +++ b/src/cli/runners/__tests__/mint-recovery.test.ts @@ -1,25 +1,25 @@ import { vi, it, expect, afterEach } from 'vitest'; -import { runWizard } from '../run-wizard'; -import { runAgent } from '@lib/agent/agent-runner'; -import { startTUI } from '@ui/tui/start-tui'; -import { WizardStore } from '@ui/tui/store'; -import { InkUI } from '@ui/tui/ink-ui'; -import { setUI } from '@ui'; -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration'; -import { ScreenId } from '@ui/tui/router'; -import { HostResolution } from '@lib/host-resolution'; -import { analytics } from '@utils/analytics'; -import { flowFor } from '@lib/programs/flow-for'; -import { Program } from '@lib/programs/program-registry'; +import { runWizard } from '../run-wizard.js'; +import { runAgent } from '@agent'; +import { startTUI } from '@tui'; +import { WizardStore } from '@store/state/store'; +import { StoreUI } from '@store/ui/store-ui'; +import { setUI } from '@store/ui'; +import { posthogIntegrationConfig } from '@store/programs/posthog-integration'; +import { ScreenId } from '@tui/router'; +import { HostResolution } from '@store/host-resolution'; +import { analytics } from '@store/shared/analytics'; +import { flowFor } from '@store/programs/flow-for'; +import { Program } from '@store/programs/program-registry'; -vi.mock('@lib/agent/agent-runner', () => ({ runAgent: vi.fn() })); -vi.mock('@ui/tui/start-tui', () => ({ startTUI: vi.fn() })); -vi.mock('@lib/local-dev', async (original) => ({ - ...(await original()), +vi.mock('@agent', () => ({ runAgent: vi.fn() })); +vi.mock('@tui', () => ({ startTUI: vi.fn() })); +vi.mock('@store/local-dev', async (original) => ({ + ...(await original()), getLocalDev: () => ({}), checkLocalServices: () => Promise.resolve(null), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('@store/shared/analytics', () => ({ analytics: { wizardCapture: vi.fn(), capture: vi.fn(), @@ -29,7 +29,7 @@ vi.mock('@utils/analytics', () => ({ }, sessionProperties: () => ({}), })); -vi.mock('@lib/task-stream/index', () => ({ +vi.mock('@store/task-stream/task-stream-push', () => ({ TaskStreamPush: class { attach = vi.fn(); shutdown() { @@ -37,7 +37,7 @@ vi.mock('@lib/task-stream/index', () => ({ } }, })); -vi.mock('@lib/task-stream/destinations/posthog', () => ({ +vi.mock('@store/task-stream/destinations/posthog', () => ({ PostHogDestination: class {}, })); @@ -50,7 +50,7 @@ it.each(['continue', 'exit'] as const)( 'catches a failed run, shows the handoff screen, and exits 1 after %s', async (action) => { const store = new WizardStore(flowFor(Program.PostHogIntegration).flow); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); vi.spyOn(store, 'runReadyHooks').mockResolvedValue(undefined); vi.spyOn(store, 'getGate').mockResolvedValue(undefined); const unmount = vi.fn(); diff --git a/src/cli/runners/index.ts b/src/cli/runners/index.ts new file mode 100644 index 000000000..2a2412700 --- /dev/null +++ b/src/cli/runners/index.ts @@ -0,0 +1,5 @@ +export { runWizard } from './run-wizard.js'; +export { runWizardCI } from './run-wizard-ci.js'; +export { runWizardHeadless } from './run-wizard-headless.js'; +export { API_KEY_HINT } from './run-non-interactive.js'; +export type { NonInteractiveMode } from './run-non-interactive.js'; diff --git a/src/lib/runners/resolve-no-telemetry.ts b/src/cli/runners/resolve-no-telemetry.ts similarity index 100% rename from src/lib/runners/resolve-no-telemetry.ts rename to src/cli/runners/resolve-no-telemetry.ts diff --git a/src/lib/runners/run-non-interactive.ts b/src/cli/runners/run-non-interactive.ts similarity index 90% rename from src/lib/runners/run-non-interactive.ts rename to src/cli/runners/run-non-interactive.ts index f017065a8..54c479685 100644 --- a/src/lib/runners/run-non-interactive.ts +++ b/src/cli/runners/run-non-interactive.ts @@ -1,28 +1,30 @@ -import { POSTHOG_DOCS_URL, type Harness, type Sequence } from '@lib/constants'; import { + POSTHOG_DOCS_URL, checkLocalServices, getLocalDev, POSTHOG_LOCAL_URL, -} from '@lib/local-dev'; -import type { CloudRegion } from '@utils/types'; -import { getUI, setUI } from '@ui'; -import { LoggingUI } from '@ui/tui/console/logging-ui'; -import type { ProgramConfig } from '@lib/programs/program-step'; -import { runConfigFor } from '@lib/programs/run-config'; -import { getAuditChecks } from '@lib/programs/audit/types'; -import { analytics } from '@utils/analytics'; -import { resolveNoTelemetry } from './resolve-no-telemetry'; -import type { WizardStore } from '@ui/tui/store'; -import type { TaskStreamPush } from '@lib/task-stream/task-stream-push'; -import { join } from 'node:path'; -import { + getUI, + setUI, + analytics, ErrorCodes, classifyRunFailure, detectErrorCode, emitWizardError, -} from '@lib/errors'; -import type { OutroData, RunPhase as RunPhaseT } from '@lib/wizard-session'; -import { flowFor } from '@lib/programs/flow-for'; +} from '@store'; +import type { + Harness, + Sequence, + CloudRegion, + ProgramConfig, + WizardStore, + TaskStreamPush, + OutroData, + RunPhase as RunPhaseT, +} from '@store/types'; +import { LoggingUI } from '@tui/console'; +import { runConfigFor, getAuditChecks, flowFor } from '@store/programs'; +import { resolveNoTelemetry } from './resolve-no-telemetry.js'; +import { join } from 'node:path'; /** * The two non-interactive run modes. Both drive the same pipeline today; the @@ -105,15 +107,13 @@ export function runNonInteractive( void (async () => { const path = await import('path'); - const { buildSession, RunPhase, OutroKind } = await import( - '@lib/wizard-session' - ); - const { readEnvironment } = await import('@utils/environment'); - const { readApiKeyFromEnv } = await import('@utils/env-api-key'); + const { buildSession, RunPhase, OutroKind } = await import('@store'); + const { readEnvironment } = await import('@store'); + const { readApiKeyFromEnv } = await import('@store'); const { configureLogFileFromEnvironment, logToFile } = await import( - '@utils/debug' + '@store' ); - const { wizardAbort, WizardError } = await import('@utils/wizard-abort'); + const { wizardAbort, WizardError } = await import('@store'); configureLogFileFromEnvironment(); @@ -182,10 +182,10 @@ export function runNonInteractive( let store: WizardStore | null = null; let taskStream: TaskStreamPush | null = null; { - const { WizardStore } = await import('@ui/tui/store'); - const { HeadlessUI } = await import('@ui/tui/console/headless-ui'); + const { WizardStore } = await import('@store'); + const { HeadlessUI } = await import('@tui/console'); const { TaskStreamPush, PostHogDestination, createFileDestination } = - await import('@lib/task-stream/index'); + await import('@store'); // `''` resolves to the default path, so `--ci` always dumps. const logTarget = @@ -240,9 +240,7 @@ export function runNonInteractive( try { if (mode === 'ci') { - const { configureGatewayFromCIEnvironment } = await import( - '@lib/gateway-session' - ); + const { configureGatewayFromCIEnvironment } = await import('@agent'); configureGatewayFromCIEnvironment( Number(session.projectId), session.region ?? 'us', @@ -337,7 +335,7 @@ export function runNonInteractive( } } - const { runAgent } = await import('@lib/agent/agent-runner'); + const { runAgent } = await import('@agent'); await runAgent(runConfigFor(config), session); await settleStream(RunPhase.Completed); } catch (error) { diff --git a/src/lib/runners/run-wizard-ci.ts b/src/cli/runners/run-wizard-ci.ts similarity index 77% rename from src/lib/runners/run-wizard-ci.ts rename to src/cli/runners/run-wizard-ci.ts index e278bd5f5..6ca055bb6 100644 --- a/src/lib/runners/run-wizard-ci.ts +++ b/src/cli/runners/run-wizard-ci.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import { runNonInteractive } from './run-non-interactive'; +import type { ProgramConfig } from '@store/types'; +import { runNonInteractive } from './run-non-interactive.js'; /** * CI-mode entry point (`--ci`, dev/test builds). A thin shell over the shared diff --git a/src/lib/runners/run-wizard-headless.ts b/src/cli/runners/run-wizard-headless.ts similarity index 84% rename from src/lib/runners/run-wizard-headless.ts rename to src/cli/runners/run-wizard-headless.ts index 20916c8eb..310e7ee34 100644 --- a/src/lib/runners/run-wizard-headless.ts +++ b/src/cli/runners/run-wizard-headless.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import { runNonInteractive } from './run-non-interactive'; +import type { ProgramConfig } from '@store/types'; +import { runNonInteractive } from './run-non-interactive.js'; /** * Headless entry point (the experimental published-build, non-interactive run diff --git a/src/lib/runners/run-wizard.ts b/src/cli/runners/run-wizard.ts similarity index 86% rename from src/lib/runners/run-wizard.ts rename to src/cli/runners/run-wizard.ts index 6b4d37a58..aabad35df 100644 --- a/src/lib/runners/run-wizard.ts +++ b/src/cli/runners/run-wizard.ts @@ -1,24 +1,34 @@ -import { VERSION } from '@lib/version'; -import { logToFile, getLogFilePath } from '@utils/debug'; -import { runAgent } from '@lib/agent/agent-runner'; -import { authenticate } from '@lib/agent/runner/shared/authenticate'; -import { getProgramConfig } from '@lib/programs/program-registry'; -import { runConfigFor } from '@lib/programs/run-config'; -import { getAuditChecks } from '@lib/programs/audit/types'; -import { maybeStampAiSdkDetected } from '@lib/programs/posthog-integration/detect'; -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { Harness, Sequence } from '@lib/constants'; -import type { startTUI as StartTUIFn } from '@ui/tui/start-tui'; -import type { WizardStore } from '@ui/tui/store'; -import { OutroKind, type WizardSession } from '@lib/wizard-session'; -import type { TaskStreamPush as TaskStreamPushClass } from '@lib/task-stream/task-stream-push'; -import { resolveNoTelemetry } from './resolve-no-telemetry'; -import { checkLocalServices, getLocalDev } from '@lib/local-dev'; -import { runCleanups } from '@utils/wizard-abort'; -import { classifyRunFailure, emitWizardError } from '@lib/errors'; -import { isRunFailure } from '@ui/mint-failure'; -import { getUI } from '@ui'; -import { analytics } from '@utils/analytics'; +import { + VERSION, + logToFile, + getLogFilePath, + authenticate, + OutroKind, + checkLocalServices, + getLocalDev, + runCleanups, + classifyRunFailure, + emitWizardError, + isRunFailure, + getUI, + analytics, +} from '@store'; +import { + getProgramConfig, + runConfigFor, + getAuditChecks, + maybeStampAiSdkDetected, +} from '@store/programs'; +import type { + ProgramConfig, + Harness, + Sequence, + WizardStore, + WizardSession, + TaskStreamPush as TaskStreamPushClass, +} from '@store/types'; +import type { TuiHandle } from '@tui/types'; +import { resolveNoTelemetry } from './resolve-no-telemetry.js'; import { join } from 'node:path'; const WIZARD_VERSION = VERSION; @@ -58,6 +68,7 @@ async function advanceStep( await authenticate(store.session, config.id); maybeStampAiSdkDetected(store.session); } else if (step.run) { + const { runAgent } = await import('@agent'); await runAgent( runConfigFor(getProgramConfig(step.run.programId)), await prepareRunSession(step, store.session), @@ -65,6 +76,7 @@ async function advanceStep( ); store.completeRunStep(step.id); } else if (step.screenId === 'run') { + const { runAgent } = await import('@agent'); await runAgent( runConfigFor(config), await prepareRunSession(step, store.session), @@ -83,7 +95,7 @@ export function runWizard( config: ProgramConfig, options: Record, ): void { - let tui: ReturnType | null = null; + let tui: TuiHandle | null = null; let taskStream: TaskStreamPushClass | null = null; let onSignal: (() => void) | null = null; let exitInProgress = false; @@ -92,15 +104,11 @@ export function runWizard( try { const installDir = (options.installDir as string) || process.cwd(); - const { startTUI } = await import('@ui/tui/start-tui'); - const { buildSession, RunPhase } = await import('@lib/wizard-session'); - const { TaskStreamPush } = await import('@lib/task-stream/index'); - const { PostHogDestination } = await import( - '@lib/task-stream/destinations/posthog' - ); - const { createFileDestination } = await import( - '@lib/task-stream/destinations/file' - ); + const { startTUI } = await import('@tui'); + const { buildSession, RunPhase } = await import('@store'); + const { TaskStreamPush } = await import('@store'); + const { PostHogDestination } = await import('@store'); + const { createFileDestination } = await import('@store'); // Before the TUI mounts: once Ink owns the alt screen, anything written // to it is wiped on unmount (see the catch block below), so an abort here @@ -113,7 +121,7 @@ export function runWizard( localPosthog: local.localPosthog && !options.baseUrl, }); if (localServicesError) { - const { wizardAbort } = await import('@utils/wizard-abort'); + const { wizardAbort } = await import('@store'); await wizardAbort({ message: localServicesError }); return; } @@ -252,7 +260,7 @@ export function runWizard( if (shown(step)) await advanceStep(step, activeTui.store, config); } } else if (skipAgent) { - const { getOrAskForProjectData } = await import('@utils/setup-utils'); + const { getOrAskForProjectData } = await import('@store'); const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({ signup: session.signup, @@ -270,6 +278,7 @@ export function runWizard( }); } else { try { + const { runAgent } = await import('@agent'); await runAgent(runConfigFor(config), activeTui.store.session); } catch (error) { // The run threw before its own error handling rendered an outro. diff --git a/src/cli/testing/fake-surfaces.ts b/src/cli/testing/fake-surfaces.ts new file mode 100644 index 000000000..9633e9cc1 --- /dev/null +++ b/src/cli/testing/fake-surfaces.ts @@ -0,0 +1,38 @@ +import type { RunAgent } from '@agent/types'; +import { StoreUI, WizardStore, setUI } from '@store'; +import { flowFor } from '@store/programs'; +import type { ProgramId } from '@store/types'; +import type { TuiHandle } from '@tui/types'; + +export interface RunAgentCall { + programId: string; + installDir: string; + frameworkContextKeys: string[]; + composed: boolean; +} + +/** A RunAgent that records what each independent run received. */ +export function fakeRunAgent(): { runAgent: RunAgent; calls: RunAgentCall[] } { + const calls: RunAgentCall[] = []; + const runAgent: RunAgent = (config, session, options = {}) => { + calls.push({ + programId: config.id, + installDir: session.installDir, + frameworkContextKeys: Object.keys(session.frameworkContext), + composed: options.composed ?? false, + }); + return Promise.resolve(); + }; + return { runAgent, calls }; +} + +/** A real store behind StoreUI, no Ink: what startTUI hands the runner. */ +export function fakeStartTUI(programId: ProgramId): TuiHandle { + const store = new WizardStore(flowFor(programId).flow); + setUI(new StoreUI(store)); + return { + store, + unmount: () => undefined, + waitForSetup: () => Promise.resolve(), + }; +} diff --git a/src/cli/tsconfig.json b/src/cli/tsconfig.json new file mode 100644 index 000000000..f2abb8b3d --- /dev/null +++ b/src/cli/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../.tsbuild/cli" + }, + "include": [ + "**/*", + "../../bin.ts", + "../../e2e-tests/mocks/**/*", + "../../types/**/*.d.ts" + ], + "references": [ + { + "path": "../../tsconfig.env.json" + }, + { + "path": "../store" + }, + { + "path": "../agent" + }, + { + "path": "../tui" + } + ], + "exclude": ["vitest.config.ts"] +} diff --git a/src/cli/types.ts b/src/cli/types.ts index f474d6138..f5085fc2f 100644 --- a/src/cli/types.ts +++ b/src/cli/types.ts @@ -1,2 +1,2 @@ -/** Shape of the cli composition root. Populated by the surface split (P3). */ -export {}; +/** Shape of the cli composition root. Type-only re-exports keep it free of runtime imports. */ +export type { Command } from './commands/command.js'; diff --git a/src/cli/vitest.config.ts b/src/cli/vitest.config.ts new file mode 100644 index 000000000..96a59660e --- /dev/null +++ b/src/cli/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineProject } from 'vitest/config'; +import { surfaceProject } from '../../vitest.shared.js'; + +export default defineProject( + surfaceProject({ + name: 'cli', + imports: ['env', 'store', 'agent', 'tui', 'cli'], + ink: 'forbidden', + }), +); diff --git a/src/wizard.ts b/src/cli/wizard.ts similarity index 98% rename from src/wizard.ts rename to src/cli/wizard.ts index 7149cc708..aa15d05ee 100644 --- a/src/wizard.ts +++ b/src/cli/wizard.ts @@ -2,12 +2,16 @@ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import type { Argv } from 'yargs'; import { IS_PRODUCTION_BUILD } from '@env'; -import { Harness, Sequence } from '@lib/constants'; -import { regionOption } from '@lib/headless-mode'; -import { initLocalDev, localMcpSkillsNotice } from '@lib/local-dev'; -import { toCommandModule, type Command } from './commands/command'; -import { ErrorCodes } from '@lib/errors'; -import { emitWizardError } from '@lib/errors'; +import { + Harness, + Sequence, + regionOption, + initLocalDev, + localMcpSkillsNotice, + ErrorCodes, + emitWizardError, +} from '@store'; +import { toCommandModule, type Command } from './commands/command.js'; /** * Global yargs options applied to every command. These are read from the diff --git a/src/commands/basic-integration/playground.ts b/src/commands/basic-integration/playground.ts deleted file mode 100644 index 61eaaf0fc..000000000 --- a/src/commands/basic-integration/playground.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { VERSION } from '@lib/version'; -import { startPlayground } from '@ui/tui/playground/start-playground'; - -/** Launch the TUI primitives playground. */ -export function runPlayground(): void { - startPlayground(VERSION); -} diff --git a/src/commands/mcp/index.ts b/src/commands/mcp/index.ts deleted file mode 100644 index 24f57079f..000000000 --- a/src/commands/mcp/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { mcpAddCommand } from './add'; -import { mcpRemoveCommand } from './remove'; -import { mcpTutorialCommand } from './tutorial'; -import type { Command } from '../command'; - -export const mcpCommand: Command = { - name: 'mcp', - description: 'MCP server management commands', - children: [mcpAddCommand, mcpRemoveCommand, mcpTutorialCommand], -}; diff --git a/src/env.ts b/src/env.ts index 1c5424c14..8a35cd70a 100644 --- a/src/env.ts +++ b/src/env.ts @@ -15,7 +15,8 @@ * this module instead. */ -import { HEADLESS_FLAG } from '@lib/headless-mode'; +/** The hidden non-interactive flag. Declared here so env reads nothing from a surface. */ +export const HEADLESS_FLAG = 'headless-DONOTUSE-EXPERIMENTAL'; // ── Build-time constants ───────────────────────────────────────────── // tsdown replaces `process.env.NODE_ENV` with a string literal. diff --git a/src/lib/agent/agent-runner.ts b/src/lib/agent/agent-runner.ts deleted file mode 100644 index f8fd5a00b..000000000 --- a/src/lib/agent/agent-runner.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Re-export shim. The runner has been split into agent/runner/. - * Import from there directly; this shim keeps existing importers working. - */ - -export { - runAgent, - runProgram, - shouldDisableAsk, - type ProgramRun, - type ProgramRunConfig, - type BootstrapResult, - type AbortCase, - type PromptContext, - type Credentials, -} from './runner/index'; diff --git a/src/lib/middleware/index.ts b/src/lib/middleware/index.ts deleted file mode 100644 index 070727a8f..000000000 --- a/src/lib/middleware/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Middleware system for wizard agent runs. - */ - -export { MiddlewarePipeline } from './pipeline'; -export { PhaseDetector } from './phase-detector'; -export type { Middleware, MiddlewareContext, MiddlewareStore } from './types'; - -export { loadBenchmarkConfig, getDefaultConfig } from './config'; -export type { BenchmarkConfig } from './config'; - -export { createBenchmarkPipeline } from './benchmark'; -export type { BenchmarkData, StepUsage } from './benchmark'; - -export { createPluginsFromConfig } from './benchmarks'; diff --git a/src/lib/registry.ts b/src/lib/registry.ts deleted file mode 100644 index cd0133aeb..000000000 --- a/src/lib/registry.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { FrameworkConfig } from './framework-config'; -import { Integration } from './constants'; -import { NEXTJS_AGENT_CONFIG } from '@frameworks/nextjs/nextjs-wizard-agent'; -import { NUXT_AGENT_CONFIG } from '@frameworks/nuxt/nuxt-wizard-agent'; -import { VUE_AGENT_CONFIG } from '@frameworks/vue/vue-wizard-agent'; -import { REACT_ROUTER_AGENT_CONFIG } from '@frameworks/react-router/react-router-wizard-agent'; -import { TANSTACK_ROUTER_AGENT_CONFIG } from '@frameworks/tanstack-router/tanstack-router-wizard-agent'; -import { TANSTACK_START_AGENT_CONFIG } from '@frameworks/tanstack-start/tanstack-start-wizard-agent'; -import { REACT_NATIVE_AGENT_CONFIG } from '@frameworks/react-native/react-native-wizard-agent'; -import { ANGULAR_AGENT_CONFIG } from '@frameworks/angular/angular-wizard-agent'; -import { ASTRO_AGENT_CONFIG } from '@frameworks/astro/astro-wizard-agent'; -import { DJANGO_AGENT_CONFIG } from '@frameworks/django/django-wizard-agent'; -import { FLASK_AGENT_CONFIG } from '@frameworks/flask/flask-wizard-agent'; -import { FASTAPI_AGENT_CONFIG } from '@frameworks/fastapi/fastapi-wizard-agent'; -import { LARAVEL_AGENT_CONFIG } from '@frameworks/laravel/laravel-wizard-agent'; -import { SVELTEKIT_AGENT_CONFIG } from '@frameworks/svelte/svelte-wizard-agent'; -import { FLUTTER_AGENT_CONFIG } from '@frameworks/flutter/flutter-wizard-agent'; -import { SWIFT_AGENT_CONFIG } from '@frameworks/swift/swift-wizard-agent'; -import { KMP_AGENT_CONFIG } from '@frameworks/kmp/kmp-wizard-agent'; -import { ANDROID_AGENT_CONFIG } from '@frameworks/android/android-wizard-agent'; -import { RAILS_AGENT_CONFIG } from '@frameworks/rails/rails-wizard-agent'; -import { ELIXIR_AGENT_CONFIG } from '@frameworks/elixir/elixir-wizard-agent'; -import { GO_AGENT_CONFIG } from '@frameworks/go/go-wizard-agent'; -import { JAVA_AGENT_CONFIG } from '@frameworks/java/java-wizard-agent'; -import { RUST_AGENT_CONFIG } from '@frameworks/rust/rust-wizard-agent'; -import { PYTHON_AGENT_CONFIG } from '@frameworks/python/python-wizard-agent'; -import { RUBY_AGENT_CONFIG } from '@frameworks/ruby/ruby-wizard-agent'; -import { JAVASCRIPT_NODE_AGENT_CONFIG } from '@frameworks/javascript-node/javascript-node-wizard-agent'; -import { JAVASCRIPT_WEB_AGENT_CONFIG } from '@frameworks/javascript-web/javascript-web-wizard-agent'; - -export const FRAMEWORK_REGISTRY: Record = { - [Integration.nextjs]: NEXTJS_AGENT_CONFIG, - [Integration.nuxt]: NUXT_AGENT_CONFIG, - [Integration.vue]: VUE_AGENT_CONFIG, - [Integration.tanstackStart]: TANSTACK_START_AGENT_CONFIG, - [Integration.reactRouter]: REACT_ROUTER_AGENT_CONFIG, - [Integration.tanstackRouter]: TANSTACK_ROUTER_AGENT_CONFIG, - [Integration.reactNative]: REACT_NATIVE_AGENT_CONFIG, - [Integration.angular]: ANGULAR_AGENT_CONFIG, - [Integration.astro]: ASTRO_AGENT_CONFIG, - [Integration.django]: DJANGO_AGENT_CONFIG, - [Integration.flask]: FLASK_AGENT_CONFIG, - [Integration.fastapi]: FASTAPI_AGENT_CONFIG, - [Integration.laravel]: LARAVEL_AGENT_CONFIG, - [Integration.sveltekit]: SVELTEKIT_AGENT_CONFIG, - [Integration.flutter]: FLUTTER_AGENT_CONFIG, - [Integration.kmp]: KMP_AGENT_CONFIG, - [Integration.swift]: SWIFT_AGENT_CONFIG, - [Integration.android]: ANDROID_AGENT_CONFIG, - [Integration.rails]: RAILS_AGENT_CONFIG, - [Integration.elixir]: ELIXIR_AGENT_CONFIG, - [Integration.go]: GO_AGENT_CONFIG, - [Integration.rust]: RUST_AGENT_CONFIG, - [Integration.java]: JAVA_AGENT_CONFIG, - [Integration.python]: PYTHON_AGENT_CONFIG, - [Integration.ruby]: RUBY_AGENT_CONFIG, - [Integration.javascriptNode]: JAVASCRIPT_NODE_AGENT_CONFIG, - [Integration.javascript_web]: JAVASCRIPT_WEB_AGENT_CONFIG, -}; diff --git a/src/lib/runners/index.ts b/src/lib/runners/index.ts deleted file mode 100644 index e42598b8e..000000000 --- a/src/lib/runners/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { runWizard } from './run-wizard'; -export { runWizardCI } from './run-wizard-ci'; -export { runWizardHeadless } from './run-wizard-headless'; -export { API_KEY_HINT } from './run-non-interactive'; -export type { NonInteractiveMode } from './run-non-interactive'; diff --git a/src/lib/wizard-tools/index.ts b/src/lib/wizard-tools/index.ts deleted file mode 100644 index 1c4902827..000000000 --- a/src/lib/wizard-tools/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Wizard tools — `./tools` is the shared behavior core, `./mcp` the MCP - * facade the anthropic harness mounts (pi's facade lives with its harness). - * Re-exported together so importers keep the `@lib/wizard-tools` path. - */ -export * from './tools'; -export * from './mcp'; diff --git a/src/steps/index.ts b/src/steps/index.ts deleted file mode 100644 index fd6758c45..000000000 --- a/src/steps/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './run-prettier'; -export * from './add-or-update-environment-variables'; -export * from './add-mcp-server-to-clients'; -export * from './upload-environment-variables'; diff --git a/src/store/README.md b/src/store/README.md new file mode 100644 index 000000000..1f6b8c6ba --- /dev/null +++ b/src/store/README.md @@ -0,0 +1,41 @@ +# store + +Render-agnostic state and the contract between the agent and whatever renders. + +## Owns + +- `state/`: `WizardStore`, flows, interrupts, screen resolution, run failure. +- `session/`: `WizardSession`, ask policy, ask bridge, secret vault. +- `ui/`: the `WizardUI` interface, `getUI`/`setUI`, `StoreUI`, `NullUI`. +- `agent-protocol/`: run configs, agent signals, token pricing, subprocess env. +- `programs/`: program registry, run configs, flows as data, detection modules. +- `tools/`: wizard tool behavior shared by every harness facade. +- `detection/`, `frameworks`, `services/`, `security/`, `task-stream/`, + `shared/`. + +## Never contains + +Ink, console output, or any import of `@agent`, `@tui`, or `@cli`. + +## May import + +`@env` and its own files. Nothing else. + +## Public entries + +- `index.ts`: runtime API. `types.ts`: every type another surface consumes. +- `programs/index.ts`: program registry and definitions. +- Agent implementations arrive by injection: `setUI`, `setDetectionAgent`, + `setMcpPromptRunner`. + +## Tests + +`pnpm test:store` and `pnpm typecheck:store`. `vitest.config.ts` resolves only +`@env` and `@store`; an import of any other surface fails at load and `ink` +throws. `testing/` holds `createTestStore`; shipped code never imports it. +`__tests__/contract.test.ts` pins the boundary: `StoreUI` and `NullUI` implement +`WizardUI`, `ProgramConfig` extends `ProgramRunConfig`, `runConfigFor` emits +nothing beyond the run contract, and `WizardStore` satisfies `WizardStoreApi` +(`state/store-api.ts`, whose member list the architecture suite derives from +real tui, cli, and harness usage). Goldens live under +`**/__tests__/__snapshots__` and must stay byte identical across refactors. diff --git a/src/lib/__tests__/__snapshots__/credential-isolation-snapshot.test.ts.snap b/src/store/__tests__/__snapshots__/credential-isolation-snapshot.test.ts.snap similarity index 100% rename from src/lib/__tests__/__snapshots__/credential-isolation-snapshot.test.ts.snap rename to src/store/__tests__/__snapshots__/credential-isolation-snapshot.test.ts.snap diff --git a/src/lib/__tests__/agent-env-isolation.test.ts b/src/store/__tests__/agent-env-isolation.test.ts similarity index 99% rename from src/lib/__tests__/agent-env-isolation.test.ts rename to src/store/__tests__/agent-env-isolation.test.ts index d68f01c09..b8047d499 100644 --- a/src/lib/__tests__/agent-env-isolation.test.ts +++ b/src/store/__tests__/agent-env-isolation.test.ts @@ -2,7 +2,7 @@ import { sanitizeAgentSubprocessEnv, isBlockedAgentEnvKey, BLOCKED_AGENT_ENV_KEYS, -} from '@lib/agent-env-isolation'; +} from '../agent-protocol/agent-env-isolation.js'; describe('isBlockedAgentEnvKey', () => { it('blocks the direct API key that outranks the gateway auth token', () => { diff --git a/src/lib/__tests__/claude-settings-backup.test.ts b/src/store/__tests__/claude-settings-backup.test.ts similarity index 98% rename from src/lib/__tests__/claude-settings-backup.test.ts rename to src/store/__tests__/claude-settings-backup.test.ts index 8dd9815e0..8cf5b77b6 100644 --- a/src/lib/__tests__/claude-settings-backup.test.ts +++ b/src/store/__tests__/claude-settings-backup.test.ts @@ -7,7 +7,7 @@ const { captureException, wizardCapture } = vi.hoisted(() => ({ wizardCapture: vi.fn(), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('../shared/analytics.js', () => ({ analytics: { captureException: (...args: unknown[]) => captureException(...args), wizardCapture: (...args: unknown[]) => wizardCapture(...args), @@ -18,7 +18,7 @@ import { backupAndFixClaudeSettings, restoreClaudeSettings, recoverOrphanedSettingsBackups, -} from '@lib/claude-settings'; +} from '../services/claude-settings.js'; const SETTINGS = 'settings.json'; const BACKUP = 'settings.json.wizard-backup'; diff --git a/src/__tests__/clipboard.test.ts b/src/store/__tests__/clipboard.test.ts similarity index 94% rename from src/__tests__/clipboard.test.ts rename to src/store/__tests__/clipboard.test.ts index 04197656d..f76cab2b6 100644 --- a/src/__tests__/clipboard.test.ts +++ b/src/store/__tests__/clipboard.test.ts @@ -1,4 +1,4 @@ -import { browserOpenCommands } from '@utils/clipboard'; +import { browserOpenCommands } from '../shared/clipboard.js'; const URL = 'https://us.posthog.com/api/environments/227926/integrations/authorize?kind=github'; diff --git a/src/lib/__tests__/cloudflare-detection.test.ts b/src/store/__tests__/cloudflare-detection.test.ts similarity index 97% rename from src/lib/__tests__/cloudflare-detection.test.ts rename to src/store/__tests__/cloudflare-detection.test.ts index 7879b5320..2aa18a4b8 100644 --- a/src/lib/__tests__/cloudflare-detection.test.ts +++ b/src/store/__tests__/cloudflare-detection.test.ts @@ -1,9 +1,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { detectCloudflareTarget } from '@lib/cloudflare-detection'; +import { detectCloudflareTarget } from '../cloudflare-detection.js'; -vi.mock('../../utils/debug'); +vi.mock('../shared/debug.js'); function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'cloudflare-detect-')); diff --git a/src/lib/__tests__/constants.test.ts b/src/store/__tests__/constants.test.ts similarity index 87% rename from src/lib/__tests__/constants.test.ts rename to src/store/__tests__/constants.test.ts index 6a5390819..07257eb15 100644 --- a/src/lib/__tests__/constants.test.ts +++ b/src/store/__tests__/constants.test.ts @@ -1,4 +1,7 @@ -import { WIZARD_USER_AGENT, wizardUserAgentForProgram } from '@lib/constants'; +import { + WIZARD_USER_AGENT, + wizardUserAgentForProgram, +} from '../shared/constants.js'; describe('wizardUserAgentForProgram', () => { it('tags the program so the backend can attribute created_via (self-driving → self_driving)', () => { diff --git a/src/store/__tests__/contract.test.ts b/src/store/__tests__/contract.test.ts new file mode 100644 index 000000000..7c6c3e829 --- /dev/null +++ b/src/store/__tests__/contract.test.ts @@ -0,0 +1,69 @@ +import { expectTypeOf } from 'vitest'; +import type { ProgramRunConfig } from '../agent-protocol/program-run.js'; +import type { ProgramConfig } from '../programs/program-step.js'; +import { + getProgramConfig, + Program, + PROGRAM_REGISTRY, +} from '../programs/program-registry.js'; +import { runConfigFor } from '../programs/run-config.js'; +import type { WizardStoreApi } from '../state/store-api.js'; +import type { WizardStore } from '../state/store.js'; +import { createTestStore } from '../testing/index.js'; +import { NullUI } from '../ui/null-ui.js'; +import { StoreUI } from '../ui/store-ui.js'; +import type { WizardUI } from '../ui/wizard-ui.js'; + +/** The fields the agent may read from a run config. */ +const RUN_CONTRACT_KEYS = [ + 'id', + 'run', + 'agentFlow', + 'skillId', + 'requiresAi', + 'seedTasks', + 'auditLedgerFile', + 'reportFile', + 'eventPlanFile', + 'streamWorkflowId', + 'allowedTools', + 'disallowedTools', + 'postAuthGateIds', + 'healthCheckDeclared', +] as const satisfies readonly (keyof ProgramRunConfig)[]; + +describe('store contract', () => { + it('StoreUI and NullUI implement WizardUI', () => { + expectTypeOf().toMatchTypeOf(); + expectTypeOf().toMatchTypeOf(); + expect(new StoreUI(createTestStore()).interactive).toBe(true); + expect(new NullUI().interactive).toBe(false); + }); + + it('the store satisfies the API other surfaces see', () => { + expectTypeOf().toMatchTypeOf(); + }); + + it('every ProgramConfig is a ProgramRunConfig', () => { + expectTypeOf().toMatchTypeOf(); + }); + + it('every Program value resolves to a registry entry with that id', () => { + for (const id of Object.values(Program)) { + expect(getProgramConfig(id).id).toBe(id); + } + expect(new Set(PROGRAM_REGISTRY.map((c) => c.id)).size).toBe( + PROGRAM_REGISTRY.length, + ); + }); + + it('runConfigFor hands the agent only the run contract', () => { + const allowed = new Set(RUN_CONTRACT_KEYS); + for (const config of PROGRAM_REGISTRY) { + const extra = Object.keys(runConfigFor(config)).filter( + (k) => !allowed.has(k), + ); + expect(extra, config.id).toEqual([]); + } + }); +}); diff --git a/src/lib/__tests__/credential-isolation-snapshot.test.ts b/src/store/__tests__/credential-isolation-snapshot.test.ts similarity index 95% rename from src/lib/__tests__/credential-isolation-snapshot.test.ts rename to src/store/__tests__/credential-isolation-snapshot.test.ts index e0ee0d4e7..07067bc36 100644 --- a/src/lib/__tests__/credential-isolation-snapshot.test.ts +++ b/src/store/__tests__/credential-isolation-snapshot.test.ts @@ -13,9 +13,9 @@ * isolation surface — a diff here means a credential path changed disposition. */ -import { sanitizeAgentSubprocessEnv } from '@lib/agent-env-isolation'; -import { classifySettingsConflicts } from '@lib/claude-settings'; -import type { SettingsConflict } from '@lib/claude-settings'; +import { sanitizeAgentSubprocessEnv } from '../agent-protocol/agent-env-isolation.js'; +import { classifySettingsConflicts } from '../services/claude-settings.js'; +import type { SettingsConflict } from '../services/claude-settings.js'; // Every env-based avenue (one key each), plus the gateway routing and benign // env that must survive. Grouped by avenue for readability; the snapshot sorts. diff --git a/src/lib/__tests__/fetch-retry.test.ts b/src/store/__tests__/fetch-retry.test.ts similarity index 98% rename from src/lib/__tests__/fetch-retry.test.ts rename to src/store/__tests__/fetch-retry.test.ts index d36d94509..8da33195b 100644 --- a/src/lib/__tests__/fetch-retry.test.ts +++ b/src/store/__tests__/fetch-retry.test.ts @@ -3,8 +3,11 @@ import { fetchWithRetry, awsUrlFor, resetOriginPreference, -} from '../fetch-retry'; -import { GITHUB_SKILLS_BASE_URL, AWS_SKILLS_BASE_URL } from '../constants'; +} from '../fetch-retry.js'; +import { + GITHUB_SKILLS_BASE_URL, + AWS_SKILLS_BASE_URL, +} from '../shared/constants.js'; const GH_LATEST = 'https://github.com/PostHog/context-mill/releases/latest/download'; diff --git a/src/lib/__tests__/flow-resolution.test.ts b/src/store/__tests__/flow-resolution.test.ts similarity index 78% rename from src/lib/__tests__/flow-resolution.test.ts rename to src/store/__tests__/flow-resolution.test.ts index 278a759b7..b2d72fd66 100644 --- a/src/lib/__tests__/flow-resolution.test.ts +++ b/src/store/__tests__/flow-resolution.test.ts @@ -3,14 +3,13 @@ import { McpOutcome, OutroKind, RunPhase, -} from '@lib/wizard-session'; -import { HostResolution } from '@lib/host-resolution'; -import { WizardReadiness } from '@lib/health-checks/readiness'; -import { ScreenId, Overlay, Program, type ProgramId } from '@ui/tui/router'; -import { flowEntries, resolveActiveScreen } from '@lib/flow-resolution'; -import { flowFor } from '@lib/programs/flow-for'; -import type { WizardSession } from '@lib/wizard-session'; -import type { Interrupt } from '@lib/interrupts'; +} from '../session/wizard-session.js'; +import { HostResolution } from '../host-resolution.js'; +import { WizardReadiness } from '../health-checks/readiness.js'; +import { flowEntries, resolveActiveScreen } from '../state/flow-resolution.js'; +import { flowFor } from '../programs/flow-for.js'; +import type { WizardSession } from '../session/wizard-session.js'; +import { Interrupt } from '../state/interrupts.js'; /** The old router surface over the pure resolver, so the cases port as-is. */ function routerFor(program: ProgramId) { @@ -28,9 +27,13 @@ function routerFor(program: ProgramId) { }, }; } -import { Integration } from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { PROGRAM_REGISTRY } from '@lib/programs/program-registry'; +import { Integration } from '../shared/constants.js'; +import { FRAMEWORK_REGISTRY } from '../registry.js'; +import { + PROGRAM_REGISTRY, + Program, + type ProgramId, +} from '../programs/program-registry.js'; function baseWizardSession() { return buildSession({}); @@ -54,10 +57,10 @@ describe('flow resolution', () => { 'shows a failed run over every step and overlay in %s', (program) => { const router = routerFor(program); - router.pushOverlay(Overlay.WizardAsk); + router.pushOverlay(Interrupt.WizardAsk); const session = failedRunSession(); session.outroDismissed = true; - expect(router.resolve(session)).toBe(ScreenId.MintFailure); + expect(router.resolve(session)).toBe('mint-failure'); }, ); @@ -65,15 +68,15 @@ describe('flow resolution', () => { const router = routerFor(Program.SelfDriving); const session = failedRunSession(); session.mintHandoff = 'continue'; - expect(router.resolve(session)).toBe(ScreenId.Mcp); + expect(router.resolve(session)).toBe('mcp'); session.mcpComplete = true; - expect(router.resolve(session)).toBe(ScreenId.SlackConnect); + expect(router.resolve(session)).toBe('slack-connect'); session.slackStepDismissed = true; - expect(router.resolve(session)).toBe(ScreenId.KeepSkills); + expect(router.resolve(session)).toBe('keep-skills'); session.skillsComplete = true; - expect(router.resolve(session)).toBe(ScreenId.Exit); + expect(router.resolve(session)).toBe('exit'); session.mintHandoff = 'exit'; - expect(router.resolve(session)).toBe(ScreenId.Exit); + expect(router.resolve(session)).toBe('exit'); }); describe('resolve', () => { @@ -81,7 +84,7 @@ describe('flow resolution', () => { const router = routerFor(Program.PostHogIntegration); const session = baseWizardSession(); - expect(router.resolve(session)).toBe(ScreenId.Intro); + expect(router.resolve(session)).toBe('intro'); session.setupConfirmed = true; session.readinessResult = { @@ -96,7 +99,7 @@ describe('flow resolution', () => { projectId: 1, }; - expect(router.resolve(session)).toBe(ScreenId.Run); + expect(router.resolve(session)).toBe('run'); }); it('skips the setup screen when there are no unanswered framework questions', () => { @@ -118,7 +121,7 @@ describe('flow resolution', () => { } as never; session.frameworkContext = { packageManager: 'pnpm' }; - expect(router.resolve(session)).toBe(ScreenId.Auth); + expect(router.resolve(session)).toBe('auth'); }); // Every login failure path (OAuth denied, missing completion scope, no @@ -136,14 +139,14 @@ describe('flow resolution', () => { health: {} as never, reasons: [], }; - expect(router.resolve(session)).toBe(ScreenId.Auth); + expect(router.resolve(session)).toBe('auth'); // An error phase alone (no outro yet) stays on auth. session.runPhase = RunPhase.Error; - expect(router.resolve(session)).toBe(ScreenId.Auth); + expect(router.resolve(session)).toBe('auth'); session.outroData = { kind: OutroKind.Error, message: 'login failed' }; - expect(router.resolve(session)).toBe(ScreenId.Outro); + expect(router.resolve(session)).toBe('outro'); }); it('returns the last flow screen when every entry is complete', () => { @@ -166,20 +169,20 @@ describe('flow resolution', () => { session.mcpComplete = true; session.slackStepDismissed = true; - expect(router.resolve(session)).toBe(ScreenId.Outro); + expect(router.resolve(session)).toBe('outro'); }); it('gives the topmost overlay precedence over the flow screen', () => { const router = routerFor(Program.PostHogIntegration); const session = baseWizardSession(); - router.pushOverlay(Overlay.SettingsOverride); - router.pushOverlay(Overlay.AuthError); + router.pushOverlay(Interrupt.SettingsOverride); + router.pushOverlay(Interrupt.AuthError); - expect(router.resolve(session)).toBe(Overlay.AuthError); + expect(router.resolve(session)).toBe(Interrupt.AuthError); router.popOverlay(); - expect(router.resolve(session)).toBe(Overlay.SettingsOverride); + expect(router.resolve(session)).toBe(Interrupt.SettingsOverride); }); it('shows the session-timeout overlay over the auth screen that never completes', () => { @@ -195,10 +198,10 @@ describe('flow resolution', () => { health: {} as never, reasons: [], }; - expect(router.resolve(session)).toBe(ScreenId.Auth); + expect(router.resolve(session)).toBe('auth'); - router.pushOverlay(Overlay.SessionTimeout); - expect(router.resolve(session)).toBe(Overlay.SessionTimeout); + router.pushOverlay(Interrupt.SessionTimeout); + expect(router.resolve(session)).toBe(Interrupt.SessionTimeout); }); }); @@ -206,22 +209,22 @@ describe('flow resolution', () => { it('defaults to the first screen in the active flow', () => { const router = routerFor(Program.McpRemove); - expect(router.activeScreen).toBe(ScreenId.McpRemove); + expect(router.activeScreen).toBe('mcp-remove'); }); it('returns the top overlay when overlays are active', () => { const router = routerFor(Program.PostHogIntegration); - router.pushOverlay(Overlay.ManagedSettings); + router.pushOverlay(Interrupt.ManagedSettings); - expect(router.activeScreen).toBe(Overlay.ManagedSettings); + expect(router.activeScreen).toBe(Interrupt.ManagedSettings); }); }); describe('McpAdd flow', () => { it('starts at McpAdd', () => { const router = routerFor(Program.McpAdd); - expect(router.activeScreen).toBe(ScreenId.McpAdd); + expect(router.activeScreen).toBe('mcp-add'); }); it('exits after install when MCP install was skipped', () => { @@ -232,7 +235,7 @@ describe('flow resolution', () => { // Skipped → tutorial step is hidden, so the only visible // step (mcp-add) is complete and the program resolves to Exit. - expect(router.resolve(session)).toBe(ScreenId.Exit); + expect(router.resolve(session)).toBe('exit'); }); it('advances to SlackConnect after a successful install', () => { @@ -243,7 +246,7 @@ describe('flow resolution', () => { // Slack is the first post-install step (loginless render); the // tutorial follows it. - expect(router.resolve(session)).toBe(ScreenId.SlackConnect); + expect(router.resolve(session)).toBe('slack-connect'); }); it('advances to McpSuggestedPrompts once the Slack step is dismissed', () => { @@ -253,7 +256,7 @@ describe('flow resolution', () => { session.mcpOutcome = McpOutcome.Installed; session.slackStepDismissed = true; - expect(router.resolve(session)).toBe(ScreenId.McpSuggestedPrompts); + expect(router.resolve(session)).toBe('mcp-suggested-prompts'); }); it('exits once the tutorial step is dismissed', () => { @@ -264,7 +267,7 @@ describe('flow resolution', () => { session.slackStepDismissed = true; session.mcpSuggestedPromptsDismissed = true; - expect(router.resolve(session)).toBe(ScreenId.Exit); + expect(router.resolve(session)).toBe('exit'); }); it('skips the Slack step when MCP install was skipped', () => { @@ -275,7 +278,7 @@ describe('flow resolution', () => { // Both the tutorial and slack-connect steps are gated on a // successful install, so a skipped install resolves straight to Exit. - expect(router.resolve(session)).toBe(ScreenId.Exit); + expect(router.resolve(session)).toBe('exit'); }); }); @@ -289,23 +292,21 @@ describe('flow resolution', () => { it('asks "set up PostHog?" when none detected and undecided', () => { const router = routerFor(Program.SelfDriving); const session = confirmed(); // integrate null, postHogPresent unset - expect(router.resolve(session)).toBe( - ScreenId.SelfDrivingIntegrationCheck, - ); + expect(router.resolve(session)).toBe('self-driving-integration-check'); }); it('skips the question when PostHog is already detected', () => { const router = routerFor(Program.SelfDriving); const session = confirmed(); session.frameworkContext.postHogPresent = true; - expect(router.resolve(session)).toBe(ScreenId.HealthCheck); + expect(router.resolve(session)).toBe('health-check'); }); it('skips the question when --integrate pre-decided it', () => { const router = routerFor(Program.SelfDriving); const session = confirmed(); session.integrate = true; - expect(router.resolve(session)).toBe(ScreenId.HealthCheck); + expect(router.resolve(session)).toBe('health-check'); }); function readyToIntegrate() { @@ -328,9 +329,7 @@ describe('flow resolution', () => { it('shows the detect+pick screen after auth, before a project is picked', () => { const router = routerFor(Program.SelfDriving); const session = readyToIntegrate(); // integration still null - expect(router.resolve(session)).toBe( - ScreenId.SelfDrivingIntegrationDetect, - ); + expect(router.resolve(session)).toBe('self-driving-integration-detect'); }); it('advances to the integration run once a project is picked', () => { @@ -339,7 +338,7 @@ describe('flow resolution', () => { session.integration = Integration.javascriptNode; // picked session.frameworkConfig = FRAMEWORK_REGISTRY[Integration.javascriptNode]; // integrate-run shares the 'run' screen; the phase hasn't completed yet. - expect(router.resolve(session)).toBe(ScreenId.Run); + expect(router.resolve(session)).toBe('run'); }); }); @@ -363,7 +362,7 @@ describe('flow resolution', () => { it('shows the project picker after login, before a project is picked', () => { const router = routerFor(Program.ErrorTracking); - expect(router.resolve(loggedIn())).toBe(ScreenId.ErrorTrackingDetect); + expect(router.resolve(loggedIn())).toBe('error-tracking-detect'); }); it('advances to the run once a project is picked', () => { @@ -371,7 +370,7 @@ describe('flow resolution', () => { const session = loggedIn(); session.integration = Integration.nextjs; session.frameworkConfig = FRAMEWORK_REGISTRY[Integration.nextjs]; - expect(router.resolve(session)).toBe(ScreenId.Run); + expect(router.resolve(session)).toBe('run'); }); }); }); diff --git a/src/lib/__tests__/host-resolution.test.ts b/src/store/__tests__/host-resolution.test.ts similarity index 97% rename from src/lib/__tests__/host-resolution.test.ts rename to src/store/__tests__/host-resolution.test.ts index a22d55150..95f6f7ed0 100644 --- a/src/lib/__tests__/host-resolution.test.ts +++ b/src/store/__tests__/host-resolution.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; -import { HostResolution, mcpUrlFor } from '@lib/host-resolution'; +import { HostResolution, mcpUrlFor } from '../host-resolution.js'; /** * Contract test for HostResolution — the durable record of what the host family @@ -102,7 +102,7 @@ describe('mcpUrlFor', () => { process.env.MCP_URL = 'https://evil.example.com/mcp'; try { vi.resetModules(); - const fresh = await import('@lib/host-resolution'); + const fresh = await import('../host-resolution.js'); expect(fresh.mcpUrlFor(false)).toBe('https://mcp.posthog.com/mcp'); expect(fresh.mcpUrlFor(true)).toBe('http://localhost:8787/mcp'); } finally { diff --git a/src/lib/__tests__/local-dev.test.ts b/src/store/__tests__/local-dev.test.ts similarity index 99% rename from src/lib/__tests__/local-dev.test.ts rename to src/store/__tests__/local-dev.test.ts index 02ced19c2..55e0a6033 100644 --- a/src/lib/__tests__/local-dev.test.ts +++ b/src/store/__tests__/local-dev.test.ts @@ -11,12 +11,12 @@ import { localMcpSkillsNotice, resetLocalDev, resolveLocalDev, -} from '@lib/local-dev'; +} from '../local-dev.js'; import { getSkillsBaseUrl, GITHUB_SKILLS_BASE_URL, LOCAL_SKILLS_BASE_URL, -} from '@lib/constants'; +} from '../shared/constants.js'; describe('local dev endpoints', () => { it('pins each service to its own port', () => { diff --git a/src/lib/__tests__/mcp-project-profile.test.ts b/src/store/__tests__/mcp-project-profile.test.ts similarity index 99% rename from src/lib/__tests__/mcp-project-profile.test.ts rename to src/store/__tests__/mcp-project-profile.test.ts index 14f793ee5..c17dce765 100644 --- a/src/lib/__tests__/mcp-project-profile.test.ts +++ b/src/store/__tests__/mcp-project-profile.test.ts @@ -3,7 +3,7 @@ import { degradedProfile, isKnownCloudHost, type EventVolume, -} from '@lib/mcp-project-profile'; +} from '../mcp-project-profile.js'; // Inconclusive REST result for every product — the "we couldn't tell" // default used by most tier/event tests so they isolate the events probe. diff --git a/src/lib/__tests__/mcp-role-prompts.test.ts b/src/store/__tests__/mcp-role-prompts.test.ts similarity index 99% rename from src/lib/__tests__/mcp-role-prompts.test.ts rename to src/store/__tests__/mcp-role-prompts.test.ts index 704f44cf7..6c8b41cec 100644 --- a/src/lib/__tests__/mcp-role-prompts.test.ts +++ b/src/store/__tests__/mcp-role-prompts.test.ts @@ -10,14 +10,14 @@ import { getSlackAppCard, FOLLOW_UP_EXIT_SENTINEL, TAILORED_ROLES, -} from '@lib/mcp-role-prompts'; -import { Integration } from '@lib/constants'; +} from '../mcp-role-prompts.js'; +import { Integration } from '../shared/constants.js'; import { degradedProfile, type EventVolume, type ProductPresence, type ProjectDataProfile, -} from '@lib/mcp-project-profile'; +} from '../mcp-project-profile.js'; // Build a profile fixture without the network. Defaults to a rich profile // with a clean SaaS funnel and every product absent (so activation diff --git a/src/lib/__tests__/mcp-seed-events.test.ts b/src/store/__tests__/mcp-seed-events.test.ts similarity index 98% rename from src/lib/__tests__/mcp-seed-events.test.ts rename to src/store/__tests__/mcp-seed-events.test.ts index c10031f78..0155351dd 100644 --- a/src/lib/__tests__/mcp-seed-events.test.ts +++ b/src/store/__tests__/mcp-seed-events.test.ts @@ -2,11 +2,11 @@ import { buildSeedEvents, tallySeedEvents, seededProfile, -} from '@lib/mcp-seed-events'; +} from '../mcp-seed-events.js'; import { degradedProfile, type ProjectDataProfile, -} from '@lib/mcp-project-profile'; +} from '../mcp-project-profile.js'; const NOW = new Date('2026-06-08T12:00:00.000Z'); const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000; diff --git a/src/__tests__/package-json.test.ts b/src/store/__tests__/package-json.test.ts similarity index 99% rename from src/__tests__/package-json.test.ts rename to src/store/__tests__/package-json.test.ts index 0be66cddc..d4ad92d3a 100644 --- a/src/__tests__/package-json.test.ts +++ b/src/store/__tests__/package-json.test.ts @@ -7,7 +7,7 @@ import { hasDeclaredDependency, findDeclaredPackage, type PackageJson, -} from '@utils/package-json'; +} from '../shared/package-json.js'; describe('getDeclaredVersion', () => { it('returns version from dependencies', () => { diff --git a/src/lib/__tests__/secret-vault.test.ts b/src/store/__tests__/secret-vault.test.ts similarity index 97% rename from src/lib/__tests__/secret-vault.test.ts rename to src/store/__tests__/secret-vault.test.ts index 6e1db3661..64ed91684 100644 --- a/src/lib/__tests__/secret-vault.test.ts +++ b/src/store/__tests__/secret-vault.test.ts @@ -1,4 +1,4 @@ -import { createSecretVault, isSecretRef } from '../secret-vault'; +import { createSecretVault, isSecretRef } from '../session/secret-vault.js'; describe('createSecretVault', () => { it('stores a value and returns a ref', () => { diff --git a/src/lib/__tests__/settings-conflicts.test.ts b/src/store/__tests__/settings-conflicts.test.ts similarity index 80% rename from src/lib/__tests__/settings-conflicts.test.ts rename to src/store/__tests__/settings-conflicts.test.ts index 2c71f14c2..780fe0358 100644 --- a/src/lib/__tests__/settings-conflicts.test.ts +++ b/src/store/__tests__/settings-conflicts.test.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../shared/analytics.js', () => ({ analytics: { captureException: vi.fn(), wizardCapture: vi.fn() }, })); @@ -10,9 +10,8 @@ import { checkAllSettingsConflicts, managedSettingsPath, classifySettingsConflicts, -} from '@lib/claude-settings'; -import type { SettingsConflict } from '@lib/claude-settings'; -import { buildAuthErrorContext } from '@lib/agent/agent-interface'; +} from '../services/claude-settings.js'; +import type { SettingsConflict } from '../services/claude-settings.js'; const OVERRIDE = JSON.stringify({ apiKeyHelper: 'echo sk-x' }); const ENV_OVERRIDE = JSON.stringify({ @@ -214,49 +213,3 @@ describe('classifySettingsConflicts', () => { expect(warnOnly.map((c) => c.source)).toEqual(['user', 'project-local']); }); }); - -describe('buildAuthErrorContext', () => { - it('reports no conflict and a default region when nothing overrides auth', () => { - const ctx = buildAuthErrorContext( - project, - 'https://ai-gateway.us.posthog.com', - home, - ); - - expect(ctx.hasSettingsConflict).toBe(false); - expect(ctx.conflicts).toEqual([]); - expect(ctx.conflictSources).toEqual([]); - expect(ctx.conflictKeys).toEqual([]); - expect(ctx.region).toBe('us'); - }); - - it('summarises conflicts and dedupes keys for telemetry', () => { - write(home, 'settings.json', JSON.stringify({ apiKeyHelper: 'x' })); - write(project, 'settings.json', JSON.stringify({ apiKeyHelper: 'y' })); - - const ctx = buildAuthErrorContext( - project, - 'https://ai-gateway.eu.posthog.com', - home, - ); - - expect(ctx.hasSettingsConflict).toBe(true); - expect(ctx.conflictSources).toEqual( - expect.arrayContaining(['user', 'project']), - ); - expect(ctx.conflictKeys).toEqual(['apiKeyHelper']); - expect(ctx.region).toBe('eu'); - }); - - it('derives the region from the gateway url', () => { - expect( - buildAuthErrorContext(project, 'https://ai-gateway.eu.posthog.com', home) - .region, - ).toBe('eu'); - expect( - buildAuthErrorContext(project, 'http://localhost:3308/wizard', home) - .region, - ).toBe('local'); - expect(buildAuthErrorContext(project, '', home).region).toBe('us'); - }); -}); diff --git a/src/lib/__tests__/token-pricing.test.ts b/src/store/__tests__/token-pricing.test.ts similarity index 99% rename from src/lib/__tests__/token-pricing.test.ts rename to src/store/__tests__/token-pricing.test.ts index 4a713cb19..92d728b2b 100644 --- a/src/lib/__tests__/token-pricing.test.ts +++ b/src/store/__tests__/token-pricing.test.ts @@ -3,7 +3,7 @@ import { pricePerMtokForModel, formatTokenCount, formatCostUsd, -} from '@lib/token-pricing'; +} from '../agent-protocol/token-pricing.js'; describe('pricePerMtokForModel', () => { it('defaults to Sonnet pricing (DEFAULT_AGENT_MODEL) when no model is given', () => { diff --git a/src/__tests__/wizard-abort.test.ts b/src/store/__tests__/wizard-abort.test.ts similarity index 95% rename from src/__tests__/wizard-abort.test.ts rename to src/store/__tests__/wizard-abort.test.ts index 8699354c6..6899c8330 100644 --- a/src/__tests__/wizard-abort.test.ts +++ b/src/store/__tests__/wizard-abort.test.ts @@ -5,13 +5,13 @@ import { registerCleanup, clearCleanup, runCleanups, -} from '@utils/wizard-abort'; -import { analytics } from '@utils/analytics'; -import { ErrorCodes } from '@lib/errors'; -import { getUI } from '../ui'; +} from '../shared/wizard-abort.js'; +import { analytics } from '../shared/analytics.js'; +import { ErrorCodes } from '../shared/errors/index.js'; +import { getUI } from '../ui/index.js'; -vi.mock('../utils/analytics'); -vi.mock('../ui', () => ({ +vi.mock('../shared/analytics.js'); +vi.mock('../ui/index.js', () => ({ getUI: vi.fn().mockReturnValue({ outroError: vi.fn(), waitForOutroDismissed: vi.fn().mockResolvedValue(undefined), @@ -247,7 +247,7 @@ describe('abort() delegates to wizardAbort()', () => { }); it('abort() calls wizardAbort with message and exitCode', async () => { - const { abort } = await import('@utils/setup-utils'); + const { abort } = await import('../shared/setup-utils.js'); await expect(abort('Test abort', 3)).rejects.toThrow('process.exit called'); @@ -258,7 +258,7 @@ describe('abort() delegates to wizardAbort()', () => { }); it('abort() uses defaults when called with no args', async () => { - const { abort } = await import('@utils/setup-utils'); + const { abort } = await import('../shared/setup-utils.js'); await expect(abort()).rejects.toThrow('process.exit called'); diff --git a/src/lib/__tests__/wizard-ask-bridge.test.ts b/src/store/__tests__/wizard-ask-bridge.test.ts similarity index 97% rename from src/lib/__tests__/wizard-ask-bridge.test.ts rename to src/store/__tests__/wizard-ask-bridge.test.ts index 1f12b9a4c..e33d2c0ce 100644 --- a/src/lib/__tests__/wizard-ask-bridge.test.ts +++ b/src/store/__tests__/wizard-ask-bridge.test.ts @@ -2,11 +2,11 @@ import { CANCELLED_SENTINEL, createWizardAskBridge, isFullyCancelled, -} from '@lib/wizard-ask-bridge'; -import { analytics } from '@utils/analytics'; -import type { AskAnswers, PendingQuestion } from '@lib/wizard-session'; +} from '../session/wizard-ask-bridge.js'; +import { analytics } from '../shared/analytics.js'; +import type { AskAnswers, PendingQuestion } from '../session/wizard-session.js'; -vi.mock('../../utils/analytics', () => ({ +vi.mock('../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), }, diff --git a/src/lib/__tests__/wizard-spellbook.test.ts b/src/store/__tests__/wizard-spellbook.test.ts similarity index 88% rename from src/lib/__tests__/wizard-spellbook.test.ts rename to src/store/__tests__/wizard-spellbook.test.ts index 727b5f5f1..aabaa3c5d 100644 --- a/src/lib/__tests__/wizard-spellbook.test.ts +++ b/src/store/__tests__/wizard-spellbook.test.ts @@ -1,14 +1,14 @@ import fs from 'fs/promises'; import os from 'os'; import path from 'path'; -import { Integration } from '../constants'; -import type { ProgramConfig } from '../programs/program-step'; -import { buildSession } from '../wizard-session'; -import { writeWizardSpellbook } from '../wizard-spellbook'; -import { downloadSkill, fetchSkillMenu } from '../wizard-tools/tools'; +import { Integration } from '../shared/constants.js'; +import type { ProgramConfig } from '../programs/program-step.js'; +import { buildSession } from '../session/wizard-session.js'; +import { writeWizardSpellbook } from '../wizard-spellbook.js'; +import { downloadSkill, fetchSkillMenu } from '../tools/tools.js'; -vi.mock('../wizard-tools/tools', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('../tools/tools.js', async (importOriginal) => ({ + ...(await importOriginal()), fetchSkillMenu: vi.fn(), downloadSkill: vi.fn(), })); diff --git a/src/lib/__tests__/wizard-tools.test.ts b/src/store/__tests__/wizard-tools.test.ts similarity index 99% rename from src/lib/__tests__/wizard-tools.test.ts rename to src/store/__tests__/wizard-tools.test.ts index 5ddeff913..791b37e1f 100644 --- a/src/lib/__tests__/wizard-tools.test.ts +++ b/src/store/__tests__/wizard-tools.test.ts @@ -28,8 +28,8 @@ import { resolveAskQuestionKinds, resolveEnvPath, templateEnvWriteRefusal, -} from '@lib/wizard-tools'; -import type { AuditCheck } from '@lib/programs/audit/types'; +} from '../tools/index.js'; +import type { AuditCheck } from '../programs/audit/types.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'wizard-tools-')); diff --git a/src/lib/agent-env-isolation.ts b/src/store/agent-protocol/agent-env-isolation.ts similarity index 100% rename from src/lib/agent-env-isolation.ts rename to src/store/agent-protocol/agent-env-isolation.ts diff --git a/src/lib/agent/agent-phase.ts b/src/store/agent-protocol/agent-phase.ts similarity index 100% rename from src/lib/agent/agent-phase.ts rename to src/store/agent-protocol/agent-phase.ts diff --git a/src/lib/agent-signals.ts b/src/store/agent-protocol/agent-signals.ts similarity index 100% rename from src/lib/agent-signals.ts rename to src/store/agent-protocol/agent-signals.ts diff --git a/src/store/agent-protocol/mcp-prompt.ts b/src/store/agent-protocol/mcp-prompt.ts new file mode 100644 index 000000000..27702ff8c --- /dev/null +++ b/src/store/agent-protocol/mcp-prompt.ts @@ -0,0 +1,42 @@ +import type { Credentials } from '../session/wizard-session.js'; + +/** One streamed piece of an MCP suggested-prompt run, as the TUI renders it. */ +export type AgentChunk = + | { kind: 'text'; text: string } + /** `command` carries CLI mode's exec command string (`call …`) so the + * screen can recover the inner tool for context-aware follow-ups. */ + | { kind: 'tool-call'; toolName: string; detail: string; command?: string } + | { kind: 'tool-result'; toolName: string; detail: string } + | { kind: 'error'; text: string } + /** Stream completed. `sessionId` is the SDK session ID of the just- + * completed turn; pass it back as `resumeSessionId` on a follow-up + * call to continue the conversation with full history. */ + | { kind: 'done'; sessionId?: string }; + +/** What the TUI asks the agent to run for a suggested prompt. */ +export interface McpPromptRequest { + prompt: string; + credentials: Credentials; + signal: AbortSignal; + /** Prior SDK session to continue, so a follow-up can reference earlier turns. */ + resumeSessionId?: string; + /** Program this run's gateway spend attributes to. */ + programId?: string; + integration?: string; +} + +/** Runs one suggested prompt. The agent surface provides it; the entry point installs it. */ +export interface McpPromptRunner { + runMcpPrompt(args: McpPromptRequest): AsyncIterable; +} + +let runner: McpPromptRunner | null = null; + +export function setMcpPromptRunner(next: McpPromptRunner): void { + runner = next; +} + +export function getMcpPromptRunner(): McpPromptRunner { + if (!runner) throw new Error('MCP prompt runner not installed'); + return runner; +} diff --git a/src/lib/program-run.ts b/src/store/agent-protocol/program-run.ts similarity index 97% rename from src/lib/program-run.ts rename to src/store/agent-protocol/program-run.ts index 5296e6a6b..dee08d757 100644 --- a/src/lib/program-run.ts +++ b/src/store/agent-protocol/program-run.ts @@ -9,9 +9,9 @@ import type { AdditionalFeature, WizardSession, TaskNotice, -} from '@lib/wizard-session'; -import type { PackageManagerDetector } from '@lib/detection/package-manager'; -import type { HostResolution } from '@lib/host-resolution'; +} from '../session/wizard-session.js'; +import type { PackageManagerDetector } from '../detection/package-manager.js'; +import type { HostResolution } from '../host-resolution.js'; export type { Credentials }; @@ -53,7 +53,7 @@ export interface AbortCase { message: string; body: string; docsUrl?: string; - errorCode?: import('@lib/errors').ErrorCode; + errorCode?: import('../shared/errors/index.js').ErrorCode; } /** diff --git a/src/lib/token-pricing.ts b/src/store/agent-protocol/token-pricing.ts similarity index 99% rename from src/lib/token-pricing.ts rename to src/store/agent-protocol/token-pricing.ts index 192168207..38fd4842b 100644 --- a/src/lib/token-pricing.ts +++ b/src/store/agent-protocol/token-pricing.ts @@ -35,7 +35,7 @@ import { DEFAULT_AGENT_MODEL, HAIKU_MODEL, SONNET_5_MODEL, -} from '@lib/constants'; +} from '../shared/constants.js'; export interface PricePerMtok { input: number; diff --git a/src/lib/api.ts b/src/store/api.ts similarity index 98% rename from src/lib/api.ts rename to src/store/api.ts index 02bf1c04a..20fe44a0b 100644 --- a/src/lib/api.ts +++ b/src/store/api.ts @@ -1,7 +1,7 @@ import axios, { AxiosError } from 'axios'; import { z } from 'zod'; -import { analytics } from '@utils/analytics'; -import { WIZARD_USER_AGENT } from './constants'; +import { analytics } from './shared/analytics.js'; +import { WIZARD_USER_AGENT } from './shared/constants.js'; /** * User payload from `/api/users/@me/`. Schema typed for the fields the diff --git a/src/lib/auth-session-state.ts b/src/store/auth-session-state.ts similarity index 100% rename from src/lib/auth-session-state.ts rename to src/store/auth-session-state.ts diff --git a/src/lib/cloudflare-detection.ts b/src/store/cloudflare-detection.ts similarity index 95% rename from src/lib/cloudflare-detection.ts rename to src/store/cloudflare-detection.ts index 7dfe304b8..f569ca255 100644 --- a/src/lib/cloudflare-detection.ts +++ b/src/store/cloudflare-detection.ts @@ -1,6 +1,6 @@ import fg from 'fast-glob'; -import { logToFile } from '@utils/debug'; -import { tryGetPackageJson } from '@utils/setup-utils'; +import { logToFile } from './shared/debug.js'; +import { tryGetPackageJson } from './shared/setup-utils.js'; const CLOUDFLARE_PACKAGES = [ '@react-router/cloudflare', diff --git a/src/lib/detection/__tests__/agentic.test.ts b/src/store/detection/__tests__/agentic.test.ts similarity index 99% rename from src/lib/detection/__tests__/agentic.test.ts rename to src/store/detection/__tests__/agentic.test.ts index c63335c74..01a159dbd 100644 --- a/src/lib/detection/__tests__/agentic.test.ts +++ b/src/store/detection/__tests__/agentic.test.ts @@ -3,7 +3,7 @@ import { deriveReportJson, manifestGlob, resolveProjectDir, -} from '@lib/detection/agentic'; +} from '../agentic.js'; const TARGETS = ['nextjs', 'node', 'vite']; diff --git a/src/lib/detection/__tests__/context.test.ts b/src/store/detection/__tests__/context.test.ts similarity index 92% rename from src/lib/detection/__tests__/context.test.ts rename to src/store/detection/__tests__/context.test.ts index 138b94d0c..ae197fe2d 100644 --- a/src/lib/detection/__tests__/context.test.ts +++ b/src/store/detection/__tests__/context.test.ts @@ -1,9 +1,6 @@ -import { - gatherFrameworkContext, - checkFrameworkVersion, -} from '@lib/detection/context'; -import type { FrameworkConfig } from '@lib/framework-config'; -import type { WizardRunOptions } from '@utils/types'; +import { gatherFrameworkContext, checkFrameworkVersion } from '../context.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import type { WizardRunOptions } from '../../shared/types.js'; const baseOptions: WizardRunOptions = { installDir: '/test/dir', diff --git a/src/lib/detection/__tests__/features.test.ts b/src/store/detection/__tests__/features.test.ts similarity index 97% rename from src/lib/detection/__tests__/features.test.ts rename to src/store/detection/__tests__/features.test.ts index a5a21ff7f..2b26df548 100644 --- a/src/lib/detection/__tests__/features.test.ts +++ b/src/store/detection/__tests__/features.test.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { discoverFeatures } from '@lib/detection/features'; -import { DiscoveredFeature } from '@lib/wizard-session'; +import { discoverFeatures } from '../features.js'; +import { DiscoveredFeature } from '../../session/wizard-session.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'features-detect-')); diff --git a/src/lib/detection/__tests__/framework.test.ts b/src/store/detection/__tests__/framework.test.ts similarity index 95% rename from src/lib/detection/__tests__/framework.test.ts rename to src/store/detection/__tests__/framework.test.ts index 947159368..73b2ef77d 100644 --- a/src/lib/detection/__tests__/framework.test.ts +++ b/src/store/detection/__tests__/framework.test.ts @@ -1,15 +1,15 @@ import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; -import { detectFramework } from '@lib/detection/framework'; -import { Integration } from '@lib/constants'; -import { ANDROID_AGENT_CONFIG } from '../../../frameworks/android/android-wizard-agent'; -import { KMP_AGENT_CONFIG } from '../../../frameworks/kmp/kmp-wizard-agent'; -import { ELIXIR_AGENT_CONFIG } from '../../../frameworks/elixir/elixir-wizard-agent'; -import { GO_AGENT_CONFIG } from '../../../frameworks/go/go-wizard-agent'; -import { JAVA_AGENT_CONFIG } from '../../../frameworks/java/java-wizard-agent'; -import { RUST_AGENT_CONFIG } from '../../../frameworks/rust/rust-wizard-agent'; -import { FLUTTER_AGENT_CONFIG } from '../../../frameworks/flutter/flutter-wizard-agent'; +import { detectFramework } from '../framework.js'; +import { Integration } from '../../shared/constants.js'; +import { ANDROID_AGENT_CONFIG } from '../../frameworks/android/android-wizard-agent.js'; +import { KMP_AGENT_CONFIG } from '../../frameworks/kmp/kmp-wizard-agent.js'; +import { ELIXIR_AGENT_CONFIG } from '../../frameworks/elixir/elixir-wizard-agent.js'; +import { GO_AGENT_CONFIG } from '../../frameworks/go/go-wizard-agent.js'; +import { JAVA_AGENT_CONFIG } from '../../frameworks/java/java-wizard-agent.js'; +import { RUST_AGENT_CONFIG } from '../../frameworks/rust/rust-wizard-agent.js'; +import { FLUTTER_AGENT_CONFIG } from '../../frameworks/flutter/flutter-wizard-agent.js'; /** A throwaway project dir seeded with the given files. */ function makeProject(files: Record): string { diff --git a/src/lib/detection/__tests__/package-manager.test.ts b/src/store/detection/__tests__/package-manager.test.ts similarity index 98% rename from src/lib/detection/__tests__/package-manager.test.ts rename to src/store/detection/__tests__/package-manager.test.ts index e74e27733..49b3109c8 100644 --- a/src/lib/detection/__tests__/package-manager.test.ts +++ b/src/store/detection/__tests__/package-manager.test.ts @@ -12,13 +12,13 @@ import { mixPackageManager, goModulesPackageManager, pubPackageManager, -} from '@lib/detection/package-manager'; +} from '../package-manager.js'; -vi.mock('../../../utils/debug'); -vi.mock('../../../telemetry', () => ({ +vi.mock('../../shared/debug.js'); +vi.mock('../../shared/telemetry.js', () => ({ withProgress: (_name: string, fn: () => unknown) => fn(), })); -vi.mock('../../../utils/analytics', () => ({ +vi.mock('../../shared/analytics.js', () => ({ analytics: { setTag: vi.fn() }, })); diff --git a/src/lib/detection/__tests__/project-scope.test.ts b/src/store/detection/__tests__/project-scope.test.ts similarity index 93% rename from src/lib/detection/__tests__/project-scope.test.ts rename to src/store/detection/__tests__/project-scope.test.ts index 46aedaf04..4dc7d2fe6 100644 --- a/src/lib/detection/__tests__/project-scope.test.ts +++ b/src/store/detection/__tests__/project-scope.test.ts @@ -1,25 +1,22 @@ -import { - detectProjectsWithAgent, - type AgenticProject, -} from '@lib/detection/agentic'; +import { detectProjectsWithAgent, type AgenticProject } from '../agentic.js'; import { chooseIntegrationProject, scopeInstallDirToProject, -} from '@lib/detection/project-scope'; +} from '../project-scope.js'; import { AGENTIC_DETECTION_TIMEOUT_MS, WIZARD_BASIC_INTEGRATION_AGENTIC_DETECTION_FLAG_KEY, -} from '@lib/constants'; -import { authenticate } from '@lib/agent/runner/shared/authenticate'; -import { buildSession } from '@lib/wizard-session'; -import { analytics } from '@utils/analytics'; +} from '../../shared/constants.js'; +import { authenticate } from '../../services/authenticate.js'; +import { buildSession } from '../../session/wizard-session.js'; +import { analytics } from '../../shared/analytics.js'; // Mock only the two network edges of scopeInstallDirToProject; everything else runs real. -vi.mock('@lib/agent/runner/shared/authenticate', () => ({ +vi.mock('../../services/authenticate.js', () => ({ authenticate: vi.fn().mockResolvedValue(undefined), })); -vi.mock('@lib/detection/agentic', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('../agentic.js', async (importOriginal) => ({ + ...(await importOriginal()), detectProjectsWithAgent: vi.fn(), })); diff --git a/src/store/detection/agentic.ts b/src/store/detection/agentic.ts new file mode 100644 index 000000000..6363a4b31 --- /dev/null +++ b/src/store/detection/agentic.ts @@ -0,0 +1,241 @@ +/** + * Agentic project detection. + * + * A reusable detection tool that drives a Haiku agent over the repo: it finds + * project roots, resolves monorepo/workspace markers, reads package manifests, + * classifies each project against a caller-supplied set of targets, and reports + * which projects already have a PostHog SDK installed. + * + * Product-knowledge-free by design — the caller passes the targets to classify + * into (e.g. source-map skill variants) and maps the result back. Sits next to + * the other detection tools (framework, features, package-manager) so it's + * discoverable. Runs AFTER auth: it uses the same agent loop every program + * uses, which needs credentials. + */ + +import { isAbsolute, resolve, sep } from 'path'; +import type { WizardSession } from '../session/wizard-session.js'; + +/** A category the agent classifies each project into (id the agent returns). */ +export type DetectTarget = { id: string; name: string }; + +/** One project the agent found in the repo. */ +export type AgenticProject = { + /** Path relative to the working directory ("." for the repo root). */ + path: string; + /** Human-readable framework the agent detected (e.g. "Next.js"). */ + framework: string; + /** A target id when the project matches one of the supplied targets, else null. */ + targetId: string | null; + /** Whether a PostHog SDK is already installed in this project. */ + hasPostHog: boolean; + /** True on the one project picked as the main user-facing app; only present when the scan set `recommend`. */ + recommended?: boolean; +}; + +export type AgenticDetectionReport = { + repoType: 'monorepo' | 'single'; + projects: AgenticProject[]; +}; + +/** Streaming progress callback — one short activity line per agent step. */ +export type DetectEvent = (line: string) => void; + +/** + * Every project-manifest / workspace-marker filename the wizard's frameworks + * are identified by. One brace-expansion Glob over all of these locates every + * project root in the repo in a single call, regardless of language. + * + * Counterpart: POSTHOG_MANIFESTS in @lib/programs/self-driving/detect (SDK + * grep); keep the two in sync. + */ +export const PROJECT_MANIFESTS: readonly string[] = [ + // JS/TS + workspace markers + 'package.json', + 'pnpm-workspace.yaml', + 'turbo.json', + 'nx.json', + 'lerna.json', + // Python + 'requirements.txt', + 'pyproject.toml', + 'setup.py', + 'Pipfile', + 'manage.py', + // Ruby / PHP + 'Gemfile', + 'composer.json', + // Java + 'pom.xml', + // Rust + 'Cargo.toml', + // Elixir + 'mix.exs', + // Go + 'go.mod', + // .NET: no framework targets yet, but found so + // an existing PostHog SDK is reported (feeds self-driving's "continue" path). + '*.csproj', + // Mobile / native + 'Package.swift', + 'Podfile', + 'project.yml', + 'project.pbxproj', + 'pubspec.yaml', + 'build.gradle', + 'build.gradle.kts', + 'settings.gradle', + 'settings.gradle.kts', + // Gradle version catalog (holds dependency coordinates). + 'gradle/libs.versions.toml', +]; + +/** The single brace-expansion glob covering every supported manifest. */ +export function manifestGlob(): string { + return `**/{${PROJECT_MANIFESTS.join(',')}}`; +} + +export type AgenticDetectOptions = { + /** + * Categories to classify each project into. Order matters: list targets by + * priority, most specific first. When a project could match more than one, + * the agent keeps the earliest — so the caller encodes precedence purely + * through ordering (e.g. a bundler target before a generic framework target). + */ + targets: readonly DetectTarget[]; + /** The program this scan bills to. Required, not optional: the scan drives a + * real agent through the gateway, and a caller that forgets leaves that + * spend unattributed. */ + programId: string; + /** One short clause describing what the scan is for (frames the prompt). */ + purpose?: string; + /** Ask the agent to label exactly one project `recommended` (the main client app). Off by default. */ + recommend?: boolean; + /** + * Target ids whose technologies co-occur in one manifest (e.g. the JS + * family). Among these, the enumeration's priority winner overrides the + * model's pick; elsewhere a valid pick always wins — see coerceAgenticReport. + */ + rerankIds?: readonly string[]; + /** Streaming activity callback for the UI. */ + onEvent?: DetectEvent; +}; + +export function deriveReportJson(text: string): unknown | null { + const byPath = new Map>(); + for (const line of text.split('\n')) { + const start = line.indexOf('{'); + const end = line.lastIndexOf('}'); + if (start === -1 || end <= start) continue; + let parsed: unknown; + try { + parsed = JSON.parse(line.slice(start, end + 1)); + } catch { + continue; // not JSON — prose, shape echoes, pretty-printed fragments + } + const obj = (parsed ?? {}) as Record; + const candidates = Array.isArray(obj.projects) ? obj.projects : [obj]; + for (const candidate of candidates) { + const p = (candidate ?? {}) as Record; + if (typeof p.path === 'string') byPath.set(p.path, p); + } + } + if (byPath.size === 0) return null; + const projects = [...byPath.values()]; + return { repoType: projects.length > 1 ? 'monorepo' : 'single', projects }; +} + +/** + * Clamp an agent-reported project path to a safe repo-relative dir. The path + * is LLM output: absolute paths or `..` segments could steer later phases + * (e.g. integrate-run's targetDir) outside the repo, so they clamp to '.'. + */ +function coercePath(raw: unknown): string { + if (typeof raw !== 'string' || raw.length === 0) return '.'; + if (isAbsolute(raw) || raw.split(/[\\/]/).includes('..')) return '.'; + return raw; +} + +/** Resolve an agent-reported path to an absolute dir clamped to the root — the caller-side counterpart of coercePath. */ +export function resolveProjectDir(installDir: string, rel: unknown): string { + if (typeof rel !== 'string' || rel === '.') return installDir; + const root = resolve(installDir); + const dir = resolve(root, rel); + return dir === root || dir.startsWith(root + sep) ? dir : root; +} + +/** + * Validate the agent's raw JSON into a report, clamping each targetId to the + * supplied set and each path to a repo-relative dir. Exported for testing. + * `recommended` is stripped unless requested; at most one (the first) survives. + */ +export function coerceAgenticReport( + parsed: unknown, + validTargetIds: readonly string[], + options?: { recommend?: boolean; rerankIds?: readonly string[] }, +): AgenticDetectionReport { + const recommend = options?.recommend === true; + const rerankIds = options?.rerankIds ?? []; + const obj = (parsed ?? {}) as Record; + const repoType = obj.repoType === 'monorepo' ? 'monorepo' : 'single'; + const rawProjects = Array.isArray(obj.projects) ? obj.projects : []; + let recommendedSeen = false; + const projects: AgenticProject[] = rawProjects.map((raw) => { + const p = (raw ?? {}) as Record; + // Trust the model's pick; an invalid one falls back to the enumeration's + // highest-priority member (validTargetIds IS the priority order). The + // winner overrides a valid pick only when both sit in rerankIds — stacks + // that co-occur in one manifest, where a misordered enumeration is the + // common miss. Elsewhere enumerations are padded across exclusive stacks + // (a Flutter app listing react-native) and must not beat a correct pick. + const pick = + typeof p.targetId === 'string' && validTargetIds.includes(p.targetId) + ? p.targetId + : null; + const enumerated = Array.isArray(p.matchingTargets) + ? validTargetIds.find((id) => + (p.matchingTargets as unknown[]).includes(id), + ) ?? null + : null; + const targetId = + pick === null + ? enumerated + : enumerated !== null && + rerankIds.includes(enumerated) && + rerankIds.includes(pick) + ? enumerated + : pick; + const recommended = recommend && !recommendedSeen && p.recommended === true; + recommendedSeen ||= recommended; + return { + path: coercePath(p.path), + framework: typeof p.framework === 'string' ? p.framework : 'Unknown', + targetId, + hasPostHog: p.hasPostHog === true, + ...(recommend ? { recommended } : {}), + }; + }); + return { repoType, projects }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any + +/** Runs the detection agent. The agent surface provides it; the entry point installs it. */ +export type DetectProjectsWithAgent = ( + session: WizardSession, + options: AgenticDetectOptions, +) => Promise; + +let detectionAgent: DetectProjectsWithAgent | null = null; + +export function setDetectionAgent(fn: DetectProjectsWithAgent): void { + detectionAgent = fn; +} + +export function detectProjectsWithAgent( + session: WizardSession, + options: AgenticDetectOptions, +): Promise { + if (!detectionAgent) throw new Error('detection agent not installed'); + return detectionAgent(session, options); +} diff --git a/src/lib/detection/context.ts b/src/store/detection/context.ts similarity index 91% rename from src/lib/detection/context.ts rename to src/store/detection/context.ts index 5ecb68925..0f16c755b 100644 --- a/src/lib/detection/context.ts +++ b/src/store/detection/context.ts @@ -7,9 +7,9 @@ */ import * as semver from 'semver'; -import { DETECTION_TIMEOUT_MS } from '@lib/constants'; -import type { FrameworkConfig } from '@lib/framework-config'; -import type { WizardRunOptions } from '@utils/types'; +import { DETECTION_TIMEOUT_MS } from '../shared/constants.js'; +import type { FrameworkConfig } from '../framework-config.js'; +import type { WizardRunOptions } from '../shared/types.js'; /** * Run a framework's `gatherContext()` to collect variant-specific diff --git a/src/lib/detection/features.ts b/src/store/detection/features.ts similarity index 97% rename from src/lib/detection/features.ts rename to src/store/detection/features.ts index 2975d5f6c..2cdb88472 100644 --- a/src/lib/detection/features.ts +++ b/src/store/detection/features.ts @@ -7,8 +7,8 @@ */ import { join } from 'path'; -import { readProjectFile } from '@utils/bounded-fs'; -import { DiscoveredFeature } from '@lib/wizard-session'; +import { readProjectFile } from '../shared/bounded-fs.js'; +import { DiscoveredFeature } from '../session/wizard-session.js'; const STRIPE_PACKAGES = new Set(['stripe', '@stripe/stripe-js']); diff --git a/src/lib/detection/framework.ts b/src/store/detection/framework.ts similarity index 88% rename from src/lib/detection/framework.ts rename to src/store/detection/framework.ts index 4efd9f6bf..354a018f7 100644 --- a/src/lib/detection/framework.ts +++ b/src/store/detection/framework.ts @@ -6,8 +6,8 @@ * (or undefined). No store mutations, no UI calls. */ -import { Integration, DETECTION_TIMEOUT_MS } from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; +import { Integration, DETECTION_TIMEOUT_MS } from '../shared/constants.js'; +import { FRAMEWORK_REGISTRY } from '../registry.js'; /** * Loop through all registered frameworks and return the first one diff --git a/src/lib/detection/index.ts b/src/store/detection/index.ts similarity index 100% rename from src/lib/detection/index.ts rename to src/store/detection/index.ts diff --git a/src/lib/detection/package-manager.ts b/src/store/detection/package-manager.ts similarity index 99% rename from src/lib/detection/package-manager.ts rename to src/store/detection/package-manager.ts index be50909fb..8fe77e0dd 100644 --- a/src/lib/detection/package-manager.ts +++ b/src/store/detection/package-manager.ts @@ -12,11 +12,11 @@ import * as path from 'node:path'; import { detectAllPackageManagers, type PackageManager, -} from '@utils/package-manager'; +} from '../shared/package-manager.js'; import { detectPackageManager as detectPythonPM, PythonPackageManager, -} from '@frameworks/python/utils'; +} from '../frameworks/python/utils.js'; // --------------------------------------------------------------------------- // Common types diff --git a/src/lib/detection/project-scope.ts b/src/store/detection/project-scope.ts similarity index 95% rename from src/lib/detection/project-scope.ts rename to src/store/detection/project-scope.ts index 73279b075..1d6ab18d1 100644 --- a/src/lib/detection/project-scope.ts +++ b/src/store/detection/project-scope.ts @@ -8,17 +8,17 @@ import { type DetectEvent, type DetectTarget, } from './agentic.js'; -import { authenticate } from '@lib/agent/runner/shared/authenticate'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; +import { authenticate } from '../services/authenticate.js'; +import { FRAMEWORK_REGISTRY } from '../registry.js'; import { AGENTIC_DETECTION_TIMEOUT_MS, Integration, WIZARD_BASIC_INTEGRATION_AGENTIC_DETECTION_FLAG_KEY, -} from '@lib/constants'; -import type { WizardSession } from '@lib/wizard-session'; -import { getUI } from '@ui/index'; -import { analytics } from '@utils/analytics'; -import { logToFile } from '@utils/debug'; +} from '../shared/constants.js'; +import type { WizardSession } from '../session/wizard-session.js'; +import { getUI } from '../ui/index.js'; +import { analytics } from '../shared/analytics.js'; +import { logToFile } from '../shared/debug.js'; /** Integration framework targets for the agentic detector (id → display name). */ const INTEGRATION_TARGETS: DetectTarget[] = Object.entries( diff --git a/src/lib/fetch-retry.ts b/src/store/fetch-retry.ts similarity index 97% rename from src/lib/fetch-retry.ts rename to src/store/fetch-retry.ts index ee6edfe25..a8682ff49 100644 --- a/src/lib/fetch-retry.ts +++ b/src/store/fetch-retry.ts @@ -6,9 +6,9 @@ * asset redirects and blocked regions where the asset is present. */ -import { logToFile } from '@utils/debug'; -import { analytics } from '@utils/analytics'; -import { CONTEXT_MILL_URL, AWS_SKILLS_BASE_URL } from './constants'; +import { logToFile } from './shared/debug.js'; +import { analytics } from './shared/analytics.js'; +import { CONTEXT_MILL_URL, AWS_SKILLS_BASE_URL } from './shared/constants.js'; const DEFAULT_TIMEOUT_MS = 60000; // per attempt const DEFAULT_MAX_ATTEMPTS = 3; diff --git a/src/lib/file-watcher.ts b/src/store/file-watcher.ts similarity index 99% rename from src/lib/file-watcher.ts rename to src/store/file-watcher.ts index 1d3d07cc8..0ab175ef1 100644 --- a/src/lib/file-watcher.ts +++ b/src/store/file-watcher.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import { basename, dirname } from 'node:path'; -import { logToFile } from '@utils/debug'; +import { logToFile } from './shared/debug.js'; const DEFAULT_POLL_INTERVAL_MS = 5000; const DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1000; diff --git a/src/lib/framework-config.ts b/src/store/framework-config.ts similarity index 98% rename from src/lib/framework-config.ts rename to src/store/framework-config.ts index 5bbc7440b..0d7b0edc2 100644 --- a/src/lib/framework-config.ts +++ b/src/store/framework-config.ts @@ -1,6 +1,6 @@ -import type { Integration } from './constants'; -import type { WizardRunOptions } from '@utils/types'; -import type { PackageManagerDetector } from './detection/package-manager'; +import type { Integration } from './shared/constants.js'; +import type { WizardRunOptions } from './shared/types.js'; +import type { PackageManagerDetector } from './detection/package-manager.js'; /** * A setup question that the SetupScreen renders for framework disambiguation. diff --git a/src/frameworks/android/android-wizard-agent.ts b/src/store/frameworks/android/android-wizard-agent.ts similarity index 92% rename from src/frameworks/android/android-wizard-agent.ts rename to src/store/frameworks/android/android-wizard-agent.ts index dd9acaebf..176c965c7 100644 --- a/src/frameworks/android/android-wizard-agent.ts +++ b/src/store/frameworks/android/android-wizard-agent.ts @@ -1,16 +1,16 @@ /* Android (Kotlin) wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { Integration } from '@lib/constants'; -import { boundedGlob } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { Integration } from '../../shared/constants.js'; +import { boundedGlob } from '../../shared/bounded-fs.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { getKotlinVersion, getKotlinVersionBucket, getMinSdkVersion, -} from './utils'; -import { gradlePackageManager } from '@lib/detection/package-manager'; +} from './utils.js'; +import { gradlePackageManager } from '../../detection/package-manager.js'; type AndroidContext = { kotlinVersion?: string; diff --git a/src/frameworks/android/utils.ts b/src/store/frameworks/android/utils.ts similarity index 89% rename from src/frameworks/android/utils.ts rename to src/store/frameworks/android/utils.ts index 4afad3c77..b827b1a38 100644 --- a/src/frameworks/android/utils.ts +++ b/src/store/frameworks/android/utils.ts @@ -1,6 +1,6 @@ -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/angular/angular-wizard-agent.ts b/src/store/frameworks/angular/angular-wizard-agent.ts similarity index 85% rename from src/frameworks/angular/angular-wizard-agent.ts rename to src/store/frameworks/angular/angular-wizard-agent.ts index 7db04b37a..266e7570a 100644 --- a/src/frameworks/angular/angular-wizard-agent.ts +++ b/src/store/frameworks/angular/angular-wizard-agent.ts @@ -1,16 +1,16 @@ /* Angular wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getAngularVersionBucket } from './utils'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getAngularVersionBucket } from './utils.js'; type AngularContext = Record; diff --git a/src/frameworks/angular/utils.ts b/src/store/frameworks/angular/utils.ts similarity index 64% rename from src/frameworks/angular/utils.ts rename to src/store/frameworks/angular/utils.ts index f820ac582..13e4084d8 100644 --- a/src/frameworks/angular/utils.ts +++ b/src/store/frameworks/angular/utils.ts @@ -1,4 +1,4 @@ -import { createVersionBucket } from '@utils/semver'; +import { createVersionBucket } from '../../shared/semver.js'; /** * Get Angular version bucket for analytics diff --git a/src/frameworks/astro/astro-wizard-agent.ts b/src/store/frameworks/astro/astro-wizard-agent.ts similarity index 91% rename from src/frameworks/astro/astro-wizard-agent.ts rename to src/store/frameworks/astro/astro-wizard-agent.ts index f427935ab..52dc31972 100644 --- a/src/frameworks/astro/astro-wizard-agent.ts +++ b/src/store/frameworks/astro/astro-wizard-agent.ts @@ -1,22 +1,22 @@ /* Astro wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getUI } from '@ui'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getUI } from '../../ui/index.js'; import { getAstroRenderingMode, getAstroVersionBucket, getAstroRenderingModeName, AstroRenderingMode, -} from './utils'; +} from './utils.js'; type AstroContext = { renderingMode?: AstroRenderingMode; diff --git a/src/frameworks/astro/utils.ts b/src/store/frameworks/astro/utils.ts similarity index 93% rename from src/frameworks/astro/utils.ts rename to src/store/frameworks/astro/utils.ts index 28db0f641..d0fea2891 100644 --- a/src/frameworks/astro/utils.ts +++ b/src/store/frameworks/astro/utils.ts @@ -1,8 +1,8 @@ -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import fs from 'fs/promises'; import path from 'path'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; export const getAstroVersionBucket = createVersionBucket(); diff --git a/src/frameworks/django/django-wizard-agent.ts b/src/store/frameworks/django/django-wizard-agent.ts similarity index 91% rename from src/frameworks/django/django-wizard-agent.ts rename to src/store/frameworks/django/django-wizard-agent.ts index 30e2660aa..e0598aee0 100644 --- a/src/frameworks/django/django-wizard-agent.ts +++ b/src/store/frameworks/django/django-wizard-agent.ts @@ -1,10 +1,10 @@ /* Django wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { PYTHON_PACKAGE_INSTALLATION } from '@lib/framework-config'; -import { detectPythonPackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { PYTHON_PACKAGE_INSTALLATION } from '../../framework-config.js'; +import { detectPythonPackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import * as path from 'node:path'; import { getDjangoVersion, @@ -13,7 +13,7 @@ import { getDjangoVersionBucket, DjangoProjectType, findDjangoSettingsFile, -} from './utils'; +} from './utils.js'; const EXTRA_IGNORE = ['**/env/**', '**/.env/**']; diff --git a/src/frameworks/django/utils.ts b/src/store/frameworks/django/utils.ts similarity index 96% rename from src/frameworks/django/utils.ts rename to src/store/frameworks/django/utils.ts index 276c2b746..7ea0544e4 100644 --- a/src/frameworks/django/utils.ts +++ b/src/store/frameworks/django/utils.ts @@ -1,7 +1,7 @@ -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/elixir/elixir-wizard-agent.ts b/src/store/frameworks/elixir/elixir-wizard-agent.ts similarity index 93% rename from src/frameworks/elixir/elixir-wizard-agent.ts rename to src/store/frameworks/elixir/elixir-wizard-agent.ts index 26eb007e1..c71711e4f 100644 --- a/src/frameworks/elixir/elixir-wizard-agent.ts +++ b/src/store/frameworks/elixir/elixir-wizard-agent.ts @@ -1,10 +1,10 @@ /* Elixir wizard using posthog-agent with PostHog MCP */ import * as fs from 'node:fs'; import * as path from 'node:path'; -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { mixPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { mixPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; type ElixirContext = { phoenix?: boolean; diff --git a/src/frameworks/fastapi/fastapi-wizard-agent.ts b/src/store/frameworks/fastapi/fastapi-wizard-agent.ts similarity index 92% rename from src/frameworks/fastapi/fastapi-wizard-agent.ts rename to src/store/frameworks/fastapi/fastapi-wizard-agent.ts index 61f0d8d8d..bea765d2f 100644 --- a/src/frameworks/fastapi/fastapi-wizard-agent.ts +++ b/src/store/frameworks/fastapi/fastapi-wizard-agent.ts @@ -1,9 +1,9 @@ /* FastAPI wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { PYTHON_PACKAGE_INSTALLATION } from '@lib/framework-config'; -import { detectPythonPackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { PYTHON_PACKAGE_INSTALLATION } from '../../framework-config.js'; +import { detectPythonPackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getFastAPIVersion, getFastAPIProjectType, @@ -11,8 +11,8 @@ import { getFastAPIVersionBucket, FastAPIProjectType, findFastAPIAppFile, -} from './utils'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +} from './utils.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import * as path from 'node:path'; const EXTRA_IGNORE = ['**/env/**', '**/.env/**']; diff --git a/src/frameworks/fastapi/utils.ts b/src/store/frameworks/fastapi/utils.ts similarity index 97% rename from src/frameworks/fastapi/utils.ts rename to src/store/frameworks/fastapi/utils.ts index b208dd72f..e8fd56850 100644 --- a/src/frameworks/fastapi/utils.ts +++ b/src/store/frameworks/fastapi/utils.ts @@ -1,7 +1,7 @@ import { major, minVersion } from 'semver'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; import * as path from 'node:path'; export enum FastAPIProjectType { diff --git a/src/frameworks/flask/flask-wizard-agent.ts b/src/store/frameworks/flask/flask-wizard-agent.ts similarity index 91% rename from src/frameworks/flask/flask-wizard-agent.ts rename to src/store/frameworks/flask/flask-wizard-agent.ts index 539afa840..7234e608f 100644 --- a/src/frameworks/flask/flask-wizard-agent.ts +++ b/src/store/frameworks/flask/flask-wizard-agent.ts @@ -1,10 +1,10 @@ /* Flask wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { PYTHON_PACKAGE_INSTALLATION } from '@lib/framework-config'; -import { detectPythonPackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { PYTHON_PACKAGE_INSTALLATION } from '../../framework-config.js'; +import { detectPythonPackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import * as path from 'node:path'; import { getFlaskVersion, @@ -13,7 +13,7 @@ import { getFlaskVersionBucket, FlaskProjectType, findFlaskAppFile, -} from './utils'; +} from './utils.js'; const EXTRA_IGNORE = ['**/env/**', '**/.env/**']; diff --git a/src/frameworks/flask/utils.ts b/src/store/frameworks/flask/utils.ts similarity index 97% rename from src/frameworks/flask/utils.ts rename to src/store/frameworks/flask/utils.ts index 66eb46a1c..bb3a89d9c 100644 --- a/src/frameworks/flask/utils.ts +++ b/src/store/frameworks/flask/utils.ts @@ -1,7 +1,7 @@ -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as path from 'node:path'; export enum FlaskProjectType { diff --git a/src/frameworks/flutter/flutter-wizard-agent.ts b/src/store/frameworks/flutter/flutter-wizard-agent.ts similarity index 93% rename from src/frameworks/flutter/flutter-wizard-agent.ts rename to src/store/frameworks/flutter/flutter-wizard-agent.ts index 8a44cddfc..8b69f84d3 100644 --- a/src/frameworks/flutter/flutter-wizard-agent.ts +++ b/src/store/frameworks/flutter/flutter-wizard-agent.ts @@ -1,10 +1,10 @@ /* Flutter wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { Integration } from '../../shared/constants.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import { pubPackageManager } from '@lib/detection/package-manager'; +import { pubPackageManager } from '../../detection/package-manager.js'; /** Platform subtrees `flutter create` scaffolds; each needs its own setup notes. */ const FLUTTER_PLATFORM_DIRS = [ diff --git a/src/frameworks/go/go-wizard-agent.ts b/src/store/frameworks/go/go-wizard-agent.ts similarity index 92% rename from src/frameworks/go/go-wizard-agent.ts rename to src/store/frameworks/go/go-wizard-agent.ts index 6010e945b..f4155821a 100644 --- a/src/frameworks/go/go-wizard-agent.ts +++ b/src/store/frameworks/go/go-wizard-agent.ts @@ -1,10 +1,10 @@ /* Go wizard using posthog-agent with PostHog MCP */ import * as fs from 'node:fs'; import * as path from 'node:path'; -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { goModulesPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { goModulesPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; type GoContext = { goVersion?: string; diff --git a/src/frameworks/java/java-wizard-agent.ts b/src/store/frameworks/java/java-wizard-agent.ts similarity index 95% rename from src/frameworks/java/java-wizard-agent.ts rename to src/store/frameworks/java/java-wizard-agent.ts index 9223a0525..055d6ea7d 100644 --- a/src/frameworks/java/java-wizard-agent.ts +++ b/src/store/frameworks/java/java-wizard-agent.ts @@ -2,10 +2,10 @@ import fg from 'fast-glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectJavaPackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectJavaPackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; type JavaContext = { buildTool?: 'maven' | 'gradle'; diff --git a/src/frameworks/javascript-node/javascript-node-wizard-agent.ts b/src/store/frameworks/javascript-node/javascript-node-wizard-agent.ts similarity index 89% rename from src/frameworks/javascript-node/javascript-node-wizard-agent.ts rename to src/store/frameworks/javascript-node/javascript-node-wizard-agent.ts index fb12fb38e..e83ee3f28 100644 --- a/src/frameworks/javascript-node/javascript-node-wizard-agent.ts +++ b/src/store/frameworks/javascript-node/javascript-node-wizard-agent.ts @@ -1,8 +1,8 @@ /* Generic Node.js language wizard using posthog-agent with PostHog MCP */ -import type { FrameworkConfig } from '@lib/framework-config'; -import { Integration } from '@lib/constants'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { Integration } from '../../shared/constants.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; type JavaScriptNodeContext = Record; diff --git a/src/frameworks/javascript-web/javascript-web-wizard-agent.ts b/src/store/frameworks/javascript-web/javascript-web-wizard-agent.ts similarity index 91% rename from src/frameworks/javascript-web/javascript-web-wizard-agent.ts rename to src/store/frameworks/javascript-web/javascript-web-wizard-agent.ts index 1f963eab3..bd65fe3cd 100644 --- a/src/frameworks/javascript-web/javascript-web-wizard-agent.ts +++ b/src/store/frameworks/javascript-web/javascript-web-wizard-agent.ts @@ -1,19 +1,19 @@ /* Generic JavaScript Web (client-side) wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { Integration } from '../../shared/constants.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import { hasDeclaredDependency } from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; +import { hasDeclaredDependency } from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; import { FRAMEWORK_PACKAGES, detectJsPackageManager, detectBundler, hasIndexHtml, type JavaScriptContext, -} from './utils'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; +} from './utils.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; export const JAVASCRIPT_WEB_AGENT_CONFIG: FrameworkConfig = { metadata: { diff --git a/src/frameworks/javascript-web/utils.ts b/src/store/frameworks/javascript-web/utils.ts similarity index 91% rename from src/frameworks/javascript-web/utils.ts rename to src/store/frameworks/javascript-web/utils.ts index 276b72216..110edaa2f 100644 --- a/src/frameworks/javascript-web/utils.ts +++ b/src/store/frameworks/javascript-web/utils.ts @@ -1,8 +1,8 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; -import { boundedGlob } from '@utils/bounded-fs'; -import { detectAllPackageManagers } from '@utils/package-manager'; -import type { WizardRunOptions } from '@utils/types'; +import { boundedGlob } from '../../shared/bounded-fs.js'; +import { detectAllPackageManagers } from '../../shared/package-manager.js'; +import type { WizardRunOptions } from '../../shared/types.js'; export type JavaScriptContext = { packageManagerName?: string; diff --git a/src/frameworks/kmp/kmp-wizard-agent.ts b/src/store/frameworks/kmp/kmp-wizard-agent.ts similarity index 93% rename from src/frameworks/kmp/kmp-wizard-agent.ts rename to src/store/frameworks/kmp/kmp-wizard-agent.ts index 6fa6085d2..51dd01bd6 100644 --- a/src/frameworks/kmp/kmp-wizard-agent.ts +++ b/src/store/frameworks/kmp/kmp-wizard-agent.ts @@ -1,8 +1,8 @@ /* Kotlin Multiplatform (KMP) wizard using posthog-agent with PostHog MCP */ -import type { FrameworkConfig } from '../../lib/framework-config'; -import { Integration } from '../../lib/constants'; -import { gradlePackageManager } from '../../lib/detection/package-manager'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { Integration } from '../../shared/constants.js'; +import { gradlePackageManager } from '../../detection/package-manager.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import * as path from 'node:path'; export const KMP_AGENT_CONFIG: FrameworkConfig = { diff --git a/src/frameworks/laravel/laravel-wizard-agent.ts b/src/store/frameworks/laravel/laravel-wizard-agent.ts similarity index 94% rename from src/frameworks/laravel/laravel-wizard-agent.ts rename to src/store/frameworks/laravel/laravel-wizard-agent.ts index 36b81b971..58c8166b3 100644 --- a/src/frameworks/laravel/laravel-wizard-agent.ts +++ b/src/store/frameworks/laravel/laravel-wizard-agent.ts @@ -1,9 +1,9 @@ /* Laravel wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { composerPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; -import { boundedGlob } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { composerPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; +import { boundedGlob } from '../../shared/bounded-fs.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { @@ -15,7 +15,7 @@ import { findLaravelServiceProvider, findLaravelBootstrapFile, detectLaravelStructure, -} from './utils'; +} from './utils.js'; type LaravelContext = { projectType?: LaravelProjectType; diff --git a/src/frameworks/laravel/utils.ts b/src/store/frameworks/laravel/utils.ts similarity index 96% rename from src/frameworks/laravel/utils.ts rename to src/store/frameworks/laravel/utils.ts index 08f9e6900..55a52bf80 100644 --- a/src/frameworks/laravel/utils.ts +++ b/src/store/frameworks/laravel/utils.ts @@ -1,7 +1,7 @@ -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/nextjs/nextjs-wizard-agent.ts b/src/store/frameworks/nextjs/nextjs-wizard-agent.ts similarity index 88% rename from src/frameworks/nextjs/nextjs-wizard-agent.ts rename to src/store/frameworks/nextjs/nextjs-wizard-agent.ts index d98442f5a..65f2139ed 100644 --- a/src/frameworks/nextjs/nextjs-wizard-agent.ts +++ b/src/store/frameworks/nextjs/nextjs-wizard-agent.ts @@ -1,22 +1,22 @@ /* Simplified Next.js wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getUI } from '@ui'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getUI } from '../../ui/index.js'; import { getNextJsRouter, getNextJsVersionBucket, getNextJsRouterName, NextJsRouter, -} from './utils'; +} from './utils.js'; type NextjsContext = { router?: NextJsRouter; diff --git a/src/frameworks/nextjs/utils.ts b/src/store/frameworks/nextjs/utils.ts similarity index 86% rename from src/frameworks/nextjs/utils.ts rename to src/store/frameworks/nextjs/utils.ts index 2815df167..2a89e29d4 100644 --- a/src/frameworks/nextjs/utils.ts +++ b/src/store/frameworks/nextjs/utils.ts @@ -1,6 +1,6 @@ -import type { WizardRunOptions } from '@utils/types'; -import { boundedGlob } from '@utils/bounded-fs'; -import { createVersionBucket } from '@utils/semver'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { boundedGlob } from '../../shared/bounded-fs.js'; +import { createVersionBucket } from '../../shared/semver.js'; export const getNextJsVersionBucket = createVersionBucket(); diff --git a/src/frameworks/nuxt/nuxt-wizard-agent.ts b/src/store/frameworks/nuxt/nuxt-wizard-agent.ts similarity index 86% rename from src/frameworks/nuxt/nuxt-wizard-agent.ts rename to src/store/frameworks/nuxt/nuxt-wizard-agent.ts index 56899b903..70d019293 100644 --- a/src/frameworks/nuxt/nuxt-wizard-agent.ts +++ b/src/store/frameworks/nuxt/nuxt-wizard-agent.ts @@ -1,16 +1,16 @@ /* Nuxt wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { createVersionBucket } from '@utils/semver'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { createVersionBucket } from '../../shared/semver.js'; const getNuxtVersionBucket = createVersionBucket(); diff --git a/src/frameworks/python/python-wizard-agent.ts b/src/store/frameworks/python/python-wizard-agent.ts similarity index 94% rename from src/frameworks/python/python-wizard-agent.ts rename to src/store/frameworks/python/python-wizard-agent.ts index fc44b370b..aeaeef356 100644 --- a/src/frameworks/python/python-wizard-agent.ts +++ b/src/store/frameworks/python/python-wizard-agent.ts @@ -1,9 +1,9 @@ /* Generic Python language wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { PYTHON_PACKAGE_INSTALLATION } from '@lib/framework-config'; -import { detectPythonPackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { PYTHON_PACKAGE_INSTALLATION } from '../../framework-config.js'; +import { detectPythonPackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import fg from 'fast-glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; @@ -13,7 +13,7 @@ import { detectPackageManager, getPackageManagerName, PythonPackageManager, -} from './utils'; +} from './utils.js'; type PythonContext = { packageManager?: PythonPackageManager; diff --git a/src/frameworks/python/utils.ts b/src/store/frameworks/python/utils.ts similarity index 98% rename from src/frameworks/python/utils.ts rename to src/store/frameworks/python/utils.ts index 1eb8ac78d..297c6a45e 100644 --- a/src/frameworks/python/utils.ts +++ b/src/store/frameworks/python/utils.ts @@ -1,5 +1,5 @@ import { execSync } from 'node:child_process'; -import type { WizardRunOptions } from '@utils/types'; +import type { WizardRunOptions } from '../../shared/types.js'; export enum PythonPackageManager { UV = 'uv', diff --git a/src/frameworks/rails/rails-wizard-agent.ts b/src/store/frameworks/rails/rails-wizard-agent.ts similarity index 93% rename from src/frameworks/rails/rails-wizard-agent.ts rename to src/store/frameworks/rails/rails-wizard-agent.ts index f473ac98b..c13a5c18d 100644 --- a/src/frameworks/rails/rails-wizard-agent.ts +++ b/src/store/frameworks/rails/rails-wizard-agent.ts @@ -1,8 +1,8 @@ /* Ruby on Rails wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { bundlerPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { bundlerPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getRailsVersion, getRailsProjectType, @@ -11,7 +11,7 @@ import { RailsProjectType, findInitializersDir, isRailsProject, -} from './utils'; +} from './utils.js'; type RailsContext = { projectType?: RailsProjectType; diff --git a/src/frameworks/rails/utils.ts b/src/store/frameworks/rails/utils.ts similarity index 96% rename from src/frameworks/rails/utils.ts rename to src/store/frameworks/rails/utils.ts index ab7993e4d..7cc5c5a15 100644 --- a/src/frameworks/rails/utils.ts +++ b/src/store/frameworks/rails/utils.ts @@ -1,7 +1,7 @@ import fg from 'fast-glob'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/react-native/react-native-wizard-agent.ts b/src/store/frameworks/react-native/react-native-wizard-agent.ts similarity index 90% rename from src/frameworks/react-native/react-native-wizard-agent.ts rename to src/store/frameworks/react-native/react-native-wizard-agent.ts index 7d231781c..7d3b959be 100644 --- a/src/frameworks/react-native/react-native-wizard-agent.ts +++ b/src/store/frameworks/react-native/react-native-wizard-agent.ts @@ -1,21 +1,21 @@ /* React Native wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; import { detectReactNativeVariant, getReactNativeVariantName, getReactNativeVersionBucket, ReactNativeVariant, -} from './utils'; +} from './utils.js'; type ReactNativeContext = { variant?: ReactNativeVariant; diff --git a/src/frameworks/react-native/utils.ts b/src/store/frameworks/react-native/utils.ts similarity index 74% rename from src/frameworks/react-native/utils.ts rename to src/store/frameworks/react-native/utils.ts index a3601217f..7e09828d6 100644 --- a/src/frameworks/react-native/utils.ts +++ b/src/store/frameworks/react-native/utils.ts @@ -1,8 +1,8 @@ -import { createVersionBucket } from '@utils/semver'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { hasDeclaredDependency } from '@utils/package-json'; -import { getUI } from '@ui'; -import type { WizardRunOptions } from '@utils/types'; +import { createVersionBucket } from '../../shared/semver.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { hasDeclaredDependency } from '../../shared/package-json.js'; +import { getUI } from '../../ui/index.js'; +import type { WizardRunOptions } from '../../shared/types.js'; export const getReactNativeVersionBucket = createVersionBucket(); diff --git a/src/frameworks/react-router/react-router-wizard-agent.ts b/src/store/frameworks/react-router/react-router-wizard-agent.ts similarity index 89% rename from src/frameworks/react-router/react-router-wizard-agent.ts rename to src/store/frameworks/react-router/react-router-wizard-agent.ts index e1c211ebe..a62514391 100644 --- a/src/frameworks/react-router/react-router-wizard-agent.ts +++ b/src/store/frameworks/react-router/react-router-wizard-agent.ts @@ -1,22 +1,22 @@ /* React Router wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getUI } from '@ui'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getUI } from '../../ui/index.js'; import { getReactRouterMode, getReactRouterModeName, getReactRouterVersionBucket, ReactRouterMode, -} from './utils'; +} from './utils.js'; type ReactRouterContext = { routerMode?: ReactRouterMode; diff --git a/src/frameworks/react-router/utils.ts b/src/store/frameworks/react-router/utils.ts similarity index 91% rename from src/frameworks/react-router/utils.ts rename to src/store/frameworks/react-router/utils.ts index 05987339b..2183106fe 100644 --- a/src/frameworks/react-router/utils.ts +++ b/src/store/frameworks/react-router/utils.ts @@ -1,9 +1,9 @@ import { major } from 'semver'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import type { WizardRunOptions } from '@utils/types'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { getDeclaredVersion } from '@utils/package-json'; -import { createVersionBucket } from '@utils/semver'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { getDeclaredVersion } from '../../shared/package-json.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as path from 'node:path'; import * as semver from 'semver'; diff --git a/src/frameworks/ruby/ruby-wizard-agent.ts b/src/store/frameworks/ruby/ruby-wizard-agent.ts similarity index 93% rename from src/frameworks/ruby/ruby-wizard-agent.ts rename to src/store/frameworks/ruby/ruby-wizard-agent.ts index aa63873b9..526262ea8 100644 --- a/src/frameworks/ruby/ruby-wizard-agent.ts +++ b/src/store/frameworks/ruby/ruby-wizard-agent.ts @@ -1,8 +1,8 @@ /* Generic Ruby language wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { bundlerPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { bundlerPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getRubyVersion, getRubyVersionBucket, @@ -10,7 +10,7 @@ import { getPackageManagerName, RubyPackageManager, isRubyProject, -} from './utils'; +} from './utils.js'; type RubyContext = { packageManager?: RubyPackageManager; diff --git a/src/frameworks/ruby/utils.ts b/src/store/frameworks/ruby/utils.ts similarity index 94% rename from src/frameworks/ruby/utils.ts rename to src/store/frameworks/ruby/utils.ts index d86deee1c..7341c38c8 100644 --- a/src/frameworks/ruby/utils.ts +++ b/src/store/frameworks/ruby/utils.ts @@ -1,6 +1,6 @@ -import { boundedGlob } from '@utils/bounded-fs'; -import type { WizardRunOptions } from '@utils/types'; -import { createVersionBucket } from '@utils/semver'; +import { boundedGlob } from '../../shared/bounded-fs.js'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/rust/rust-wizard-agent.ts b/src/store/frameworks/rust/rust-wizard-agent.ts similarity index 93% rename from src/frameworks/rust/rust-wizard-agent.ts rename to src/store/frameworks/rust/rust-wizard-agent.ts index 6c0aef1e2..cf05d1116 100644 --- a/src/frameworks/rust/rust-wizard-agent.ts +++ b/src/store/frameworks/rust/rust-wizard-agent.ts @@ -1,10 +1,10 @@ /* Rust wizard using posthog-agent with PostHog MCP */ import * as fs from 'node:fs'; import * as path from 'node:path'; -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { cargoPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { cargoPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; type RustContext = { asyncRuntime?: boolean; diff --git a/src/frameworks/svelte/svelte-wizard-agent.ts b/src/store/frameworks/svelte/svelte-wizard-agent.ts similarity index 86% rename from src/frameworks/svelte/svelte-wizard-agent.ts rename to src/store/frameworks/svelte/svelte-wizard-agent.ts index e84e2cef7..a43986ad8 100644 --- a/src/frameworks/svelte/svelte-wizard-agent.ts +++ b/src/store/frameworks/svelte/svelte-wizard-agent.ts @@ -1,13 +1,13 @@ /* SvelteKit wizard using posthog-agent with PostHog MCP */ -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; type SvelteKitContext = Record; diff --git a/src/frameworks/swift/__tests__/utils.test.ts b/src/store/frameworks/swift/__tests__/utils.test.ts similarity index 96% rename from src/frameworks/swift/__tests__/utils.test.ts rename to src/store/frameworks/swift/__tests__/utils.test.ts index 1705b3da4..f50705ad4 100644 --- a/src/frameworks/swift/__tests__/utils.test.ts +++ b/src/store/frameworks/swift/__tests__/utils.test.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { detectSwiftProjectType, SwiftProjectType } from '../utils'; -import type { WizardRunOptions } from '@utils/types'; +import { detectSwiftProjectType, SwiftProjectType } from '../utils.js'; +import type { WizardRunOptions } from '../../../shared/types.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'swift-utils-')); diff --git a/src/frameworks/swift/swift-wizard-agent.ts b/src/store/frameworks/swift/swift-wizard-agent.ts similarity index 92% rename from src/frameworks/swift/swift-wizard-agent.ts rename to src/store/frameworks/swift/swift-wizard-agent.ts index 5e6343b87..60b19e790 100644 --- a/src/frameworks/swift/swift-wizard-agent.ts +++ b/src/store/frameworks/swift/swift-wizard-agent.ts @@ -1,9 +1,9 @@ /* Swift wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { swiftPackageManager } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; -import { boundedGlob } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { swiftPackageManager } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; +import { boundedGlob } from '../../shared/bounded-fs.js'; import fg from 'fast-glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; @@ -11,7 +11,7 @@ import { detectSwiftProjectType, getSwiftProjectTypeName, SwiftProjectType, -} from './utils'; +} from './utils.js'; type SwiftContext = { projectType?: SwiftProjectType; diff --git a/src/frameworks/swift/utils.ts b/src/store/frameworks/swift/utils.ts similarity index 93% rename from src/frameworks/swift/utils.ts rename to src/store/frameworks/swift/utils.ts index a41d51ca3..b592bc22c 100644 --- a/src/frameworks/swift/utils.ts +++ b/src/store/frameworks/swift/utils.ts @@ -1,5 +1,5 @@ -import type { WizardRunOptions } from '@utils/types'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; import fg from 'fast-glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/tanstack-router/tanstack-router-wizard-agent.ts b/src/store/frameworks/tanstack-router/tanstack-router-wizard-agent.ts similarity index 90% rename from src/frameworks/tanstack-router/tanstack-router-wizard-agent.ts rename to src/store/frameworks/tanstack-router/tanstack-router-wizard-agent.ts index c63245a85..2e5dddfa5 100644 --- a/src/frameworks/tanstack-router/tanstack-router-wizard-agent.ts +++ b/src/store/frameworks/tanstack-router/tanstack-router-wizard-agent.ts @@ -1,22 +1,22 @@ /* TanStack Router wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getUI } from '@ui'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getUI } from '../../ui/index.js'; import { getTanStackRouterMode, getTanStackRouterModeName, getTanStackRouterVersionBucket, TanStackRouterMode, -} from './utils'; +} from './utils.js'; type TanStackRouterContext = { routerMode?: TanStackRouterMode; diff --git a/src/frameworks/tanstack-router/utils.ts b/src/store/frameworks/tanstack-router/utils.ts similarity index 92% rename from src/frameworks/tanstack-router/utils.ts rename to src/store/frameworks/tanstack-router/utils.ts index 450a4fe47..c3c76be1d 100644 --- a/src/frameworks/tanstack-router/utils.ts +++ b/src/store/frameworks/tanstack-router/utils.ts @@ -1,7 +1,7 @@ -import type { WizardRunOptions } from '@utils/types'; -import { boundedGlob, readProjectFile } from '@utils/bounded-fs'; -import { hasDeclaredDependency } from '@utils/package-json'; -import { createVersionBucket } from '@utils/semver'; +import type { WizardRunOptions } from '../../shared/types.js'; +import { boundedGlob, readProjectFile } from '../../shared/bounded-fs.js'; +import { hasDeclaredDependency } from '../../shared/package-json.js'; +import { createVersionBucket } from '../../shared/semver.js'; import * as fs from 'node:fs'; import * as path from 'node:path'; diff --git a/src/frameworks/tanstack-start/tanstack-start-wizard-agent.ts b/src/store/frameworks/tanstack-start/tanstack-start-wizard-agent.ts similarity index 85% rename from src/frameworks/tanstack-start/tanstack-start-wizard-agent.ts rename to src/store/frameworks/tanstack-start/tanstack-start-wizard-agent.ts index a279ef6bb..dd650fa52 100644 --- a/src/frameworks/tanstack-start/tanstack-start-wizard-agent.ts +++ b/src/store/frameworks/tanstack-start/tanstack-start-wizard-agent.ts @@ -1,16 +1,16 @@ /* TanStack Start wizard using posthog-agent with PostHog MCP */ -import type { WizardRunOptions } from '@utils/types'; -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { WizardRunOptions } from '../../shared/types.js'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { getTanStackStartVersionBucket } from './utils'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { getTanStackStartVersionBucket } from './utils.js'; type TanStackStartContext = Record; diff --git a/src/frameworks/tanstack-start/utils.ts b/src/store/frameworks/tanstack-start/utils.ts similarity index 67% rename from src/frameworks/tanstack-start/utils.ts rename to src/store/frameworks/tanstack-start/utils.ts index 4f9500600..6fc295bad 100644 --- a/src/frameworks/tanstack-start/utils.ts +++ b/src/store/frameworks/tanstack-start/utils.ts @@ -1,4 +1,4 @@ -import { createVersionBucket } from '@utils/semver'; +import { createVersionBucket } from '../../shared/semver.js'; /** * Get TanStack Start version bucket for analytics diff --git a/src/frameworks/vue/vue-wizard-agent.ts b/src/store/frameworks/vue/vue-wizard-agent.ts similarity index 85% rename from src/frameworks/vue/vue-wizard-agent.ts rename to src/store/frameworks/vue/vue-wizard-agent.ts index a37492a8d..732576500 100644 --- a/src/frameworks/vue/vue-wizard-agent.ts +++ b/src/store/frameworks/vue/vue-wizard-agent.ts @@ -1,15 +1,15 @@ /* Vue wizard using posthog-agent with PostHog MCP */ -import type { FrameworkConfig } from '@lib/framework-config'; -import { detectNodePackageManagers } from '@lib/detection/package-manager'; -import { Integration } from '@lib/constants'; +import type { FrameworkConfig } from '../../framework-config.js'; +import { detectNodePackageManagers } from '../../detection/package-manager.js'; +import { Integration } from '../../shared/constants.js'; import { getDeclaredVersion, getInstalledPackageVersion, hasDeclaredDependency, type PackageJson, -} from '@utils/package-json'; -import { tryGetPackageJson } from '@utils/setup-utils'; -import { createVersionBucket } from '@utils/semver'; +} from '../../shared/package-json.js'; +import { tryGetPackageJson } from '../../shared/setup-utils.js'; +import { createVersionBucket } from '../../shared/semver.js'; const getVueVersionBucket = createVersionBucket(); diff --git a/src/lib/health-checks/__tests__/health-checks.test.ts b/src/store/health-checks/__tests__/health-checks.test.ts similarity index 98% rename from src/lib/health-checks/__tests__/health-checks.test.ts rename to src/store/health-checks/__tests__/health-checks.test.ts index b23b7e2c4..953103ca6 100644 --- a/src/lib/health-checks/__tests__/health-checks.test.ts +++ b/src/store/health-checks/__tests__/health-checks.test.ts @@ -5,12 +5,9 @@ import { evaluateWizardReadiness, ServiceHealthStatus, WizardReadiness, -} from '@lib/health-checks/index'; -import { - checkLlmGatewayHealth, - fetchEndpointHealth, -} from '@lib/health-checks/endpoints'; -import { SIGNUP_WIZARD_READINESS_CONFIG } from '@lib/health-checks/readiness'; +} from '../index.js'; +import { checkLlmGatewayHealth, fetchEndpointHealth } from '../endpoints.js'; +import { SIGNUP_WIZARD_READINESS_CONFIG } from '../readiness.js'; const URLS = { githubSkillMenu: diff --git a/src/lib/health-checks/endpoints.ts b/src/store/health-checks/endpoints.ts similarity index 97% rename from src/lib/health-checks/endpoints.ts rename to src/store/health-checks/endpoints.ts index f98a9eb7b..d352756bb 100644 --- a/src/lib/health-checks/endpoints.ts +++ b/src/store/health-checks/endpoints.ts @@ -1,6 +1,9 @@ -import { AWS_SKILLS_BASE_URL, GITHUB_SKILLS_BASE_URL } from '@lib/constants'; -import { logToFile } from '@utils/debug'; -import { ServiceHealthStatus, type BaseHealthResult } from './types'; +import { + AWS_SKILLS_BASE_URL, + GITHUB_SKILLS_BASE_URL, +} from '../shared/constants.js'; +import { logToFile } from '../shared/debug.js'; +import { ServiceHealthStatus, type BaseHealthResult } from './types.js'; // Direct gateway and skill-origin checks distinguish HTTP failures from connection failures. diff --git a/src/lib/health-checks/index.ts b/src/store/health-checks/index.ts similarity index 84% rename from src/lib/health-checks/index.ts rename to src/store/health-checks/index.ts index a6af0fb7c..3e4f8faf2 100644 --- a/src/lib/health-checks/index.ts +++ b/src/store/health-checks/index.ts @@ -3,9 +3,9 @@ export { type BaseHealthResult, type AllServicesHealth, type HealthCheckKey, -} from './types'; +} from './types.js'; -export { checkLlmGatewayHealth, checkSkillsOriginHealth } from './endpoints'; +export { checkLlmGatewayHealth, checkSkillsOriginHealth } from './endpoints.js'; export { type WizardReadinessConfig, @@ -14,4 +14,4 @@ export { WizardReadiness, type WizardReadinessResult, evaluateWizardReadiness, -} from './readiness'; +} from './readiness.js'; diff --git a/src/lib/health-checks/readiness.ts b/src/store/health-checks/readiness.ts similarity index 97% rename from src/lib/health-checks/readiness.ts rename to src/store/health-checks/readiness.ts index 0eba5a3b4..4957abe9c 100644 --- a/src/lib/health-checks/readiness.ts +++ b/src/store/health-checks/readiness.ts @@ -3,9 +3,9 @@ import { type AllServicesHealth, type BaseHealthResult, type HealthCheckKey, -} from './types'; -import { checkSkillsOriginHealth } from './endpoints'; -import { logToFile } from '@utils/debug'; +} from './types.js'; +import { checkSkillsOriginHealth } from './endpoints.js'; +import { logToFile } from '../shared/debug.js'; // --------------------------------------------------------------------------- // Service labels (used in human-readable reason strings) diff --git a/src/lib/health-checks/testme.md b/src/store/health-checks/testme.md similarity index 86% rename from src/lib/health-checks/testme.md rename to src/store/health-checks/testme.md index ba5b04187..40b2acc5d 100644 --- a/src/lib/health-checks/testme.md +++ b/src/store/health-checks/testme.md @@ -3,7 +3,7 @@ Run the existing health and gateway tests with mocked HTTP requests: ```bash -pnpm exec vitest run src/lib/health-checks/__tests__/health-checks.test.ts src/lib/__tests__/gateway-session.test.ts +pnpm exec vitest run src/store/health-checks/__tests__/health-checks.test.ts src/agent/__tests__/gateway-session.test.ts ``` The checks cover gateway readiness, endpoint retries, and skills downloads from diff --git a/src/lib/health-checks/types.ts b/src/store/health-checks/types.ts similarity index 100% rename from src/lib/health-checks/types.ts rename to src/store/health-checks/types.ts diff --git a/src/lib/helper-functions.ts b/src/store/helper-functions.ts similarity index 100% rename from src/lib/helper-functions.ts rename to src/store/helper-functions.ts diff --git a/src/lib/host-resolution.ts b/src/store/host-resolution.ts similarity index 97% rename from src/lib/host-resolution.ts rename to src/store/host-resolution.ts index f55f1b4bc..4789eeb24 100644 --- a/src/lib/host-resolution.ts +++ b/src/store/host-resolution.ts @@ -22,10 +22,10 @@ import { getUiHostFromHost, detectRegion, resolveBaseUrl, -} from '@utils/urls'; +} from './shared/urls.js'; import { IS_PRODUCTION_BUILD, runtimeEnv } from '@env'; -import { MCP_LOCAL_URL } from '@lib/local-dev'; -import type { CloudRegion } from '@utils/types'; +import { MCP_LOCAL_URL } from './local-dev.js'; +import type { CloudRegion } from './shared/types.js'; // The wizard's client gets CLI mode (a single `exec` tool) by server default, // so no mode is pinned; the dev env override (see env.ts) is taken verbatim. diff --git a/src/store/index.ts b/src/store/index.ts index 5a19657a8..d06771cd6 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,292 @@ -/** Public runtime API of the store surface. Populated by the surface split. */ -export {}; +/** Public runtime API of the store surface. Other surfaces import only this, @store/types, and @store/programs. */ +export { sanitizeAgentSubprocessEnv } from './agent-protocol/agent-env-isolation.js'; +export { + getMcpPromptRunner, + setMcpPromptRunner, +} from './agent-protocol/mcp-prompt.js'; +export { + AgentPhase, + classifyToolToStage, +} from './agent-protocol/agent-phase.js'; +export { + AgentErrorType, + AgentSignals, + REMARK_INSTRUCTION, + RESUME_INSTRUCTION, +} from './agent-protocol/agent-signals.js'; +export { + computeTokenCostUsd, + formatCostUsd, + formatTokenCount, +} from './agent-protocol/token-pricing.js'; +export { + ApiError, + fetchGithubConnected, + fetchSlackConnected, + fetchUserData, +} from './api.js'; +export { isGrantRevoked } from './auth-session-state.js'; +export { + coerceAgenticReport, + deriveReportJson, + manifestGlob, + setDetectionAgent, +} from './detection/agentic.js'; +export { detectNodePackageManagers } from './detection/package-manager.js'; +export { fetchWithRetry } from './fetch-retry.js'; +export { startFileWatcher } from './file-watcher.js'; +export { checkLlmGatewayHealth } from './health-checks/endpoints.js'; +export { + SERVICE_LABELS, + SIGNUP_WIZARD_READINESS_CONFIG, + WizardReadiness, + evaluateWizardReadiness, + getBlockingServiceKeys, +} from './health-checks/readiness.js'; +export { ServiceHealthStatus } from './health-checks/types.js'; +export { HostResolution, mcpUrlFor } from './host-resolution.js'; +export { + POSTHOG_LOCAL_URL, + checkLocalServices, + getLocalDev, + initLocalDev, + localMcpSkillsNotice, +} from './local-dev.js'; +export { + assembleProfile, + degradedProfile, + isKnownCloudHost, + probeProjectData, +} from './mcp-project-profile.js'; +export { + FOLLOW_UP_EXIT_SENTINEL, + TAILORED_ROLES, + getFollowUps, + getGeneratedQuests, + getRoleGreeting, + getRolePrompts, + getSeedOfferGreeting, + getSlackAppCard, + getTutorialPicker, +} from './mcp-role-prompts.js'; +export { seedDemoEvents, seededProfile } from './mcp-seed-events.js'; +export { FRAMEWORK_REGISTRY } from './registry.js'; +export { LINTING_TOOLS } from './safe-tools.js'; +export { + createPostToolUseYaraHooks, + createPreToolUseYaraHooks, + createRepeatBlockTracker, + flushScanReport, + formatScanReport, + formatYaraAbortMessage, + isWizardDocumentationPath, + prewarmYaraScanner, + recordExternalScan, + repeatBlockReason, + scanAndTriage, + writeScanReport, +} from './security/yara-hooks.js'; +export { publishBlockingMatch, scanVerdict } from './security/yara-policy.js'; +export { + authenticate, + refreshAccessTokenIfNeeded, +} from './services/authenticate.js'; +export { + backupAndFixClaudeSettings, + checkAllSettingsConflicts, + classifySettingsConflicts, + recoverOrphanedSettingsBackups, + restoreClaudeSettings, +} from './services/claude-settings.js'; +export { isBrowserFinishable } from './services/steps/add-mcp-server-to-clients/browser-client.js'; +export { + ALL_FEATURE_VALUES, + AVAILABLE_FEATURES, + isAllFeaturesSelected, +} from './services/steps/add-mcp-server-to-clients/defaults.js'; +export { + addMCPServerToClientsStep, + getInstalledClients, + getSupportedClients, + getSupportedPluginClients, + installPlugins, + removeMCPServer, + removeMCPServerFromClientsStep, +} from './services/steps/add-mcp-server-to-clients/index.js'; +export { isLoginCapable } from './services/steps/add-mcp-server-to-clients/login-client.js'; +export { isPluginCapable } from './services/steps/add-mcp-server-to-clients/plugin-client.js'; +export { + McpClientStatus, + isOk, + namesWithStatus, + redactSecrets, + summarizeFailure, + toClientResult, +} from './services/steps/add-mcp-server-to-clients/results.js'; +export { + CLI_STEERING_TARGETS, + detectTargets, + findTarget, + installOrUpdatePostHogCli, + installSteeringSnippet, +} from './services/steps/install-cli-steering/index.js'; +export { shouldDisableAsk } from './session/ask-policy.js'; +export { createSecretVault } from './session/secret-vault.js'; +export { + LONGER_ASK_TIMEOUT_MS, + createWizardAskBridge, + isFullyCancelled, +} from './session/wizard-ask-bridge.js'; +export { + ADDITIONAL_FEATURE_LABELS, + ADDITIONAL_FEATURE_PROMPTS, + AdditionalFeature, + DiscoveredFeature, + McpOutcome, + OutroKind, + RunPhase, + ScanConsent, + buildSession, +} from './session/wizard-session.js'; +export { analytics } from './shared/analytics.js'; +export { makeMutex, writeJsonAtomic } from './shared/atomic-ledger.js'; +export { ciExcludedTaskTypes } from './shared/ci-flag-overrides.js'; +export { copyToClipboard, openInBrowser } from './shared/clipboard.js'; +export { + AWS_SKILLS_BASE_URL, + CONTEXT_MILL_RELEASES_URL, + CONTEXT_MILL_URL, + CallType, + DEFAULT_AGENT_MODEL, + GITHUB_SKILLS_BASE_URL, + GPT5_6_LUNA_MODEL, + GPT5_6_SOL_MODEL, + GPT5_6_TERRA_MODEL, + HAIKU_MODEL, + HAIKU_TRIAGE_MODEL, + Harness, + Integration, + OAUTH_PORTS, + OAUTH_TIMEOUT_MS, + POSTHOG_APP_URL, + POSTHOG_DOCS_URL, + POSTHOG_ORG_AI_SETTINGS_URL, + POSTHOG_PRIVACY_URL, + POSTHOG_TERMS_URL, + SONNET_5_MODEL, + Sequence, + WIZARD_CONTACT_EMAIL, + WIZARD_ORCHESTRATOR_FLAG_KEY, + WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY, + WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY, + WIZARD_REMARK_EVENT_NAME, + WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY, + WIZARD_USER_AGENT, + getSkillsBaseUrl, + wizardUserAgentForProgram, +} from './shared/constants.js'; +export { createCustomHeaders } from './shared/custom-headers.js'; +export { + configureLogFile, + configureLogFileFromEnvironment, + debug, + enableDebugLogs, + getLogFilePath, + initLogFile, + logToFile, +} from './shared/debug.js'; +export { readApiKeyFromEnv } from './shared/env-api-key.js'; +export { isTemplateEnvFileName } from './shared/env-scan.js'; +export { + isNonInteractiveEnvironment, + readEnvironment, +} from './shared/environment.js'; +export { AGENT_ERROR_CODE } from './shared/errors/agent-map.js'; +export { classifyAuthFailure } from './shared/errors/auth.js'; +export { ErrorCodes } from './shared/errors/codes.js'; +export { detectErrorCode } from './shared/errors/detect-map.js'; +export { emitWizardError } from './shared/errors/emit.js'; +export { classifyRunFailure } from './shared/errors/run-failure.js'; +export { skillErrorCode } from './shared/errors/skill-map.js'; +export { + headlessOption, + isHeadless, + regionOption, +} from './shared/headless-mode.js'; +export { openTrackedLink, setEntryCommand, withUtm } from './shared/links.js'; +export { extractOAuthCode } from './shared/oauth.js'; +export { + WIZARD_BENCHMARK_FILE, + WIZARD_LOG_FILE, + relativeToInstallDir, +} from './shared/paths.js'; +export { provisionNewAccount, requestDeepLink } from './shared/provisioning.js'; +export { getOrAskForProjectData } from './shared/setup-utils.js'; +export { ringTerminalBell } from './shared/terminal-bell.js'; +export { getIntegrationAuthorizeUrl } from './shared/urls.js'; +export { VERSION } from './shared/version.js'; +export { + WizardError, + registerCleanup, + runCleanups, + wizardAbort, +} from './shared/wizard-abort.js'; +export { isSkillInstallCommand } from './skill-install.js'; +export { Interrupt } from './state/interrupts.js'; +export { isRunFailure } from './state/run-failure.js'; +export { STORE_BOUNDARY_MEMBERS } from './state/store-api.js'; +export { + MAX_STATUS_MESSAGES, + WizardStore, + totalTokenCount, +} from './state/store.js'; +export { createFileDestination } from './task-stream/destinations/file.js'; +export { PostHogDestination } from './task-stream/destinations/posthog.js'; +export { TaskStreamPush } from './task-stream/task-stream-push.js'; +export { + PUBLISH_HANDOFF_CONTENT_DESCRIPTION, + PUBLISH_HANDOFF_DESCRIPTION, + PUBLISH_HANDOFF_TOOL_NAME, + publishHandoff, +} from './tools/handoff.js'; +export { + AUDIT_ADD_CHECKS_DESCRIPTION, + AUDIT_ADD_CHECKS_PARAM_DESCRIPTION, + AUDIT_RESOLVE_CHECKS_DESCRIPTION, + AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION, + AUDIT_SEED_CHECKS_DESCRIPTION, + AUDIT_SEED_CHECKS_PARAM_DESCRIPTION, + AUDIT_STATUSES, + CHECK_ENV_KEYS_DESCRIPTION, + CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION, + DEFAULT_ASK_MAX_QUESTIONS, + ENV_FILE_PATH_DESCRIPTION, + SERVER_NAME, + WIZARD_ASK_KIND_DESCRIPTION, + WIZARD_ASK_SENSITIVE_DESCRIPTION, + WIZARD_ASK_SUBJECT_DESCRIPTION, + WIZARD_ASK_TOOL_DESCRIPTION, + WIZARD_TOOL_NAMES, + addAuditChecks, + checkEnvKeys, + createAskAccounting, + describeAskCancellation, + downloadSkill, + ensureGitignoreCoverage, + fetchSkillMenu, + installSkillById, + legacyKeyNameRefusal, + mergeEnvValues, + normaliseAskSubject, + resolveAskQuestionKinds, + resolveAuditChecks, + resolveEnvPath, + resolveEnvSecretRefs, + seedAuditChecks, + templateEnvWriteRefusal, + vaultSensitiveAnswers, +} from './tools/tools.js'; +export { getUI, setUI } from './ui/index.js'; +export { StoreUI } from './ui/store-ui.js'; +export { TaskStatus } from './ui/wizard-ui.js'; +export { writeWizardSpellbook } from './wizard-spellbook.js'; diff --git a/src/lib/local-dev.ts b/src/store/local-dev.ts similarity index 100% rename from src/lib/local-dev.ts rename to src/store/local-dev.ts diff --git a/src/lib/mcp-project-profile.ts b/src/store/mcp-project-profile.ts similarity index 99% rename from src/lib/mcp-project-profile.ts rename to src/store/mcp-project-profile.ts index 12a398871..b4ebff12d 100644 --- a/src/lib/mcp-project-profile.ts +++ b/src/store/mcp-project-profile.ts @@ -25,8 +25,8 @@ */ import axios from 'axios'; -import { WIZARD_USER_AGENT } from './constants'; -import { logToFile } from '@utils/debug'; +import { WIZARD_USER_AGENT } from './shared/constants.js'; +import { logToFile } from './shared/debug.js'; // Time-box every probe call. The scout sits on the critical path between // auth and the picker, so a wedged endpoint must not stall the tutorial. diff --git a/src/lib/mcp-role-prompts.copy.json b/src/store/mcp-role-prompts.copy.json similarity index 100% rename from src/lib/mcp-role-prompts.copy.json rename to src/store/mcp-role-prompts.copy.json diff --git a/src/lib/mcp-role-prompts.ts b/src/store/mcp-role-prompts.ts similarity index 99% rename from src/lib/mcp-role-prompts.ts rename to src/store/mcp-role-prompts.ts index 5b8921f73..50dbb4504 100644 --- a/src/lib/mcp-role-prompts.ts +++ b/src/store/mcp-role-prompts.ts @@ -19,11 +19,11 @@ * 3. Unknown role → DEFAULT_KIT. */ -import type { Integration } from './constants'; +import type { Integration } from './shared/constants.js'; import type { ProductPresence, ProjectDataProfile, -} from './mcp-project-profile'; +} from './mcp-project-profile.js'; import copyData from './mcp-role-prompts.copy.json'; /** Keys of `ProductPresence` — the products an activation cross-sell can target. */ diff --git a/src/lib/mcp-seed-events.ts b/src/store/mcp-seed-events.ts similarity index 98% rename from src/lib/mcp-seed-events.ts rename to src/store/mcp-seed-events.ts index 99d783189..ab8d37efc 100644 --- a/src/lib/mcp-seed-events.ts +++ b/src/store/mcp-seed-events.ts @@ -23,12 +23,12 @@ * meant to create. */ -import { logToFile } from '@utils/debug'; +import { logToFile } from './shared/debug.js'; import { assembleProfile, type EventVolume, type ProjectDataProfile, -} from './mcp-project-profile'; +} from './mcp-project-profile.js'; export interface SeedEvent { event: string; diff --git a/src/lib/programs/__tests__/__snapshots__/flow-traces.test.ts.snap b/src/store/programs/__tests__/__snapshots__/flow-traces.test.ts.snap similarity index 100% rename from src/lib/programs/__tests__/__snapshots__/flow-traces.test.ts.snap rename to src/store/programs/__tests__/__snapshots__/flow-traces.test.ts.snap diff --git a/src/lib/programs/__tests__/__snapshots__/post-auth-gates.test.ts.snap b/src/store/programs/__tests__/__snapshots__/post-auth-gates.test.ts.snap similarity index 100% rename from src/lib/programs/__tests__/__snapshots__/post-auth-gates.test.ts.snap rename to src/store/programs/__tests__/__snapshots__/post-auth-gates.test.ts.snap diff --git a/src/lib/programs/__tests__/agent-skill.test.ts b/src/store/programs/__tests__/agent-skill.test.ts similarity index 92% rename from src/lib/programs/__tests__/agent-skill.test.ts rename to src/store/programs/__tests__/agent-skill.test.ts index f3df4a406..a3161eac5 100644 --- a/src/lib/programs/__tests__/agent-skill.test.ts +++ b/src/store/programs/__tests__/agent-skill.test.ts @@ -2,10 +2,10 @@ import { createSkillProgram, AGENT_SKILL_STEPS, type SkillProgramOptions, -} from '@lib/programs/agent-skill/index'; -import type { ProgramRun } from '@lib/program-run'; -import { buildSession, RunPhase } from '@lib/wizard-session'; -import { HostResolution } from '@lib/host-resolution'; +} from '../agent-skill/index.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import { buildSession, RunPhase } from '../../session/wizard-session.js'; +import { HostResolution } from '../../host-resolution.js'; const baseOpts: SkillProgramOptions = { skillId: 'error-tracking-setup', diff --git a/src/lib/programs/__tests__/audit-seed.test.ts b/src/store/programs/__tests__/audit-seed.test.ts similarity index 71% rename from src/lib/programs/__tests__/audit-seed.test.ts rename to src/store/programs/__tests__/audit-seed.test.ts index 1897a2b19..906b15ea3 100644 --- a/src/lib/programs/__tests__/audit-seed.test.ts +++ b/src/store/programs/__tests__/audit-seed.test.ts @@ -2,9 +2,8 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { AUDIT_SEED_CHECKS, seedAuditLedger } from '@lib/programs/audit/seed'; -import { AUDIT_CHECKS_FILE, type AuditCheck } from '@lib/programs/audit/types'; -import { COL_AREA_WIDTH } from '@ui/tui/screens/audit/AuditChecksViewer/layout'; +import { AUDIT_SEED_CHECKS, seedAuditLedger } from '../audit/seed.js'; +import { AUDIT_CHECKS_FILE, type AuditCheck } from '../audit/types.js'; const ids = (checks: AuditCheck[]) => checks.map((c) => c.id); @@ -34,17 +33,6 @@ describe('AUDIT_SEED_CHECKS', () => { expect.arrayContaining(['init-correct', 'init-not-duplicated']), ); }); - - it('fits every area in the checks viewer column', () => { - // Area is the one hard constraint: computeLayout pins it to a fixed - // COL_AREA_WIDTH that never flexes, so a longer area name is truncated at - // every terminal size. Labels get the flexed column and are allowed to run - // past COL_LABEL_MIN — several seeded ones already do, and only clip on a - // narrow terminal. - for (const check of AUDIT_SEED_CHECKS) { - expect(check.area.length).toBeLessThanOrEqual(COL_AREA_WIDTH); - } - }); }); describe('seedAuditLedger', () => { diff --git a/src/lib/programs/__tests__/error-tracking.test.ts b/src/store/programs/__tests__/error-tracking.test.ts similarity index 77% rename from src/lib/programs/__tests__/error-tracking.test.ts rename to src/store/programs/__tests__/error-tracking.test.ts index b2520dcf2..9109c2b70 100644 --- a/src/lib/programs/__tests__/error-tracking.test.ts +++ b/src/store/programs/__tests__/error-tracking.test.ts @@ -1,39 +1,40 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'; -import type { ProgramRun } from '@lib/program-run'; -import { Integration } from '@lib/constants'; -import type { AgenticDetectionReport } from '@lib/detection/agentic'; -import { detectFramework } from '@lib/detection/index'; -import { ErrorCodes } from '@lib/errors'; -import { ERROR_TRACKING_TIPS } from '@ui/tui/programs/error-tracking/content/tips'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import { Integration } from '../../shared/constants.js'; +import type { AgenticDetectionReport } from '../../detection/agentic.js'; +import { detectFramework } from '../../detection/index.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; import { ERROR_TRACKING_PROJECT_PATH_KEY, toErrorTrackingReport, -} from '@lib/programs/error-tracking/detect-agentic'; +} from '../error-tracking/detect-agentic.js'; import { errorTrackingConfig, SYMBOL_UPLOAD_CLI_FRAMEWORKS, -} from '@lib/programs/error-tracking/index'; -import { VARIANTS_REQUIRING_POSTHOG_CLI } from '@lib/programs/error-tracking-upload-source-maps/detect'; -import { preinstallPostHogCliOnce } from '@lib/programs/shared/posthog-cli-preinstall'; -import type { WizardSession } from '@lib/wizard-session'; -import { analytics } from '@utils/analytics'; -import { wizardAbort } from '@utils/wizard-abort'; - -vi.mock('@lib/detection/index', async (importOriginal) => ({ - ...(await importOriginal()), +} from '../error-tracking/index.js'; +import { VARIANTS_REQUIRING_POSTHOG_CLI } from '../error-tracking-upload-source-maps/detect.js'; +import { preinstallPostHogCliOnce } from '../shared/posthog-cli-preinstall.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { analytics } from '../../shared/analytics.js'; +import { wizardAbort } from '../../shared/wizard-abort.js'; + +vi.mock('../../detection/index.js', async (importOriginal) => ({ + ...(await importOriginal()), detectFramework: vi.fn(), })); -vi.mock('@lib/detection/project-scope', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('../../detection/project-scope.js', async (importOriginal) => ({ + ...(await importOriginal< + typeof import('../../detection/project-scope.js') + >()), scopeInstallDirToProject: vi.fn(), detectIntegrationProjects: vi.fn(), })); -vi.mock('@lib/programs/shared/posthog-cli-preinstall', () => ({ +vi.mock('../shared/posthog-cli-preinstall.js', () => ({ preinstallPostHogCliOnce: vi.fn(), })); -vi.mock('@utils/wizard-abort', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('../../shared/wizard-abort.js', async (importOriginal) => ({ + ...(await importOriginal()), wizardAbort: vi.fn(), })); @@ -212,17 +213,3 @@ describe('error-tracking posthog-cli pre-install set', () => { expect([...SYMBOL_UPLOAD_CLI_FRAMEWORKS].sort()).toEqual(expected); }); }); - -describe('error-tracking tips', () => { - const replayTip = ERROR_TRACKING_TIPS.find((t) => t.id === 'session-replay'); - const storeFor = (integration: Integration | null) => - ({ session: { integration } } as never); - - test('shows the replay tip only where session replay records', () => { - expect(replayTip?.visible?.(storeFor(Integration.nextjs))).toBe(true); - expect(replayTip?.visible?.(storeFor(Integration.javascriptNode))).toBe( - false, - ); - expect(replayTip?.visible?.(storeFor(null))).toBe(false); - }); -}); diff --git a/src/lib/programs/__tests__/flow-traces.test.ts b/src/store/programs/__tests__/flow-traces.test.ts similarity index 79% rename from src/lib/programs/__tests__/flow-traces.test.ts rename to src/store/programs/__tests__/flow-traces.test.ts index bdc5c825a..40b2ab949 100644 --- a/src/lib/programs/__tests__/flow-traces.test.ts +++ b/src/store/programs/__tests__/flow-traces.test.ts @@ -3,31 +3,30 @@ * by walking each program's steps through the store with a generic advance per * screen. Baseline for the surface split: must stay byte identical. */ -import { WizardStore, RunPhase, McpOutcome } from '@ui/tui/store'; -import { ScreenId } from '@ui/tui/router'; -import { InkUI } from '@ui/tui/ink-ui'; -import { setUI } from '@ui/index'; +import { WizardStore, RunPhase, McpOutcome } from '../../state/store.js'; +import { StoreUI } from '@store/ui/store-ui'; +import { setUI } from '../../ui/index.js'; import { buildSession, OutroKind, type WizardSession, -} from '@lib/wizard-session'; -import { Integration } from '@lib/constants'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { HostResolution } from '@lib/host-resolution'; -import { WizardReadiness } from '@lib/health-checks/readiness'; -import { analytics } from '@utils/analytics'; +} from '../../session/wizard-session.js'; +import { Integration } from '../../shared/constants.js'; +import { FRAMEWORK_REGISTRY } from '../../registry.js'; +import { HostResolution } from '../../host-resolution.js'; +import { WizardReadiness } from '../../health-checks/readiness.js'; +import { analytics } from '../../shared/analytics.js'; import { PROGRAM_REGISTRY, getProgramConfig, type ProgramId, -} from '../program-registry'; -import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '../self-driving/detect'; -import { ERROR_TRACKING_PROJECT_PATH_KEY } from '../error-tracking/detect-agentic'; -import { SOURCE_MAPS_CONTEXT_KEYS } from '../error-tracking-upload-source-maps/detect'; -import { flowFor } from '@lib/programs/flow-for'; +} from '../program-registry.js'; +import { SELF_DRIVING_INTEGRATE_PATH_KEY } from '../self-driving/detect.js'; +import { ERROR_TRACKING_PROJECT_PATH_KEY } from '../error-tracking/detect-agentic.js'; +import { SOURCE_MAPS_CONTEXT_KEYS } from '../error-tracking-upload-source-maps/detect.js'; +import { flowFor } from '../flow-for.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../shared/analytics.js', () => ({ analytics: { capture: vi.fn(), wizardCapture: vi.fn(), @@ -60,7 +59,7 @@ const NODE = FRAMEWORK_REGISTRY[Integration.javascriptNode]; function createStore(program: ProgramId, integration: Integration | null) { const store = new WizardStore(flowFor(program).flow); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); const session = buildSession({ installDir: '/app', ci: false }); if (integration) { session.integration = integration; @@ -78,19 +77,19 @@ const approved = (ok: boolean) => /** Commit what a user, the runner, or the agent would commit on this screen. */ function advance(store: WizardStore, screen: string): boolean { const s = store.session; - if (screen === ScreenId.Intro || screen.endsWith('-intro')) { + if (screen === 'intro' || screen.endsWith('-intro')) { store.completeSetup(); return true; } switch (screen) { - case ScreenId.HealthCheck: + case 'health-check': store.setReadinessResult({ decision: WizardReadiness.Yes, health: {} as never, reasons: [], }); return true; - case ScreenId.Setup: { + case 'setup': { const questions = s.frameworkConfig?.metadata.setup?.questions ?? []; for (const q of questions) { if (!(q.key in s.frameworkContext)) { @@ -99,7 +98,7 @@ function advance(store: WizardStore, screen: string): boolean { } return true; } - case ScreenId.Auth: + case 'auth': store.setCredentials({ accessToken: 'phx_test', projectApiKey: 'phc_test', @@ -108,11 +107,11 @@ function advance(store: WizardStore, screen: string): boolean { }); store.setApiUser(approved(false)); return true; - case ScreenId.AiOptIn: + case 'ai-opt-in': store.setApiUser(approved(true)); return true; - case ScreenId.Run: - case ScreenId.AuditRun: { + case 'run': + case 'audit-run': { const steps = getProgramConfig(store.activeProgram).steps; const runStep = steps.find( (st) => @@ -128,46 +127,46 @@ function advance(store: WizardStore, screen: string): boolean { } return true; } - case ScreenId.Outro: - case ScreenId.AuditOutro: - case ScreenId.SourceMapsOutro: + case 'outro': + case 'audit-outro': + case 'source-maps-outro': store.setOutroDismissed(); return true; - case ScreenId.DoctorReport: + case 'doctor-report': store.setOutroData({ kind: OutroKind.Success, message: 'done' }); return true; - case ScreenId.Mcp: - case ScreenId.McpAdd: - case ScreenId.McpRemove: + case 'mcp': + case 'mcp-add': + case 'mcp-remove': store.setMcpComplete(McpOutcome.Skipped); return true; - case ScreenId.McpSuggestedPrompts: + case 'mcp-suggested-prompts': store.setMcpSuggestedPromptsDismissed(); return true; - case ScreenId.SlackConnect: + case 'slack-connect': store.setSlackStepDismissed(); return true; - case ScreenId.KeepSkills: + case 'keep-skills': store.setSkillsComplete(true); return true; - case ScreenId.SelfDrivingIntegrationCheck: + case 'self-driving-integration-check': store.setIntegrate(true); return true; - case ScreenId.SelfDrivingIntegrationDetect: + case 'self-driving-integration-detect': store.setFrameworkContext(SELF_DRIVING_INTEGRATE_PATH_KEY, '.'); store.setFrameworkConfig(Integration.javascriptNode, NODE); return true; - case ScreenId.SelfDrivingHandoff: + case 'self-driving-handoff': store.confirmSelfDrivingHandoff(); return true; - case ScreenId.SelfDrivingGithub: + case 'self-driving-github': store.setGithubConnected(true); return true; - case ScreenId.ErrorTrackingDetect: + case 'error-tracking-detect': store.setFrameworkContext(ERROR_TRACKING_PROJECT_PATH_KEY, '.'); store.setFrameworkConfig(Integration.javascriptNode, NODE); return true; - case ScreenId.SourceMapsDetect: + case 'source-maps-detect': store.setFrameworkContext( SOURCE_MAPS_CONTEXT_KEYS.selectedVariant, 'node', @@ -187,7 +186,7 @@ function trace(program: ProgramId, integration: Integration | null) { for (let guard = 0; guard < 40; guard++) { const screen = store.currentScreen; screens.push(screen); - if (screen === ScreenId.Exit) break; + if (screen === 'exit') break; if (!advance(store, screen)) { stoppedOn = screen; break; @@ -218,7 +217,7 @@ describe('headless walk analytics', () => { it(`${program}: run phases without a TUI`, () => { wizardCapture.mockClear(); const store = new WizardStore(flowFor(program).flow); - setUI(new InkUI(store)); + setUI(new StoreUI(store)); store.session = buildSession({ installDir: '/app', ci: true }); store.setRunPhase(RunPhase.Running); store.setOutroData({ kind: OutroKind.Success, message: 'done' }); diff --git a/src/lib/programs/__tests__/mcp-analytics.test.ts b/src/store/programs/__tests__/mcp-analytics.test.ts similarity index 97% rename from src/lib/programs/__tests__/mcp-analytics.test.ts rename to src/store/programs/__tests__/mcp-analytics.test.ts index e9a8546dc..65fd22a59 100644 --- a/src/lib/programs/__tests__/mcp-analytics.test.ts +++ b/src/store/programs/__tests__/mcp-analytics.test.ts @@ -1,7 +1,7 @@ import { MCP_ANALYTICS_ABORT_CASES, mcpAnalyticsConfig, -} from '@lib/programs/mcp-analytics/index'; +} from '../mcp-analytics/index.js'; describe('MCP_ANALYTICS_ABORT_CASES', () => { // These are the exact `[ABORT] ` strings the mcp-analytics skill diff --git a/src/lib/programs/__tests__/post-auth-gates.test.ts b/src/store/programs/__tests__/post-auth-gates.test.ts similarity index 83% rename from src/lib/programs/__tests__/post-auth-gates.test.ts rename to src/store/programs/__tests__/post-auth-gates.test.ts index 15caa52a2..fa17fdea6 100644 --- a/src/lib/programs/__tests__/post-auth-gates.test.ts +++ b/src/store/programs/__tests__/post-auth-gates.test.ts @@ -2,8 +2,8 @@ * Golden of the post-auth gate ids the agent runner awaits per program * (`postAuthGateIdsFor`, the walk between the `auth` and `run` steps). */ -import { PROGRAM_REGISTRY } from '../program-registry'; -import { postAuthGateIdsFor, runConfigFor } from '../run-config'; +import { PROGRAM_REGISTRY } from '../program-registry.js'; +import { postAuthGateIdsFor, runConfigFor } from '../run-config.js'; describe('post-auth gate ids per program', () => { it('match the golden', () => { diff --git a/src/lib/programs/__tests__/posthog-cli-preinstall.test.ts b/src/store/programs/__tests__/posthog-cli-preinstall.test.ts similarity index 82% rename from src/lib/programs/__tests__/posthog-cli-preinstall.test.ts rename to src/store/programs/__tests__/posthog-cli-preinstall.test.ts index 355fd10b1..f05cf5218 100644 --- a/src/lib/programs/__tests__/posthog-cli-preinstall.test.ts +++ b/src/store/programs/__tests__/posthog-cli-preinstall.test.ts @@ -3,18 +3,18 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'; import { preinstallPostHogCliOnce, resetPostHogCliPreinstallForTests, -} from '@lib/programs/shared/posthog-cli-preinstall'; -import { installOrUpdatePostHogCli } from '@steps/install-cli-steering'; -import { getUI } from '@ui'; -import { analytics } from '@utils/analytics'; +} from '../shared/posthog-cli-preinstall.js'; +import { installOrUpdatePostHogCli } from '../../services/steps/install-cli-steering/index.js'; +import { getUI } from '../../ui/index.js'; +import { analytics } from '../../shared/analytics.js'; -vi.mock('@steps/install-cli-steering', () => ({ +vi.mock('../../services/steps/install-cli-steering/index.js', () => ({ installOrUpdatePostHogCli: vi.fn(), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); -vi.mock('@ui', () => ({ getUI: vi.fn() })); +vi.mock('../../ui/index.js', () => ({ getUI: vi.fn() })); const warn = vi.fn(); diff --git a/src/lib/programs/__tests__/posthog-integration-detect.test.ts b/src/store/programs/__tests__/posthog-integration-detect.test.ts similarity index 96% rename from src/lib/programs/__tests__/posthog-integration-detect.test.ts rename to src/store/programs/__tests__/posthog-integration-detect.test.ts index 7249ee81e..5363c039e 100644 --- a/src/lib/programs/__tests__/posthog-integration-detect.test.ts +++ b/src/store/programs/__tests__/posthog-integration-detect.test.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { detectExistingPostHog } from '@lib/programs/posthog-integration/detect'; +import { detectExistingPostHog } from '../posthog-integration/detect.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'ph-detect-')); diff --git a/src/lib/programs/__tests__/program-registry.test.ts b/src/store/programs/__tests__/program-registry.test.ts similarity index 97% rename from src/lib/programs/__tests__/program-registry.test.ts rename to src/store/programs/__tests__/program-registry.test.ts index 90f3e472d..fd2a89ff0 100644 --- a/src/lib/programs/__tests__/program-registry.test.ts +++ b/src/store/programs/__tests__/program-registry.test.ts @@ -5,8 +5,8 @@ import { getLaunchablePrograms, getProgramConfig, getSubcommandPrograms, -} from '@lib/programs/program-registry'; -import type { WizardSession } from '@lib/wizard-session'; +} from '../program-registry.js'; +import type { WizardSession } from '../../session/wizard-session.js'; describe('PROGRAM_REGISTRY', () => { it('every entry has unique id, description, and non-empty steps', () => { diff --git a/src/lib/programs/__tests__/program-step.test.ts b/src/store/programs/__tests__/program-step.test.ts similarity index 92% rename from src/lib/programs/__tests__/program-step.test.ts rename to src/store/programs/__tests__/program-step.test.ts index c19bf1f14..58b81646e 100644 --- a/src/lib/programs/__tests__/program-step.test.ts +++ b/src/store/programs/__tests__/program-step.test.ts @@ -1,6 +1,6 @@ -import type { ProgramStep } from '@lib/programs/program-step'; -import type { Flow } from '@lib/flow'; -import { flowEntries } from '@lib/flow-resolution'; +import type { ProgramStep } from '../program-step.js'; +import type { Flow } from '../../state/flow.js'; +import { flowEntries } from '../../state/flow-resolution.js'; const flowOf = (steps: ProgramStep[]): Flow => ({ programId: 'posthog-integration', diff --git a/src/lib/programs/__tests__/replay-vision.test.ts b/src/store/programs/__tests__/replay-vision.test.ts similarity index 95% rename from src/lib/programs/__tests__/replay-vision.test.ts rename to src/store/programs/__tests__/replay-vision.test.ts index a9146d2af..0321bb234 100644 --- a/src/lib/programs/__tests__/replay-vision.test.ts +++ b/src/store/programs/__tests__/replay-vision.test.ts @@ -1,10 +1,10 @@ import { describe, expect, test } from 'vitest'; -import { Integration } from '@lib/constants'; +import { Integration } from '../../shared/constants.js'; import { replayVisionConfig, REPLAY_VISION_SUPPORTED, -} from '@lib/programs/replay-vision/index'; +} from '../replay-vision/index.js'; describe('replay-vision program', () => { test('runs the replay-vision agent flow', () => { diff --git a/src/lib/programs/__tests__/revenue-analytics-detect.test.ts b/src/store/programs/__tests__/revenue-analytics-detect.test.ts similarity index 95% rename from src/lib/programs/__tests__/revenue-analytics-detect.test.ts rename to src/store/programs/__tests__/revenue-analytics-detect.test.ts index 5907dc4fa..5011c1aa3 100644 --- a/src/lib/programs/__tests__/revenue-analytics-detect.test.ts +++ b/src/store/programs/__tests__/revenue-analytics-detect.test.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { detectRevenuePrerequisites } from '@lib/programs/revenue-analytics/index'; -import { buildSession } from '@lib/wizard-session'; +import { detectRevenuePrerequisites } from '../revenue-analytics/index.js'; +import { buildSession } from '../../session/wizard-session.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'rev-detect-')); diff --git a/src/lib/programs/__tests__/self-driving-detect.test.ts b/src/store/programs/__tests__/self-driving-detect.test.ts similarity index 94% rename from src/lib/programs/__tests__/self-driving-detect.test.ts rename to src/store/programs/__tests__/self-driving-detect.test.ts index a5d7461fc..325fff0c8 100644 --- a/src/lib/programs/__tests__/self-driving-detect.test.ts +++ b/src/store/programs/__tests__/self-driving-detect.test.ts @@ -5,29 +5,28 @@ import { detectSelfDrivingPrerequisites, selfDrivingConfig, SELF_DRIVING_ABORT_CASES, -} from '@lib/programs/self-driving/index'; +} from '../self-driving/index.js'; import { detectPostHogPresent, POSTHOG_MANIFESTS, SELF_DRIVING_DETECTED_TOOLS_KEY, SELF_DRIVING_TOOL_KINDS, getSelfDrivingDetectedTools, -} from '@lib/programs/self-driving/detect'; -import { getDetectedWarehouseSources } from '@lib/programs/warehouse-source/detect'; -import { WizardStore } from '@ui/tui/store'; -import { PROGRAM_PRESENTATION } from '@ui/tui/programs/presentation'; -import { SOURCE_DETECTORS } from '@lib/warehouse-sources/registry'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; -import { toIntegrationReport } from '@lib/programs/self-driving/detect-agentic'; +} from '../self-driving/detect.js'; +import { getDetectedWarehouseSources } from '../warehouse-source/detect.js'; +import { WizardStore } from '../../state/store.js'; +import { SOURCE_DETECTORS } from '../../services/warehouse-sources/registry.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; +import { toIntegrationReport } from '../self-driving/detect-agentic.js'; import { PROJECT_MANIFESTS, type AgenticDetectionReport, -} from '@lib/detection/agentic'; -import { Integration } from '@lib/constants'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import { buildSession } from '@lib/wizard-session'; +} from '../../detection/agentic.js'; +import { Integration } from '../../shared/constants.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; +import { buildSession } from '../../session/wizard-session.js'; import type { Mock } from 'vitest'; -import { flowFor } from '@lib/programs/flow-for'; +import { flowFor } from '../flow-for.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'self-driving-detect-')); @@ -190,16 +189,6 @@ describe('selfDrivingConfig', () => { ); }); - it('ships its own Learn deck ending on the self-driving closer', () => { - const blocks = - PROGRAM_PRESENTATION['self-driving']?.getContentBlocks?.() ?? []; - expect(blocks.length).toBeGreaterThan(0); - const last = blocks[blocks.length - 1]; - expect( - typeof last === 'object' && 'content' in last ? last.content : '', - ).toBe('Your product drives itself.'); - }); - it('gives wizard_ask a 30-min timeout for the browser-handoff steps', async () => { // `run` is resolved per-session so the prompt can carry the integrate flag. const { run } = selfDrivingConfig; diff --git a/src/lib/programs/__tests__/self-driving-prompt.test.ts b/src/store/programs/__tests__/self-driving-prompt.test.ts similarity index 95% rename from src/lib/programs/__tests__/self-driving-prompt.test.ts rename to src/store/programs/__tests__/self-driving-prompt.test.ts index 36d850cb9..48332d3bc 100644 --- a/src/lib/programs/__tests__/self-driving-prompt.test.ts +++ b/src/store/programs/__tests__/self-driving-prompt.test.ts @@ -1,7 +1,7 @@ -import { buildSelfDrivingPrompt } from '@lib/programs/self-driving/prompt'; -import type { PromptContext } from '@lib/program-run'; -import { HostResolution } from '@lib/host-resolution'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import { buildSelfDrivingPrompt } from '../self-driving/prompt.js'; +import type { PromptContext } from '../../agent-protocol/program-run.js'; +import { HostResolution } from '../../host-resolution.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; const ctx: PromptContext = { projectId: 123, diff --git a/src/lib/programs/__tests__/source-maps-detect-agentic.test.ts b/src/store/programs/__tests__/source-maps-detect-agentic.test.ts similarity index 99% rename from src/lib/programs/__tests__/source-maps-detect-agentic.test.ts rename to src/store/programs/__tests__/source-maps-detect-agentic.test.ts index a64c6973f..0071fdac0 100644 --- a/src/lib/programs/__tests__/source-maps-detect-agentic.test.ts +++ b/src/store/programs/__tests__/source-maps-detect-agentic.test.ts @@ -6,8 +6,8 @@ import { goSdkVerifier, rustSdkVerifier, SOURCE_MAPS_TARGETS, -} from '@lib/programs/error-tracking-upload-source-maps/detect-agentic'; -import { AUTOMATABLE_VARIANTS } from '@lib/programs/error-tracking-upload-source-maps/detect'; +} from '../error-tracking-upload-source-maps/detect-agentic.js'; +import { AUTOMATABLE_VARIANTS } from '../error-tracking-upload-source-maps/detect.js'; describe('SOURCE_MAPS_TARGETS precedence', () => { const ids = SOURCE_MAPS_TARGETS.map((t) => t.id); diff --git a/src/lib/programs/__tests__/source-maps-detect.test.ts b/src/store/programs/__tests__/source-maps-detect.test.ts similarity index 98% rename from src/lib/programs/__tests__/source-maps-detect.test.ts rename to src/store/programs/__tests__/source-maps-detect.test.ts index 456933ad1..7d8a65097 100644 --- a/src/lib/programs/__tests__/source-maps-detect.test.ts +++ b/src/store/programs/__tests__/source-maps-detect.test.ts @@ -4,8 +4,8 @@ import * as os from 'os'; import { detectSourceMapsPrerequisites, SOURCE_MAPS_CONTEXT_KEYS, -} from '@lib/programs/error-tracking-upload-source-maps/index'; -import { buildSession } from '@lib/wizard-session'; +} from '../error-tracking-upload-source-maps/index.js'; +import { buildSession } from '../../session/wizard-session.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'source-maps-detect-')); diff --git a/src/lib/programs/__tests__/source-maps-prompt.test.ts b/src/store/programs/__tests__/source-maps-prompt.test.ts similarity index 97% rename from src/lib/programs/__tests__/source-maps-prompt.test.ts rename to src/store/programs/__tests__/source-maps-prompt.test.ts index 3945fdc50..3656902f9 100644 --- a/src/lib/programs/__tests__/source-maps-prompt.test.ts +++ b/src/store/programs/__tests__/source-maps-prompt.test.ts @@ -1,4 +1,4 @@ -import { buildSourceMapsUploadPrompt } from '@lib/programs/error-tracking-upload-source-maps/prompt'; +import { buildSourceMapsUploadPrompt } from '../error-tracking-upload-source-maps/prompt.js'; const baseParams = { displayName: 'Node.js', diff --git a/src/lib/programs/__tests__/warehouse-ask-timeout.test.ts b/src/store/programs/__tests__/warehouse-ask-timeout.test.ts similarity index 83% rename from src/lib/programs/__tests__/warehouse-ask-timeout.test.ts rename to src/store/programs/__tests__/warehouse-ask-timeout.test.ts index c74c5f766..2d6e25490 100644 --- a/src/lib/programs/__tests__/warehouse-ask-timeout.test.ts +++ b/src/store/programs/__tests__/warehouse-ask-timeout.test.ts @@ -7,9 +7,9 @@ * The command was on the 5-minute default, so the fallback route gave the * user a quarter of the time the in-run prompt does for identical questions. */ -import type { WizardSession } from '@lib/wizard-session'; +import type { WizardSession } from '../../session/wizard-session.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), setTag: vi.fn(), @@ -18,11 +18,11 @@ vi.mock('@utils/analytics', () => ({ }, })); -import { warehouseSourceConfig } from '@lib/programs/warehouse-source/index'; +import { warehouseSourceConfig } from '../warehouse-source/index.js'; import { LONGER_ASK_TIMEOUT_MS, DEFAULT_ASK_TIMEOUT_MS, -} from '@lib/wizard-ask-bridge'; +} from '../../session/wizard-ask-bridge.js'; function session(): WizardSession { return { installDir: '/tmp/app', frameworkContext: {} } as WizardSession; diff --git a/src/lib/programs/__tests__/warehouse-seed-task.test.ts b/src/store/programs/__tests__/warehouse-seed-task.test.ts similarity index 92% rename from src/lib/programs/__tests__/warehouse-seed-task.test.ts rename to src/store/programs/__tests__/warehouse-seed-task.test.ts index 0a6458392..9a45d9870 100644 --- a/src/lib/programs/__tests__/warehouse-seed-task.test.ts +++ b/src/store/programs/__tests__/warehouse-seed-task.test.ts @@ -3,10 +3,10 @@ * so it belongs only in a run that has both something to connect and someone * to answer — and the wizard, not the planner, is what decides that. */ -import type { WizardSession } from '@lib/wizard-session'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), setTag: vi.fn(), @@ -15,8 +15,8 @@ vi.mock('@utils/analytics', () => ({ }, })); -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; -import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@lib/programs/warehouse-source/detect'; +import { posthogIntegrationConfig } from '../posthog-integration/index.js'; +import { DETECTED_WAREHOUSE_SOURCES_KEY } from '../warehouse-source/detect.js'; const POSTGRES: DetectedSource = { kind: 'Postgres', diff --git a/src/lib/programs/__tests__/warehouse-suggestion.test.ts b/src/store/programs/__tests__/warehouse-suggestion.test.ts similarity index 95% rename from src/lib/programs/__tests__/warehouse-suggestion.test.ts rename to src/store/programs/__tests__/warehouse-suggestion.test.ts index 0f6023f28..909307404 100644 --- a/src/lib/programs/__tests__/warehouse-suggestion.test.ts +++ b/src/store/programs/__tests__/warehouse-suggestion.test.ts @@ -13,11 +13,14 @@ * say the run already connected the sources. */ -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; -import { POSTHOG_INTEGRATION_PROGRAM } from '@lib/programs/posthog-integration/steps'; -import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@lib/programs/warehouse-source/detect'; -import { buildSession, type WizardSession } from '@lib/wizard-session'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import { posthogIntegrationConfig } from '../posthog-integration/index.js'; +import { POSTHOG_INTEGRATION_PROGRAM } from '../posthog-integration/steps.js'; +import { DETECTED_WAREHOUSE_SOURCES_KEY } from '../warehouse-source/detect.js'; +import { + buildSession, + type WizardSession, +} from '../../session/wizard-session.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; const POSTGRES: DetectedSource = { kind: 'postgres', diff --git a/src/lib/programs/__tests__/web-analytics-doctor-detect.test.ts b/src/store/programs/__tests__/web-analytics-doctor-detect.test.ts similarity index 95% rename from src/lib/programs/__tests__/web-analytics-doctor-detect.test.ts rename to src/store/programs/__tests__/web-analytics-doctor-detect.test.ts index 2d689c11c..82fcdae53 100644 --- a/src/lib/programs/__tests__/web-analytics-doctor-detect.test.ts +++ b/src/store/programs/__tests__/web-analytics-doctor-detect.test.ts @@ -5,9 +5,9 @@ import { detectWebAnalyticsPrerequisites, webAnalyticsDoctorConfig, WEB_ANALYTICS_ABORT_CASES, -} from '@lib/programs/web-analytics-doctor/index'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import { buildSession } from '@lib/wizard-session'; +} from '../web-analytics-doctor/index.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; +import { buildSession } from '../../session/wizard-session.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'wa-detect-')); diff --git a/src/lib/programs/agent-skill/index.ts b/src/store/programs/agent-skill/index.ts similarity index 94% rename from src/lib/programs/agent-skill/index.ts rename to src/store/programs/agent-skill/index.ts index fd3da7f80..c5f916873 100644 --- a/src/lib/programs/agent-skill/index.ts +++ b/src/store/programs/agent-skill/index.ts @@ -19,8 +19,11 @@ * }) */ -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun, AbortCase } from '@lib/program-run'; +import type { ProgramConfig } from '../program-step.js'; +import type { + ProgramRun, + AbortCase, +} from '../../agent-protocol/program-run.js'; import { AGENT_SKILL_STEPS } from './steps.js'; export interface SkillProgramOptions { diff --git a/src/lib/programs/agent-skill/steps.ts b/src/store/programs/agent-skill/steps.ts similarity index 82% rename from src/lib/programs/agent-skill/steps.ts rename to src/store/programs/agent-skill/steps.ts index 992726616..ddcc823e3 100644 --- a/src/lib/programs/agent-skill/steps.ts +++ b/src/store/programs/agent-skill/steps.ts @@ -5,9 +5,9 @@ * No detection, no setup, no MCP. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import { RunPhase } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import { RunPhase } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; export const AGENT_SKILL_STEPS: ProgramStep[] = [ { diff --git a/src/lib/programs/ai-observability/index.ts b/src/store/programs/ai-observability/index.ts similarity index 95% rename from src/lib/programs/ai-observability/index.ts rename to src/store/programs/ai-observability/index.ts index c9319e69f..81ff0c015 100644 --- a/src/lib/programs/ai-observability/index.ts +++ b/src/store/programs/ai-observability/index.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig, ProgramStep } from '@lib/programs/program-step'; -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/index'; +import type { ProgramConfig, ProgramStep } from '../program-step.js'; +import { AGENT_SKILL_STEPS } from '../agent-skill/index.js'; const AI_OBSERVABILITY_STEPS: ProgramStep[] = AGENT_SKILL_STEPS.map((step) => step.id === 'intro' ? { ...step, screenId: 'ai-observability-intro' } : step, diff --git a/src/lib/programs/ai-observability/test/e2e.json b/src/store/programs/ai-observability/test/e2e.json similarity index 100% rename from src/lib/programs/ai-observability/test/e2e.json rename to src/store/programs/ai-observability/test/e2e.json diff --git a/src/lib/programs/ai-opt-in-gate.ts b/src/store/programs/ai-opt-in-gate.ts similarity index 97% rename from src/lib/programs/ai-opt-in-gate.ts rename to src/store/programs/ai-opt-in-gate.ts index d101a02a3..eaf134a54 100644 --- a/src/lib/programs/ai-opt-in-gate.ts +++ b/src/store/programs/ai-opt-in-gate.ts @@ -31,7 +31,7 @@ * already treats `ci || signup` as one non-interactive mode. */ -import type { WizardSession } from '@lib/wizard-session'; +import type { WizardSession } from '../session/wizard-session.js'; import type { ProgramConfig, ProgramStep } from './program-step.js'; /** Step id — also the ScreenId.AiOptIn enum value in screen-sequences. */ diff --git a/src/lib/programs/audit/detect.ts b/src/store/programs/audit/detect.ts similarity index 82% rename from src/lib/programs/audit/detect.ts rename to src/store/programs/audit/detect.ts index 4312f79f1..e3705b57c 100644 --- a/src/lib/programs/audit/detect.ts +++ b/src/store/programs/audit/detect.ts @@ -1,5 +1,5 @@ -import type { AbortCase } from '@lib/program-run'; -import { ErrorCodes } from '@lib/errors'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; /** `[ABORT] ` cases the audit skill can emit. Reason strings are * defined in the skill's `Abort statuses` section. */ diff --git a/src/lib/programs/audit/index.ts b/src/store/programs/audit/index.ts similarity index 88% rename from src/lib/programs/audit/index.ts rename to src/store/programs/audit/index.ts index e0847a05d..42aae89a1 100644 --- a/src/lib/programs/audit/index.ts +++ b/src/store/programs/audit/index.ts @@ -1,13 +1,10 @@ -import { - AGENT_SKILL_STEPS, - createSkillProgram, -} from '@lib/programs/agent-skill/index'; -import type { ProgramStep, ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import type { WizardSession } from '@lib/wizard-session'; -import { OutroKind } from '@lib/wizard-session'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import { headlessOption, regionOption } from '@lib/headless-mode'; +import { AGENT_SKILL_STEPS, createSkillProgram } from '../agent-skill/index.js'; +import type { ProgramStep, ProgramConfig } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { OutroKind } from '../../session/wizard-session.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; +import { headlessOption, regionOption } from '../../shared/headless-mode.js'; import { AUDIT_ABORT_CASES } from './detect.js'; import { AUDIT_CHECKS_FILE, diff --git a/src/lib/programs/audit/ledger-watcher.ts b/src/store/programs/audit/ledger-watcher.ts similarity index 89% rename from src/lib/programs/audit/ledger-watcher.ts rename to src/store/programs/audit/ledger-watcher.ts index f7a312543..fd635a1ae 100644 --- a/src/lib/programs/audit/ledger-watcher.ts +++ b/src/store/programs/audit/ledger-watcher.ts @@ -5,13 +5,13 @@ */ import path from 'path'; -import { getUI } from '@ui'; +import { getUI } from '../../ui/index.js'; import { startFileWatcher, type FileWatcherHandle, type FileWatcherOptions, -} from '@lib/file-watcher'; -import { logToFile } from '@utils/debug'; +} from '../../file-watcher.js'; +import { logToFile } from '../../shared/debug.js'; import { AUDIT_CHECKS_KEY, coerceAuditChecks } from './types.js'; const MAX_LEDGER_FILE_BYTES = 256 * 1024; diff --git a/src/lib/programs/audit/seed.ts b/src/store/programs/audit/seed.ts similarity index 96% rename from src/lib/programs/audit/seed.ts rename to src/store/programs/audit/seed.ts index 47a673c11..626043b81 100644 --- a/src/lib/programs/audit/seed.ts +++ b/src/store/programs/audit/seed.ts @@ -1,6 +1,6 @@ import path from 'path'; -import { writeJsonAtomic } from '@utils/atomic-ledger'; -import { logToFile } from '@utils/debug'; +import { writeJsonAtomic } from '../../shared/atomic-ledger.js'; +import { logToFile } from '../../shared/debug.js'; import { AUDIT_CHECKS_FILE, type AuditCheck } from './types.js'; /** diff --git a/src/lib/programs/audit/test/e2e.json b/src/store/programs/audit/test/e2e.json similarity index 100% rename from src/lib/programs/audit/test/e2e.json rename to src/store/programs/audit/test/e2e.json diff --git a/src/lib/programs/audit/types.ts b/src/store/programs/audit/types.ts similarity index 95% rename from src/lib/programs/audit/types.ts rename to src/store/programs/audit/types.ts index dd858a709..48242e3c9 100644 --- a/src/lib/programs/audit/types.ts +++ b/src/store/programs/audit/types.ts @@ -1,4 +1,4 @@ -import type { WizardSession } from '@lib/wizard-session'; +import type { WizardSession } from '../../session/wizard-session.js'; export type AuditStatus = | 'pending' diff --git a/src/lib/programs/error-tracking-upload-source-maps/detect-agentic.ts b/src/store/programs/error-tracking-upload-source-maps/detect-agentic.ts similarity index 98% rename from src/lib/programs/error-tracking-upload-source-maps/detect-agentic.ts rename to src/store/programs/error-tracking-upload-source-maps/detect-agentic.ts index 17d3561c0..ca8f07129 100644 --- a/src/lib/programs/error-tracking-upload-source-maps/detect-agentic.ts +++ b/src/store/programs/error-tracking-upload-source-maps/detect-agentic.ts @@ -9,15 +9,15 @@ import { existsSync, readFileSync, readdirSync } from 'fs'; import { join } from 'path'; -import { IGNORED_DIRS, readProjectFile } from '@utils/bounded-fs'; +import { IGNORED_DIRS, readProjectFile } from '../../shared/bounded-fs.js'; import { detectProjectsWithAgent, coerceAgenticReport, type DetectTarget, type AgenticDetectionReport, type DetectEvent, -} from '@lib/detection/agentic'; -import type { WizardSession } from '@lib/wizard-session'; +} from '../../detection/agentic.js'; +import type { WizardSession } from '../../session/wizard-session.js'; import { VARIANT_DISPLAY_NAME, AUTOMATABLE_VARIANTS, diff --git a/src/lib/programs/error-tracking-upload-source-maps/detect.ts b/src/store/programs/error-tracking-upload-source-maps/detect.ts similarity index 98% rename from src/lib/programs/error-tracking-upload-source-maps/detect.ts rename to src/store/programs/error-tracking-upload-source-maps/detect.ts index 5fa9e7ddd..3befb6bcb 100644 --- a/src/lib/programs/error-tracking-upload-source-maps/detect.ts +++ b/src/store/programs/error-tracking-upload-source-maps/detect.ts @@ -15,10 +15,10 @@ import { MAX_DIR_ENTRIES, MAX_WALK_FILES, safeReadFile, -} from '@utils/bounded-fs'; -import type { WizardSession } from '@lib/wizard-session'; -import type { AbortCase } from '@lib/program-run'; -import { ErrorCodes } from '@lib/errors'; +} from '../../shared/bounded-fs.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; /** * Skill variants published under the `error-tracking-upload-source-maps` diff --git a/src/lib/programs/error-tracking-upload-source-maps/index.ts b/src/store/programs/error-tracking-upload-source-maps/index.ts similarity index 92% rename from src/lib/programs/error-tracking-upload-source-maps/index.ts rename to src/store/programs/error-tracking-upload-source-maps/index.ts index fe2df3850..6b1b72e41 100644 --- a/src/lib/programs/error-tracking-upload-source-maps/index.ts +++ b/src/store/programs/error-tracking-upload-source-maps/index.ts @@ -1,7 +1,7 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import type { WizardSession } from '@lib/wizard-session'; -import { OutroKind } from '@lib/wizard-session'; +import type { ProgramConfig } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { OutroKind } from '../../session/wizard-session.js'; import { ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM } from './steps.js'; import { buildSourceMapsUploadPrompt, @@ -13,8 +13,8 @@ import { VARIANTS_REQUIRING_POSTHOG_CLI, type SkillVariant, } from './detect.js'; -import { getUI } from '@ui'; -import { preinstallPostHogCliOnce } from '@lib/programs/shared/posthog-cli-preinstall'; +import { getUI } from '../../ui/index.js'; +import { preinstallPostHogCliOnce } from '../shared/posthog-cli-preinstall.js'; const REPORT_FILE = 'posthog-source-maps-report.md'; const DOCS_URL = 'https://posthog.com/docs/error-tracking/upload-source-maps'; diff --git a/src/lib/programs/error-tracking-upload-source-maps/prompt.ts b/src/store/programs/error-tracking-upload-source-maps/prompt.ts similarity index 99% rename from src/lib/programs/error-tracking-upload-source-maps/prompt.ts rename to src/store/programs/error-tracking-upload-source-maps/prompt.ts index ed31336c6..5bbe087a3 100644 --- a/src/lib/programs/error-tracking-upload-source-maps/prompt.ts +++ b/src/store/programs/error-tracking-upload-source-maps/prompt.ts @@ -1,4 +1,4 @@ -import { AgentSignals } from '@lib/agent-signals'; +import { AgentSignals } from '../../agent-protocol/agent-signals.js'; import type { SkillVariant } from './detect.js'; export type SourceMapsUploadPromptParams = { diff --git a/src/lib/programs/error-tracking-upload-source-maps/steps.ts b/src/store/programs/error-tracking-upload-source-maps/steps.ts similarity index 90% rename from src/lib/programs/error-tracking-upload-source-maps/steps.ts rename to src/store/programs/error-tracking-upload-source-maps/steps.ts index 33bfc7449..9c106e495 100644 --- a/src/lib/programs/error-tracking-upload-source-maps/steps.ts +++ b/src/store/programs/error-tracking-upload-source-maps/steps.ts @@ -7,9 +7,9 @@ * needs credentials. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; -import { RunPhase } from '@lib/wizard-session'; +import type { ProgramStep } from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { RunPhase } from '../../session/wizard-session.js'; import { SOURCE_MAPS_CONTEXT_KEYS } from './detect.js'; function projectSelected(session: WizardSession): boolean { diff --git a/src/lib/programs/error-tracking-upload-source-maps/test/e2e.json b/src/store/programs/error-tracking-upload-source-maps/test/e2e.json similarity index 100% rename from src/lib/programs/error-tracking-upload-source-maps/test/e2e.json rename to src/store/programs/error-tracking-upload-source-maps/test/e2e.json diff --git a/src/lib/programs/error-tracking/detect-agentic.ts b/src/store/programs/error-tracking/detect-agentic.ts similarity index 92% rename from src/lib/programs/error-tracking/detect-agentic.ts rename to src/store/programs/error-tracking/detect-agentic.ts index 5f7fd5268..4c143a674 100644 --- a/src/lib/programs/error-tracking/detect-agentic.ts +++ b/src/store/programs/error-tracking/detect-agentic.ts @@ -11,18 +11,18 @@ * - The scan bills to error-tracking. */ -import { Integration } from '@lib/constants'; +import { Integration } from '../../shared/constants.js'; import { resolveProjectDir, type AgenticDetectionReport, type DetectEvent, -} from '@lib/detection/agentic'; -import { gatherFrameworkContext } from '@lib/detection/index'; +} from '../../detection/agentic.js'; +import { gatherFrameworkContext } from '../../detection/index.js'; import { detectIntegrationProjects, toIntegrationCandidates, -} from '@lib/detection/project-scope'; -import type { WizardSession } from '@lib/wizard-session'; +} from '../../detection/project-scope.js'; +import type { WizardSession } from '../../session/wizard-session.js'; /** frameworkContext key for the picked project's path, relative to the repo root. */ export const ERROR_TRACKING_PROJECT_PATH_KEY = 'errorTrackingProjectPath'; diff --git a/src/lib/programs/error-tracking/index.ts b/src/store/programs/error-tracking/index.ts similarity index 90% rename from src/lib/programs/error-tracking/index.ts rename to src/store/programs/error-tracking/index.ts index e52d37bf4..8aa47422a 100644 --- a/src/lib/programs/error-tracking/index.ts +++ b/src/store/programs/error-tracking/index.ts @@ -1,20 +1,20 @@ -import { Integration } from '@lib/constants'; -import { detectFramework } from '@lib/detection/index'; -import { scopeInstallDirToProject } from '@lib/detection/project-scope'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import type { ProgramRun } from '@lib/program-run'; -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/steps'; +import { Integration } from '../../shared/constants.js'; +import { detectFramework } from '../../detection/index.js'; +import { scopeInstallDirToProject } from '../../detection/project-scope.js'; +import { FRAMEWORK_REGISTRY } from '../../registry.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import { AGENT_SKILL_STEPS } from '../agent-skill/steps.js'; import { ERROR_TRACKING_UNSUPPORTED, errorTrackingProjectDir, gatherErrorTrackingContext, -} from '@lib/programs/error-tracking/detect-agentic'; -import type { ProgramConfig, ProgramStep } from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; -import { preinstallPostHogCliOnce } from '@lib/programs/shared/posthog-cli-preinstall'; -import { analytics } from '@utils/analytics'; -import { wizardAbort } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; +} from './detect-agentic.js'; +import type { ProgramConfig, ProgramStep } from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { preinstallPostHogCliOnce } from '../shared/posthog-cli-preinstall.js'; +import { analytics } from '../../shared/analytics.js'; +import { wizardAbort } from '../../shared/wizard-abort.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; const ERROR_TRACKING_REPORT_FILE = 'posthog-error-tracking-report.md'; const ERROR_TRACKING_DOCS_URL = 'https://posthog.com/docs/error-tracking'; diff --git a/src/lib/programs/error-tracking/test/e2e.json b/src/store/programs/error-tracking/test/e2e.json similarity index 100% rename from src/lib/programs/error-tracking/test/e2e.json rename to src/store/programs/error-tracking/test/e2e.json diff --git a/src/lib/programs/events-audit/constants.ts b/src/store/programs/events-audit/constants.ts similarity index 100% rename from src/lib/programs/events-audit/constants.ts rename to src/store/programs/events-audit/constants.ts diff --git a/src/lib/programs/events-audit/index.ts b/src/store/programs/events-audit/index.ts similarity index 87% rename from src/lib/programs/events-audit/index.ts rename to src/store/programs/events-audit/index.ts index ae5d1dd9f..96707a062 100644 --- a/src/lib/programs/events-audit/index.ts +++ b/src/store/programs/events-audit/index.ts @@ -1,13 +1,13 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import type { WizardSession } from '@lib/wizard-session'; -import { OutroKind } from '@lib/wizard-session'; -import { SPINNER_MESSAGE } from '@lib/framework-config'; -import { isUsingTypeScript } from '@utils/setup-utils'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; +import type { ProgramConfig } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { OutroKind } from '../../session/wizard-session.js'; +import { SPINNER_MESSAGE } from '../../framework-config.js'; +import { isUsingTypeScript } from '../../shared/setup-utils.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; import { EVENTS_AUDIT_PROGRAM } from './steps.js'; -import { AUDIT_CHECKS_FILE, AUDIT_CHECKS_KEY } from '@lib/programs/audit/types'; -import { seedAuditLedger } from '@lib/programs/audit/seed'; +import { AUDIT_CHECKS_FILE, AUDIT_CHECKS_KEY } from '../audit/types.js'; +import { seedAuditLedger } from '../audit/seed.js'; import { EVENTS_AUDIT_SEED_CHECKS } from './seed.js'; // SETUP_REPORT_FILE is also re-exported for backward compat with existing diff --git a/src/lib/programs/events-audit/seed.ts b/src/store/programs/events-audit/seed.ts similarity index 96% rename from src/lib/programs/events-audit/seed.ts rename to src/store/programs/events-audit/seed.ts index f2c0df189..3bc4d178c 100644 --- a/src/lib/programs/events-audit/seed.ts +++ b/src/store/programs/events-audit/seed.ts @@ -1,4 +1,4 @@ -import type { AuditCheck } from '@lib/programs/audit/types'; +import type { AuditCheck } from '../audit/types.js'; /** * The 7 phases the events-audit skill marches through. One check per area diff --git a/src/lib/programs/events-audit/steps.ts b/src/store/programs/events-audit/steps.ts similarity index 86% rename from src/lib/programs/events-audit/steps.ts rename to src/store/programs/events-audit/steps.ts index b9e07298a..94dab6c22 100644 --- a/src/lib/programs/events-audit/steps.ts +++ b/src/store/programs/events-audit/steps.ts @@ -8,10 +8,10 @@ * logic) instead of the integration intro. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; -import { RunPhase } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { RunPhase } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; function needsSetup(session: WizardSession): boolean { const config = session.frameworkConfig; diff --git a/src/lib/programs/flow-for.ts b/src/store/programs/flow-for.ts similarity index 92% rename from src/lib/programs/flow-for.ts rename to src/store/programs/flow-for.ts index 705297194..0d20bce84 100644 --- a/src/lib/programs/flow-for.ts +++ b/src/store/programs/flow-for.ts @@ -1,4 +1,4 @@ -import type { Flow } from '@lib/flow'; +import type { Flow } from '../state/flow.js'; import { getProgramConfig, type ProgramId } from './program-registry.js'; import type { ProgramConfig } from './program-step.js'; import { withAiOptInGate } from './ai-opt-in-gate.js'; diff --git a/src/store/programs/index.ts b/src/store/programs/index.ts new file mode 100644 index 000000000..d2881c969 --- /dev/null +++ b/src/store/programs/index.ts @@ -0,0 +1,67 @@ +/** Program registry and definitions consumed by the cli and the tui. */ +export { createSkillProgram } from './agent-skill/index.js'; +export { aiObservabilityConfig } from './ai-observability/index.js'; +export { auditConfig } from './audit/index.js'; +export { startAuditLedgerWatcher } from './audit/ledger-watcher.js'; +export { + AUDIT_CHECKS_FILE, + AUDIT_REPORT_FILE, + AUDIT_SEVERITY_STYLE, + getAuditChecks, +} from './audit/types.js'; +export { detectSourceMapsProjects } from './error-tracking-upload-source-maps/detect-agentic.js'; +export { + MANUAL_SDK_VARIANTS, + SOURCE_MAPS_CONTEXT_KEYS, +} from './error-tracking-upload-source-maps/detect.js'; +export { + VARIANT_DISPLAY_NAME, + errorTrackingUploadSourceMapsConfig, +} from './error-tracking-upload-source-maps/index.js'; +export { + ERROR_TRACKING_PROJECT_PATH_KEY, + detectErrorTrackingProjects, +} from './error-tracking/detect-agentic.js'; +export { errorTrackingConfig } from './error-tracking/index.js'; +export { flowFor } from './flow-for.js'; +export { mcpAnalyticsConfig } from './mcp-analytics/index.js'; +export { metricsConfig } from './metrics/index.js'; +export { migrationConfig } from './migration/index.js'; +export { fetchHealthIssues } from './posthog-doctor/fetch.js'; +export { posthogDoctorConfig } from './posthog-doctor/index.js'; +export { getKindMeta } from './posthog-doctor/kind-metadata.js'; +export { maybeStampAiSdkDetected } from './posthog-integration/detect.js'; +export { + SETUP_REPORT_FILE, + posthogIntegrationConfig, +} from './posthog-integration/index.js'; +export { + PROGRAM_REGISTRY, + Program, + agentSkillConfig, + getCommandPath, + getLaunchablePrograms, + getProgramConfig, +} from './program-registry.js'; +export { + REPLAY_VISION_SUPPORTED, + replayVisionConfig, +} from './replay-vision/index.js'; +export { revenueAnalyticsConfig } from './revenue-analytics/index.js'; +export { runConfigFor } from './run-config.js'; +export { detectSelfDrivingIntegrationProjects } from './self-driving/detect-agentic.js'; +export { + GITHUB_REQUIRED_BODY, + GITHUB_REQUIRED_MESSAGE, + SELF_DRIVING_INTEGRATE_PATH_KEY, +} from './self-driving/detect.js'; +export { selfDrivingConfig } from './self-driving/index.js'; +export { + NO_DEFAULT_LIMIT, + PRICING_LONG, + PRICING_SHORT, +} from './self-driving/pricing.js'; +export { POSTHOG_SDKS, STRIPE_SDKS } from './shared/package-scanning.js'; +export { getDetectedWarehouseSources } from './warehouse-source/detect.js'; +export { warehouseSourceConfig } from './warehouse-source/index.js'; +export { webAnalyticsDoctorConfig } from './web-analytics-doctor/index.js'; diff --git a/src/lib/programs/mcp-analytics/index.ts b/src/store/programs/mcp-analytics/index.ts similarity index 94% rename from src/lib/programs/mcp-analytics/index.ts rename to src/store/programs/mcp-analytics/index.ts index c4f16857e..2e1f1b276 100644 --- a/src/lib/programs/mcp-analytics/index.ts +++ b/src/store/programs/mcp-analytics/index.ts @@ -1,6 +1,6 @@ -import type { AbortCase } from '@lib/program-run'; -import { ErrorCodes } from '@lib/errors'; -import { createSkillProgram } from '@lib/programs/agent-skill/index'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; +import { createSkillProgram } from '../agent-skill/index.js'; const MCP_ANALYTICS_REPORT_FILE = 'posthog-mcp-analytics-report.md'; diff --git a/src/lib/programs/mcp/index.ts b/src/store/programs/mcp/index.ts similarity index 97% rename from src/lib/programs/mcp/index.ts rename to src/store/programs/mcp/index.ts index 819e19e8e..39f15b8b0 100644 --- a/src/lib/programs/mcp/index.ts +++ b/src/store/programs/mcp/index.ts @@ -8,8 +8,8 @@ * screen-sequences.ts). */ -import type { ProgramConfig } from '@lib/programs/program-step'; -import { McpOutcome } from '@lib/wizard-session'; +import type { ProgramConfig } from '../program-step.js'; +import { McpOutcome } from '../../session/wizard-session.js'; export const mcpAddConfig: ProgramConfig = { id: 'mcp-add', diff --git a/src/lib/programs/__tests__/metrics-program.test.ts b/src/store/programs/metrics/__tests__/metrics-program.test.ts similarity index 76% rename from src/lib/programs/__tests__/metrics-program.test.ts rename to src/store/programs/metrics/__tests__/metrics-program.test.ts index 3a7eba662..d9c6faad8 100644 --- a/src/lib/programs/__tests__/metrics-program.test.ts +++ b/src/store/programs/metrics/__tests__/metrics-program.test.ts @@ -1,9 +1,7 @@ -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/index'; -import { getProgramConfig, Program } from '@lib/programs/program-registry'; -import { metricsConfig } from '@lib/programs/metrics/index'; -import type { ProgramRun } from '@lib/program-run'; - -import { metricsCommand } from '../../../commands/metrics'; +import { AGENT_SKILL_STEPS } from '../../agent-skill/index.js'; +import { getProgramConfig, Program } from '../../program-registry.js'; +import { metricsConfig } from '../index.js'; +import type { ProgramRun } from '../../../types.js'; function staticRun(config: typeof metricsConfig): ProgramRun { if (typeof config.run === 'function') { @@ -58,10 +56,4 @@ describe('metrics program', () => { expect(run.reportFile).toBe('posthog-metrics-report.md'); expect(metricsConfig.reportFile).toBe(run.reportFile); }); - - it('is exposed as a yargs command via nativeCommandFactory', () => { - expect(metricsCommand.name).toBe('metrics'); - expect(metricsCommand.description).toBe(metricsConfig.description); - expect(typeof metricsCommand.handler).toBe('function'); - }); }); diff --git a/src/lib/programs/metrics/index.ts b/src/store/programs/metrics/index.ts similarity index 95% rename from src/lib/programs/metrics/index.ts rename to src/store/programs/metrics/index.ts index 4430a72c0..50aa62905 100644 --- a/src/lib/programs/metrics/index.ts +++ b/src/store/programs/metrics/index.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig, ProgramStep } from '@lib/programs/program-step'; -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/index'; +import type { ProgramConfig, ProgramStep } from '../program-step.js'; +import { AGENT_SKILL_STEPS } from '../agent-skill/index.js'; const METRICS_STEPS: ProgramStep[] = AGENT_SKILL_STEPS.map((step) => step.id === 'intro' ? { ...step, screenId: 'metrics-intro' } : step, diff --git a/src/lib/programs/metrics/test/e2e.json b/src/store/programs/metrics/test/e2e.json similarity index 100% rename from src/lib/programs/metrics/test/e2e.json rename to src/store/programs/metrics/test/e2e.json diff --git a/src/lib/programs/migration/index.ts b/src/store/programs/migration/index.ts similarity index 92% rename from src/lib/programs/migration/index.ts rename to src/store/programs/migration/index.ts index 1c3605fbf..9e96a1f65 100644 --- a/src/lib/programs/migration/index.ts +++ b/src/store/programs/migration/index.ts @@ -1,6 +1,6 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { AbortCase } from '@lib/program-run'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; +import type { ProgramConfig } from '../program-step.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; import { MIGRATION_PROGRAM } from './steps.js'; const MIGRATION_REPORT_FILE = 'migration-report.md'; diff --git a/src/lib/programs/migration/steps.ts b/src/store/programs/migration/steps.ts similarity index 79% rename from src/lib/programs/migration/steps.ts rename to src/store/programs/migration/steps.ts index 33635d863..6b670f5f0 100644 --- a/src/lib/programs/migration/steps.ts +++ b/src/store/programs/migration/steps.ts @@ -1,6 +1,6 @@ -import type { ProgramStep } from '@lib/programs/program-step'; -import { RunPhase } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import { RunPhase } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; export const MIGRATION_PROGRAM: ProgramStep[] = [ { diff --git a/src/lib/programs/posthog-doctor/__tests__/doctor-schema.test.ts b/src/store/programs/posthog-doctor/__tests__/doctor-schema.test.ts similarity index 92% rename from src/lib/programs/posthog-doctor/__tests__/doctor-schema.test.ts rename to src/store/programs/posthog-doctor/__tests__/doctor-schema.test.ts index cc23b479f..fa079ffb5 100644 --- a/src/lib/programs/posthog-doctor/__tests__/doctor-schema.test.ts +++ b/src/store/programs/posthog-doctor/__tests__/doctor-schema.test.ts @@ -1,12 +1,9 @@ -import { - HealthIssueListResponseSchema, - HealthIssueSchema, -} from '@lib/programs/posthog-doctor/types'; +import { HealthIssueListResponseSchema, HealthIssueSchema } from '../types.js'; import { getKindMeta, KIND_METADATA, UNKNOWN_KIND_META, -} from '@lib/programs/posthog-doctor/kind-metadata'; +} from '../kind-metadata.js'; describe('posthog-doctor schema', () => { const canned = { diff --git a/src/lib/programs/posthog-doctor/fetch.ts b/src/store/programs/posthog-doctor/fetch.ts similarity index 81% rename from src/lib/programs/posthog-doctor/fetch.ts rename to src/store/programs/posthog-doctor/fetch.ts index b0a5f2e44..3879ec155 100644 --- a/src/lib/programs/posthog-doctor/fetch.ts +++ b/src/store/programs/posthog-doctor/fetch.ts @@ -1,8 +1,8 @@ import axios from 'axios'; -import { analytics } from '@utils/analytics'; -import { handleApiError } from '@lib/api'; -import { WIZARD_USER_AGENT } from '@lib/constants'; -import { HealthIssueListResponseSchema, type HealthIssue } from './types'; +import { analytics } from '../../shared/analytics.js'; +import { handleApiError } from '../../api.js'; +import { WIZARD_USER_AGENT } from '../../shared/constants.js'; +import { HealthIssueListResponseSchema, type HealthIssue } from './types.js'; export async function fetchHealthIssues( accessToken: string, diff --git a/src/lib/programs/posthog-doctor/index.ts b/src/store/programs/posthog-doctor/index.ts similarity index 84% rename from src/lib/programs/posthog-doctor/index.ts rename to src/store/programs/posthog-doctor/index.ts index 8ea70acf1..590112661 100644 --- a/src/lib/programs/posthog-doctor/index.ts +++ b/src/store/programs/posthog-doctor/index.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; +import type { ProgramConfig } from '../program-step.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; import { POSTHOG_DOCTOR_PROGRAM } from './steps.js'; export const posthogDoctorConfig: ProgramConfig = { diff --git a/src/lib/programs/posthog-doctor/kind-metadata.ts b/src/store/programs/posthog-doctor/kind-metadata.ts similarity index 97% rename from src/lib/programs/posthog-doctor/kind-metadata.ts rename to src/store/programs/posthog-doctor/kind-metadata.ts index 885e1062e..12787670c 100644 --- a/src/lib/programs/posthog-doctor/kind-metadata.ts +++ b/src/store/programs/posthog-doctor/kind-metadata.ts @@ -1,4 +1,4 @@ -import { POSTHOG_DOCS_URL } from '@lib/constants'; +import { POSTHOG_DOCS_URL } from '../../shared/constants.js'; export interface KindMeta { title: string; diff --git a/src/lib/programs/posthog-doctor/steps.ts b/src/store/programs/posthog-doctor/steps.ts similarity index 81% rename from src/lib/programs/posthog-doctor/steps.ts rename to src/store/programs/posthog-doctor/steps.ts index fe0ef895c..8be7a9434 100644 --- a/src/lib/programs/posthog-doctor/steps.ts +++ b/src/store/programs/posthog-doctor/steps.ts @@ -1,5 +1,5 @@ -import type { ProgramStep } from '@lib/programs/program-step'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; export const POSTHOG_DOCTOR_PROGRAM: ProgramStep[] = [ { diff --git a/src/lib/programs/posthog-doctor/types.ts b/src/store/programs/posthog-doctor/types.ts similarity index 100% rename from src/lib/programs/posthog-doctor/types.ts rename to src/store/programs/posthog-doctor/types.ts diff --git a/src/lib/programs/posthog-integration/__tests__/detect.test.ts b/src/store/programs/posthog-integration/__tests__/detect.test.ts similarity index 95% rename from src/lib/programs/posthog-integration/__tests__/detect.test.ts rename to src/store/programs/posthog-integration/__tests__/detect.test.ts index 3e4a67f56..2f936cded 100644 --- a/src/lib/programs/posthog-integration/__tests__/detect.test.ts +++ b/src/store/programs/posthog-integration/__tests__/detect.test.ts @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), setTag: vi.fn(), @@ -15,33 +15,36 @@ vi.mock('@utils/analytics', () => ({ })); // Wrapped so one test can force a throw; the rest use the real scanner. -vi.mock('@lib/warehouse-sources/detect', async (importOriginal) => { - const actual = await importOriginal< - typeof import('@lib/warehouse-sources/detect') - >(); - return { - ...actual, - detectWarehouseSources: vi.fn(actual.detectWarehouseSources), - }; -}); +vi.mock( + '../../../services/warehouse-sources/detect.js', + async (importOriginal) => { + const actual = await importOriginal< + typeof import('../../../services/warehouse-sources/detect.js') + >(); + return { + ...actual, + detectWarehouseSources: vi.fn(actual.detectWarehouseSources), + }; + }, +); -import { analytics } from '@utils/analytics'; -import { detectWarehouseSources } from '@lib/warehouse-sources/detect'; +import { analytics } from '../../../shared/analytics.js'; +import { detectWarehouseSources } from '../../../services/warehouse-sources/detect.js'; import { detectPostHogIntegration, maybeStampAiSdkDetected, reportWarehouseSourcesDetected, -} from '@lib/programs/posthog-integration/detect'; -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; -import { DETECTED_WAREHOUSE_SOURCES_KEY } from '@lib/programs/warehouse-source/detect'; -import type { ProgramReadyContext } from '@lib/programs/program-step'; +} from '../detect.js'; +import { posthogIntegrationConfig } from '../index.js'; +import { DETECTED_WAREHOUSE_SOURCES_KEY } from '../../warehouse-source/detect.js'; +import type { ProgramReadyContext } from '../../program-step.js'; import { buildSession, DiscoveredFeature, ScanConsent, type WizardSession, -} from '@lib/wizard-session'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +} from '../../../session/wizard-session.js'; +import type { DetectedSource } from '../../../services/warehouse-sources/types.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'warehouse-reporting-')); @@ -288,7 +291,7 @@ describe('reportWarehouseSourcesDetected', () => { // scanned". const session = buildSession({ installDir: tmpDir, ci: true }); const { detectWarehousePrerequisites } = await import( - '@lib/programs/warehouse-source/detect' + '../../warehouse-source/detect.js' ); detectWarehousePrerequisites(session, (key, value) => { session.frameworkContext[key] = value; diff --git a/src/lib/programs/posthog-integration/__tests__/handoff.test.ts b/src/store/programs/posthog-integration/__tests__/handoff.test.ts similarity index 96% rename from src/lib/programs/posthog-integration/__tests__/handoff.test.ts rename to src/store/programs/posthog-integration/__tests__/handoff.test.ts index cc6a47e55..4f5ddd95d 100644 --- a/src/lib/programs/posthog-integration/__tests__/handoff.test.ts +++ b/src/store/programs/posthog-integration/__tests__/handoff.test.ts @@ -1,4 +1,4 @@ -import { buildCodingAgentPrompt } from '../handoff'; +import { buildCodingAgentPrompt } from '../handoff.js'; const NOTEBOOK_URL = 'https://us.posthog.com/project/1/notebooks/AbCdEfGh'; diff --git a/src/lib/programs/posthog-integration/__tests__/index.test.ts b/src/store/programs/posthog-integration/__tests__/index.test.ts similarity index 84% rename from src/lib/programs/posthog-integration/__tests__/index.test.ts rename to src/store/programs/posthog-integration/__tests__/index.test.ts index ec55f6efe..e5d535665 100644 --- a/src/lib/programs/posthog-integration/__tests__/index.test.ts +++ b/src/store/programs/posthog-integration/__tests__/index.test.ts @@ -6,12 +6,15 @@ * state, so the value rides on every later capture either way. */ -import { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index'; -import { buildSession, type WizardSession } from '@lib/wizard-session'; -import { analytics } from '@utils/analytics'; -import { isUsingTypeScript } from '@utils/setup-utils'; +import { posthogIntegrationConfig } from '../index.js'; +import { + buildSession, + type WizardSession, +} from '../../../session/wizard-session.js'; +import { analytics } from '../../../shared/analytics.js'; +import { isUsingTypeScript } from '../../../shared/setup-utils.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), setTag: vi.fn(), @@ -19,7 +22,7 @@ vi.mock('@utils/analytics', () => ({ }, })); -vi.mock('@utils/setup-utils', () => ({ +vi.mock('../../../shared/setup-utils.js', () => ({ isUsingTypeScript: vi.fn(), tryGetPackageJson: vi.fn().mockResolvedValue(null), })); diff --git a/src/lib/programs/posthog-integration/constants.ts b/src/store/programs/posthog-integration/constants.ts similarity index 100% rename from src/lib/programs/posthog-integration/constants.ts rename to src/store/programs/posthog-integration/constants.ts diff --git a/src/lib/programs/posthog-integration/detect.ts b/src/store/programs/posthog-integration/detect.ts similarity index 94% rename from src/lib/programs/posthog-integration/detect.ts rename to src/store/programs/posthog-integration/detect.ts index f27faa6a9..bd12750f5 100644 --- a/src/lib/programs/posthog-integration/detect.ts +++ b/src/store/programs/posthog-integration/detect.ts @@ -9,29 +9,29 @@ * extracted here so the `integrate` subcommand can reuse it. */ -import type { ProgramReadyContext } from '@lib/programs/program-step'; +import type { ProgramReadyContext } from '../program-step.js'; import { DiscoveredFeature, mayReportScanResults, ScanConsent, type WizardSession, -} from '@lib/wizard-session'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; +} from '../../session/wizard-session.js'; +import { FRAMEWORK_REGISTRY } from '../../registry.js'; import { detectFramework, discoverFeatures, gatherFrameworkContext, checkFrameworkVersion, -} from '@lib/detection/index'; -import { analytics } from '@utils/analytics'; -import { detectWarehouseSources } from '@lib/warehouse-sources/detect'; -import { AI_SOURCE_KINDS } from '@lib/warehouse-sources/registry'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +} from '../../detection/index.js'; +import { analytics } from '../../shared/analytics.js'; +import { detectWarehouseSources } from '../../services/warehouse-sources/detect.js'; +import { AI_SOURCE_KINDS } from '../../services/warehouse-sources/registry.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; import { DETECTED_WAREHOUSE_SOURCES_KEY, getDetectedWarehouseSources, -} from '@lib/programs/warehouse-source/detect'; -import { findPackageJsons } from '@lib/programs/shared/package-scanning'; +} from '../warehouse-source/detect.js'; +import { findPackageJsons } from '../shared/package-scanning.js'; export async function detectPostHogIntegration( ctx: ProgramReadyContext, diff --git a/src/lib/programs/posthog-integration/handoff.ts b/src/store/programs/posthog-integration/handoff.ts similarity index 100% rename from src/lib/programs/posthog-integration/handoff.ts rename to src/store/programs/posthog-integration/handoff.ts diff --git a/src/lib/programs/posthog-integration/index.ts b/src/store/programs/posthog-integration/index.ts similarity index 92% rename from src/lib/programs/posthog-integration/index.ts rename to src/store/programs/posthog-integration/index.ts index bd78e52a5..fb3fb0786 100644 --- a/src/lib/programs/posthog-integration/index.ts +++ b/src/store/programs/posthog-integration/index.ts @@ -1,27 +1,37 @@ -import type { ProgramConfig, ProgramStep } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; -import type { WizardSession } from '@lib/wizard-session'; -import { mayReportScanResults, OutroKind, RunPhase } from '@lib/wizard-session'; -import { AgentSignals } from '@lib/agent-signals'; +import type { ProgramConfig, ProgramStep } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { + mayReportScanResults, + OutroKind, + RunPhase, +} from '../../session/wizard-session.js'; +import { AgentSignals } from '../../agent-protocol/agent-signals.js'; import { DEFAULT_PACKAGE_INSTALLATION, SPINNER_MESSAGE, -} from '@lib/framework-config'; -import { tryGetPackageJson, isUsingTypeScript } from '@utils/setup-utils'; -import { analytics } from '@utils/analytics'; -import { detectFramework, gatherFrameworkContext } from '@lib/detection/index'; -import { scopeInstallDirToProject } from '@lib/detection/project-scope'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { wizardAbort } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; -import { WIZARD_INTERACTION_EVENT_NAME } from '@lib/constants'; -import { getUI } from '@ui/index'; -import { requestDeepLink } from '@utils/provisioning'; -import { openTrackedLink, withUtm } from '@utils/links'; -import type { HostResolution } from '@lib/host-resolution'; -import { getDetectedWarehouseSources } from '@lib/programs/warehouse-source/detect'; -import { shouldDisableAsk } from '@lib/ask-policy'; +} from '../../framework-config.js'; +import { + tryGetPackageJson, + isUsingTypeScript, +} from '../../shared/setup-utils.js'; +import { analytics } from '../../shared/analytics.js'; +import { + detectFramework, + gatherFrameworkContext, +} from '../../detection/index.js'; +import { scopeInstallDirToProject } from '../../detection/project-scope.js'; +import { FRAMEWORK_REGISTRY } from '../../registry.js'; +import { wizardAbort } from '../../shared/wizard-abort.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; +import { WIZARD_INTERACTION_EVENT_NAME } from '../../shared/constants.js'; +import { getUI } from '../../ui/index.js'; +import { requestDeepLink } from '../../shared/provisioning.js'; +import { openTrackedLink, withUtm } from '../../shared/links.js'; +import type { HostResolution } from '../../host-resolution.js'; +import { getDetectedWarehouseSources } from '../warehouse-source/detect.js'; +import { shouldDisableAsk } from '../../session/ask-policy.js'; import { POSTHOG_INTEGRATION_PROGRAM } from './steps.js'; import { buildCodingAgentPrompt } from './handoff.js'; import { EVENT_PLAN_FILE } from './constants.js'; @@ -262,7 +272,9 @@ export const posthogIntegrationConfig: ProgramConfig = { installDir: session.installDir, }); if (packageJson) { - const { hasDeclaredDependency } = await import('@utils/package-json'); + const { hasDeclaredDependency } = await import( + '../../shared/package-json.js' + ); if (!hasDeclaredDependency(config.detection.packageName, packageJson)) { getUI().log.warn( `${config.detection.packageDisplayName} does not seem to be installed. Continuing anyway — the agent will handle it.`, @@ -373,7 +385,7 @@ ${warehouseReportInstruction(session)} ); if (config.environment.uploadToHosting) { const { uploadEnvironmentVariablesStep } = await import( - '@steps/index' + '../../services/steps/index.js' ); const uploadedEnvVars = await uploadEnvironmentVariablesStep( envVars, diff --git a/src/lib/programs/posthog-integration/steps.ts b/src/store/programs/posthog-integration/steps.ts similarity index 89% rename from src/lib/programs/posthog-integration/steps.ts rename to src/store/programs/posthog-integration/steps.ts index bc5adc3b0..df125ca7c 100644 --- a/src/lib/programs/posthog-integration/steps.ts +++ b/src/store/programs/posthog-integration/steps.ts @@ -6,10 +6,10 @@ * definitions — no hardcoded per-flow logic in the store. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; -import { RunPhase } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { RunPhase } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; import { detectPostHogIntegration } from './detect.js'; function needsSetup(session: WizardSession): boolean { diff --git a/src/lib/programs/posthog-integration/test/README.md b/src/store/programs/posthog-integration/test/README.md similarity index 100% rename from src/lib/programs/posthog-integration/test/README.md rename to src/store/programs/posthog-integration/test/README.md diff --git a/src/lib/programs/posthog-integration/test/e2e.json b/src/store/programs/posthog-integration/test/e2e.json similarity index 100% rename from src/lib/programs/posthog-integration/test/e2e.json rename to src/store/programs/posthog-integration/test/e2e.json diff --git a/src/lib/programs/program-registry.ts b/src/store/programs/program-registry.ts similarity index 99% rename from src/lib/programs/program-registry.ts rename to src/store/programs/program-registry.ts index 162c2436e..ee2849894 100644 --- a/src/lib/programs/program-registry.ts +++ b/src/store/programs/program-registry.ts @@ -11,7 +11,7 @@ */ import type { ProgramConfig } from './program-step.js'; -import { POSTHOG_DOCS_URL } from '../constants.js'; +import { POSTHOG_DOCS_URL } from '../shared/constants.js'; import { posthogIntegrationConfig } from './posthog-integration/index.js'; import { revenueAnalyticsConfig } from './revenue-analytics/index.js'; import { warehouseSourceConfig } from './warehouse-source/index.js'; diff --git a/src/lib/programs/program-step.ts b/src/store/programs/program-step.ts similarity index 97% rename from src/lib/programs/program-step.ts rename to src/store/programs/program-step.ts index 22c46ce51..c927daa33 100644 --- a/src/lib/programs/program-step.ts +++ b/src/store/programs/program-step.ts @@ -1,12 +1,12 @@ -import type { WizardSession } from '@lib/wizard-session'; +import type { WizardSession } from '../session/wizard-session.js'; import type { FlowStep, StoreInitContext, ProgramReadyContext, -} from '@lib/flow'; +} from '../state/flow.js'; export type { StoreInitContext, ProgramReadyContext }; -import type { ProgramRunConfig } from '@lib/program-run'; +import type { ProgramRunConfig } from '../agent-protocol/program-run.js'; // Type-only — erased at compile time, so no runtime cycle with the // registry that imports `ProgramConfig` back from this module. import type { ProgramId } from './program-registry.js'; diff --git a/src/lib/programs/replay-vision/index.ts b/src/store/programs/replay-vision/index.ts similarity index 90% rename from src/lib/programs/replay-vision/index.ts rename to src/store/programs/replay-vision/index.ts index 0bb2b0b2f..c077ca74f 100644 --- a/src/lib/programs/replay-vision/index.ts +++ b/src/store/programs/replay-vision/index.ts @@ -1,20 +1,23 @@ -import type { AbortCase } from '@lib/program-run'; -import { Integration } from '@lib/constants'; -import { detectFramework, gatherFrameworkContext } from '@lib/detection/index'; -import { scopeInstallDirToProject } from '@lib/detection/project-scope'; -import { FRAMEWORK_REGISTRY } from '@lib/registry'; -import { createSkillProgram } from '@lib/programs/agent-skill/index'; -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/steps'; -import { detectPostHogIntegration } from '@lib/programs/posthog-integration/detect'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { Integration } from '../../shared/constants.js'; +import { + detectFramework, + gatherFrameworkContext, +} from '../../detection/index.js'; +import { scopeInstallDirToProject } from '../../detection/project-scope.js'; +import { FRAMEWORK_REGISTRY } from '../../registry.js'; +import { createSkillProgram } from '../agent-skill/index.js'; +import { AGENT_SKILL_STEPS } from '../agent-skill/steps.js'; +import { detectPostHogIntegration } from '../posthog-integration/detect.js'; import type { ProgramConfig, ProgramReadyContext, ProgramStep, -} from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; -import { analytics } from '@utils/analytics'; -import { wizardAbort } from '@utils/wizard-abort'; -import { ErrorCodes } from '@lib/errors'; +} from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { analytics } from '../../shared/analytics.js'; +import { wizardAbort } from '../../shared/wizard-abort.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; const REPLAY_VISION_REPORT_FILE = 'posthog-replay-vision-report.md'; diff --git a/src/lib/programs/replay-vision/test/e2e.json b/src/store/programs/replay-vision/test/e2e.json similarity index 100% rename from src/lib/programs/replay-vision/test/e2e.json rename to src/store/programs/replay-vision/test/e2e.json diff --git a/src/lib/programs/revenue-analytics/detect.ts b/src/store/programs/revenue-analytics/detect.ts similarity index 94% rename from src/lib/programs/revenue-analytics/detect.ts rename to src/store/programs/revenue-analytics/detect.ts index 4fff50d25..58b114ada 100644 --- a/src/lib/programs/revenue-analytics/detect.ts +++ b/src/store/programs/revenue-analytics/detect.ts @@ -6,16 +6,16 @@ */ import { existsSync, statSync } from 'fs'; -import type { WizardSession } from '@lib/wizard-session'; -import type { AbortCase } from '@lib/program-run'; -import { findPackageJsons } from '@lib/programs/shared/package-scanning'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { findPackageJsons } from '../shared/package-scanning.js'; export { findPackageJsons, POSTHOG_SDKS, STRIPE_SDKS, type PackageMatch, -} from '@lib/programs/shared/package-scanning'; +} from '../shared/package-scanning.js'; /** * Structured detection errors. The screen renders each kind into JSX diff --git a/src/lib/programs/revenue-analytics/index.ts b/src/store/programs/revenue-analytics/index.ts similarity index 90% rename from src/lib/programs/revenue-analytics/index.ts rename to src/store/programs/revenue-analytics/index.ts index 6478bbd97..117a87ea0 100644 --- a/src/lib/programs/revenue-analytics/index.ts +++ b/src/store/programs/revenue-analytics/index.ts @@ -1,5 +1,5 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import { WIZARD_TOOL_NAMES } from '@lib/wizard-tools'; +import type { ProgramConfig } from '../program-step.js'; +import { WIZARD_TOOL_NAMES } from '../../tools/index.js'; import { REVENUE_ANALYTICS_PROGRAM } from './steps.js'; import { REVENUE_ABORT_CASES } from './detect.js'; diff --git a/src/lib/programs/revenue-analytics/steps.ts b/src/store/programs/revenue-analytics/steps.ts similarity index 88% rename from src/lib/programs/revenue-analytics/steps.ts rename to src/store/programs/revenue-analytics/steps.ts index 7e983ab9d..567b89be7 100644 --- a/src/lib/programs/revenue-analytics/steps.ts +++ b/src/store/programs/revenue-analytics/steps.ts @@ -5,9 +5,9 @@ * and agent run live in the program runner (see agent-runner.ts). */ -import type { ProgramStep } from '@lib/programs/program-step'; -import { RunPhase } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; +import type { ProgramStep } from '../program-step.js'; +import { RunPhase } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; import { detectRevenuePrerequisites } from './detect.js'; export const REVENUE_ANALYTICS_PROGRAM: ProgramStep[] = [ diff --git a/src/lib/programs/run-config.ts b/src/store/programs/run-config.ts similarity index 57% rename from src/lib/programs/run-config.ts rename to src/store/programs/run-config.ts index 0ddb1c8f5..0c69b0504 100644 --- a/src/lib/programs/run-config.ts +++ b/src/store/programs/run-config.ts @@ -1,4 +1,4 @@ -import type { ProgramRunConfig } from '@lib/program-run'; +import type { ProgramRunConfig } from '../agent-protocol/program-run.js'; import type { ProgramConfig, ProgramStep } from './program-step.js'; /** Gated step ids between the `auth` and the first `run` step, in order. */ @@ -12,10 +12,35 @@ export function postAuthGateIdsFor(steps: readonly ProgramStep[]): string[] { .map((s) => s.id); } -/** The run contract the agent receives for a program. */ +/** The run contract the agent receives for a program: nothing beyond it. */ export function runConfigFor(config: ProgramConfig): ProgramRunConfig { + const { + id, + run, + agentFlow, + skillId, + requiresAi, + seedTasks, + auditLedgerFile, + reportFile, + eventPlanFile, + streamWorkflowId, + allowedTools, + disallowedTools, + } = config; return { - ...config, + id, + run, + agentFlow, + skillId, + requiresAi, + seedTasks, + auditLedgerFile, + reportFile, + eventPlanFile, + streamWorkflowId, + allowedTools, + disallowedTools, postAuthGateIds: postAuthGateIdsFor(config.steps), healthCheckDeclared: config.steps.some( (s) => s.screenId === 'health-check', diff --git a/src/lib/programs/self-driving/ARCHITECTURE.md b/src/store/programs/self-driving/ARCHITECTURE.md similarity index 97% rename from src/lib/programs/self-driving/ARCHITECTURE.md rename to src/store/programs/self-driving/ARCHITECTURE.md index 96408a2d0..a4fcccf70 100644 --- a/src/lib/programs/self-driving/ARCHITECTURE.md +++ b/src/store/programs/self-driving/ARCHITECTURE.md @@ -22,11 +22,11 @@ anchors are point-in-time — the symbol names are the durable part. | Need | Go to | | -------------------------------------- | ---------------------------------------------------------- | -| The ordered steps | `src/lib/programs/self-driving/prompt.ts` | +| The ordered steps | `src/store/programs/self-driving/prompt.ts` | | What each step _does_ | `context-mill/context/skills/self-driving/references/*.md` | -| Program registration / lifecycle | `src/lib/programs/self-driving/index.ts` | -| `wizard_ask` / `.env` tools | `src/lib/wizard-tools.ts`, `src/lib/wizard-ask-bridge.ts` | -| OAuth scopes (+ prod ceiling) | `src/lib/oauth/program-scopes.ts` (§3, §7) | +| Program registration / lifecycle | `src/store/programs/self-driving/index.ts` | +| `wizard_ask` / `.env` tools | `src/store/tools/tools.ts`, `src/store/session/wizard-ask-bridge.ts` | +| OAuth scopes (+ prod ceiling) | `src/store/services/oauth/program-scopes.ts` (§3, §7) | | Signals models / MCP / sync | `posthog/products/signals/backend/…` (§5) | | Why a team gets no findings | §6 | | What to change for prod | §7 | @@ -146,7 +146,7 @@ repos. ## 3. Wizard internals -**Program definition** (`src/lib/programs/self-driving/`, five files): +**Program definition** (`src/store/programs/self-driving/`, five files): `index.ts` (config + lifecycle), `prompt.ts` (the 10 steps + mechanics + project URLs), `detect.ts` (prerequisite check + abort vocabulary), `steps.ts` (TUI screen sequence `detect → intro → health-check → auth → self-driving-github → @@ -155,7 +155,7 @@ run → outro`), and sources + scouts + scanners in plain language, wired via `getTips`; `RunScreen` falls back to `DEFAULT_TIPS` for every other program, so nothing else is affected). `selfDrivingConfig` is built from the `createSkillProgram` factory -(`src/lib/programs/agent-skill/`) with overrides. Notables in `index.ts`: +(`src/store/programs/agent-skill/`) with overrides. Notables in `index.ts`: `SELF_DRIVING_SKILL_ID = 'self-driving-setup'`, `REPORT_FILE = 'posthog-self-driving-report.md'`, `maxQuestions: 13` (tracker picks + custom-scout proposal), `richLinks: true` (OSC-8 links so long @@ -163,14 +163,14 @@ OAuth URLs survive wrapping), and `postRun` (just `removeInstalledSkill` — the setup skill is transient, marker-guarded by `.posthog-wizard`, so there's no keep-skills step). The outro inbox URL is the clean `…/project/:id/inbox` built in `buildOutroData` (no auth deep-link — §7 item 7). CLI: -`src/commands/self-driving.ts`; `--install-dir` becomes `session.installDir` +`src/cli/commands/self-driving.ts`; `--install-dir` becomes `session.installDir` (the agent's working dir and detection target). **Runner & agent loop (generic — not Signals-aware).** `runProgram` -(`src/lib/agent/agent-runner.ts`) is the fixed pipeline +(`src/agent/runner/index.ts`) is the fixed pipeline `init → health → settings → OAuth → skill install → agent → run → errors → postRun → outro`. It installs the skill by ID, resolves the MCP URL, runs the Claude Agent SDK -`query()` (`src/lib/agent/agent-interface.ts`) in a sandbox with the +`query()` (`src/agent/agent-interface.ts`) in a sandbox with the `posthog-wizard` + `wizard-tools` MCP servers, and parses agent output: `[STATUS]` → UI, `[ABORT] ` → terminal `AgentErrorType.ABORT` matched against `config.abortCases`. `PromptContext` (project/host + AI-consent @@ -179,7 +179,7 @@ against `config.abortCases`. `PromptContext` (project/host + AI-consent `buildSelfDrivingPrompt`. Anything deeper here is generic machinery — read those two files directly. -**`wizard-tools` MCP + `wizard_ask`** (`src/lib/wizard-tools.ts`). +**`wizard-tools` MCP + `wizard_ask`** (`src/store/tools/tools.ts`). `check_env_keys` / `set_env_values` are the only sanctioned `.env` access (value-safe, `.gitignore`-guarded, secret-vault aware). `wizard_ask` is the **only** way to ask the user anything — 1–8 questions, capped at `maxQuestions` @@ -196,12 +196,12 @@ A multi-select's default focus is its first enabled option and an empty `enter` submits that focused option — which is why a **decline option, when present, is placed first** (it becomes the safe default). No bridge (CI/non-interactive) → returns an error telling the agent to default or emit -`[ABORT] requires-interactive-mode`. The bridge (`src/lib/wizard-ask-bridge.ts`) +`[ABORT] requires-interactive-mode`. The bridge (`src/store/session/wizard-ask-bridge.ts`) brokers into the TUI overlay; cancelled/timed-out fields resolve to `CANCELLED_SENTINEL = '__cancelled__'`. -**OAuth scopes** (`src/lib/oauth/program-scopes.ts`). Base `WIZARD_OAUTH_SCOPES` -(`src/lib/constants.ts`) ∪ `SELF_DRIVING_SCOPE_ADDITIONS` — **12 strings**, +**OAuth scopes** (`src/store/services/oauth/program-scopes.ts`). Base `WIZARD_OAUTH_SCOPES` +(`src/store/shared/constants.ts`) ∪ `SELF_DRIVING_SCOPE_ADDITIONS` — **12 strings**, requested via a PKCE auth-code flow: | Scope | Why | @@ -226,7 +226,7 @@ requests none. (An *exhaustive* ceiling — no `@default` — is possible and wo reject anything unlisted, but the wizard apps aren't configured that way.) See §7 item 1 and the README's "OAuth app scope ceiling". -**Security & TUI.** YARA hooks (`src/lib/yara-hooks.ts`) scan +**Security & TUI.** YARA hooks (`src/store/security/yara-hooks.ts`) scan Bash/Write/Edit/Read content and installed skills via the `warlock` scanner (fail-closed; categories: prompt injection, exfiltration, destructive ops, supply-chain, secrets, PII); a critical match aborts the run. New rules go in @@ -260,7 +260,7 @@ The canonical `signals-scout-*` skills do **not** live here — they're in posth hot-rebuilds individual skill zips but **not** the bundle. Release: a PR to `main` with the **`mcp-publish`** label builds and force-moves the `latest` GitHub release tag. The wizard resolves the skill ID at runtime against - `getSkillsBaseUrl(localMcp)` (`src/lib/constants.ts`): + `getSkillsBaseUrl(localMcp)` (`src/store/shared/constants.ts`): `…/releases/latest/download` (prod) or `localhost:8765` (`--local-mcp`) — so skill content is decoupled from the wizard npm release (and a prod wizard is broken until the skill is published to `latest`; §7). @@ -358,7 +358,7 @@ source is enabled. > and the `[ABORT] self-driving is not available for this project` path is now > only a safety net for a genuine Signals-API outage. -1. **UI flag `product-autonomy`** (`posthog/frontend/src/lib/constants.tsx`, +1. **UI flag `product-autonomy`** (`posthog/frontend/src/store/shared/constants.ts`, `FEATURE_FLAGS.PRODUCT_AUTONOMY`). Frontend-only — gates the Inbox scene, nav item, and source-config loading. Off → the user can't _see_ the inbox; the pipeline is unaffected. @@ -374,7 +374,7 @@ source is enabled. (`posthog/models/organization.py`, default `True`, nullable; admin toggle at `/settings/organization#organization-ai-consent`). Fail-closed; without it findings are silently dropped. Enforced for this program by the **base - wizard's AI opt-in gate** (`src/lib/programs/ai-opt-in-gate.ts`, + wizard's AI opt-in gate** (`src/store/programs/ai-opt-in-gate.ts`, `withAiOptInGate`): it injects an `ai-opt-in` step after `auth` for every program that doesn't set `requiresAi: false` (self-driving doesn't), and `store.getGate('ai-opt-in')` parks the agent until approval lands — so the @@ -479,7 +479,7 @@ must be running, or no scout ever dispatches. > (`self-driving` — so the `programLabel` shown in the intro/exit reads > `self-driving`), the `program-scopes.ts` map key, the `self-driving/` > dir + `SELF_DRIVING_*` constants + `SelfDriving*` types / components, -> `src/commands/self-driving.ts` + `selfDrivingCommand`, the screen id +> `src/cli/commands/self-driving.ts` + `selfDrivingCommand`, the screen id > `self-driving-intro`, every user-facing string (intro copy, > success/outro/spinner messages, `detect.ts` abort `message`/`body`, > prompt header + task labels), and the report filename diff --git a/src/lib/programs/self-driving/__tests__/step-keys.test.ts b/src/store/programs/self-driving/__tests__/step-keys.test.ts similarity index 100% rename from src/lib/programs/self-driving/__tests__/step-keys.test.ts rename to src/store/programs/self-driving/__tests__/step-keys.test.ts diff --git a/src/lib/programs/self-driving/detect-agentic.ts b/src/store/programs/self-driving/detect-agentic.ts similarity index 93% rename from src/lib/programs/self-driving/detect-agentic.ts rename to src/store/programs/self-driving/detect-agentic.ts index ddb416941..8429a6b1c 100644 --- a/src/lib/programs/self-driving/detect-agentic.ts +++ b/src/store/programs/self-driving/detect-agentic.ts @@ -14,14 +14,14 @@ import type { AgenticDetectionReport, DetectEvent, -} from '@lib/detection/agentic'; +} from '../../detection/agentic.js'; import { detectIntegrationProjects, toIntegrationCandidates, -} from '@lib/detection/project-scope'; -import { gatherFrameworkContext } from '@lib/detection/index'; -import type { Integration } from '@lib/constants'; -import type { WizardSession } from '@lib/wizard-session'; +} from '../../detection/project-scope.js'; +import { gatherFrameworkContext } from '../../detection/index.js'; +import type { Integration } from '../../shared/constants.js'; +import type { WizardSession } from '../../session/wizard-session.js'; export type { DetectEvent }; diff --git a/src/lib/programs/self-driving/detect.ts b/src/store/programs/self-driving/detect.ts similarity index 96% rename from src/lib/programs/self-driving/detect.ts rename to src/store/programs/self-driving/detect.ts index 94e30c33e..cc50e7db7 100644 --- a/src/lib/programs/self-driving/detect.ts +++ b/src/store/programs/self-driving/detect.ts @@ -27,12 +27,12 @@ import { type Dirent, } from 'fs'; import { join } from 'path'; -import { analytics } from '@utils/analytics'; -import type { WizardSession } from '@lib/wizard-session'; -import type { AbortCase } from '@lib/program-run'; -import { ErrorCodes } from '@lib/errors'; -import { detectWarehouseSources } from '@lib/warehouse-sources/detect'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import { analytics } from '../../shared/analytics.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; +import { detectWarehouseSources } from '../../services/warehouse-sources/detect.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; /** frameworkContext key holding the deterministic PostHog-presence result. */ export const POSTHOG_PRESENT_KEY = 'postHogPresent'; diff --git a/src/lib/programs/self-driving/index.ts b/src/store/programs/self-driving/index.ts similarity index 94% rename from src/lib/programs/self-driving/index.ts rename to src/store/programs/self-driving/index.ts index b0fd3b1f6..28b5361d0 100644 --- a/src/lib/programs/self-driving/index.ts +++ b/src/store/programs/self-driving/index.ts @@ -1,8 +1,8 @@ import { join } from 'path'; import { access, rm } from 'node:fs/promises'; -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import { OutroKind, type WizardSession } from '@lib/wizard-session'; +import type { ProgramConfig } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import { OutroKind, type WizardSession } from '../../session/wizard-session.js'; import { createSkillProgram } from '../agent-skill/index.js'; import { SELF_DRIVING_PROGRAM } from './steps.js'; import { @@ -11,11 +11,7 @@ import { } from './detect.js'; import { buildSelfDrivingPrompt } from './prompt.js'; import { resolveSelfDrivingStepKey } from './step-keys.js'; -import { - NO_DEFAULT_LIMIT, - PRICE_PER_PR_USD, - PRICING_LONG, -} from '@ui/tui/programs/self-driving/content/pricing.js'; +import { NO_DEFAULT_LIMIT, PRICE_PER_PR_USD, PRICING_LONG } from './pricing.js'; export const SELF_DRIVING_SKILL_ID = 'self-driving-setup'; const REPORT_FILE = 'posthog-self-driving-report.md'; diff --git a/src/ui/tui/programs/self-driving/content/pricing.ts b/src/store/programs/self-driving/pricing.ts similarity index 100% rename from src/ui/tui/programs/self-driving/content/pricing.ts rename to src/store/programs/self-driving/pricing.ts diff --git a/src/lib/programs/self-driving/prompt.ts b/src/store/programs/self-driving/prompt.ts similarity index 98% rename from src/lib/programs/self-driving/prompt.ts rename to src/store/programs/self-driving/prompt.ts index 07033c4d0..df79d8a5c 100644 --- a/src/lib/programs/self-driving/prompt.ts +++ b/src/store/programs/self-driving/prompt.ts @@ -1,6 +1,6 @@ -import { AgentSignals } from '@lib/agent-signals'; -import type { PromptContext } from '@lib/program-run'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import { AgentSignals } from '../../agent-protocol/agent-signals.js'; +import type { PromptContext } from '../../agent-protocol/program-run.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; /** * Render the deterministic codebase-tool scan for the prompt. STEP 4 and diff --git a/src/lib/programs/self-driving/step-keys.ts b/src/store/programs/self-driving/step-keys.ts similarity index 100% rename from src/lib/programs/self-driving/step-keys.ts rename to src/store/programs/self-driving/step-keys.ts diff --git a/src/lib/programs/self-driving/steps.ts b/src/store/programs/self-driving/steps.ts similarity index 94% rename from src/lib/programs/self-driving/steps.ts rename to src/store/programs/self-driving/steps.ts index 4eeceb5d4..c30cd89bb 100644 --- a/src/lib/programs/self-driving/steps.ts +++ b/src/store/programs/self-driving/steps.ts @@ -14,11 +14,11 @@ * gates on the GitHub App connection the run cannot proceed without. No keep-skills step: the setup skill is transient, so postRun removes it. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import { resolveProjectDir } from '@lib/detection/agentic'; -import { RunPhase, type WizardSession } from '@lib/wizard-session'; -import { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step'; -import { integrationRunStep } from '@lib/programs/posthog-integration/index'; +import type { ProgramStep } from '../program-step.js'; +import { resolveProjectDir } from '../../detection/agentic.js'; +import { RunPhase, type WizardSession } from '../../session/wizard-session.js'; +import { HEALTH_CHECK_STEP } from '../shared/health-check-step.js'; +import { integrationRunStep } from '../posthog-integration/index.js'; import { detectSelfDrivingPrerequisites, POSTHOG_PRESENT_KEY, diff --git a/src/lib/programs/self-driving/test/e2e.json b/src/store/programs/self-driving/test/e2e.json similarity index 100% rename from src/lib/programs/self-driving/test/e2e.json rename to src/store/programs/self-driving/test/e2e.json diff --git a/src/lib/programs/shared/health-check-step.ts b/src/store/programs/shared/health-check-step.ts similarity index 89% rename from src/lib/programs/shared/health-check-step.ts rename to src/store/programs/shared/health-check-step.ts index 1c630a52c..53da9b47d 100644 --- a/src/lib/programs/shared/health-check-step.ts +++ b/src/store/programs/shared/health-check-step.ts @@ -11,15 +11,15 @@ * render the OutroScreen. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import type { WizardSession } from '@lib/wizard-session'; +import type { ProgramStep } from '../program-step.js'; +import type { WizardSession } from '../../session/wizard-session.js'; import { evaluateWizardReadiness, WizardReadiness, SIGNUP_WIZARD_READINESS_CONFIG, getBlockingServiceKeys, -} from '@lib/health-checks/readiness'; -import { logToFile } from '@utils/debug'; +} from '../../health-checks/readiness.js'; +import { logToFile } from '../../shared/debug.js'; export function healthCheckReady(session: WizardSession): boolean { if (!session.readinessResult) return false; diff --git a/src/lib/programs/shared/package-scanning.ts b/src/store/programs/shared/package-scanning.ts similarity index 95% rename from src/lib/programs/shared/package-scanning.ts rename to src/store/programs/shared/package-scanning.ts index 3b399edf0..5f06769fb 100644 --- a/src/lib/programs/shared/package-scanning.ts +++ b/src/store/programs/shared/package-scanning.ts @@ -1,5 +1,5 @@ import { relative } from 'path'; -import { safeReadFile, walkProjectFiles } from '@utils/bounded-fs'; +import { safeReadFile, walkProjectFiles } from '../../shared/bounded-fs.js'; export const POSTHOG_SDKS = new Set([ 'posthog-js', diff --git a/src/lib/programs/shared/posthog-cli-preinstall.ts b/src/store/programs/shared/posthog-cli-preinstall.ts similarity index 87% rename from src/lib/programs/shared/posthog-cli-preinstall.ts rename to src/store/programs/shared/posthog-cli-preinstall.ts index 865a25a9f..9993709b6 100644 --- a/src/lib/programs/shared/posthog-cli-preinstall.ts +++ b/src/store/programs/shared/posthog-cli-preinstall.ts @@ -8,9 +8,9 @@ * needs the CLI. */ -import { installOrUpdatePostHogCli } from '@steps/install-cli-steering'; -import { getUI } from '@ui'; -import { analytics } from '@utils/analytics'; +import { installOrUpdatePostHogCli } from '../../services/steps/install-cli-steering/index.js'; +import { getUI } from '../../ui/index.js'; +import { analytics } from '../../shared/analytics.js'; let attempted = false; diff --git a/src/lib/programs/slack/index.ts b/src/store/programs/slack/index.ts similarity index 91% rename from src/lib/programs/slack/index.ts rename to src/store/programs/slack/index.ts index 43823ef7d..ca3d5e0ef 100644 --- a/src/lib/programs/slack/index.ts +++ b/src/store/programs/slack/index.ts @@ -6,7 +6,7 @@ * happens in the browser, so a wizard login adds nothing for the user. */ -import type { ProgramConfig } from '@lib/programs/program-step'; +import type { ProgramConfig } from '../program-step.js'; export const slackConnectConfig: ProgramConfig = { id: 'slack', diff --git a/src/lib/programs/warehouse-source/detect.ts b/src/store/programs/warehouse-source/detect.ts similarity index 91% rename from src/lib/programs/warehouse-source/detect.ts rename to src/store/programs/warehouse-source/detect.ts index d6c6bc490..5e05bb1dc 100644 --- a/src/lib/programs/warehouse-source/detect.ts +++ b/src/store/programs/warehouse-source/detect.ts @@ -7,11 +7,11 @@ */ import { existsSync, statSync } from 'fs'; -import { analytics } from '@utils/analytics'; -import type { WizardSession } from '@lib/wizard-session'; -import type { AbortCase } from '@lib/program-run'; -import { detectWarehouseSources } from '@lib/warehouse-sources/detect'; -import type { DetectedSource } from '@lib/warehouse-sources/types'; +import { analytics } from '../../shared/analytics.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { detectWarehouseSources } from '../../services/warehouse-sources/detect.js'; +import type { DetectedSource } from '../../services/warehouse-sources/types.js'; /** Structured detection errors rendered by the intro screen. */ export type WarehouseDetectError = diff --git a/src/lib/programs/warehouse-source/index.ts b/src/store/programs/warehouse-source/index.ts similarity index 91% rename from src/lib/programs/warehouse-source/index.ts rename to src/store/programs/warehouse-source/index.ts index e98fc420f..76d007aa5 100644 --- a/src/lib/programs/warehouse-source/index.ts +++ b/src/store/programs/warehouse-source/index.ts @@ -1,7 +1,7 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; -import type { ProgramRun } from '@lib/program-run'; -import type { WizardSession } from '@lib/wizard-session'; -import { LONGER_ASK_TIMEOUT_MS } from '@lib/wizard-ask-bridge'; +import type { ProgramConfig } from '../program-step.js'; +import type { ProgramRun } from '../../agent-protocol/program-run.js'; +import type { WizardSession } from '../../session/wizard-session.js'; +import { LONGER_ASK_TIMEOUT_MS } from '../../session/wizard-ask-bridge.js'; import { WAREHOUSE_SOURCE_PROGRAM } from './steps.js'; import { WAREHOUSE_ABORT_CASES, diff --git a/src/lib/programs/warehouse-source/steps.ts b/src/store/programs/warehouse-source/steps.ts similarity index 92% rename from src/lib/programs/warehouse-source/steps.ts rename to src/store/programs/warehouse-source/steps.ts index 1a64bfebd..535032bba 100644 --- a/src/lib/programs/warehouse-source/steps.ts +++ b/src/store/programs/warehouse-source/steps.ts @@ -6,8 +6,8 @@ * both in-CLI source creation and deep-link emission per detected source. */ -import type { ProgramStep } from '@lib/programs/program-step'; -import { RunPhase } from '@lib/wizard-session'; +import type { ProgramStep } from '../program-step.js'; +import { RunPhase } from '../../session/wizard-session.js'; import { detectWarehousePrerequisites } from './detect.js'; export const WAREHOUSE_SOURCE_PROGRAM: ProgramStep[] = [ diff --git a/src/lib/programs/warehouse-source/test/e2e.json b/src/store/programs/warehouse-source/test/e2e.json similarity index 100% rename from src/lib/programs/warehouse-source/test/e2e.json rename to src/store/programs/warehouse-source/test/e2e.json diff --git a/src/lib/programs/web-analytics-doctor/detect.ts b/src/store/programs/web-analytics-doctor/detect.ts similarity index 90% rename from src/lib/programs/web-analytics-doctor/detect.ts rename to src/store/programs/web-analytics-doctor/detect.ts index 10f037282..3778a70e2 100644 --- a/src/lib/programs/web-analytics-doctor/detect.ts +++ b/src/store/programs/web-analytics-doctor/detect.ts @@ -1,8 +1,8 @@ import { existsSync, statSync } from 'fs'; -import type { WizardSession } from '@lib/wizard-session'; -import type { AbortCase } from '@lib/program-run'; -import { ErrorCodes } from '@lib/errors'; -import { findPackageJsons } from '@lib/programs/shared/package-scanning'; +import type { WizardSession } from '../../session/wizard-session.js'; +import type { AbortCase } from '../../agent-protocol/program-run.js'; +import { ErrorCodes } from '../../shared/errors/index.js'; +import { findPackageJsons } from '../shared/package-scanning.js'; export type WebAnalyticsDetectError = | { diff --git a/src/lib/programs/web-analytics-doctor/index.ts b/src/store/programs/web-analytics-doctor/index.ts similarity index 96% rename from src/lib/programs/web-analytics-doctor/index.ts rename to src/store/programs/web-analytics-doctor/index.ts index ee360dd0e..1a482dd24 100644 --- a/src/lib/programs/web-analytics-doctor/index.ts +++ b/src/store/programs/web-analytics-doctor/index.ts @@ -1,4 +1,4 @@ -import type { ProgramConfig } from '@lib/programs/program-step'; +import type { ProgramConfig } from '../program-step.js'; import { createSkillProgram } from '../agent-skill/index.js'; import { WEB_ANALYTICS_DOCTOR_PROGRAM } from './steps.js'; import { WEB_ANALYTICS_ABORT_CASES } from './detect.js'; diff --git a/src/lib/programs/web-analytics-doctor/steps.ts b/src/store/programs/web-analytics-doctor/steps.ts similarity index 70% rename from src/lib/programs/web-analytics-doctor/steps.ts rename to src/store/programs/web-analytics-doctor/steps.ts index 941b58a9d..4a717cf9f 100644 --- a/src/lib/programs/web-analytics-doctor/steps.ts +++ b/src/store/programs/web-analytics-doctor/steps.ts @@ -1,5 +1,5 @@ -import type { ProgramStep } from '@lib/programs/program-step'; -import { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/steps'; +import type { ProgramStep } from '../program-step.js'; +import { AGENT_SKILL_STEPS } from '../agent-skill/steps.js'; import { detectWebAnalyticsPrerequisites } from './detect.js'; export const WEB_ANALYTICS_DOCTOR_PROGRAM: ProgramStep[] = [ diff --git a/src/store/registry.ts b/src/store/registry.ts new file mode 100644 index 000000000..c7ed52aa9 --- /dev/null +++ b/src/store/registry.ts @@ -0,0 +1,59 @@ +import type { FrameworkConfig } from './framework-config.js'; +import { Integration } from './shared/constants.js'; +import { NEXTJS_AGENT_CONFIG } from './frameworks/nextjs/nextjs-wizard-agent.js'; +import { NUXT_AGENT_CONFIG } from './frameworks/nuxt/nuxt-wizard-agent.js'; +import { VUE_AGENT_CONFIG } from './frameworks/vue/vue-wizard-agent.js'; +import { REACT_ROUTER_AGENT_CONFIG } from './frameworks/react-router/react-router-wizard-agent.js'; +import { TANSTACK_ROUTER_AGENT_CONFIG } from './frameworks/tanstack-router/tanstack-router-wizard-agent.js'; +import { TANSTACK_START_AGENT_CONFIG } from './frameworks/tanstack-start/tanstack-start-wizard-agent.js'; +import { REACT_NATIVE_AGENT_CONFIG } from './frameworks/react-native/react-native-wizard-agent.js'; +import { ANGULAR_AGENT_CONFIG } from './frameworks/angular/angular-wizard-agent.js'; +import { ASTRO_AGENT_CONFIG } from './frameworks/astro/astro-wizard-agent.js'; +import { DJANGO_AGENT_CONFIG } from './frameworks/django/django-wizard-agent.js'; +import { FLASK_AGENT_CONFIG } from './frameworks/flask/flask-wizard-agent.js'; +import { FASTAPI_AGENT_CONFIG } from './frameworks/fastapi/fastapi-wizard-agent.js'; +import { LARAVEL_AGENT_CONFIG } from './frameworks/laravel/laravel-wizard-agent.js'; +import { SVELTEKIT_AGENT_CONFIG } from './frameworks/svelte/svelte-wizard-agent.js'; +import { FLUTTER_AGENT_CONFIG } from './frameworks/flutter/flutter-wizard-agent.js'; +import { SWIFT_AGENT_CONFIG } from './frameworks/swift/swift-wizard-agent.js'; +import { KMP_AGENT_CONFIG } from './frameworks/kmp/kmp-wizard-agent.js'; +import { ANDROID_AGENT_CONFIG } from './frameworks/android/android-wizard-agent.js'; +import { RAILS_AGENT_CONFIG } from './frameworks/rails/rails-wizard-agent.js'; +import { ELIXIR_AGENT_CONFIG } from './frameworks/elixir/elixir-wizard-agent.js'; +import { GO_AGENT_CONFIG } from './frameworks/go/go-wizard-agent.js'; +import { JAVA_AGENT_CONFIG } from './frameworks/java/java-wizard-agent.js'; +import { RUST_AGENT_CONFIG } from './frameworks/rust/rust-wizard-agent.js'; +import { PYTHON_AGENT_CONFIG } from './frameworks/python/python-wizard-agent.js'; +import { RUBY_AGENT_CONFIG } from './frameworks/ruby/ruby-wizard-agent.js'; +import { JAVASCRIPT_NODE_AGENT_CONFIG } from './frameworks/javascript-node/javascript-node-wizard-agent.js'; +import { JAVASCRIPT_WEB_AGENT_CONFIG } from './frameworks/javascript-web/javascript-web-wizard-agent.js'; + +export const FRAMEWORK_REGISTRY: Record = { + [Integration.nextjs]: NEXTJS_AGENT_CONFIG, + [Integration.nuxt]: NUXT_AGENT_CONFIG, + [Integration.vue]: VUE_AGENT_CONFIG, + [Integration.tanstackStart]: TANSTACK_START_AGENT_CONFIG, + [Integration.reactRouter]: REACT_ROUTER_AGENT_CONFIG, + [Integration.tanstackRouter]: TANSTACK_ROUTER_AGENT_CONFIG, + [Integration.reactNative]: REACT_NATIVE_AGENT_CONFIG, + [Integration.angular]: ANGULAR_AGENT_CONFIG, + [Integration.astro]: ASTRO_AGENT_CONFIG, + [Integration.django]: DJANGO_AGENT_CONFIG, + [Integration.flask]: FLASK_AGENT_CONFIG, + [Integration.fastapi]: FASTAPI_AGENT_CONFIG, + [Integration.laravel]: LARAVEL_AGENT_CONFIG, + [Integration.sveltekit]: SVELTEKIT_AGENT_CONFIG, + [Integration.flutter]: FLUTTER_AGENT_CONFIG, + [Integration.kmp]: KMP_AGENT_CONFIG, + [Integration.swift]: SWIFT_AGENT_CONFIG, + [Integration.android]: ANDROID_AGENT_CONFIG, + [Integration.rails]: RAILS_AGENT_CONFIG, + [Integration.elixir]: ELIXIR_AGENT_CONFIG, + [Integration.go]: GO_AGENT_CONFIG, + [Integration.rust]: RUST_AGENT_CONFIG, + [Integration.java]: JAVA_AGENT_CONFIG, + [Integration.python]: PYTHON_AGENT_CONFIG, + [Integration.ruby]: RUBY_AGENT_CONFIG, + [Integration.javascriptNode]: JAVASCRIPT_NODE_AGENT_CONFIG, + [Integration.javascript_web]: JAVASCRIPT_WEB_AGENT_CONFIG, +}; diff --git a/src/lib/safe-tools.ts b/src/store/safe-tools.ts similarity index 100% rename from src/lib/safe-tools.ts rename to src/store/safe-tools.ts diff --git a/src/lib/__tests__/yara-hooks.test.ts b/src/store/security/__tests__/yara-hooks.test.ts similarity index 99% rename from src/lib/__tests__/yara-hooks.test.ts rename to src/store/security/__tests__/yara-hooks.test.ts index c5167d547..e26ee3ffe 100644 --- a/src/lib/__tests__/yara-hooks.test.ts +++ b/src/store/security/__tests__/yara-hooks.test.ts @@ -8,20 +8,20 @@ import { captureScanReport, recordExternalScan, resetScanReport, -} from '@lib/yara-hooks'; +} from '../yara-hooks.js'; import { scan, triageMatches } from '@posthog/warlock'; import fs from 'fs'; import fg from 'fast-glob'; -import * as analyticsModule from '../../utils/analytics'; +import * as analyticsModule from '../../shared/analytics.js'; // Mock dependencies -vi.mock('../../utils/debug'); -vi.mock('../../utils/analytics'); +vi.mock('../../shared/debug.js'); +vi.mock('../../shared/analytics.js'); vi.mock('fs'); vi.mock('fast-glob'); // Mock isSkillInstallCommand from skill-install (extracted to break circular dep) -vi.mock('../skill-install', () => ({ +vi.mock('../../skill-install.js', () => ({ isSkillInstallCommand: (command: string) => command.startsWith('mkdir -p .claude/skills/') && command.includes('curl -sL') && diff --git a/src/lib/__tests__/yara-policy.test.ts b/src/store/security/__tests__/yara-policy.test.ts similarity index 99% rename from src/lib/__tests__/yara-policy.test.ts rename to src/store/security/__tests__/yara-policy.test.ts index 33b725f34..63ea692c6 100644 --- a/src/lib/__tests__/yara-policy.test.ts +++ b/src/store/security/__tests__/yara-policy.test.ts @@ -4,7 +4,7 @@ import { isTerminalMatch, publishBlockingMatch, scanVerdict, -} from '../yara-policy'; +} from '../yara-policy.js'; function match( severity: string, diff --git a/src/lib/yara-hooks.ts b/src/store/security/yara-hooks.ts similarity index 98% rename from src/lib/yara-hooks.ts rename to src/store/security/yara-hooks.ts index 3ec2cb266..c648a615a 100644 --- a/src/lib/yara-hooks.ts +++ b/src/store/security/yara-hooks.ts @@ -32,19 +32,19 @@ import type { LLMProvider, Category, } from '@posthog/warlock'; -import { logToFile } from '@utils/debug'; -import { readFileHead } from '@utils/bounded-fs'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; -import type { WizardSession } from '@lib/wizard-session'; -import { isSkillInstallCommand } from './skill-install'; +import { logToFile } from '../shared/debug.js'; +import { readFileHead } from '../shared/bounded-fs.js'; +import { analytics } from '../shared/analytics.js'; +import { getUI } from '../ui/index.js'; +import type { WizardSession } from '../session/wizard-session.js'; +import { isSkillInstallCommand } from '../skill-install.js'; import { highestSeverityMatch, publishBlockingMatch, scanVerdict, -} from './yara-policy'; -import type { ScanAction, ScanContext } from './yara-policy'; -import { WIZARD_YARA_REPORT_FILE } from '@utils/paths'; +} from './yara-policy.js'; +import type { ScanAction, ScanContext } from './yara-policy.js'; +import { WIZARD_YARA_REPORT_FILE } from '../shared/paths.js'; // TODO(wizard#594): invert this dependency. // L2 infra (yara-hooks) imports product-specific filename constants from // individual programs. The leaf `constants.ts` modules break the *import* @@ -58,9 +58,9 @@ import { SETUP_REPORT_FILE as EVENTS_AUDIT_REPORT_FILE, EVENT_INVENTORY_FILE, EVENT_INVENTORY_PART_PATTERN, -} from '@lib/programs/events-audit/constants'; -import { AUDIT_REPORT_FILE } from '@lib/programs/audit/types'; -import { EVENT_PLAN_FILE } from '@lib/programs/posthog-integration/constants'; +} from '../programs/events-audit/constants.js'; +import { AUDIT_REPORT_FILE } from '../programs/audit/types.js'; +import { EVENT_PLAN_FILE } from '../programs/posthog-integration/constants.js'; // ─── Warlock module accessor ───────────────────────────────────── // Warlock is ESM-only and lazily inits its WASM engine + compiles rules on the @@ -120,7 +120,7 @@ export interface HookCallbackMatcher { timeout?: number; } -export type { ScanAction, ScanContext } from './yara-policy'; +export type { ScanAction, ScanContext } from './yara-policy.js'; // ─── Scan Report Accumulator ───────────────────────────────────── diff --git a/src/lib/yara-policy.ts b/src/store/security/yara-policy.ts similarity index 100% rename from src/lib/yara-policy.ts rename to src/store/security/yara-policy.ts diff --git a/src/lib/agent/runner/shared/__tests__/refresh-access-token-if-needed.test.ts b/src/store/services/__tests__/refresh-access-token-if-needed.test.ts similarity index 88% rename from src/lib/agent/runner/shared/__tests__/refresh-access-token-if-needed.test.ts rename to src/store/services/__tests__/refresh-access-token-if-needed.test.ts index 5138af7cb..11d1a6f49 100644 --- a/src/lib/agent/runner/shared/__tests__/refresh-access-token-if-needed.test.ts +++ b/src/store/services/__tests__/refresh-access-token-if-needed.test.ts @@ -1,18 +1,24 @@ -import { refreshAccessTokenIfNeeded } from '../authenticate'; -import { refreshAccessToken } from '@utils/oauth'; -import { OAuthError } from '@utils/oauth-errors'; -import { isGrantRevoked, resetAuthSessionState } from '@lib/auth-session-state'; -import type { WizardSession, Credentials } from '@lib/wizard-session'; - -vi.mock('@utils/oauth', () => ({ refreshAccessToken: vi.fn() })); -vi.mock('@utils/debug', () => ({ logToFile: vi.fn() })); -vi.mock('@utils/analytics', () => ({ +import { refreshAccessTokenIfNeeded } from '../authenticate.js'; +import { refreshAccessToken } from '../../shared/oauth.js'; +import { OAuthError } from '../../shared/oauth-errors.js'; +import { + isGrantRevoked, + resetAuthSessionState, +} from '../../auth-session-state.js'; +import type { + WizardSession, + Credentials, +} from '../../session/wizard-session.js'; + +vi.mock('../../shared/oauth.js', () => ({ refreshAccessToken: vi.fn() })); +vi.mock('../../shared/debug.js', () => ({ logToFile: vi.fn() })); +vi.mock('../../shared/analytics.js', () => ({ analytics: { wizardCapture: vi.fn() }, groupsFromUser: vi.fn(), })); const setAccessToken = vi.fn(); -vi.mock('@ui', () => ({ +vi.mock('../../ui/index.js', () => ({ getUI: () => ({ setAccessToken }), })); diff --git a/src/lib/agent/runner/shared/authenticate.ts b/src/store/services/authenticate.ts similarity index 88% rename from src/lib/agent/runner/shared/authenticate.ts rename to src/store/services/authenticate.ts index 8644a328c..46a2098ec 100644 --- a/src/lib/agent/runner/shared/authenticate.ts +++ b/src/store/services/authenticate.ts @@ -10,15 +10,15 @@ * back rather than fetching again. */ -import type { Credentials, WizardSession } from '@lib/wizard-session'; -import type { ProgramId } from '@lib/programs/program-registry'; -import { getOrAskForProjectData } from '@utils/setup-utils'; -import { refreshAccessToken } from '@utils/oauth'; -import { OAuthError } from '@utils/oauth-errors'; -import { markGrantRevoked } from '@lib/auth-session-state'; -import { analytics, groupsFromUser } from '@utils/analytics'; -import { getUI } from '@ui'; -import { logToFile } from '@utils/debug'; +import type { Credentials, WizardSession } from '../session/wizard-session.js'; +import type { ProgramId } from '../programs/program-registry.js'; +import { getOrAskForProjectData } from '../shared/setup-utils.js'; +import { refreshAccessToken } from '../shared/oauth.js'; +import { OAuthError } from '../shared/oauth-errors.js'; +import { markGrantRevoked } from '../auth-session-state.js'; +import { analytics, groupsFromUser } from '../shared/analytics.js'; +import { getUI } from '../ui/index.js'; +import { logToFile } from '../shared/debug.js'; export async function authenticate( session: WizardSession, diff --git a/src/lib/claude-settings.ts b/src/store/services/claude-settings.ts similarity index 98% rename from src/lib/claude-settings.ts rename to src/store/services/claude-settings.ts index 43da0b418..99cac2592 100644 --- a/src/lib/claude-settings.ts +++ b/src/store/services/claude-settings.ts @@ -10,12 +10,12 @@ import path from 'path'; import * as fs from 'fs'; import * as os from 'os'; -import { analytics } from '@utils/analytics'; -import { registerCleanup } from '@utils/wizard-abort'; +import { analytics } from '../shared/analytics.js'; +import { registerCleanup } from '../shared/wizard-abort.js'; import { BLOCKED_AGENT_ENV_KEYS, BLOCKED_AGENT_ENV_PATTERNS, -} from './agent-env-isolation'; +} from '../agent-protocol/agent-env-isolation.js'; /** The file names Claude Code accepts for project settings, in priority order. */ const SETTINGS_FILENAMES = ['settings.json', 'settings'] as const; diff --git a/src/lib/oauth/__tests__/program-scopes.test.ts b/src/store/services/oauth/__tests__/program-scopes.test.ts similarity index 98% rename from src/lib/oauth/__tests__/program-scopes.test.ts rename to src/store/services/oauth/__tests__/program-scopes.test.ts index 773a7f15d..f048f15d5 100644 --- a/src/lib/oauth/__tests__/program-scopes.test.ts +++ b/src/store/services/oauth/__tests__/program-scopes.test.ts @@ -6,7 +6,7 @@ import { getOAuthScopesForProgram, getProvisioningScopesForProgram, -} from '@lib/oauth/program-scopes'; +} from '../program-scopes.js'; describe('posthog-integration scopes', () => { it('includes the warehouse pair for the orchestrator warehouse task', () => { diff --git a/src/lib/oauth/program-scopes.ts b/src/store/services/oauth/program-scopes.ts similarity index 99% rename from src/lib/oauth/program-scopes.ts rename to src/store/services/oauth/program-scopes.ts index 69da4f59a..71a6be4f3 100644 --- a/src/lib/oauth/program-scopes.ts +++ b/src/store/services/oauth/program-scopes.ts @@ -31,11 +31,11 @@ // read as `undefined` at module init. Keep this type-only and reference // program IDs by their string-literal value below — TypeScript still // catches renames via the `Partial>` keying. -import type { ProgramId } from '@lib/programs/program-registry'; +import type { ProgramId } from '../../programs/program-registry.js'; import { WIZARD_OAUTH_SCOPES, WIZARD_PROVISIONING_SCOPES, -} from '@lib/constants'; +} from '../../shared/constants.js'; /** * Extra scopes the MCP tutorial needs on top of `WIZARD_OAUTH_SCOPES`. diff --git a/src/steps/add-mcp-server-to-clients/MCPClient.ts b/src/store/services/steps/add-mcp-server-to-clients/MCPClient.ts similarity index 98% rename from src/steps/add-mcp-server-to-clients/MCPClient.ts rename to src/store/services/steps/add-mcp-server-to-clients/MCPClient.ts index 087f075c7..2c2082423 100644 --- a/src/steps/add-mcp-server-to-clients/MCPClient.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/MCPClient.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as jsonc from 'jsonc-parser'; -import { getDefaultServerConfig } from './defaults'; -import type { InstallResult } from './results'; +import { getDefaultServerConfig } from './defaults.js'; +import type { InstallResult } from './results.js'; export type MCPServerConfig = Record; diff --git a/src/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts b/src/store/services/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts similarity index 97% rename from src/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts index c20b8f53b..2c4495a31 100644 --- a/src/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/__tests__/defaults.test.ts @@ -2,7 +2,7 @@ import { buildMCPUrl, getDefaultServerConfig, getNativeHTTPServerConfig, -} from '@steps/add-mcp-server-to-clients/defaults'; +} from '../defaults.js'; describe('defaults', () => { describe('buildMCPUrl', () => { diff --git a/src/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts b/src/store/services/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts similarity index 96% rename from src/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts index 82b6aaea4..3e04f9ca5 100644 --- a/src/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/__tests__/mcp-client.test.ts @@ -1,4 +1,4 @@ -import { DefaultMCPClient } from '@steps/add-mcp-server-to-clients/MCPClient'; +import { DefaultMCPClient } from '../MCPClient.js'; import * as fs from 'fs'; vi.mock('fs', () => ({ diff --git a/src/steps/add-mcp-server-to-clients/__tests__/results.test.ts b/src/store/services/steps/add-mcp-server-to-clients/__tests__/results.test.ts similarity index 98% rename from src/steps/add-mcp-server-to-clients/__tests__/results.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/__tests__/results.test.ts index 56f49dc89..443bf6f53 100644 --- a/src/steps/add-mcp-server-to-clients/__tests__/results.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/__tests__/results.test.ts @@ -5,7 +5,7 @@ import { redactSecrets, summarizeFailure, toClientResult, -} from '@steps/add-mcp-server-to-clients/results'; +} from '../results.js'; describe('toClientResult', () => { it('maps a plain success to installed', () => { diff --git a/src/steps/add-mcp-server-to-clients/browser-client.ts b/src/store/services/steps/add-mcp-server-to-clients/browser-client.ts similarity index 100% rename from src/steps/add-mcp-server-to-clients/browser-client.ts rename to src/store/services/steps/add-mcp-server-to-clients/browser-client.ts diff --git a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts similarity index 95% rename from src/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts index 4af8c4e36..59e7969e5 100644 --- a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-code.test.ts @@ -1,6 +1,6 @@ -import { ClaudeCodeMCPClient } from '@steps/add-mcp-server-to-clients/clients/claude-code'; +import { ClaudeCodeMCPClient } from '../claude-code.js'; import { execSync } from 'child_process'; -import { analytics } from '@utils/analytics'; +import { analytics } from '../../../../../shared/analytics.js'; vi.mock('child_process', () => ({ execSync: vi.fn(), @@ -10,11 +10,11 @@ vi.mock('fs', () => ({ existsSync: vi.fn().mockReturnValue(false), })); -vi.mock('../../../../utils/analytics', () => ({ +vi.mock('../../../../../shared/analytics.js', () => ({ analytics: { captureException: vi.fn() }, })); -vi.mock('../../../../utils/debug', () => ({ +vi.mock('../../../../../shared/debug.js', () => ({ debug: vi.fn(), })); diff --git a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts similarity index 86% rename from src/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts index 3455279cc..1a872091e 100644 --- a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude-web.test.ts @@ -1,8 +1,8 @@ -import { ClaudeWebMCPClient } from '@steps/add-mcp-server-to-clients/clients/claude-web'; -import { isBrowserFinishable } from '@steps/add-mcp-server-to-clients/browser-client'; -import { openTrackedLink } from '@utils/links'; +import { ClaudeWebMCPClient } from '../claude-web.js'; +import { isBrowserFinishable } from '../../browser-client.js'; +import { openTrackedLink } from '../../../../../shared/links.js'; -vi.mock('@utils/links', () => ({ +vi.mock('../../../../../shared/links.js', () => ({ openTrackedLink: vi.fn(), })); diff --git a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts similarity index 98% rename from src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts index 6e2cca39c..cd5ed11e4 100644 --- a/src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts @@ -2,11 +2,11 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { ClaudeMCPClient } from '@steps/add-mcp-server-to-clients/clients/claude'; +import { ClaudeMCPClient } from '../claude.js'; import { getDefaultServerConfig, DefaultMCPClientConfig, -} from '@steps/add-mcp-server-to-clients/defaults'; +} from '../../defaults.js'; vi.mock('fs', () => ({ promises: { @@ -21,7 +21,7 @@ vi.mock('os', () => ({ homedir: vi.fn(), })); -vi.mock('../../defaults', () => ({ +vi.mock('../../defaults.js', () => ({ DefaultMCPClientConfig: { parse: vi.fn(), }, diff --git a/src/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts similarity index 98% rename from src/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts index 4ff93c361..6d33fcfd3 100644 --- a/src/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/codex.test.ts @@ -1,7 +1,7 @@ -import { CodexMCPClient } from '@steps/add-mcp-server-to-clients/clients/codex'; +import { CodexMCPClient } from '../codex.js'; import { execSync, spawnSync } from 'node:child_process'; import * as fs from 'node:fs'; -import { analytics } from '@utils/analytics'; +import { analytics } from '../../../../../shared/analytics.js'; vi.mock('node:child_process', () => ({ execSync: vi.fn(), @@ -14,7 +14,7 @@ vi.mock('node:fs', () => ({ rmSync: vi.fn(), })); -vi.mock('../../../../utils/analytics', () => ({ +vi.mock('../../../../../shared/analytics.js', () => ({ analytics: { captureException: vi.fn() }, })); diff --git a/src/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts similarity index 98% rename from src/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts index 3b20c6b22..1cb1a225d 100644 --- a/src/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/__tests__/opencode.test.ts @@ -1,4 +1,4 @@ -import { OpenCodeMCPClient } from '@steps/add-mcp-server-to-clients/clients/opencode'; +import { OpenCodeMCPClient } from '../opencode.js'; import { execSync } from 'node:child_process'; import * as fs from 'node:fs'; import * as os from 'node:os'; @@ -28,7 +28,7 @@ vi.mock('@env', () => ({ runtimeEnv: vi.fn(), })); -vi.mock('@utils/debug', () => ({ +vi.mock('../../../../../shared/debug.js', () => ({ debug: vi.fn(), })); diff --git a/src/steps/add-mcp-server-to-clients/clients/claude-code.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/claude-code.ts similarity index 93% rename from src/steps/add-mcp-server-to-clients/clients/claude-code.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/claude-code.ts index 2374a2163..2ccd6c05a 100644 --- a/src/steps/add-mcp-server-to-clients/clients/claude-code.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/claude-code.ts @@ -1,21 +1,12 @@ -import { DefaultMCPClient } from '@steps/add-mcp-server-to-clients/MCPClient'; -import { - DefaultMCPClientConfig, - buildMCPUrl, -} from '@steps/add-mcp-server-to-clients/defaults'; -import { - PluginCapable, - PluginInstallResult, -} from '@steps/add-mcp-server-to-clients/plugin-client'; -import { - redactSecrets, - type InstallResult, -} from '@steps/add-mcp-server-to-clients/results'; -import { LoginCapable } from '@steps/add-mcp-server-to-clients/login-client'; +import { DefaultMCPClient } from '../MCPClient.js'; +import { DefaultMCPClientConfig, buildMCPUrl } from '../defaults.js'; +import { PluginCapable, PluginInstallResult } from '../plugin-client.js'; +import { redactSecrets, type InstallResult } from '../results.js'; +import { LoginCapable } from '../login-client.js'; import { z } from 'zod'; import { execSync } from 'child_process'; -import { analytics } from '@utils/analytics'; -import { debug } from '@utils/debug'; +import { analytics } from '../../../../shared/analytics.js'; +import { debug } from '../../../../shared/debug.js'; import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; diff --git a/src/steps/add-mcp-server-to-clients/clients/claude-web.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/claude-web.ts similarity index 85% rename from src/steps/add-mcp-server-to-clients/clients/claude-web.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/claude-web.ts index 2e34d779e..4c8891bb1 100644 --- a/src/steps/add-mcp-server-to-clients/clients/claude-web.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/claude-web.ts @@ -1,7 +1,7 @@ -import { MCPClient } from '@steps/add-mcp-server-to-clients/MCPClient'; -import type { InstallResult } from '@steps/add-mcp-server-to-clients/results'; -import { BrowserFinishable } from '@steps/add-mcp-server-to-clients/browser-client'; -import { openTrackedLink } from '@utils/links'; +import { MCPClient } from '../MCPClient.js'; +import type { InstallResult } from '../results.js'; +import { BrowserFinishable } from '../browser-client.js'; +import { openTrackedLink } from '../../../../shared/links.js'; /** * Claude Desktop / Claude.ai (web). PostHog ships here as a hosted connector, diff --git a/src/steps/add-mcp-server-to-clients/clients/claude.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/claude.ts similarity index 87% rename from src/steps/add-mcp-server-to-clients/clients/claude.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/claude.ts index f7db763f5..e852b886f 100644 --- a/src/steps/add-mcp-server-to-clients/clients/claude.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/claude.ts @@ -1,7 +1,7 @@ -import { DefaultMCPClient } from '@steps/add-mcp-server-to-clients/MCPClient'; +import { DefaultMCPClient } from '../MCPClient.js'; import * as path from 'path'; import * as os from 'os'; -import { DefaultMCPClientConfig } from '@steps/add-mcp-server-to-clients/defaults'; +import { DefaultMCPClientConfig } from '../defaults.js'; import { runtimeEnv } from '@env'; import { z } from 'zod'; diff --git a/src/steps/add-mcp-server-to-clients/clients/codex.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/codex.ts similarity index 95% rename from src/steps/add-mcp-server-to-clients/clients/codex.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/codex.ts index e4020d54b..4ef98a7c8 100644 --- a/src/steps/add-mcp-server-to-clients/clients/codex.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/codex.ts @@ -4,22 +4,13 @@ import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; -import { LoginCapable } from '@steps/add-mcp-server-to-clients/login-client'; -import { DefaultMCPClient } from '@steps/add-mcp-server-to-clients/MCPClient'; -import { - DefaultMCPClientConfig, - buildMCPUrl, -} from '@steps/add-mcp-server-to-clients/defaults'; -import { - PluginCapable, - PluginInstallResult, -} from '@steps/add-mcp-server-to-clients/plugin-client'; -import { - redactSecrets, - type InstallResult, -} from '@steps/add-mcp-server-to-clients/results'; - -import { analytics } from '@utils/analytics'; +import { LoginCapable } from '../login-client.js'; +import { DefaultMCPClient } from '../MCPClient.js'; +import { DefaultMCPClientConfig, buildMCPUrl } from '../defaults.js'; +import { PluginCapable, PluginInstallResult } from '../plugin-client.js'; +import { redactSecrets, type InstallResult } from '../results.js'; + +import { analytics } from '../../../../shared/analytics.js'; /** Wording codex uses when the thing we're adding is already registered. */ const ALREADY_INSTALLED_PATTERN = diff --git a/src/steps/add-mcp-server-to-clients/clients/cursor.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/cursor.ts similarity index 85% rename from src/steps/add-mcp-server-to-clients/clients/cursor.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/cursor.ts index c13d18c12..594ff9e6d 100644 --- a/src/steps/add-mcp-server-to-clients/clients/cursor.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/cursor.ts @@ -1,13 +1,10 @@ -import { - DefaultMCPClient, - MCPServerConfig, -} from '@steps/add-mcp-server-to-clients/MCPClient'; +import { DefaultMCPClient, MCPServerConfig } from '../MCPClient.js'; import * as path from 'path'; import * as os from 'os'; import { DefaultMCPClientConfig, getNativeHTTPServerConfig, -} from '@steps/add-mcp-server-to-clients/defaults'; +} from '../defaults.js'; import { z } from 'zod'; export const CursorMCPConfig = DefaultMCPClientConfig; diff --git a/src/steps/add-mcp-server-to-clients/clients/opencode.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/opencode.ts similarity index 91% rename from src/steps/add-mcp-server-to-clients/clients/opencode.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/opencode.ts index a6485dbe3..9890ebda8 100644 --- a/src/steps/add-mcp-server-to-clients/clients/opencode.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/opencode.ts @@ -3,11 +3,8 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import { execSync } from 'node:child_process'; -import { - DefaultMCPClient, - MCPServerConfig, -} from '@steps/add-mcp-server-to-clients/MCPClient'; -import { getNativeHTTPServerConfig } from '@steps/add-mcp-server-to-clients/defaults'; +import { DefaultMCPClient, MCPServerConfig } from '../MCPClient.js'; +import { getNativeHTTPServerConfig } from '../defaults.js'; import { runtimeEnv } from '@env'; export const OpenCodeMCPConfig = z diff --git a/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts similarity index 91% rename from src/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts index 4c82ded04..398933b2b 100644 --- a/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/visual-studio-code.ts @@ -1,11 +1,8 @@ import z from 'zod'; import * as path from 'path'; import * as os from 'os'; -import { - DefaultMCPClient, - MCPServerConfig, -} from '@steps/add-mcp-server-to-clients/MCPClient'; -import { getNativeHTTPServerConfig } from '@steps/add-mcp-server-to-clients/defaults'; +import { DefaultMCPClient, MCPServerConfig } from '../MCPClient.js'; +import { getNativeHTTPServerConfig } from '../defaults.js'; import { runtimeEnv } from '@env'; export const VisualStudioCodeMCPConfig = z diff --git a/src/steps/add-mcp-server-to-clients/clients/zed.ts b/src/store/services/steps/add-mcp-server-to-clients/clients/zed.ts similarity index 91% rename from src/steps/add-mcp-server-to-clients/clients/zed.ts rename to src/store/services/steps/add-mcp-server-to-clients/clients/zed.ts index cfd0a7667..ef80bd777 100644 --- a/src/steps/add-mcp-server-to-clients/clients/zed.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/clients/zed.ts @@ -1,11 +1,8 @@ import z from 'zod'; import * as path from 'path'; import * as os from 'os'; -import { - DefaultMCPClient, - MCPServerConfig, -} from '@steps/add-mcp-server-to-clients/MCPClient'; -import { getNativeHTTPServerConfig } from '@steps/add-mcp-server-to-clients/defaults'; +import { DefaultMCPClient, MCPServerConfig } from '../MCPClient.js'; +import { getNativeHTTPServerConfig } from '../defaults.js'; import { runtimeEnv } from '@env'; export const ZedMCPConfig = z diff --git a/src/steps/add-mcp-server-to-clients/defaults.ts b/src/store/services/steps/add-mcp-server-to-clients/defaults.ts similarity index 100% rename from src/steps/add-mcp-server-to-clients/defaults.ts rename to src/store/services/steps/add-mcp-server-to-clients/defaults.ts diff --git a/src/steps/add-mcp-server-to-clients/index.ts b/src/store/services/steps/add-mcp-server-to-clients/index.ts similarity index 91% rename from src/steps/add-mcp-server-to-clients/index.ts rename to src/store/services/steps/add-mcp-server-to-clients/index.ts index 9dfcd10ee..a02e035b3 100644 --- a/src/steps/add-mcp-server-to-clients/index.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/index.ts @@ -1,25 +1,25 @@ -import type { Integration } from '@lib/constants'; -import type { CloudRegion } from '@utils/types'; -import { withProgress } from '../../telemetry'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; -import { MCPClient } from './MCPClient'; -import { CursorMCPClient } from './clients/cursor'; -import { ClaudeCodeMCPClient } from './clients/claude-code'; -import { ClaudeWebMCPClient } from './clients/claude-web'; -import { VisualStudioCodeClient } from './clients/visual-studio-code'; -import { ZedClient } from './clients/zed'; -import { CodexMCPClient } from './clients/codex'; -import { OpenCodeMCPClient } from './clients/opencode'; -import { ALL_FEATURE_VALUES } from './defaults'; -import { debug } from '@utils/debug'; -import { isPluginCapable, PluginCapable } from './plugin-client'; +import type { Integration } from '../../../shared/constants.js'; +import type { CloudRegion } from '../../../shared/types.js'; +import { withProgress } from '../../../shared/telemetry.js'; +import { analytics } from '../../../shared/analytics.js'; +import { getUI } from '../../../ui/index.js'; +import { MCPClient } from './MCPClient.js'; +import { CursorMCPClient } from './clients/cursor.js'; +import { ClaudeCodeMCPClient } from './clients/claude-code.js'; +import { ClaudeWebMCPClient } from './clients/claude-web.js'; +import { VisualStudioCodeClient } from './clients/visual-studio-code.js'; +import { ZedClient } from './clients/zed.js'; +import { CodexMCPClient } from './clients/codex.js'; +import { OpenCodeMCPClient } from './clients/opencode.js'; +import { ALL_FEATURE_VALUES } from './defaults.js'; +import { debug } from '../../../shared/debug.js'; +import { isPluginCapable, PluginCapable } from './plugin-client.js'; import { McpClientStatus, namesWithStatus, toClientResult, type McpClientResult, -} from './results'; +} from './results.js'; export const getSupportedClients = async (): Promise => { const allClients = [ diff --git a/src/steps/add-mcp-server-to-clients/login-client.ts b/src/store/services/steps/add-mcp-server-to-clients/login-client.ts similarity index 100% rename from src/steps/add-mcp-server-to-clients/login-client.ts rename to src/store/services/steps/add-mcp-server-to-clients/login-client.ts diff --git a/src/steps/add-mcp-server-to-clients/plugin-client.ts b/src/store/services/steps/add-mcp-server-to-clients/plugin-client.ts similarity index 93% rename from src/steps/add-mcp-server-to-clients/plugin-client.ts rename to src/store/services/steps/add-mcp-server-to-clients/plugin-client.ts index ea2a0459f..41c308873 100644 --- a/src/steps/add-mcp-server-to-clients/plugin-client.ts +++ b/src/store/services/steps/add-mcp-server-to-clients/plugin-client.ts @@ -1,4 +1,4 @@ -import type { InstallResult } from './results'; +import type { InstallResult } from './results.js'; export type PluginInstallResult = InstallResult; diff --git a/src/steps/add-mcp-server-to-clients/results.ts b/src/store/services/steps/add-mcp-server-to-clients/results.ts similarity index 100% rename from src/steps/add-mcp-server-to-clients/results.ts rename to src/store/services/steps/add-mcp-server-to-clients/results.ts diff --git a/src/steps/add-or-update-environment-variables.ts b/src/store/services/steps/add-or-update-environment-variables.ts similarity index 95% rename from src/steps/add-or-update-environment-variables.ts rename to src/store/services/steps/add-or-update-environment-variables.ts index 67787dfa8..2bf0d6dbe 100644 --- a/src/steps/add-or-update-environment-variables.ts +++ b/src/store/services/steps/add-or-update-environment-variables.ts @@ -1,8 +1,8 @@ -import type { Integration } from '@lib/constants'; -import { withProgress } from '../telemetry'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; -import { getDotGitignore } from '@utils/bounded-fs'; +import type { Integration } from '../../shared/constants.js'; +import { withProgress } from '../../shared/telemetry.js'; +import { analytics } from '../../shared/analytics.js'; +import { getUI } from '../../ui/index.js'; +import { getDotGitignore } from '../../shared/bounded-fs.js'; import * as fs from 'fs'; import path from 'path'; diff --git a/src/store/services/steps/index.ts b/src/store/services/steps/index.ts new file mode 100644 index 000000000..a957338de --- /dev/null +++ b/src/store/services/steps/index.ts @@ -0,0 +1,4 @@ +export * from './run-prettier.js'; +export * from './add-or-update-environment-variables.js'; +export * from './add-mcp-server-to-clients/index.js'; +export * from './upload-environment-variables/index.js'; diff --git a/src/steps/install-cli-steering/__tests__/install-cli-steering.test.ts b/src/store/services/steps/install-cli-steering/__tests__/install-cli-steering.test.ts similarity index 98% rename from src/steps/install-cli-steering/__tests__/install-cli-steering.test.ts rename to src/store/services/steps/install-cli-steering/__tests__/install-cli-steering.test.ts index 19a0b9c8f..4acaf4335 100644 --- a/src/steps/install-cli-steering/__tests__/install-cli-steering.test.ts +++ b/src/store/services/steps/install-cli-steering/__tests__/install-cli-steering.test.ts @@ -10,9 +10,9 @@ import { findTarget, installOrUpdatePostHogCli, installSteeringSnippet, -} from '@steps/install-cli-steering'; +} from '../index.js'; -vi.mock('../../../utils/debug'); +vi.mock('../../../../shared/debug.js'); vi.mock('node:child_process', () => ({ spawnSync: vi.fn(), })); diff --git a/src/steps/install-cli-steering/index.ts b/src/store/services/steps/install-cli-steering/index.ts similarity index 98% rename from src/steps/install-cli-steering/index.ts rename to src/store/services/steps/install-cli-steering/index.ts index 45e133219..f594a6f41 100644 --- a/src/steps/install-cli-steering/index.ts +++ b/src/store/services/steps/install-cli-steering/index.ts @@ -3,7 +3,7 @@ import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; -import { debug } from '@utils/debug'; +import { debug } from '../../../shared/debug.js'; /** * A coding agent whose global instructions file the PostHog CLI steering diff --git a/src/steps/run-prettier.ts b/src/store/services/steps/run-prettier.ts similarity index 83% rename from src/steps/run-prettier.ts rename to src/store/services/steps/run-prettier.ts index 61a4d165e..9eceb9de7 100644 --- a/src/steps/run-prettier.ts +++ b/src/store/services/steps/run-prettier.ts @@ -1,14 +1,14 @@ -import type { Integration } from '@lib/constants'; -import { withProgress } from '../telemetry'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; +import type { Integration } from '../../shared/constants.js'; +import { withProgress } from '../../shared/telemetry.js'; +import { analytics } from '../../shared/analytics.js'; +import { getUI } from '../../ui/index.js'; import { tryGetPackageJson, getUncommittedOrUntrackedFiles, isInGitRepo, -} from '@utils/setup-utils'; -import { hasDeclaredDependency } from '@utils/package-json'; -import type { WizardRunOptions } from '@utils/types'; +} from '../../shared/setup-utils.js'; +import { hasDeclaredDependency } from '../../shared/package-json.js'; +import type { WizardRunOptions } from '../../shared/types.js'; import * as childProcess from 'node:child_process'; export async function runPrettierStep({ diff --git a/src/steps/upload-environment-variables/EnvironmentProvider.ts b/src/store/services/steps/upload-environment-variables/EnvironmentProvider.ts similarity index 100% rename from src/steps/upload-environment-variables/EnvironmentProvider.ts rename to src/store/services/steps/upload-environment-variables/EnvironmentProvider.ts diff --git a/src/steps/upload-environment-variables/index.ts b/src/store/services/steps/upload-environment-variables/index.ts similarity index 72% rename from src/steps/upload-environment-variables/index.ts rename to src/store/services/steps/upload-environment-variables/index.ts index 3a15081b7..fbf04b374 100644 --- a/src/steps/upload-environment-variables/index.ts +++ b/src/store/services/steps/upload-environment-variables/index.ts @@ -1,10 +1,10 @@ -import type { Integration } from '@lib/constants'; -import { withProgress } from '../../telemetry'; -import { analytics } from '@utils/analytics'; -import { getUI } from '@ui'; -import type { WizardSession } from '@lib/wizard-session'; -import { EnvironmentProvider } from './EnvironmentProvider'; -import { VercelEnvironmentProvider } from './providers/vercel'; +import type { Integration } from '../../../shared/constants.js'; +import { withProgress } from '../../../shared/telemetry.js'; +import { analytics } from '../../../shared/analytics.js'; +import { getUI } from '../../../ui/index.js'; +import type { WizardSession } from '../../../session/wizard-session.js'; +import { EnvironmentProvider } from './EnvironmentProvider.js'; +import { VercelEnvironmentProvider } from './providers/vercel.js'; export const uploadEnvironmentVariablesStep = async ( envVars: Record, diff --git a/src/steps/upload-environment-variables/providers/__tests__/vercel.test.ts b/src/store/services/steps/upload-environment-variables/providers/__tests__/vercel.test.ts similarity index 96% rename from src/steps/upload-environment-variables/providers/__tests__/vercel.test.ts rename to src/store/services/steps/upload-environment-variables/providers/__tests__/vercel.test.ts index 97c8f73b1..16a3efafa 100644 --- a/src/steps/upload-environment-variables/providers/__tests__/vercel.test.ts +++ b/src/store/services/steps/upload-environment-variables/providers/__tests__/vercel.test.ts @@ -1,4 +1,4 @@ -import { VercelEnvironmentProvider } from '@steps/upload-environment-variables/providers/vercel'; +import { VercelEnvironmentProvider } from '../vercel.js'; import * as fs from 'fs'; import * as child_process from 'child_process'; diff --git a/src/steps/upload-environment-variables/providers/vercel.ts b/src/store/services/steps/upload-environment-variables/providers/vercel.ts similarity index 95% rename from src/steps/upload-environment-variables/providers/vercel.ts rename to src/store/services/steps/upload-environment-variables/providers/vercel.ts index 3279f6ec1..4f10e007b 100644 --- a/src/steps/upload-environment-variables/providers/vercel.ts +++ b/src/store/services/steps/upload-environment-variables/providers/vercel.ts @@ -1,9 +1,9 @@ import { execSync, spawn, spawnSync } from 'child_process'; -import { EnvironmentProvider } from '@steps/upload-environment-variables/EnvironmentProvider'; +import { EnvironmentProvider } from '../EnvironmentProvider.js'; import * as fs from 'fs'; import * as path from 'path'; -import { getUI } from '@ui'; -import { analytics } from '@utils/analytics'; +import { getUI } from '../../../../ui/index.js'; +import { analytics } from '../../../../shared/analytics.js'; export class VercelEnvironmentProvider extends EnvironmentProvider { name = 'Vercel'; diff --git a/src/lib/warehouse-sources/__tests__/detect.test.ts b/src/store/services/warehouse-sources/__tests__/detect.test.ts similarity index 99% rename from src/lib/warehouse-sources/__tests__/detect.test.ts rename to src/store/services/warehouse-sources/__tests__/detect.test.ts index 341756363..c40b05a1d 100644 --- a/src/lib/warehouse-sources/__tests__/detect.test.ts +++ b/src/store/services/warehouse-sources/__tests__/detect.test.ts @@ -5,9 +5,9 @@ import { detectWarehouseSources, parseGemfile, parseEnvKeys, -} from '@lib/warehouse-sources/detect'; -import { MAX_REPORTED_PATH_LENGTH } from '@utils/env-scan'; -import { SOURCE_DETECTORS } from '@lib/warehouse-sources/registry'; +} from '../detect.js'; +import { MAX_REPORTED_PATH_LENGTH } from '../../../shared/env-scan.js'; +import { SOURCE_DETECTORS } from '../registry.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'warehouse-detect-')); diff --git a/src/lib/warehouse-sources/detect.ts b/src/store/services/warehouse-sources/detect.ts similarity index 95% rename from src/lib/warehouse-sources/detect.ts rename to src/store/services/warehouse-sources/detect.ts index 2153a9a69..720b4d65d 100644 --- a/src/lib/warehouse-sources/detect.ts +++ b/src/store/services/warehouse-sources/detect.ts @@ -9,21 +9,21 @@ * Note we only read `.env` KEY NAMES, never values. */ -import { analytics } from '@utils/analytics'; -import { walkProjectFiles, safeReadFile } from '@utils/bounded-fs'; +import { analytics } from '../../shared/analytics.js'; +import { walkProjectFiles, safeReadFile } from '../../shared/bounded-fs.js'; import { ENV_SCAN_MAX_DEPTH, MAX_ENV_KEY_SET, isEnvFileName, parseEnvKeyNames, toPromptSafeRelativePath, -} from '@utils/env-scan'; -import type { PackageJson } from '@utils/package-json'; +} from '../../shared/env-scan.js'; +import type { PackageJson } from '../../shared/package-json.js'; import { parseRequirementsTxt, parsePyprojectToml, parsePipfile, -} from '@lib/detection/features'; +} from '../../detection/features.js'; import { SOURCE_DETECTORS } from './registry.js'; import type { DetectedSource, SourceDetector } from './types.js'; @@ -222,4 +222,4 @@ export function parseGemfile(content: string): string[] { * Re-exported from `@utils/env-scan`, which `check_env_keys` shares, so the * detector and the tool cannot disagree about what counts as a key. */ -export { parseEnvKeyNames as parseEnvKeys } from '@utils/env-scan'; +export { parseEnvKeyNames as parseEnvKeys } from '../../shared/env-scan.js'; diff --git a/src/lib/warehouse-sources/registry.ts b/src/store/services/warehouse-sources/registry.ts similarity index 100% rename from src/lib/warehouse-sources/registry.ts rename to src/store/services/warehouse-sources/registry.ts diff --git a/src/lib/warehouse-sources/types.ts b/src/store/services/warehouse-sources/types.ts similarity index 100% rename from src/lib/warehouse-sources/types.ts rename to src/store/services/warehouse-sources/types.ts diff --git a/src/lib/__tests__/agent-runner-ask.test.ts b/src/store/session/__tests__/ask-policy.test.ts similarity index 94% rename from src/lib/__tests__/agent-runner-ask.test.ts rename to src/store/session/__tests__/ask-policy.test.ts index 2364b5ccf..7ea2da842 100644 --- a/src/lib/__tests__/agent-runner-ask.test.ts +++ b/src/store/session/__tests__/ask-policy.test.ts @@ -1,5 +1,5 @@ -import { shouldDisableAsk } from '@lib/agent/agent-runner'; -import { buildSession } from '@lib/wizard-session'; +import { shouldDisableAsk } from '../ask-policy.js'; +import { buildSession } from '../wizard-session.js'; describe('shouldDisableAsk', () => { it('enables wizard_ask in interactive runs by default', () => { diff --git a/src/lib/ask-policy.ts b/src/store/session/ask-policy.ts similarity index 94% rename from src/lib/ask-policy.ts rename to src/store/session/ask-policy.ts index c0b55652d..cad3ded1c 100644 --- a/src/lib/ask-policy.ts +++ b/src/store/session/ask-policy.ts @@ -1,4 +1,4 @@ -import type { WizardSession } from '@lib/wizard-session'; +import type { WizardSession } from './wizard-session.js'; /** * Decide whether the `wizard_ask` overlay should be wired for this run. diff --git a/src/lib/secret-vault.ts b/src/store/session/secret-vault.ts similarity index 100% rename from src/lib/secret-vault.ts rename to src/store/session/secret-vault.ts diff --git a/src/lib/wizard-ask-bridge.ts b/src/store/session/wizard-ask-bridge.ts similarity index 98% rename from src/lib/wizard-ask-bridge.ts rename to src/store/session/wizard-ask-bridge.ts index 93b06cefa..723327136 100644 --- a/src/lib/wizard-ask-bridge.ts +++ b/src/store/session/wizard-ask-bridge.ts @@ -12,12 +12,12 @@ */ import { randomUUID } from 'crypto'; -import { analytics } from '@utils/analytics'; +import { analytics } from '../shared/analytics.js'; import type { AskAnswers, AskQuestion, PendingQuestion, -} from './wizard-session'; +} from './wizard-session.js'; export interface WizardAskRequest { questions: AskQuestion[]; diff --git a/src/lib/wizard-session.ts b/src/store/session/wizard-session.ts similarity index 97% rename from src/lib/wizard-session.ts rename to src/store/session/wizard-session.ts index bee8c8de9..87361a6df 100644 --- a/src/lib/wizard-session.ts +++ b/src/store/session/wizard-session.ts @@ -10,13 +10,14 @@ * Business logic reads from the session. Never calls a prompt. */ -import { POSTHOG_LOCAL_URL, resolveLocalDev } from './local-dev'; -import type { Harness, Integration, Sequence } from './constants'; -import type { FrameworkConfig } from './framework-config'; -import type { WizardReadinessResult } from './health-checks/readiness'; -import type { SettingsConflict } from './claude-settings'; -import type { ApiUser, ApiProject } from './api'; -import type { HostResolution } from './host-resolution'; +import { POSTHOG_LOCAL_URL, resolveLocalDev } from '../local-dev.js'; +import type { Harness, Integration, Sequence } from '../shared/constants.js'; +import type { CloudRegion } from '../shared/types.js'; +import type { FrameworkConfig } from '../framework-config.js'; +import type { WizardReadinessResult } from '../health-checks/readiness.js'; +import type { SettingsConflict } from '../services/claude-settings.js'; +import type { ApiUser, ApiProject } from '../api.js'; +import type { HostResolution } from '../host-resolution.js'; export interface Credentials { accessToken: string; @@ -47,7 +48,7 @@ function parseProjectIdArg(value: string | undefined): number | undefined { return Number.isInteger(n) && n > 0 ? n : undefined; } -export type CloudRegion = 'us' | 'eu'; +export type { CloudRegion }; /** Lifecycle phase of the main work (agent run, MCP install, etc.) */ export enum RunPhase { @@ -130,7 +131,7 @@ export interface OutroData { /** Report file the agent wrote (e.g. "posthog-setup-report.md") */ reportFile?: string; /** Stable machine-readable error code from the error catalog (@lib/errors). */ - errorCode?: import('@lib/errors').ErrorCode; + errorCode?: import('../shared/errors/index.js').ErrorCode; /** Structured context for the error code; safe for telemetry payloads. */ errorDetail?: Record; /** PostHog dashboard URL the program created on the user's behalf. */ @@ -478,6 +479,7 @@ export function buildSession(args: { e2eAsk?: boolean; localDev?: boolean; localMcp?: boolean; + localContextMill?: boolean; localPosthog?: boolean; mcpFeatures?: string[]; apiKey?: string; diff --git a/src/utils/__fixtures__/provisioning.ts b/src/store/shared/__fixtures__/provisioning.ts similarity index 100% rename from src/utils/__fixtures__/provisioning.ts rename to src/store/shared/__fixtures__/provisioning.ts diff --git a/src/utils/__tests__/analytics.test.ts b/src/store/shared/__tests__/analytics.test.ts similarity index 99% rename from src/utils/__tests__/analytics.test.ts rename to src/store/shared/__tests__/analytics.test.ts index 347424ec1..a9e38f3dd 100644 --- a/src/utils/__tests__/analytics.test.ts +++ b/src/store/shared/__tests__/analytics.test.ts @@ -1,14 +1,14 @@ -import { Analytics, groupsFromUser, sessionProperties } from '@utils/analytics'; +import { Analytics, groupsFromUser, sessionProperties } from '../analytics.js'; import { PostHog } from 'posthog-node'; import { v4 as uuidv4 } from 'uuid'; -import { ANALYTICS_TEAM_TAG, WIZARD_FLAG_KEYS } from '@lib/constants'; -import { VERSION } from '@lib/version'; -import type { ApiUser } from '@lib/api'; +import { ANALYTICS_TEAM_TAG, WIZARD_FLAG_KEYS } from '../constants.js'; +import { VERSION } from '../version.js'; +import type { ApiUser } from '../../api.js'; import { buildSession, DiscoveredFeature, ScanConsent, -} from '@lib/wizard-session'; +} from '../../session/wizard-session.js'; vi.mock('posthog-node'); vi.mock('uuid'); diff --git a/src/utils/__tests__/bounded-fs-walk.test.ts b/src/store/shared/__tests__/bounded-fs-walk.test.ts similarity index 89% rename from src/utils/__tests__/bounded-fs-walk.test.ts rename to src/store/shared/__tests__/bounded-fs-walk.test.ts index c9ddeb512..4ec1390d6 100644 --- a/src/utils/__tests__/bounded-fs-walk.test.ts +++ b/src/store/shared/__tests__/bounded-fs-walk.test.ts @@ -1,12 +1,12 @@ import fs from 'fs'; -import { walkProjectFiles, safeReadFile } from '@utils/bounded-fs'; -import { analytics } from '@utils/analytics'; -import { logToFile } from '@utils/debug'; +import { walkProjectFiles, safeReadFile } from '../bounded-fs.js'; +import { analytics } from '../analytics.js'; +import { logToFile } from '../debug.js'; -vi.mock('../analytics', () => ({ +vi.mock('../analytics.js', () => ({ analytics: { captureException: vi.fn() }, })); -vi.mock('../debug', () => ({ logToFile: vi.fn() })); +vi.mock('../debug.js', () => ({ logToFile: vi.fn() })); const captureException = analytics.captureException as ReturnType; const mockLogToFile = logToFile as ReturnType; diff --git a/src/utils/__tests__/bounded-fs.test.ts b/src/store/shared/__tests__/bounded-fs.test.ts similarity index 99% rename from src/utils/__tests__/bounded-fs.test.ts rename to src/store/shared/__tests__/bounded-fs.test.ts index 99fa0f0a7..d7d859c30 100644 --- a/src/utils/__tests__/bounded-fs.test.ts +++ b/src/store/shared/__tests__/bounded-fs.test.ts @@ -6,7 +6,7 @@ import { readFileHead, readProjectFile, MAX_GLOB_MATCHES, -} from '@utils/bounded-fs'; +} from '../bounded-fs.js'; describe('boundedGlob', () => { let dir: string; diff --git a/src/utils/__tests__/ci-flag-overrides.test.ts b/src/store/shared/__tests__/ci-flag-overrides.test.ts similarity index 94% rename from src/utils/__tests__/ci-flag-overrides.test.ts rename to src/store/shared/__tests__/ci-flag-overrides.test.ts index ff6f78876..a24df2668 100644 --- a/src/utils/__tests__/ci-flag-overrides.test.ts +++ b/src/store/shared/__tests__/ci-flag-overrides.test.ts @@ -1,9 +1,9 @@ import { applyCiFlagOverrides, ciExcludedTaskTypes, -} from '@utils/ci-flag-overrides'; +} from '../ci-flag-overrides.js'; -vi.mock('@utils/debug', () => ({ +vi.mock('../debug.js', () => ({ logToFile: vi.fn(), debug: vi.fn(), })); @@ -72,7 +72,7 @@ describe('applyCiFlagOverrides', () => { // Re-import fresh so the module re-reads NODE_ENV at load time (the // vitest equivalent of jest.isolateModules). vi.resetModules(); - const prod = (await import('@utils/ci-flag-overrides')) as { + const prod = (await import('../ci-flag-overrides.js')) as { applyCiFlagOverrides: typeof applyCiFlagOverrides; }; const result = prod.applyCiFlagOverrides({ @@ -108,7 +108,7 @@ describe('ciExcludedTaskTypes', () => { // Re-import fresh so the module re-reads NODE_ENV at load time (the // vitest equivalent of jest.isolateModules). vi.resetModules(); - const prod = (await import('@utils/ci-flag-overrides')) as { + const prod = (await import('../ci-flag-overrides.js')) as { ciExcludedTaskTypes: typeof ciExcludedTaskTypes; }; const result = prod.ciExcludedTaskTypes(); diff --git a/src/utils/__tests__/ci-region.test.ts b/src/store/shared/__tests__/ci-region.test.ts similarity index 90% rename from src/utils/__tests__/ci-region.test.ts rename to src/store/shared/__tests__/ci-region.test.ts index d174852a5..bb5355299 100644 --- a/src/utils/__tests__/ci-region.test.ts +++ b/src/store/shared/__tests__/ci-region.test.ts @@ -1,32 +1,32 @@ -import { getOrAskForProjectData } from '@utils/setup-utils'; -import { detectRegion } from '@utils/urls'; -import { fetchProjectData, fetchUserData } from '@lib/api'; -import { performOAuthFlow } from '@utils/oauth'; +import { getOrAskForProjectData } from '../setup-utils.js'; +import { detectRegion } from '../urls.js'; +import { fetchProjectData, fetchUserData } from '../../api.js'; +import { performOAuthFlow } from '../oauth.js'; -vi.mock('@ui', () => ({ +vi.mock('../../ui/index.js', () => ({ getUI: () => ({ log: { info: vi.fn(), error: vi.fn(), success: vi.fn(), warn: vi.fn() }, }), })); -vi.mock('@utils/urls', () => ({ +vi.mock('../urls.js', () => ({ detectRegion: vi.fn(), getHost: (r: string) => `https://${r}.posthog.com`, getCloudUrl: (r: string) => `https://${r}.posthog.com`, getUiHostFromHost: (host: string) => host, resolveBaseUrl: (baseUrl?: string) => baseUrl, })); -vi.mock('@lib/api', () => ({ +vi.mock('../../api.js', () => ({ fetchProjectData: vi.fn(), fetchUserData: vi.fn(), })); -vi.mock('@utils/analytics', () => ({ +vi.mock('../analytics.js', () => ({ analytics: { identifyUser: vi.fn(), captureException: vi.fn(), setTag: vi.fn(), }, })); -vi.mock('@utils/oauth', () => ({ +vi.mock('../oauth.js', () => ({ performOAuthFlow: vi.fn(), assertWizardCompletionScope: vi.fn(), missingOAuthScopes: vi.fn(() => []), diff --git a/src/utils/__tests__/debug.test.ts b/src/store/shared/__tests__/debug.test.ts similarity index 98% rename from src/utils/__tests__/debug.test.ts rename to src/store/shared/__tests__/debug.test.ts index 31ab68581..f71202caa 100644 --- a/src/utils/__tests__/debug.test.ts +++ b/src/store/shared/__tests__/debug.test.ts @@ -6,7 +6,7 @@ import { getLogFilePath, initLogFile, logToFile, -} from '@utils/debug'; +} from '../debug.js'; describe('log file writing', () => { const originalPath = getLogFilePath(); diff --git a/src/utils/__tests__/env-api-key.test.ts b/src/store/shared/__tests__/env-api-key.test.ts similarity index 93% rename from src/utils/__tests__/env-api-key.test.ts rename to src/store/shared/__tests__/env-api-key.test.ts index a3a192c2b..60e9ec725 100644 --- a/src/utils/__tests__/env-api-key.test.ts +++ b/src/store/shared/__tests__/env-api-key.test.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { readApiKeyFromEnv } from '@utils/env-api-key'; +import { readApiKeyFromEnv } from '../env-api-key.js'; describe('readApiKeyFromEnv', () => { let dir: string; diff --git a/src/utils/__tests__/env-scan.test.ts b/src/store/shared/__tests__/env-scan.test.ts similarity index 99% rename from src/utils/__tests__/env-scan.test.ts rename to src/store/shared/__tests__/env-scan.test.ts index 4d03d8f90..1d31dec8c 100644 --- a/src/utils/__tests__/env-scan.test.ts +++ b/src/store/shared/__tests__/env-scan.test.ts @@ -12,7 +12,7 @@ import { toPromptSafeRelativePath, toRelativePosixPath, type EnvKeyLocations, -} from '@utils/env-scan'; +} from '../env-scan.js'; function makeTmpDir(): string { return fs.mkdtempSync(path.join(os.tmpdir(), 'env-scan-')); diff --git a/src/utils/__tests__/environment.test.ts b/src/store/shared/__tests__/environment.test.ts similarity index 92% rename from src/utils/__tests__/environment.test.ts rename to src/store/shared/__tests__/environment.test.ts index 7938c399c..a11ad5635 100644 --- a/src/utils/__tests__/environment.test.ts +++ b/src/store/shared/__tests__/environment.test.ts @@ -8,9 +8,9 @@ * a run with nobody to answer. */ -import { readEnvironment } from '@utils/environment'; -import { buildSession } from '@lib/wizard-session'; -import { shouldDisableAsk } from '@lib/agent/agent-runner'; +import { readEnvironment } from '../environment.js'; +import { buildSession } from '../../session/wizard-session.js'; +import { shouldDisableAsk } from '../../session/ask-policy.js'; /** Every var this file sets, cleared between cases. */ const TOUCHED = [ diff --git a/src/utils/__tests__/links.test.ts b/src/store/shared/__tests__/links.test.ts similarity index 96% rename from src/utils/__tests__/links.test.ts rename to src/store/shared/__tests__/links.test.ts index 537aac2a4..123790e19 100644 --- a/src/utils/__tests__/links.test.ts +++ b/src/store/shared/__tests__/links.test.ts @@ -1,4 +1,4 @@ -import { withUtm } from '../links'; +import { withUtm } from '../links.js'; describe('withUtm', () => { it('tags a URL with the wizard UTM params and no campaign', () => { diff --git a/src/utils/__tests__/oauth-errors.test.ts b/src/store/shared/__tests__/oauth-errors.test.ts similarity index 99% rename from src/utils/__tests__/oauth-errors.test.ts rename to src/store/shared/__tests__/oauth-errors.test.ts index 5e0068245..2b6d9f28b 100644 --- a/src/utils/__tests__/oauth-errors.test.ts +++ b/src/store/shared/__tests__/oauth-errors.test.ts @@ -6,12 +6,12 @@ import { oauthErrorFromCallbackParams, oauthErrorFromTokenBody, sanitizeOAuthParam, -} from '@utils/oauth-errors'; +} from '../oauth-errors.js'; import { ISSUES_URL, POSTHOG_STATUS_PAGE_URL, WIZARD_CONTACT_EMAIL, -} from '@lib/constants'; +} from '../constants.js'; describe('OAuthError', () => { it('keeps the exact legacy message shape so fingerprint parsing still works', () => { diff --git a/src/utils/__tests__/oauth-refresh.test.ts b/src/store/shared/__tests__/oauth-refresh.test.ts similarity index 83% rename from src/utils/__tests__/oauth-refresh.test.ts rename to src/store/shared/__tests__/oauth-refresh.test.ts index 94e775287..185c1f82a 100644 --- a/src/utils/__tests__/oauth-refresh.test.ts +++ b/src/store/shared/__tests__/oauth-refresh.test.ts @@ -1,14 +1,14 @@ import axios from 'axios'; -import { refreshAccessToken } from '@utils/oauth'; -import { POSTHOG_PROXY_CLIENT_ID } from '@lib/constants'; +import { refreshAccessToken } from '../oauth.js'; +import { POSTHOG_PROXY_CLIENT_ID } from '../constants.js'; vi.mock('axios'); // No base-URL override resolves to prod routing (kills IS_DEV's implicit localhost). -vi.mock('../urls', async (importOriginal) => ({ - ...(await importOriginal()), +vi.mock('../urls.js', async (importOriginal) => ({ + ...(await importOriginal()), resolveBaseUrl: (baseUrl?: string) => baseUrl, })); -vi.mock('../debug', () => ({ logToFile: vi.fn() })); +vi.mock('../debug.js', () => ({ logToFile: vi.fn() })); const mockedAxios = axios as Mocked; diff --git a/src/utils/__tests__/oauth-server.test.ts b/src/store/shared/__tests__/oauth-server.test.ts similarity index 96% rename from src/utils/__tests__/oauth-server.test.ts rename to src/store/shared/__tests__/oauth-server.test.ts index f5086fa04..9e3e635bc 100644 --- a/src/utils/__tests__/oauth-server.test.ts +++ b/src/store/shared/__tests__/oauth-server.test.ts @@ -1,9 +1,9 @@ import * as http from 'node:http'; import * as net from 'node:net'; -import { startCallbackServer } from '@utils/oauth'; -import { logToFile } from '../debug'; +import { startCallbackServer } from '../oauth.js'; +import { logToFile } from '../debug.js'; -vi.mock('../debug', () => ({ logToFile: vi.fn() })); +vi.mock('../debug.js', () => ({ logToFile: vi.fn() })); const authUrl = 'https://oauth.example.test/authorize'; const signupUrl = 'https://oauth.example.test/signup'; diff --git a/src/utils/__tests__/oauth.test.ts b/src/store/shared/__tests__/oauth.test.ts similarity index 98% rename from src/utils/__tests__/oauth.test.ts rename to src/store/shared/__tests__/oauth.test.ts index 6c60212ac..c5dda941f 100644 --- a/src/utils/__tests__/oauth.test.ts +++ b/src/store/shared/__tests__/oauth.test.ts @@ -5,12 +5,12 @@ import { missingOAuthScopes, OAuthTokenResponseSchema, parseOAuthScopes, -} from '@utils/oauth'; +} from '../oauth.js'; import { WIZARD_OAUTH_SCOPES, WIZARD_PROVISIONING_SCOPES, -} from '@lib/constants'; -import { getOAuthScopesForProgram } from '@lib/oauth/program-scopes'; +} from '../constants.js'; +import { getOAuthScopesForProgram } from '../../services/oauth/program-scopes.js'; describe('extractOAuthCode', () => { it('extracts the code from a full callback URL', () => { diff --git a/src/utils/__tests__/project-resolution.test.ts b/src/store/shared/__tests__/project-resolution.test.ts similarity index 95% rename from src/utils/__tests__/project-resolution.test.ts rename to src/store/shared/__tests__/project-resolution.test.ts index 2b99f8273..6dae09ddb 100644 --- a/src/utils/__tests__/project-resolution.test.ts +++ b/src/store/shared/__tests__/project-resolution.test.ts @@ -1,4 +1,4 @@ -import { resolveGrantedProject } from '@utils/project-resolution'; +import { resolveGrantedProject } from '../project-resolution.js'; describe('resolveGrantedProject', () => { // The main integration flow (and every other program) runs without --project-id; diff --git a/src/utils/__tests__/provisioning.test.ts b/src/store/shared/__tests__/provisioning.test.ts similarity index 98% rename from src/utils/__tests__/provisioning.test.ts rename to src/store/shared/__tests__/provisioning.test.ts index 052f04913..a9167ed1b 100644 --- a/src/utils/__tests__/provisioning.test.ts +++ b/src/store/shared/__tests__/provisioning.test.ts @@ -2,8 +2,8 @@ import axios from 'axios'; import { ProvisionedAccountUnreadableError, provisionNewAccount, -} from '@utils/provisioning'; -import { analytics } from '../analytics'; +} from '../provisioning.js'; +import { analytics } from '../analytics.js'; // Fixtures live outside `__tests__` on purpose: every `.ts` in there is collected as a // test suite. import { @@ -11,16 +11,16 @@ import { RESOURCE_READBACK_RESPONSE, RESOURCE_RESPONSE, TOKEN_RESPONSE, -} from '../__fixtures__/provisioning'; +} from '../__fixtures__/provisioning.js'; vi.mock('axios'); // Return the override verbatim so region-based prod routing applies (no IS_DEV // localhost); undefined means no override. -vi.mock('../urls', () => ({ +vi.mock('../urls.js', () => ({ resolveBaseUrl: (baseUrl?: string) => baseUrl, })); -vi.mock('../debug', () => ({ logToFile: vi.fn() })); -vi.mock('../analytics', () => ({ +vi.mock('../debug.js', () => ({ logToFile: vi.fn() })); +vi.mock('../analytics.js', () => ({ analytics: { captureException: vi.fn() }, })); diff --git a/src/utils/__tests__/semver.test.ts b/src/store/shared/__tests__/semver.test.ts similarity index 98% rename from src/utils/__tests__/semver.test.ts rename to src/store/shared/__tests__/semver.test.ts index ee50adfc9..4293e5f4f 100644 --- a/src/utils/__tests__/semver.test.ts +++ b/src/store/shared/__tests__/semver.test.ts @@ -1,4 +1,4 @@ -import { createVersionBucket, versionSatisfiesRange } from '@utils/semver'; +import { createVersionBucket, versionSatisfiesRange } from '../semver.js'; describe('createVersionBucket', () => { describe('without minimum threshold', () => { diff --git a/src/utils/__tests__/terminal-bell.test.ts b/src/store/shared/__tests__/terminal-bell.test.ts similarity index 96% rename from src/utils/__tests__/terminal-bell.test.ts rename to src/store/shared/__tests__/terminal-bell.test.ts index 8978162bb..bea263e82 100644 --- a/src/utils/__tests__/terminal-bell.test.ts +++ b/src/store/shared/__tests__/terminal-bell.test.ts @@ -4,7 +4,7 @@ * of it. It has to be audible to a person who stepped away, and invisible * everywhere a bell cannot ring. */ -import { ringTerminalBell } from '@utils/terminal-bell'; +import { ringTerminalBell } from '../terminal-bell.js'; const BEL = '\u0007'; diff --git a/src/utils/analytics.ts b/src/store/shared/analytics.ts similarity index 98% rename from src/utils/analytics.ts rename to src/store/shared/analytics.ts index f494fc439..969dbc3a5 100644 --- a/src/utils/analytics.ts +++ b/src/store/shared/analytics.ts @@ -4,18 +4,18 @@ import { ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, ANALYTICS_TEAM_TAG, WIZARD_FLAG_KEYS, -} from '@lib/constants'; +} from './constants.js'; import { reportableDiscoveredFeatures, reportablePosthogSdkDetected, type WizardSession, -} from '@lib/wizard-session'; -import type { ApiUser } from '@lib/api'; +} from '../session/wizard-session.js'; +import type { ApiUser } from '../api.js'; import { v4 as uuidv4 } from 'uuid'; import { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } from '@env'; -import { VERSION } from '@lib/version'; -import { debug, logToFile } from './debug'; -import { applyCiFlagOverrides } from './ci-flag-overrides'; +import { VERSION } from './version.js'; +import { debug, logToFile } from './debug.js'; +import { applyCiFlagOverrides } from './ci-flag-overrides.js'; /** * The invocation, reduced to flag-safe strings: the command word (first diff --git a/src/utils/atomic-ledger.ts b/src/store/shared/atomic-ledger.ts similarity index 100% rename from src/utils/atomic-ledger.ts rename to src/store/shared/atomic-ledger.ts diff --git a/src/utils/bounded-fs.ts b/src/store/shared/bounded-fs.ts similarity index 98% rename from src/utils/bounded-fs.ts rename to src/store/shared/bounded-fs.ts index 35e6dd55c..40fa30e49 100644 --- a/src/utils/bounded-fs.ts +++ b/src/store/shared/bounded-fs.ts @@ -7,9 +7,9 @@ import path from 'path'; import fs from 'fs'; import type { Dirent } from 'fs'; import fg from 'fast-glob'; -import { analytics } from './analytics'; -import { logToFile } from './debug'; -import type { WizardRunOptions } from './types'; +import { analytics } from './analytics.js'; +import { logToFile } from './debug.js'; +import type { WizardRunOptions } from './types.js'; /** * Errno codes that are expected while walking an arbitrary tree and mean diff --git a/src/utils/ci-flag-overrides.ts b/src/store/shared/ci-flag-overrides.ts similarity index 98% rename from src/utils/ci-flag-overrides.ts rename to src/store/shared/ci-flag-overrides.ts index 9c3864743..b555e5299 100644 --- a/src/utils/ci-flag-overrides.ts +++ b/src/store/shared/ci-flag-overrides.ts @@ -14,7 +14,7 @@ * become a production surface. */ import { runtimeEnv } from '@env'; -import { logToFile } from './debug'; +import { logToFile } from './debug.js'; export function applyCiFlagOverrides( flags: Record, diff --git a/src/utils/clipboard.ts b/src/store/shared/clipboard.ts similarity index 100% rename from src/utils/clipboard.ts rename to src/store/shared/clipboard.ts diff --git a/src/lib/constants.ts b/src/store/shared/constants.ts similarity index 99% rename from src/lib/constants.ts rename to src/store/shared/constants.ts index a0162e708..e19ef76be 100644 --- a/src/lib/constants.ts +++ b/src/store/shared/constants.ts @@ -2,7 +2,7 @@ * Shared constants for the PostHog wizard. */ -import { VERSION } from './version'; +import { VERSION } from './version.js'; // ── Models ────────────────────────────────────────────────────────── // Coordinate IDs/efforts with the mint allowlists and gateway transport/required prompt policy; see agent/runner/README.md. @@ -117,7 +117,7 @@ import { CONTEXT_MILL_LOCAL_URL, getLocalDev, POSTHOG_LOCAL_URL, -} from './local-dev'; +} from '../local-dev.js'; export { IS_DEV }; export const DEBUG = false; diff --git a/src/utils/custom-headers.ts b/src/store/shared/custom-headers.ts similarity index 100% rename from src/utils/custom-headers.ts rename to src/store/shared/custom-headers.ts diff --git a/src/utils/debug.ts b/src/store/shared/debug.ts similarity index 96% rename from src/utils/debug.ts rename to src/store/shared/debug.ts index 1081ff09a..86aee31f1 100644 --- a/src/utils/debug.ts +++ b/src/store/shared/debug.ts @@ -1,9 +1,9 @@ import { appendFileSync, mkdirSync } from 'fs'; import path from 'path'; import { inspect } from 'node:util'; -import { getUI } from '@ui'; +import { getUI } from '../ui/index.js'; import { IS_DEV, runtimeEnv } from '@env'; -import { WIZARD_LOG_FILE } from './paths'; +import { WIZARD_LOG_FILE } from './paths.js'; // Dev builds may redirect the log so concurrent runs don't interleave one file. let logFilePath = @@ -50,7 +50,7 @@ let reportedLogFailure = false; function reportLogFailureOnce(err: unknown): void { if (reportedLogFailure) return; reportedLogFailure = true; - void import('./analytics') + void import('./analytics.js') .then(({ analytics }) => analytics.captureException( err instanceof Error ? err : new Error(String(err)), diff --git a/src/utils/env-api-key.ts b/src/store/shared/env-api-key.ts similarity index 91% rename from src/utils/env-api-key.ts rename to src/store/shared/env-api-key.ts index db1becbd7..79e09f704 100644 --- a/src/utils/env-api-key.ts +++ b/src/store/shared/env-api-key.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { readProjectFile } from './bounded-fs'; +import { readProjectFile } from './bounded-fs.js'; /** * Read POSTHOG_PERSONAL_API_KEY from .env.local or .env in the current diff --git a/src/utils/env-scan.ts b/src/store/shared/env-scan.ts similarity index 99% rename from src/utils/env-scan.ts rename to src/store/shared/env-scan.ts index 866b9826b..3481db63a 100644 --- a/src/utils/env-scan.ts +++ b/src/store/shared/env-scan.ts @@ -18,7 +18,7 @@ */ import path from 'path'; -import { walkProjectFiles, safeReadFile } from './bounded-fs'; +import { walkProjectFiles, safeReadFile } from './bounded-fs.js'; /** * Directory levels below the install dir that an env scan descends. Bounds the diff --git a/src/utils/environment.ts b/src/store/shared/environment.ts similarity index 94% rename from src/utils/environment.ts rename to src/store/shared/environment.ts index 58589c869..7ac24e30c 100644 --- a/src/utils/environment.ts +++ b/src/store/shared/environment.ts @@ -4,10 +4,10 @@ const readEnv = typeof readEnvModule === 'function' ? readEnvModule : (readEnvModule as any).default; -import { tryGetPackageJson } from './setup-utils'; -import type { WizardRunOptions } from './types'; -import { boundedGlob } from './bounded-fs'; -import { IS_DEV } from '@lib/constants'; +import { tryGetPackageJson } from './setup-utils.js'; +import type { WizardRunOptions } from './types.js'; +import { boundedGlob } from './bounded-fs.js'; +import { IS_DEV } from './constants.js'; export function isNonInteractiveEnvironment(): boolean { if (IS_DEV) { diff --git a/src/lib/errors/__tests__/auth.test.ts b/src/store/shared/errors/__tests__/auth.test.ts similarity index 94% rename from src/lib/errors/__tests__/auth.test.ts rename to src/store/shared/errors/__tests__/auth.test.ts index 085cfbc71..9021d5bbe 100644 --- a/src/lib/errors/__tests__/auth.test.ts +++ b/src/store/shared/errors/__tests__/auth.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { classifyAuthFailure } from '../auth'; -import { ErrorCodes } from '../codes'; +import { classifyAuthFailure } from '../auth.js'; +import { ErrorCodes } from '../codes.js'; describe('classifyAuthFailure', () => { it('falls back to invalid-or-expired when nothing is known', () => { diff --git a/src/lib/errors/__tests__/codes.test.ts b/src/store/shared/errors/__tests__/codes.test.ts similarity index 97% rename from src/lib/errors/__tests__/codes.test.ts rename to src/store/shared/errors/__tests__/codes.test.ts index 0a49a4ace..36870d658 100644 --- a/src/lib/errors/__tests__/codes.test.ts +++ b/src/store/shared/errors/__tests__/codes.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { ErrorCodes, ERROR_CODE_PATTERN, isErrorCode } from '../codes'; -import { ERROR_CATALOG } from '../catalog'; +import { ErrorCodes, ERROR_CODE_PATTERN, isErrorCode } from '../codes.js'; +import { ERROR_CATALOG } from '../catalog.js'; describe('error codes', () => { it('every code matches the PHW pattern', () => { diff --git a/src/lib/errors/__tests__/detect-map.test.ts b/src/store/shared/errors/__tests__/detect-map.test.ts similarity index 95% rename from src/lib/errors/__tests__/detect-map.test.ts rename to src/store/shared/errors/__tests__/detect-map.test.ts index 28d12cac7..a9580656d 100644 --- a/src/lib/errors/__tests__/detect-map.test.ts +++ b/src/store/shared/errors/__tests__/detect-map.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { ErrorCodes } from '../codes'; -import { ERROR_CATALOG } from '../catalog'; -import { detectErrorCode, type DetectErrorKind } from '../detect-map'; +import { ErrorCodes } from '../codes.js'; +import { ERROR_CATALOG } from '../catalog.js'; +import { detectErrorCode, type DetectErrorKind } from '../detect-map.js'; /** * Every kind the programs can emit. `DetectErrorKind` is derived from their diff --git a/src/lib/errors/__tests__/run-failure.test.ts b/src/store/shared/errors/__tests__/run-failure.test.ts similarity index 82% rename from src/lib/errors/__tests__/run-failure.test.ts rename to src/store/shared/errors/__tests__/run-failure.test.ts index 3d9c30091..9de9c394c 100644 --- a/src/lib/errors/__tests__/run-failure.test.ts +++ b/src/store/shared/errors/__tests__/run-failure.test.ts @@ -1,10 +1,9 @@ import { describe, expect, it } from 'vitest'; -import { classifyRunFailure } from '../run-failure'; -import { ErrorCodes } from '../codes'; -import { WizardError } from '@utils/wizard-abort'; -import { GatewayMintRefused } from '@lib/gateway-session'; +import { classifyRunFailure } from '../run-failure.js'; +import { ErrorCodes } from '../codes.js'; +import { WizardError } from '../../wizard-abort.js'; -vi.mock('@utils/analytics', () => ({ +vi.mock('../../analytics.js', () => ({ analytics: { wizardCapture: vi.fn(), captureException: vi.fn() }, })); @@ -12,7 +11,9 @@ describe('classifyRunFailure', () => { it('keeps a mint refusal as its own code and message', () => { // The runners print this message alone, without the unhandled framing. const failure = classifyRunFailure( - new GatewayMintRefused(403, 'This account is blocked.', 'blocked'), + Object.assign(new Error('This account is blocked.'), { + code: ErrorCodes.GatewayMintRefused, + }), ); expect(failure).toEqual({ code: ErrorCodes.GatewayMintRefused, diff --git a/src/lib/errors/__tests__/sanitize.test.ts b/src/store/shared/errors/__tests__/sanitize.test.ts similarity index 94% rename from src/lib/errors/__tests__/sanitize.test.ts rename to src/store/shared/errors/__tests__/sanitize.test.ts index 464acad8a..af38235f8 100644 --- a/src/lib/errors/__tests__/sanitize.test.ts +++ b/src/store/shared/errors/__tests__/sanitize.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { sanitizeErrorDetail } from '../sanitize'; +import { sanitizeErrorDetail } from '../sanitize.js'; describe('sanitizeErrorDetail', () => { it('keeps allowlisted fields', () => { diff --git a/src/lib/errors/agent-map.ts b/src/store/shared/errors/agent-map.ts similarity index 81% rename from src/lib/errors/agent-map.ts rename to src/store/shared/errors/agent-map.ts index c795f0e5b..2b5919443 100644 --- a/src/lib/errors/agent-map.ts +++ b/src/store/shared/errors/agent-map.ts @@ -1,5 +1,5 @@ -import { AgentErrorType } from '@lib/agent-signals'; -import { ErrorCodes, type ErrorCode } from './codes'; +import { AgentErrorType } from '../../agent-protocol/agent-signals.js'; +import { ErrorCodes, type ErrorCode } from './codes.js'; export const AGENT_ERROR_CODE: Record = { [AgentErrorType.MCP_MISSING]: ErrorCodes.AgentMcpMissing, diff --git a/src/lib/errors/auth.ts b/src/store/shared/errors/auth.ts similarity index 95% rename from src/lib/errors/auth.ts rename to src/store/shared/errors/auth.ts index 243dc9067..f70637b97 100644 --- a/src/lib/errors/auth.ts +++ b/src/store/shared/errors/auth.ts @@ -1,4 +1,4 @@ -import { ErrorCodes, type ErrorCode } from './codes'; +import { ErrorCodes, type ErrorCode } from './codes.js'; export interface AuthFailureInput { hasSettingsConflict?: boolean; diff --git a/src/lib/errors/catalog.ts b/src/store/shared/errors/catalog.ts similarity index 98% rename from src/lib/errors/catalog.ts rename to src/store/shared/errors/catalog.ts index e49be2929..166c4e90f 100644 --- a/src/lib/errors/catalog.ts +++ b/src/store/shared/errors/catalog.ts @@ -1,5 +1,5 @@ -import { ErrorCodes, type ErrorCode } from './codes'; -import type { ErrorCatalogEntry } from './types'; +import { ErrorCodes, type ErrorCode } from './codes.js'; +import type { ErrorCatalogEntry } from './types.js'; export const ERROR_CATALOG: Record = { [ErrorCodes.CliNodeVersion]: { diff --git a/src/lib/errors/codes.ts b/src/store/shared/errors/codes.ts similarity index 100% rename from src/lib/errors/codes.ts rename to src/store/shared/errors/codes.ts diff --git a/src/lib/errors/detect-map.ts b/src/store/shared/errors/detect-map.ts similarity index 78% rename from src/lib/errors/detect-map.ts rename to src/store/shared/errors/detect-map.ts index b632966ac..9721ec515 100644 --- a/src/lib/errors/detect-map.ts +++ b/src/store/shared/errors/detect-map.ts @@ -1,9 +1,9 @@ -import { ErrorCodes, type ErrorCode } from './codes'; -import type { RevenueDetectError } from '@lib/programs/revenue-analytics/detect'; -import type { SelfDrivingDetectError } from '@lib/programs/self-driving/detect'; -import type { SourceMapsDetectError } from '@lib/programs/error-tracking-upload-source-maps/detect'; -import type { WarehouseDetectError } from '@lib/programs/warehouse-source/detect'; -import type { WebAnalyticsDetectError } from '@lib/programs/web-analytics-doctor/detect'; +import { ErrorCodes, type ErrorCode } from './codes.js'; +import type { RevenueDetectError } from '../../programs/revenue-analytics/detect.js'; +import type { SelfDrivingDetectError } from '../../programs/self-driving/detect.js'; +import type { SourceMapsDetectError } from '../../programs/error-tracking-upload-source-maps/detect.js'; +import type { WarehouseDetectError } from '../../programs/warehouse-source/detect.js'; +import type { WebAnalyticsDetectError } from '../../programs/web-analytics-doctor/detect.js'; /** * Every `kind` a program detect step can write into diff --git a/src/lib/errors/emit.ts b/src/store/shared/errors/emit.ts similarity index 90% rename from src/lib/errors/emit.ts rename to src/store/shared/errors/emit.ts index 4fcae6d9f..046f4893c 100644 --- a/src/lib/errors/emit.ts +++ b/src/store/shared/errors/emit.ts @@ -1,4 +1,4 @@ -import type { ErrorCode } from './codes'; +import type { ErrorCode } from './codes.js'; export const PHW_ERROR_PREFIX = 'phw-error:'; diff --git a/src/lib/errors/index.ts b/src/store/shared/errors/index.ts similarity index 60% rename from src/lib/errors/index.ts rename to src/store/shared/errors/index.ts index 5558c7942..842455bdc 100644 --- a/src/lib/errors/index.ts +++ b/src/store/shared/errors/index.ts @@ -3,18 +3,18 @@ export { ERROR_CODE_PATTERN, isErrorCode, type ErrorCode, -} from './codes'; -export { ERROR_CATALOG } from './catalog'; -export type { ErrorCatalogEntry, ErrorGroup, RetryAdvice } from './types'; -export { classifyAuthFailure, type AuthFailureInput } from './auth'; -export { AGENT_ERROR_CODE } from './agent-map'; -export { detectErrorCode, type DetectErrorKind } from './detect-map'; -export { skillErrorCode } from './skill-map'; +} from './codes.js'; +export { ERROR_CATALOG } from './catalog.js'; +export type { ErrorCatalogEntry, ErrorGroup, RetryAdvice } from './types.js'; +export { classifyAuthFailure, type AuthFailureInput } from './auth.js'; +export { AGENT_ERROR_CODE } from './agent-map.js'; +export { detectErrorCode, type DetectErrorKind } from './detect-map.js'; +export { skillErrorCode } from './skill-map.js'; export { PHW_ERROR_PREFIX, emitWizardError, formatWizardErrorLine, type WizardErrorLine, -} from './emit'; -export { sanitizeErrorDetail } from './sanitize'; -export { classifyRunFailure, type RunFailure } from './run-failure'; +} from './emit.js'; +export { sanitizeErrorDetail } from './sanitize.js'; +export { classifyRunFailure, type RunFailure } from './run-failure.js'; diff --git a/src/lib/errors/run-failure.ts b/src/store/shared/errors/run-failure.ts similarity index 99% rename from src/lib/errors/run-failure.ts rename to src/store/shared/errors/run-failure.ts index 8ad3b0f20..3a958f639 100644 --- a/src/lib/errors/run-failure.ts +++ b/src/store/shared/errors/run-failure.ts @@ -1,4 +1,4 @@ -import { ErrorCodes, isErrorCode, type ErrorCode } from './codes'; +import { ErrorCodes, isErrorCode, type ErrorCode } from './codes.js'; export interface RunFailure { code: ErrorCode; diff --git a/src/lib/errors/sanitize.ts b/src/store/shared/errors/sanitize.ts similarity index 100% rename from src/lib/errors/sanitize.ts rename to src/store/shared/errors/sanitize.ts diff --git a/src/lib/errors/skill-map.ts b/src/store/shared/errors/skill-map.ts similarity index 77% rename from src/lib/errors/skill-map.ts rename to src/store/shared/errors/skill-map.ts index 1bca38eef..10cd219f9 100644 --- a/src/lib/errors/skill-map.ts +++ b/src/store/shared/errors/skill-map.ts @@ -1,5 +1,5 @@ -import { ErrorCodes, type ErrorCode } from './codes'; -import type { InstallSkillResult } from '@lib/wizard-tools'; +import { ErrorCodes, type ErrorCode } from './codes.js'; +import type { InstallSkillResult } from '../../tools/index.js'; const SKILL_CODES: Record< Exclude, diff --git a/src/lib/errors/types.ts b/src/store/shared/errors/types.ts similarity index 100% rename from src/lib/errors/types.ts rename to src/store/shared/errors/types.ts diff --git a/src/lib/headless-mode.ts b/src/store/shared/headless-mode.ts similarity index 97% rename from src/lib/headless-mode.ts rename to src/store/shared/headless-mode.ts index 20f3c4f05..4925e83c1 100644 --- a/src/lib/headless-mode.ts +++ b/src/store/shared/headless-mode.ts @@ -16,12 +16,13 @@ */ import type { Options } from 'yargs'; +import { HEADLESS_FLAG } from '@env'; /** * The on-CLI flag name. Intentionally ugly + undocumented; do not surface it in * `--help`, the README, or user-facing error messages. */ -export const HEADLESS_FLAG = 'headless-DONOTUSE-EXPERIMENTAL'; +export { HEADLESS_FLAG }; /** * The yargs option declaration for the headless flag. Declared per-command diff --git a/src/utils/links.ts b/src/store/shared/links.ts similarity index 98% rename from src/utils/links.ts rename to src/store/shared/links.ts index 14be27b4b..85fecaa02 100644 --- a/src/utils/links.ts +++ b/src/store/shared/links.ts @@ -8,7 +8,7 @@ */ import opn from 'opn'; import { NODE_ENV } from '@env'; -import { analytics } from './analytics'; +import { analytics } from './analytics.js'; /** * Record the CLI command this run was started with (e.g. `integrate`, diff --git a/src/utils/oauth-errors.ts b/src/store/shared/oauth-errors.ts similarity index 99% rename from src/utils/oauth-errors.ts rename to src/store/shared/oauth-errors.ts index e95f7f751..5644e6ef2 100644 --- a/src/utils/oauth-errors.ts +++ b/src/store/shared/oauth-errors.ts @@ -14,7 +14,7 @@ import { ISSUES_URL, POSTHOG_STATUS_PAGE_URL, WIZARD_CONTACT_EMAIL, -} from '@lib/constants'; +} from './constants.js'; /** * A structured OAuth failure (RFC 6749 §4.1.2.1 authorize errors, §5.2 token diff --git a/src/utils/oauth.ts b/src/store/shared/oauth.ts similarity index 98% rename from src/utils/oauth.ts rename to src/store/shared/oauth.ts index 0fc53e78f..7cf81fe11 100644 --- a/src/utils/oauth.ts +++ b/src/store/shared/oauth.ts @@ -2,27 +2,27 @@ import * as crypto from 'node:crypto'; import * as http from 'node:http'; import { execSync } from 'node:child_process'; import axios from 'axios'; -import { logToFile } from './debug'; +import { logToFile } from './debug.js'; import { z } from 'zod'; -import { getUI } from '@ui'; +import { getUI } from '../ui/index.js'; import { OAUTH_PORTS, OAUTH_TIMEOUT_MS, POSTHOG_DEV_CLIENT_ID, POSTHOG_PROXY_CLIENT_ID, WIZARD_USER_AGENT, -} from '@lib/constants'; -import { getOAuthUrl, resolveBaseUrl } from './urls'; -import { abort } from './setup-utils'; -import { openTrackedLink, withUtm } from './links'; -import { analytics } from './analytics'; +} from './constants.js'; +import { getOAuthUrl, resolveBaseUrl } from './urls.js'; +import { abort } from './setup-utils.js'; +import { openTrackedLink, withUtm } from './links.js'; +import { analytics } from './analytics.js'; import { OAuthError, buildCallbackErrorHtml, buildOAuthFailureMessage, oauthErrorFromCallbackParams, oauthErrorFromTokenBody, -} from './oauth-errors'; +} from './oauth-errors.js'; const OAUTH_CALLBACK_STYLES = `