Skip to content

feat(cli): add one-shot user commands - #3210

Open
me2seeks wants to merge 8 commits into
apache:mainfrom
me2seeks:feat/cli-user-shell-mode
Open

feat(cli): add one-shot user commands#3210
me2seeks wants to merge 8 commits into
apache:mainfrom
me2seeks:feat/cli-user-shell-mode

Conversation

@me2seeks

@me2seeks me2seeks commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Codex-style !<command> interaction to the idle TUI. It runs one command through Runtime Host in the current Session workspace, keeps the TUI rendering, and shows the result as a local user-command card. It does not create an agent turn. User-command output is expanded by default; Ctrl+O remains the toggle for model tool cards.

Runtime boundary. Runtime Host remains the execution and resource-lifecycle authority. Only one-shot !<command> resources are stored with visibility: "user"; Runtime rejects model reads of those resources with the same non-disclosing not-found result used for inaccessible resources. The Desktop-owned interactive login shell carries no command and keeps its prior model-visible behavior. Client resource projections can still display the command output.

Protocol compatibility. runtime.resource.start now accepts an optional one-shot command, and the durable Shell Run record carries visibility. RUNTIME_HOST_COMPATIBILITY_EPOCH moves to 28 so a pre-widening peer is refused at admission instead of failing on the first ! command.

Privilege. runtime.resource.start was already in REMOTE_OWNER_OPERATION_GRANTS for the interactive login shell; this PR adds no new grant. The new command-carrying surface reuses the existing owner grant — no new privilege.

Ordering boundary. The CLI starts observing the resource before runtime.resource.start, merges updates by revision, and applies a terminal update that arrived before the local card was created. There is no second executor or CLI-owned shell lifecycle.

Fixes #3209

中文说明(实现与架构边界)

TUI 空闲时输入 !<command> 会由 Runtime Host 在当前 Session 工作目录执行一次命令。TUI 不会暂停渲染,也不会接管交互式 PTY。命令结果以仅本地的“User command”卡片展示,不创建 agent turn。用户命令输出默认展开;Ctrl+O 继续只控制模型工具卡片。

运行时边界。 Runtime Host 继续拥有命令执行、资源生命周期和 Session 工作目录。只有一次性 !<command> 资源标记为 visibility: "user":Runtime 会拒绝模型通过资源引用读取它,并使用非披露的 not-found 结果;Desktop 的交互登录 shell 不携带 command,保持原有的模型可见行为。客户端资源投影仍可展示输出。

协议兼容。 runtime.resource.start 新增可选的一次性 command 字段,持久化的 Shell Run 记录新增 visibilityRUNTIME_HOST_COMPATIBILITY_EPOCH 升至 28,旧版本对端会在准入阶段被拒绝,而不是在第一条 ! 命令上失败。

权限。 runtime.resource.start 本就在 REMOTE_OWNER_OPERATION_GRANTS 中(交互登录 shell 已在使用);此 PR 不新增任何授权,新表面复用既有 owner 权限。

顺序边界。 CLI 在发起资源前开始观察同一命令资源,按 revision 合并更新,并在创建卡片后回放已经到达的终态更新。因此快速命令不会因“先完成、后建卡”而丢失输出。此 PR 不新增第二个执行器,不改变模型 Bash 的权限或上下文语义。

Verification

  • Node 24.18.1: complete maka-agent CLI suite passed.
  • Passed affected package builds: @maka/core, @maka/runtime, @maka/runtime-host, and maka-agent.
  • Passed complete affected Runtime and Runtime Host suites.
  • Passed scoped Biome format/lint checks and git diff --check.
  • Added coverage for !<command> routing, default-expanded user-command output, Ctrl+O isolation from user-command cards, pre-card terminal-update replay, Runtime model-read rejection of visibility: "user" resources, client inspection, protocol bounds, epoch-28 gating of the widened start input, stop-before-switch aborting without a durable relocation, turn-interrupt isolation from user-command stop failures, Ctrl+C exit-chord recovery after a rejected stop, chronological re-insertion of preserved cards on reconnect, and transcript projection.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Codex prepared the implementation, tests, Issue, and PR description. The human contributor reviews the diff and remains responsible for submission, correctness, provenance, and licensing.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

Visual evidence

Live terminal capture from exact feature head ecfa72feb: completed user commands show their real output expanded by default, without pressing Ctrl+O, while a bare ! shows the localized inline prompt. The capture uses the local Runtime Host and Chinese TUI locale.

基于功能分支精确 head ecfa72feb 的真实终端截图:用户命令完成后无需按 Ctrl+O 即默认展开真实输出;输入裸 ! 时同时显示本地化提示。截图使用本地 Runtime Host 和中文 TUI。

Live TUI one-shot commands with default-expanded output

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary

This PR adds Codex-style !<command> support to the idle TUI. Each command runs once through Runtime Host in the current Session workspace. The TUI remains active. Results appear in a local user-command card and do not create an agent turn. The /shell interaction is removed.

The implementation extends the existing Runtime Resource, session-driver, transcript, and client-inspection paths. It does not create a separate command execution system. User commands use visibility: "user". Runtime blocks model reads, writes, and stops for these resources while allowing client inspection.

The solution is the smallest coherent path shown by the diff. It reuses shell-run resources and existing update handling. The added race handling is necessary because terminal updates can arrive before the local transcript card exists. The new protocol validation and caller checks are necessary to enforce command bounds and access restrictions.

Complexity delta

  • Authorities: Adds explicit model and client caller identities. Adds user and model shell-run visibility.
  • State: Adds user-command resource state, local transcript-card state, and one retained raced update.
  • Branches: Adds ! command parsing, idle and first-run handling, running-turn rejection, command-versus-default-shell startup, and caller-based resource access checks.
  • Configuration: Adds the UTF-8 command-size limit.
  • Public surface: Adds ShellRunVisibility, MakaUserCommand, runUserCommand, command input support, caller parameters, and user-command guidance.
  • Test burden: Adds coverage for routing, transcript projection, update replay, protocol bounds, runtime access control, and Runtime Host execution. Existing interactive-shell and model-task behavior remains covered through updated tests.
  • Removed behavior: Removes the /shell interaction.

No test or implementation area is clearly removable without weakening regression coverage. The total maintenance complexity increases, but the increase is justified by the new user-command behavior, access boundary, protocol validation, and race-replay requirements.

Validation

The reported validation includes package builds, CLI, Runtime, and Runtime Host suites, formatting, lint, and diff checks. Additional tests cover command routing, no-agent-turn behavior, transcript projection, raced update replay, caller restrictions, client inspection, protocol bounds, and Runtime Host launch parameters. The final check status remains subject to independent verification.

Review-relevant risks

  • The PR changes user-visible TUI behavior by adding !<command> and removing /shell. A maintainer must independently review this behavior.
  • The PR changes public TypeScript interfaces and Runtime Host protocol inputs. A maintainer must independently review compatibility and release impact.
  • The PR changes resource access control. Model callers cannot read, write, or stop user-visible shell runs, while client callers can inspect them. A maintainer must independently review this security boundary.
  • The PR changes Runtime Resource ownership and transcript projection. A maintainer must independently review data exposure and governance implications.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR adds !<command> execution in the TUI. Commands run through Runtime Host as user-visible, non-PTY resources. Results render in local transcript cards and remain inaccessible to model runtime reads.

Changes

One-shot user command flow

Layer / File(s) Summary
User-owned shell-run visibility
packages/core/src/shell-run.ts, packages/runtime/src/shell-run-contract.ts, packages/runtime/src/shell-run-manager.ts, packages/runtime/src/__tests__/shell-run-manager.test.ts
Shell runs now record model or user visibility. Runtime authorization limits model access to non-user resources and excludes user resources from model context summaries.
Runtime resource command startup
packages/runtime-host/src/protocol/runtime-resource.ts, packages/runtime-host/src/server/runtime-resource-coordinator.ts, packages/runtime-host/src/__tests__/runtime-resource-*
Runtime Host accepts validated commands and starts explicit commands as user-visible, non-PTY resources. Interactive shell defaults retain PTY behavior.
Session driver command execution
packages/cli/src/session-driver.ts, packages/cli/src/runtime-host-session-driver.ts, packages/cli/src/__tests__/runtime-host-session-driver.test.ts
The session driver starts one-shot commands and retains asynchronous updates that arrive before transcript card creation.
TUI parsing and transcript projection
packages/cli/src/pi-tui-runner.ts, packages/cli/src/pi-transcript.ts, packages/cli/src/tui-primary-guidance.ts, packages/cli/src/__tests__/*
The TUI parses !<command>, runs valid idle commands without an agent turn, renders local user-command cards, applies raced updates, and shows help guidance.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 313ed

The PR adds one-shot user commands, but completed commands can currently produce an extra background-task notice in addition to their local result card. This creates bounded duplicate or misleading TUI output; the change is otherwise mergeable with explicit owner follow-up to suppress that notice and cover the behavior with a test.

Suggested reviewers: m4n5ter, astro-han, jackwener

Sequence Diagram(s)

sequenceDiagram
  participant TUI
  participant SessionDriver
  participant RuntimeHost
  participant Runtime
  TUI->>SessionDriver: runUserCommand(command)
  SessionDriver->>RuntimeHost: runtime.resource.start(command)
  RuntimeHost->>Runtime: create user-visible shell run
  Runtime-->>RuntimeHost: snapshot and shell-run update
  RuntimeHost-->>SessionDriver: command result and raced update
  SessionDriver-->>TUI: local transcript card data
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement all coding objectives in issue #3209, including routing, Runtime Host execution, visibility restrictions, local cards, and update replay.
Out of Scope Changes check ✅ Passed All changes support the linked feature, including command execution, access control, protocol validation, transcript rendering, guidance, and regression tests.
Ai Use Disclosure ✅ Passed The description selects substantive generative tooling, names Codex and its scope, and the sole PR commit has a standalone consistent Generated-by: Codex trailer.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding one-shot user commands to the CLI.
Description check ✅ Passed The description covers the required summary, issue reference, verification, AI use, checklist, behavior change, and visual evidence.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

qodo-code-review Bot commented Aug 18, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Add Runtime Host-backed one-shot user commands to the TUI

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Adds idle ! execution through Runtime Host without creating agent turns.
• Keeps user-command resources client-visible while excluding them from model access and context.
• Replays raced resource updates so fast commands render complete local transcript cards.
Diagram

sequenceDiagram
  actor User
  participant TUI as CLI TUI
  participant Driver as Session Driver
  participant Host as Runtime Host
  participant Manager as Shell Manager
  participant Store as Shell Store
  participant Model
  User->>TUI: Submit !command
  TUI->>Driver: runUserCommand
  Driver->>Host: Observe then start
  Host->>Manager: Launch user-owned pipes
  Manager->>Store: Persist revisions
  Manager-->>Host: Resource update
  Host-->>Driver: Subscription and query
  Driver-->>TUI: Snapshot plus raced update
  TUI-->>User: Render local card
  Model->>Manager: Read user resource
  Manager-->>Model: Non-disclosing not found
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Spawn commands directly from the CLI
  • ➕ Simpler request path with less protocol work.
  • ➕ Could display process output without resource subscriptions.
  • ➖ Duplicates shell execution and lifecycle ownership.
  • ➖ Risks workspace, environment, cleanup, and authorization drift from Runtime Host.
  • ➖ Cannot share the existing revisioned resource projection consistently.
2. Execute commands as agent Bash turns
  • ➕ Reuses the existing model tool-call and transcript flow.
  • ➕ Avoids introducing user-owned resource visibility.
  • ➖ Creates unwanted agent turns and prompt history.
  • ➖ Exposes command input and output to model context.
  • ➖ Changes permissions and semantics for a user-only convenience command.

Recommendation: Keep the PR’s Runtime Host-backed resource approach. It preserves a single execution authority, session workspace semantics, and client projections while explicitly separating user commands from model turns; the race-safe observation and revision merge address the main cost of this architecture.

Files changed (16) +568 / -21

Enhancement (9) +215 / -19
pi-transcript.tsAdd local user-command transcript cards +31/-2

Add local user-command transcript cards

• Introduces user-owned tool cards labeled “User command” and allows shell-run updates to target either Bash or user-owned cards. Cards reuse existing shell output formatting and status projection without representing model tool calls.

packages/cli/src/pi-transcript.ts

pi-tui-runner.tsRoute leading-bang input to one-shot user commands +51/-4

Route leading-bang input to one-shot user commands

• Parses idle '!<command>' submissions, rejects empty commands and execution during active turns, and invokes the session driver without opening an agent turn. It creates a local card and applies any terminal update that raced card creation.

packages/cli/src/pi-tui-runner.ts

runtime-host-session-driver.tsStart and observe user commands through Runtime Host +45/-0

Start and observe user commands through Runtime Host

• Adds Runtime Host-backed user-command execution using the current session and resource channel. It observes updates before starting the resource, merges them by revision, and exposes the newest raced update exactly once.

packages/cli/src/runtime-host-session-driver.ts

session-driver.tsExtend session drivers with user-command execution +15/-1

Extend session drivers with user-command execution

• Defines the user-command result contract, including its initial shell snapshot and raced-update accessor. Adds an optional 'runUserCommand' capability to session drivers.

packages/cli/src/session-driver.ts

shell-run.tsPersist shell-run visibility metadata +14/-0

Persist shell-run visibility metadata

• Adds 'model' and 'user' shell-run visibility values to the core record contract. Normalization and canonical serialization now validate and preserve the optional field.

packages/core/src/shell-run.ts

runtime-resource.tsAllow bounded commands in resource start requests +22/-4

Allow bounded commands in resource start requests

• Extends 'runtime.resource.start' with an optional command for one-shot execution while retaining omission for interactive desktop terminals. Validation rejects blank commands, unknown fields, and payloads above 32 KiB.

packages/runtime-host/src/protocol/runtime-resource.ts

runtime-resource-coordinator.tsLaunch user commands as Host-owned pipe resources +8/-5

Launch user commands as Host-owned pipe resources

• Uses supplied commands for non-PTY shell runs and marks all client-started resources as user-visible. Client control and stop requests now explicitly bypass model-only visibility restrictions.

packages/runtime-host/src/server/runtime-resource-coordinator.ts

shell-run-contract.tsAdd visibility and caller context to shell contracts +5/-0

Add visibility and caller context to shell contracts

• Allows shell launches to declare model or user visibility. Write and stop operations can now distinguish model callers from trusted client control paths.

packages/runtime/src/shell-run-contract.ts

shell-run-manager.tsEnforce user-resource isolation in the shell manager +24/-3

Enforce user-resource isolation in the shell manager

• Persists shell visibility, filters user-owned runs from model context summaries, and rejects model read, write, or stop access with a non-disclosing not-found result. Explicit client callers retain inspection and lifecycle control.

packages/runtime/src/shell-run-manager.ts

Tests (6) +350 / -2
pi-transcript.test.tsVerify user-command resource updates render in transcript cards +32/-1

Verify user-command resource updates render in transcript cards

• Adds coverage that a local user-command card accepts a completed shell-run update and displays its output with a done status.

packages/cli/src/tests/pi-transcript.test.ts

pi-tui-runner.test.tsTest one-shot command routing and help guidance +51/-0

Test one-shot command routing and help guidance

• Verifies localized help advertises '!<command>' and that submitting '!pwd' invokes the user-command driver without sending an agent prompt. Adds a test driver returning a completed shell resource.

packages/cli/src/tests/pi-tui-runner.test.ts

runtime-host-session-driver.test.tsCover Runtime Host command startup and raced updates +147/-0

Cover Runtime Host command startup and raced updates

• Tests session creation, 'runtime.resource.start' inputs, pipe-mode results, and the absence of agent turns. Also verifies terminal updates arriving before card creation are retained and replayable.

packages/cli/src/tests/runtime-host-session-driver.test.ts

runtime-resource-coordinator.test.tsTest user-owned pipe resource launches +38/-1

Test user-owned pipe resource launches

• Verifies command-bearing resource starts run in pipe mode from the session workspace with user visibility. Updates the harness to inspect the most recently started pipe or PTY snapshot.

packages/runtime-host/src/tests/runtime-resource-coordinator.test.ts

runtime-resource-protocol.test.tsValidate user-command protocol inputs and size bounds +31/-0

Validate user-command protocol inputs and size bounds

• Covers valid command-bearing start requests, rejects empty or whitespace-only commands, and enforces the UTF-8 command byte limit.

packages/runtime-host/src/tests/runtime-resource-protocol.test.ts

shell-run-manager.test.tsTest model isolation for user-owned shell resources +51/-0

Test model isolation for user-owned shell resources

• Verifies user-owned commands are omitted from model background-task summaries and model reads return a non-disclosing not-found error. Confirms client inspection can still retrieve command output.

packages/runtime/src/tests/shell-run-manager.test.ts

Documentation (1) +3 / -0
tui-primary-guidance.tsDocument user commands in localized TUI help +3/-0

Document user commands in localized TUI help

• Adds English and Chinese help text describing the '!<command>' syntax and its user-only visibility.

packages/cli/src/tui-primary-guidance.ts

@qodo-code-review

qodo-code-review Bot commented Aug 18, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Reconnect erases command cards 🐞 Bug ☼ Reliability ⭐ New
Description
Disposition: fix-now. appendUserCommandToTranscript stores the card only in state.entries, so a
same-session Runtime Host reconnect replaces the transcript from durable messages, drops the local
card, and leaves later shell-run updates with no card to update.
Code

packages/cli/src/pi-transcript.ts[R320-323]

+  state.entries.push({
+    kind: 'tool',
+    toolUseId: input.commandId,
+    toolName: 'User command',
Relevance

●●● Strong

Clear reconnect data-loss bug in new feature code; team accepts reliability fixes for state-loss
issues.

PR-#3079
PR-#2945

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new function appends the user command only to volatile transcript state. The driver emits a full
transcript replacement on reconnect, and the runner routes that event to
replaceTranscriptWithStoredMessages, which assigns a newly materialized durable entry array;
because user commands are intentionally absent from stored messages, the card disappears, and
shell-run hydration only updates matching existing cards rather than recreating one.

packages/cli/src/pi-transcript.ts[315-342]
packages/cli/src/runtime-host-session-driver.ts[944-963]
packages/cli/src/pi-tui-runner.ts[424-445]
packages/cli/src/shell-run-hydration.ts[101-114]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Local `User command` cards are appended only to the in-memory transcript. A same-session Runtime Host reconnect rebuilds the transcript from stored messages and erases these cards, after which resource hydration cannot display their completion or output.

## Issue Context
Reuse the existing reconnect replacement seam rather than persisting user commands or adding another resource authority. Preserve current `userOwned` entries only for a replacement of the same active session; normal session switches may still replace the transcript, and the cards must remain excluded from model/durable history.

## Fix Focus Areas
- packages/cli/src/pi-transcript.ts[315-342]
- packages/cli/src/pi-tui-runner.ts[424-445]
- packages/cli/src/__tests__/pi-transcript.test.ts[1718-1747]
- packages/cli/src/__tests__/pi-tui-runner.test.ts[190-213]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Failed setup leaks PTY ⊘ Outdated 🐞 Bug ☼ Reliability
Description
After runtime.resource.start succeeds, a controller-acquire or initial-resize failure enters this
catch block and only releases controller ownership; it never stops the already-running resource. The
user sees an open error while the shell process and Runtime Host residency continue until the shell
independently exits.
Code

packages/cli/src/runtime-host-session-driver.ts[R372-374]

+    } catch (error) {
+      await release().catch(() => undefined);
+      throw error;
Relevance

●●● Strong

Accepted reliability precedents favor cleanup of partially initialized resources; this catch clearly
omits stopping the started resource.

PR-#3169
PR-#3176

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Resource creation occurs before acquisition and initial resize. The catch invokes release(), whose
implementation only sends runtime.resource.controller.release; stopping is a separate operation
exposed solely on the successfully returned shell, so this failure path leaves the process live and
retains Host residency until completion.

packages/cli/src/runtime-host-session-driver.ts[278-301]
packages/cli/src/runtime-host-session-driver.ts[326-374]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[156-179]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[529-559]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[564-594]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A PTY successfully started by Runtime Host remains running when subsequent controller acquisition or initial resize fails.

## Issue Context
Track that the resource has started and issue a best-effort `runtime.resource.stop` in the existing catch path before releasing ownership and rethrowing. Reuse the existing stop operation; no new lifecycle state or public API is needed beyond the local started resource reference.

## Fix Focus Areas
- packages/cli/src/runtime-host-session-driver.ts[278-301]
- packages/cli/src/runtime-host-session-driver.ts[326-374]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Shutdown leaks launching shell ⊘ Outdated 🐞 Bug ☼ Reliability
Description
Disposition: fix-now. If SIGINT/SIGTERM or TUI close occurs while driver.openInteractiveShell() is
pending, shutdown cannot stop the not-yet-assigned interactiveShell; when the request later
resolves, the detached continuation starts terminal input, activates the PTY, and waits for
completion after runMakaPiTui() has returned, potentially retaking raw terminal control and
leaking the PTY/controller while the Runtime Host connection is closing.
Code

packages/cli/src/pi-tui-runner.ts[R1359-1364]

+      shell = await input.driver.openInteractiveShell({
+        cols: terminal.columns,
+        rows: terminal.rows,
+        onData: (data) => terminal.write(data),
+      });
+      interactiveShell = shell;
Relevance

●●● Strong

Recent accepted precedents favor explicit cancellation and cleanup for in-flight asynchronous
operations, matching this shutdown leak.

PR-#3169
PR-#3079

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The /shell flow awaits an asynchronous multi-request open and stores the shell handle only after
that await returns, while the close path resolves the runner and calls stop() only on an
already-assigned interactiveShell. After a late resolution, the continuation installs terminal
handlers, starts input, activates the shell, and waits for shell.finished without first checking
closed, so shutdown during the await provides no stop path for the newly created Host resource and
terminal handling can restart during outer teardown.

packages/cli/src/pi-tui-runner.ts[623-623]
packages/cli/src/pi-tui-runner.ts[1359-1379]
packages/cli/src/pi-tui-runner.ts[609-637]
packages/cli/src/pi-tui-runner.ts[1353-1382]
packages/cli/src/pi-tui-runner.ts[2528-2537]
packages/cli/src/pi-tui-runner.ts[2961-2961]
packages/cli/src/runtime-host-tui-command.ts[54-95]
packages/cli/src/runtime-host-session-driver.ts[275-371]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A close signal can arrive while the Runtime Host shell-open request is pending. Because the shell object is assigned only after the await and shutdown stops only an already-assigned object, a successful late response can activate a PTY after TUI teardown and escape the existing shutdown stop path.

## Issue Context
Use the existing `closed` state and `MakaInteractiveShell.stop()` authority rather than adding new lifecycle state, cancellation authority, or public surface. Immediately after the driver open resolves, assign the shell and check `closed` before calling `terminal.start()`; if shutdown has started, request a best-effort stop of the newly opened shell and let the existing `finally` release the controller without starting terminal forwarding or awaiting `finished`.

## Fix Focus Areas
- packages/cli/src/pi-tui-runner.ts[1359-1379]
- packages/cli/src/pi-tui-runner.ts[1376-1382]
- packages/cli/src/pi-tui-runner.ts[620-637]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: 🧠 Deep: This push adds substantive behavior across CLI routing/transcript lifecycle, Runtime Host protocol/coordinator execution, and Runtime visibility/access-control paths, creating multiple independent correctness and security-sensitive failure modes that benefit from redundant review.

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Finding overflow, which tucks the rest behind 'View more'

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous review results

Review updated until commit 313edbb 🧠 Deep

Results up to commit 76f6a88 🧠 Deep


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Failed setup leaks PTY ⊘ Outdated 🐞 Bug ☼ Reliability
Description
After runtime.resource.start succeeds, a controller-acquire or initial-resize failure enters this
catch block and only releases controller ownership; it never stops the already-running resource. The
user sees an open error while the shell process and Runtime Host residency continue until the shell
independently exits.
Code

packages/cli/src/runtime-host-session-driver.ts[R372-374]

+    } catch (error) {
+      await release().catch(() => undefined);
+      throw error;
Relevance

●●● Strong

Accepted reliability precedents favor cleanup of partially initialized resources; this catch clearly
omits stopping the started resource.

PR-#3169
PR-#3176

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Resource creation occurs before acquisition and initial resize. The catch invokes release(), whose
implementation only sends runtime.resource.controller.release; stopping is a separate operation
exposed solely on the successfully returned shell, so this failure path leaves the process live and
retains Host residency until completion.

packages/cli/src/runtime-host-session-driver.ts[278-301]
packages/cli/src/runtime-host-session-driver.ts[326-374]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[156-179]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[529-559]
packages/runtime-host/src/server/runtime-resource-coordinator.ts[564-594]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A PTY successfully started by Runtime Host remains running when subsequent controller acquisition or initial resize fails.

## Issue Context
Track that the resource has started and issue a best-effort `runtime.resource.stop` in the existing catch path before releasing ownership and rethrowing. Reuse the existing stop operation; no new lifecycle state or public API is needed beyond the local started resource reference.

## Fix Focus Areas
- packages/cli/src/runtime-host-session-driver.ts[278-301]
- packages/cli/src/runtime-host-session-driver.ts[326-374]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Shutdown leaks launching shell ⊘ Outdated 🐞 Bug ☼ Reliability
Description
Disposition: fix-now. If SIGINT/SIGTERM or TUI close occurs while driver.openInteractiveShell() is
pending, shutdown cannot stop the not-yet-assigned interactiveShell; when the request later
resolves, the detached continuation starts terminal input, activates the PTY, and waits for
completion after runMakaPiTui() has returned, potentially retaking raw terminal control and
leaking the PTY/controller while the Runtime Host connection is closing.
Code

packages/cli/src/pi-tui-runner.ts[R1359-1364]

+      shell = await input.driver.openInteractiveShell({
+        cols: terminal.columns,
+        rows: terminal.rows,
+        onData: (data) => terminal.write(data),
+      });
+      interactiveShell = shell;
Relevance

●●● Strong

Recent accepted precedents favor explicit cancellation and cleanup for in-flight asynchronous
operations, matching this shutdown leak.

PR-#3169
PR-#3079

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The /shell flow awaits an asynchronous multi-request open and stores the shell handle only after
that await returns, while the close path resolves the runner and calls stop() only on an
already-assigned interactiveShell. After a late resolution, the continuation installs terminal
handlers, starts input, activates the shell, and waits for shell.finished without first checking
closed, so shutdown during the await provides no stop path for the newly created Host resource and
terminal handling can restart during outer teardown.

packages/cli/src/pi-tui-runner.ts[623-623]
packages/cli/src/pi-tui-runner.ts[1359-1379]
packages/cli/src/pi-tui-runner.ts[609-637]
packages/cli/src/pi-tui-runner.ts[1353-1382]
packages/cli/src/pi-tui-runner.ts[2528-2537]
packages/cli/src/pi-tui-runner.ts[2961-2961]
packages/cli/src/runtime-host-tui-command.ts[54-95]
packages/cli/src/runtime-host-session-driver.ts[275-371]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A close signal can arrive while the Runtime Host shell-open request is pending. Because the shell object is assigned only after the await and shutdown stops only an already-assigned object, a successful late response can activate a PTY after TUI teardown and escape the existing shutdown stop path.

## Issue Context
Use the existing `closed` state and `MakaInteractiveShell.stop()` authority rather than adding new lifecycle state, cancellation authority, or public surface. Immediately after the driver open resolves, assign the shell and check `closed` before calling `terminal.start()`; if shutdown has started, request a best-effort stop of the newly opened shell and let the existing `finally` release the controller without starting terminal forwarding or awaiting `finished`.

## Fix Focus Areas
- packages/cli/src/pi-tui-runner.ts[1359-1379]
- packages/cli/src/pi-tui-runner.ts[1376-1382]
- packages/cli/src/pi-tui-runner.ts[620-637]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment thread packages/cli/src/runtime-host-session-driver.ts
Comment thread packages/cli/src/pi-tui-runner.ts Outdated
@me2seeks
me2seeks marked this pull request as draft August 18, 2026 14:38
@me2seeks
me2seeks force-pushed the feat/cli-user-shell-mode branch from 76f6a88 to 313edbb Compare August 18, 2026 15:04
@me2seeks me2seeks changed the title feat(cli): add an interactive user shell feat(cli): add one-shot user commands Aug 18, 2026
@me2seeks
me2seeks marked this pull request as ready for review August 18, 2026 15:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/runtime/src/shell-run-contract.ts (1)

74-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the canonical visibility type.

Use ShellRunVisibility from packages/core/src/shell-run.ts here. The literal union duplicates the persisted visibility authority. A later visibility change can otherwise create a contract mismatch.

Disposition: optional.

As per path instructions, consolidate duplicated authority and reuse the closest existing seam.

Source: Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ab21c065-4510-4f86-b3a6-a9717fa3999f

📥 Commits

Reviewing files that changed from the base of the PR and between a3c4d0b and 313edbb.

📒 Files selected for processing (16)
  • packages/cli/src/__tests__/pi-transcript.test.ts
  • packages/cli/src/__tests__/pi-tui-runner.test.ts
  • packages/cli/src/__tests__/runtime-host-session-driver.test.ts
  • packages/cli/src/pi-transcript.ts
  • packages/cli/src/pi-tui-runner.ts
  • packages/cli/src/runtime-host-session-driver.ts
  • packages/cli/src/session-driver.ts
  • packages/cli/src/tui-primary-guidance.ts
  • packages/core/src/shell-run.ts
  • packages/runtime-host/src/__tests__/runtime-resource-coordinator.test.ts
  • packages/runtime-host/src/__tests__/runtime-resource-protocol.test.ts
  • packages/runtime-host/src/protocol/runtime-resource.ts
  • packages/runtime-host/src/server/runtime-resource-coordinator.ts
  • packages/runtime/src/__tests__/shell-run-manager.test.ts
  • packages/runtime/src/shell-run-contract.ts
  • packages/runtime/src/shell-run-manager.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 0 remain after this review.

Comment thread packages/cli/src/pi-transcript.ts
Comment thread packages/cli/src/pi-transcript.ts
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 313edbb

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core direction is sound: Runtime Host remains the sole execution and resource-lifecycle authority, and the CLI adds only a local projection. I found three concrete lifecycle/projection gaps that should be addressed before merge: commands have no cancellation or close-time cleanup, reconnect discards their only UI projection, and terminal updates reuse the model-background-task notice. The smallest design is to keep Runtime Host authoritative while having the CLI retain active user-command refs, stop them through the existing client-owned resource API, and reconstruct their cards from user-visible resource snapshots after reconnect.

AI-assisted review: Codex coordinated two independent reviewer passes and an OpenCode Go DeepSeek V4 Flash high-effort adversarial pass. I verified these findings against exact head 313edbbcf18f961714c116ebb21669f313e299cb, the relevant call paths, and current CI. No local tests were run in this review.

中文审查

整体方向正确:执行权和资源生命周期仍由 Runtime Host 统一负责,CLI 只增加本地投影。当前有三个需要修复的具体缺口:用户命令没有取消或退出清理路径;重连会删除唯一的 UI 卡片;终态更新会错误复用模型后台任务通知。最小方案是不新增执行权,而是让 CLI 保存活跃 user-command ref,通过已有 client-owned resource stop API 清理,并在重连后从用户可见资源快照重建卡片。

本次为 AI 辅助审查:Codex 协调两轮独立 reviewer 审查及 OpenCode Go DeepSeek V4 Flash high 对抗性复核,并核验了精确 head、相关调用链和当前 CI。本轮未运行本地测试。

Comment thread packages/runtime-host/src/server/runtime-resource-coordinator.ts
Comment thread packages/cli/src/pi-tui-runner.ts
Comment thread packages/cli/src/pi-transcript.ts
@Astro-Han

Copy link
Copy Markdown
Contributor

This PR adds a new user-visible TUI flow. Could you please add a screenshot showing a ! command in the idle TUI and the resulting User command card, including its completed output state? One annotated screenshot is fine. Thanks!

Posted by Codex on behalf of Astro-Han.

@me2seeks

Copy link
Copy Markdown
Contributor Author

Added the requested screenshot to the PR body. It shows an idle !echo maka-user-ok command and the completed, expanded User command card with output. No source or commits on this branch were changed.

@me2seeks
me2seeks force-pushed the feat/cli-user-shell-mode branch from 313edbb to 2c65cc5 Compare August 19, 2026 15:55

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current-head rereview confirms that the prior teardown, same-session reconnect, and duplicate-settlement findings are fixed. The actual terminal capture also matches the current UX: completed user commands are expanded by default and the bare ! hint is visible. All six commits carry Generated-by: Codex, and the PR body discloses the substantive scope.

One nonduplicate session-transition P2 remains below. Exact-head CI has not run yet because the Apache Actions lanes are still queued/unavailable, so this head is not merge-ready independently of the finding.

AI-assisted review by OpenAI Codex. I verified the range-diff from the previously reviewed head, lifecycle and projection paths, existing threads, current screenshot, provenance, and live check state.

中文

当前 head 已修复上一轮的退出清理、同 Session 重连和重复终态通知问题;真实终端截图也与当前 UX 一致。6 个提交均保留 Generated-by: Codex,PR body 的 AI 披露完整。

下面仍有一个新的 Session 切换 P2。当前 exact-head CI 还没有实际运行,因此即使不考虑 finding,也尚不可合并。

本次由 OpenAI Codex 辅助,已核对上一轮 head 的 range-diff、生命周期与投影路径、已有线程、截图、来源披露和实时检查状态。

Comment thread packages/cli/src/runtime-host-session-driver.ts
@me2seeks
me2seeks force-pushed the feat/cli-user-shell-mode branch from 3225392 to 787ad6a Compare August 20, 2026 11:19
@me2seeks
me2seeks requested a review from Astro-Han August 20, 2026 11:25

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COMMENT. One P1 that I think blocks the merge, plus four smaller findings and a contract question.

Scope note first: I reviewed this at 787ad6aae, after the rebase and the fix(cli): stop user commands before leaving their Session commit. The start-barrier and stop-generation machinery in stopUserCommands is a real improvement over the previous head, and the two threads I opened earlier — cancellation/teardown at runtime-resource-coordinator.ts:352 and stop-on-session-change at runtime-host-session-driver.ts:355 — are both genuinely addressed. Two of the findings below are residuals of those fixes rather than repeats of them.

The P1 is the compatibility epoch. This PR widens runtime.resource.start's input to accept command and leaves RUNTIME_HOST_COMPATIBILITY_EPOCH at 27, which is what main has, so a new CLI and an old remote Runtime Host still shake hands and then fail on the first ! command. Details inline. The same PR also adds visibility to the durable ShellRunRecord (packages/core/src/shell-run.ts:117, key set at :305), which an older binary reading the same workspace operational-state DB rejects as a malformed field — and listSessionShellRuns maps over the whole session, so one such row takes out that session's entire shell-run projection. Same root cause, same fix.

Two things I could not confirm and am not filing:

  • The close path. beginClose (pi-tui-runner.ts:695-704) fires void input.driver.stop().catch(() => {}) and returns, so /exit with a running !sleep 3600 does not await the runtime.resource.stop before the caller tears the connection down, and beginClose skips driver.stop() entirely when interruptRequested is already set. Against a managed host that leaves the command running and holding a maxLiveShellRuns slot. I am reasonably confident this is real but I could not construct the failure end to end at this head, so I am recording it as an observation on the existing teardown thread rather than as a numbered finding.
  • Whether runtime.resource.start being in REMOTE_OWNER_OPERATION_GRANTS is a privilege change. I do not think it is — a remote owner could already start the login-shell PTY, acquire a controller and type anything into it — but the new surface is non-interactive and scriptable, which is a different exposure profile. An explicit "no new privilege" line in the PR body would settle it.

Test gaps, none of which I am giving a P level:

  • runtime-resource-coordinator.test.ts's starts a one-shot user command in pipes without exposing it to the model asserts only the ShellRunBashInput handed to a fake runBackgroundBash; the harness's readRuntimeResource has no visibility gate, so the test cannot prove non-exposure. The real coverage is in shell-run-manager.test.ts; the name overclaims.
  • stops a running user command before switching Sessions (#3210) asserts that a runtime.resource.stop exists in the request log, not that it preceded the identity change — which is the actual claim.
  • UserCommandDriver in pi-tui-runner.test.ts returns status: 'completed' from runUserCommand, so the running-to-terminal card transition is never exercised in the runner suite.
  • The PR body's "removes /shell" is stale: neither /shell nor openInteractiveShell exists on main or in this diff.

biome format is clean on every changed TS file at this head.

AI disclosure: this review was assisted by Claude (Opus), which performed the initial code search and cross-checking. Every finding published here I re-derived myself against the source at 787ad6aae, and I dropped the ones I could not confirm at that head — the two observations above are marked as such rather than filed.

Comment thread packages/runtime-host/src/protocol/runtime-resource.ts
Comment thread packages/cli/src/runtime-host-session-driver.ts Outdated
Comment thread packages/cli/src/pi-tui-runner.ts Outdated
Comment thread packages/cli/src/runtime-host-session-driver.ts Outdated
Comment thread packages/cli/src/pi-transcript.ts Outdated
Comment thread packages/cli/src/skill-highlight-editor.ts
Comment thread packages/runtime-host/src/server/runtime-resource-coordinator.ts Outdated
me2seeks and others added 8 commits August 21, 2026 00:31
Show localized privacy and Ctrl+O guidance while the editor contains only the user-command prefix.

Generated-by: Codex
Keep the inline guidance concise while separating input, privacy, and output expansion.

Generated-by: Codex
Keep privacy details in help and show only immediate editor actions inline.

Generated-by: Codex
Reserve Ctrl+O for model tool cards and show user-invoked command output by default.

Generated-by: Codex
Session switches (/session, rewind) and /new replace the transcript,
which dropped the only projection of a running user-owned command and
disabled its Ctrl+C stop affordance while the command kept running
invisibly. Await the start-barrier-aware stop path in switchSession
before changing Session identity, and trigger the same synchronous
generation bump in startNewSession so in-flight starts self-stop. Add
running-command → switch and running-command → /new regressions.

Generated-by: Codex
…rt input

- Bump RUNTIME_HOST_COMPATIBILITY_EPOCH to 29: runtime.resource.start now
  accepts an optional one-shot command and the durable Shell Run record
  carries visibility, so a pre-widening peer must be refused at admission
  instead of failing on the first ! command.
- switchSession awaits stopUserCommands before the durable cwd relocation,
  so a rejecting stop aborts the switch with nothing committed rather than
  stranding a half-switched Session.
- driver.stop() stops user commands best-effort so a rejecting
  runtime.resource.stop is never reported as a failed turn interrupt.
- A rejected Ctrl+C user-command stop disarms the capture so the next
  press returns to the exit chord instead of being swallowed forever.
- Same-session reconnect re-inserts preserved user-command cards at their
  chronological position instead of the transcript tail.
- Scope visibility: "user" to command-carrying starts; the Desktop
  interactive login shell keeps its prior model-visible behavior.

Generated-by: Maka
@me2seeks
me2seeks force-pushed the feat/cli-user-shell-mode branch from d7552f7 to a87fc52 Compare August 20, 2026 16:41
@me2seeks

Copy link
Copy Markdown
Contributor Author

Rebased onto current main; new head a87fc5229.

  • The epoch moved 28 → 29 because main landed the relay Fast service-tier change as 28 while this was in flight. The comment and the gate test were renumbered (the test now asserts >= 29 relative to the constant instead of an exact value, so the next advance cannot silently pass this gate).
  • The tip commit's trailer now follows CONTRIBUTING's Generated-by: <tool> format; the epoch reference in its message was updated to match.
  • Local suites on the rebased branch: runtime-host 1031/1031 (the previously failing epoch assertion fixed by the renumber), cli 353/353, core 558/558, desktop main green.

Everything else from the 2026-08-20 11:31 review is unchanged from d7552f796: the widened start input is gated by the epoch, visibility is scoped to command-carrying starts, stop failures are isolated from turn interrupt and abort a Session switch before anything is committed, and reconnect re-inserts preserved cards chronologically.

中文说明

已 rebase 到最新 main;epoch 因 main 占用 28 而推进到 29,gate 测试改为相对断言,tip 提交补上合规的 Generated-by trailer。本地套件全绿。11:31 review 的全部修复保持不变,等待重新 review。

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.

feat(cli): add one-shot user commands

2 participants