From 008ae0c01e9bbf0dfc8ea4711d8833da6337ae68 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Thu, 27 Aug 2026 01:28:14 +0800 Subject: [PATCH] docs(inspector): record cross-realm architecture --- ...-08-23-cross-realm-cdp-inspector.i18n.yaml | 6 + .../2026-08-23-cross-realm-cdp-inspector.md | 100 ++++++++++++++++ ...2026-08-23-cross-realm-cdp-inspector.zh.md | 100 ++++++++++++++++ ...4-cordis-runtime-tree-inspection.i18n.yaml | 6 + ...26-08-24-cordis-runtime-tree-inspection.md | 113 ++++++++++++++++++ ...08-24-cordis-runtime-tree-inspection.zh.md | 113 ++++++++++++++++++ ...ution-realms-and-protocol-planes.i18n.yaml | 6 + ...or-execution-realms-and-protocol-planes.md | 104 ++++++++++++++++ ...execution-realms-and-protocol-planes.zh.md | 104 ++++++++++++++++ docs/capability-seams.i18n.yaml | 4 +- docs/capability-seams.md | 4 + docs/capability-seams.zh.md | 4 + docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 68 +++++++++++ docs/config-catalog.zh.md | 68 +++++++++++ docs/event-producer-consumer.i18n.yaml | 4 +- docs/event-producer-consumer.md | 6 +- docs/event-producer-consumer.zh.md | 6 +- docs/module-graph.i18n.yaml | 4 +- docs/module-graph.md | 48 +++----- docs/module-graph.zh.md | 50 ++++---- docs/subsystems/extensions.i18n.yaml | 4 +- docs/subsystems/extensions.md | 18 +++ docs/subsystems/extensions.zh.md | 18 +++ packages/experimental/README.i18n.yaml | 4 +- packages/experimental/README.md | 3 +- packages/experimental/README.zh.md | 3 +- .../experimental/inspector/README.i18n.yaml | 6 + packages/experimental/inspector/README.md | 105 ++++++++++++++++ packages/experimental/inspector/README.zh.md | 105 ++++++++++++++++ scripts/gen-doc-graphs.ts | 7 ++ .../verify-package-readme-model-experience.ts | 1 + 32 files changed, 1117 insertions(+), 79 deletions(-) create mode 100644 .agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.i18n.yaml create mode 100644 .agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md create mode 100644 .agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md create mode 100644 .agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.i18n.yaml create mode 100644 .agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md create mode 100644 .agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.zh.md create mode 100644 .agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.i18n.yaml create mode 100644 .agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.md create mode 100644 .agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md create mode 100644 packages/experimental/inspector/README.i18n.yaml create mode 100644 packages/experimental/inspector/README.md create mode 100644 packages/experimental/inspector/README.zh.md diff --git a/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.i18n.yaml new file mode 100644 index 0000000000..505887522c --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md +2026-08-23-cross-realm-cdp-inspector.md: 2b4860a84982b0ed6bf749c6b408dbda9a16416e +2026-08-23-cross-realm-cdp-inspector.zh.md: 64e52fe9d57d7c30e9c16358f2b1b7345f815849 diff --git a/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md new file mode 100644 index 0000000000..2b4860a849 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md @@ -0,0 +1,100 @@ +# Agent Note: Cross-realm CDP inspector + +Status: implemented + +English | [中文](2026-08-23-cross-realm-cdp-inspector.zh.md) + +## Problem + +Host diagnostics, browser Client observations, and JavaScript debugging originate in different JavaScript realms. A debugger transport implemented on the Host main thread cannot deliver `Debugger.resume` while that thread is paused, and a design that lets each producer emit CDP directly duplicates protocol state and couples application instrumentation to Chrome's presentation protocol. + +## Decision + +`@deepseek-ai/dsh-experimental-inspector` is one private Client/Host Cordis plugin package. Its Host face starts a Node Worker; its Client face connects directly to that Worker. Cordis owns composition, service publication, bootstrap injection, and disposal only. The source protocol, Worker state, CDP server, V8 bridge, and domain adapters do not inspect Cordis runtime data. + +The Worker is the sole CDP endpoint and the sole owner of CDP state. Host and Client producers send validated observations under a versioned internal protocol; Client Runtime, Console, Sources, and semantic queries use separate typed frame families on the same authenticated carrier. A realm registry gives every DevTools connection the same Runtime, Console, Sources, and Debugger capability slots, while explicit unsupported members preserve different Host and Client support levels. + +## Realm ownership + +The Host main thread owns application objects and `globalThis.fetch`. It sends observations over a dedicated `MessagePort` and never constructs CDP messages. + +The Client page owns browser observations, evaluated values, and Client object handles. It exchanges JSON frames directly with the Worker over an authenticated ingest WebSocket, so a paused Host does not stop Client delivery or Runtime execution. + +The Inspector Worker owns HTTP discovery, both WebSocket routes, source generations, retention, realm sessions, CDP sessions, and domain adapters. Each DevTools connection opens one backend session for the Host and every connected Client realm. V8 object ids remain inside the Node Runtime backend. Client object handles remain inside the typed Client protocol. One connection-local object table maps either backend handle to CDP object ids and projects the same RemoteObject, property, exception, Console, and paused-frame types. + +Chrome DevTools consumes one page-type target. Runtime methods route by execution context or object id. Debugger source methods route by script id; Host scripts retain native debugging, while Client scripts expose read-only content and reject active debugging. `Profiler` and `HeapProfiler` remain Host-only. `Network` and the minimal page-target scaffold run inside the Worker. + +## Source protocol + +Both MessagePort and WebSocket carriers use the same JSON value set and discriminated frames. A source identifies one logical producer and one connection generation, declares capabilities and topics, sends an initial replacement, then appends sequence-numbered batches. The Worker rejects malformed, oversized, stale-generation, and undeclared-topic frames before reading domain fields. + +Delivery is ordered and best-effort. Producers never wait for an acknowledgement on an application path. A bounded producer queue reports dropped prefixes through sequence gaps; the Worker requests a new snapshot after an unexplained gap. Domain stores retain bounded state and explicitly close unfinished operations when a source disconnects. + +Runtime frames use closed command and result unions instead of method strings with untyped parameter records. Every request carries a source id, source generation, DevTools Runtime session id, request id, and command. Every result repeats those identities and the command discriminant. Console lifecycle/events, chunked source reads, and non-CDP semantic queries have separate correlated frame families. RemoteObject values, previews, property descriptors, call arguments, exceptions, Console events, debugger frames, scripts, and errors have dedicated exact decoders. + +## Client Runtime, Console, and Sources + +`Runtime.enable` publishes the Host's real execution context and one negative-id synthetic execution context for each connected Client source that declares the Runtime capability. An omitted context continues to mean Host. Client source replacement destroys the old context and creates a new context with a new generation and unique id. + +The Client Runtime subset covers `Runtime.evaluate`, `Runtime.getProperties`, `Runtime.callFunctionOn`, `Runtime.awaitPromise`, `Runtime.releaseObject`, `Runtime.releaseObjectGroup`, and `Runtime.globalLexicalScopeNames`. The Client executes commands in its page realm and retains live objects in a table isolated by DevTools Runtime session. It returns opaque handles and JSON-safe metadata; the Worker validates the result and assigns a connection-local CDP object id. An object argument may be used only by the same Client source generation and DevTools session. Closing the source, disabling Runtime, closing DevTools, releasing an object, or releasing an object group removes the corresponding handles. + +JavaScript exceptions are successful Runtime responses carrying `exceptionDetails`; transport failures use a separate error union. Finite command deadlines, object counts, property counts, source bytes, and frame bytes bound retained or returned state. + +The Client Console observer preserves the original page call and asynchronously emits one event per enabled DevTools session. Each session serializes arguments into its own `console` object group, so disconnect, Runtime disable, or `Runtime.discardConsoleEntries` can release one connection without invalidating another. Context and Fiber arguments use the same semantic reference and DOM reverse mapping as evaluation results. + +The Client discovers this package's `lib/client.js` URL from the assembled web boot graph. `Debugger.enable` reads metadata through a typed source operation, and `Debugger.getScriptSource` reassembles bounded base64 chunks; the source map remains available at the advertised URL. Client-script breakpoint, step, and call-frame operations remain explicitly unsupported because page JavaScript cannot pause its own realm and continue servicing control messages. Target-wide pause and resume continue to control the Host debugger. + +## Host debugging + +The Worker attaches each DevTools connection to the Host main isolate through its own Node inspector Session. Node Runtime, Console, Sources, and Debugger backends normalize native values and events into the same realm model used by Client backends. The common projector allocates connection-local object ids for evaluation results, Console arguments, paused scopes, and call-frame results. Breakpoint requests are translated back to native backend handles before reaching Node. The default context may receive the display name `Host` while retaining its real id and metadata. + +The Worker event loop, DevTools socket, Client ingest socket, and Node inspector Session remain runnable while Host JavaScript is paused. Host observations naturally stop until resume. + +## Fetch capture + +Fetch capture wraps `globalThis.fetch` and is enabled by default. Every later fetch records its complete URL, headers, request body, response headers, response body, timing, cancellation, and error. No field is redacted by default; using the inspector grants local DevTools access to those secrets. + +The wrapper passes a normalized Request to the original fetch, reads request and response clones on independent capture tasks, and returns the original Response as soon as fetch resolves. Capture failure never changes the caller's fetch result. Finite per-body and journal budgets prevent unbounded retention; exceeding a budget preserves the captured prefix and reports truncation. + +## Alternatives considered + +**Run the CDP server on the Host main thread.** Rejected because a breakpoint freezes the socket responsible for delivering `Debugger.resume`. + +**Relay Client observations through the Host web server.** Rejected because the relay also freezes at a Host breakpoint and makes the Client data path depend on Host responsiveness. + +**Let producers emit CDP messages.** Rejected because producer code would own Chrome-specific request ids, replay, enable state, and ordering instead of domain observations. + +**Share one Node inspector Session across DevTools clients.** Rejected because object ids, object groups, enable state, and debugger operations belong to one protocol session; sharing requires an error-prone virtual-session layer. + +**Send live Client objects or CDP object ids over WebSocket.** Rejected because JSON cannot preserve identity or behavior, and a CDP object id belongs to one DevTools session. Client-local handles plus a Worker-owned per-connection mapping preserve both ownership rules. + +**Use one untyped Runtime RPC method.** Rejected because method strings and arbitrary parameter objects cannot enforce command/result correlation, object-reference ownership, or exhaustive evolution as Runtime, Sources, and Debugger support grows. + +**Split protocol, Host, and Client into separate packages.** Rejected for the experimental phase. One package keeps the capability deployable as one Client/Host plugin while source directories and build entries preserve realm boundaries. + +**Use Undici diagnostics channels as the complete fetch source.** Rejected because they observe transport lifecycle but cannot provide complete request and response bodies without consuming application streams. They may later augment transport-level timing. + +## Verification + +- A real Worker accepts Host MessagePort and Client WebSocket sources and exposes both through one CDP target. +- Malformed, oversized, stale-generation, and sequence-gap frames cannot corrupt another source or the Worker. +- Console evaluates in the Host context and receives Host console events. +- Console lists Host and Client contexts; Client evaluation, properties, function calls, promise awaiting, and release operations preserve RemoteObject identity without sharing objects across realms or DevTools connections. +- Host and Client Console events use the same projector; Client arguments remain isolated by DevTools connection and Cordis arguments resolve to Elements nodes. +- Sources receives Host scripts and the built Client bundle; Client source reads are chunked and active debugging fails explicitly, while a breakpoint can pause the Host, evaluate a call frame, and resume. +- Host paused scopes and call-frame results use the same connection-local RemoteObject table as Runtime evaluation. +- Network replays requests that predate `Network.enable` and streams later requests without loss or duplication. +- Successful, failed, aborted, redirected, textual, binary, streaming, and truncated fetches preserve caller behavior and expose the configured captured data. +- Disposal stops capture, closes admission, disconnects V8 sessions, closes sockets, and waits for Worker exit before completing. + +## Consequences + +The Worker-owned endpoint keeps DevTools control responsive while Host JavaScript is paused and gives Host and Client observations one CDP state owner. That ownership adds the following security, resource, and compatibility costs. + +Full fetch capture intentionally exposes credentials and payloads to any local process that can attach to the CDP endpoint. Loopback binding is mandatory but is not authentication. + +Cloning request and response streams adds CPU, memory, and I/O pressure. Finite limits bound retained bytes but cannot make full capture free. + +A page-type synthetic target depends on a small set of Chrome DevTools compatibility responses outside Node's native inspector domains. Each no-op must be named and covered because silently accepting every unknown method hides protocol drift. + +Client Runtime execution uses page JavaScript evaluation, so page Content Security Policy may reject it and native DevTools command-line or REPL semantics are not promised. Read-only Client Sources do not imply active Client debugging; adding that capability requires an execution agent that remains responsive while the inspected page realm is paused. diff --git a/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md new file mode 100644 index 0000000000..64e52fe9d5 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md @@ -0,0 +1,100 @@ +# Agent Note: 跨 realm CDP Inspector + +Status: implemented + +[English](2026-08-23-cross-realm-cdp-inspector.md) | 中文 + +## Problem + +Host 诊断、浏览器 Client 观测和 JavaScript 调试来自不同 JavaScript realm。Host 主线程上的 debugger transport 无法在该线程暂停时投递 `Debugger.resume`;若每个 producer 直接生成 CDP,又会重复协议状态,并把应用观测逻辑绑到 Chrome 呈现协议。 + +## Decision + +`@deepseek-ai/dsh-experimental-inspector` 是一个私有 Client/Host 双面 Cordis 插件包。Host 面启动 Node Worker,Client 面直接连接该 Worker。Cordis 只负责组合、服务发布、bootstrap 注入与 dispose;source 协议、Worker 状态、CDP server、V8 bridge 和 domain adapter 不检查 Cordis 运行时数据。 + +Worker 是唯一 CDP endpoint,也是 CDP 状态的唯一 owner。Host 与 Client producer 通过有版本的内部协议发送验证后的观测记录;Client Runtime、Console、Sources 和语义查询在同一条鉴权 carrier 上使用相互独立的类型化帧。realm registry 为每条 DevTools 连接提供相同的 Runtime、Console、Sources 和 Debugger capability slot,并用明确的 unsupported 成员保留 Host 与 Client 的支持差异。 + +## Realm 所有权 + +Host 主线程拥有应用对象和 `globalThis.fetch`。它通过专用 `MessagePort` 发送观测记录,绝不构造 CDP 消息。 + +Client 页面拥有浏览器观测、求值得到的值和 Client object handle。它通过带鉴权的 ingest WebSocket 直接与 Worker 交换 JSON 帧,因此 Host 暂停不会阻断 Client 投递或 Runtime 执行。 + +Inspector Worker 拥有 HTTP discovery、两条 WebSocket route、source generation、保留历史、realm session、CDP session 和 domain adapter。每条 DevTools 连接为 Host 和每个已连接 Client realm 分别建立一套 backend session。V8 object id 只留在 Node Runtime backend 内。Client object handle 只留在类型化 Client 协议内。单个 connection-local object table 把两类 backend handle 映射成 CDP object id,并投影同一种 RemoteObject、property、exception、Console 与 paused-frame 类型。 + +Chrome DevTools 消费一个 page 类型 target。Runtime 方法按 execution context 或 object id 路由;Debugger source 方法按 script id 路由。Host script 保留原生调试,Client script 只暴露只读内容,并拒绝 active debugging。`Profiler` 与 `HeapProfiler` 仍然只属于 Host;`Network` 与最小 page-target scaffold 在 Worker 内执行。 + +## Source 协议 + +MessagePort 与 WebSocket carrier 使用同一组 JSON 值和判别联合帧。source 标识一个逻辑 producer 和一个连接 generation,声明 capability 与 topic,发送初始 replace,再追加带 sequence 的 batch。Worker 在读取 domain 字段前拒绝畸形、超限、旧 generation 和未声明 topic 的帧。 + +投递有序且尽力而为。producer 不在应用路径上等待 acknowledgement。有界 producer 队列通过 sequence gap 报告被丢弃的前缀;无法解释的 gap 会让 Worker 请求新 snapshot。domain store 只保留有界状态,并在 source 断开时明确关闭未完成操作。 + +Runtime 帧使用封闭的 command 与 result 联合,而不是 method 字符串加无类型 parameter record。每个 request 携带 source id、source generation、DevTools Runtime session id、request id 和 command;每个 result 重复这些身份与 command 判别符。Console lifecycle/event、分块 source 读取和非 CDP 语义查询使用各自独立的关联帧。RemoteObject value、preview、property descriptor、call argument、exception、Console event、debugger frame、script 与 error 都有独立的精确 decoder。 + +## Client Runtime、Console 与 Sources + +`Runtime.enable` 发布 Host 的真实 execution context,并为每个声明 Runtime 能力的已连接 Client source 发布一个负数 id synthetic execution context。不指定 context 仍然表示 Host。Client source replacement 会销毁旧 context,并以新的 generation 与 unique id 创建新 context。 + +Client Runtime 子集包括 `Runtime.evaluate`、`Runtime.getProperties`、`Runtime.callFunctionOn`、`Runtime.awaitPromise`、`Runtime.releaseObject`、`Runtime.releaseObjectGroup` 和 `Runtime.globalLexicalScopeNames`。Client 在页面 realm 中执行命令,并在按 DevTools Runtime session 隔离的表中保留实时对象。Client 只返回不透明 handle 与 JSON-safe metadata;Worker 验证结果并分配连接私有的 CDP object id。对象参数只能由同一 Client source generation 与 DevTools session 使用。source 断开、Runtime disable、DevTools 关闭、释放对象或释放 object group 都会移除对应 handle。 + +JavaScript exception 是携带 `exceptionDetails` 的成功 Runtime response;transport failure 使用独立的 error 联合。有限的命令 deadline、对象数、属性数、source 字节数与帧字节数约束保留或返回的状态。 + +Client Console observer 保持原始页面调用行为,并为每个已启用的 DevTools session 异步发出一份 event。每个 session 把 argument 序列化到自己的 `console` object group,因此断联、Runtime disable 或 `Runtime.discardConsoleEntries` 可以释放一条连接而不使其他连接失效。Context 与 Fiber argument 使用和求值结果相同的语义引用及 DOM 反向映射。 + +Client 从组装后的 web boot graph 发现本包 `lib/client.js` 的 URL。`Debugger.enable` 通过类型化 source operation 读取 metadata,`Debugger.getScriptSource` 重组有界 base64 chunk;source map 保持在公布的 URL 上可用。Client script breakpoint、step 与 call-frame 操作明确不受支持,因为页面 JavaScript 无法暂停自身 realm 后继续处理控制消息。target-wide pause 与 resume 继续控制 Host debugger。 + +## Host 调试 + +Worker 为每条 DevTools 连接建立独立 Node inspector Session,并连接 Host 主 isolate。Node Runtime、Console、Sources 与 Debugger backend 把原生 value 和 event 归一化成 Client backend 使用的同一种 realm model。公共 projector 为求值结果、Console argument、paused scope 和 call-frame result 分配 connection-local object id。breakpoint request 到达 Node 前会反向转换成原生 backend handle。默认 context 可以改显示名为 `Host`,但保留真实 id 和 metadata。 + +Host JavaScript 暂停时,Worker event loop、DevTools socket、Client ingest socket 与 Node inspector Session 仍可运行。Host 观测自然暂停到 resume。 + +## Fetch 采集 + +fetch 采集包装 `globalThis.fetch`,并默认开启。之后每次 fetch 都记录完整 URL、headers、请求体、响应 headers、响应体、时间、取消与错误。默认不脱敏任何字段;启用 Inspector 即把这些秘密交给本机 DevTools。 + +wrapper 把标准化 Request 交给原 fetch,通过独立采集任务读取 request/response clone,并在 fetch resolve 后立即把原始 Response 交给调用方。采集失败不得改变调用方的 fetch 结果。有限的单体与 journal 预算阻止无界保留;超过预算时保留已采集前缀并报告截断。 + +## Alternatives considered + +**在 Host 主线程运行 CDP server。** 拒绝,因为断点会冻结负责投递 `Debugger.resume` 的 socket。 + +**经 Host web server 中转 Client 观测。** 拒绝,因为 Host 断点同样冻结中转,并使 Client 数据路径依赖 Host 响应。 + +**让 producer 直接生成 CDP 消息。** 拒绝,因为 Chrome 专用 request id、回放、enable 状态和排序会落入 producer,而不是领域观测。 + +**多个 DevTools client 共用一个 Node inspector Session。** 拒绝,因为 object id、object group、enable 状态与 debugger 操作属于单个协议 session;共享需要易错的虚拟 session 层。 + +**通过 WebSocket 发送 Client 实时对象或 CDP object id。** 拒绝,因为 JSON 无法保留对象身份或行为,而 CDP object id 只属于一条 DevTools session。Client-local handle 加 Worker 所有的逐连接映射同时维护这两条所有权规则。 + +**使用一个无类型 Runtime RPC method。** 拒绝,因为 method 字符串和任意 parameter object 无法保证 command/result 关联、对象引用所有权,也无法在 Runtime、Sources 与 Debugger 支持增长时做穷尽演进。 + +**把 protocol、Host 与 Client 拆成多个包。** 实验阶段拒绝。一个包保持能力以一个 Client/Host 插件部署,同时由源码目录与构建入口维护 realm 边界。 + +**用 Undici diagnostics channel 作为完整 fetch 数据源。** 拒绝,因为它能观察 transport lifecycle,却无法在不消费应用 stream 的前提下提供完整 request/response body。后续可以用它补充 transport 级 timing。 + +## Verification + +- 真实 Worker 同时接收 Host MessagePort 与 Client WebSocket source,并通过一个 CDP target 暴露两者。 +- 畸形、超限、旧 generation 与 sequence gap 帧不会破坏其他 source 或 Worker。 +- Console 在 Host context 求值并接收 Host console event。 +- Console 列出 Host 与 Client context;Client 求值、属性、函数调用、Promise await 与释放操作维持 RemoteObject 身份,且不在 realm 或 DevTools 连接之间共享对象。 +- Host 与 Client Console event 使用相同 projector;Client argument 按 DevTools 连接隔离,Cordis argument 可以解析到 Elements node。 +- Sources 接收 Host script 与构建后的 Client bundle;Client source 读取采用分块传输,active debugging 明确失败,而 Host 仍可被断点暂停、求值 call frame 并 resume。 +- Host paused scope 与 call-frame result 使用和 Runtime 求值相同的 connection-local RemoteObject table。 +- Network 回放 `Network.enable` 前的请求,并无遗漏、无重复地推送后续请求。 +- 成功、失败、取消、重定向、文本、二进制、流式与截断 fetch 都保持调用方行为,并暴露配置允许的完整采集数据。 +- dispose 停止采集、关闭入口、断开 V8 session、关闭 socket,并等待 Worker exit 后完成。 + +## Consequences + +Worker 所有的 endpoint 在 Host JavaScript 暂停时仍保持 DevTools 控制可响应,并让 Host 与 Client 观测共享唯一 CDP 状态 owner。这项所有权带来以下安全、资源与兼容性成本。 + +完整 fetch 采集会有意把 credential 和 payload 暴露给任何能连接 CDP endpoint 的本机进程。loopback 监听是强制要求,但不是鉴权。 + +clone request/response stream 会增加 CPU、内存与 I/O 压力。有限预算能约束保留字节,不能让完整采集没有成本。 + +page 类型 synthetic target 依赖 Node 原生 inspector domain 之外的一组 Chrome DevTools 兼容响应。每个 no-op 都必须明确命名并有测试;统一吞掉未知方法会掩盖协议漂移。 + +Client Runtime 执行使用页面 JavaScript 求值,因此页面 Content Security Policy 可能拒绝它,也不承诺原生 DevTools command-line 或 REPL 语义。只读 Client Sources 不代表 active Client debugging;增加该能力需要一个在被检查页面 realm 暂停时仍能响应的执行 agent。 diff --git a/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.i18n.yaml new file mode 100644 index 0000000000..baaec4c1f1 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md +2026-08-24-cordis-runtime-tree-inspection.md: 49a0bb4de34cf2a3c9f2943b432a62051ae85a9d +2026-08-24-cordis-runtime-tree-inspection.zh.md: b08b8fcb8d2bbed624be4dd5273406c856393e62 diff --git a/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md new file mode 100644 index 0000000000..49a0bb4de3 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md @@ -0,0 +1,113 @@ +# Agent Note: Cordis runtime tree inspection + +Status: implemented + +English | [中文](2026-08-24-cordis-runtime-tree-inspection.zh.md) + +## Problem + +The Inspector needs to present each Host and Client Cordis runtime as a tree in Chrome DevTools Elements. A Cordis Context or Fiber selected in Elements must also behave as a live Runtime object, while a Cordis object printed in Console must be revealable as the same semantic node. CDP identifiers cannot be the source model: `NodeId`, `BackendNodeId`, and `RemoteObjectId` have different owners and lifetimes, and a future model-facing runtime query must consume the same Cordis data without translating CDP. + +Host and Client run the same Cordis abstractions in different JavaScript realms. Tree discovery and classification must therefore be one browser-safe implementation, while object resolution remains realm-local and only opaque references cross MessagePort or WebSocket boundaries. + +## Decision + +The Inspector uses one serialized Cordis tree model and keeps CDP as one adapter over it. The package separates live-object discovery, immutable snapshots, Worker-owned storage, and consumers: + +The existing [cross-realm Inspector decision](../../implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md) owns the Worker, source carriers, Runtime routing, and security model. This note owns only the Cordis semantic data and its consumers. + +```text +Host Context/Fiber ─┐ + ├─ CordisTreeCollector ─ CordisTreeSnapshot ─ source transport ─ CordisTreeStore ─┬─ CDP DOM adapter +Client Context/Fiber┘ └─ future model adapter +``` + +`CordisTreeCollector` and its identity registry are browser-safe modules compiled into both package faces. Host and Client instantiate that same code against their own `ctx.root`; neither side carries a second classification implementation. + +## Cordis tree model + +`CordisTreeSnapshot` is a CDP-independent, lossless-JSON value with a schema version, monotonically increasing revision, object-registry id, truncation flag, and one nested root Context. Context nodes contain an opaque object handle and ordered Context/Fiber children. Fiber nodes contain their Cordis `uid`, an opaque object handle, and exactly one Context child representing `fiber.ctx`. Host and Client publish this same realm-tree type. No generated Context id, plugin metadata, service data, arbitrary property value, or object preview enters the tree. + +The inspection tree starts at the root Context and omits the Cordis root Fiber. For every other plugin, its parent Context contains the Fiber and that Fiber contains its owned Context. A Context created by `extend()`, `isolate()`, or `intercept()` without a new Fiber remains a direct Context child. Nesting expresses parentage without generated node ids and preserves both object identities without introducing the `Fiber.ctx` / `Context.fiber` cycle. + +The collector starts from the root, every live registry Fiber, and every event hook's owning Context. It follows Context prototype links back to the inspected root, unwraps Cordis shadow contexts, deduplicates by object identity, and excludes disposed fibers. `internal/plugin` and `internal/status` events schedule one microtask-coalesced replacement snapshot. Node-count and encoded-byte limits remove complete trailing branches, so every retained node still has its parent and every retained Fiber still has its owned Context. + +## Identity and lifetime + +The identities are intentionally distinct: + +- Fiber `uid` comes from Cordis. Context currently has no Cordis-owned id and the Inspector does not expose a generated substitute. +- `InspectorObjectReference` is an opaque realm-local handle resolving a tree node to its live Context or Fiber. Snapshots carry the handle for routing, never as a semantic id or DOM attribute. +- `BackendNodeId` is assigned by the Worker to one retained `(source id, source generation, object reference)` and is shared by DevTools connections while that generation's snapshot is retained. +- `NodeId` is assigned per DevTools connection when a node enters that frontend's document. It is discarded on `DOM.documentUpdated` or connection close. +- `RemoteObjectId` is assigned by the selected Runtime session when `DOM.resolveNode` exposes the live object. It remains scoped to that DevTools connection and object group. + +`sourceId` identifies one Client runtime instance and remains stable across its automatic transport reconnects; `generation` identifies one WebSocket admission. Disconnect removes the synthetic context from the Console with `Runtime.executionContextDestroyed`. Reconnection announces a fresh CDP execution-context id because the destroyed id and its RemoteObjects cannot be reused, but this does not imply that the browser's underlying JavaScript realm was recreated. + +Standard CDP does not place a `RemoteObjectId` field on `DOM.Node`. `DOM.Node` carries `nodeId` and `backendNodeId`; `DOM.resolveNode` returns the corresponding `Runtime.RemoteObject`, and `DOM.requestNode` performs the reverse mapping. The implementation keeps these three CDP identities correlated without adding non-standard DOM fields. + +## Realm object bridge + +Each collector registers a realm-local object table under a private global symbol. The table maps opaque handles to live objects and can identify a currently retained object by identity. Replacing a snapshot removes handles absent from the new tree; disposing the observer unregisters the table. + +For Host nodes, the Worker uses that DevTools connection's private `node:inspector.Session` to evaluate a lookup in the Host table, producing a native V8 `RemoteObjectId`. For Client nodes, the Worker routes the same lookup through the existing typed Client Runtime channel and maps the returned Client handle to a connection-local CDP object id. No live object or engine object id crosses a source transport. + +Client Runtime values carry an optional validated `InspectorObjectReference`, while Host Runtime values are probed through their native V8 object id. The common CDP adapter changes recognized evaluation results, properties, exceptions, Console arguments, and paused-frame objects to `subtype: "node"`, records the object-id-to-backend-node relation, and supplies the Cordis element description. This gives both directions: Elements can expose a live object, and a Context or Fiber returned or printed in Console can be revealed in Elements. + +## Worker repository and updates + +Sources publish the Cordis tree as retained state rather than an event history. Host MessagePort and Client WebSocket publishers keep the latest state record and include it in `source/replace` after admission, reconnection, or a resnapshot request. Live replacements still use the ordinary sequenced append path. The Worker validates every snapshot for exact fields, bounded node count and depth, unique object handles and Fiber uids, a Context root, and exactly one Context child per Fiber before atomically replacing the prior tree. + +`CordisTreeStore` owns validated realm snapshots and source lifecycle only. Its internal reader retains live object routes for Runtime and DOM, while its public reader projects a detached `{ host, clients }` tree without transport or CDP ids. Host and Client `ctx.inspector.cordis.getTree()` calls use the same correlated query protocol and Worker reader without creating a CDP session. `CordisDomBackend` adds Worker-global backend ids, while each `CordisDomSession` owns frontend node ids, searches, enabled state, and RemoteObject correlations. A model adapter can consume the public reader without depending on DOM serialization or debugger activation. + +Closing a source changes its stored tree from connected to disconnected instead of deleting the last snapshot. Object lookup excludes disconnected trees, so the snapshot remains inspectable as data without retaining or reviving a live Context, Fiber, or Runtime object. A replacement from the same source id and a new transport generation atomically restores the connected state. The configurable disconnected-tree limit evicts the oldest retained snapshots. + +Accepted tree replacements emit `DOM.documentUpdated` and require the frontend to pull a fresh document. A disconnect that does not evict another tree invalidates object routes without changing the DOM document, preserving the loaded tree, expansion, and selection. Connection state remains in the inspection model until its Elements presentation is designed. Retention eviction falls back to `DOM.documentUpdated`. Further incremental tree diffs can be added behind `CordisDomSession` without changing collectors, snapshots, or model consumers. + +## CDP projection + +The synthetic document has a `` container and a `` container. `` contains the Host root Context. `` contains one `` per Client source, and each `` contains that realm's root Context. These structural elements have no Runtime object or attributes. Context elements have no attributes. Fiber elements expose only `uid`, copied without reinterpretation from Cordis. Connected Context and Fiber elements resolve to live RemoteObjects; disconnected snapshots retain their DOM nodes but object resolution fails. + +Standard CDP has no backend-controlled frozen, locked, or dimmed state for a node in the ordinary Elements tree. Chromium's detached-node presentation is frontend-local to the Memory panel's `DOM.getDetachedDomNodes` flow. No connection-state attribute or non-standard `DOM.Node` field is added until its presentation is decided. + +The read-only adapter implements document retrieval, child requests, node description, attributes, outer HTML, search, backend-id pushes, node resolution, and reverse object lookup. Mutating DOM methods fail explicitly. Layout, CSS, accessibility, and browser DOM geometry are outside this semantic tree and return empty or unsupported responses only where Chrome DevTools requires a compatibility response. + +## Alternatives considered + +**Build CDP DOM nodes directly in each realm.** Rejected because Host and Client would duplicate classification, frontend ids would leak into source protocols, and a model consumer would need to reverse a presentation protocol back into Cordis concepts. + +**Send live objects or V8 object ids to the Worker.** Rejected because structured clone and JSON do not preserve identity or behavior, and engine object ids belong to one inspector session. + +**Generate an Inspector Context id.** Rejected because Cordis Context has no intrinsic id and a presentation adapter must not make an implementation key look like framework identity. Nested children express parentage; opaque object handles remain routing data. + +**Use one id for Fiber uid, backend nodes, and frontend nodes.** Rejected because source reconnection, multiple DevTools connections, document refresh, and Runtime object release have independent lifetimes. + +**Expose only Contexts and treat each Fiber-owned Context as the Fiber.** Rejected because it loses one of the two live objects, makes Console identity ambiguous, and prevents later Fiber-specific properties from having a stable owner. + +**Put the model-facing API on the CDP adapter.** Rejected because model access would inherit Chrome-specific node serialization, per-connection ids, and enable state. The Worker repository is the shared source; CDP and model access are sibling adapters. + +**Remove a realm tree when its source disconnects.** Rejected because transport loss would discard the last useful topology and collapse the user's Elements inspection state. Keeping old object handles usable was also rejected: a new connection generation cannot prove that any prior live object still exists. + +## Verification + +- The same collector implementation produces Host and Client snapshots from equivalent Cordis runtimes. +- Elements shows `` and `/` containers with each realm's root Context directly beneath its container. +- Context elements have no attributes; Fiber elements expose only their Cordis `uid`; the root Fiber is absent. +- Every connected Context and Fiber has a connection-local frontend node id, a Worker backend node id, and a resolvable connection-local Runtime object id without exposing them as attributes. +- `DOM.resolveNode` and `DOM.requestNode` round-trip Context and Fiber identities without sharing object ids across DevTools connections or source generations. +- A Context or Fiber returned by Runtime evaluation is node-branded and can be revealed in Elements. +- Disconnect destroys the Client execution context and its RemoteObjects while retaining the last Elements tree unchanged; a new transport generation replaces it after a complete snapshot arrives. +- Reconnect and resnapshot replay the latest tree state; malformed or oversized replacements do not replace the last valid snapshot. +- The stored snapshot and query API contain no CDP types and can support a future model-facing adapter unchanged. + +## Consequences + +Cordis exposes no complete global Context registry. The collector can recover contexts reachable from live fibers and event hooks; a context that is created, never used, and retained only by application code is intentionally absent. + +Object recognition adds a Runtime round trip for each Host object that requires semantic identification. An annotation failure leaves an ordinary RemoteObject rather than breaking Runtime or Debugger delivery. Client Console observation preserves the original method result and schedules serialization afterward; each enabled DevTools session receives independently retained handles, so recognition never blocks the page call or shares objects between connections. + +Full-tree replacement is simpler than incremental source mutations but can become expensive in very large runtimes. Node and byte limits preserve a valid prefix and report truncation; a later delta protocol can replace the transport without changing the snapshot model. + +The object table intentionally keeps every object in the current visible tree strongly reachable until the next replacement or observer disposal. This is bounded by the retained snapshot and must not become a general-purpose object registry. + +The Worker retains only serialized metadata for a disconnected snapshot; any still-running source owns its realm-local object registry independently and disposal releases that registry. `maxDisconnectedCordisTrees` bounds Worker snapshot memory and may force a full Elements document refresh when an older disconnected tree is evicted. diff --git a/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.zh.md b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.zh.md new file mode 100644 index 0000000000..b08b8fcb8d --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.zh.md @@ -0,0 +1,113 @@ +# Agent Note: Cordis 运行时树检查 + +Status: implemented + +[English](2026-08-24-cordis-runtime-tree-inspection.md) | 中文 + +## Problem + +Inspector 需要在 Chrome DevTools Elements 中把每个 Host 和 Client Cordis 运行时呈现为一棵树。在 Elements 中选中的 Cordis Context 或 Fiber 也必须表现为实时 Runtime 对象,而 Console 中打印出的 Cordis 对象必须能定位回同一个语义节点。CDP id 不能成为源模型:`NodeId`、`BackendNodeId` 与 `RemoteObjectId` 的 owner 和生命周期不同,并且未来面向模型的运行时查询必须使用同一份 Cordis 数据,而不是再反向解析 CDP。 + +Host 与 Client 在不同 JavaScript realm 中运行相同的 Cordis 抽象。因此,树发现与分类必须只有一份浏览器安全实现;对象解析仍留在各自 realm 内,跨 MessagePort 或 WebSocket 只传递不透明引用。 + +## Decision + +Inspector 使用一套序列化 Cordis 树模型,并把 CDP 作为它的一个适配器。包内分离实时对象发现、不可变快照、Worker 存储与消费方: + +现有的[跨 realm Inspector 决策](../../implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md)负责 Worker、source carrier、Runtime 路由与安全模型;本 Note 只负责 Cordis 语义数据及其消费方。 + +```text +Host Context/Fiber ─┐ + ├─ CordisTreeCollector ─ CordisTreeSnapshot ─ source transport ─ CordisTreeStore ─┬─ CDP DOM adapter +Client Context/Fiber┘ └─ future model adapter +``` + +`CordisTreeCollector` 及其身份注册表是浏览器安全模块,同时编入包的两个运行面。Host 与 Client 针对各自的 `ctx.root` 实例化同一份代码;任何一侧都不维护第二套分类实现。 + +## Cordis tree model + +`CordisTreeSnapshot` 是与 CDP 无关的无损 JSON 值,包含 schema 版本、单调递增 revision、对象注册表 id、截断标志和一棵以 Context 为根的嵌套树。Context 节点包含不透明 object handle 与有序的 Context/Fiber children。Fiber 节点包含 Cordis `uid`、不透明 object handle,以及唯一一个表示 `fiber.ctx` 的 Context child。Host 与 Client 发布同一种 realm-tree 类型。生成的 Context id、插件 metadata、服务数据、任意属性值与对象 preview 都不进入树。 + +inspection tree 从 root Context 开始,不包含 Cordis root Fiber。对其他每个插件,其 parent Context 包含 Fiber,该 Fiber 再包含它拥有的 Context。通过 `extend()`、`isolate()` 或 `intercept()` 创建且未创建新 Fiber 的 Context 仍是直接 Context 子节点。嵌套结构无需生成 node id 即可表达 parent,并保留两类对象身份,同时避免把 `Fiber.ctx` / `Context.fiber` 环写入序列化树。 + +collector 从 root、注册表中的每个 live Fiber,以及每个 event hook 的 owner Context 开始。它沿 Context prototype 链回溯到被检查的 root,解开 Cordis shadow Context,按对象身份去重,并排除已 dispose 的 Fiber。`internal/plugin` 与 `internal/status` 事件调度一次 microtask 合并后的 replacement snapshot。节点数和编码字节数限制会移除完整的尾部 branch,因此每个保留节点仍有 parent,每个保留 Fiber 仍有其 owned Context。 + +## Identity and lifetime + +各类身份刻意保持独立: + +- Fiber `uid` 来自 Cordis。Context 当前没有 Cordis 自有 id,Inspector 不会暴露一个生成值来替代。 +- `InspectorObjectReference` 是 realm 本地的不透明 handle,用于把树节点解析成实时 Context 或 Fiber。snapshot 携带该 handle 只为完成路由,不把它当成语义 id 或 DOM attribute。 +- `BackendNodeId` 由 Worker 为一条保留的 `(source id, source generation, object reference)` 分配,并在该 generation 的 snapshot 被保留期间由所有 DevTools 连接共享。 +- `NodeId` 在节点进入某个 frontend document 时按 DevTools 连接分配;`DOM.documentUpdated` 或连接关闭时丢弃。 +- `RemoteObjectId` 在 `DOM.resolveNode` 暴露实时对象时由选定的 Runtime session 分配;它只属于该 DevTools 连接和 object group。 + +`sourceId` 标识一个 Client runtime instance,并在自动重连 transport 时保持稳定;`generation` 标识一次 WebSocket 接纳。断联通过 `Runtime.executionContextDestroyed` 从 Console 移除 synthetic context。重连会发布新的 CDP execution-context id,因为已销毁的 id 及其 RemoteObject 不能复用;这并不表示浏览器底层 JavaScript realm 被重新创建。 + +标准 CDP 不会在 `DOM.Node` 上放置 `RemoteObjectId` 字段。`DOM.Node` 携带 `nodeId` 与 `backendNodeId`;`DOM.resolveNode` 返回对应的 `Runtime.RemoteObject`,`DOM.requestNode` 执行反向映射。实现会关联这三类 CDP 身份,而不添加非标准 DOM 字段。 + +## Realm object bridge + +每个 collector 都在私有 global symbol 下注册一个 realm 本地对象表。该表把不透明 handle 映射到实时对象,并能按身份识别当前保留的对象。替换快照时会移除新树中不存在的 handle;dispose observer 时注销该表。 + +对 Host 节点,Worker 使用该 DevTools 连接私有的 `node:inspector.Session` 在 Host 对象表中执行查询,从而生成原生 V8 `RemoteObjectId`。对 Client 节点,Worker 通过已有的类型化 Client Runtime channel 路由同一查询,再把返回的 Client handle 映射为连接本地 CDP object id。实时对象和引擎 object id 都不会穿过 source transport。 + +Client Runtime value 携带一个可选、已验证的 `InspectorObjectReference`,Host Runtime value 则通过原生 V8 object id 探测。公共 CDP adapter 把已识别的 evaluation result、property、exception、Console argument 和 paused-frame object 改成 `subtype: "node"`,记录 object-id 到 backend-node 的关系,并提供 Cordis element description。这样两个方向都成立:Elements 可以暴露实时对象,Console 中返回或打印的 Context 与 Fiber 也能定位到 Elements。 + +## Worker repository and updates + +source 把 Cordis 树作为保留状态发布,而不是事件历史。Host MessagePort 与 Client WebSocket publisher 保留最新状态记录,并在接纳、重连或收到 resnapshot 请求后把它放入 `source/replace`。实时 replacement 仍走普通的有序 append 路径。Worker 在原子替换旧树前验证 snapshot 的精确字段、节点数与深度限制、object handle 与 Fiber uid 唯一性、Context root,以及每个 Fiber 恰好拥有一个 Context child。 + +`CordisTreeStore` 只拥有已验证 realm snapshot 和 source 生命周期。内部 reader 为 Runtime 与 DOM 保留 live object route;公共 reader 则投影一棵不含 transport 或 CDP id 的 detached `{ host, clients }` tree。Host 与 Client 的 `ctx.inspector.cordis.getTree()` 通过同一套关联查询协议读取同一个 Worker reader,不创建 CDP session。`CordisDomBackend` 增加 Worker 全局 backend id,每个 `CordisDomSession` 则拥有 frontend node id、搜索、enable 状态和 RemoteObject 关联。模型 adapter 可以消费公共 reader,而不依赖 DOM 序列化或 debugger activation。 + +source 关闭时,存储的树从 connected 变为 disconnected,而不是删除最后一份 snapshot。对象查询会排除 disconnected 树,因此 snapshot 仍可作为数据检查,但不会保留或复活实时 Context、Fiber 或 Runtime object。同一 source id 的新 transport generation 提交 replacement 后,会原子恢复 connected 状态。可配置的 disconnected tree 数量上限会淘汰最早保留的 snapshot。 + +接受 tree replacement 后发送 `DOM.documentUpdated`,要求 frontend 重新拉取 document。如果断联没有淘汰另一棵树,则只失效对象路由,不改变 DOM document,从而保留已加载的树、展开状态与选择。连接状态留在 inspection model 中,等待其 Elements 展示方式被明确设计。保留上限触发淘汰时回退到 `DOM.documentUpdated`。以后可以在 `CordisDomSession` 内增加更多增量 DOM diff,而无需修改 collector、snapshot 或模型消费方。 + +## CDP projection + +synthetic document 包含一个 `` container 和一个 `` container。`` 包含 Host root Context;`` 为每个 Client source 包含一个 ``,每个 `` 再包含该 realm 的 root Context。这些结构 element 没有 Runtime object 或 attribute。Context element 没有 attribute。Fiber element 只暴露从 Cordis 原样复制的 `uid`。connected Context 与 Fiber 可以解析为 live RemoteObject;disconnected snapshot 保留 DOM node,但对象解析失败。 + +标准 CDP 没有可由 backend 控制、用于普通 Elements 树节点的 frozen、locked 或 dimmed 状态。Chromium 的 detached-node 展示只存在于 Memory 面板的 `DOM.getDetachedDomNodes` 流程,并由 frontend 本地设置。在展示方式明确前,不增加 connection-state attribute 或非标准 `DOM.Node` 字段。 + +只读适配器实现 document 获取、子节点请求、节点描述、属性、outer HTML、搜索、backend-id push、节点解析和对象反向查询。修改型 DOM 方法明确失败。layout、CSS、accessibility 与浏览器 DOM geometry 不属于这棵语义树;仅在 Chrome DevTools 需要兼容响应时返回空结果或 unsupported。 + +## Alternatives considered + +**在每个 realm 直接构建 CDP DOM node。** 拒绝,因为 Host 与 Client 会重复分类,frontend id 会泄漏进 source 协议,模型消费方还必须把展示协议反向解析成 Cordis 概念。 + +**把实时对象或 V8 object id 发送给 Worker。** 拒绝,因为 structured clone 与 JSON 无法保留身份或行为,而且引擎 object id 只属于一个 inspector session。 + +**由 Inspector 生成 Context id。** 拒绝,因为 Cordis Context 没有自身 id,展示适配器不能把实现 key 伪装成框架身份。嵌套 children 表达 parent,不透明 object handle 只作为路由数据。 + +**Fiber uid、backend node 与 frontend node 共用一个 id。** 拒绝,因为 source 重连、多条 DevTools 连接、document refresh 与 Runtime object release 的生命周期彼此独立。 + +**只暴露 Context,并把每个 Fiber 拥有的 Context 当成 Fiber。** 拒绝,因为这会丢失两类实时对象中的一类,使 Console 身份产生歧义,并让后续 Fiber 专属属性失去稳定 owner。 + +**把模型访问 API 放在 CDP 适配器上。** 拒绝,因为模型访问会继承 Chrome 专用 node 序列化、逐连接 id 和 enable 状态。Worker repository 是共享数据源,CDP 与模型访问是并列适配器。 + +**source 断联时移除 realm 树。** 拒绝,因为传输中断会丢失最后一份有用拓扑,并折叠用户在 Elements 中的检查状态。继续使用旧 object handle 同样不可接受:新的连接 generation 无法证明任何先前实时对象仍然存在。 + +## Verification + +- 同一个 collector 实现能从等价 Cordis 运行时生成 Host 和 Client 快照。 +- Elements 显示 `` 与 `/` container,每个 realm 的 root Context 直接位于其 container 下。 +- Context element 不含 attribute;Fiber element 只暴露 Cordis `uid`;root Fiber 不出现。 +- 每个 connected Context 与 Fiber 都有一个连接本地 frontend node id、一个 Worker backend node id 和一个可解析的连接本地 Runtime object id,且它们都不作为 attribute 暴露。 +- `DOM.resolveNode` 与 `DOM.requestNode` 能往返映射 Context/Fiber 身份,且不会跨 DevTools 连接或 source generation 共享 object id。 +- Runtime evaluation 返回的 Context 或 Fiber 会被标记为 node,并能在 Elements 中定位。 +- 断联会销毁 Client execution context 与 RemoteObject,同时原样保留最后一棵 Elements 树;新的 transport generation 在完整 snapshot 到达后替换它。 +- 重连和 resnapshot 会重放最新树状态;畸形或超限 replacement 不会替换最后一个有效快照。 +- 存储的 snapshot 与查询 API 不包含 CDP 类型,可以不加修改地支持未来的模型适配器。 + +## Consequences + +Cordis 不提供完整的全局 Context registry。collector 能恢复从 live fiber 与 event hook 可达的 Context;一个已创建、从未使用且只由应用代码保留的 Context 会有意缺席。 + +需要语义识别的每个 Host object 都会增加一次 Runtime round trip。annotation 失败时保留普通 RemoteObject,不破坏 Runtime 或 Debugger 投递。Client Console observation 保留原始 method result,并在之后调度序列化;每个已启用 DevTools session 独立保留 handle,因此识别既不阻塞页面调用,也不在连接间共享对象。 + +完整树 replacement 比增量 source mutation 更简单,但在超大运行时中可能昂贵。节点数与字节数限制会保留有效前缀并报告截断;以后可以替换为 delta 协议,而不修改 snapshot model。 + +对象表会有意强引用当前可见树中的每个对象,直到下一次 replacement 或 observer dispose。该集合受保留快照限制,不能扩展成通用对象注册表。 + +Worker 对断联 snapshot 只保留序列化 metadata;仍在运行的 source 独立拥有其 realm-local object registry,dispose 会释放该 registry。`maxDisconnectedCordisTrees` 约束 Worker snapshot 内存;淘汰较早的断联树时,Elements document 可能需要完整刷新。 diff --git a/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.i18n.yaml b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.i18n.yaml new file mode 100644 index 0000000000..31a09c0e9a --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.md +2026-08-26-inspector-execution-realms-and-protocol-planes.md: 67f37add1a788a450643a362fac24426ff80a43e +2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md: be4dd947fd999d0b9c09f7b4c821390b5b3b1245 diff --git a/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.md b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.md new file mode 100644 index 0000000000..67f37add1a --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.md @@ -0,0 +1,104 @@ +# Agent Note: Inspector execution realms and protocol planes + +Status: proposed + +English | [中文](2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md) + +## Problem + +The Inspector package executes code in three JavaScript environments: the browser Client, the Host Node main thread, and an Inspector Worker thread. Its current source tree mixes execution ownership with feature names: browser and Host producers have unrelated layouts, Worker-executed Client and Host backends sit under a generic backend directory, and one protocol directory combines transport frames, Cordis data, network observations, and CDP-oriented Runtime values. A file path therefore does not establish where code runs or which identifiers it may own. + +This ambiguity is risky because Host and Client support intentionally differs while their architecture must remain comparable. Host Runtime and Debugger delegate to Node's inspector protocol; Client Runtime and Console simulate the same backend semantics over an internal bridge. If their files, interfaces, and unsupported operations diverge structurally, each new protocol method encourages a second routing model. Likewise, consumers that only need the Cordis runtime tree must not inherit debugger activation, Chrome connection state, or CDP identifiers. + +The [cross-realm CDP inspector decision](../../implemented/architecture/2026-08-23-cross-realm-cdp-inspector.md) continues to own Worker, transport, Runtime, debugger, and security behavior. The [Cordis runtime tree inspection decision](../../implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.md) continues to own Cordis tree semantics, object routing, and DOM projection. This proposal owns source placement, dependency direction, and the separation between domain data, backend semantics, internal transport, and Chrome CDP state. + +## Proposal + +Top-level source directories will identify execution ownership. `client/` will contain only browser Client code, `host/` only Host Node-main-thread code, `worker/` only Worker-thread code, and `shared/` code that is safe in every environment. A module that executes in the Worker on behalf of a Client still belongs under `worker/`, not `client/`. + +The repository-required `src/index.ts` and `src/invariant.ts` discovery entries are the only root-level source exceptions. They expose the Host package entry and its service type or register the invariant companion, contain no Inspector runtime implementation, and remain at fixed paths for repository tooling. + +```text +src/ + shared/ environment-independent data and interfaces + client/ browser Client producer and adapters + host/ Host Node-main-thread producer and adapters + worker/ Worker transport, repositories, realm backends, and CDP endpoint +``` + +`client/` and `host/` will have the same relative directories and filenames. Their common roles are plugin entry, bridge lifecycle and RPC, Cordis and network inspection, and CDP-oriented Runtime, Console, Debugger, Sources, Profiler, and HeapProfiler adapters. Support may differ: an unavailable operation remains in the corresponding mirrored module and returns the shared capability-unavailable or typed-unsupported result. Mirroring standardizes where a capability is implemented; it does not claim equal engine support. + +Worker-side realm adapters will use the same rule under `worker/realms/client/` and `worker/realms/host/`. These adapters normalize Client simulation and Node inspector behavior behind shared CDP-oriented backend interfaces. They do not own Chrome wire messages or connection-local CDP identifiers. + +## Execution ownership + +`client/` owns page-realm observation, Client object handles, browser evaluation, browser Console interception, Client source publication, and its direct authenticated bridge to the Worker. It may use browser APIs but not Node or Worker implementation modules. + +`host/` owns Cordis plugin composition on the Node main thread, Worker startup and disposal, Host object observation, fetch capture, Node inspector notification forwarding, and the Host side of the Worker bridge. It may use Node APIs but does not construct Chrome CDP responses. + +`worker/bridge/` owns source admission, transport endpoints, connection generations, frame dispatch, correlation, and routing between source producers and Worker consumers. `worker/inspection/` owns retained Cordis and network observations plus transport-independent queries. `worker/realms/` owns the normalized Host and Client runtime backends. `worker/cdp/` owns HTTP discovery, DevTools sessions, Chrome method dispatch, domain enable state, and every connection-local Chrome identifier. + +The Worker remains the sole Chrome CDP wire and state owner. Client code simulates shared backend operations, not the CDP wire. Host code delegates supported backend operations to Node inspector, but Node protocol identifiers are translated inside the Worker Host realm before common domain projection. + +## Data and identifier ownership + +`shared/cordis/` contains the CDP-independent semantic model, immutable snapshots, collection and observation, realm-local object registration, projections, and reader interfaces. `model.ts` contains no transport handles or CDP identifiers. `snapshot.ts` may carry a realm-local opaque object reference because a live object query needs that route, but consumers can project it away. + +`shared/network/` contains fetch and network observations, captured body representation, and header normalization. These records describe observed activity and do not contain CDP request ids or domain enable state. + +`shared/cdp/` contains normalized backend interfaces and values for realm capabilities, Runtime, Console, Debugger, Sources, Profiler, HeapProfiler, and typed unsupported results. Backend handles in these interfaces are opaque and realm-owned. They are not Chrome `RemoteObjectId`, `ExecutionContextId`, `ScriptId`, or `CallFrameId` values. + +`shared/bridge/` contains the versioned internal carrier: source and generation identifiers, envelopes, codecs, validation, bounded publication, RPC correlation, dispatch interfaces, and domain-specific message unions. Its message modules may transport Cordis snapshots, network observations, Console events, Runtime operations, source reads, debugger operations, and semantic queries without turning those values into CDP messages. + +`worker/cdp/ids.ts` is the only owner of Chrome connection-local identifiers such as `RemoteObjectId`, `ExecutionContextId`, `ScriptId`, `NodeId`, and `CallFrameId`. Worker domain sessions allocate and release them and map them to realm backend handles or inspection records. Source, generation, sequence, request, Cordis Fiber uid, realm object reference, backend handle, and Chrome id remain distinct types because their owners and lifetimes differ. + +## Dependency rules + +The domain modules `shared/cordis/`, `shared/network/`, and `shared/cdp/` do not import `shared/bridge/` or any execution-specific directory. `shared/bridge/` may import those domain types when defining internal messages. No module under `shared/` imports Node-only or browser-only APIs. + +Top-level `client/` and `host/` import `shared/` but never each other or `worker/`. Equivalent roles use equivalent shared interfaces. Environment-specific transport and engine behavior stays in the mirrored implementation file rather than entering a shared conditional implementation. + +`worker/realms/` and `worker/inspection/` import shared interfaces but do not import `worker/cdp/`; normalized backend results and stored observations cannot contain Chrome connection state. `worker/cdp/` may consume realm and inspection interfaces to project CDP. `worker/bridge/` routes shared messages and invokes Worker services without becoming an owner of Cordis, network, Runtime, or Chrome state. + +The package remains one `@deepseek-ai/dsh-experimental-inspector` package with explicit Client and Host compiler faces. Directory separation is an execution and dependency rule, not a package split. + +## Migration order + +First, the current Cordis implementation and its semantic types move into `shared/cordis/`. The current protocol directory then separates into `shared/bridge/`, `shared/cdp/`, and `shared/network/` while preserving validated frame discriminants and limits. + +Next, top-level Client and Host files move into exact mirrored paths. Missing support is represented explicitly so the mirrors remain complete. Worker Client and Node backends then move to mirrored `worker/realms/client/` and `worker/realms/host/` directories, with Node renamed to Host at the architectural interface. + +Finally, source transport and routing move under `worker/bridge/`, Cordis, network, and query repositories under `worker/inspection/`, and Chrome endpoint and domains under `worker/cdp/`. Imports, explicit compiler-face file lists, package entries, and focused tests change with each owning layer. The final tree has no generic top-level `protocol/` or `cordis/` directory and no generic `worker/backends/` directory. + +## Alternatives considered + +**Organize every file by feature domain.** Rejected because a Runtime or Cordis feature spans three environments with different available APIs. Feature-only paths conceal execution constraints and make accidental browser-to-Node imports difficult to review. + +**Put Worker Client and Host adapters in top-level `client/` and `host/`.** Rejected because those adapters execute in the Worker and own different resources from page and Node-main-thread producers. A directory name must answer where code runs before it answers which remote realm it represents. + +**Allow Client and Host trees to contain only currently supported files.** Rejected because asymmetric layout obscures missing capability decisions and lets equivalent routing roles acquire unrelated interfaces. Explicit unsupported implementations keep evolution exhaustive without pretending support exists. + +**Keep one shared protocol directory.** Rejected because internal carrier identities, Cordis semantic data, normalized Runtime values, and Chrome wire identifiers have different consumers and lifetimes. A single directory encourages domain models to depend on transport and CDP presentation. + +**Split Client, Host, protocol, and Worker into separate packages.** Rejected for the experimental phase. The deployment unit remains one Client/Host Cordis plugin, and package boundaries would add build and release coordination without improving the required execution separation. + +## Acceptance criteria + +- Every runtime implementation has an unambiguous execution owner through `shared/`, `client/`, `host/`, or `worker/`; only the repository-required package and invariant forwarding entries remain at the source root. +- Top-level Client and Host trees, and Worker Client and Host realm trees, have identical relative implementation paths; unequal capability support is explicit and typed. +- Cordis and network readers can be used without importing debugger, source, transport, or CDP session modules. +- Internal messages contain source-level identities and validated domain values but no Chrome connection-local ids. +- Normalized realm backend interfaces support Host delegation and Client simulation without either implementation constructing Chrome CDP messages. +- Only Worker CDP modules allocate Chrome ids and own DevTools connection enable, object, script, node, and call-frame state. +- Existing Host Runtime and debugging, Client Runtime and Console, Network capture, Cordis Elements projection, disconnect retention, and semantic query behavior remain covered after the move. +- Compiler faces, import checks, and a structural test reject environment leaks and Client/Host mirror drift. + +## Risks + +Exact mirroring adds small adapter files for unsupported capabilities. Those files are intentional compatibility points between implementations, but they must stay thin and must not manufacture fake behavior. + +Moving types without changing behavior can still expose hidden dependency cycles, especially where Runtime object annotation reaches Cordis repositories. The dependency rules require inversion through shared interfaces rather than a temporary import from a lower-level module. + +`shared/cdp/` can become a second copy of the Chrome protocol if normalized types are added indiscriminately. A shared type belongs there only when both realm implementations or a common Worker projector consume it; Chrome session bookkeeping and wire-only fields remain under `worker/cdp/`. + +The migration may temporarily leave the package uncompilable between local move steps. The completed change must restore both compiler faces and behavior tests before review. diff --git a/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md new file mode 100644 index 0000000000..be4dd947fd --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-08-26-inspector-execution-realms-and-protocol-planes.zh.md @@ -0,0 +1,104 @@ +# Agent Note: Inspector 执行环境与协议平面 + +Status: proposed + +[English](2026-08-26-inspector-execution-realms-and-protocol-planes.md) | 中文 + +## Problem + +Inspector 包的代码运行在三个 JavaScript 环境中:浏览器 Client、Host Node 主线程和 Inspector Worker thread。当前源码树把执行归属与功能名称混在一起:浏览器和 Host producer 使用互不对应的目录结构,代表 Client 与 Host 的 Worker 代码位于笼统的 backend 目录,而一个 protocol 目录同时包含 transport frame、Cordis 数据、network observation 与面向 CDP 的 Runtime value。因此,文件路径无法说明代码在哪里运行,也无法说明它可以持有哪些标识符。 + +这种含糊会带来风险,因为 Host 与 Client 的支持能力有意不同,但架构必须保持可比较。Host Runtime 与 Debugger 委托 Node inspector protocol;Client Runtime 与 Console 通过内部 bridge 模拟同一套 backend 语义。如果两边的文件、接口与 unsupported operation 在结构上分叉,每增加一种协议方法都容易产生第二套路由模型。同样,只需要 Cordis 运行时树的消费方不应继承 debugger activation、Chrome 连接状态或 CDP 标识符。 + +现有的[跨 realm CDP Inspector 决策](../../implemented/architecture/2026-08-23-cross-realm-cdp-inspector.zh.md)继续负责 Worker、transport、Runtime、debugger 与安全行为。[Cordis 运行时树检查决策](../../implemented/architecture/2026-08-24-cordis-runtime-tree-inspection.zh.md)继续负责 Cordis 树语义、对象路由与 DOM projection。本提案只负责源码位置、依赖方向,以及领域数据、backend 语义、内部 transport 和 Chrome CDP 状态之间的分隔。 + +## Proposal + +顶层源码目录将标识执行归属。`client/` 只包含浏览器 Client 代码,`host/` 只包含 Host Node 主线程代码,`worker/` 只包含 Worker thread 代码,`shared/` 只包含在所有环境中都安全的代码。即使某个模块代表 Client,只要它实际在 Worker 中执行,就仍属于 `worker/`,而不是 `client/`。 + +仓库要求的 `src/index.ts` 与 `src/invariant.ts` 发现入口是仅有的源码根目录例外。它们暴露 Host package entry 及其 service type,或注册 invariant companion,不包含 Inspector 运行时实现,并为仓库工具保留在固定路径。 + +```text +src/ + shared/ environment-independent data and interfaces + client/ browser Client producer and adapters + host/ Host Node-main-thread producer and adapters + worker/ Worker transport, repositories, realm backends, and CDP endpoint +``` + +`client/` 与 `host/` 将拥有相同的相对目录和文件名。共同角色包括 plugin entry、bridge lifecycle 与 RPC、Cordis 和 network inspection,以及面向 CDP 的 Runtime、Console、Debugger、Sources、Profiler 和 HeapProfiler adapter。支持程度可以不同:不可用的操作仍保留在对应的镜像模块中,并返回共享的 capability-unavailable 或类型化 unsupported 结果。镜像结构统一的是能力实现位置,而不是宣称两个引擎支持相同功能。 + +Worker 侧 realm adapter 在 `worker/realms/client/` 与 `worker/realms/host/` 下遵守相同规则。这些 adapter 通过共享的面向 CDP backend 接口,规范化 Client 模拟行为与 Node inspector 行为。它们不拥有 Chrome wire message 或连接局部的 CDP 标识符。 + +## Execution ownership + +`client/` 负责 page realm observation、Client object handle、浏览器求值、浏览器 Console interception、Client source publication 以及到 Worker 的直接鉴权 bridge。它可以使用浏览器 API,但不能导入 Node 或 Worker 实现模块。 + +`host/` 负责 Node 主线程上的 Cordis plugin composition、Worker 启动与 dispose、Host object observation、fetch capture、Node inspector notification forwarding,以及 Worker bridge 的 Host 一侧。它可以使用 Node API,但不构造 Chrome CDP response。 + +`worker/bridge/` 负责 source admission、transport endpoint、connection generation、frame dispatch、correlation,以及 source producer 与 Worker consumer 之间的路由。`worker/inspection/` 负责保留的 Cordis 与 network observation,以及不依赖 transport 的 query。`worker/realms/` 负责规范化的 Host 与 Client runtime backend。`worker/cdp/` 负责 HTTP discovery、DevTools session、Chrome method dispatch、domain enable 状态与所有连接局部的 Chrome 标识符。 + +Worker 继续作为唯一的 Chrome CDP wire 与状态 owner。Client 代码模拟共享 backend operation,而不是模拟 CDP wire。Host 代码把支持的 backend operation 委托给 Node inspector,但 Node protocol 标识符在 Worker Host realm 内转换后才进入公共 domain projection。 + +## Data and identifier ownership + +`shared/cordis/` 包含与 CDP 无关的语义模型、不可变 snapshot、collection 与 observation、realm-local object registration、projection 与 reader interface。`model.ts` 不包含 transport handle 或 CDP 标识符。`snapshot.ts` 可以携带 realm-local opaque object reference,因为实时对象查询需要该路由信息,但消费方可以在 projection 中移除它。 + +`shared/network/` 包含 fetch 与 network observation、采集 body 表示及 header normalization。这些记录描述已观测活动,不包含 CDP request id 或 domain enable 状态。 + +`shared/cdp/` 包含 realm capability、Runtime、Console、Debugger、Sources、Profiler、HeapProfiler 的规范化 backend 接口和值,以及类型化 unsupported 结果。这些接口中的 backend handle 是不透明且由 realm 持有的。它们不是 Chrome `RemoteObjectId`、`ExecutionContextId`、`ScriptId` 或 `CallFrameId`。 + +`shared/bridge/` 包含带版本的内部 carrier:source 与 generation 标识符、envelope、codec、validation、有限 publication、RPC correlation、dispatch interface 及分领域的 message union。其 message 模块可以传输 Cordis snapshot、network observation、Console event、Runtime operation、source read、debugger operation 与语义 query,但不会把这些值转换成 CDP message。 + +`worker/cdp/ids.ts` 是 Chrome 连接局部标识符的唯一 owner,包括 `RemoteObjectId`、`ExecutionContextId`、`ScriptId`、`NodeId` 与 `CallFrameId`。Worker domain session 分配并释放这些 id,把它们映射到 realm backend handle 或 inspection record。source、generation、sequence、request、Cordis Fiber uid、realm object reference、backend handle 与 Chrome id 必须保持为不同类型,因为它们的 owner 和生命周期不同。 + +## Dependency rules + +领域模块 `shared/cordis/`、`shared/network/` 与 `shared/cdp/` 不导入 `shared/bridge/` 或任何执行环境专属目录。`shared/bridge/` 在定义内部 message 时可以导入这些领域类型。`shared/` 下的任何模块都不导入 Node-only 或 browser-only API。 + +顶层 `client/` 与 `host/` 可以导入 `shared/`,但不能互相导入,也不能导入 `worker/`。等价角色使用等价的共享接口。环境专属 transport 与 engine 行为保留在对应镜像实现文件中,不进入带条件分支的共享实现。 + +`worker/realms/` 与 `worker/inspection/` 可以导入共享接口,但不导入 `worker/cdp/`;规范化 backend result 和已存 observation 不能包含 Chrome connection state。`worker/cdp/` 可以消费 realm 与 inspection interface 来生成 CDP projection。`worker/bridge/` 路由共享 message 并调用 Worker service,但不成为 Cordis、network、Runtime 或 Chrome 状态的 owner。 + +本能力继续保留在同一个 `@deepseek-ai/dsh-experimental-inspector` 包中,并使用显式 Client 与 Host compiler face。目录分隔是执行与依赖规则,不是拆包方案。 + +## Migration order + +首先把现有 Cordis 实现及其语义类型移动到 `shared/cordis/`。随后把当前 protocol 目录拆成 `shared/bridge/`、`shared/cdp/` 与 `shared/network/`,同时保留已验证的 frame discriminant 与限制。 + +接下来把顶层 Client 与 Host 文件移动到严格镜像的路径。缺失支持使用显式表示,使镜像保持完整。然后把 Worker Client 与 Node backend 移动到镜像的 `worker/realms/client/` 和 `worker/realms/host/` 目录,并在架构接口上把 Node 命名统一为 Host。 + +最后把 source transport 与 routing 移到 `worker/bridge/`,Cordis、network 与 query repository 移到 `worker/inspection/`,Chrome endpoint 与 domain 移到 `worker/cdp/`。imports、显式 compiler-face file list、package entry 与聚焦测试随所属层一起修改。最终源码树不保留笼统的顶层 `protocol/`、`cordis/` 或 `worker/backends/` 目录。 + +## Alternatives considered + +**所有文件都按功能领域组织。** 拒绝,因为一个 Runtime 或 Cordis 功能会跨越三个可用 API 不同的环境。只有功能信息的路径会隐藏执行限制,也让 browser 到 Node 的意外导入难以审查。 + +**把 Worker Client 与 Host adapter 放入顶层 `client/` 和 `host/`。** 拒绝,因为这些 adapter 实际运行在 Worker 中,持有的资源也不同于 page 与 Node 主线程 producer。目录名应先回答代码在哪里运行,再回答它代表哪个远端 realm。 + +**Client 与 Host 目录只保留当前支持的文件。** 拒绝,因为不对称目录会隐藏缺失能力决策,并允许等价路由角色形成无关接口。显式 unsupported 实现既保证穷尽演进,也不虚构已支持行为。 + +**保留一个共享 protocol 目录。** 拒绝,因为内部 carrier identity、Cordis 语义数据、规范化 Runtime value 与 Chrome wire identifier 的消费方和生命周期不同。单一目录会诱导领域模型依赖 transport 和 CDP presentation。 + +**把 Client、Host、protocol 与 Worker 拆成多个包。** 实验阶段拒绝。部署单元仍是一个 Client/Host Cordis plugin;包边界会增加构建和发布协作,却不能改善所需的执行环境分隔。 + +## Acceptance criteria + +- 每个运行时实现都通过 `shared/`、`client/`、`host/` 或 `worker/` 拥有明确的执行 owner;只有仓库要求的 package 与 invariant 转发入口留在源码根目录。 +- 顶层 Client/Host 树与 Worker Client/Host realm 树分别拥有相同的相对实现路径;不同能力支持使用显式类型表示。 +- Cordis 与 network reader 无需导入 debugger、source、transport 或 CDP session 模块即可使用。 +- 内部 message 包含 source 层 identity 与已验证领域值,但不包含 Chrome 连接局部 id。 +- 规范化 realm backend interface 同时支持 Host 委托与 Client 模拟,且两种实现都不构造 Chrome CDP message。 +- 只有 Worker CDP 模块分配 Chrome id,并持有 DevTools 连接的 enable、object、script、node 与 call-frame 状态。 +- 移动后继续覆盖现有 Host Runtime 与 debugging、Client Runtime 与 Console、Network capture、Cordis Elements projection、断联保留与语义 query 行为。 +- compiler face、import check 与结构测试能够拒绝环境泄漏和 Client/Host 镜像漂移。 + +## Risks + +严格镜像会为不支持的能力增加小型 adapter 文件。这些文件是两个实现之间有意保留的兼容点,但必须保持轻薄,也不能制造虚假行为。 + +即使只移动类型而不改变行为,也可能暴露隐藏的依赖环,尤其是 Runtime object annotation 访问 Cordis repository 的位置。依赖规则要求通过共享接口反转依赖,不能临时从较低层模块反向导入。 + +如果不加约束地添加规范化类型,`shared/cdp/` 可能变成第二份 Chrome protocol。只有两个 realm 实现或公共 Worker projector 会消费的类型才属于这里;Chrome session bookkeeping 与 wire-only field 保留在 `worker/cdp/`。 + +本地迁移步骤之间可能暂时无法编译。完整变更必须在 review 前恢复两个 compiler face 与行为测试。 diff --git a/docs/capability-seams.i18n.yaml b/docs/capability-seams.i18n.yaml index 5d1d98a404..4a4d691ac6 100644 --- a/docs/capability-seams.i18n.yaml +++ b/docs/capability-seams.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/capability-seams.md -capability-seams.md: 1e7e6e39d307a9e72b5d57420bde99f51063f64d -capability-seams.zh.md: e33a1e6da7f71838c48b961f93389ba1a089f57f +capability-seams.md: 3886ca582ea934c51fc20dfec01fd9f2af829597 +capability-seams.zh.md: a79b93bb8d6fff36e0828dbba8f7e20b885bcbfe diff --git a/docs/capability-seams.md b/docs/capability-seams.md index 1e7e6e39d3..3886ca582e 100644 --- a/docs/capability-seams.md +++ b/docs/capability-seams.md @@ -177,6 +177,8 @@ flowchart LR svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"] pkg_experimental_tool_agent_team["experimental-tool-agent-team"] pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"] + pkg_inspector["inspector"] + svc_inspector["ctx.inspector
Cross-realm runtime inspection"] pkg_jobs["jobs"] svc_jobs["ctx.jobs
Background job registry"] pkg_jobs_local["jobs-local"] @@ -256,6 +258,7 @@ flowchart LR pkg_host_directory_picker_browse --> svc_directoryPicker pkg_host_directory_picker_native --> svc_directoryPicker pkg_host_webserver --> svc_webServer + pkg_inspector --> svc_inspector pkg_invariants --> svc_invariants pkg_jobs --> svc_jobs pkg_jobs_local --> svc_jobs @@ -513,6 +516,7 @@ flowchart LR | `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | The basic backend consumes post-step pressure and request-error recovery events; there is no model-facing compact tool. | | `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/workflow/tool-ralph) | - | Providers implement transports; the service also owns optional Activation-based continuation orchestration, tool-subagent selects one-shot or continuable delegation, tool-subagent-control delivers follow-ups, and tool-ralph requires one fresh structured-output route. | | `ctx.agentTeams` | `core` | [`experimental-agent-team`](../packages/experimental/agent-team) | - | [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team), [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | - | Owns the implicit-root roster, durable peer mailbox, shared task DAG, continuable-child lifecycle, and generated Team Remote methods; tool-agent-team contributes model controls and client-ui-agent-team mounts the browser contribution. | +| `ctx.inspector` | `core` | `inspector` | - | - | - | Owns the Worker-hosted CDP target and the transport-independent Host and Client observation and Cordis-tree query API. | | `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | - | Producers (background bash, PTY sends, and subagent delegations) register running work; tool-jobs is the model-facing controller that reads, lists, and kills it; jobs-local is the process-local registry. | | `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names. | | `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill. | diff --git a/docs/capability-seams.zh.md b/docs/capability-seams.zh.md index e33a1e6da7..a79b93bb8d 100644 --- a/docs/capability-seams.zh.md +++ b/docs/capability-seams.zh.md @@ -179,6 +179,8 @@ flowchart LR svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"] pkg_experimental_tool_agent_team["experimental-tool-agent-team"] pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"] + pkg_inspector["inspector"] + svc_inspector["ctx.inspector
Cross-realm runtime inspection"] pkg_jobs["jobs"] svc_jobs["ctx.jobs
Background job registry"] pkg_jobs_local["jobs-local"] @@ -258,6 +260,7 @@ flowchart LR pkg_host_directory_picker_browse --> svc_directoryPicker pkg_host_directory_picker_native --> svc_directoryPicker pkg_host_webserver --> svc_webServer + pkg_inspector --> svc_inspector pkg_invariants --> svc_invariants pkg_jobs --> svc_jobs pkg_jobs_local --> svc_jobs @@ -515,6 +518,7 @@ flowchart LR | `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | 基础后端消费步骤后的压力事件和请求错误恢复事件;不存在面向模型的压缩工具。 | | `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/workflow/tool-ralph) | - | 提供方实现传输;该服务还负责可选的、基于 Activation 的延续编排,tool-subagent 选择一次性或可延续委派,tool-subagent-control 传递后续消息,而 tool-ralph 要求一条全新的结构化输出路由。 | | `ctx.agentTeams` | `core` | [`experimental-agent-team`](../packages/experimental/agent-team) | - | [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team), [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | - | 负责隐式 Root roster、持久 peer mailbox、共享任务 DAG、continuable child 生命周期与生成式 Team Remote method;tool-agent-team 提供模型控制工具,client-ui-agent-team 挂载浏览器 contribution。 | +| `ctx.inspector` | `core` | `inspector` | - | - | - | 负责 Worker 托管的 CDP target,以及独立于传输的 Host 和 Client observation 与 Cordis tree query API。 | | `ctx.jobs` | `seam` | [`jobs`](../packages/jobs/jobs) | [`jobs-local`](../packages/jobs/jobs-local) | [`tool-bash`](../packages/shell/tool-bash), [`tool-terminal`](../packages/terminal/tool-terminal), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-jobs`](../packages/jobs/tool-jobs) | - | 生产方(后台 bash、PTY 发送和 subagent 委派)登记正在运行的工作;tool-jobs 是面向模型的控制器,用于读取、列出和终止这些工作;jobs-local 是进程本地注册表。 | | `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-http`](../packages/web/web-fetch-http) | [`tool-web`](../packages/web/tool-web) | - | 搜索和抓取提供方注册到同一个 ctx.web seam;tool-web 负责稳定的面向模型名称。 | | `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | 后端保存过大的工具文本,并返回面向模型的定位信息和取回提示;spill-policy 是 tools/post-execute 消费方,负责决定何时 spill。 | diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 750dab17ed..638000d0ef 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/config-catalog.md -config-catalog.md: ab16221ff6c13768c9b0fb6a8189e30565dcc289 -config-catalog.zh.md: 8c9d956ad3ad5f672f73e5b4dd02aaed938c8667 +config-catalog.md: 4331c0a5153f32f0e6af5b6ec6fd182ee9b335b4 +config-catalog.zh.md: 54f6ddde10053d422af2c5ebfd88a367597adc89 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index ab16221ff6..4331c0a515 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -612,6 +612,74 @@ export interface Config { Source: [`packages/experimental/agent-team/src/types.ts:131`](../packages/experimental/agent-team/src/types.ts) + + +## `@deepseek-ai/dsh-experimental-inspector` + +Requires: `webServer` + +```ts config-catalog +/** Host plugin configuration. Fetch capture is enabled by default. */ +export interface Config extends Omit { + /** Browser origins allowed to open the Client ingest WebSocket. */ + clientOrigins?: string[] +} + +/** User-facing Host options; every memory and lifecycle bound is configurable. */ +export interface InspectorOptions { + /** Loopback address used by the Worker HTTP and WebSocket endpoint. */ + readonly host?: '127.0.0.1' + /** First port to bind; occupied ports advance until one is available. */ + readonly port?: number + /** Additional exact browser origins admitted to the Client ingest socket. */ + readonly clientOrigins?: readonly string[] + /** Whether to observe calls made through the current global fetch function. */ + readonly captureFetch?: boolean + /** Maximum request-body prefix retained for one fetch. */ + readonly maxRequestBodyBytes?: number + /** Maximum response-body prefix retained for one fetch. */ + readonly maxResponseBodyBytes?: number + /** Maximum raw bytes encoded into one body observation. */ + readonly maxBodyChunkBytes?: number + /** Maximum total request and response body bytes retained by the Worker. */ + readonly maxJournalBytes?: number + /** Maximum active and completed fetch requests retained by the Worker. */ + readonly maxRetainedRequests?: number + /** Maximum encoded bytes accepted in one source transport frame. */ + readonly maxSourceFrameBytes?: number + /** Maximum observation records accepted in one source batch. */ + readonly maxSourceRecordsPerFrame?: number + /** Maximum records waiting in one producer queue. */ + readonly maxQueuedRecords?: number + /** Maximum encoded bytes waiting in one producer queue. */ + readonly maxQueuedBytes?: number + /** Maximum time allowed for the Worker to become ready. */ + readonly startupTimeoutMs?: number + /** Grace period before a stopping Worker is terminated. */ + readonly stopTimeoutMs?: number + /** Initial upper bound for randomized Client reconnect delay. */ + readonly clientReconnectBaseMs?: number + /** Maximum upper bound for randomized Client reconnect delay. */ + readonly clientReconnectMaxMs?: number + /** Deadline for one Worker-to-Client Runtime or Sources request. */ + readonly clientRuntimeTimeoutMs?: number + /** Deadline for one non-CDP semantic query. */ + readonly queryTimeoutMs?: number + /** Maximum live object handles retained per Client Runtime session. */ + readonly maxClientRuntimeObjects?: number + /** Maximum descriptors returned by one Client property request. */ + readonly maxClientRuntimeProperties?: number + /** Maximum encoded bytes read for one Client script or source map. */ + readonly maxClientSourceBytes?: number + /** Maximum Context and Fiber nodes retained in one realm snapshot. */ + readonly maxCordisNodes?: number + /** Disconnected Cordis snapshots retained after their live realm closes. */ + readonly maxDisconnectedCordisTrees?: number +} +``` + +Source: [`packages/experimental/inspector/src/index.ts:66`](../packages/experimental/inspector/src/index.ts) + ## `@deepseek-ai/dsh-experimental-tool-agent-team` diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 8c9d956ad3..54f6ddde10 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -614,6 +614,74 @@ export interface Config { 来源:[`packages/experimental/agent-team/src/types.ts:125`](../packages/experimental/agent-team/src/types.ts) + + +## `@deepseek-ai/dsh-experimental-inspector` + +需要:`webServer` + +```ts config-catalog +/** Host plugin configuration. Fetch capture is enabled by default. */ +export interface Config extends Omit { + /** Browser origins allowed to open the Client ingest WebSocket. */ + clientOrigins?: string[] +} + +/** User-facing Host options; every memory and lifecycle bound is configurable. */ +export interface InspectorOptions { + /** Loopback address used by the Worker HTTP and WebSocket endpoint. */ + readonly host?: '127.0.0.1' + /** First port to bind; occupied ports advance until one is available. */ + readonly port?: number + /** Additional exact browser origins admitted to the Client ingest socket. */ + readonly clientOrigins?: readonly string[] + /** Whether to observe calls made through the current global fetch function. */ + readonly captureFetch?: boolean + /** Maximum request-body prefix retained for one fetch. */ + readonly maxRequestBodyBytes?: number + /** Maximum response-body prefix retained for one fetch. */ + readonly maxResponseBodyBytes?: number + /** Maximum raw bytes encoded into one body observation. */ + readonly maxBodyChunkBytes?: number + /** Maximum total request and response body bytes retained by the Worker. */ + readonly maxJournalBytes?: number + /** Maximum active and completed fetch requests retained by the Worker. */ + readonly maxRetainedRequests?: number + /** Maximum encoded bytes accepted in one source transport frame. */ + readonly maxSourceFrameBytes?: number + /** Maximum observation records accepted in one source batch. */ + readonly maxSourceRecordsPerFrame?: number + /** Maximum records waiting in one producer queue. */ + readonly maxQueuedRecords?: number + /** Maximum encoded bytes waiting in one producer queue. */ + readonly maxQueuedBytes?: number + /** Maximum time allowed for the Worker to become ready. */ + readonly startupTimeoutMs?: number + /** Grace period before a stopping Worker is terminated. */ + readonly stopTimeoutMs?: number + /** Initial upper bound for randomized Client reconnect delay. */ + readonly clientReconnectBaseMs?: number + /** Maximum upper bound for randomized Client reconnect delay. */ + readonly clientReconnectMaxMs?: number + /** Deadline for one Worker-to-Client Runtime or Sources request. */ + readonly clientRuntimeTimeoutMs?: number + /** Deadline for one non-CDP semantic query. */ + readonly queryTimeoutMs?: number + /** Maximum live object handles retained per Client Runtime session. */ + readonly maxClientRuntimeObjects?: number + /** Maximum descriptors returned by one Client property request. */ + readonly maxClientRuntimeProperties?: number + /** Maximum encoded bytes read for one Client script or source map. */ + readonly maxClientSourceBytes?: number + /** Maximum Context and Fiber nodes retained in one realm snapshot. */ + readonly maxCordisNodes?: number + /** Disconnected Cordis snapshots retained after their live realm closes. */ + readonly maxDisconnectedCordisTrees?: number +} +``` + +来源:[`packages/experimental/inspector/src/index.ts:66`](../packages/experimental/inspector/src/index.ts) + ## `@deepseek-ai/dsh-experimental-tool-agent-team` diff --git a/docs/event-producer-consumer.i18n.yaml b/docs/event-producer-consumer.i18n.yaml index 3cdec59fc3..e5cf853414 100644 --- a/docs/event-producer-consumer.i18n.yaml +++ b/docs/event-producer-consumer.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/event-producer-consumer.md -event-producer-consumer.md: 9bd351a204ceb6ab262d2f2b9a0276c44be20cc5 -event-producer-consumer.zh.md: 453d22632dbcc73edec67a44759f1de42490be88 +event-producer-consumer.md: e849cb84265c0781e4a8680d0bb247e9955b5c2e +event-producer-consumer.zh.md: b5835c56b26f3a75fd792d3a71c3ab2dc688ea42 diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 9bd351a204..e849cb8426 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -65,7 +65,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-jobs`](../packages/jobs/tool-jobs) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) | | `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:85`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes` | -| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `modules` | +| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `inspector`, `modules` | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | @@ -78,8 +78,8 @@ This matrix shows which packages dispatch each harness-owned event and which pac | Event string | Dispatchers | Listeners | | --- | --- | --- | | `internal/dispatch` | - | `agent-team`, [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`schedule`](../packages/schedule/schedule), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`terminal-bash`](../packages/terminal/terminal-bash), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval), [`webhook`](../packages/webhook/webhook), [`workflow`](../packages/workflow/workflow) | -| `internal/plugin` | - | `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` | +| `internal/plugin` | - | `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` | | `internal/service` | - | [`agent-presets`](../packages/preset/agent-presets), `gateway` | -| `internal/status` | - | [`agent`](../packages/core/agent) | +| `internal/status` | - | [`agent`](../packages/core/agent), `inspector` | Maintenance mode: generated: Cordis event declarations and producer/listener edges are resolved from the repository TypeScript Program. diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md index 453d22632d..b5835c56b2 100644 --- a/docs/event-producer-consumer.zh.md +++ b/docs/event-producer-consumer.zh.md @@ -67,7 +67,7 @@ | `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-jobs`](../packages/jobs/tool-jobs) | | `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) | | `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:85`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes` | -| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `modules` | +| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:34`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `inspector`, `modules` | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | @@ -80,8 +80,8 @@ | 事件字符串 | 派发方 | 监听方 | | --- | --- | --- | | `internal/dispatch` | - | `agent-team`, [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission-presets`](../packages/interaction/permission-presets), [`plan-mode`](../packages/plan/plan-mode), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`schedule`](../packages/schedule/schedule), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-log-deepseek`](../packages/session/session-log-deepseek), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`terminal-bash`](../packages/terminal/terminal-bash), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tool-workflow`](../packages/workflow/tool-workflow), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval), [`webhook`](../packages/webhook/webhook), [`workflow`](../packages/workflow/workflow) | -| `internal/plugin` | - | `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` | +| `internal/plugin` | - | `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), `modules`, `webserver` | | `internal/service` | - | [`agent-presets`](../packages/preset/agent-presets), `gateway` | -| `internal/status` | - | [`agent`](../packages/core/agent) | +| `internal/status` | - | [`agent`](../packages/core/agent), `inspector` | 维护模式:生成内容。Cordis 事件声明及生产方/监听方的关系边由仓库的 TypeScript Program 解析。 diff --git a/docs/module-graph.i18n.yaml b/docs/module-graph.i18n.yaml index 5a1b662432..1fda2fbe2d 100644 --- a/docs/module-graph.i18n.yaml +++ b/docs/module-graph.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/module-graph.md -module-graph.md: e6013b2915121444f9f1e5ccc172190b8fccc650 -module-graph.zh.md: 6b491805dbbf7733cbda881552a2b8319d81ecc4 +module-graph.md: 0708aca1672546d28e956109f0fd7e5c255f4613 +module-graph.zh.md: ee0a7e54bef93247c1056d8736868c3de8e813d3 diff --git a/docs/module-graph.md b/docs/module-graph.md index e6013b2915..0708aca167 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -108,7 +108,6 @@ flowchart TD pkg_api_gateway["api-gateway"] pkg_api_remotes["api-remotes"] pkg_api_session_controller["api-session-controller"] - pkg_api_settings_controller["api-settings-controller"] pkg_api_workspace_controller["api-workspace-controller"] end subgraph group_attachment["packages/attachment"] @@ -209,6 +208,7 @@ flowchart TD pkg_experimental_agent_team_profile["experimental-agent-team-profile"] pkg_experimental_agent_team_web_profile["experimental-agent-team-web-profile"] pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"] + pkg_experimental_inspector["experimental-inspector"] pkg_experimental_tool_agent_team["experimental-tool-agent-team"] pkg_experimental_webworker_packer["experimental-webworker-packer"] pkg_experimental_webworker_runtime["experimental-webworker-runtime"] @@ -411,6 +411,8 @@ flowchart TD pkg_anonymous_user_id --> pkg_brand pkg_anonymous_user_id --> pkg_home_paths pkg_anonymous_user_id --> pkg_invariants + pkg_settings --> pkg_brand + pkg_settings --> pkg_invariants pkg_storage_domain --> pkg_invariants pkg_storage_domain --> pkg_storage pkg_storage_json --> pkg_invariants @@ -437,6 +439,13 @@ flowchart TD pkg_credentials_local --> pkg_home_paths pkg_credentials_local --> pkg_invariants pkg_credentials_local --> pkg_launch_environment + pkg_experimental_inspector --> pkg_client_modules + pkg_experimental_inspector --> pkg_host_webserver + pkg_experimental_inspector --> pkg_invariants + pkg_settings_file --> pkg_atomic_write + pkg_settings_file --> pkg_home_paths + pkg_settings_file --> pkg_invariants + pkg_settings_file --> pkg_settings pkg_session --> pkg_brand pkg_session --> pkg_invariants pkg_session --> pkg_llm @@ -499,9 +508,6 @@ flowchart TD pkg_session_persistence --> pkg_timeout pkg_session_projection --> pkg_invariants pkg_session_projection --> pkg_session - pkg_settings --> pkg_brand - pkg_settings --> pkg_invariants - pkg_settings --> pkg_session pkg_session_snapshot --> pkg_invariants pkg_session_snapshot --> pkg_session pkg_llm_retry --> pkg_agent @@ -535,11 +541,6 @@ flowchart TD pkg_web_search_deepseek --> pkg_web pkg_spill_local --> pkg_invariants pkg_spill_local --> pkg_spill - pkg_api_settings_controller --> pkg_credentials - pkg_api_settings_controller --> pkg_invariants - pkg_api_settings_controller --> pkg_session - pkg_api_settings_controller --> pkg_settings - pkg_api_settings_controller --> pkg_typert_protocol pkg_file_reference --> pkg_agent pkg_file_reference --> pkg_invariants pkg_file_reference --> pkg_typert_protocol @@ -608,10 +609,6 @@ flowchart TD pkg_session_title --> pkg_llm pkg_session_title --> pkg_session pkg_session_title --> pkg_session_projection - pkg_settings_file --> pkg_atomic_write - pkg_settings_file --> pkg_home_paths - pkg_settings_file --> pkg_invariants - pkg_settings_file --> pkg_settings pkg_shell --> pkg_invariants pkg_shell --> pkg_sandbox pkg_shell --> pkg_settings @@ -1095,7 +1092,6 @@ flowchart TD pkg_client_connection --> pkg_invariants pkg_client_connection --> pkg_llm pkg_client_connection --> pkg_session - pkg_client_connection --> pkg_settings pkg_client_connection --> pkg_tool_todo pkg_compaction_basic --> pkg_agent pkg_compaction_basic --> pkg_commands @@ -1111,10 +1107,7 @@ flowchart TD pkg_session_reference --> pkg_llm pkg_session_reference --> pkg_output_retention pkg_session_reference --> pkg_session - pkg_session_reference --> pkg_session_projection - pkg_session_reference --> pkg_session_projection_cache pkg_session_reference --> pkg_session_query - pkg_session_reference --> pkg_session_title pkg_session_reference --> pkg_typert_protocol pkg_agent_spine_demo --> pkg_agent pkg_agent_spine_demo --> pkg_agent_instructions @@ -1303,7 +1296,6 @@ flowchart TD pkg_api_remotes --> pkg_agent_presets pkg_api_remotes --> pkg_api_gateway pkg_api_remotes --> pkg_api_session_controller - pkg_api_remotes --> pkg_api_settings_controller pkg_api_remotes --> pkg_api_workspace_controller pkg_api_remotes --> pkg_commands pkg_api_remotes --> pkg_cordis_host_runner @@ -1547,15 +1539,12 @@ flowchart TD pkg_client_ui_commands --> pkg_invariants pkg_client_ui_commands --> pkg_session pkg_client_ui_reference --> pkg_api_remotes - pkg_client_ui_reference --> pkg_api_session_controller - pkg_client_ui_reference --> pkg_client_connection pkg_client_ui_reference --> pkg_client_locale pkg_client_ui_reference --> pkg_client_ui_input_trigger pkg_client_ui_reference --> pkg_file_reference pkg_client_ui_reference --> pkg_invariants pkg_client_ui_reference --> pkg_session_reference pkg_client_ui_reference --> pkg_typert_protocol - pkg_client_ui_reference --> pkg_util_workspace_path pkg_client_ui_subagent --> pkg_api_session_controller pkg_client_ui_subagent --> pkg_client_connection pkg_client_ui_subagent --> pkg_client_locale @@ -1631,6 +1620,7 @@ flowchart TD pkg_client_ui_model_selection --> pkg_typert_protocol pkg_client_ui_permission_presets --> pkg_api_remotes pkg_client_ui_permission_presets --> pkg_api_session_controller + pkg_client_ui_permission_presets --> pkg_client_connection pkg_client_ui_permission_presets --> pkg_client_locale pkg_client_ui_permission_presets --> pkg_client_ui_commands pkg_client_ui_permission_presets --> pkg_client_ui_input_trigger @@ -1742,6 +1732,7 @@ flowchart TD | [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) | | [`host-plugin-inventory`](../packages/host/plugin-inventory) | `host` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) | | [`anonymous-user-id`](../packages/identity/anonymous-user-id) | `identity` | [`brand`](../packages/util/brand), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) | +| [`settings`](../packages/settings/settings) | `settings` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`storage-domain`](../packages/storage/storage-domain) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | | [`storage-json`](../packages/storage/storage-json) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | | [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | @@ -1751,6 +1742,8 @@ flowchart TD | [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) | +| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | +| [`settings-file`](../packages/settings/settings-file) | `settings` | [`atomic-write`](../packages/util/atomic-write), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) | | [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) | | [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) | @@ -1770,7 +1763,6 @@ flowchart TD | [`session-log-deepseek`](../packages/session/session-log-deepseek) | `session` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-persistence`](../packages/session/session-persistence) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | | [`session-projection`](../packages/session/session-projection) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | -| [`settings`](../packages/settings/settings) | `settings` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`llm-retry`](../packages/llm/llm-retry) | `llm` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | | [`agent-default-model`](../packages/core/agent-default-model) | `core` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`settings`](../packages/settings/settings) | @@ -1778,7 +1770,6 @@ flowchart TD | [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) | | [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) | | [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) | -| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) | | [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) | | [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) | @@ -1794,7 +1785,6 @@ flowchart TD | [`session-stats`](../packages/session/session-stats) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) | | [`session-telemetry`](../packages/session/session-telemetry) | `session` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-title`](../packages/session/session-title) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) | -| [`settings-file`](../packages/settings/settings-file) | `settings` | [`atomic-write`](../packages/util/atomic-write), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`shell`](../packages/shell/shell) | `shell` | [`invariants`](../packages/runtime-diagnostics/invariants), [`sandbox`](../packages/sandbox/sandbox), [`settings`](../packages/settings/settings), [`subprocess`](../packages/subprocess/subprocess) | | [`terminal`](../packages/terminal/terminal) | `terminal` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`loader-smoke`](../packages/test-support/loader-smoke) | `test-support` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) | @@ -1873,9 +1863,9 @@ flowchart TD | [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) | | [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) | -| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) | +| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tool-todo`](../packages/todo/tool-todo) | | [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) | -| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) | +| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`typert-protocol`](../packages/typert/protocol) | | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) | | [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-modules`](../packages/client/modules), [`host-apiproxy`](../packages/host/apiproxy), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) | @@ -1901,7 +1891,7 @@ flowchart TD | [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) | | [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) | | [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) | -| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) | +| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) | | [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | @@ -1928,7 +1918,7 @@ flowchart TD | [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) | | [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | -| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) | +| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) | | [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) | @@ -1937,7 +1927,7 @@ flowchart TD | [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | -| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) | +| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) | | [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) | | [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-store`](../packages/client/store), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) | diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md index 6b491805db..ee0a7e54be 100644 --- a/docs/module-graph.zh.md +++ b/docs/module-graph.zh.md @@ -110,7 +110,6 @@ flowchart TD pkg_api_gateway["api-gateway"] pkg_api_remotes["api-remotes"] pkg_api_session_controller["api-session-controller"] - pkg_api_settings_controller["api-settings-controller"] pkg_api_workspace_controller["api-workspace-controller"] end subgraph group_attachment["packages/attachment"] @@ -211,6 +210,7 @@ flowchart TD pkg_experimental_agent_team_profile["experimental-agent-team-profile"] pkg_experimental_agent_team_web_profile["experimental-agent-team-web-profile"] pkg_experimental_client_ui_agent_team["experimental-client-ui-agent-team"] + pkg_experimental_inspector["experimental-inspector"] pkg_experimental_tool_agent_team["experimental-tool-agent-team"] pkg_experimental_webworker_packer["experimental-webworker-packer"] pkg_experimental_webworker_runtime["experimental-webworker-runtime"] @@ -413,6 +413,8 @@ flowchart TD pkg_anonymous_user_id --> pkg_brand pkg_anonymous_user_id --> pkg_home_paths pkg_anonymous_user_id --> pkg_invariants + pkg_settings --> pkg_brand + pkg_settings --> pkg_invariants pkg_storage_domain --> pkg_invariants pkg_storage_domain --> pkg_storage pkg_storage_json --> pkg_invariants @@ -439,6 +441,13 @@ flowchart TD pkg_credentials_local --> pkg_home_paths pkg_credentials_local --> pkg_invariants pkg_credentials_local --> pkg_launch_environment + pkg_experimental_inspector --> pkg_client_modules + pkg_experimental_inspector --> pkg_host_webserver + pkg_experimental_inspector --> pkg_invariants + pkg_settings_file --> pkg_atomic_write + pkg_settings_file --> pkg_home_paths + pkg_settings_file --> pkg_invariants + pkg_settings_file --> pkg_settings pkg_session --> pkg_brand pkg_session --> pkg_invariants pkg_session --> pkg_llm @@ -501,9 +510,6 @@ flowchart TD pkg_session_persistence --> pkg_timeout pkg_session_projection --> pkg_invariants pkg_session_projection --> pkg_session - pkg_settings --> pkg_brand - pkg_settings --> pkg_invariants - pkg_settings --> pkg_session pkg_session_snapshot --> pkg_invariants pkg_session_snapshot --> pkg_session pkg_llm_retry --> pkg_agent @@ -537,11 +543,6 @@ flowchart TD pkg_web_search_deepseek --> pkg_web pkg_spill_local --> pkg_invariants pkg_spill_local --> pkg_spill - pkg_api_settings_controller --> pkg_credentials - pkg_api_settings_controller --> pkg_invariants - pkg_api_settings_controller --> pkg_session - pkg_api_settings_controller --> pkg_settings - pkg_api_settings_controller --> pkg_typert_protocol pkg_file_reference --> pkg_agent pkg_file_reference --> pkg_invariants pkg_file_reference --> pkg_typert_protocol @@ -610,10 +611,6 @@ flowchart TD pkg_session_title --> pkg_llm pkg_session_title --> pkg_session pkg_session_title --> pkg_session_projection - pkg_settings_file --> pkg_atomic_write - pkg_settings_file --> pkg_home_paths - pkg_settings_file --> pkg_invariants - pkg_settings_file --> pkg_settings pkg_shell --> pkg_invariants pkg_shell --> pkg_sandbox pkg_shell --> pkg_settings @@ -1097,7 +1094,6 @@ flowchart TD pkg_client_connection --> pkg_invariants pkg_client_connection --> pkg_llm pkg_client_connection --> pkg_session - pkg_client_connection --> pkg_settings pkg_client_connection --> pkg_tool_todo pkg_compaction_basic --> pkg_agent pkg_compaction_basic --> pkg_commands @@ -1113,10 +1109,7 @@ flowchart TD pkg_session_reference --> pkg_llm pkg_session_reference --> pkg_output_retention pkg_session_reference --> pkg_session - pkg_session_reference --> pkg_session_projection - pkg_session_reference --> pkg_session_projection_cache pkg_session_reference --> pkg_session_query - pkg_session_reference --> pkg_session_title pkg_session_reference --> pkg_typert_protocol pkg_agent_spine_demo --> pkg_agent pkg_agent_spine_demo --> pkg_agent_instructions @@ -1305,7 +1298,6 @@ flowchart TD pkg_api_remotes --> pkg_agent_presets pkg_api_remotes --> pkg_api_gateway pkg_api_remotes --> pkg_api_session_controller - pkg_api_remotes --> pkg_api_settings_controller pkg_api_remotes --> pkg_api_workspace_controller pkg_api_remotes --> pkg_commands pkg_api_remotes --> pkg_cordis_host_runner @@ -1549,15 +1541,12 @@ flowchart TD pkg_client_ui_commands --> pkg_invariants pkg_client_ui_commands --> pkg_session pkg_client_ui_reference --> pkg_api_remotes - pkg_client_ui_reference --> pkg_api_session_controller - pkg_client_ui_reference --> pkg_client_connection pkg_client_ui_reference --> pkg_client_locale pkg_client_ui_reference --> pkg_client_ui_input_trigger pkg_client_ui_reference --> pkg_file_reference pkg_client_ui_reference --> pkg_invariants pkg_client_ui_reference --> pkg_session_reference pkg_client_ui_reference --> pkg_typert_protocol - pkg_client_ui_reference --> pkg_util_workspace_path pkg_client_ui_subagent --> pkg_api_session_controller pkg_client_ui_subagent --> pkg_client_connection pkg_client_ui_subagent --> pkg_client_locale @@ -1633,6 +1622,7 @@ flowchart TD pkg_client_ui_model_selection --> pkg_typert_protocol pkg_client_ui_permission_presets --> pkg_api_remotes pkg_client_ui_permission_presets --> pkg_api_session_controller + pkg_client_ui_permission_presets --> pkg_client_connection pkg_client_ui_permission_presets --> pkg_client_locale pkg_client_ui_permission_presets --> pkg_client_ui_commands pkg_client_ui_permission_presets --> pkg_client_ui_input_trigger @@ -1696,7 +1686,7 @@ flowchart TD pkg_client_ui_cordis --> pkg_invariants ``` -| Package | Group | Depends on | +| 包 | 分组 | 依赖 | | --- | --- | --- | | [`invariants`](../packages/runtime-diagnostics/invariants) | `runtime-diagnostics` | — | | [`atomic-write`](../packages/util/atomic-write) | `util` | [`invariants`](../packages/runtime-diagnostics/invariants) | @@ -1744,6 +1734,7 @@ flowchart TD | [`subprocess-e2b`](../packages/e2b/subprocess-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`invariants`](../packages/runtime-diagnostics/invariants), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) | | [`host-plugin-inventory`](../packages/host/plugin-inventory) | `host` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) | | [`anonymous-user-id`](../packages/identity/anonymous-user-id) | `identity` | [`brand`](../packages/util/brand), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) | +| [`settings`](../packages/settings/settings) | `settings` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`storage-domain`](../packages/storage/storage-domain) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | | [`storage-json`](../packages/storage/storage-json) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | | [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/runtime-diagnostics/invariants), [`storage`](../packages/storage/storage) | @@ -1753,6 +1744,8 @@ flowchart TD | [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`client-hmr`](../packages/client/hmr) | `client` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment) | +| [`experimental-inspector`](../packages/experimental/inspector) | `experimental` | [`client-modules`](../packages/client/modules), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | +| [`settings-file`](../packages/settings/settings-file) | `settings` | [`atomic-write`](../packages/util/atomic-write), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`session`](../packages/core/session) | `core` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`typert-protocol`](../packages/typert/protocol) | | [`system-prompt`](../packages/core/system-prompt) | `core` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) | | [`skill`](../packages/skill/skill) | `skill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope) | @@ -1772,7 +1765,6 @@ flowchart TD | [`session-log-deepseek`](../packages/session/session-log-deepseek) | `session` | [`deepseek-llm-api-extensions`](../packages/llm/deepseek-llm-api-extensions), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-persistence`](../packages/session/session-persistence) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | | [`session-projection`](../packages/session/session-projection) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | -| [`settings`](../packages/settings/settings) | `settings` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`llm-retry`](../packages/llm/llm-retry) | `llm` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) | | [`agent-default-model`](../packages/core/agent-default-model) | `core` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`settings`](../packages/settings/settings) | @@ -1780,7 +1772,6 @@ flowchart TD | [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) | | [`web-search-deepseek`](../packages/web/web-search-deepseek) | `web` | [`agent`](../packages/core/agent), [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`launch-environment`](../packages/util/launch-environment), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`web`](../packages/web/web) | | [`spill-local`](../packages/spill/spill-local) | `spill` | [`invariants`](../packages/runtime-diagnostics/invariants), [`spill`](../packages/spill/spill) | -| [`api-settings-controller`](../packages/api/settings-controller) | `api` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`typert-protocol`](../packages/typert/protocol) | | [`file-reference`](../packages/context/file-reference) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol) | | [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`message-feedback`](../packages/feedback/message-feedback) | `feedback` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`storage-domain`](../packages/storage/storage-domain), [`typert-protocol`](../packages/typert/protocol) | @@ -1796,7 +1787,6 @@ flowchart TD | [`session-stats`](../packages/session/session-stats) | `session` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) | | [`session-telemetry`](../packages/session/session-telemetry) | `session` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`session-title`](../packages/session/session-title) | `session` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) | -| [`settings-file`](../packages/settings/settings-file) | `settings` | [`atomic-write`](../packages/util/atomic-write), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`shell`](../packages/shell/shell) | `shell` | [`invariants`](../packages/runtime-diagnostics/invariants), [`sandbox`](../packages/sandbox/sandbox), [`settings`](../packages/settings/settings), [`subprocess`](../packages/subprocess/subprocess) | | [`terminal`](../packages/terminal/terminal) | `terminal` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`loader-smoke`](../packages/test-support/loader-smoke) | `test-support` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) | @@ -1875,9 +1865,9 @@ flowchart TD | [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) | | [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) | -| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`settings`](../packages/settings/settings), [`tool-todo`](../packages/todo/tool-todo) | +| [`client-connection`](../packages/client/connection) | `client` | [`attachment`](../packages/attachment/attachment), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`host-apiproxy`](../packages/host/apiproxy), [`host-directory-picker`](../packages/host/directory-picker), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tool-todo`](../packages/todo/tool-todo) | | [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) | -| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`typert-protocol`](../packages/typert/protocol) | +| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`typert-protocol`](../packages/typert/protocol) | | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) | | [`experimental-webworker-runtime`](../packages/experimental/webworker-runtime) | `experimental` | [`client-modules`](../packages/client/modules), [`host-apiproxy`](../packages/host/apiproxy), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`webhook-github`](../packages/webhook/webhook-github) | `webhook` | [`credentials`](../packages/credentials/credentials), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`webhook`](../packages/webhook/webhook) | @@ -1903,7 +1893,7 @@ flowchart TD | [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) | | [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) | | [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) | -| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-settings-controller`](../packages/api/settings-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) | +| [`api-remotes`](../packages/api/remotes) | `api` | [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-reference`](../packages/context/session-reference), [`settings`](../packages/settings/settings), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval), [`user-questions`](../packages/interaction/user-questions) | | [`client-ui-session`](../packages/client/ui-session) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-ui-renderer`](../packages/client/ui-renderer), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | | [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | | [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) | @@ -1930,7 +1920,7 @@ flowchart TD | [`experimental-client-ui-agent-team`](../packages/experimental/client-ui-agent-team) | `experimental` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-slots`](../packages/client/ui-slots), [`experimental-agent-team`](../packages/experimental/agent-team), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-chat`](../packages/client/ui-chat) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-locale`](../packages/client/locale), [`client-ui-approval`](../packages/client/ui-approval), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-layout`](../packages/client/ui-layout), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-workspace`](../packages/client/ui-workspace), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`util-workspace-path`](../packages/util/workspace-path) | | [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session) | -| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol), [`util-workspace-path`](../packages/util/workspace-path) | +| [`client-ui-reference`](../packages/client/ui-reference) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`file-reference`](../packages/context/file-reference), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-reference`](../packages/context/session-reference), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-subagent`](../packages/client/ui-subagent) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter) | | [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) | | [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) | @@ -1939,7 +1929,7 @@ flowchart TD | [`client-ui-goal`](../packages/client/ui-goal) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`commands`](../packages/interaction/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-message-feedback`](../packages/client/ui-message-feedback) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | | [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | -| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) | +| [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`api-session-controller`](../packages/api/session-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) | | [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`api-workspace-controller`](../packages/api/workspace-controller), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`util-workspace-path`](../packages/util/workspace-path) | | [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`api-session-controller`](../packages/api/session-controller), [`client-locale`](../packages/client/locale), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`api-session-controller`](../packages/api/session-controller), [`api-workspace-controller`](../packages/api/workspace-controller), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-store`](../packages/client/store), [`client-ui-chat`](../packages/client/ui-chat), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-renderer`](../packages/client/ui-renderer), [`client-ui-session`](../packages/client/ui-session), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) | diff --git a/docs/subsystems/extensions.i18n.yaml b/docs/subsystems/extensions.i18n.yaml index e3a18d04d7..91f9f20574 100644 --- a/docs/subsystems/extensions.i18n.yaml +++ b/docs/subsystems/extensions.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/extensions.md -extensions.md: 0418afc7f1b6b6cd892deb618a4f346f6cde720d -extensions.zh.md: f2d86add9f1b62913fcc1b89abf1fc1a1d2a178f +extensions.md: 540f3c477b4e128b0c1062192185e6276c9e9263 +extensions.zh.md: ebfe7827484cea2cf8c6d77ca26796f7751d203a diff --git a/docs/subsystems/extensions.md b/docs/subsystems/extensions.md index 0418afc7f1..540f3c477b 100644 --- a/docs/subsystems/extensions.md +++ b/docs/subsystems/extensions.md @@ -256,6 +256,24 @@ Types: [Agent](core.md) Source: [`packages/extensions/cordis-host-runner/src/index.ts`](../../packages/extensions/cordis-host-runner/src/index.ts) + + +### `ctx.inspector` — `InspectorService` + +Shared Host/Client service façade over the realm's source publisher. + +```ts cordis-catalog +/** + * Publish one JSON observation without waiting for Worker delivery. + * @param topic - Domain-owned topic name. + * @param payload - JSON value validated before it reaches the carrier. + * @param monotonicMs - Source-clock timestamp; defaults to `performance.now()`. + */ +publish(topic: string, payload: InspectorJsonValue, monotonicMs?: number): void +``` + +Source: [`packages/experimental/inspector/src/index.ts`](../../packages/experimental/inspector/src/index.ts) + ### `cordis/*` events diff --git a/docs/subsystems/extensions.zh.md b/docs/subsystems/extensions.zh.md index f2d86add9f..ebfe782748 100644 --- a/docs/subsystems/extensions.zh.md +++ b/docs/subsystems/extensions.zh.md @@ -256,6 +256,24 @@ Types: [Agent](core.zh.md) Source: [`packages/extensions/cordis-host-runner/src/index.ts`](../../packages/extensions/cordis-host-runner/src/index.ts) + + +### `ctx.inspector` — `InspectorService` + +Shared Host/Client service façade over the realm's source publisher. + +```ts cordis-catalog +/** + * Publish one JSON observation without waiting for Worker delivery. + * @param topic - Domain-owned topic name. + * @param payload - JSON value validated before it reaches the carrier. + * @param monotonicMs - Source-clock timestamp; defaults to `performance.now()`. + */ +publish(topic: string, payload: InspectorJsonValue, monotonicMs?: number): void +``` + +Source: [`packages/experimental/inspector/src/index.ts`](../../packages/experimental/inspector/src/index.ts) + ### `cordis/*` events diff --git a/packages/experimental/README.i18n.yaml b/packages/experimental/README.i18n.yaml index 3636475c1a..b7e7236631 100644 --- a/packages/experimental/README.i18n.yaml +++ b/packages/experimental/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/experimental/README.md -README.md: 2812388377611ebbed0f415d637bd14bffcee34c -README.zh.md: 3dcf13d9ef73b540fe4b8f3d7f6df2e623bca6f4 +README.md: 750f38a116681a4a57575e9a55a49c06e7b40108 +README.zh.md: 551ef051a57e2787cea080a3df26c98d2af68f7c diff --git a/packages/experimental/README.md b/packages/experimental/README.md index 2812388377..750f38a116 100644 --- a/packages/experimental/README.md +++ b/packages/experimental/README.md @@ -9,7 +9,7 @@ English | [中文](README.zh.md) ## Summary -The experimental group contains prototype capabilities that are not part of any official release: they run on the real harness, but their contracts can change and they carry no support promise. The group holds Agent Teams plus the browser-worker runtime and image packer used by preview deployments. Use these packages to try an unreleased capability; they carry no stability promise, and released products must not depend on them. +The experimental group contains prototype capabilities that are not part of any official release: they run on the real harness, but their contracts can change and they carry no support promise. The group holds Agent Teams, the cross-realm Inspector, and the browser-worker runtime and image packer used by preview deployments. Use these packages to try an unreleased capability; they carry no stability promise, and released products must not depend on them. ## Table of Contents @@ -28,6 +28,7 @@ The experimental group contains prototype capabilities that are not part of any | [`agent-team`](agent-team/README.md) | Named teammates with durable messages and a shared task board | `ctx.agentTeams` | | [`agent-team-web-profile`](agent-team-web-profile/README.md) | Explicit source-checkout Web layer for Agent Teams | — | | [`client-ui-agent-team`](client-ui-agent-team/README.md) | Team roster, task board, and teammate navigation for Web | — | +| [`inspector`](inspector/README.md) | Cross-realm CDP hub for Host debugging, Client Runtime inspection, network capture, and Cordis trees | `ctx.inspector` | | [`tool-agent-team`](tool-agent-team/README.md) | Ten tools that let the model create, message, and coordinate teammates | registers scoped tools on `ctx.tools` | | [`webworker-packer`](webworker-packer/README.md) | Builds the gzip-compressed VFS image consumed by the browser worker preview | library and CLI — no ctx key | | [`webworker-runtime`](webworker-runtime/README.md) | Runs the harness plugin tree inside a dedicated browser worker | library and worker entry — no ctx key | diff --git a/packages/experimental/README.zh.md b/packages/experimental/README.zh.md index 3dcf13d9ef..551ef051a5 100644 --- a/packages/experimental/README.zh.md +++ b/packages/experimental/README.zh.md @@ -9,7 +9,7 @@ kind: "package-group" ## 概述 -实验组包含不属于任何正式发布的原型能力:它们运行在真实 harness 上,但约定可能变更,也不提供支持承诺。本组包含 Agent Teams,以及预览部署使用的浏览器 worker 运行时与镜像打包器。用这些包来尝试未发布的能力;它们没有稳定性承诺,已发布产品不得依赖它们。 +实验组包含不属于任何正式发布的原型能力:它们运行在真实 harness 上,但约定可能变更,也不提供支持承诺。本组包含 Agent Teams、跨 realm Inspector,以及预览部署使用的浏览器 worker 运行时与镜像打包器。用这些包来尝试未发布的能力;它们没有稳定性承诺,已发布产品不得依赖它们。 ## 目录 @@ -28,6 +28,7 @@ kind: "package-group" | [`agent-team`](agent-team/README.zh.md) | 具名 teammate,成员之间持久消息与共享任务板 | `ctx.agentTeams` | | [`agent-team-web-profile`](agent-team-web-profile/README.zh.md) | Agent Teams 的显式源码 checkout Web 层 | — | | [`client-ui-agent-team`](client-ui-agent-team/README.zh.md) | Web Team roster、任务板与 teammate 导航 | — | +| [`inspector`](inspector/README.zh.md) | 用于 Host 调试、Client Runtime 检查、网络采集与 Cordis 树的跨 realm CDP hub | `ctx.inspector` | | [`tool-agent-team`](tool-agent-team/README.zh.md) | 让模型创建、发消息与协调 teammate 的十个工具 | 按作用域注册工具到 `ctx.tools` | | [`webworker-packer`](webworker-packer/README.zh.md) | 构建浏览器 worker 预览所消费的 gzip 压缩 VFS 镜像 | 库与 CLI,不使用 ctx key | | [`webworker-runtime`](webworker-runtime/README.zh.md) | 在专用浏览器 worker 中运行 harness 插件树 | 库与 worker 入口,不使用 ctx key | diff --git a/packages/experimental/inspector/README.i18n.yaml b/packages/experimental/inspector/README.i18n.yaml new file mode 100644 index 0000000000..f146394b7a --- /dev/null +++ b/packages/experimental/inspector/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/experimental/inspector/README.md +README.md: dcebe9527de1b909fe1efc9f73977735ad374a95 +README.zh.md: 9ca43b0420f22969b6bd060bf9546eb094c4fbc0 diff --git a/packages/experimental/inspector/README.md b/packages/experimental/inspector/README.md new file mode 100644 index 0000000000..dcebe9527d --- /dev/null +++ b/packages/experimental/inspector/README.md @@ -0,0 +1,105 @@ +# @deepseek-ai/dsh-experimental-inspector + +English | [中文](README.zh.md) + +Experimental Client/Host Cordis plugin that exposes one Chrome DevTools Protocol target from a Node worker thread. The Host and browser Client publish versioned observations into the Worker; the Worker is the sole owner of CDP state and output. + +The package is private and excluded from releases. The Worker never accesses live Cordis objects: the shared Host/Client collector projects them into validated snapshots before transport. Cordis also owns plugin composition, `ctx.inspector` registration, bootstrap injection, and disposal. + +## Runtime layout + +The Host plugin starts the Worker and connects a dedicated `MessagePort`. The Client plugin reads the injected `globalThis.__DSH_INSPECTOR__` bootstrap and opens a separate authenticated WebSocket directly to the Worker. Chrome DevTools connects to the Worker's CDP WebSocket. A private `node:inspector.Session` per DevTools connection attaches from the Worker to the Host main thread, so Host Console evaluation, Sources, breakpoints, and resume remain available while Host JavaScript is paused. + +The source tree follows those execution environments: `client/` and `host/` provide mirrored adapter entry paths, `worker/` contains only Worker-thread orchestration and Chrome protocol state, and `shared/` contains environment-independent Cordis and network models, normalized realm backend interfaces, and the internal bridge protocol. Worker-side Client and Host adapters are mirrored under `worker/realms/`; a Client adapter in that directory still executes in the Worker. + +Host and Client producers send internal observation records rather than CDP messages. Records contain a source generation, sequence, source-clock timestamp, topic, and JSON payload. The Worker validates every process or network frame, owns source state and retention, and translates recognized topics to standard CDP domains. + +Client sources declare typed Runtime, Console, and read-only Sources capabilities. `Runtime.enable` publishes the real Host execution context and one synthetic context for every connected Client source. Selecting a Client context routes evaluation, property access, function calls, promise awaiting, and object release to that browser realm. Client Console arguments use the same session-local object table, while `Debugger.enable` publishes the built `lib/client.js` catalog and `Debugger.getScriptSource` reads bounded content chunks. Client-script breakpoints, step, and call frames remain unsupported; target-wide pause and resume control the Host debugger only. + +Both plugin faces run the same browser-safe Cordis collector. It converts reachable Context and Fiber objects into a versioned `CordisTreeSnapshot`; the Worker stores that CDP-independent representation and projects each Host or Client source into the Elements panel. + +## Configuration + +The Host plugin injects `webServer` and accepts these fields: + +| Field | Default | Meaning | +|---|---:|---| +| `host` | `127.0.0.1` | Worker endpoint bind address; only loopback is accepted | +| `port` | `9230` | First Worker endpoint port; occupied ports advance upward, while `0` requests an OS-assigned port | +| `clientOrigins` | `[]` | Additional exact browser origins accepted by `/ingest`; loopback origins remain accepted | +| `captureFetch` | `true` | Wrap `globalThis.fetch` and publish every later call | +| `maxRequestBodyBytes` | 8 MiB | Per-request captured request-body prefix | +| `maxResponseBodyBytes` | 32 MiB | Per-request captured response-body prefix | +| `maxBodyChunkBytes` | 48 KiB | Raw bytes carried by one body record before base64 encoding | +| `maxJournalBytes` | 256 MiB | Worker-retained request and response body bytes | +| `maxRetainedRequests` | `2000` | Active and completed requests retained by the Worker | +| `maxSourceFrameBytes` | 128 KiB | Encoded source-frame limit | +| `maxSourceRecordsPerFrame` | `128` | Records in one source batch | +| `maxQueuedRecords` | `2048` | Per-producer records waiting for transport | +| `maxQueuedBytes` | 16 MiB | Per-producer queued encoded bytes | +| `startupTimeoutMs` | 10 seconds | Worker readiness deadline | +| `stopTimeoutMs` | 5 seconds | Graceful Worker shutdown deadline before termination | +| `clientReconnectBaseMs` | 250 ms | First Client reconnect backoff cap | +| `clientReconnectMaxMs` | 5 seconds | Maximum Client reconnect backoff cap | +| `clientRuntimeTimeoutMs` | 30 seconds | Deadline for one Worker-to-Client Runtime or Sources command | +| `queryTimeoutMs` | 10 seconds | Deadline for one non-CDP semantic query | +| `maxClientRuntimeObjects` | `10000` | Live Client object handles retained per DevTools connection | +| `maxClientRuntimeProperties` | `2000` | Property descriptors returned by one Client object inspection | +| `maxClientSourceBytes` | 8 MiB | Maximum encoded bytes read from one Client script or source map | +| `maxCordisNodes` | `2048` | Context and Fiber nodes admitted from one realm snapshot before truncation | +| `maxDisconnectedCordisTrees` | `8` | Last disconnected realm trees retained as non-live snapshots | + +The Host logs a `devtools://` URL after the Worker listens. The same Worker serves `/json`, `/json/list`, `/json/version`, the target WebSocket under `/devtools/page/`, and the Client source at `/ingest`. + +## Observation API + +Both plugin faces provide the same service: + +```ts +import type { Context } from '@deepseek-ai/cordis' +import type { InspectorJsonValue } from '@deepseek-ai/dsh-experimental-inspector' + +declare const ctx: Context +declare const topic: string +declare const jsonPayload: InspectorJsonValue + +ctx.inspector.publish(topic, jsonPayload) +await ctx.inspector.cordis.getTree() +``` + +Publishing validates lossless JSON and schedules delivery without waiting for the Worker. Each source has a bounded queue. Overflow is reported as a sequence gap and never delays the observed application operation. `cordis.getTree()` reads the Worker's latest detached semantic snapshot without creating a CDP session or enabling Runtime, Debugger, or Sources. + +## Cordis tree inspection + +The Elements document has fixed `` and `` containers. `` contains the Host root Context; `` contains one `` per Client source, and each `` contains that realm's root Context. The Cordis root Fiber is omitted. Every other Fiber is a child of `fiber.parent`, owns exactly one Context child for `fiber.ctx`, and carries only `uid=""`; Context elements have no attributes. Context-only `extend()`, `isolate()`, and `intercept()` layers remain direct Context descendants. + +Host and Client publish the same nested `CordisTreeSnapshot` type. Context and Fiber nodes carry opaque object handles for realm-local object lookup; Fiber nodes additionally carry Cordis `uid`. The Worker composes those realm snapshots into one `{ host, clients }` inspection tree. It assigns `BackendNodeId` values per source generation; each DevTools connection assigns its own `NodeId` values; `DOM.resolveNode` asks the owning Host or Client Runtime for a connection-local `RemoteObjectId`. `DOM.requestNode` maps that object id back to the same Elements node. `ctx.inspector.cordis.getTree()` and `DSHInspector.getCordisTree` read the detached consumer-neutral tree without routing handles or CDP ids. + +When a Client disconnects, its Console execution context and live object ids are destroyed immediately. With disconnected-tree retention enabled, Elements keeps the last tree unchanged while connection state remains in the inspection model rather than becoming an unreviewed DOM attribute. Reconnection keeps the logical source id, creates a new synthetic CDP context id for the new transport generation, and replaces the stale tree after its complete snapshot arrives. The Worker retains at most `maxDisconnectedCordisTrees` such snapshots; zero removes them immediately. + +## Host fetch capture + +Fetch capture is on by default and records the complete URL, all request and response headers, request body, response body, status, timing, errors, and cancellation. It does not redact credentials, cookies, query values, or payloads. Body capture reads clones; the caller receives the original Response as soon as the original fetch resolves. + +The configured body limits bound retention rather than select fields: capture keeps the prefix and marks the result truncated. `Network.getRequestPostData` and `Network.getResponseBody` read the Worker's retained bytes. `Network.streamResourceContent` returns the buffered prefix and adds later response bytes to `Network.dataReceived` for that DevTools connection, which drives live Response and EventStream views. Direct Undici Client/Dispatcher calls and fetch references retained before plugin activation are outside this observer. + +## Security + +The CDP target grants arbitrary code execution in both Host and connected Client realms through `Runtime.evaluate`; Host Debugger operations provide additional control. Full fetch capture includes secrets. The Worker therefore accepts only a `127.0.0.1` bind address. Client ingest additionally requires a random WebSocket subprotocol token injected by the Host and rejects non-loopback origins unless explicitly configured. The CDP socket itself has no token; loopback binding is its only access control. + +## Model Experience + +None, as this developer-only inspector observes runtime activity without changing model requests. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **Client active debugging is unsupported** — Console events, Runtime evaluation, RemoteObject access, and read-only `lib/client.js` Sources work. Client-script debugger requests return explicit unsupported errors; target-wide pause and resume control the Host only. +- **Client Sources expose the Inspector bundle only** — other page scripts are not cataloged by this package. +- **Client evaluation uses page JavaScript** — page Content Security Policy can block dynamic evaluation, and the synthetic context does not provide DevTools command-line helpers or native REPL declaration semantics. +- **Fetch interception covers `globalThis.fetch`** — direct Undici APIs and fetch references retained before activation are not observed. +- **Body cloning has cost** — full capture tees request and response streams up to the configured limits and can increase memory and I/O pressure. The retained-body limit does not include buffering inside the stream tee, including an oversized source chunk or data queued for a slower application reader. +- **No automatic Worker restart** — an unexpected Worker exit fails the current Inspector instance; lifecycle recovery belongs to a later change. diff --git a/packages/experimental/inspector/README.zh.md b/packages/experimental/inspector/README.zh.md new file mode 100644 index 0000000000..9ca43b0420 --- /dev/null +++ b/packages/experimental/inspector/README.zh.md @@ -0,0 +1,105 @@ +# @deepseek-ai/dsh-experimental-inspector + +[English](README.md) | 中文 + +实验性 Client/Host 双面 Cordis 插件,在 Node worker thread 中提供一个 Chrome DevTools Protocol target。Host 与浏览器 Client 向 Worker 发布带版本的观测记录;Worker 独占 CDP 状态与输出。 + +本包为私有包,不进入正式发布。Worker 不访问实时 Cordis 对象;共享 Host/Client collector 会在传输前把它们投影成已验证 snapshot。Cordis 还负责插件组合、注册 `ctx.inspector`、注入 bootstrap 和资源释放。 + +## 运行时布局 + +Host 插件启动 Worker 并连接专用 `MessagePort`。Client 插件读取注入的 `globalThis.__DSH_INSPECTOR__` bootstrap,直接向 Worker 打开一条独立、带鉴权的 WebSocket。Chrome DevTools 连接 Worker 的 CDP WebSocket。每条 DevTools 连接在 Worker 中独占一个连接 Host 主线程的 `node:inspector.Session`,因此 Host JavaScript 暂停时,Host Console 求值、Sources、断点和 resume 仍然可用。 + +源码树遵循这些执行环境:`client/` 与 `host/` 提供镜像的 adapter entry path,`worker/` 只包含 Worker thread orchestration 与 Chrome protocol 状态,`shared/` 包含与环境无关的 Cordis 和 network model、规范化 realm backend interface 及内部 bridge protocol。Worker 侧 Client 与 Host adapter 镜像放在 `worker/realms/` 下;其中的 Client adapter 仍然在 Worker 中执行。 + +Host 与 Client producer 发送内部观测记录,不发送 CDP 消息。记录包含 source generation、sequence、source 时钟时间、topic 和 JSON payload。Worker 验证每个进程或网络帧,独占 source 状态与保留历史,并把已识别 topic 转换成标准 CDP domain。 + +Client source 声明类型化 Runtime、Console 和只读 Sources 能力。`Runtime.enable` 发布真实 Host execution context,并为每个已连接的 Client source 发布一个 synthetic context。选择 Client context 后,求值、属性读取、函数调用、Promise await 和对象释放都会路由到该浏览器 realm。Client Console argument 使用同一份 session-local object table;`Debugger.enable` 发布构建后的 `lib/client.js` catalog,`Debugger.getScriptSource` 读取有界 content chunk。Client script 断点、step 和 call frame 仍不支持;target-wide pause 与 resume 只控制 Host debugger。 + +两个插件面运行同一份浏览器安全 Cordis collector。它把可达 Context 与 Fiber 对象转换成有版本的 `CordisTreeSnapshot`;Worker 存储这份与 CDP 无关的表示,并把每个 Host 或 Client source 投影到 Elements 面板。 + +## 配置 + +Host 插件注入 `webServer`,接受以下字段: + +| 字段 | 默认值 | 含义 | +|---|---:|---| +| `host` | `127.0.0.1` | Worker endpoint 监听地址;只接受 loopback | +| `port` | `9230` | Worker endpoint 起始端口;端口占用时向上递增,`0` 表示由操作系统分配 | +| `clientOrigins` | `[]` | `/ingest` 额外接受的精确浏览器 origin;loopback origin 始终允许 | +| `captureFetch` | `true` | 包装 `globalThis.fetch` 并发布之后的每次调用 | +| `maxRequestBodyBytes` | 8 MiB | 每次请求保留的 request body 前缀 | +| `maxResponseBodyBytes` | 32 MiB | 每次请求保留的 response body 前缀 | +| `maxBodyChunkBytes` | 48 KiB | base64 编码前一条 body 记录携带的原始字节数 | +| `maxJournalBytes` | 256 MiB | Worker 保留的请求与响应 body 总字节数 | +| `maxRetainedRequests` | `2000` | Worker 保留的进行中与已完成请求总数 | +| `maxSourceFrameBytes` | 128 KiB | 编码后的 source frame 上限 | +| `maxSourceRecordsPerFrame` | `128` | 每个 source batch 的记录数 | +| `maxQueuedRecords` | `2048` | 每个 producer 等待发送的记录数 | +| `maxQueuedBytes` | 16 MiB | 每个 producer 等待发送的编码字节数 | +| `startupTimeoutMs` | 10 秒 | Worker ready 截止时间 | +| `stopTimeoutMs` | 5 秒 | 强制终止前的 Worker 优雅关闭期限 | +| `clientReconnectBaseMs` | 250 ms | Client 首次重连退避上限 | +| `clientReconnectMaxMs` | 5 秒 | Client 最大重连退避上限 | +| `clientRuntimeTimeoutMs` | 30 秒 | 一次 Worker 到 Client Runtime 或 Sources 命令的截止时间 | +| `queryTimeoutMs` | 10 秒 | 一次非 CDP 语义查询的截止时间 | +| `maxClientRuntimeObjects` | `10000` | 每条 DevTools 连接保留的 Client 实时对象 handle 数 | +| `maxClientRuntimeProperties` | `2000` | 单次 Client 对象检查返回的属性描述符数 | +| `maxClientSourceBytes` | 8 MiB | 单个 Client script 或 source map 允许读取的最大编码字节数 | +| `maxCordisNodes` | `2048` | 一个 realm snapshot 截断前允许的 Context 与 Fiber 节点数 | +| `maxDisconnectedCordisTrees` | `8` | 作为非实时 snapshot 保留的最近断联 realm 树数量 | + +Worker 监听后,Host 会记录一个 `devtools://` URL。同一个 Worker 提供 `/json`、`/json/list`、`/json/version`、`/devtools/page/` target WebSocket 和 `/ingest` Client source。 + +## 观测 API + +两个插件面都提供同一个服务: + +```ts +import type { Context } from '@deepseek-ai/cordis' +import type { InspectorJsonValue } from '@deepseek-ai/dsh-experimental-inspector' + +declare const ctx: Context +declare const topic: string +declare const jsonPayload: InspectorJsonValue + +ctx.inspector.publish(topic, jsonPayload) +await ctx.inspector.cordis.getTree() +``` + +发布操作先验证无损 JSON,再调度发送,不等待 Worker。每个 source 的队列都有上限;溢出表现为 sequence gap,绝不延迟被观察的应用操作。`cordis.getTree()` 读取 Worker 最新的 detached semantic snapshot,不创建 CDP session,也不启用 Runtime、Debugger 或 Sources。 + +## Cordis tree inspection + +Elements document 包含固定的 `` 与 `` 容器。`` 包含 Host root Context;`` 为每个 Client source 包含一个 ``,每个 `` 再包含该 realm 的 root Context。Cordis root Fiber 不显示。其他 Fiber 都是 `fiber.parent` 的子节点,并包含唯一一个表示 `fiber.ctx` 的 Context 子节点;Fiber 只携带 `uid=""`,Context element 不携带 attribute。只有 Context 的 `extend()`、`isolate()` 与 `intercept()` 层仍然是直接 Context 后代。 + +Host 与 Client 发布同一种嵌套 `CordisTreeSnapshot` 类型。Context 与 Fiber 节点携带用于 realm-local 对象查询的不透明 object handle;Fiber 还携带 Cordis `uid`。Worker 把这些 realm snapshot 组合成一棵 `{ host, clients }` inspection tree。Worker 按 source generation 分配 `BackendNodeId`;每条 DevTools 连接分配自己的 `NodeId`;`DOM.resolveNode` 请求所属 Host 或 Client Runtime 生成连接本地 `RemoteObjectId`。`DOM.requestNode` 把该 object id 映射回同一个 Elements 节点。`ctx.inspector.cordis.getTree()` 与 `DSHInspector.getCordisTree` 读取不含 routing handle 或 CDP id 的 detached consumer-neutral tree。 + +Client 断联时,其 Console execution context 与 live object id 会立即销毁。启用断联树保留后,Elements 会原样保留最后一棵树;连接状态留在 inspection model 中,不会未经设计就成为 DOM attribute。重连会沿用逻辑 source id,为新的 transport generation 创建新的 synthetic CDP context id,并在完整 snapshot 到达后替换旧树。Worker 最多保留 `maxDisconnectedCordisTrees` 棵此类 snapshot;设为零会立即移除。 + +## Host fetch 采集 + +fetch 采集默认开启,记录完整 URL、全部请求与响应 headers、请求体、响应体、状态、时间、错误和取消。它不脱敏 credential、Cookie、query value 或 payload。body 采集读取 clone;原始 fetch resolve 后,调用方立即拿到原始 Response。 + +配置的 body 上限限制保留量,而不选择字段:采集保留前缀并标记 truncated。`Network.getRequestPostData` 与 `Network.getResponseBody` 读取 Worker 保留的字节。`Network.streamResourceContent` 返回已缓冲的前缀,并仅为发起调用的 DevTools 连接把后续 response 字节附加到 `Network.dataReceived`,以驱动实时 Response 与 EventStream 视图。直接调用 Undici Client/Dispatcher,以及插件激活前保存的 fetch 引用,不在观察范围内。 + +## 安全 + +CDP target 通过 `Runtime.evaluate` 提供 Host 和已连接 Client realm 中的任意代码执行能力,Host Debugger 操作还会提供额外控制,完整 fetch 采集也包含秘密。因此 Worker 只接受 `127.0.0.1` 监听地址。Client ingest 还要求 Host 注入的随机 WebSocket subprotocol token;除非配置明确允许,否则拒绝非 loopback origin。CDP socket 本身不携带 token,loopback 监听是它唯一的访问控制。 + +## 模型体验 + +无:这个仅供开发者使用的 Inspector 只观察运行时活动,不改变模型请求。 + +#### KV Cache 影响 + +无:本包既不组装也不发送 provider 请求。 + +## Known Limitations and Deferred Work + +- **Client active debugging 不受支持**——Console event、Runtime 求值、RemoteObject 访问和只读 `lib/client.js` Sources 可用。Client script debugger request 返回明确的 unsupported error;target-wide pause 与 resume 只控制 Host。 +- **Client Sources 只暴露 Inspector bundle**——本包不收录页面中的其他 script。 +- **Client 求值使用页面 JavaScript**——页面 Content Security Policy 可能阻止动态求值;synthetic context 不提供 DevTools command-line helper 或原生 REPL 声明语义。 +- **fetch 拦截范围是 `globalThis.fetch`**——直接调用 Undici API,以及激活前保存的 fetch 引用不会被观察。 +- **body clone 有运行成本**——完整采集会 tee 请求与响应 stream,直至达到配置上限,可能增加内存与 I/O 压力。保留 body 的上限不包含 stream tee 内部的缓冲,包括来源提供的超大 chunk,或为读取较慢的应用分支排队的数据。 +- **不自动重启 Worker**——Worker 意外退出会使当前 Inspector 实例失败;生命周期恢复留待后续改动。 diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index 00af95b674..25c60c5b52 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -549,6 +549,13 @@ const SERVICE_ROLES: ServiceRole[] = [ consumers: ['experimental-tool-agent-team', 'experimental-client-ui-agent-team'], note: 'Owns the implicit-root roster, durable peer mailbox, shared task DAG, continuable-child lifecycle, and generated Team Remote methods; tool-agent-team contributes model controls and client-ui-agent-team mounts the browser contribution.', }, + { + key: 'inspector', + pkg: 'inspector', + title: 'Cross-realm runtime inspection', + mode: 'core', + note: 'Owns the Worker-hosted CDP target and the transport-independent Host and Client observation and Cordis-tree query API.', + }, { key: 'jobs', pkg: 'jobs', diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts index 9e88355ec9..4ea84b36fe 100644 --- a/scripts/verify-package-readme-model-experience.ts +++ b/scripts/verify-package-readme-model-experience.ts @@ -66,6 +66,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly> = { 'packages/test-support/client-runtime': { kind: 'none', reason: 'Browser-side test infrastructure (jsdom bench); registers nothing model-facing.' }, 'packages/experimental/webworker-runtime': { kind: 'none', reason: 'Browser-side host runtime and Node-compatibility layer; the plugins it boots own every model-facing registration.' }, 'packages/experimental/webworker-packer': { kind: 'none', reason: 'Build-time image writer; its output reaches a model only through the tree the worker then boots.' }, + 'packages/experimental/inspector': { kind: 'none', reason: 'Developer diagnostics transport; it observes runtime activity without changing model requests.' }, 'packages/client/ui-slots': { kind: 'none', reason: 'Browser-side UI plugin layer; registers nothing model-facing.' }, 'packages/client/ui-attachment': { kind: 'none', reason: 'Browser-side UI plugin layer; registers nothing model-facing.' }, 'packages/client/ui-primitives': { kind: 'none', reason: 'Browser-side UI plugin layer; registers nothing model-facing.' },