Skip to content

fix(tui): flush analytics before a screen's exit request ends the run - #1417

Merged
gewenyu99 merged 2 commits into
mainfrom
fix/integrate-silent-exit
Oct 6, 2026
Merged

gewenyu99 merged 2 commits into
mainfrom
fix/integrate-silent-exit

Conversation

@gewenyu99

Copy link
Copy Markdown
Collaborator

Problem

When someone picks Cancel on the intro, or any other screen ends the run with requestExit, the process exits before analytics flush, so the run sends only wizard: started (12–20% of prod integrate runs since 2.75.0).

Changes

  • When a screen asks to exit, runTui now reports the end with analytics.shutdown before it exits: cancelled for code 0, error otherwise. The first status still wins, so a run that already reported success keeps it.
  • Then it flushes analytics and ends with the screen's code. The task stream still doesn't shut down on this path, same as before.

Test plan

  • New run.test.ts cases: an exit request before the run (codes 0 and 1) shuts analytics down with the right status and flushes before exiting. Both fail on main.
  • run.test.ts 21/21, plus full vitest, typecheck and lint.
  • Local run of the built CLI with analytics stubbed, picking Cancel on the intro. Main sends only wizard: started. This branch also sends wizard: intro menu selected and setup wizard finished.

Sources

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 5, 2026

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 marked this pull request as ready for review October 5, 2026 14:51
@gewenyu99
gewenyu99 requested a review from a team as a code owner October 5, 2026 14:51
…uest

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@gewenyu99 gewenyu99 left a comment

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.

🥸 Reviewed by NotVincent, totally not Vincent. The real Vincent will review it separately. Probably slop, please disregard.

Comment thread src/tui/run.ts Outdated
if (code === null || handedOff || exitInProgress || signalled) return;
exitInProgress = true;
launch.signal.removeEventListener('abort', onAbort);
void (async () => {

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.

suggested

Here's the potential issue: After Cancel, the intro stays on screen and keeps taking input until the analytics flush finishes. Nothing checks the exit request again.

analytics host blocked -> user picks Cancel -> menu still live -> user picks Continue -> run starts, then exit.end kills it mid-login

Suggested fix: Unmount the TUI before awaiting the shutdown and flush, the way the tool host does on its exit path.

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.

Hi, NotVincent here :disguise-emoji:, I will do the deeds

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.

It's done, NotVincent will tell Vincent to double check.

Comment thread src/tui/run.ts
const code = store.exitRequest;
if (code === null || handedOff || exitInProgress || signalled) return;
exitInProgress = true;
launch.signal.removeEventListener('abort', onAbort);

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.

suggested

Here's the potential issue: Cancel used to exit at once. Now it waits on two analytics shutdowns with no time limit, and Ctrl-C is ignored for the whole wait.

network that drops PostHog requests -> user picks Cancel -> exit waits about 30 s or more -> Ctrl-C does nothing -> user kills the terminal

Suggested fix: Cap the shutdown and flush with a short timeout, like the 2 s cap on the stream shutdown.

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.

Hi, NotVincent here :disguise-emoji:, I will do the deeds

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.

It's done, NotVincent will tell Vincent to double check.

Comment thread src/tui/run.ts Outdated
const activeTui = tui;
const { store } = activeTui;
// A screen's exit request ends the run with no shutdown; start-tui's exit listener unmounts.
// A screen's exit request ends the run with no stream shutdown, once analytics report its end; start-tui's exit listener unmounts.

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.

nit

Here's the potential issue: The TUI README still says runTui resolves a screen's exit request as is. The older test named for starting no end shutdown now runs one.

next reader adds an exit request on a hot path -> trusts the README -> doesn't expect a network wait before exit

Suggested fix: Update the README sentence to mention the report and flush, and rename the older test to say no stream shutdown.

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.

Hi, NotVincent here :disguise-emoji:, I will do the deeds

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.

It's done, NotVincent will tell Vincent to double check.

@gewenyu99
gewenyu99 merged commit 3c8fe39 into main Oct 6, 2026
18 checks passed
@gewenyu99
gewenyu99 deleted the fix/integrate-silent-exit branch October 6, 2026 13:53
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.

2 participants