Execute an interactive command (port of TS ``local-jsx``). Runs the command body against ``ctx.ui`` and maps its :class:`InteractiveOutcome` onto a ``CommandResult``, propagating the ``display`` / ``should_query`` / ``meta_messages`` fields that the LOCAL arm hardcod
(
self,
command: InteractiveCommand,
args: str,
)
| 220 | ) |
| 221 | |
| 222 | async def _execute_interactive( |
| 223 | self, |
| 224 | command: InteractiveCommand, |
| 225 | args: str, |
| 226 | ) -> CommandResult: |
| 227 | """Execute an interactive command (port of TS ``local-jsx``). |
| 228 | |
| 229 | Runs the command body against ``ctx.ui`` and maps its |
| 230 | :class:`InteractiveOutcome` onto a ``CommandResult``, propagating the |
| 231 | ``display`` / ``should_query`` / ``meta_messages`` fields that the |
| 232 | LOCAL arm hardcodes away (``_execute_local`` forces ``system`` / |
| 233 | ``False`` / drops meta). A surface that wired no ``ui`` gets a |
| 234 | ``NullUIHost`` so the body can always assume ``ctx.ui`` exists; that |
| 235 | host raises :class:`InteractiveUnavailableError` for mutating prompts, |
| 236 | which we surface as a clean error result. |
| 237 | """ |
| 238 | # Substitute the null surface when none was wired (SDK / |
| 239 | # non-interactive). Done here, once, so command bodies never see a |
| 240 | # ``None`` ui. Idempotent: a real surface sets ``ui`` at startup. |
| 241 | if self.context.ui is None: |
| 242 | self.context.ui = NullUIHost() |
| 243 | |
| 244 | try: |
| 245 | outcome = await command.run(args, self.context) |
| 246 | except InteractiveUnavailableError as e: |
| 247 | # Expected on the null surface — a clean, typed message rather |
| 248 | # than a stack trace. |
| 249 | return CommandResult.error(command.name, str(e)) |
| 250 | except Exception as e: |
| 251 | return CommandResult.error(command.name, str(e)) |
| 252 | |
| 253 | if not isinstance(outcome, InteractiveOutcome): |
| 254 | return CommandResult.error( |
| 255 | command.name, |
| 256 | f"interactive command returned {type(outcome).__name__}, " |
| 257 | "expected InteractiveOutcome", |
| 258 | ) |
| 259 | |
| 260 | # ``display == 'skip'`` (e.g. the cancelled path) → no output. |
| 261 | if outcome.display == "skip": |
| 262 | return CommandResult.skip(command.name) |
| 263 | |
| 264 | return CommandResult( |
| 265 | success=True, |
| 266 | command_name=command.name, |
| 267 | result_type="text", |
| 268 | text=outcome.message or "", |
| 269 | should_query=outcome.should_query, |
| 270 | display=outcome.display, |
| 271 | meta_messages=list(outcome.meta_messages), |
| 272 | ) |
| 273 | |
| 274 | def add_command_hook( |
| 275 | self, |
no test coverage detected