Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
0338764
fix(session): stabilize compaction and timed message state
stack-muggle Sep 15, 2026
e2453e9
fix(ui): compact Claude background task controls
stack-muggle Sep 15, 2026
e0e678e
fix(claude): request readable SDK thinking summaries
stack-muggle Sep 15, 2026
bad9f20
fix(claude): preserve background reply ownership and completion state
stack-muggle Sep 16, 2026
0d5c809
feat(ui): add muted themes and a global bold text preference
stack-muggle Sep 16, 2026
2310921
fix(ui): strengthen bold text across fallback fonts
stack-muggle Sep 16, 2026
9ec92e8
feat(btw): support attachments and per-chat service tiers
stack-muggle Sep 16, 2026
4a2d49b
feat(usage): show native per-turn token counts
stack-muggle Sep 16, 2026
735f289
fix(ui): restore Claude progress and readable previews
stack-muggle Sep 17, 2026
71c2d18
feat(claude): add persistent sessions and native steering
stack-muggle Sep 17, 2026
1b3cc16
fix(tui): align recovery with the merged session protocol
stack-muggle Sep 17, 2026
8b3b8c4
ci(checks): limit remote CI to pytest and web build
stack-muggle Sep 17, 2026
eb53584
fix(claude): recover failed persistent service callbacks
stack-muggle Sep 17, 2026
17d9b26
fix(claude): isolate persistent session recovery failures
stack-muggle Sep 17, 2026
b6610c4
fix(claude): recover healthy services and retire steer uploads
stack-muggle Sep 17, 2026
572e5c4
fix(claude): retry closing controller leases during recovery
stack-muggle Sep 17, 2026
2552da8
fix(claude): preserve journal gaps after background delivery failures
stack-muggle Sep 17, 2026
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
7 changes: 7 additions & 0 deletions .agents/skills/cc-remote-deploy/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ and use the repository's immutable activation transactions. Lost connectivity
means an unknown result: inspect the original operation before retrying. Do not
overwrite live directories or restart the controlling Wrapper from itself.

For Claude deployments, also read
[persistent session installation and acceptance](../../../docs/claude-session-service.md).
An independent SDK service must survive ordinary Wrapper upgrades. Check first
migration, remaining in-process `/btw` turns, and deferred queues separately;
wait for them to drain instead of interrupting work. Do not restart or replace
an active SDK service to satisfy a version/readiness check.

## Codex CLI sharing is an acceptance check

For every enabled Codex **Code** account, follow
Expand Down
66 changes: 7 additions & 59 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: CI

on:
workflow_dispatch:
workflow_call:
pull_request:
push:
Expand Down Expand Up @@ -40,82 +41,29 @@ jobs:
with:
name: ci-web-dist
path: web/dist
- name: Test and lint
run: |
.venv/bin/python -m pytest
uvx --from ruff==0.15.13 ruff check cc_remote tests deploy
- name: Run pytest
run: .venv/bin/python -m pytest

web:
name: Web
name: Web build
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Install uv for the model-free Viewer fixture
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.16"
- name: Install Viewer fixture runtime
run: |
uv venv --python 3.13 .venv
uv pip sync \
--python .venv/bin/python \
--require-hashes --only-binary=:all: --no-binary=http-ece \
requirements.lock
- uses: actions/setup-node@v6
with:
node-version-file: ".nvmrc"
cache: npm
cache-dependency-path: web/package-lock.json
- name: Install dependencies
run: |
npm --prefix web ci
npm --prefix web exec -- playwright install --with-deps chromium webkit
- name: Build, test, and lint
run: |
npm --prefix web run build
npm --prefix web run test:reliability
npm --prefix web run test:history-browser
npm --prefix web run test:viewer
npm --prefix web run lint
- name: Preserve Playwright failure evidence
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-failure-${{ github.run_attempt }}
path: web/test-results
if-no-files-found: warn
retention-days: 3
run: npm --prefix web ci
- name: Build Web client
run: npm --prefix web run build
- name: Preserve built Web client
uses: actions/upload-artifact@v4
with:
name: ci-web-dist
path: web/dist
if-no-files-found: error
retention-days: 1

deploy:
name: Deploy scripts
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- name: Validate scripts
run: |
bash -n \
deploy/install.sh \
deploy/install-relay.sh \
deploy/install-wrapper.sh \
deploy/setup-vps.sh
shellcheck -x \
deploy/install.sh \
deploy/install-relay.sh \
deploy/install-wrapper.sh \
deploy/setup-vps.sh \
deploy/setup_transaction.sh
git diff --check
46 changes: 33 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ and keep a decline or pending answer separate from deployment success. App
attachment and optional App-control MCP tools are separate user choices.

## Critical constraints / traps
- **Claude service lifetime**: when `CC_REMOTE_CLAUDE_SERVICE_SOCKET` is set,
regular Claude Code/Work SDK processes belong to the separate local service.
Wrapper shutdown detaches; explicit stop/reconnect/eviction still has its
deliberate native lifecycle. Never resubmit an accepted query during recovery,
treat a background Result as the human terminal, or restart the service during
an ordinary Wrapper deploy. See `docs/claude-session-service.md` for first
migration, remaining in-process tasks, queue drain and version boundaries.
- **Drain footgun**: after `ClaudeSDKClient.interrupt()`, the SDK does NOT kill
the session — the current turn's stream still emits a terminal
`ResultMessage(subtype="error_during_execution")`. You MUST keep consuming
Expand All @@ -50,6 +57,12 @@ attachment and optional App-control MCP tools are separate user choices.
to the terminal ResultMessage; state only returns to `idle` (and the next
query is only accepted) after that break. Reject-while-busy prevents a second
query racing the drain.
- **Claude steering**: send `priority="next"` through streaming input, keeping
the one session reader. Rebind the visible turn only on the exact native user
UUID echo. A Result before an accepted input is consumed is intermediate;
the persistent service journals this distinction and commits the original
root turn identity. Explicit Stop uses `interrupt(cancel_queued=true)` when
advertised and pending inputs exist, then drains the real Result as above.
- **cwd must match resume**: a session's jsonl lives at
`~/.claude/projects/<cwd-with-/-as->/<uuid>.jsonl`. `ClaudeAgentOptions.cwd`
MUST equal the original session's cwd or `resume` can't find it.
Expand All @@ -58,7 +71,7 @@ attachment and optional App-control MCP tools are separate user choices.
interrupt+drain verification after any upgrade (`SdkHandle.preflight()` guards
the exact verified patch at startup).
- **Claude Code is the user's daily CLI, not the SDK bundle**: Claude Code
`>=2.1.258` is required and checked before a Claude session starts. The wrapper
`>=2.1.263` is required and checked before a Claude session starts. The wrapper
defaults `CLAUDE_BIN` to `~/.local/bin/claude` and passes that path explicitly
to the SDK. An empty value keeps this default; only another absolute path may
override it. Keep that CLI updated and signed in before starting the wrapper.
Expand Down Expand Up @@ -93,7 +106,7 @@ attachment and optional App-control MCP tools are separate user choices.
transport, never the caller's Origin. Uvicorn trusts forwarded transport
metadata only from loopback Caddy. Never put tokens in URLs or protocol
message bodies; logging redacts token/password fields.
- **Protocol version gate**: current wire protocol v67 is declared by
- **Protocol version gate**: current wire protocol v71 is declared by
`PROTOCOL_VERSION` in both `protocol.py` and `web/src/protocol.ts`.
`deserialize` hard-rejects a version mismatch, and
`_Base` is `extra="forbid"`, so ANY protocol change must be deployed to all
Expand Down Expand Up @@ -219,11 +232,15 @@ attachment and optional App-control MCP tools are separate user choices.
committing, verify the stored message and scope with
`git log -1 --format=raw --stat`, then recheck
`git status --short --branch`.
- Before opening or updating **every** PR, run the complete local gate below;
a docs-only or apparently narrow change does not skip it unless the user
explicitly accepts that exception. Every command must exit zero. Expected
platform-defined test skips are allowed, but failures or missing tools must
be reported rather than silently bypassed.
- Before opening or updating a maintainer-authored PR (including work prepared
by an agent for the maintainer), run the complete local gate below. A docs-only
or apparently narrow change does not skip it unless the user explicitly
accepts that exception. Every command must exit zero. Expected platform-defined
test skips are allowed; report failures or missing tools rather than bypassing
them. During development, use checks appropriate to the change.
- Other contributors may open or update a PR without running the complete local
gate. Include the checks performed and any known validation gaps in the PR
description. Automatic CI still builds Web and runs pytest for every PR.
- Run the Web gate with Node 24 (see `.nvmrc`), matching CI. Newer Node
browser-like globals must not mask missing browser-environment guards.

Expand All @@ -232,8 +249,6 @@ attachment and optional App-control MCP tools are separate user choices.
uvx --from ruff==0.15.13 ruff check cc_remote tests deploy
npm --prefix web run build
npm --prefix web run test:reliability
npm --prefix web run test:history-browser
npm --prefix web run test:viewer
npm --prefix web run lint
bash -n \
deploy/install.sh \
Expand All @@ -249,9 +264,15 @@ shellcheck -x \
git diff --check
```

- `.github/workflows/ci.yml` repeats this gate for pushes and PRs. A local pass
is required before PR publication and does not replace green remote CI before
merge. These checks are zero-token; do not substitute a live model probe.
- `.github/workflows/ci.yml` automatically runs only the Web build and pytest
on PRs and pushes to `master`. Release tags reuse the same CI before packaging
and publishing. Pytest waits only for the Web build artifact. Lint, front-end
reliability tests and shell checks remain part of the local gate above.
- Playwright is not part of CI or the required local PR gate. Existing browser
tests remain available for explicitly requested diagnostics. When the
maintainer asks for PR acceptance, check out the requested revision, run the
application and verify the changed behavior; report the actual checks and
any remaining gaps. The automated checks above do not call a live model.

## Run / test
```bash
Expand All @@ -260,7 +281,6 @@ python -m cc_remote.relay # terminal 1 (set WEB_STATIC_DIR=web/dist to se
python -m cc_remote.wrapper # terminal 2 (on each machine running Claude/Codex)
pytest # zero-token unit tests
npm --prefix web run test:reliability
npm --prefix web run test:viewer
npm --prefix web run lint
npm --prefix web run build
```
Expand Down
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@

## Unreleased

- Combine terminal queue controls and session recovery under protocol v71.
Upgrade Relay, Wrapper, Web and TUI together. TUI recovery replaces replayed
text without duplicating existing output.

- Add an optional independent Claude session service: Wrapper reconnects recover
accepted turns and pending questions without resubmitting prompts. Include a
separate service installer and preserve account isolation.
- Support native Claude steering during active work, retaining message, attachment
and token ownership. Reserve private BTW identities before launch, refresh live
context without overwriting newer readings, and retry busy session-list reads.
- Replace replayed text prefixes and bound history summaries. Protocol v70
requires Wrapper, Relay and Web to be upgraded together.

- Preview `.mmd` and `.mermaid` Work artifacts as diagrams, with a source view.

- Keep Claude's internal recovery prompts hidden after compaction and rebuild
stale projections. Show autonomous replies after agent completion in separate
live process sections, with their own thinking, tools and working indicator.
- Stream subagent text without waiting for whole messages. Recover agent-detail
read errors and timeouts, refresh active source-backed agents, and show each
agent's own running state.
- Use a subdued text shimmer for active process and tool summaries. Present
readable command/search inputs and structured tool output, with raw data
available on demand.

- Show native input/output token counts beside the working spark, with exact
counts and cache usage on click or tap. Use subdued counters that show
the latest readings directly. Keep per-turn ownership and
replace-only recovery snapshots across reconnects (protocol v68).


- Request readable Claude thinking summaries in SDK sessions and show returned
text in the existing thinking timeline. Preserve native thinking mode,
token budget and effort across new sessions, resume and private forks.

- Accept provider-native Claude model ids (e.g. `glm-5.2` behind a custom
`ANTHROPIC_BASE_URL` gateway) as explicit model selections: they are handed
to Claude Code, persisted in the private session store, and restored across
Expand All @@ -17,6 +52,23 @@
TUI editing, cancellation and ordering controls. Reject stale queue snapshots
and changes while a message is starting. Deploy Relay, Web, Wrapper and TUI
together; protocol v66 clients cannot connect to protocol v67 services.
- Replace Claude's persistent background-task panel with a compact composer
indicator. Open details above the trigger on desktop or in a centered mobile
dialog; native task completion removes finished items and closes the indicator
when no tasks remain, independently of the parent reply's completion.
- Track Claude compaction through native status and boundary events, preserve
valid context readings during refresh failures, and show the applied automatic
compaction threshold separately from model capacity. Hide internal command
messages and keep completed-turn timestamps stable when rebuilding history.
Require Claude Code 2.1.263 or newer for the verified control APIs.
- Keep account-specific Claude controls attached to the correct session and
omit transient Codex thread notifications that have no readable history from
the session list.
- Show explicit timed-message tags, a rounded moving session outline and the
next scheduled send time. Tasks use account-scoped native queue receipts
independently of Goals (protocol v67). Session menus and task popovers
avoid the sidebar footer and the mobile visual viewport.

- Backport shared improvements from the DSH branch without adding a third
engine (protocol v66): rounded Claude/Codex Goal dialogs with native save
confirmation and mobile keyboard recovery; directory links open `/open`, and
Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@

## 未发布

- 终端队列控制与会话恢复合并使用协议 v71,Relay、Wrapper、Web 和 TUI 需要
一起升级。TUI 恢复时替换已有文本,不再重复追加已显示的内容。

- 新增可选的独立 Claude 会话服务:Wrapper 重连可恢复已接受的轮次和待回答问题,
不会重发提示词;提供独立服务安装器,并保持账号隔离。
- 支持 Claude 运行中原生引导,保留消息、附件和 token 的轮次归属;启动前预留私有
BTW 会话标识,运行中刷新上下文时保留较新读数,会话列表忙碌时自动重试读取。
- 重放时替换已有文本前缀,并限制历史摘要块数。协议升至 v70,Wrapper、Relay 和
Web 需要同步升级。

- Work Artifacts 支持 `.mmd` / `.mermaid` 图表预览,并可切换查看源码。

- 修复 Claude 压缩历史中内部续写提示泄漏为用户消息的问题,并重建旧缓存。
子代理返回后的主代理续写独立显示实时过程、思考、工具和运行提示。
- 子代理流式文字及时显示,无需等待整段消息完成;详情读取支持错误恢复与超时
重试,运行中的原生记录自动刷新,并显示子代理自己的运行状态和小火花。
- 处理过程和工具摘要使用低调的文字扫光;命令、搜索条件和结构化工具结果按
可读形式展示,原始数据可按需展开。

- 在处理中的小火花旁以低调灰色直接显示原生输入/输出 token 计数,点击查看完整数字
和缓存用量;绑定当前轮次,重连恢复不重复累计(protocol v68)。


- Claude SDK 会话明确请求思考摘要,返回内容显示在现有“思考”区域;新建、恢复
和私有分叉均保留原生思考模式、token 预算和强度。

- 支持把提供商原生模型 ID(例如自定义 `ANTHROPIC_BASE_URL` 网关下的
`glm-5.2`)作为显式模型选择:它会传给 Claude Code、写入私有会话记录,并在
重连和冷恢复后保留。仅在转录或 `/context` 元数据中“观测到”的模型 ID 依旧
Expand All @@ -13,6 +39,18 @@
- 新增服务端队列原子排序(protocol v67),TUI 编辑、取消及排序操作支持配置
快捷键。拒绝基于过期队列的排序和消息启动期间的调整。Relay、Web、Wrapper
与 TUI 必须一起升级;protocol v66 客户端不能连接 protocol v67 服务。
- Claude 后台任务改为输入区工具栏中的紧凑胶囊;桌面向上展开详情,手机居中显示。
按原生任务状态移除已结束的任务,全部结束时自动关闭小窗并隐藏入口;助手回复
完成不会提前隐藏仍在运行的后台任务。
- 按 Claude 原生状态与压缩边界更新压缩动画;上下文刷新失败时保留有效读数,
分别显示生效的自动压缩阈值和模型容量。历史中隐藏内部命令消息,避免后续压缩
改变已完成回答的时间戳。已验证的控制接口要求 Claude Code 2.1.263 或更高版本。
- 修复多账号 Claude 会话控制的持久化归属;Codex 临时线程通知尚无可读历史时,
不再生成点开后为空的会话列表项。
- 定时消息增加来源标签;待发送任务的会话卡片显示圆角流动光圈及下次发送时间。
按账号和原生队列回执关联,与 Goal 分开(protocol v67);会话菜单和任务小窗
自动避让侧栏底栏及手机可视区域。

- 整合 DSH 分支中的通用改进,保留 Claude/Codex 双引擎(protocol v66):圆角
Goal 小窗等待原生保存确认,恢复手机键盘收起后的布局;目录链接接入 `/open`,
XLSX 可预览已保存的单元格、切换工作表并下载原文件。
Expand Down
11 changes: 10 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ this optional step does not block core deployment. App-control MCP tools require
a separate choice; sharing alone does not authorize them.

## Critical constraints / traps
- **Claude service lifetime**: when `CC_REMOTE_CLAUDE_SERVICE_SOCKET` is set,
regular Claude Code/Work SDK processes belong to the separate local service.
Wrapper shutdown detaches; never resubmit an accepted query during recovery
or restart the service during an ordinary Wrapper deploy. See
`docs/claude-session-service.md` for first migration and drain boundaries.
- **Claude steering**: send `priority="next"` through the sole streaming-input
reader and rebind only on the exact native user UUID echo. A Result before
an accepted input is consumed is intermediate. Explicit Stop cancels queued
inputs when supported, then drains the real terminal Result.
- **Drain footgun**: after `ClaudeSDKClient.interrupt()`, the SDK does NOT kill
the session — the current turn's stream still emits a terminal
`ResultMessage(subtype="error_during_execution")`. You MUST keep consuming
Expand Down Expand Up @@ -88,7 +97,7 @@ a separate choice; sharing alone does not authorize them.
`useLayoutEffect` is deliberately dependency-free — late virtualizer/image
measurements settle without a React render, and constraining it to its read
set reintroduces a full-viewport jump on touch release.
- **Protocol version gate**: current wire protocol v67 is declared by
- **Protocol version gate**: current wire protocol v71 is declared by
`PROTOCOL_VERSION` in both `protocol.py` and `web/src/protocol.ts`.
`deserialize` hard-rejects a version mismatch, and
`_Base` is `extra="forbid"`, so ANY protocol change must be deployed to all
Expand Down
Loading
Loading