Skip to content

Detect interactive environment on Context#804

Draft
Amoifr wants to merge 1 commit intojolicode:mainfrom
Amoifr:feat/context-env-interactive
Draft

Detect interactive environment on Context#804
Amoifr wants to merge 1 commit intojolicode:mainfrom
Amoifr:feat/context-env-interactive

Conversation

@Amoifr
Copy link
Copy Markdown
Contributor

@Amoifr Amoifr commented Apr 14, 2026

Summary

First stab at #803: let Context know whether the surrounding environment supports interactive commands, and prevent toInteractive() from silently hanging in CI / under AI agent runners.

  • New Context::isEnvInteractive() / withEnvInteractive()
  • Auto-detection from CI env var + STDIN being a TTY (override with withEnvInteractive(false))
  • Context::toInteractive() now throws a LogicException when the environment is not interactive, with toInteractive(throwOnNonInteractiveEnv: false) as an escape hatch
  • Tests, CHANGELOG and docs updated

Opening as draft because two design points really benefit from your input before going further:

1. Auto-detection scope

I went conservative on purpose: only CI + !stream_isatty(STDIN). The issue mentioned CURSOR_AGENT / AI_AGENT / etc., but that ecosystem is fragmented and there's no real standard yet — I'd rather let users declare their own runner with withEnvInteractive(false) than hardcode a list that goes stale fast. Happy to expand the list if you'd prefer broader detection out of the box.

2. BC break on toInteractive()

As suggested by @joelwurtz in the issue, toInteractive() now throws when the env is not interactive. This is technically a BC break for anyone calling toInteractive() from CI today (even if such a call was almost certainly already broken in practice). The bypass param is there for the rare legitimate use case. Let me know if you'd rather have it opt-in via a separate method instead.

Out of scope

The "automatically hide commands when env is not interactive" idea from the issue thread isn't in this PR — it's a bigger change touching command discovery, and felt better as a follow-up once the foundation is agreed on.

Refs #803

Test plan

  • vendor/bin/phpunit tests/ContextTest.php (6 new tests)
  • tools/phpstan/vendor/bin/phpstan clean
  • tools/php-cs-fixer/vendor/bin/php-cs-fixer fix clean
  • Full suite: only pre-existing unrelated failures remain (locale-dependent RunVerboseArguments* tests + network-dependent RemoteImportRemoteTasks)

Thanks a lot for maintaining Castor — happy to iterate on this based on your feedback! 🙌

Add Context::isEnvInteractive() / withEnvInteractive() so tasks can know
whether the surrounding environment supports interactive commands. The
flag is auto-detected from the CI env var and STDIN being attached to a
TTY, and can be overridden explicitly.

Context::toInteractive() now throws a LogicException when the environment
is not interactive, to fail fast instead of silently hanging in CI or
under AI agent runners. Pass toInteractive(throwOnNonInteractiveEnv: false)
to bypass the check.

Refs jolicode#803
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