You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Non-TTY guard from init (#41) should cover the other prompting commands #49
Adjacent finding from the PR #48 review (non-blocking there, pre-existing): init now has an explicit non-TTY guard for its overwrite prompt (explicit refusal + --yes escape hatch, landed via #48 / issue #41), but the other prompting commands (add, edit-project, remove-project, remove-learning) still rely on the incidental event-loop drain when stdin is non-interactive — the same bug class #41 fixed for init.
Provenance: #48 (comment) ("Adjacent (not a finding on this PR)").
Ask:
Audit each prompting command for what happens with non-TTY stdin today (piped / /dev/null): does a prompt hang, drain out mid-promise, or exit cleanly? Document per-command.
Where a destructive or overwrite action can be reached non-interactively, apply the same explicit guard pattern init uses (see packages/core/src/commands/init.ts:66-75): refuse with a clear message + flag escape hatch, rather than depending on the drain.
Where the command is purely informational (no destructive path), record that no guard is needed — the audit result is the deliverable, not blanket refactors.
Constraints per AGENTS.md: build/lint/test only, no dev servers; gate green before any PR.
prompt renders, then silent exit 0 mid-promise — no cancel message, no overwrite, no error
yes
add → component re-add
raw failure: "✖ Failed to add component — User force closed the prompt with 0 null", exit 1; no overwrite
yes — safe but misreported
edit project (no flags)
"✖ Cancelled.", exit 0
no
remove project (no --force)
"✖ Cancelled.", exit 0 (also verified with an open-pipe stdin)
no
remove learning (no --index)
"✖ Cancelled.", exit 0
no
Correction to the original premise:edit-project, remove-project and remove-learning already handle prompt cancellation explicitly — they do not rely on an incidental event-loop drain, and no destructive action is reachable non-interactively through them (each also has a non-interactive escape hatch: flags, --force, --index). The surviving instance of the #41 bug class is in add's theme path: an empty catch {} around the overwrite confirm swallows ExitPromptError and the process drains mid-promise — the exact pattern #41 fixed for init. The component path never overwrites either, but a cancellation escapes to the generic error handler and is reported as "Failed to add component".
Per the issue's own ask #3, the audit above is the deliverable for the already-safe commands — no guards there.
Agent Brief
Category: bug Summary: Make add's overwrite prompts behave explicitly under non-TTY stdin, matching the guard pattern init uses.
Current behavior:
Theme path: the overwrite confirm() sits inside an empty catch {}; under non-TTY stdin the prompt's ExitPromptError is swallowed and the process exits 0 silently mid-promise (no message, no cancel notice, nothing written).
Component path: ExitPromptError from the overwrite confirm() reaches the generic error handler → "✖ Failed to add component" + internal prompt error text, exit 1.
Desired behavior:
Theme path: when an existing theme file would be overwritten and stdin is non-interactive without --force, refuse up front with a clear message (run in a TTY to confirm, or pass --force) — the same explicit-guard shape init uses for config overwrite. Prompt cancellation (ExitPromptError) prints "✖ Add cancelled." and returns cleanly; non-prompt errors surface instead of being swallowed.
Component path: ExitPromptError is caught explicitly → "✖ Add cancelled." + clean return, mirroring how remove-project handles it. The generic "Failed to add component" handler never sees a prompt cancellation.
Acceptance criteria:
add <theme> with an existing theme file, stdin /dev/null, no --force → explicit refusal message (not silent), file untouched
add <theme> with an existing file + --force, stdin /dev/null → overwrites without prompting
add <component> re-add under /dev/null stdin → "✖ Add cancelled." (not "Failed to add component"), no partial writes
New tests cover all three paths; full gate green (pnpm install && pnpm build && pnpm typecheck && pnpm lint && pnpm test)
Out of scope:
Guards for edit-project / remove-project / remove-learning (verified already-safe; audit recorded above)
Changes to prompt text/UX of other commands
The .d.ts-only component source quirk in getSourceFiles (dist ships only .d.ts/.js for components — separate concern worth its own issue)
Delegation: filed on the Hermes kanban board (coder card + reviewer card, serially gated).
Activity
ManningWorks commentedon Oct 14, 2026
Triage result
Category: bug · State: ready-for-agent
Verified against the live CLI (built from current
main, stdin from/dev/null, 2026-10-14):init(baseline)--yesescape hatchadd→ theme re-addadd→ component re-addedit project(no flags)remove project(no--force)remove learning(no--index)Correction to the original premise:
edit-project,remove-projectandremove-learningalready handle prompt cancellation explicitly — they do not rely on an incidental event-loop drain, and no destructive action is reachable non-interactively through them (each also has a non-interactive escape hatch: flags,--force,--index). The surviving instance of the #41 bug class is inadd's theme path: an emptycatch {}around the overwrite confirm swallowsExitPromptErrorand the process drains mid-promise — the exact pattern #41 fixed forinit. The component path never overwrites either, but a cancellation escapes to the generic error handler and is reported as "Failed to add component".Per the issue's own ask #3, the audit above is the deliverable for the already-safe commands — no guards there.
Agent Brief
Category: bug
Summary: Make
add's overwrite prompts behave explicitly under non-TTY stdin, matching the guard patterninituses.Current behavior:
confirm()sits inside an emptycatch {}; under non-TTY stdin the prompt'sExitPromptErroris swallowed and the process exits 0 silently mid-promise (no message, no cancel notice, nothing written).ExitPromptErrorfrom the overwriteconfirm()reaches the generic error handler → "✖ Failed to add component" + internal prompt error text, exit 1.Desired behavior:
--force, refuse up front with a clear message (run in a TTY to confirm, or pass--force) — the same explicit-guard shapeinituses for config overwrite. Prompt cancellation (ExitPromptError) prints "✖ Add cancelled." and returns cleanly; non-prompt errors surface instead of being swallowed.ExitPromptErroris caught explicitly → "✖ Add cancelled." + clean return, mirroring howremove-projecthandles it. The generic "Failed to add component" handler never sees a prompt cancellation.Acceptance criteria:
add <theme>with an existing theme file, stdin/dev/null, no--force→ explicit refusal message (not silent), file untouchedadd <theme>with an existing file +--force, stdin/dev/null→ overwrites without promptingadd <component>re-add under/dev/nullstdin → "✖ Add cancelled." (not "Failed to add component"), no partial writespnpm install && pnpm build && pnpm typecheck && pnpm lint && pnpm test)Out of scope:
edit-project/remove-project/remove-learning(verified already-safe; audit recorded above).d.ts-only component source quirk ingetSourceFiles(dist ships only.d.ts/.jsfor components — separate concern worth its own issue)Delegation: filed on the Hermes kanban board (coder card + reviewer card, serially gated).