Skip to content

refactor(serve): extract DaemonWorkspaceService from AcpSessionBridge (issue #4542, 方案 C)#4563

Merged
doudouOUC merged 44 commits into
daemon_mode_b_mainfrom
feat/daemon-workspace-service
Jun 6, 2026
Merged

refactor(serve): extract DaemonWorkspaceService from AcpSessionBridge (issue #4542, 方案 C)#4563
doudouOUC merged 44 commits into
daemon_mode_b_mainfrom
feat/daemon-workspace-service

Conversation

@doudouOUC

@doudouOUC doudouOUC commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Rename HttpAcpBridgeAcpSessionBridge (now honestly session-only)
  • Extract the workspace-level status / init / tool-toggle / MCP-restart operations into a new DaemonWorkspaceService facade
  • Bridge exposes generic queryWorkspaceStatus + invokeWorkspaceCommand so the facade reaches the ACP child via callback injection (no direct bridge reference)
  • server.ts + acpHttp/dispatch.ts route those workspace ops through the facade; HTTP/ACP API surface unchanged

Scope note (updated 2026-05-31): an earlier revision of this PR also added four File/Auth/Agents/Memory sub-services, but they were never wired into any production route — the existing workspaceMemory.ts / workspaceAgents.ts handlers still serve all traffic, and two of the four were constructed with undefined deps behind throwing stubs. Per chiga0's R1 review (option b), that fully-built-but-dead layer has been removed from this PR and will land together with its route wiring + e2e tests in a follow-up. This PR is now the bridge rename + the wired workspace-level facade only.

Architecture

L2 应用层 (两个聚焦兄弟,单向依赖倒置)
┌──────────────────────────┐   ┌─────────────────────────────────┐
│ AcpSessionBridge          │   │ DaemonWorkspaceService (facade)  │
│ • session lifecycle       │   │ • status: mcp/skills/providers/  │
│ • prompt/cancel/EventBus  │   │     env/preflight                │
│ • permission mediator     │   │ • init / tool-toggle / mcp-restart│
│ • session status/config   │   │ • delegates to child via injected │
│ • runtime MCP add/remove  │   │     callbacks (no bridge ref)     │
└──────────┬───────────────┘   └─────────────────────────────────┘
           │ L3 → child

Splitting principle: workspace-scoped → service, session-scoped → bridge.

Key Design Decisions

  1. Callback injection for cross-cutting deps (publishWorkspaceEvent, queryWorkspaceStatus, invokeWorkspaceCommand) — the facade holds function refs, not the bridge type (one-way dependency inversion).
  2. originatorClientId is optional — matches existing AuditContext behavior (reads work without clientId).
  3. isChannelLive() on the bridge — wraps the internal liveChannelInfo() probe so the facade's acpChannelLive field is accurate during the cold-spawn / post-kill windows (where sessionCount > 0 would mislead).
  4. env/preflight status — uses DaemonStatusProvider (daemon-local) not an ACP query.

What's Deferred

  • File / Auth / Agents / Memory sub-services — extracted-but-unwired; deferred to the route-wiring PR together with deviceFlowRegistry/subagentManager injection, the validateClientId facade gate, and route→service e2e tests.
  • /workspace/memory, /workspace/agents route migration — still served by the existing workspaceMemory.ts / workspaceAgents.ts handlers.
  • initWorkspacefsFactory / WorkspaceFileSystem — still uses the carried-over raw node:fs implementation (with the existing TOCTOU / symlink guards); the fsFactory trust-gate + audit migration is a follow-up (no regression vs. the old bridge).
  • /acp northbound qwen/workspace/* methods — blocked on PR feat(daemon): ACP Streamable HTTP transport at /acp [RFD #721] #4472 (ACP Streamable HTTP transport).
  • workspace-scoped EventBus / ClientRegistry extraction — PR 24 territory.

Test Plan

  • cd packages/acp-bridge && npx vitest run — 309 tests pass
  • cd packages/cli && npx vitest run src/serve/workspace-service/ src/serve/daemonStatusProvider.test.ts — 40 tests pass
  • cd packages/cli && npx vitest run src/serve/server.test.ts — 373 tests pass
  • TypeScript: tsc --noEmit — 0 new errors in modified packages
  • lint + prettier clean on changed files

Closes #4542

🤖 Generated with Qwen Code


📝 描述准确性更新(2026-05-31,作者自查)

更正:initWorkspace 为逐字搬运、仍用 node:fs、删除了 FIXME 注释,并未如描述改用 fsFactory + trust gate + audit;另 getWorkspacePreflightStatus 新增 acp-locality 过滤是行为变更(非纯抽取),建议在描述中声明。

Copilot AI review requested due to automatic review settings May 27, 2026 03:00
@github-actions

Copy link
Copy Markdown
Contributor

📋 Review Summary

This PR extracts workspace-scoped capabilities from HttpAcpBridge (renamed to AcpSessionBridge) into a new DaemonWorkspaceService facade with 4 sub-services (File/Auth/Agents/Memory). The architecture is well-designed with clear separation of concerns, callback injection to avoid circular dependencies, and comprehensive test coverage (109 new tests). The implementation follows the design doc closely and maintains backward compatibility through the REST API surface.

🔍 General Feedback

  • Strong architectural decision: The scope-based splitting principle (workspace-scoped → service, session-scoped → bridge) is clean and well-executed
  • Excellent test coverage: 109 new unit + integration tests for the workspace service, plus 277 acp-bridge tests passing
  • Good use of callback injection: The queryWorkspaceStatus and invokeWorkspaceCommand callbacks elegantly avoid circular dependencies between the bridge and workspace service
  • Thoughtful design: The originatorClientId being optional matches existing AuditContext behavior, allowing reads without clientId
  • Well-documented: Comprehensive design docs and implementation plan in .qwen/superpowers/
  • Type safety: Strong TypeScript typing throughout with well-defined interfaces for all sub-services

🎯 Specific Feedback

🟡 High

  • packages/cli/src/serve/routes/workspaceFileWrite.ts:8-9 - This file still imports from ../httpAcpBridge.js instead of ../acpSessionBridge.js. The route layer should be updated to use the new workspace service for file operations rather than direct bridge access. This appears to be incomplete migration.

  • packages/cli/src/serve/server.ts - The workspace service construction in createServeApp creates a default when not injected, but this default wires up callbacks to the bridge. This creates a potential inconsistency where production uses the injected service but tests use a constructed default. Consider making the injection mandatory for clarity.

🟢 Medium

  • packages/cli/src/serve/workspace-service/memoryService.ts:103-113 - The read method uses getAllGeminiMdFilenames()[0] to pick a filename, which may not be deterministic if multiple filenames exist. Consider explicit handling of the filename selection or documentation of the fallback behavior.

  • packages/cli/src/serve/workspace-service/agentsService.ts:58-62 - The toSummary and toDetail mapper functions are defined inline. These should be extracted to a separate utility module for reusability and testability.

  • packages/cli/src/serve/workspace-service/index.ts:156-164 - The auth service construction casts deviceFlowRegistry with as DeviceFlowRegistry despite it being potentially undefined. While the comment explains this is safe, the type assertion could be avoided by making the registry required in the deps or handling the undefined case more explicitly.

  • packages/acp-bridge/src/bridgeTypes.ts:265-272 - The new queryWorkspaceStatus and invokeWorkspaceCommand methods are generic but lack JSDoc examples showing typical usage patterns. Consider adding @example tags.

🔵 Low

  • packages/cli/src/serve/workspace-service/types.ts - The file is 489 lines with many interface definitions. Consider splitting into separate files per sub-service interface (e.g., types/file.ts, types/auth.ts, etc.) for better maintainability.

  • packages/cli/src/serve/workspace-service/fileService.ts:79-82 - The edit method delegates to writeTextAtomic but doesn't capture the semantic intent of an edit operation. Consider if a dedicated edit method with diff-based semantics would be more appropriate.

  • packages/cli/src/serve/runQwenServe.ts:723-744 - The persistDisabledToolsFn is duplicated between the bridge options and workspace service deps. While the comment explains this is intentional for sharing, consider extracting to a named function in a utility module.

  • docs/superpowers/plans/2026-05-27-daemon-workspace-service.md - The implementation plan is comprehensive but the "File Map" table lists e2e.test.ts which doesn't appear in the changed files. Either the test wasn't implemented yet or should be removed from the plan.

  • packages/cli/src/serve/workspace-service/index.ts:207-216 - The getWorkspacePreflightStatus method has complex logic for stitching daemon and ACP cells. Consider extracting the cell filtering logic (filter((c) => c.locality === 'acp')) to a named helper function with a comment explaining why.

✅ Highlights

  • Excellent security boundary handling: The initWorkspace method includes thorough symlink and path escape checks (lines 250-300 in index.ts), preventing writes outside the workspace boundary even through symlinks.

  • Clean callback injection pattern: The DaemonWorkspaceServiceDeps interface uses function types for cross-cutting concerns (publishWorkspaceEvent, knownClientIds, queryWorkspaceStatus, invokeWorkspaceCommand), which elegantly decouples the service from the bridge while maintaining functionality.

  • Comprehensive error handling: The preflight status method gracefully handles both daemon and ACP query failures, falling back to idle placeholders rather than propagating errors to users.

  • Thoughtful event publishing: All mutations (tool toggle, init, MCP restart, memory writes, agent CRUD) publish workspace events for SSE fan-out, maintaining consistency with the existing bridge event system.

  • Good test structure: Tests are well-organized with clear separation between unit tests for each sub-service and integration tests for the facade.

Copilot AI 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.

Pull request overview

This PR refactors the qwen serve daemon layering by renaming the bridge (HttpAcpBridgeAcpSessionBridge) and introducing a new DaemonWorkspaceService facade intended to own workspace-scoped operations (status/env/preflight/tool toggle/init/MCP restart + sub-services for file/auth/agents/memory), while keeping the HTTP REST surface unchanged.

Changes:

  • Introduces packages/cli/src/serve/workspace-service/ (types + facade + sub-services) and rewires workspace status/mutation REST routes in server.ts to call the workspace service.
  • Renames and re-exports bridge types/factory (AcpSessionBridge / createAcpSessionBridge), and updates tests/imports accordingly across CLI and @qwen-code/acp-bridge.
  • Updates Vitest aliases to ensure monorepo tests resolve @qwen-code/acp-bridge/* subpath exports to source.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/cli/vitest.config.ts Adds aliases so CLI tests resolve @qwen-code/acp-bridge/* subpaths to live source files.
packages/cli/src/serve/workspaceMemory.ts Updates bridge type import to AcpSessionBridge.
packages/cli/src/serve/workspaceMemory.test.ts Updates test stubs/types to AcpSessionBridge.
packages/cli/src/serve/workspaceAgents.ts Updates bridge import and comment to acpSessionBridge.
packages/cli/src/serve/workspaceAgents.test.ts Updates test stubs/types to AcpSessionBridge.
packages/cli/src/serve/workspace-service/types.ts Adds workspace-service public types: request context, sub-service interfaces, facade deps.
packages/cli/src/serve/workspace-service/index.ts Implements createDaemonWorkspaceService facade and workspace status/mutation methods.
packages/cli/src/serve/workspace-service/fileService.ts Adds FileService wrapper over WorkspaceFileSystemFactory.
packages/cli/src/serve/workspace-service/authService.ts Adds AuthService wrapper over DeviceFlowRegistry.
packages/cli/src/serve/workspace-service/agentsService.ts Adds AgentsService wrapper over SubagentManager + event fan-out.
packages/cli/src/serve/workspace-service/memoryService.ts Adds MemoryService for QWEN.md/AGENTS.md discovery + write/delete fan-out.
packages/cli/src/serve/workspace-service/tests/fileService.test.ts Unit tests for FileService context mapping and delegation.
packages/cli/src/serve/workspace-service/tests/authService.test.ts Unit tests for AuthService delegation and clientId threading.
packages/cli/src/serve/workspace-service/tests/agentsService.test.ts Unit tests for AgentsService CRUD behavior and event emission.
packages/cli/src/serve/workspace-service/tests/memoryService.test.ts Unit tests for MemoryService discovery/mutation + event emission.
packages/cli/src/serve/workspace-service/tests/facade.test.ts Unit tests for facade wiring + status/mutation behavior (incl. init workspace).
packages/cli/src/serve/workspace-service/tests/integration.test.ts Integration tests verifying Express routes delegate into injected workspace service.
packages/cli/src/serve/server.ts Rewires workspace status/init/tool/MCP-restart routes to call DaemonWorkspaceService; adds workspace ctx helper.
packages/cli/src/serve/server.test.ts Updates server tests for new workspace-service behavior and wiring.
packages/cli/src/serve/runQwenServe.ts Constructs and injects DaemonWorkspaceService into createServeApp; refactors tool-disable persistence.
packages/cli/src/serve/routes/workspaceFileWrite.ts Updates bridge type import to AcpSessionBridge.
packages/cli/src/serve/permissionAudit.ts Updates doc references from createHttpAcpBridge/HttpAcpBridge to createAcpSessionBridge/AcpSessionBridge.
packages/cli/src/serve/index.ts Updates serve barrel exports to include createAcpSessionBridge and new bridge types.
packages/cli/src/serve/daemonStatusProvider.test.ts Rewrites daemon status provider integration tests to exercise workspace-service env/preflight.
packages/cli/src/serve/acpSessionBridge.ts Updates shim docs and re-exports to include createAcpSessionBridge while preserving legacy exports.
packages/acp-bridge/src/status.ts Updates BridgeTimeoutError message prefix to AcpSessionBridge.
packages/acp-bridge/src/status.test.ts Updates tests for new BridgeTimeoutError message prefix.
packages/acp-bridge/src/internal/testUtils.ts Switches test helper bridge factory to createAcpSessionBridge + AcpSessionBridge type.
packages/acp-bridge/src/bridgeTypes.ts Renames interface to AcpSessionBridge, removes workspace methods, adds generic workspace query/command methods, keeps HttpAcpBridge as deprecated alias.
packages/acp-bridge/src/bridgeOptions.ts Updates docstrings to reference createAcpSessionBridge.
packages/acp-bridge/src/bridge.test.ts Renames suite + removes tests for workspace methods migrated out of bridge.
docs/superpowers/specs/2026-05-27-daemon-workspace-service-design.md Adds implementation design doc for the refactor (方案 C).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/runQwenServe.ts Outdated
Comment thread packages/cli/src/serve/server.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/server.ts
@doudouOUC doudouOUC requested a review from chiga0 May 27, 2026 03:37
@doudouOUC doudouOUC marked this pull request as draft May 27, 2026 03:40

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] [typecheck] tsc --noEmit reports 2 errors on unchanged lines that reference a now-missing symbol:

bridge.ts(2674,14): error TS2304: Cannot find name 'STATUS_SCHEMA_VERSION'.
bridge.ts(2696,14): error TS2304: Cannot find name 'STATUS_SCHEMA_VERSION'.

The PR removed the import or definition of STATUS_SCHEMA_VERSION but two references remain in getWorkspaceMcpToolsStatus and getWorkspaceToolsStatus. This blocks the CI build step.

Comment thread packages/acp-bridge/src/bridge.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/agentsService.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/acp-bridge/src/bridge.ts
Comment thread packages/cli/src/serve/runQwenServe.ts Outdated
@doudouOUC doudouOUC force-pushed the feat/daemon-workspace-service branch from 3e6bd9e to 5882d7f Compare May 27, 2026 06:58

@chiga0 chiga0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Deep Review — PR #4563: refactor(serve): extract DaemonWorkspaceService from AcpSessionBridge

1. 架构设计评估 — 与文档一致性

PR 完整实现了参考文档 §6.2 推荐的方案 C

文档要求 PR 实现 状态
新建 DaemonWorkspaceService 作为 L2 兄弟 workspace-service/index.ts facade 一致
HttpAcpBridgeAcpSessionBridge 改名 ✅ 带 @deprecated 兼容别名 一致
拆分原则 = 是否依赖 ACP child 基本一致
两组件互不依赖 ⚠️ 见 Finding #1 部分偏离
跨切需求用单向回调注入 publishWorkspaceEvent / queryWorkspaceStatus / invokeWorkspaceCommand 一致
trust/context 单点封装 WorkspaceRequestContext 一致

2. 关键发现 (Findings)

Finding 1 [Critical] — "互不依赖"承诺被打破:workspace service 实际上深度依赖 bridge 的 live channel

// runQwenServe.ts
queryWorkspaceStatus: (method, idle) =>
  bridge.queryWorkspaceStatus(method, idle),
invokeWorkspaceCommand: (method, params, invokeOpts) =>
  bridge.invokeWorkspaceCommand(method, params, invokeOpts),
publishWorkspaceEvent: (event) => bridge.publishWorkspaceEvent(event),
knownClientIds: () => bridge.knownClientIds(),
isChannelLive: () => bridge.sessionCount > 0,

文档 §6.2 说:"两组件互不依赖",但 workspace service 的 5 个核心 deps 全部闭包 bridge 实例。这不是"互不依赖"——这是 workspace service 运行时单向依赖 bridge。

影响

  • 如果 bridge 未初始化 / shutdown,workspace service 的 status / restart 全部不可用
  • 构造顺序被锁死(bridge 先于 service)
  • 未来如果要把 workspace service 独立测试/部署,必须 mock 全部 5 个回调

建议:文档中"互不依赖"的说法应调整为"单向依赖(service → bridge callbacks),无反向"。架构上仍然合格(bridge 不知道 service 存在),但应诚实描述。或者考虑把 queryWorkspaceStatus / invokeWorkspaceCommand 的实现从 bridge 抽成独立的 ChannelAccessor,让 service 和 bridge 都依赖这个更低层的组件——真正实现"互不依赖"。


Finding 2 [Critical] — invokeWorkspaceCommand 返回 as any 类型擦除

// bridge.ts
async invokeWorkspaceCommand(method, params, invokeOpts) {
  ...
  return response as any; // ← 类型安全丧失
},

bridge 的 invokeWorkspaceCommand<T> 签名承诺返回 T,但实现用 as any 消除了类型约束。如果 ACP child 返回了不匹配 T 的结构,编译期和运行期都不会报错——下游 workspace service 会拿到一个 shape 不对的对象,直到某个字段访问 .restarted / .durationMsundefined

建议

  • 至少在 workspace service 侧对 restartMcpServer 结果做 runtime shape check
  • 或者把泛型 <T> 降级为 unknown 并在 caller 侧显式 narrow——把 unsafe cast 收到离业务最近的地方

Finding 3 [Critical] — deviceFlowRegistry: undefined / subagentManager: undefined + as 强转 = 运行时 NPE 地雷

// runQwenServe.ts
deviceFlowRegistry: undefined,
subagentManager: undefined,

但 facade 内部:

const auth = createAuthService({
  registry: deviceFlowRegistry as DeviceFlowRegistry, // undefined as DeviceFlowRegistry
});
const agents = createAgentsService({
  subagentManager: subagentManager as SubagentManager, // undefined as SubagentManager
});

facade 在构造时就创建了 sub-service 并暴露了 .auth / .agents 属性。如果任何代码路径意外调了 workspace.auth.startDeviceFlow(ctx, ...)workspace.agents.list(ctx),就会在 undefined.someMethod() 上 NPE——无任何有意义的错误消息。

建议(三选一):

  1. sub-service factory 内加 guard:if (!registry) throw new Error('AuthService: DeviceFlowRegistry not wired')
  2. .auth / .agents 做成 lazy getter,缺依赖时抛 "not available" 错误
  3. DaemonWorkspaceService 接口上把 auth / agents 标为 optional(auth?: AuthService

Finding 4 [Suggestion] — getWorkspaceEnvStatus 丢失了 bridge 原版的 error 日志

原 bridge 实现:

} catch (err) {
  writeStderrLine(`qwen serve: statusProvider.getEnvStatus failed; falling back...`);
  return createIdleEnvStatus(boundWorkspace, acpChannelLive);
}

新 workspace service 实现:

} catch {
  return createIdleEnvStatus(boundWorkspace, false);
}

诊断信息丢失。生产中如果 statusProvider.getEnvStatus 持续报错,operator 无法从 stderr 看到原因。getWorkspacePreflightStatus 的 daemon cells catch 也有同样问题。

建议:注入一个 logger 回调到 deps,在 catch 中输出错误信息。


Finding 5 [Suggestion] — getWorkspacePreflightStatus 降低了 error 结构精度

原 bridge 实现用 mapDomainErrorToErrorKind(err) 给 error cell 加了 errorKind 字段(区分 timeout / channel-close / unknown)。新实现只有 { kind, status, error }errorKind 字段丢失。SDK client 侧可能依赖此字段做差异化 UI。

建议:从 bridge 错误映射中提取 mapDomainErrorToErrorKind,在 workspace service 里复用。


Finding 6 [Suggestion] — REST routes 实际迁移范围 < PR body 描述

PR body 说 "REST routes rewired to call workspace service"。从 diff 看,实际迁移了 env/preflight/init/tool-toggle/restart。但 file / agents / memory 路由仍然在原文件里直接用 bridge(只改了类型名)。

这作为分期实施是合理的,但 PR body 应明确为 "status/init/tool-toggle/restart routes rewired; file/agents/memory route migration deferred"。


3. 分层合理性总评

维度 评价
L1 薄 ✅ 路由 handler 只做 ctx 构造 + 调 service + 错误映射
L2 聚焦 ✅ 两个 L2 门面各管一域
trust/audit 单点 WorkspaceRequestContext 贯穿所有 sub-service
bridge 瘦身 ✅ 移除了 ~750 行 workspace-local 逻辑
向后兼容 HttpAcpBridge type alias + createHttpAcpBridge re-export

4. Client 接入友好度

  • SDK 无修改:REST 接口 surface 未变,对现有 client 零影响
  • WorkspaceRequestContext 设计合理:originatorClientId optional(GET 路由不必传)、route 为 audit、workspaceCwd 为 trust boundary
  • validateClientId 独立模块,sub-service 可选用——良好的 opt-in 模式

5. 建议行动项

优先级 项目
Must Fix invokeWorkspaceCommandas any — service 侧加 runtime shape guard
Must Fix undefined as DeviceFlowRegistry 强转 — 改为 fail-early guard 或 optional 接口
Should Fix 保留 env/preflight 的 error 日志(原 bridge 有 writeStderrLine
Should Fix PR body 修正迁移范围描述
Nice to Have preflight error cell 保留 errorKind 字段
Nice to Have 文档修正:"互不依赖"→"单向回调依赖,bridge 不知道 service 存在"

@chiga0

chiga0 commented May 27, 2026

Copy link
Copy Markdown
Collaborator

补充:关于 Finding #1 "互不依赖" — 当前实现优于文档字面描述

经过进一步分析,当前 PR 的 callback injection 实现是正确的架构选择,不需要为了满足"互不依赖"的字面描述去抽出第三方组件。

为什么当前实现更好

如果要实现字面意义上的"互不依赖",就得抽出 ChannelAccessor / WorkspaceEventBus 等第三方组件,让 bridge 和 workspace service 都依赖它。但这会:

  • 多一层纯粹为了"图上好看"的抽象
  • bridge 本身持有 child process / EventBus / clientId registry 的生命周期——强行抽出是人为割裂
  • 增加理解成本,却没有带来实际的可测试性 / 可替换性收益

PR 当前的 callback injection 模式已经达到了架构上有意义的独立

维度 达成情况
类型层面不耦合 ✅ workspace service 代码中没有 import AcpSessionBridge
可独立测试 ✅ 只需 mock 5 个回调函数
无反向依赖 ✅ bridge 完全不知道 service 存在
替换自由 ✅ 未来 channel 从 bridge 拆出时,换回调实现即可

这正是 hexagonal architecture 里"通过端口解耦"的标准做法——workspace service 依赖的是 contract(函数签名),不是 concrete(bridge 类型)。实质上的 DIP(依赖倒置)已经到位。

文档建议修正

原文档 §6.2 中"两组件互不依赖"建议改为:

两组件无类型耦合、无反向依赖。workspace service 通过构造时注入的回调函数间接使用 bridge 拥有的 channel 和 EventBus 能力;bridge 不知道 service 的存在。这是单向依赖倒置——service 依赖 contract,不依赖 concrete bridge type。

这样既诚实描述了运行时的数据流方向,又不会误导读者觉得需要再抽一层。


总结:PR 在这个点上的实现选择是 pragmatic + architecturally sound 的,值得肯定。 callback injection 既保持了 bridge 的内聚性(不为外部消费者拆碎自己的内部状态),又给 workspace service 提供了干净的测试边界和未来的替换自由度。这比追求图上的"对称独立"更有工程价值。

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Fix Summary — addressing wenshao CHANGES_REQUESTED + chiga0 review

All 12 wenshao [Critical] items + chiga0 findings fixed in da8d045:

# File Issue Action
1 bridge.ts:2678 as any type erasure Fixed → as T
2a index.ts:384 restartMcpServer timeout 10s→300s Fixed → 300_000ms
2b index.ts:384 Lost ACP error translation Fixed → McpServerNotFoundError/RestartFailedError
2c index.ts:384 Lost pool-mode event fan-out Fixed → per-entry events
3 index.ts:362 Force-overwrite follows symlinks Fixed → O_WRONLY|O_NOFOLLOW + truncate
4 index.ts:341 Missing post-open parent verification Fixed → verifyParentPostOpen
5 agentsService.ts:166 Wrong event names (agent_created) Fixed → agent_changed
6 memoryService.ts:163 Wrong event names (memory_written) Fixed → memory_changed
7 agentsService.ts:159 Missing collision preflight Fixed → loadSubagent check
8 index.ts:172 acpChannelLive scoped in try Fixed → hoisted
9 index.ts:178 Silent catch (no stderr log) Fixed → writeStderrLine
10 index.ts:228 Missing errorKind in preflight error Fixed → mapDomainErrorToErrorKind
11 bridge.ts:2673 invokeWorkspaceCommand injects unwanted cwd Fixed → params only
12 index.ts undefined as DeviceFlowRegistry NPE Fixed → Proxy stub with descriptive errors

Deferred (noted, not blocking):

  • isChannelLive via sessionCount vs liveChannelInfo — acknowledged approximation, proper bridge.isChannelLive() in follow-up
  • PR body scope clarification (file/agents/memory route migration deferred) — will update

🤖 Generated with Qwen Code

Comment thread packages/acp-bridge/src/bridge.ts
Comment thread packages/acp-bridge/src/bridge.ts
Comment thread packages/acp-bridge/src/bridge.test.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/fileService.ts Outdated
Comment thread packages/acp-bridge/src/bridgeOptions.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Fix Summary R2 — addressing wenshao's second CHANGES_REQUESTED

Fixed in 210d213:

# File Issue Action
1 bridge.ts:2666 Missing <T> generic on invokeWorkspaceCommand Fixed
2 bridge.ts:25 STATUS_SCHEMA_VERSION removed from import but still used Fixed — re-added
3 bridge.test.ts:7 afterEach removed from import, breaks test suite Fixed — restored
4 index.ts:253 acpChannelLive hardcoded false in catch Fixed — uses computed value

Deferred (Suggestions):

  • Proxy stubs for auth/agents — intentional for this PR, wiring in follow-up
  • validateClientId in facade mutations — defense-in-depth, add with route migration
  • editoverwriteAtomic rename — follow-up
  • Dead BridgeOptions fields cleanup — follow-up
  • Test coverage for error translation + TOCTOU — follow-up

Comment thread packages/acp-bridge/src/bridge.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread docs/superpowers/specs/2026-05-27-daemon-workspace-service-design.md Outdated
Comment thread packages/cli/src/serve/workspace-service/agentsService.ts Outdated
@chiga0

chiga0 commented May 28, 2026

Copy link
Copy Markdown
Collaborator

[Critical] The rename from httpAcpBridge.ts to acpSessionBridge.ts left at least one stale import outside the changed-file set: packages/cli/src/serve/runQwenServe.test.ts:17 still imports type { HttpAcpBridge } from "./httpAcpBridge.js", but that file no longer exists in this PR. This will break the serve test/typecheck path once the project references are built. Either keep a compatibility shim file or update the test import to ./acpSessionBridge.js (the HttpAcpBridge alias is still exported there).

Generated By GPT-5 model

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Agreed, fixed in 25b0661 — updated runQwenServe.test.ts import to ./acpSessionBridge.js.

Comment thread packages/cli/src/serve/workspace-service/memoryService.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/acp-bridge/src/bridge.ts
Comment thread packages/cli/src/serve/workspace-service/memoryService.ts Outdated
@doudouOUC doudouOUC force-pushed the feat/daemon-workspace-service branch 2 times, most recently from 170dfa5 to 024caa8 Compare May 28, 2026 07:12

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] [build] npm run build fails with 8 TS2551/TS2339 errors in packages/cli/src/serve/acpHttp/dispatch.ts (lines 751, 757, 764, 768, 774, 793, 815, 856). The workspace-service extraction removed getWorkspaceMcpStatus, getWorkspaceSkillsStatus, getWorkspaceProvidersStatus, getWorkspaceEnvStatus, getWorkspacePreflightStatus, initWorkspace, setWorkspaceToolEnabled, and restartMcpServer from the AcpSessionBridge interface and implementation, but dispatch.ts (the ACP northbound JSON-RPC handler) still calls this.bridge.<method>(). Either wire WorkspaceService into dispatch and route through it, or keep the methods on the bridge interface until the dispatch migration PR.

Comment thread packages/cli/src/serve/server.test.ts Outdated
Comment thread packages/cli/src/serve/server.test.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Agreed, fixed in 5f09914 — injected DaemonWorkspaceService into AcpDispatcher. All 8 workspace method calls now route through the service, matching the REST surface pattern.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] [typecheck] server.test.ts lines 796, 804, 811 — 8 mock function parameters implicitly have any type (TS7006). These are on unchanged lines outside the diff hunks, so they can't be posted as inline comments. The mock helpers at lines 796 (toolName, enabled, originatorClientId), 804 (initOpts, originatorClientId), and 811 (serverName, originatorClientId, restartOpts) need explicit type annotations to satisfy noImplicitAny.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/serve/workspace-service/agentsService.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/memoryService.ts Outdated
Comment thread packages/cli/src/serve/acpHttp/dispatch.ts Outdated
Comment thread packages/cli/src/serve/server.ts
Comment thread packages/cli/src/serve/workspace-service/agentsService.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/memoryService.ts Outdated
Comment thread packages/cli/src/serve/workspace-service/agentsService.ts Outdated
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Fixed in af56189 — added explicit type annotations to mock helpers at lines 796/804/811.

@doudouOUC doudouOUC force-pushed the feat/daemon-workspace-service branch 3 times, most recently from 4272001 to 6300583 Compare May 28, 2026 17:49
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

R35 Review Response

# Thread Verdict Action
1 [Critical] Double-close in verifyParentPostOpen (ERR_INVALID_STATE on Node 22+) Agree Fixed in 9bf9ab103 — removed fh.close() from helper, callers' finally handles cleanup
2 [Suggestion] verifyParentPostOpen test coverage Defer Inherited base-branch code, scope expansion
3 [Suggestion] contextFilename hardcoded in server.ts fallback Push back Test-only fallback; production passes from runQwenServe.ts
4 [Suggestion] errors guard ? vs .length > 0 Agree Fixed in 9bf9ab103
5 [Suggestion] Double createDaemonStatusProvider in server.ts Push back Stateless, test-only fallback
6 [Suggestion] as cast in else branch bypasses union narrowing Defer Valid type improvement, follow-up
7 [Suggestion] Happy path cell merge test missing Defer Good follow-up, scope expansion

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] forceFlushMetrics() runs sequentially before bridge.shutdown() with no timeout (runQwenServe.ts:1130). If the OTLP collector is unreachable, shutdown blocks for the exporter's full timeout (typically 30s gRPC). In k8s with 30s terminationGracePeriodSeconds, the pod gets SIGKILL before bridge.shutdown() starts, orphaning agent children. Fix: add Promise.race([forceFlushMetrics(), sleep(5000)]) or flush in parallel with shutdown. This also caused 10 runQwenServe tests to hang in afterEach (server.test.ts).

— qwen3.7-max via Qwen Code /review

});
}

return result;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] as cast bypasses discriminated union narrowing on RestartMcpServerResult. By the else branch, TypeScript has already narrowed result to the second variant via 'entries' in result + result.restarted === true checks. The cast is unnecessary and erases the field's required-ness and literal type.

Suggested change
return result;
reason: result.reason,

— qwen3.7-max via Qwen Code /review

const idleCells = createIdleAcpPreflightCells();

// Get daemon cells (local, no ACP query).
let daemonCells: ServeWorkspacePreflightStatus['cells'] = [];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] getDaemonPreflightCells() and queryWorkspaceStatus() are independent (daemon cells from local state, ACP cells from child process) but execute sequentially. Parallelize with Promise.allSettled to halve /workspace/preflight latency for SDK polling.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
Comment thread packages/cli/src/serve/workspace-service/index.ts
const idleCells = createIdleAcpPreflightCells();

// Get daemon cells (local, no ACP query).
let daemonCells: ServeWorkspacePreflightStatus['cells'] = [];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] getDaemonPreflightCells() and queryWorkspaceStatus() are independent (daemon cells from local state, ACP cells from child process) but execute sequentially. /workspace/preflight is polled by SDKs on a timer — parallelize with Promise.allSettled to halve response latency.

— qwen3.7-max via Qwen Code /review

createDaemonWorkspaceService({
boundWorkspace,
contextFilename: deps.contextFilename ?? 'QWEN.md',
statusProvider: createDaemonStatusProvider(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] createDaemonStatusProvider() is called twice in createServeApp — once here for the workspace service and once at bridge construction (line ~554). runQwenServe.ts correctly creates a single shared instance. Extract a local to match:

const statusProvider = createDaemonStatusProvider();
// pass to both bridge and workspace service

— qwen3.7-max via Qwen Code /review

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

R36 Review Response

The review body's [Critical] about forceFlushMetrics() blocking shutdown is a pre-existing pattern — identical code at line 1087 of daemon_mode_b_main. Not introduced by this extraction.

# Thread Verdict Action
1 [Suggestion] getWorkspaceEnvStatus silent fallback Push back Intentional graceful degradation
2 [Suggestion] as ServeWorkspacePreflightStatus cast Defer Type improvement, follow-up
3-4 Test noise comments Resolved
5 [Critical] as cast bypasses union narrowing Push back Same as R35 #6, already deferred

No code changes needed this round — all findings are pre-existing patterns or deferred type improvements.

// Env status is answered daemon-locally from process state — no ACP
// query needed. The old bridge used statusProvider.getEnvStatus()
// directly; replicate that behavior here.
const acpChannelLive = isChannelLive?.() ?? false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] getWorkspaceEnvStatus silently returns idle placeholders on error with only writeStderrLine. No programmatic signal distinguishes "daemon working, ACP cold" from "status provider threw." Compare with getWorkspacePreflightStatus which surfaces errors in the response body's errors array. Consider mirroring that pattern.

— qwen3.7-max via Qwen Code /review

acpChannelLive,
cells: [...daemonCells, ...acpCells],
...(errors && errors.length > 0 ? { errors } : {}),
} as ServeWorkspacePreflightStatus;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] as ServeWorkspacePreflightStatus cast masks potential drift — if the interface gains a new required field, this compiles cleanly but produces an incomplete response. Build without the cast using a typed local variable with conditional errors assignment.

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

✅ Local Verification Report — PR #4563

refactor: extract DaemonWorkspaceService from AcpSessionBridge

Environment

  • macOS Darwin 25.4.0, Node.js, npm workspaces monorepo
  • Branch: daemon_mode_b_main target
  • Verified commits up to: af58779 (restore dropped gauge callbacks)

Build Verification

Step Result
npm run build (full monorepo) ✅ PASS
tsc --build (type-check) ✅ PASS

Test Results

Suite Result Details
ACP Bridge (packages/acp-bridge) ✅ 752/752 passed Full suite green
Workspace-service facade tests ✅ 40/40 passed All DaemonWorkspaceService unit tests
Workspace-service integration tests ✅ 13/13 passed End-to-end workspace lifecycle
Server workspace routes (init/status/transport) ✅ 21/21 passed 9 init + 10 status + 2 transport
CLI full suite ✅ 14841 passed, 46 failed All 46 failures are pre-existing (see below)

Pre-existing Failures (not introduced by this PR)

  • Crawler timeout tests (git binary 5s threshold)
  • Capability registry count mismatch
  • envSnapshot platform format
  • AnthropicContentGenerator identity
  • worktreeStartup git operations
  • Stale dist resolution during parallel run (transient)

None of these failures touch files modified by this PR (git diff --name-only confirmed).

Critical Review Issues — All Addressed

Issue Fix Commit
Double-close in verifyParentPostOpen 9bf9ab1
Shared MCP constant + TOCTOU race tests a83c069
Restore dropped gauge callbacks af58779

Minor Note

  • packages/cli/vitest.config.ts is missing a @qwen-code/acp-bridge/mcpTimeouts alias. Non-blocking: the package.json exports resolve correctly when acp-bridge/dist is built (which CI always does). Only affects local dev without a prior npm run build in acp-bridge.

Verdict

✅ PASS — Architecture extraction is clean, all workspace-service tests pass, Critical review items addressed, no regressions introduced.


Verified by wenshao

@doudouOUC doudouOUC merged commit 95f6ff3 into daemon_mode_b_main Jun 6, 2026
41 checks passed
@doudouOUC doudouOUC deleted the feat/daemon-workspace-service branch June 6, 2026 00:34
chiga0 pushed a commit that referenced this pull request Jun 7, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 7, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 7, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 7, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
chiga0 pushed a commit that referenced this pull request Jun 8, 2026
Rebased on daemon_mode_b_main (post #4563 merge). Adds all wave 1+2
methods in a single commit:

- Session (6): recap, btw, shell, detach, context_usage, tasks
- Memory (2): workspace/memory read + write (1MB limit, scope/mode validation)
- Files (7): read, read_bytes, stat, list, glob, write, edit (via WorkspaceFileSystem)
- Auth (4): status, device_flow start/get/cancel (projected, no verification leak)
- Workspace (5): tools, mcp/tools, mcp/servers add/remove, sessions/delete (100 cap, dedup)
- Agents (5): list, get, create, update, delete (SubagentManager)

Production hardening:
- toRpcError: FsError, MemoryError, AuthError, SubagentError → structured errorKind
- Error data propagation: catch blocks forward data to JSON-RPC error frames
- BTW_MAX_INPUT_LENGTH validation, shell audit logging
- sessions/delete: 100 cap + dedup + strict types + error preservation
- auth/status: verification material stripped (security)

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
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.

4 participants