Skip to content

fix(cli): CLI-side defensive exit only. Did not bump ink 6.8.0 -> 7... (#204)#53

Draft
aidandaly24 wants to merge 1 commit into
mainfrom
fix/204
Draft

fix(cli): CLI-side defensive exit only. Did not bump ink 6.8.0 -> 7... (#204)#53
aidandaly24 wants to merge 1 commit into
mainfrom
fix/204

Conversation

@aidandaly24

Copy link
Copy Markdown
Owner

Refs aws#204

Issues

Root cause

The brief's trace is correct, but the framing is sharper than "never patched" — this is a REGRESSION. Flow at v0.20.2: no-flag create -> requireTTY() (src/cli/tui/guards/tty.ts:8) -> handleCreateTUI() (src/cli/commands/create/command.tsx:42-49) -> renderTUI({initialRoute:'create', isInteractive:false}) (src/cli/tui/render.ts:35). renderTUI does render(App) + await waitUntilExit() (render.ts:50-52), then on return prints the exit message and printPostCommandNotices and RETURNS with NO process.exit (render.ts:54-113). CreateScreen auto-exits on success via Ink's exit() (CreateScreen.tsx:265-289). On exit, Ink 6.8.0 App.handleExit -> disableRawMode() runs synchronous stdin.setRawMode(false) + stdin.unref() (verified node_modules/ink/build/components/App.js:54-67). On Windows this synchronous raw-mode teardown does not cancel the pending libuv stdin read, so the loop stays alive until a keypress flushes it. CRITICAL FINDING the brief missed: aws#199 (commit 2ac14a1) DID fix this by adding explicit unmount(); process.exit(0) to handleCreateTUI's onExit, but commit c21d870 (aws#1365 "create global entrypoint for tui", 2026-05-27, verified ancestor of the v0.20.2 HEAD) refactored handleCreateTUI to route through renderTUI() and DROPPED that explicit exit. So the bug is a regression of a shipped fix, not an un-patched path. Corroborating that natural-drain is the wrong assumption: the non-interactive create path exits cleanly because handleCreateCLI -> runCliCommand calls process.exit(0) (src/cli/telemetry/cli-command-run.ts:154,157), and the dev command force-exits at src/cli/commands/dev/command.tsx:554. Ink pinned ^6.6.0 -> resolves 6.8.0 (pre the 7.0.2 "Defer raw mode disable" fix).

The fix

Primary CLI fix (low risk, matches existing pattern): force a clean exit after the create TUI returns. Best placement is the renderTUI chokepoint (src/cli/tui/render.ts) — after telemetry flush + printPostCommandNotices, call process.exit(0) for terminal TUI flows, guarded to skip the dev/exec/exec-shell re-entry branches (render.ts:70-103) which intentionally continue. This single chokepoint also cures add/deploy/remove/invoke/export and the no-arg main (cli.ts:164), all of which share the same natural-drain assumption. Minimal alternative: restore the aws#199 pattern by adding process.exit(0) after the await handleCreateTUI() calls (command.tsx:556 and 637), exactly as the dev command does at dev/command.tsx:554. Root-cause/upstream complement: bump ink 6.8.0 -> 7.x (which contains the v7.0.2 raw-mode-disable-defer fix); dependabot PR aws#1512 (branch dependabot/npm_and_yarn/ink-7.0.5, title "bump ink from 6.8.0 to 7.1.0", state OPEN — verified via gh) already does this but is an unmerged major-version bump needing validation. Recommend the CLI defensive exit now; the ink bump is the durable root-cause fix for all TUI flows. Design decision to confirm: chokepoint exit in renderTUI vs per-command, and ensure exec/exec-shell/dev re-entry are excluded.

Files touched: src/cli/tui/render.ts (renderTUI, add a guarded process.exit(0) at the terminal end, lines ~104-113, excluding the dev/exec/exec-shell early returns at 70-103) — or, minimal, src/cli/commands/create/command.tsx after handleCreateTUI() at lines 556 and 637. Upstream root-cause: package.json "ink": "^6.6.0" -> 7.x (tracked by open PR aws#1512).

Validation evidence

The fix was verified by reproducing the original symptom and re-running after the change:

FIX (src/cli/tui/render.ts, +6 lines): adds process.exit(0) after printPostCommandNotices(...) at the end of renderTUI; the dev/exec/exec-shell re-entry branches (render.ts:70-103) return before it, so they are intentionally not force-exited. Confirmed in the built bundle: fixed dist/cli/index.mjs ends the terminal flow ...await Sbt(o,n),process.exit(0)}, base ends ...await Sbt(o,n)} (no exit).

RUNTIME REPRO (tui-harness driving the real built CLI at /local/home/aidandal/workplace/issues/bugfix-run/clusters/204/repo/dist/cli/index.mjs): no-flag agentcore create -> name acfix204app -> build-type "Skip" wrote the project successfully ([done] Create acfix204app/ project directory, [done] Prepare agentcore/ directory, [done] Initialize git repository, then "Created: acfix204app/ ... Next: Run agentcore add"). With the fix, WITHOUT sending any key after the success screen, the process exited on its own: wrapper printed CLI_EXIT_CODE=0 and MARKER_SHELL_PROMPT_RETURNED, harness session reported alive:false / signal:null (natural exit). Project files verified on disk (agentcore/agentcore.json, aws-targets.json, cdk/, README.md, .git). (Used AGENTCORE_SKIP_INSTALL=1 — equivalent of the first-class --skip-install option — only to avoid an unrelated npm/tar ENOENT in the /tmp sandbox during the heavy CDK install; the exit path under test is identical.)

PLATFORM CAVEAT: the actual hang is Windows-specific (ink 6.x synchronous raw-mode teardown does not cancel libuv's pe

Test suite: green.


Staged on the fork as a draft for human review. Promote to aws/agentcore-cli after vetting.

…s to the shell on Windows

CLI-side defensive exit only. Did not bump ink 6.8.0 -> 7.x (the upstream root-cause complement tracked by open PR aws#1512), which is a major-version change needing separate validation and is out of scope for a surgical fix. No test added: a unit test would need to mock Ink rendering and intercept process.exit, making it larger and more fragile than the one-line fix (violating the "test only if smaller than the fix" rule); the regression guard is the tui-harness surface per the gate.

symptom: On Windows, no-flag `agentcore create` (interactive TUI) writes the project successfully but hangs until the user presses Enter instead of returning to the shell.
pass_condition: a successful no-flag create through the TUI exits with code 0 on its own within a short timeout without any stdin/keypress; renderTUI reaches a guarded process.exit(0) on the terminal flow while the dev/exec/exec-shell early-return branches at render.ts:70-103 are NOT force-exited.
test_surface: tui-harness.

Verified: `tsc --noEmit` clean; 787 pure TUI/create/invoke unit tests pass; the 15 create.test.ts subprocess failures are pre-existing (identical on the stashed clean base) caused by a missing dist/ build, and all 16 pass after `npm run build` — confirming they are unrelated to this change.
@github-actions github-actions Bot added the size/xs PR size: XS label Jun 25, 2026
@github-actions

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 37.16% 13593 / 36578
🔵 Statements 36.43% 14452 / 39668
🔵 Functions 31.8% 2333 / 7336
🔵 Branches 31.1% 9000 / 28932
Generated in workflow #107 for commit 81862ff by the Vitest Coverage Report Action

@github-actions github-actions Bot added agentcore-harness-reviewing AgentCore Harness review in progress and removed agentcore-harness-reviewing AgentCore Harness review in progress labels Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xs PR size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant