Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/architecture/agent-runtime-services-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ SDK profile 当前从共享产品事实获得与 Headless CLI 相同的能力集
Rust Runtime SDK,不注册未实现的 `RuntimeServices` 能力,也不宣称完整 Desktop profile 可用。CLI 通过
一个调用级上下文把该 Rust 接口、Harness、能力注册、调用级权限和 Agentic 事件广播交给 TUI、Exec、Session、Usage 与
交互模式下的 Peer Host。Rust Runtime SDK 已承接会话创建/列举/删除/基础恢复、重命名/归档、会话模型更新、thread-goal 查询、类型化转录读取、本地分支、用量生成、
轮次提交/取消与精确结算,以及 CLI/TUI 的工具确认、拒绝和用户问题回答;固定 ID 创建使用独立的
轮次提交/取消与精确结算、用户显式 Shell 命令,以及 CLI/TUI 的工具确认、拒绝和用户问题回答;Shell 命令通过窄端口回到 Core 的正常 ToolPipeline、权限、工作区路由和持久化 owner,不构成通用 Tool 或进程执行 API。固定 ID 创建使用独立的
`create_session_with_id` 方法,普通创建 DTO 只增加可选工作区 ID 与模型 ID 事实,不承载调用方指定的会话 ID。
未实现该能力的提供方返回类型化不支持错误;实现成功时 Runtime 必须校验返回 ID 与请求完全一致,不能
替换为自动生成的 ID。`SessionSelector::Create` 仍保持自动生成。Peer Host 通过同一 Rust Runtime SDK 处理对话提交、精确取消、
Expand Down Expand Up @@ -1132,7 +1132,7 @@ Product 测试:
turn、处理基础会话控制、更新会话模型并处理工具确认/拒绝;本地工作区快照准备、文件清单、统计和文件回滚通过独立 owner port 复用 Core 实现,
富历史和其余持久化维护缺口仍通过单一 Core 兼容接口处理,不再构造独立调度器、持久化 manager 或事件队列;
wire schema、Relay ACK/重放和重连协议未在该切换中扩张。
- CLI 主会话客户端通过 Rust Runtime SDK 处理 session、transcript、fork、本地 Session undo/redo、usage report、用量卡片完成态本地命令轮次、turn、cancel 与 settlement;undo/redo 使用独立窄 port,由 Core 统一暂存 transcript、模型上下文与工作区边界,不扩展 `RuntimeServices` 为 service locator;其他 preview 缺口仍通过一个 Core 兼容接口处理;
- CLI 主会话客户端通过 Rust Runtime SDK 处理 session、transcript、fork、本地 Session undo/redo、usage report、用量卡片完成态本地命令轮次、用户显式 Shell 命令、turn、cancel 与 settlement;Shell 命令复用正常 ToolPipeline 和远程工作区路由,undo/redo 使用独立窄 port,由 Core 统一暂存 transcript、模型上下文与工作区边界,不扩展 `RuntimeServices` 为 service locator;其他 preview 缺口仍通过一个 Core 兼容接口处理;
该接口复用现有归属模块,不建立第二套状态或事件格式。
- CLI 托管的 ACP 服务端已以 `DeliveryProfile::Acp` 构造真实 Runtime Parts;会话创建/列举、轮次、取消、会话模型更新、工具确认/拒绝和
Agent 事件订阅复用同一 Agent Runtime API 语义,ACP stdio、连接与协议转换保持不变。Agentic Event Queue 仍是唯一事件归属模块;
Expand Down
961 changes: 183 additions & 778 deletions docs/architecture/cli-product-line-design.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion scripts/core-boundaries/rules/source/forbidden-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const forbiddenContentRules = [
reason: 'agent-runtime-ipc operation scope is frozen to the reviewed Shared TUI slice',
patterns: [
{
regex: /^\s+(?!(?:Health|ListSessions|CreateSession|RestoreSession|DeleteSession|ForkSession|RenameSession|UpdateSessionMode|UpdateSessionModel|ReloadSessionContext|CompactSession|UndoSession|RedoSession|SearchWorkspaceReferences|WorkspaceReferencesForMessage|WorkspaceDiff|SubmitTurn|CancelTurn|PendingPermissions|RespondPermission|SubmitUserAnswers|Unit|Sessions|SessionCreated|SessionRestored|SessionForked|SessionReverted|WorkspaceReferenceSearch|WorkspaceReferences|TurnAccepted|TurnCancelled|None|CurrentController|AttachExisting|UncontrolledTarget|Self|RuntimeIpcSessionRequirement|RuntimeIpcOperationRules|RuntimeSessionForkRequest|AgentContextReloadRequest|AgentDialogTurnRequest|AgentMessageWorkspaceReferencesRequest|AgentSessionCompactionRequest|AgentSessionCreateRequest|AgentSessionCreateResult|AgentSessionListRequest|AgentSessionModeUpdateRequest|AgentSessionModelUpdateRequest|AgentSessionRevertRequest|AgentSessionRevertResult|AgentSessionSummary|AgentTurnCancellationRequest|AgentTurnCancellationResult|AgentWorkspaceReference|AgentWorkspaceReferenceSearchRequest|AgentWorkspaceReferenceSearchResult|SessionTranscript|WorkspaceDiffSnapshot)\b)[A-Z][A-Za-z0-9_]*\b/,
regex: /^\s+(?!(?:Health|ListSessions|CreateSession|RestoreSession|DeleteSession|ForkSession|RenameSession|UpdateSessionMode|UpdateSessionModel|ReloadSessionContext|CompactSession|UndoSession|RedoSession|SearchWorkspaceReferences|WorkspaceReferencesForMessage|WorkspaceDiff|SubmitTurn|RunUserShellCommand|CancelTurn|PendingPermissions|RespondPermission|SubmitUserAnswers|Unit|Sessions|SessionCreated|SessionRestored|SessionForked|SessionReverted|WorkspaceReferenceSearch|WorkspaceReferences|TurnAccepted|TurnCancelled|None|CurrentController|AttachExisting|UncontrolledTarget|Self|RuntimeIpcSessionRequirement|RuntimeIpcOperationRules|RuntimeSessionForkRequest|AgentContextReloadRequest|AgentDialogTurnRequest|AgentMessageWorkspaceReferencesRequest|AgentSessionCompactionRequest|AgentSessionCreateRequest|AgentSessionCreateResult|AgentSessionListRequest|AgentSessionModeUpdateRequest|AgentSessionModelUpdateRequest|AgentSessionRevertRequest|AgentSessionRevertResult|AgentSessionSummary|AgentTurnCancellationRequest|AgentTurnCancellationResult|AgentUserShellCommandRequest|AgentWorkspaceReference|AgentWorkspaceReferenceSearchRequest|AgentWorkspaceReferenceSearchResult|SessionTranscript|WorkspaceDiffSnapshot)\b)[A-Z][A-Za-z0-9_]*\b/,
message:
'agent-runtime-ipc may not add archive, replay, observer, general controller-transfer, or other operations beyond the reviewed Shared TUI slice',
},
Expand Down
2 changes: 2 additions & 0 deletions scripts/core-boundaries/self-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4956,6 +4956,8 @@ async fn release_baseline_claim(release: BaselineClaimRelease) -> Result<(), Dis
runtimeIpcOperationPattern.test(' WorkspaceDiff {') ||
runtimeIpcOperationPattern.test(' WorkspaceDiffSnapshot,') ||
runtimeIpcOperationPattern.test(' SubmitTurn {') ||
runtimeIpcOperationPattern.test(' RunUserShellCommand {') ||
runtimeIpcOperationPattern.test(' AgentUserShellCommandRequest {') ||
runtimeIpcOperationPattern.test(' SessionForked {') ||
runtimeIpcOperationPattern.test(' SessionReverted {')
) {
Expand Down
203 changes: 102 additions & 101 deletions src/apps/cli/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,118 +1,119 @@
# BitFun CLI Agent Guide

Scope: this guide applies to `src/apps/cli`.
Scope: `src/apps/cli`.

Read [`docs/architecture/cli-product-line-design.md`](../../../docs/architecture/cli-product-line-design.md),
[`docs/architecture/product-architecture.md`](../../../docs/architecture/product-architecture.md), and
[`docs/architecture/product-customization-blueprint.md`](../../../docs/architecture/product-customization-blueprint.md)
before product-definition, TUI layout, branding, packaging, runtime, or plugin architecture changes.
Read the repository `AGENTS.md` first. For architecture-sensitive work, also
read:

- [`cli-product-line-design.md`](../../../docs/architecture/cli-product-line-design.md)
- [`product-architecture.md`](../../../docs/architecture/product-architecture.md)
- [`agent-runtime-deployment-design.md`](../../../docs/architecture/agent-runtime-deployment-design.md)
- [`product-customization-blueprint.md`](../../../docs/architecture/product-customization-blueprint.md) when changing product assembly, branding, or packaging

## Ownership

- This app owns Clap commands, TUI state and rendering, terminal input/lifecycle,
CLI-local settings, structured output projection, and user-facing CLI diagnostics.
- Peer Device Mode **host** support lives in `src/peer_host/`: after `/login`
(same Auth Server / Username / Password flow and `~/.bitfun` session/hint
files as Desktop), device routing stays up so Desktop controllers can
HostInvoke this process. CLI is not a Peer Mode controller. Same-machine
Desktop+CLI share one `device_id`; last AuthConnect wins.
- Shared session, turn, task, tool, permission, context, checkpoint, Subagent,
Harness, MCP, plugin, and capability facts belong to their runtime owners.
- Existing `bitfun-core/product-full` compatibility paths may remain during a
reviewed migration. Do not add new concrete managers, global mutable services,
or CLI-only copies of shared product behavior.

## Product and extension boundaries

- Assemble CLI behavior through `DeliveryProfile::Cli`, capability plans, typed
services, and capability availability. Hiding a command is not a backend
capability restriction.
- The target CLI consumes product identity, theme resources, data namespaces,
bundled product extensions, update channels, and TUI layout IDs from the
validated product assembly result. Resolved Product Manifest and TUI Blueprint
are retired design terms, not migration inputs. Do not read authoring product
definitions at runtime, add hard-coded branding/source
rewrites, or treat user plugins as product assembly inputs. Runtime capability
hiding does not prove code was physically removed.
- Product assembly may expose only the immutable protection IDs allowed by the
customization design. CLI must not turn them into user/source plugin policy or
store plugin activation, update, permission, or health state in the assembly result.
- OpenCode Prompt Commands from standard user and project configuration are
read-only live sources. CLI may send only the fully expanded prompt through the
existing agent owner; it must re-confirm changed conflict participants. Static
workspace file references and reviewed shell directives are expanded by their
shared owners before that handoff. CLI must not execute directives that the
prompt-command contract marks unsupported or add another approval store.
- OpenCode standalone JavaScript tools may execute only through the shared
external-source approval, conflict, Tool Runtime, and script-worker owners.
CLI/TUI consumes typed snapshots and actions; it must not import modules,
spawn tool workers, bypass a pending decision, or implement a second approval
store. TypeScript, dependency loading, package plugins, and hooks remain
non-executable until their own reviewed capability slice lands.
- OpenCode external subagents may execute only through the shared source
decision and existing Subagent owner. TUI consumes typed summaries and
actions checked against the current Subagent and preference revisions; it must not parse agent files, inject source
prompts directly, invent model fallbacks, or offer follow-up for the current
fresh single-run compatibility slice.
- The managed-package OpenCode adapter remains a static-preview path. Other
OpenCode plugin capabilities, Codex, and Claude remain import/reference sources
unless their own reviewed adapter design explicitly changes. Never copy
credentials or silently ignore unsupported fields.
- Keep native instruction references, explicit import records, executable plugin
sources, and credentials as separate asset classes. Importing non-executable
config must not establish executable-source policy. CLI consumes the external
source status and typed actions; it must not add another activation layer on top
of the source/plugin decision or claim that post-import confirmation can undo
candidate-module side effects.
- CLI plugin screens consume capability services, read-only status, and typed
diagnostics. They must not depend on raw PluginRuntimeClient contracts or raw ecosystem
payloads.
- Non-interactive commands return `action-required` only when the current operation
actually depends on a pending external asset. Unrelated confirmations remain in
structured status or `stderr` summaries and must not block the command.
- External ACP agents, external config import, and managed plugins are separate
capabilities with separate trust and lifecycle state.

## TUI and automation

- Keep terminal session restore, event normalization, state transitions, effects,
command dispatch, and rendering independently testable. Reducers and views do
not perform filesystem, network, config, or Agent operations directly.
- Slash commands, palette actions, and root CLI commands should map to the same
stable capability requests instead of reimplementing behavior per entrypoint.
- `json` is one result document; `stream-json` is one complete event per line.
Keep protocol stdout free of logs and preserve schema/exit-code compatibility.
- Keep `src/modes/exec.rs` as the stable module facade. The current private split
keeps lifecycle/event settlement in `exec/lifecycle.rs` and Patch capture/write
behavior in `exec/patch.rs`; further private splits are allowed when they keep
one executor, one output schema, and one lifecycle owner.
- Approval policy is invocation-scoped: interactive TUI defaults to ask;
non-interactive execution fails when confirmation is required unless an
explicit argument or managed policy approves it. Do not mutate a global
confirmation flag to implement an entrypoint default.
- Shell shortcuts, file references, background work, compact, checkpoint, and
rewind must use shared Tool/Agent Runtime, permission, cancellation, artifact,
and audit paths.
- Always restore raw mode, alternate screen, mouse capture, and paste mode after
normal exit, cancellation, initialization failure, or panic.
CLI owns only surface concerns:

- Clap entrypoints and CLI-local configuration
- terminal acquisition/restoration and input normalization
- TUI state, rendering, popups, local draft history, and local effects such as
clipboard or external-editor integration
- projection of Runtime events into text, JSON, JSONL, and user diagnostics
- Shared Runtime client/server adaptation and Peer Device host presentation

Session, turn, model round, tool execution, permissions, cancellation,
persistence, context, workspace binding, MCP, Subagent, and other product facts
belong to their shared owners. Do not add CLI-only managers or reproduce shared
behavior behind a TUI branch.

Existing Core compatibility forwarding may remain until a reviewed owner
migration has behavior-equivalence tests. A typed port is not evidence that the
runtime owner moved.

## Runtime paths

Normal interactive submissions follow:

```text
ChatView -> CliAgentRuntimeClient -> AgentRuntime SDK
-> Core owner -> Session / Agent execution / ToolPipeline
```

Shared TUI inserts versioned local IPC between `CliAgentRuntimeClient` and the
same Agent Runtime SDK. It must not create a second product implementation.
Side-effecting operations need stable identities, controller/idle rules,
bounded frames, and outcome-unknown handling before a connection can retry.

Explicit Shell input follows:

```text
SHELL composer -> AgentUserShellCommandPort -> Core coordinator
-> ToolPipeline(ExecCommand) -> TerminalPort / RemoteExecPort
-> standard UserDialog + ModelRound persistence and events
```

CLI must never spawn the submitted command directly or expose a generic tool or
process API. Explicit user input may auto-approve an interactive `ask`, but
static `deny` rules, workspace routing, cancellation, audit, and tool
restrictions remain enforced.

## TUI rules

- Derive slash commands, palette actions, help, availability, and key bindings
from the action registry. Do not add a second command table.
- Match established competitor entry flows when equivalent behavior exists.
Prefer OpenCode names and interactions; do not invent `/shell` or aliases for
the `!` Shell entry.
- Keep terminal input, state transitions, effects, and rendering independently
testable. Views and reducers do not perform filesystem, network, config, or
Agent operations.
- Shell mode is CLI presentation state only. It accepts an empty-composer `!`,
keeps chat/shell histories separate, treats `/` as command text, and rejects
images and structured `@` references before Runtime submission.
- Direct paste, `Ctrl+V`, and bracketed paste share `ComposerDraft`. Shared TUI
rejects unsupported image payloads before IPC.
- Local effects such as `/editor`, copy, and export stay local. Product work
such as shell execution, session mutation, and permissions goes through typed
Runtime owners.
- Always restore raw mode, alternate screen, mouse capture, paste mode, and the
cursor on success, error, cancellation, initialization failure, or panic.
- Protocol stdout contains only the selected result format. Logs are English,
contain no emoji, and use stderr or log files.

## Product and external-source boundaries

- Assemble CLI through `DeliveryProfile::Cli` and validated product Runtime
parts. Hiding a command is not a backend capability restriction.
- CLI consumes typed external-source summaries and actions. It does not parse
source files, import executable modules, start plugin workers, duplicate
approval state, or treat static discovery as runtime availability.
- ACP agents, configuration import, executable plugins, Hooks, and Peer Device
hosting have separate trust and lifecycle state. Do not infer one from
another.
- Remote-unsupported local effects must fail visibly; never fall back to the
controller machine.

Detailed compatibility rules belong in the dedicated architecture documents,
not in this file.

## Verification

Run the smallest checks matching the change:
Run the smallest checks matching the changed path:

```bash
cargo check -p bitfun-cli
cargo test -p bitfun-cli
```

Also run focused protocol/PTY tests when structured output, terminal lifecycle,
input, session control, config import, plugin management, or product assembly
behavior changes. Theme/color changes require `pnpm run theme:color-audit:all`.
Packaging or branding changes require the CLI package smoke path and a clean-tree
two-product build assertion.
Also run focused owner tests when a surface crosses a shared boundary:

## Install for end users
- Agent Runtime port/SDK changes: `cargo test -p bitfun-agent-runtime`
- Shared IPC/protocol changes: `cargo test -p bitfun-agent-runtime-ipc`
- Core turn/tool/persistence behavior: the focused `bitfun-core` tests, then
the repository shared-Rust verification row
- terminal lifecycle/input changes: the nearest PTY/ConPTY or input test
- product/packaging changes: product assembly and archive smoke paths

Use [`install.ps1`](install.ps1), [`install.sh`](install.sh), and [`README.md`](README.md) for
platform-native per-user installation. Document `bitfun` as primary; ship `bitfun-cli` only as the
deprecated compatibility entrypoint, and use `bitfun` in all new examples and integrations.
Use [`README.md`](README.md) for user-facing behavior and installation. Keep
developer internals here or in architecture docs instead of expanding the user
guide.
Loading
Loading