Skip to content

refactor: put the tui store on top of the session store - #1381

Closed
gewenyu99 wants to merge 1 commit into
posthog/functional-r9-07-program-folders-export-a-config-with-no-from
posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session-
Closed

gewenyu99 wants to merge 1 commit into
posthog/functional-r9-07-program-folders-export-a-config-with-no-from
posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session-

Conversation

@gewenyu99

@gewenyu99 gewenyu99 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Phase 2 of Release C (#1320), PR 5 of 16, after #1380. Review PR. PRs 1 to 14 of this phase split one change into reviewable pieces and compile only as a stack: review them one by one, then land the whole phase together.

Problem

On main, the TUI's WizardStore owns the whole session, screen answers included, and the TUI reaches the rest of the wizard through the process-wide WizardUI (InkUI). The session store from #1376 needs the TUI on top of it, not around it.

Changes

  • WizardStore (src/tui/store.ts) wraps a SessionStore (store.sessions) and adds TuiState (tui-state.ts): the screens' answers, overlay contents and launch choices. Screens end a run with store.requestExit(code), and the host reads exitRequest.
  • tuiWorkflow (workflow.ts) answers the steps runProgram waits on: the AI opt-in gate, the outage screen, the settings override, and reachStep before each run.
  • FlowStep (flow.ts) replaces ProgramStep for screen flows. New screen-registry.tsx and screen-sequences.ts at src/tui mount the core screens and take each program's from its TUI entry. WizardRouter.resolve reads a TuiView.
  • displayProgress and scanProgress (agent-progress.ts) put run and scan events on the screens. The browser login in src/tui/auth (oauthLogin, getOrAskForProjectData, their code moved in refactor: move every file into its layer #1375) becomes runProgram's credentials provider through oauthCredentials (login.ts), and startTUI no longer installs a WizardUI or exits.
  • addTokenUsage (token-usage.ts) adds each turn's usage to the token HUD's estimate and leaves a reconciled total as it is.
  • Only a composed sub-run that succeeded marks its step complete, as on main. A failed one keeps its tasks for the outro and the stream.
  • Focus on store.ts and tui-state.ts: which fields left the session, and that each write still re-resolves the screen and the gates.

Test plan

Created with PostHog Desktop

@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 feature-flags
  • /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 feature-flags/django
  • /wizard-ci feature-flags/next-js
  • /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.

@gewenyu99
gewenyu99 added this pull request to stack #1394 September 29, 2026 09:41
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from 3521f0c to e5138a9 Compare September 30, 2026 08:06
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from 1e0bc81 to 45ecdf8 Compare September 30, 2026 08:06
@gewenyu99
gewenyu99 removed this pull request from stack #1394 September 30, 2026 08:07
@gewenyu99
gewenyu99 added this pull request to stack #1400 September 30, 2026 08:07
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from e5138a9 to fd7ec0e Compare September 30, 2026 08:44
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from 45ecdf8 to f7978fd Compare September 30, 2026 08:44
@gewenyu99
gewenyu99 marked this pull request as ready for review September 30, 2026 09:40
@gewenyu99
gewenyu99 requested a review from a team as a code owner September 30, 2026 09:40
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from f7978fd to 8883b18 Compare September 30, 2026 14:11
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from fd7ec0e to 2b4fdc6 Compare September 30, 2026 14:11
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from 8883b18 to e757985 Compare October 1, 2026 06:43
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from 2b4fdc6 to 62de363 Compare October 1, 2026 06:43
@gewenyu99
gewenyu99 removed this pull request from stack #1400 October 1, 2026 06:47
@gewenyu99
gewenyu99 added this pull request to stack #1403 October 1, 2026 06:47

@johncwaters johncwaters left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Automated review. Not written by a human.

Comment thread src/tui/auth/project-data.ts Outdated
store.pushStatus('Signing you in to your new account instead...');

return askForWizardLogin({ signup: false, baseUrl, localMcp });
return askForWizardLogin({ store, signup: false, baseUrl, localMcp });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Automated review. Not written by a human.

[convergent: code + security + structure] MEDIUM

askForProvisioningSignup now takes programId and scopeAdditions, but both fallbacks into askForWizardLogin (here and at line 390) pass only { store, signup: false, baseUrl, localMcp }. When the provisioned account cannot be read back, or the email already has an account, the browser login asks for the bare WIZARD_OAUTH_SCOPES instead of the program's or tool's wider set, so later scope-gated calls fail or land in missingScopes. Forward programId and scopeAdditions (and projectId) in both calls.

Comment thread src/tui/store.ts Outdated
*/
reachStep(stepId: string): Promise<boolean> {
const program = this.router.activeProgram;
const steps = withAiOptInGate(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Automated review. Not written by a human.

[convergent: code + security + structure] MEDIUM

withAiOptInGate(findProgramConfig(program), flowOwner(program).flow) is built separately in _initFromProgram (line 143), reachStep (here) and programSequence in src/tui/screen-sequences.ts:41, and reachStep re-derives the isComplete ?? gate default that createProgramSequence in flow.ts owns. The comment at line 139 says the AI opt-in gate and its screen "can't drift apart", but only three identical expressions keep that true. Extract one helper (for example programFlowSteps(programId)) and use it in all three places.

Comment thread src/tui/agent-progress.ts
* writes its run state to the session store, so its progress goes through
* `displayProgress`.
*/
export function scanProgress(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Automated review. Not written by a human.

[structure/duplication] MEDIUM

scanProgress (with completeRun and setCompletionOutro) re-implements the run-state half of applyAgentProgress in src/programs/session/session-store.ts:551: lifecycle start/complete with the fallback success outro, status, tasks, url, handoff, and the live-URL-wins completion merge. The two already differ (ANSI stripping, batching), and the next change to the outro fallback or URL precedence will land in one only. Build scanProgress as applyAgentProgress(store.sessions, event) plus displayProgress(store)({ event }), move ANSI stripping into applyAgentProgress, and delete the copies.

@@ -0,0 +1,106 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Automated review. Not written by a human.

[code/duplication] LOW

Nothing imports this new registry or src/tui/screen-sequences.ts at this head: src/tui/App.tsx:4 still imports createScreens/createServices from ../ui/tui/screen-registry.js, and the old src/ui/tui/screen-registry.tsx, screen-sequences.ts and ink-ui.ts still exist. Repoint App.tsx and delete the old files here, or confirm a later PR in the stack does.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Expected at this PR: router.ts imports screen-sequences here, App.tsx and harness.tsx import the registry in #1382, and src/ui is deleted in #1386.

@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from e757985 to 76921c7 Compare October 2, 2026 16:47
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from 62de363 to 0ecdbe0 Compare October 2, 2026 16:47
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from 76921c7 to 9eb3762 Compare October 2, 2026 20:50
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from 0ecdbe0 to 7597ed2 Compare October 2, 2026 20:50
Generated-By: PostHog Desktop
Task-Id: d14e92bb-6ee1-49b5-8502-39cb80079589
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-07-program-folders-export-a-config-with-no- branch from 9eb3762 to e6300c4 Compare October 3, 2026 20:40
@gewenyu99
gewenyu99 force-pushed the posthog/functional-r9-08-put-the-tui-store-on-top-of-the-session- branch from 7597ed2 to 581e05a Compare October 3, 2026 20:40

@edwinyjlim edwinyjlim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review of #1381 at 581e05ae. Comments inline.


Drafted with Claude Code from a review of the whole Release C stack, re-verified at the stack tip 2e31e438. Line numbers are at this PR's head.

Comment thread src/tui/workflow.ts
return true;
case 'service-outage':
// The health-check screen shows the outage; the run stops.
store.setReadinessResult(step.readiness);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P2] The service-outage step re-writes a readiness result runProgram already stored, so health check blocked is captured twice

checkReadiness calls store.setReadinessResult on the shared store before asking the workflow; the connector then calls it again on the same store. The setter runs captureHealthCheckBlocked on every blocked result, so one blocked start sends two events. This hits every flow without a health-check step (warehouse-source, source-maps).

Suggested fix: Delete the setReadinessResult line in the service-outage case and just return false; the screens read the same store. Or make the capture fire once per result object.

Comment thread src/tui/agent-progress.ts
* writes its run state to the session store, so its progress goes through
* `displayProgress`.
*/
export function scanProgress(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P3] scanProgress keeps lifecycle and completion branches no scan can reach and that would derail the flow if one did

Partly fixed since the last push. The duplicate reducer is gone and scanProgress now runs through applyAgentProgress. A forwarded completion would still mark the run Completed before the run step. Unreachable today.

Every detect screen's scan goes through detectProjectsWithAgent, which drops lifecycle, completion and spinner events. If a future detector forwarded them, a scan would set the run phase to Completed and a success outro before the run step, and the router would skip the run screen.

Suggested fix: Treat those kinds as no-ops in scanProgress and remove completeRun and setCompletionOutro, or throw on them so a detector change surfaces in tests.

/**
* Core screen ids + per-program screen sequences.
*
* Owns the core ScreenId enum and projects a program's flow into the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[P3] The screen-sequences header still says it owns the core ScreenId enum

Suggested fix: Reword to "re-exports the core ScreenId and projects a program's flow".

@gewenyu99
gewenyu99 removed this pull request from stack #1403 October 5, 2026 09:47
@gewenyu99

Copy link
Copy Markdown
Collaborator Author

Folded into #1378 so the phase builds green PR by PR. This PR keeps its review; the code lands through #1378.

@gewenyu99 gewenyu99 closed this Oct 5, 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.

3 participants