Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
a410421
feat(worktree): 补充话题工作区生命周期命令
Aug 20, 2026
71a0d62
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 25, 2026
85930d5
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 25, 2026
684699b
fix(pm2): flush large readonly jlist output
Aug 26, 2026
5dc9961
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 26, 2026
76cbe73
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 28, 2026
975b6a0
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 28, 2026
25c4a44
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 29, 2026
07994c7
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 30, 2026
00eff99
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Aug 31, 2026
d4a4176
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 1, 2026
4f24cfc
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 2, 2026
a90ca3c
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 3, 2026
4f1c07b
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 4, 2026
88d7da9
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 5, 2026
cec1b0d
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 6, 2026
d9be1f2
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 7, 2026
dd60869
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 8, 2026
119f6fa
docs(lark): 补充透传轮次状态表情修复设计
Sep 8, 2026
e2cfc98
docs(lark): 补充透传轮次状态表情实施计划
Sep 8, 2026
fd76ccf
docs(context): 补充人类决策可靠同步设计
Sep 8, 2026
68a8ece
docs(context): 补充人类决策同步实施计划
Sep 8, 2026
4abb873
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 8, 2026
9ad44f7
fix(lark): 为透传执行补齐状态表情
Sep 9, 2026
08d4d64
docs(context): 移除未实施的决策同步方案
Sep 9, 2026
bdd886c
docs(adapter): 补充子代理等待态状态设计
Sep 9, 2026
09b7d7b
docs(adapter): 补充子代理等待态实施计划
Sep 9, 2026
3402c10
fix(adapter): 子代理运行期间保持任务工作态
Sep 9, 2026
5ba9287
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 9, 2026
e1ea2ec
fix(fleet): 隔离会话内重启的全局守护进程
Sep 9, 2026
1719b38
fix(fleet): 清理进程读回失败的启动尝试
Sep 9, 2026
ba156f2
fix(worktree): 保留未暂存文件完整路径
Sep 9, 2026
49833ae
fix(lark): 收紧执行接纳与状态表情时序
Sep 9, 2026
e1fa5b2
fix(lark): 跟踪项目启动表情登记
Sep 9, 2026
a56afed
fix(worktree): 显式隔离失败时拒绝共享回退
Sep 9, 2026
9a8a5bb
fix(quota): 空工作区话题不消耗消息额度
Sep 9, 2026
8e199bb
fix(worktree): 空工作树话题仍创建隔离目录
Sep 9, 2026
eca719d
fix(worktree): 清理时归一化工作树根目录
Sep 9, 2026
d568330
fix(worktree): 展示完整未提交文件计数
Sep 9, 2026
5f04781
fix(worktree): 串行化共享工作树创建
Sep 9, 2026
f2f6fa2
fix(safety): 完善工作树与子代理状态识别
Sep 9, 2026
4e73e85
fix(auth): 仓库文本启动前刷新轮次身份
Sep 9, 2026
7dee518
fix(worktree): 从仓库根派生共享工作树
Sep 9, 2026
fa41ffa
fix(lark): 按轮次隔离状态表情收尾
Sep 9, 2026
2e2b459
fix(worker): 凭据刷新后复核工作进程代次
Sep 9, 2026
5f86902
fix(worktree): 严格校验共享清理安全性
Sep 9, 2026
1b0d416
fix(worktree): 收敛审查发现的生命周期边界
Sep 9, 2026
3599c28
fix(worktree): 保留创建失败后的重试入口
Sep 9, 2026
7a71ea0
fix(reactions): 避免无反馈路径异步让步
Sep 9, 2026
284b401
fix(worktree): 强化确认与持久化清理重试
Sep 9, 2026
2ea0353
docs(commands): 补充持久化清理重试命令
Sep 9, 2026
b289803
fix(worktree): 覆盖恢复与特殊状态边界
Sep 9, 2026
7adddaa
fix(worktree): 串行化最终检查与删除
Sep 9, 2026
522e76b
fix(worktree): 补齐恢复凭据与子模块安全
Sep 9, 2026
317eb1f
fix(worktree): 保留最终安全失败的恢复路径
Sep 9, 2026
458bbdb
fix(worktree): 保留任务提升的隔离参数
Sep 9, 2026
3a692ee
fix(worktree): 收紧创建与确认授权边界
Sep 9, 2026
d14e8cd
test(restore): 更新凭据准备接线断言
Sep 9, 2026
783ea2d
Merge branch 'feat/topic-worktree-lifecycle' into fix/pr956-review-ro…
Sep 10, 2026
6d31784
Revert "Merge branch 'feat/topic-worktree-lifecycle' into fix/pr956-r…
Sep 10, 2026
25b5e84
fix(reactions): 按实际轮次结算话题状态
Sep 10, 2026
55e66fc
fix(claude-code): 排队中请求保持 in-progress reaction
Sep 10, 2026
418b53f
test(claude-code): 覆盖容量排队忙碌状态
Sep 10, 2026
9bffbb1
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 10, 2026
c405e3c
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 11, 2026
e3094e6
Revert "test(claude-code): 覆盖容量排队忙碌状态"
Sep 11, 2026
aec6768
Revert "fix(claude-code): 排队中请求保持 in-progress reaction"
Sep 11, 2026
39f7a2d
Revert "fix(reactions): 按实际轮次结算话题状态"
Sep 11, 2026
b0e824a
Revert "fix(reactions): 避免无反馈路径异步让步"
Sep 11, 2026
975617f
Revert "fix(lark): 按轮次隔离状态表情收尾"
Sep 11, 2026
9d84f14
Revert "fix(lark): 跟踪项目启动表情登记"
Sep 11, 2026
ad0c428
Revert "fix(lark): 收紧执行接纳与状态表情时序"
Sep 11, 2026
a6c01c0
Revert "fix(adapter): 子代理运行期间保持任务工作态"
Sep 11, 2026
76db51b
Revert "docs(adapter): 补充子代理等待态实施计划"
Sep 11, 2026
49007b7
Revert "docs(adapter): 补充子代理等待态状态设计"
Sep 11, 2026
d3d233b
Revert "fix(lark): 为透传执行补齐状态表情"
Sep 11, 2026
7a8fdb4
Revert "docs(lark): 补充透传轮次状态表情实施计划"
Sep 11, 2026
c889858
Revert "docs(lark): 补充透传轮次状态表情修复设计"
Sep 11, 2026
e09cb21
refactor(scope): 移除残留状态表情接线
Sep 11, 2026
e953ed2
refactor(scope): 移除命令层状态表情依赖
Sep 11, 2026
3a2b69d
refactor(scope): 对齐主干命令行适配测试
Sep 11, 2026
5053f52
fix(auth): 保留延迟启动的轮次凭据准备
Sep 11, 2026
9bec6a4
fix(auth): 接线延迟输入凭据准备
Sep 11, 2026
0c3a160
merge(master): 同步话题指令头与运行时更新
Sep 11, 2026
eec356d
Merge remote-tracking branch 'origin/master' into feat/topic-worktree…
Sep 11, 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
1 change: 1 addition & 0 deletions docs-site/docs/en/slash-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Just send these commands directly in a topic, and the daemon intercepts and hand
| `/retry` | Retry the most recent failed or interrupted turn (10s cooldown) |
| `/restart` | Restart the CLI process (preserving the session context) |
| `/close` | Close the session and send a recoverable card (including the CLI's own resume command) |
| `/cleanup-wt <ID>` | Retry a persisted worktree cleanup after a final removal failure; revalidates authorization, active sessions, worktree identity, and safety state before deleting |
| `/fork <task>` | Fork the current session with full context into a new sub-topic of the same topic group; the source session keeps running untouched (Claude family / Codex terminal only) |
| `/forklist` | Re-post the current session's forked-task panel with live/closed status and links to the child topics |
| `/fork --create <group name>` | Clone the current session into a freshly-created group instead of a sub-topic |
Expand Down
1 change: 1 addition & 0 deletions docs-site/docs/zh/slash-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
| `/retry` | 重试最近一个失败或被中断的 turn(10s 冷却) |
| `/restart` | 重启 CLI 进程(保留 session 上下文) |
| `/close` | 关闭会话并发送可恢复卡片(含 CLI 自身 resume 命令) |
| `/cleanup-wt <ID>` | worktree 最终删除失败后重试已持久化的清理任务;删除前会重新校验权限、活动会话、worktree 身份和安全状态 |
| `/fork <任务>` | 继承当前会话的完整上下文,在同一话题群新建并行子话题;源会话原样继续(仅 Claude 系 / Codex 终端模式) |
| `/forklist` | 重发当前会话的分身任务面板,显示运行/结束状态和子话题链接 |
| `/fork --create <群名>` | 不建子话题,改为把当前会话分身到一个新建群 |
Expand Down
5 changes: 3 additions & 2 deletions src/cli/pm2-readonly-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ pm2.Client.pingDaemon((alive: boolean) => {
if (mode === 'jlist') {
pm2.list((error: Error | null | undefined, list: unknown[]) => {
if (error) fail(`PM2 read-only jlist failed: ${error.message}`);
process.stdout.write(JSON.stringify(Array.isArray(list) ? list : []));
pm2.disconnect(() => process.exit(0));
process.stdout.write(JSON.stringify(Array.isArray(list) ? list : []), () => {
pm2.disconnect(() => process.exit(0));
});
});
return;
}
Expand Down
483 changes: 468 additions & 15 deletions src/core/command-handler.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/core/passthrough-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* chat) rather than relayed to the CLI. Used both for routing and to reject
* `customPassthroughCommands` entries that would shadow a daemon command.
*/
export const DAEMON_COMMANDS = new Set(['/close', '/restart', '/status', '/retry', '/help', '/cd', '/repo', '/rename', '/schedule', '/role', '/botconfig', '/skills', '/pair', '/login', '/adopt', '/detach', '/disconnect', '/oncall', '/project', '/group', '/g', '/relay', '/quote', '/fork', '/forklist', '/card', '/cot', '/term', '/list-slash-command', '/slash', '/subscribe-lark-doc', '/watch-comment', '/vc', '/insight', '/dashboard', '/sessions', '/vc-auth', '/issue', '/cli']);
export const DAEMON_COMMANDS = new Set(['/close', '/cleanup-wt', '/restart', '/status', '/retry', '/help', '/cd', '/repo', '/rename', '/schedule', '/role', '/botconfig', '/skills', '/pair', '/login', '/adopt', '/detach', '/disconnect', '/oncall', '/project', '/group', '/g', '/relay', '/quote', '/fork', '/forklist', '/card', '/cot', '/term', '/list-slash-command', '/slash', '/subscribe-lark-doc', '/watch-comment', '/vc', '/insight', '/dashboard', '/sessions', '/vc-auth', '/issue', '/cli']);

/**
* Slash commands that are forwarded verbatim to the underlying CLI (e.g.
Expand Down
10 changes: 9 additions & 1 deletion src/core/pending-repo-journal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import * as sessionStore from '../services/session-store.js';

export function stagePendingRepoSetup(
ds: DaemonSession,
args: Pick<PendingRepoSetup, 'mode'> & Partial<Pick<PendingRepoSetup, 'baseDir' | 'turnId'>>,
args: Pick<PendingRepoSetup, 'mode'> & Partial<Pick<
PendingRepoSetup,
'baseDir' | 'turnId' | 'force' | 'worktreePath' | 'branch' | 'reuseExisting' | 'targetSubdir'
>>,
): void {
const prior = {
queued: ds.session.queued,
Expand All @@ -19,6 +22,11 @@ export function stagePendingRepoSetup(
...(ds.pendingRawInput ? { rawInput: ds.pendingRawInput } : {}),
...(args.turnId ? { turnId: args.turnId } : {}),
...(args.baseDir ? { baseDir: args.baseDir } : {}),
...(args.force !== undefined ? { force: args.force } : {}),
...(args.worktreePath ? { worktreePath: args.worktreePath } : {}),
...(args.branch ? { branch: args.branch } : {}),
...(args.reuseExisting !== undefined ? { reuseExisting: args.reuseExisting } : {}),
...(args.targetSubdir ? { targetSubdir: args.targetSubdir } : {}),
...(ds.pendingCodexAppText !== undefined ? { codexAppText: ds.pendingCodexAppText } : {}),
...(ds.pendingCodexAppApplicationContext
? { codexAppApplicationContext: ds.pendingCodexAppApplicationContext }
Expand Down
10 changes: 9 additions & 1 deletion src/core/session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ function sessionLastMessageAtMs(session: { createdAt?: string; lastMessageAt?: s
async function resumeRestoredPendingRepoSetup(
ds: DaemonSession,
activeSessions: Map<string, DaemonSession>,
prepareTurn?: (ds: DaemonSession, turnId: string) => Promise<void> | undefined,
): Promise<void> {
const setup = ds.session.pendingRepoSetup;
if (!setup || ds.session.queuedActivationPending || !ds.pendingRepo) return;
Expand All @@ -136,6 +137,12 @@ async function resumeRestoredPendingRepoSetup(
operatorOpenId: ds.session.ownerOpenId,
activeSessions,
notify,
force: setup.force,
worktreePath: setup.worktreePath,
branch: setup.branch,
reuseExisting: setup.reuseExisting,
targetSubdir: setup.targetSubdir,
Comment on lines +140 to +144

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Prepare turn credentials when restoring pending /tw

When the daemon restarts while an explicit /tw is still pending and trigger-user authentication is enabled, this recovery invocation restores the new worktree parameters but does not supply prepareTurn. Consequently runAutoWorktreeCommit forwards no credential-preparation callback to commitRepoSelection, and a prompt recovered before its initial fork runs with the governed CLI identity withheld instead of the triggering user's credentials. The live /tw path supplies this callback, so the restart path needs equivalent wiring before the fork.

AGENTS.md reference: AGENTS.md:L121-L121

Useful? React with 👍 / 👎.

prepareTurn,
}).catch((err) => {
// Git/worktree recovery is deliberately detached. A failed publish or
// build may not reject daemon startup or erase this durable setup owner.
Expand Down Expand Up @@ -2097,6 +2104,7 @@ export async function staggeredRecoveryFork(
export async function restoreActiveSessions(
activeSessions: Map<string, DaemonSession>,
quarantinedSessionIds: ReadonlySet<string> = new Set(),
options: { prepareTurn?: (ds: DaemonSession, turnId: string) => Promise<void> | undefined } = {},
): Promise<void> {
const sessions = sessionStore.listSessions();
const restorePriority = (session: Session): number => {
Expand Down Expand Up @@ -2556,7 +2564,7 @@ export async function restoreActiveSessions(
announceSessionRow(ds);
if (restoredPendingRepo) {
try {
await resumeRestoredPendingRepoSetup(ds, activeSessions);
await resumeRestoredPendingRepoSetup(ds, activeSessions, options.prepareTurn);
} catch (err) {
// One unavailable scan/Lark send/worktree import must not abort the
// entire daemon restore. Rebuild volatile buffers from the retained
Expand Down
4 changes: 4 additions & 0 deletions src/core/worker-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,8 @@ export interface WorkerPoolCallbacks {
) => Promise<string>;
getSessionWorkingDir: (ds?: DaemonSession) => string;
getActiveCount: () => number;
/** Prepare trigger-user CLI identity before a delayed raw-input turn. */
prepareRawInputTurn?: (ds: DaemonSession, turnId: string) => void | Promise<void>;
/** Close a stale session (message withdrawn, etc.). `false` means the
* authoritative close failed and the active owner must remain retryable.
* `void` is retained for older embedders/tests that implement a synchronous
Expand Down Expand Up @@ -12181,6 +12183,8 @@ function setupWorkerHandlers(
const followUpCodexAppInput = followUp?.codexAppInputGateFrozen
? followUp.codexAppInput
: codexAppInputForSession(ds, followUp?.codexAppInput);
if (rawTurnId) await requireCallbacks().prepareRawInputTurn?.(ds, rawTurnId);
if (ds.worker !== worker || ds.workerGeneration !== workerGeneration) break;
sendWorkerSessionInput(ds, {
type: 'raw_input',
content: rawInput,
Expand Down
Loading