Skip to content

chore(surfaces): WIP split the tree into store, agent, tui, and cli - #1276

Closed
gewenyu99 wants to merge 5 commits into
posthog/split-p2-storefrom
posthog/split-p3-moves
Closed

gewenyu99 wants to merge 5 commits into
posthog/split-p2-storefrom
posthog/split-p3-moves

Conversation

@gewenyu99

Copy link
Copy Markdown
Collaborator

Move the tree into src/store, src/agent, src/tui, and src/cli, and enforce the boundaries.

Cross-surface imports go only through @store, @store/types, @store/programs, @agent, @agent/types, @tui, @tui/types, and @tui/console. The architecture suite enforces the matrix with no allowlist, tsc -b project references and per-surface Vitest projects mirror it, and each surface carries a contract test and a testing/ double. Goldens are byte identical to the P0 baselines. Stacked on #1271.


Created with PostHog Desktop

Every module moves under its surface: src/agent (runner, harnesses,
switchboard, gateway, security adapters, tool facades), src/store (state,
session, programs, tools, detection, frameworks, services, shared), src/tui
(everything Ink plus console renderers and program content), src/cli
(entry, commands, runners). Same-surface imports are relative; cross-surface
imports use the surface aliases @store/*, @agent/*, @tui/*, @cli/*. Vitest
projects and the boundary classifier follow the new directories; env.ts owns
the headless flag literal. Goldens are byte identical; 19 cross-surface edges
remain seeded for the next commit.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
Relocate authenticate, headless-mode, telemetry, yara hooks and policy,
agent-phase, and self-driving pricing into the store; dispatch-family into
the cli. The detection agent and the MCP prompt runner are installed from
the entry point, the tools barrel no longer reaches the MCP facade, and the
family picker takes a generic child shape. known-violations.json is empty.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
…rce them

Every import between store, agent, tui, and cli goes through the surface's
index.ts, types.ts, or a secondary barrel (@store/programs, @tui/console).
The boundary test enforces the matrix and the public entries with no
allowlist; tsc -b project references, per-project Vitest ink aliases, and
ESLint no-restricted-imports mirror it. bin.ts runs the Node preflight and
then imports src/cli/main.ts, which installs the renderer, the detection
agent, and the MCP prompt runner lazily so no command loads Ink or the agent
SDK before it runs. Tests that reached across surfaces moved to the surface
they exercise; docs point at the new paths.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
…ntracts

Each surface owns a vitest.config.ts built from vitest.shared.ts that resolves
only the surfaces it may import and forbids ink outside the tui and the
harness. Tests move to the surface whose code they exercise. Every surface
gains a contract test and a testing/ double: StoreUI and NullUI implement
WizardUI, ProgramConfig extends ProgramRunConfig, runConfigFor emits only the
run contract, both harnesses and FakeAgentHarness implement AgentHarness,
runAgent is the RunAgent entry, the console renderers are non-interactive
WizardUI implementations, UiStore satisfies UiStoreApi, and every command has
a unique key. The architecture suite snapshots the names each surface consumes
from another and derives the WizardStore members the tui, cli, and harness
touch, which must equal STORE_BOUNDARY_MEMBERS.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
@github-actions

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci ai-observability
  • /wizard-ci basic-integration
  • /wizard-ci mcp-analytics
  • /wizard-ci replay-vision
  • /wizard-ci revenue
  • /wizard-ci self-driving
  • /wizard-ci warehouse
  • /wizard-ci warehouse-seeded

Test an individual app:

  • /wizard-ci ai-observability/anthropic
  • /wizard-ci ai-observability/google-adk
  • /wizard-ci ai-observability/groq
Show more apps
  • /wizard-ci ai-observability/manual-capture
  • /wizard-ci ai-observability/openai
  • /wizard-ci ai-observability/openai-agents
  • /wizard-ci ai-observability/opentelemetry
  • /wizard-ci ai-observability/vercel-ai
  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/flutter
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci replay-vision/javascript-node
  • /wizard-ci replay-vision/next-js
  • /wizard-ci replay-vision/react-vite
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit
  • /wizard-ci warehouse/monorepo-env
  • /wizard-ci warehouse/multi-source-next
  • /wizard-ci warehouse/stripe-node
  • /wizard-ci warehouse/zero-source
  • /wizard-ci warehouse-seeded/next-stripe
  • /wizard-ci warehouse-seeded/next-stripe-declined

Test against a Context Mill branch:

  • /wizard-ci all context-mill:my-branch

Add context-mill:<branch> to any command above to pin the Context Mill branch. It defaults to main.

Results will be posted here when complete.

The composite surface projects resolve cross-surface imports through built
declarations, so lint saw `any` until `tsc -b` had run and CI reported errors
that vanish with types present. Boundaries stay enforced by tsc -b and the
architecture suite.

Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
@gewenyu99

gewenyu99 commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Surfaces: why each piece exists

Top to bottom is the import direction. A surface sees only the public entries of the layer below; instances cross the other way by injection. The three numbered ways in mark where you start for the full TUI [1], a headless workflow [2], and one agent run alone [3]; dashed lines lead to the cards each way reaches.

flowchart TB
  classDef wave_entry fill:#fff8e6,stroke:#d9a400,stroke-width:2px,color:#d9a400;
  classDef card_entry fill:#fff1c7,stroke:#d9a400,stroke-width:1px,color:#1d1d1f;
  classDef wave_cli fill:#fff1e8,stroke:#e8632c,stroke-width:2px,color:#e8632c;
  classDef card_cli fill:#ffe1cc,stroke:#e8632c,stroke-width:1px,color:#1d1d1f;
  classDef wave_tui fill:#e9f0ff,stroke:#2f6fed,stroke-width:2px,color:#2f6fed;
  classDef card_tui fill:#d6e4ff,stroke:#2f6fed,stroke-width:1px,color:#1d1d1f;
  classDef wave_agent fill:#f1e9ff,stroke:#7a3fe0,stroke-width:2px,color:#7a3fe0;
  classDef card_agent fill:#e6d8ff,stroke:#7a3fe0,stroke-width:1px,color:#1d1d1f;
  classDef wave_store fill:#e8f8ee,stroke:#1f9d55,stroke-width:2px,color:#1f9d55;
  classDef card_store fill:#d4f2df,stroke:#1f9d55,stroke-width:1px,color:#1d1d1f;
  classDef wave_control fill:#e4f5f3,stroke:#148f7a,stroke-width:2px,color:#148f7a;
  classDef card_control fill:#cfeeea,stroke:#148f7a,stroke-width:1px,color:#1d1d1f;
  classDef wave_harness fill:#f2f2f2,stroke:#6e6e73,stroke-width:2px,color:#6e6e73;
  classDef card_harness fill:#e6e6e6,stroke:#6e6e73,stroke-width:1px,color:#1d1d1f;
  classDef wave_guard fill:#fbe9e7,stroke:#c0392b,stroke-width:2px,color:#c0392b;
  classDef card_guard fill:#f8d7d2,stroke:#c0392b,stroke-width:1px,color:#1d1d1f;
  subgraph E1["THREE WAYS IN: how much of the tree each job needs"]
    direction LR
    E1C1("<b>[1] run the full thing</b><br/>npx @posthog/wizard [command]: bin.ts, @cli/main,<br/>dispatchProgram, run-wizard.ts; the TUI chains one<br/>startRun + runAgent per flow step")
    E1C2("<b>[2] run a workflow headlessly</b><br/>wizard [command] --headless-DONOTUSE-EXPERIMENTAL<br/>--api-key --project-id --install-dir: run-non-interactive.ts<br/>FlowStore + HeadlessUI, detect, one runAgent, outro to the log<br/>+ --control-socket: POST /detect, POST /runs, POST /shutdown")
    E1C3("<b>[3] run just an agent</b><br/>in process: runAgent(runConfigFor(config), session) from<br/>@agent; no flow, no screens. Over the socket (headless<br/>surface): POST /runs programId = one run on a fresh RunStore")
    E1C1 ~~~ E1C2 ~~~ E1C3
  end
  class E1 wave_entry
  class E1C1,E1C2,E1C3 card_entry
  subgraph W1["ENTRY: start the process without loading any surface"]
    direction LR
    W1C1("<b>bin.ts  [1]</b><br/>checks Node, then hands off to the composition<br/>root; nothing else may be the npm entry")
    W1C2("<b>src/env.ts</b><br/>build-time constants every surface may read,<br/>so no surface imports another just for them")
    W1C1 ~~~ W1C2
  end
  class W1 wave_entry
  class W1C1,W1C2 card_entry
  subgraph W2["src/cli: the one place that knows all three surfaces"]
    direction LR
    W2C1("<b>main.ts</b><br/>installs the console renderer and the seams<br/>before any command runs")
    W2C2("<b>wizard.ts + commands/  [2]</b><br/>turns argv into one surface choice:<br/>TUI, headless, or controlled by a parent")
    W2C3("<b>runners/  [1] [2]</b><br/>sequence independent agent runs and pass<br/>context between them; nothing below composes")
    W2C4("<b>control-hooks.ts  [3]</b><br/>what a parent may ask this process to do<br/>that the store cannot (P4)")
    W2C1 ~~~ W2C2 ~~~ W2C3 ~~~ W2C4
  end
  class W2 wave_cli
  class W2C1,W2C2,W2C3,W2C4 card_cli
  subgraph W3["src/tui and src/agent: never import each other, never share a helper"]
    direction LR
    W3C1("<b>src/tui</b><br/>renders the flow store and the run it mirrors;<br/>UiStore holds presentation state on top")
    W3C2("<b>src/agent  [3]</b><br/>runs one program; speaks to whoever renders<br/>through WizardUI, never to a screen")
    W3C1 ~~~ W3C2
  end
  class W3 wave_tui
  class W3C1,W3C2 card_tui
  subgraph W4["src/store: one run's truth, the flow above it, product knowledge as data, no rendering"]
    direction LR
    W4C1("<b>state/  RunStore + FlowStore</b><br/>one run's state, and the flow that chains runs on<br/>top; the active screen is derived, never navigated to")
    W4C2("<b>ui/  WizardUI</b><br/>the agent's whole vocabulary toward a renderer:<br/>StoreUI commits, LoggingUI prints, NullUI is silent")
    W4C3("<b>task-stream/</b><br/>publishes the run state outward, store-level<br/>and renderer-blind")
    W4C4("<b>programs/</b><br/>what to run and what to show, as data;<br/>the registry never touches Ink")
    W4C5("<b>services · tools · detection</b><br/>the wizard's capabilities, product-blind<br/>and renderer-blind")
    W4C6("<b>control/  [2] [3]</b><br/>the store put on a socket for parents and<br/>CI (P4)")
    W4C1 ~~~ W4C2 ~~~ W4C3 ~~~ W4C4 ~~~ W4C5 ~~~ W4C6
  end
  class W4 wave_store
  class W4C1,W4C2,W4C3,W4C4,W4C5,W4C6 card_store
  subgraph W5["ENFORCEMENT: three checks, all required"]
    direction LR
    W5C1("<b>tsc -b</b><br/>a deep import fails to compile: each surface<br/>references only the surfaces it may import")
    W5C2("<b>src/__tests__/architecture</b><br/>the import matrix, public entries, shape files,<br/>startup graph, and consumed names as goldens")
    W5C3("<b>smoke-test.sh + chunk manifest</b><br/>the published TUI never carries the control<br/>server; CI diffs the chunk groups")
    W5C1 ~~~ W5C2 ~~~ W5C3
  end
  class W5 wave_guard
  class W5C1,W5C2,W5C3 card_guard
  W1 -->|"import('@cli/main')  the only import bin.ts makes"| W2
  W2 -->|"setUI(StoreUI) · startTUI · runAgent · attachControlServer<br/>instances cross by injection, never by import"| W3
  W3 -->|"FlowStoreApi (tui reads and commits) · WizardUI + ProgramRunConfig (agent reads and reports)<br/>both import only @store, @store/types, @store/programs"| W4
  W4 -->|"a boundary cannot drift in one place alone"| W5
  E1 -.->|"[1] npx @posthog/wizard → bin.ts"| W1
  E1 -.->|"[1] dispatchProgram → run-wizard.ts: startTUI, then startRun + runAgent per step"| W2
  E1 -.->|"[2] --headless-DONOTUSE-EXPERIMENTAL → dispatchProgram → run-non-interactive.ts"| W2
  E1 -.->|"[3] POST /runs programId → control-hooks.ts startRun: fresh RunStore, one run"| W2
  E1 -.->|"[3] runAgent(runConfigFor(config), session): one run, nothing else loaded"| W3
  E1 -.->|"[2] [3] + --control-socket → control/: POST /detect, POST /runs, POST /shutdown"| W4
  linkStyle 18 stroke:#2f6fed,stroke-width:2px,stroke-dasharray:6 4;
  linkStyle 19 stroke:#2f6fed,stroke-width:2px,stroke-dasharray:6 4;
  linkStyle 20 stroke:#e8632c,stroke-width:2px,stroke-dasharray:6 4;
  linkStyle 21 stroke:#7a3fe0,stroke-width:2px,stroke-dasharray:6 4;
  linkStyle 22 stroke:#7a3fe0,stroke-width:2px,stroke-dasharray:6 4;
  linkStyle 23 stroke:#e8632c,stroke-width:2px,stroke-dasharray:6 4;
Loading

Interfaces, one sheet each

┌─ THREE WAYS IN ──────────────────────────────────────────────────────────────────────────────┐
│ the same store and agent, a different amount of the tree                                     │
│                                                                                              │
│ [1] full      npx @posthog/wizard [command]   bin.ts → @cli/main → dispatchProgram →         │
│   run-wizard.ts                                                                              │
│ [2] headless  wizard [command] --headless-DONOTUSE-EXPERIMENTAL --api-key … --project-id …   │
│               → run-non-interactive.ts;  + --control-socket <path>: POST /detect · POST      │
│   /runs                                                                                      │
│                 { programId, installDir?, frameworkContext?, skillId? } · GET /runs · POST   │
│   /shutdown                                                                                  │
│ [3] agent     runAgent(runConfigFor(config), session) from @agent, or POST /runs on the      │
│   headless surface                                                                           │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · [1] chains runs: one startRun + runAgent per flow step; gates and screens come from the    │
│   flow                                                                                       │
│ · [2] registers the same flow into a headless FlowStore; HeadlessUI resolves gates at once;  │
│   detect, one run                                                                            │
│ · [3] is one run: no flow steps, no screens; needs a session with credentials and a WizardUI │
│   installed                                                                                  │
│   (cli/main.ts installs LoggingUI; startTUI installs StoreUI); over the socket it gets a     │
│   fresh RunStore                                                                             │
│ · POST /run on the TUI surface is not [3]: it releases the launched program's own run; /runs │
│   is 501 there                                                                               │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ PUBLIC ENTRIES ─────────────────────────────────────────────────────────────────────────────┐
│ the only cross-surface import targets                                                        │
│                                                                                              │
│ @store            src/store/index.ts           runtime API          from: agent, tui, cli,   │
│   harness                                                                                    │
│ @store/types      src/store/types.ts           shapes, type-only    from: agent, tui, cli,   │
│   harness                                                                                    │
│ @store/programs   src/store/programs/index.ts  registry, flowFor    from: agent, tui, cli,   │
│   harness                                                                                    │
│ @store/control    src/store/control/index.ts   control API          from: cli (dynamic       │
│   import only)                                                                               │
│ @agent            src/agent/index.ts           runAgent             from: cli                │
│ @agent/types      src/agent/types.ts           RunAgent, harness    from: cli                │
│ @tui  @tui/types  src/tui/index.ts, types.ts   startTUI, ScreenId   from: cli, harness       │
│   (types)                                                                                    │
│ @tui/console      src/tui/console/index.ts     LoggingUI, HeadlessUI  from: cli              │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · a deep import (e.g. @store/state/store) across surfaces fails tsc -b, the architecture     │
│   test, and lint                                                                             │
│ · store never imports agent, tui, or cli; agent and tui never import each other or cli       │
│ · instances cross by injection: setUI(ui), new FlowStore(flow), flow.startRun(session),      │
│   runAgent, hooks                                                                            │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ WizardUI ───────────────────────────────────────────────────────────────────────────────────┐
│ src/store/ui/wizard-ui.ts · what the agent and services call, whoever renders                │
│                                                                                              │
│ readonly interactive: boolean    + 46 methods: status, spinners, tasks, token usage, outro,  │
│ requestQuestion, showTaskNotice, waitForGate, waitForAiOptIn, onEnterScreen, …               │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · getUI() / setUI(): the store owns the accessor; cli installs LoggingUI at start, StoreUI   │
│   for a TUI                                                                                  │
│ · StoreUI (interactive: true) commits to the store; LoggingUI, HeadlessUI (false) print;     │
│   NullUI is silent                                                                           │
│ · the agent never imports a renderer; a control socket and a keyboard answer the same calls  │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ FlowStoreApi ───────────────────────────────────────────────────────────────────────────────┐
│ src/store/state/store-api.ts · what tui, cli, and the harness may touch                      │
│                                                                                              │
│ FlowStoreApi = Pick<FlowStore, StoreBoundaryMember>    STORE_BOUNDARY_MEMBERS: 63 names      │
│ FlowStore.startRun(session) → RunStore   the one store an agent run, its stream, and StoreUI │
│   write to                                                                                   │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · the architecture test derives real usage with the TS checker and fails when the list       │
│   drifts                                                                                     │
│ · widening the boundary is an explicit edit here, reviewed like any API change               │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ RunAgent · ProgramRunConfig ────────────────────────────────────────────────────────────────┐
│ src/agent/types.ts, src/store/agent-protocol/program-run.ts                                  │
│                                                                                              │
│ RunAgent = (config: ProgramRunConfig, session: WizardSession, opts?: { composed?: boolean }) │
│   => Promise<void>                                                                           │
│ ProgramRunConfig: id · run · agentFlow · skillId · requiresAi · seedTasks · reportFile ·     │
│   eventPlanFile ·                                                                            │
│   auditLedgerFile · streamWorkflowId · allowedTools · disallowedTools · postAuthGateIds      │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · one call = one independent run; composition (which run after which, with what context)     │
│   lives in cli                                                                               │
│ · runConfigFor(config) picks exactly the fields the agent reads; the agent never sees steps  │
│   or screens                                                                                 │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ Flow · FlowStep ────────────────────────────────────────────────────────────────────────────┐
│ src/store/state/flow.ts · a program's screens as data                                        │
│                                                                                              │
│ Flow { programId, skillId, steps: FlowStep[] }                                               │
│ FlowStep { id, label, screenId?, show?, isComplete?, gate?, onInit?, onReady?,               │
│   controlActions? }                                                                          │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · resolveActiveScreen(flow, session, interrupts) picks the screen; no imperative navigation  │
│   anywhere                                                                                   │
│ · screenId is an opaque flow key the TUI maps to a component; the same key is the analytics  │
│   name                                                                                       │
│ · controlActions declare the socket commits a program screen offers (P4)                     │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
┌─ startTUI · TuiHandle ───────────────────────────────────────────────────────────────────────┐
│ src/tui/start-tui.ts · the only way cli reaches Ink                                          │
│                                                                                              │
│ startTUI(version, program) → TuiHandle { unmount(), store, waitForSetup() }                  │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ · the TUI builds the store from flowFor(program) and hands it back; cli installs StoreUI on  │
│   it and runs the flow                                                                       │
│ · the TUI renders and commits; it never runs agents and never imports @agent                 │
│ · TUI_ENTRY_MARKER survives bundling so the smoke test can prove the control chunk is not    │
│   imported                                                                                   │
└──────────────────────────────────────────────────────────────────────────────────────────────┘

Evidence: basic integration through the snapshot path (P3 tree)

Run on 2026-09-19 against a throwaway copy of wizard-workbench/apps/basic-integration/javascript-node/express-todo, PostHog project 228144, with the issued gateway bearer from WIZARD_CI_GATEWAY_TOKEN_FILE (no mint). The route at this phase is still the in-process host that P5 replaces.

PROGRAM=posthog-integration E2E_ASK=true WIZARD_CI_GATEWAY_TOKEN_FILE=… POSTHOG_KEY_FILE=… \
PROJECT_ID=228144 POSTHOG_REGION=us APP_DIR=/tmp/wizard-e2e-express-todo SNAP_OUT=/tmp/wz-snaps-p3 \
npx tsx scripts/tui-snapshots.no-jest.ts

Result: 25 frames, screen path intro → auth → run → outro → mcp → slack-connect → keep-skills. Every transition frame is byte identical to the main baseline after stripping ANSI, except the outro's dashboard and notebook ids, which the run creates.

Frames
01-intro.ans
02-auth.ans
03-run.ans
04-run.ans
05-run.ans
06-run.ans
07-run.ans
08-run.ans
09-run.ans
10-run.ans
11-run.ans
12-run.ans
13-run.ans
14-run.ans
15-run.ans
16-run.ans
17-run.ans
18-run.ans
19-run.ans
20-run.ans
21-outro.ans
22-outro.ans
23-mcp.ans
24-slack-connect.ans
25-keep-skills.ans
Intro frame (ANSI stripped)
                               PostHog Wizard v2.76.0                                                                    Feedback: wizard@posthog.com
                                                                               ███ PostHog Wizard 🦔
                                                               We'll use AI to analyze your project and complete work.
                                                                   Review what data is shared in "Privacy & data."
                                                                         .env* values stay on your machine.
                                                                    Let's do two hours of work in eight minutes.
                                                                        Directory ✔ /wizard-e2e-express-todo
                                                                        Framework ✔ Node.js (detected)
                                                                              ▸ Continue
                                                                                Change framework
                                                                                More info
                                                                                Privacy & data
                                                                                Cancel
                                ↑↓ navigate  enter select
Outro frame (ANSI stripped)
                               PostHog Wizard v2.76.0                                                                    Feedback: wizard@posthog.com
                               ✔ PostHog set up: 7/7 steps completed (1 skipped as not required).
                               Dashboard:
                               https://us.posthog.com/project/2/dashboard/2112928?utm_source=wizard&utm_medium=cli&utm_content=outro-dashboard
                               Notebook:
                               https://us.posthog.com/project/2/notebooks/cKOg6RVu?utm_source=wizard&utm_medium=cli&utm_content=outro-notebook
                               Learn more: https://posthog.com/docs/ai-engineering/ai-wizard?utm_source=wizard&utm_medium=cli&utm_content=outro-docs
                               Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made.
                               How did this work for you? Drop us a line: wizard@posthog.com
                               Press any key to continue

Gates on this PR

Gate Result
pnpm typecheck (tsc -b, project references) 0 errors
Vitest, six projects 199 files, 3138 tests
Import boundaries matrix and public entries enforced, allowlist deleted
Goldens (frames, flow traces, keyboard pairs, decision traces, control-state recording) byte identical to P0
pnpm build, pnpm build:ci with smoke tests pass

@gewenyu99

Copy link
Copy Markdown
Collaborator Author

How to run this step

pnpm install
pnpm typecheck                 # tsc -b tsconfig.solution.json: one composite project per surface
pnpm typecheck:store           # or agent, tui, cli, harness, arch
pnpm test                      # builds, then every Vitest project
pnpm test:store                # or agent, tui, cli, harness, arch: one project, its aliases only
pnpm test:arch                 # import matrix, public entries, shape files, startup graph
pnpm lint                      # prettier + eslint, typed against the whole-tree tsconfig
pnpm build && pnpm build:ci    # both bundles, smoke tests, chunk manifests

A deep import across surfaces fails three times: tsc -b ("not listed within the file list of project"), the architecture project, and ESLint no-restricted-imports. An ink import outside src/tui throws at test load through __mocks__/forbidden-ink.ts.

Snapshot route at this step (the in-process host, replaced in #1278):

PROGRAM=posthog-integration E2E_ASK=true POSTHOG_KEY_FILE=… WIZARD_CI_GATEWAY_TOKEN_FILE=… \
PROJECT_ID=<id> POSTHOG_REGION=us APP_DIR=/tmp/app SNAP_OUT=/tmp/snaps \
npx tsx scripts/tui-snapshots.no-jest.ts

Each surface's README.md lists what it owns, what it may import, and its test commands.

@gewenyu99 gewenyu99 closed this Sep 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant