From 22ac9a4ddf6b985fa9d0b02dce5639e9839df966 Mon Sep 17 00:00:00 2001 From: Yao Jingxi <23722032@bjtu.edu.cn> Date: Sun, 25 Oct 2026 22:12:09 +0800 Subject: [PATCH 1/3] docs(debug): propose JSON-composed debugger plugin design (#1210) --- ...lic-extension-contract-and-provider-api.md | 2 + ...r-provider-and-declarative-registration.md | 235 ++++++++++++++ .../proposals/debug-adapters-1210/README.md | 142 +++++++++ ...bug-adapter-registration.draft.schema.json | 296 ++++++++++++++++++ .../debug-capability-state.draft.schema.json | 73 +++++ .../debug-composition.draft.schema.json | 161 ++++++++++ .../debug-configuration.draft.schema.json | 97 ++++++ .../debug-function-binding.draft.schema.json | 36 +++ .../debug-start-plan.draft.schema.json | 88 ++++++ .../examples/dap-runtime.library.json | 57 ++++ .../examples/java-runtime.library.json | 48 +++ .../examples/java.capabilities.json | 21 ++ .../examples/java.configuration.json | 19 ++ .../examples/java.function-call.json | 18 ++ .../examples/java.prepare.json | 9 + .../examples/java.ready.json | 24 ++ .../examples/java.registration.json | 87 +++++ .../examples/native.capabilities.json | 26 ++ .../examples/native.configuration.json | 15 + .../examples/native.registration.json | 115 +++++++ .../examples/node.registration.json | 95 ++++++ .../examples/plugin-functions.library.json | 26 ++ .../examples/python.configuration.json | 22 ++ .../examples/python.registration.json | 105 +++++++ .../examples/schemas/java-launch.schema.json | 12 + .../schemas/native-attach.schema.json | 10 + .../schemas/native-launch.schema.json | 11 + .../examples/schemas/node-launch.schema.json | 11 + .../schemas/python-launch.schema.json | 13 + 29 files changed, 1874 insertions(+) create mode 100644 .agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md create mode 100644 shared/proposals/debug-adapters-1210/README.md create mode 100644 shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java-runtime.library.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.capabilities.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.configuration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.function-call.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.prepare.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.ready.json create mode 100644 shared/proposals/debug-adapters-1210/examples/java.registration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/native.capabilities.json create mode 100644 shared/proposals/debug-adapters-1210/examples/native.configuration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/native.registration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/node.registration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json create mode 100644 shared/proposals/debug-adapters-1210/examples/python.configuration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/python.registration.json create mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json create mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json create mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json create mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json create mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json diff --git a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md index 95e8f1015b..e7ca9b82cd 100644 --- a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md +++ b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md @@ -32,6 +32,8 @@ PR #37 是第一阶段 UI Contribution(插件声明的界面入口)基础设 内置模块和插件尽量实现相同领域 Provider 契约。Build/Run/Test/Debug 等采用类型化 Registry(按能力类型登记和查询实现的目录),组合根负责装配通用适配器,不按新增插件名追加分支。先盘点并复用已有语言服务器、构建工具、运行/测试和 DAP(调试适配器协议)链路;上游拥有的项目、任务和依赖事实仍由原工具提供,避免再造一套解释器、工程模型或调试 UI。 +Debug 的具体边界、现有链路盘点、声明与动态准备的分工、API 兼容性约束及分阶段验收见[调试适配器的声明式注册与统一会话模型](2026-10-25-debug-adapter-provider-and-declarative-registration.md),跟踪当前仓库的 [#1210](https://github.com/1lck/Lithe-IDEA/issues/1210)。该提案没有开放新字段,也不改变本 Note 中其他领域 Provider 的设计。 + ### 通用 Services 与资源所有权 Services 接入容器、Spring Boot、数据库和本地服务。后续统一设计 ServiceProvider/ServiceDescriptor/Instance/Status/Actions/Logs 的语义;这些名称是设计目标,当前没有公布字段全集或承诺已经实现。 diff --git a/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md b/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md new file mode 100644 index 0000000000..55bce9b369 --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md @@ -0,0 +1,235 @@ +# Agent 笔记:调试适配器的声明式注册与统一会话模型 + +状态:提议中 + +## 先说结论 + +针对 [DebugAdapter Registry 与第三方 DAP 接入 #1210](https://github.com/1lck/Lithe-IDEA/issues/1210),以插件好写和逻辑复用为优先:JSON 声明依赖、导出、能力、后端入口与流程组合,公共插件可以继续依赖其他插件;动态计算复用插件函数调用,并通过类型化领域契约校验结果。宿主承担通用解释与适配复杂度,允许为此迭代 API。内置与第三方适配器进入同一个类型化 Registry(按能力登记和查询实现的目录),共用现有调试窗口和 DAP(Debug Adapter Protocol,编辑器与调试后端之间的标准协议)内核。 + +统一的是会话、操作和生命周期,不要求所有后端具备相同的功能;语言专属参数与扩展能力继续由对应后端解释。本提案没有开放任何新字段,也不改变现有插件、运行配置、构建接口或调试命令;下面的概念名须在实现时与契约、校验器和标准用例一起确定。 + +可讨论的 [JSON Schema 与示例](../../../../shared/proposals/debug-adapters-1210/README.md)单独放在 `shared/proposals/`,包含依赖与导出、JSON 组合、能力声明及有效状态、解析后的配置与启动方案。它们没有进入正式插件契约;保留现有进程启动定义的引用,解释器等运行时优先从依赖插件取得。 + +## 问题 + +### 当前实现与应当复用的部分 + +以下盘点基于 `preview` 提交 `e854cfd98e4a52fe5abacff2002efd9f68082da2`。它描述源码入口,不代表所有语言或两端都已完成运行时验收。 + +| 入口 | 已有责任 | 本次应如何使用 | +| --- | --- | --- | +| `rust/lithe-core/src/debug/` | DAP 分帧、请求关联、状态转换、断点、变量分页、取消、反向终端请求、Java 热替换 | 扩展已有内核,不再写第三套协议状态机 | +| `macos/Sources/LitheCoreContracts/Debug/` | 平台无关的会话、传输、启动参数、调试操作模型 | 公共模型的兼容入口,新增身份不能改写既有字段含义 | +| `macos/Sources/LitheDebugModule/Runtime/DebugAdapterSessionManager.swift` | 多会话、激活代次、事件、断点与停止 | 演进为从 Registry 选择目标,保留旧入口的兼容适配 | +| `macos/Sources/Lithe/Services/Debug/DebugAdapterRuntimeFactory.swift` 与 `MacServiceContainer.swift` | stdio 适配器,以及 Java、Go、Node 的专用构造 | 将语言字典逐步替换成 Provider 注册;平台进程和连接能力继续留在平台层 | +| `macos/Sources/Lithe/Services/Debug/DebugLaunchConfigurationResolver.swift` 与 `DebugLaunchPreparationCoordinator.swift` | 按语言准备启动参数、保存与 Java 启动目标解析 | 将策略放进对应 Provider,复用 Run 的准备流程与运行时选择 | +| `windows/tauri/src/features/debugger/` 与 `windows/tauri/src-tauri/src/debug.rs` | 调试界面、事件投影、进程与 TCP 传输、Rust Core 调用、资源释放 | 独立实现同一契约,保留已有调用信封和断点先于 launch 入队的顺序 | +| `shared/contracts/plugins/v1/` 与两端插件宿主 | 能力版本、安装审查、工具链与进程启动、插件禁用 | 增加独立 Debug 能力,不借语言或 UI 声明取得注册资格 | + +macOS 的通用工厂和 Go、Node 目前使用 Swift `DebugAdapterProtocolSession`,Java 使用 `CoreDebugAdapterProtocolSession`。迁移不能直接删掉前者:它已有子会话处理,Rust 路径需先覆盖对应行为和反向请求,再逐个切换。 + +### 已有工具与缺口 + +| 目标 | 可复用的上游 | 当前版本或分发状态 | 接入前必须确认 | +| --- | --- | --- | --- | +| Java | JDT LS 与 Microsoft Java Debug Server | `third_party/jdtls/manifest.json` 固定 JDT LS 1.61.0、Java Debug Server 0.53.2;插件包提供资源 | 保留 JDT 工程事实、Java 测试与热替换,继续使用 Run 为同一目标选择的 JDK | +| Python | `debugpy` | 现有入口为 Python 执行 `-m debugpy.adapter`,没有统一锁定适配器版本 | 解释器、虚拟环境与适配器可用性;不在启动时静默安装依赖 | +| JavaScript / TypeScript | Microsoft `vscode-js-debug` standalone DAP server | 已有 Node TCP transport 与本地发现入口,没有统一锁定后端版本 | source map、`startDebugging` 子会话、终端与版本兼容范围;复用可独立使用的开源 server | +| Go | Delve DAP | 已有 `dlv` 发现和服务端 transport | 保留端口发现、取消和进程树回收行为 | +| C / C++ / Rust / 汇编 | `lldb-dap`,以及具备 DAP 支持的 GDB | Rust 已有 LLDB 发现和启动入口;其他目标与 GDB 不据此宣称可用 | 目标平台和架构、调试符号、DAP 构建能力、许可证、寄存器与反汇编支持 | + +GCC 是编译器。Debug 应消费构建系统返回的可执行产物和符号,不把 GCC 当作调试适配器,也不按固定输出目录猜测程序路径。LLDB/GDB 可以服务多种语言,同一种语言也可以选择不同调试后端。 + +以上适配器的升级或启用应先于自研替代方案。新增打包资源前,必须固定来源、版本、哈希和许可证;用户工具链的版本则通过既有发现机制取得并核对兼容范围。本提案不新增下载入口、缓存或第三方依赖。 + +## 提案 + +### 1. 保留三条接口边界 + +| 边界 | 提供什么 | 不承担什么 | +| --- | --- | --- | +| 声明式注册与组合 | 稳定身份、依赖导出、能力策略、配置 schema、函数绑定与步骤组合 | 复制上游工程模型,凭静态布尔值断言某次会话必然可用 | +| 动态准备 | 复用依赖插件和函数,读取上游目标与工具链,引用现有构建动作,产生可校验的启动方案 | 各自重写公共启动、调用、取消、连接与清理机制 | +| 调试会话 | 执行 DAP,投影线程、栈和变量,管理取消、终端与停止 | 重新推算 Java classpath、构建产物或 source map | + +简单适配器和复杂适配器共用 `use` / `with` 调用及 `steps` 组合。实现来源可以是依赖插件导出、本包插件函数或通用宿主原语;返回同一种类型化结果。公共插件封装 stdio、TCP 端口发现、工程准备等流程,语言插件主要选择依赖与提供参数,不要求每个插件启动新的解析服务。复杂计算复用现有 `lithe/function/invoke`,不另建 `lithe/debug/*` 传输,也不强制纯 Debug 插件声明网页。 + +目前[插件函数契约](../../implemented/architecture/2026-10-20-plugin-function-contract.md)把函数限定为私有动作,领域结果走独立类型化方法。本提案在新的能力版本中增加显式导出和领域绑定:传输复用现有函数通道,Core 仍拥有领域计划和结果解码。依赖调用由宿主检查导出、契约、调用方和资源授权,再在被调用插件自己的会话上执行;旧私有函数及 `wrongPlugin` 规则不变。JDT 原始服务不被假定实现插件函数,由已有宿主集成适配同一调用模型。 + +依赖可以递归组合,但依赖图与导出调用图必须无环。流程由宿主驱动,步骤取消传递到本次子调用;等待中的后端处理器不再回调宿主调度自己。包版本限制与导出契约版本分别校验,依赖失效或导出撤回使关联计划立即失效。通用依赖、导出和流程机制应进入统一插件层,不在 Debug 内维护第二套插件管理器。 + +JSON 流程可以组合工具、前置动作、函数结果与连接资源;最终启动方案只含宿主理解的引用、参数和连接方式。前置动作走既有 Build/Run 调度,明确区分准备前输入与准备后结果,复用现有 Java 编译失败后的继续/取消决策。需要重新编译时,必须完成该决策后再次向事实拥有者取得目标,不能执行构建前缓存的产物或 classpath。先提供有界顺序组合和类型化取值,后续按实际插件需要迭代声明能力。 + +### 2. 分开 Provider、语言、配置类型和会话身份 + +Provider 的身份由插件身份与包内局部身份组合,不能覆盖宿主或另一个插件的条目。DAP `adapterID`、导入配置的 `type`、语言 ID、运行配置 ID 与会话 ID 各自保留自己的含义;兼容映射显式登记,不能从可执行文件名推导后端身份。 + +Registry 的发现阶段只读已验证的声明,不执行工作区程序。Provider 可匹配语言、运行目标、构建产物或用户明确选择的 attach 目标;文件扩展名只是一种条件。调试二进制、连接 JVM 或启动浏览器不需要伪造源文件,也不要求安装一个同名语言插件。 + +选择顺序为:配置显式选择、工作区已保存关联、平台及目标匹配后的唯一候选。多个同等候选由用户选择;列表按稳定身份排序,插件不能通过自报高优先级抢占内置实现。重复身份拒绝注册;匹配重叠不等于身份冲突。明确选择的 Provider 不可用时报告原因,不静默换后端。 + +注册记录绑定插件版本与启用代次。重新解析、更新或禁用会让旧记录失效;已解析但尚未执行的启动方案也必须再次检查,而不是拿着旧句柄启动程序。 + +### 3. 配置保持公共外层与后端参数分离 + +公共外层表达名称、Provider 引用、`launch` 或 `attach`、目标和配置来源;后端参数由其版本化 schema 校验。已有 `DebugLaunchConfiguration` 的 `name`、`request`、`arguments`、`steppingFilters` 含义不变,由适配层产生它;不把所有语言的字段塞进同一个必填结构体。 + +原有运行配置 ID、三层配置覆盖规则、导入的 `launch.json` 字段及参数优先级必须保留。尤其不能在合并时用缺失的公共 `program` 或 `args` 覆盖后端已给出的值。未知配置类型继续保留原文并显示不可用原因,不能自动改写成当前默认 Provider。 + +Java 主类、模块路径和 classpath 来自 JDT;Python 解释器来自已选择的运行环境;C/C++ 与 Rust 产物来自 Build/Run 的结果。Debug 不维护另一份项目模型,也不增加独立的 JDK 选择链。 + +### 4. 公共会话支持能力差异与无源码位置 + +能力进入 JSON:`source: dap` 绑定标准协议,`source: function` 绑定同一种依赖/函数组合,`source: disabled` 明确关闭。前者由 DAP 初始化及后续 `capabilities` 事件确认,后者由导出契约、函数注册与宿主适配确认;两者都经过权限及目标检查。有效能力以 JSON 返回,UI 区分尚未确定、已支持和不支持及原因。配置 schema 只校验参数,`requires` 仍只判断宿主契约版本,不把它当作能力支持证据。 + +沿用已有会话、线程、栈帧、scope(变量分组)、变量和断点模型。原生调试扩展需补充会话内源码引用、指令位置、内存引用、指令断点、指令级单步、反汇编和内存读取;寄存器优先使用后端提供的 scope,不设计一个假定所有 CPU 都相同的寄存器列表。 + +无源码的栈帧不伪造源文件或行号,缺失位置按新模型显式表达。不能把既有必填数字字段直接改成 `null` 后要求旧消费者自动兼容;新增投影或版本化后,同时更新 Rust、Swift、TypeScript 与 fixtures(跨实现共用的标准输入和预期结果)。地址、内存引用与指令引用保持字符串,避免 JavaScript 数值精度损失;后端引用均为不透明值,不当作文件路径。 + +工作区源码的可持久化身份仍用相对路径;外部或远端源码通过有明确权限的映射或会话内引用取得,平台进程与 DAP 边界需要的绝对路径不变成跨工作区身份。变量引用和栈帧绑定会话及暂停代次,继续执行、重启或切换目标后不能复用。 + +Java 热替换等扩展保持已有调用与错误语义,通过 JSON 绑定版本化导出及函数。标准功能也允许使用函数适配,但其输入输出必须满足对应的公共操作契约;宿主未实现该适配时明确报告不支持。普通 UI 按有效能力显示操作,不按插件名称扩充组合根,不绕过会话校验。 + +### 5. 版本演进不能改变其他 API 的承诺 + +[插件能力版本规则](../../implemented/architecture/2026-10-17-plugin-capability-versions.md)规定基础字段只随 `pluginAPIVersion` 演进,其中包括 `permissions` 和 `activationEvents`。因此前期讨论中的 `requires.debugAdapters: 1` 只是能力名草案,不能单凭它在 API 3 中加入新的顶层权限或激活事件。 + +用户明确接受为了插件易写、依赖复用而增加通用适配器复杂度和 API 版本。本提案为独立 Debug 能力、依赖与导出、领域函数绑定及新授权分配相应版本,具体编号在实现时确定。调试授权覆盖读取与修改目标状态,不把已有 `process.run` 或 `languageServer.launch` 静默扩大为 attach、写内存权限。只有使用新特性的包升级;现有语言、Build、VCS、网页、设置和后端包继续使用原版本。 + +激活默认来自用户的启动或 attach 请求和 Registry 选择,无需为了“看起来一致”给所有旧包增加激活事件。若实现确实需要专用事件,其语法同样放进新 API 级别,不能让 API 1/2/3 接受过去会拒绝的输入。权限不是操作系统沙箱:原生调试程序的进程权限仍受平台和用户授权限制,安装审查必须准确说明它可访问调试目标。 + +兼容性必须逐项核对: + +| 现有表面 | 必须保留的行为 | +| --- | --- | +| 插件 API 1/2/3 | 旧字段、缺省值、拒绝条件、错误优先级、规范化结果和支持范围;新字段不能被旧级别偷偷接受 | +| `requires` 与 `hostCapabilities` | 能校验不代表能运行;市场筛选、磁盘安装、启动扫描与运行前检查使用同一能力表 | +| `serverProcess: 1` | 只复用已有启动语义;DAP 的 TCP 发现或新启动形式放进 Debug 能力或明确的新进程能力版本 | +| Build/Run/Test 与语言服务 | 既有命令、选项来源、配置 ID、JDK 选择与工程事实不因 Registry 改变 | +| `debug.*`、JSON 信封与 C ABI | 保留原命令、载荷和错误语义;新增操作不能重解释旧枚举或破坏穷举解码器 | +| macOS 内置模块与 Windows Worker 插件 | 既有装配和包格式继续存在;Debug 声明式接入不要求迁移无关插件 | +| 插件后端 SDK | 复用现有函数、取消、进度及进程机制;依赖导出和领域绑定显式版本化,不强制 UI;协议扩展做 SDK 端到端验证 | + +### 6. 生命周期由宿主执行,资源所有权显式记录 + +每次准备与操作沿用 `operationID`、取消、超时和失效结果规则,并绑定工作区、Provider 注册代次及会话。启动准备、连接和交互请求分别设有界期限;不能给整个调试会话设总时长,也不能把已有 JDT 工程导入等待缩成普通交互请求的期限。 + +宿主在创建进程或连接前最后检查启用状态与信任;如果禁用与启动交错,已创建的资源立即进入同一清理链路。重复 Stop 共享同一个清理完成结果,完成前不报告资源已释放;晚到端口、子会话、终端或操作结果必须拒绝并清理。 + +必须区分 adapter 进程、被调试程序、终端、共享语言服务器和外部目标。`launch` 沿用已有终止所拥有程序的策略,`attach` 默认只断开;结束 Java 调试只释放调试连接及本次资源,不终止共享 JDT LS。插件禁用时清理自身会话,不通过名称或可执行路径批量结束用户独立启动的程序。 + +`runInTerminal` 继续由 Core 规范化、平台 PTY/ConPTY 创建终端;子会话走同一个管理器,明确父子关系和停止规则。只有两端相应宿主确实实现了反向请求,才在 DAP 初始化中声明支持。 + +插件包与安装目录均只读。解析过程产出的日志、锁、缓存和临时文件由平台存储 adapter 分配,按插件、工作区与会话隔离;会话内引用不跨 worktree 共享。新增下载或生成资源时,同步维护 `scripts/worktree-resources.json`、资源复用脚本校验路由、对应验证和 `docs/ci-builds.md`,并核对代码签名与 Sparkle 增量更新基线。 + +### 7. 分阶段替换,阶段之间保留回退能力 + +| 阶段 | 工作与退出条件 | 兼容性检查 | +| --- | --- | --- | +| P0:行为基线与契约评审 | 列出内置适配器完整启动、断点、变量、终端、子会话和停止序列;确定 Debug 权限及版本方案 | 记录旧输入的接受、拒绝和归一化结果;未完成评审不提前开放新能力 | +| P1:内部 Registry | 内置 Provider 进入类型化目录;通用目标入口与文件兼容入口共存;新增一种适配器不修改语言分支 | 原有 Provider ID 映射、Run 配置、断点与多会话行为通过原回归;两端消费相同选择 fixtures | +| P2:新能力契约 | schema、Core 校验与计划、依赖导出、JSON 组合、能力及函数绑定、安装审查与纯 Debug fixture 同批设计;分步实现真实流程 | 旧 API 与私有函数 fixture 不变;循环依赖、错误导出、撤回与不支持版本准确拒绝;宿主按实现公布能力 | +| P3:第三方纵向流程 | macOS 的纯 Debug 插件进入现有 UI,完成启动或 attach、断点、线程、栈、变量和停止;Windows 独立实现同一契约 | 完成禁用竞态、失败隔离、取消、晚到事件、恢复、安装目录哈希不变;双端各自提供证据 | +| P4:内置链路迁移 | Python、Java、Go、Node、Rust 逐个迁到 Registry 和现有 Rust DAP Core;先补齐被替代路径的能力 | Java Run JDK、JUnit/TestNG、热替换、Node 子会话与 source map、终端和停止均有实际回归;同一目标只启用一个实现 | +| P5:原生与汇编扩展 | 按 DAP 扩充无源码位置、反汇编、内存、指令断点与指令单步,接入经验证的 LLDB/GDB 组合 | 有符号源码调试与无源码指令调试分别验收;不把此阶段当作 #1210 基础 Registry 关闭的前提 | + +P1 至 P4 的每个行为改动都维护功能矩阵;某平台只有模型或源码时,运行验证保持 `pending`,不能根据另一端通过就标记完成。只有新入口行为与旧入口等价、所有消费者已迁移,才删除兼容包装;不能为切换方便先移除现有功能。 + +### 正确做法 + +- Python 插件依赖运行时插件取得同 Run 的解释器,再依赖公共 DAP 插件完成 stdio 启动;主要写 JSON,断点、变量与停止进入现有链路。 +- Java 公共插件用 JSON 继续依赖工程插件,把准备结果传给已有 JDT 适配函数;其他 Java 插件直接引用其调试导出。 +- Java Provider 调用既有保存、工程同步和编译流程,向 JDT 读取当前目标,再使用 Run 已选择的 JDK;调试结束释放连接,不结束语言服务器。 +- 一个原生 Provider 同时匹配 C、C++、Rust 和汇编目标,用户明确选择 LLDB 或 GDB;没有源码的暂停显示指令位置,不创建假的文件。 + +### 不要这样做 + +- 为每个语言插件重复实现端口、资源、取消和工程准备;为了宿主简单,强迫每个插件实现本可共享的后端。 +- 把旧私有函数全部开放为跨插件调用,或用任意函数返回值绕过领域结果校验。 +- 为纯 Debug 插件声明空语言或空工具窗口,或为了使用现有网页后端而强制生成网页。 +- 注册每个插件时都给 `MacServiceContainer`、Windows 前端或 Rust dispatcher 添加插件名称判断。 +- 把 `requires` 当权限,将 `process.run` 扩大为任意调试授权,或者在 API 3 下无版本地新增基础字段。 +- 仅让新模型跑通一个模拟会话,就删除 Java 测试、热替换、子会话或旧平台清理逻辑。 + +## 考虑过的备选方案 + +### JSON 组合与依赖优先 + +采用此方向。用户希望尽量把逻辑留在 JSON,允许宿主复杂和版本增加换取插件易写。公共流程和工程动作可以通过依赖、导出与步骤复用;真正需要计算时调用函数,结果经过同一个领域解码器。代价是宿主要实现版本化组合器、图检查和调用上下文,而不是把这部分成本转给每个插件作者。 + +### 所有插件都实现可编程 Provider + +表达力完整,也能覆盖 Java 和浏览器。没有作为默认入口,因为普通插件应能直接引用已有 JSON 流程和公共导出;不应为了启动 DAP 再写第二个服务。函数是统一组合模型中的实现来源,不是另一套必写协议。 + +### 直接复用语言字符串工厂作为公共 API + +迁移量最小。但无法表达一种后端支持多语言、一种语言有多个后端,也不能自然接入无源码目标或纯 Debug 插件。保留为迁移包装,不作为最终契约。 + +### 在 API 3 下只增加能力名,同时新增调试权限 + +看似只影响 Debug,但违反基础字段的版本规则。新能力可以独立演进,新增基础授权仍需要新的 API 级别;其他包继续使用原级别,避免要求整个生态升级。 + +### 为每个语言另做一套调试 UI 或改用统一自研调试引擎 + +短期可以绕过差异,但会复制已有 DAP 功能,或承担 Python、JVM、浏览器与原生代码的调试语义。复用成熟后端与现有窗口,通过协商表达差异。 + +## 验收标准 + +- 无语言、无 UI 的 Debug 插件可以在支持对应契约的宿主安装并登记;不支持的宿主在安装和市场阶段拒绝,Core 校验成功不能绕过宿主能力检查。 +- 内置与第三方 Provider 使用同一 Registry;覆盖明确选择、工作区关联、重叠候选、重复身份、不可用工具链与禁用 Provider,不按插件名特判。 +- 覆盖插件依赖的二级组合、公共流程复用、显式函数导出与领域结果校验;拒绝循环、版本不兼容、未导出和错误资源归属,私有函数仍保持旧拒绝语义。 +- 至少一个真实第三方 DAP 完成从安装、选择目标、命中断点到线程、栈、变量和停止的完整流程;`launch` 与 `attach` 分别验证目标进程是否保留。 +- 在解析、构建、连接和终端创建的每个等待点禁用或取消,都不留下 adapter、debuggee、监听或晚到子会话;另一个会话和共享语言服务继续可用。 +- API 1/2/3、现有运行配置、Build/VCS/语言/UI/设置能力以及 JSON 调试信封的兼容 fixture 保持原结果;旧包无须增加 Debug 字段或更换 API 级别。 +- macOS 与 Windows 使用共享 fixtures,并各自给出真实流程证据;运行结束检查本次启动的 Lithe、调试程序及辅助进程均已清理,外部 attach 目标仍按既有策略保留。 +- P5 另行验证带符号与无源码程序、源码和指令单步、寄存器 scope、反汇编、只读内存查看与指令断点;后端不支持的功能明确显示不可用。 + +## 风险 + +- 组合器增加长期维护成本:以真实共享流程驱动版本演进,依赖和类型化函数覆盖复杂计算;不能以降低宿主成本为由把同一逻辑分散到所有插件。 +- Swift 与 Rust 路径能力不齐:先用同一输入与事件序列对照,再逐个迁移;未覆盖的适配器继续保留旧路径,不宣称完成统一内核。 +- 动态计划与权限脱节:安装审查、运行前检查及实际执行要验证同一个插件版本、获准程序和权限;不能信任 Provider 返回的任意命令或端点。 +- 版本方案与其他并行 API 工作冲突:实现前重新核对基础版本和能力表,只分配下一可用版本;本提案不预占正式版本号,不放宽其他能力校验。 +- 后端和平台支持不等价:GDB 的 DAP 构建能力、系统调试权限和架构必须实测;不能承诺一个模型让所有后端具备完全相同的行为。 +- 移除旧入口过早:保留按 Provider 控制的迁移开关,同一目标不双启动;回退不改用户配置、不重新绑定断点、不退回错误运行时。 + +## 验证 + +本提案阶段修改架构记录和独立评审 schema,使用本机已有的 Python `jsonschema` 离线检查 Draft 2020-12 schema、示例、参数与关键拒绝条件,再运行 `./scripts/verify-agent-notes.sh`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-runtime-bundle-immutability.sh` 和 `git diff --check`。这些检查不构成新增 Debug 功能或平台运行证据。 + +实现阶段按改动范围运行: + +- 契约与 Rust:`./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core-comments.sh`、`./scripts/verify-rust-core.sh`,以及所属插件和调试用例。 +- macOS:受影响调试、Run 配置、Java 测试与资源清理回归,通过 `./scripts/test-macos.sh` 和 `./scripts/verify-service-boundaries.sh` 验证边界。 +- Windows:`./scripts/verify-windows-boundaries.sh`;在 Windows 执行 `./scripts/build-windows.ps1 -Configuration Release`、宿主 Rust 测试及受影响前端回归,再运行真实 Debug 流程。 +- 测试实现:加载 `write-stable-tests` Skill,使用对应单测试计时 harness,所有等待有界、测试资源独立、退出清理可观测。 +- 功能与资源:`./scripts/verify-platform-feature-matrix-change.sh origin/preview HEAD`、`./scripts/verify-platform-feature-matrix.sh`、`./scripts/verify-runtime-bundle-immutability.sh`,并比较真实工作流前后的安装目录文件清单与哈希。 + +正式契约仍在主仓库与 Core 同批修改,合并后按[插件契约发布规则](../../implemented/architecture/2026-10-23-plugin-contract-publishing.md)同步到 `lithe-plugin-docs`;面向插件作者的指南写在该仓库。如果动态解析需要扩展插件后端协议,合并前在该仓库运行两个官方 SDK 的端到端验证,不能只靠主仓库测试。 + +## 适用范围 + +- `rust/lithe-core/src/debug/` +- `rust/lithe-core/src/plugins/` +- `shared/contracts/plugins/v1/` +- `shared/proposals/debug-adapters-1210/` +- `shared/contracts/application-boundary.md` +- `shared/contracts/rust-core-api.md` +- `shared/fixtures/debug/` +- `shared/platform-feature-matrix/features/` +- `macos/Sources/LitheCoreContracts/Debug/` +- `macos/Sources/LitheDebugModule/` +- `macos/Sources/Lithe/Services/Debug/` +- `macos/Sources/Lithe/Platform/MacOS/Debug/` +- `macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift` +- `windows/tauri/src/features/debugger/` +- `windows/tauri/src-tauri/src/debug.rs` +- `windows/tauri/src-tauri/src/plugin_host/` + +## 依据 + +- [公共扩展契约方向](2026-10-13-public-extension-contract-and-provider-api.md)、[构建 Provider 提案](2026-10-17-build-system-provider-api.md)。 +- [Java 构建与启动边界](../../implemented/architecture/2026-09-18-java-project-build-and-launch-boundary.md)、[Java Debug 与 Run 的 JDK](../../implemented/bug-fix/2026-10-14-java-debug-uses-the-run-jdk.md)。 +- [Windows Java 调试生命周期](../../implemented/bug-fix/2026-10-07-windows-java-debug-lifecycle.md)、[断点路径身份](../../implemented/bug-fix/2026-10-07-windows-debug-breakpoint-path-identity.md)、[Windows 声明式宿主](../../implemented/architecture/2026-10-22-windows-declarative-plugin-host.md)。 +- [DAP 标准](https://microsoft.github.io/debug-adapter-protocol/overview)、[DAP 协议定义](https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json)。 +- [debugpy](https://github.com/microsoft/debugpy)、[Java Debug Server](https://github.com/microsoft/java-debug)、[JavaScript standalone server](https://github.com/microsoft/vscode-js-debug)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)。 diff --git a/shared/proposals/debug-adapters-1210/README.md b/shared/proposals/debug-adapters-1210/README.md new file mode 100644 index 0000000000..a16c2d0a15 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/README.md @@ -0,0 +1,142 @@ +# Debug JSON 组合评审草案(#1210) + +设计目标:**普通插件尽量只写 JSON,通过依赖插件复用运行时、工程准备、适配器启动和调试能力;宿主承担通用解释与适配的复杂度。** 动态部分使用现有插件函数调用,输入输出继续由版本化领域 schema 校验。这版将能力声明、依赖、动态函数与流程组合放进同一种 JSON 模型。 + +这是 `feat/1210-debug-adapter-provider` 上的设计文件,当前宿主尚不接受。`draftVersion: "1210-3"` 是评审编号;`lithe.invalid` 只用于离线引用。没有修改现有插件契约、函数协议、产品 API 或运行逻辑。 + +## 插件作者主要写什么 + +完整例子:[Python](examples/python.registration.json)、[Java](examples/java.registration.json)、[JS/TS](examples/node.registration.json)、[C/C++/Rust/汇编](examples/native.registration.json)。 + +```json +{ + "pluginDependencies": { + "java": { + "pluginID": "example.java-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "session": { + "use": { "dependency": "java", "export": "debugSession", "contractVersion": 1 }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "configuration": { "$value": "/input/configuration" } + } + }, + "capabilities": { + "sourceBreakpoints": { "source": "dap" }, + "hotCodeReplace": { + "source": "function", + "invoke": { + "use": { "dependency": "java", "export": "hotCodeReplace", "contractVersion": 1 }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "sessionID": { "$value": "/input/sessionID" } + } + } + } + } +} +``` + +上面为节选:依赖是包级字段,`session` 和 `capabilities` 属于适配器。Java 插件不需要再次实现 JDT 准备和热替换。Python 同样依赖运行时插件取得 Run 使用的解释器,再依赖公共 DAP 插件启动 stdio;JS/TS 复用公共 TCP 启动流程。GCC 产生的程序由 LLDB 或支持 DAP 的 GDB 调试,原生 Provider 可同时服务多语言及无源码目标。 + +## 依赖可以继续依赖其他插件 + +```text +Python Debug → Python Runtime(解释器) + DAP Runtime(stdio 会话) +JS/TS Debug → Node Runtime(运行时) + DAP Runtime(动态 TCP 会话) +Java Debug → Java Runtime → Java Project Runtime(工程准备) + → 既有 JDT 集成 +``` + +公共插件也主要写 JSON。见 [DAP 公共流程](examples/dap-runtime.library.json)和 [Java 二级依赖组合](examples/java-runtime.library.json)。例子里的 `example.*` 包及部分导出仅用于展示目标结构,不代表这些依赖已发布。Java Project、Python Runtime、Node Runtime 的具体包清单不在本次 Debug 草案中定义。 + +每个导出有稳定名称和版本化契约。依赖方调用导出,不复制依赖包的路径或后端实现。包版本约束解决安装哪一版;`contractVersion` 解决本次调用使用哪种输入输出。`pluginDependencies` 与现有 `requires` 分开:前者指依赖的插件,后者仍指宿主 API 能力。最终应使用统一插件依赖管理,不保留 Debug 特有的第二套依赖管理器。 + +## 一种调用结构,三种实现来源 + +所有调用都写成 `{ "use": ..., "with": ... }`: + +| use 的形式 | 谁提供实现 | 示例 | +| --- | --- | --- | +| `{dependency, export, contractVersion}` | 依赖插件导出的 JSON 流程或函数 | 复用 Java 的 debugSession | +| `{backendRef, functionID}` | 本包插件函数,或已有集成的类型化桥接 | 调用 debug.resolve | +| `{host, version}` | 通用宿主原语 | 创建适配器资源、生成启动方案 | + +简单调用可以直接返回结果;需要多步时使用 `steps`,每步结果通过 `$value` 引用: + +```json +{ + "steps": [ + { + "id": "target", + "use": { "dependency": "project", "export": "prepareDebugTarget", "contractVersion": 1 }, + "with": { "configuration": { "$value": "/input/configuration" } } + }, + { + "id": "session", + "use": { "backendRef": "jdt", "functionID": "debug.resolve" }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "configuration": { "$value": "/input/configuration" }, + "target": { "$value": "/steps/target" } + } + } + ], + "result": { "$value": "/steps/session" } +} +``` + +宿主按顺序执行,`$value` 使用 JSON Pointer 读取输入、上下文和已完成步骤,保留对象/数组/整数类型。缺失值报错,`$literal` 可转义保留字段。路径转换、参数合并、资源登记等通用行为放进共享原语,插件不重复拼接命令,也不重复实现流程执行器。这版先提供直接调用和顺序组合;后续确有需要可以版本化扩充条件等声明能力,不以减少宿主解释器复杂度为由要求每个插件另写一套后端。 + +`/context/contextToken` 由宿主签发,调用需要它的领域契约时通过 `with` 显式传入。进入依赖包后,宿主为当前被调用方建立受限上下文,不能把调用方 token 当成访问依赖全部资源的凭据。导出契约校验公共输入和结果;JDT 桥接还接收工程准备的 `target`,该内部输入由其独立的类型化适配契约校验。 + +## 复用现有插件函数方案 + +动态后端仍使用现有进程启动、`litheFunctions` 协商、函数注册、`lithe/function/invoke`、进度、撤回、超时和取消机制,不新增 `lithe/debug/*` RPC。[自定义函数后端示例](examples/plugin-functions.library.json)展示普通后端如何导出调试启动能力;[调用消息示例](examples/java.function-call.json)展示复用的函数信封形状。 + +当前函数协议 v1/v2 只允许插件私有调用,现有领域结果也不经插件函数传输。本提案新增的是**导出和依赖调用的领域绑定**:宿主校验调用方依赖、被调用方导出、契约及授权,然后在拥有该函数的目标插件会话上调用现有函数通道,最后由 Core 校验领域结果。不会把调用方的 pluginID 塞进目标会话,也不会删除旧 `wrongPlugin` 拒绝条件。旧函数继续私有;只有显式导出的新契约能被依赖方使用。 + +JSON 组合由宿主驱动,不让正在等待结果的后端处理器再递归调度自己。依赖图与导出调用图检查循环;取消传播至本次子调用;共享后端不因一个调用取消而退出。函数撤回、插件更新或依赖禁用会使对应调用失效,迟到结果不得恢复旧会话。依赖不会继承调用者全部权限:需要执行资源时,只传递当前操作获准的受限引用。 + +JDT 是宿主已有集成,原始 JDT LS 不会因此被假定支持 `litheFunctions`。`hostIntegration` 把现有 JDT 操作适配到同一种类型化调用入口,不更改共享语言服务器的插件归属。新增普通第三方插件不需要在组合根增加插件名称分支。 + +## 能力也在 JSON 里 + +- `source: "dap"`:使用标准 DAP 实现,按 initialize 和后续 capabilities 事件确定支持。 +- `source: "function"`:通过同一种 invoke 组合调用已导出的函数,结果使用该操作的标准契约。 +- `source: "disabled"`:明确关闭。省略的能力不展示。 + +断点、变量修改、重启、反向单步、内存、反汇编、指令断点等都能声明。线程、调用栈、变量读取及基本执行控制继续复用公共 DAP 会话。函数实现标准操作也必须满足对应契约;某种绑定尚未由宿主实现时返回 `host_not_supported`。热替换作为已有的非标准能力给出完整绑定例子;其他函数操作的输入输出定义随实际接入扩充。 + +实际状态同样返回 JSON,区分 `unknown`、`supported`、`unsupported` 及原因。例如原生插件可以声明反汇编,但当前宿主未实现时,状态如 [native.capabilities.json](examples/native.capabilities.json),不会只凭清单点亮按钮。统一配置、可检查结果与动态确认可以同时存在。 + +## Schema 文件 + +| 文件 | 责任 | +| --- | --- | +| [注册](debug-adapter-registration.draft.schema.json) | 依赖、导出、后端、目标匹配、能力与会话实现 | +| [JSON 组合](debug-composition.draft.schema.json) | 导入、导出、函数/宿主调用、步骤及类型化取值 | +| [配置](debug-configuration.draft.schema.json) | 现有 Run 配置解析后的标准 Debug 输入 | +| [启动方案](debug-start-plan.draft.schema.json) | prepare / ready / failed 与现有 DAP 配置 | +| [函数领域绑定](debug-function-binding.draft.schema.json) | 复用函数通道的 Debug 输入输出契约 | +| [有效能力状态](debug-capability-state.draft.schema.json) | 宿主计算并投影给双端的能力状态 | + +已知契约由 Core 的版本目录提供 schema。插件自定义导出需提供成对的包内输入/结果 schema,引用只读包内资源;变更不兼容形状时升级契约版本。本目录没有替代 DAP 消息 schema,也不重新实现上游工程模型。 + +## 保持已有行为与后续实现 + +用户确认优先保证插件好写和复用能力,允许通用适配器复杂度和 API 版本增加。正式接入时为依赖/导出、领域函数绑定、新权限及宿主原语分配明确版本,旧版本语义继续保留。不是在现有 API 3 或函数 v1/v2 下悄悄接受新字段;也不预占并行开发中的具体版本号。这一阶段只改变评审设计,现有 Build/VCS/UI/设置/Run API 不变。 + +Run 三层覆盖、配置 ID、导入参数与最终 `DebugLaunchConfiguration` 保持兼容。`targetBindings` 由宿主统一把目标事实映射到参数;重复显式字段报冲突,不能覆盖。Java 的准备动作继续走既有工程/构建流程和编译失败决策,使用 Run JDK;准备后从 JDT 读取新路径,调试结束不终止共享服务。 + +通用宿主原语示例 `debug.process.acquire`、`debug.process.acquireTcp`、`debug.session.plan` 目前也只是契约方向,需在实现时定义完整参数/结果、期限及所有权。TCP 例子的 `jsDebugStandalone` 指复用现有端口发现逻辑的解码档位,不代表可以信任任意日志地址。导入配置里的 backendRef 在入口被规范化为调用方资源描述并取得租约,不能按依赖包的局部 ID 误解析。最终方案跨包传递的是宿主签发的 processRef / endpointRef,这些引用绑定当前操作。launch 终止自己拥有的目标,attach 默认断开;失败和取消清理本次资源,插件及应用包只读。 + +`java.ready.json` 中的 `${exampleHostResolved...}` 只是避免写入机器绝对路径的展示占位值,实际结果必须是宿主已解析的值;它不引入新的字符串模板语法。 + +新增下载或打包运行时的资源清单、工具链身份与复用验证,在实际新增资源时同步维护。本次没有下载资源,没有启动 Lithe 或后端进程,没有运行时跨平台验收证据。 + +离线校验覆盖 schema、正例、参数、局部引用和关键拒绝条件;依赖安装、图校验、函数授权、资源服务与两端执行器仍需实现。正式契约和 Core 同批落地,合并后同步 lithe-plugin-docs。 +架构理由见[对应 Agent Note](../../../.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md)。 diff --git a/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json new file mode 100644 index 0000000000..6b05fda40b --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json @@ -0,0 +1,296 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-adapter-registration.draft.schema.json", + "title": "Debug adapter registration review draft", + "description": "Issue 1210 review artifact. Not an installable plugin manifest or an allocated plugin API version.", + "type": "object", + "additionalProperties": false, + "required": ["draftVersion", "pluginID"], + "anyOf": [ + { "required": ["debugAdapters"] }, + { "required": ["exports"] } + ], + "properties": { + "draftVersion": { "const": "1210-3" }, + "pluginID": { "$ref": "#/$defs/id" }, + "pluginDependencies": { + "description": "Plugin package dependencies, distinct from requires (host API capabilities) and upstream project dependencies.", + "type": "object", + "propertyNames": { "$ref": "#/$defs/id" }, + "additionalProperties": { "$ref": "debug-composition.draft.schema.json#/$defs/dependency" } + }, + "exports": { + "type": "object", + "minProperties": 1, + "propertyNames": { "$ref": "debug-composition.draft.schema.json#/$defs/id" }, + "additionalProperties": { "$ref": "debug-composition.draft.schema.json#/$defs/export" } + }, + "backends": { + "description": "Same-plugin DAP or plugin-function resources. Dependencies reuse their own resources; importers never copy their paths or private handles.", + "type": "object", + "minProperties": 1, + "propertyNames": { "$ref": "#/$defs/id" }, + "additionalProperties": { "$ref": "#/$defs/backend" } + }, + "debugAdapters": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/adapter" } + } + }, + "$defs": { + "id": { "type": "string", "pattern": "^[a-z][a-z0-9._-]*$" }, + "packagePath": { + "description": "Read-only package-relative path. The host also rejects escaping symlinks and invalid platform paths.", + "type": "string", + "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" + }, + "serverProcess": { + "description": "Reuse serverProcess:1 launch semantics without its LSP initializationOptions field.", + "$ref": "../../contracts/plugins/v1/plugin-manifest.schema.json#/$defs/serverProcess", + "propertyNames": { + "enum": ["launch", "arguments", "validationArguments", "runtimeDependencies"] + }, + "unevaluatedProperties": false + }, + "debugProcess": { + "oneOf": [ + { "$ref": "#/$defs/serverProcess" }, + { + "description": "Reuse a runtime exported by a declared plugin dependency, without copying that plugin's executable paths or discovery rules.", + "type": "object", + "additionalProperties": false, + "required": ["launch", "arguments"], + "properties": { + "launch": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "use"], + "properties": { + "kind": { "const": "dependencyRuntime" }, + "use": { "$ref": "debug-composition.draft.schema.json#/$defs/import" } + } + }, + "arguments": { "type": "array", "items": { "type": "string" } } + } + } + ] + }, + "stdioTransport": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "processRef"], + "properties": { + "kind": { "const": "stdio" }, + "processRef": { + "description": "Host-issued process lease, scoped to the declaring package and current operation. Safe to pass through composed dependency calls.", + "type": "string", + "minLength": 1 + } + } + }, + "selector": { + "description": "Selectors are ORed. Fields within a selector are ANDed. No priority or executable discovery runs during matching.", + "type": "object", + "additionalProperties": false, + "required": ["targetKinds"], + "properties": { + "targetKinds": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "enum": ["file", "executable", "runTarget", "process", "connection"] } + }, + "languageIDs": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/$defs/id" } + } + } + }, + "request": { + "type": "object", + "additionalProperties": false, + "required": ["parametersSchema"], + "properties": { + "parametersSchema": { + "description": "Packaged Draft 2020-12 schema for parameters. Local package refs only; no network fetching.", + "$ref": "#/$defs/packagePath" + }, + "targetBindings": { + "description": "DAP argument name to a typed, host-resolved target value. Applied by the host after resolution for every backend kind. Conflicting arguments are rejected, never overwritten.", + "type": "object", + "minProperties": 1, + "propertyNames": { "type": "string", "minLength": 1 }, + "additionalProperties": { + "enum": ["target.path", "target.processID", "target.host", "target.port"] + } + } + } + }, + "backend": { + "oneOf": [ + { + "description": "Reuse a same-plugin language server owned by that plugin and negotiating litheFunctions. A host-owned shared server must instead stay behind its typed host-integration adapter.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "languageID"], + "properties": { + "kind": { "const": "languageServer" }, + "languageID": { "$ref": "#/$defs/id" } + } + }, + { + "description": "Reuse an existing typed host integration, such as JDT. The same-plugin language server must declare that integration.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "languageID", "integrationID"], + "properties": { + "kind": { "const": "hostIntegration" }, + "languageID": { "$ref": "#/$defs/id" }, + "integrationID": { "$ref": "#/$defs/id" } + } + }, + { + "description": "DAP or the existing plugin-function process protocol. No separate Debug RPC protocol or UI backend is required.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "protocol", "process", "lifetime"], + "properties": { + "kind": { "const": "process" }, + "protocol": { "enum": ["dap", "pluginFunctions"] }, + "process": { "$ref": "#/$defs/debugProcess" }, + "lifetime": { "enum": ["session", "workspace"] } + }, + "if": { "properties": { "protocol": { "const": "dap" } } }, + "then": { + "properties": { "lifetime": { "const": "session" } } + } + } + ] + }, + "capabilityID": { + "enum": [ + "sourceBreakpoints", "conditionalBreakpoints", "hitConditionalBreakpoints", "logPoints", + "functionBreakpoints", "dataBreakpoints", "exceptionInfo", "setVariable", "restart", + "terminate", "stepBack", "stepInTargets", "gotoTargets", "readMemory", "writeMemory", + "disassemble", "instructionBreakpoints", "instructionStepping", "hotCodeReplace" + ] + }, + "dapCapability": { + "description": "A standard operation can use DAP or a typed function binding. Host and permission checks apply to both.", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["source"], + "properties": { "source": { "enum": ["dap", "disabled"] } } + }, + { "$ref": "#/$defs/functionCapability" } + ] + }, + "functionCapability": { + "type": "object", + "additionalProperties": false, + "required": ["source", "invoke"], + "properties": { + "source": { "const": "function" }, + "invoke": { "$ref": "debug-composition.draft.schema.json#/$defs/workflow" } + } + }, + "capabilities": { + "description": "Manifest policy. Omitted features are not exposed through this registration. Basic threads, stack, scopes, variables and execution remain the common DAP session contract.", + "type": "object", + "additionalProperties": false, + "properties": { + "sourceBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "conditionalBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "hitConditionalBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "logPoints": { "$ref": "#/$defs/dapCapability" }, + "functionBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "dataBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "exceptionInfo": { "$ref": "#/$defs/dapCapability" }, + "setVariable": { "$ref": "#/$defs/dapCapability" }, + "restart": { "$ref": "#/$defs/dapCapability" }, + "terminate": { "$ref": "#/$defs/dapCapability" }, + "stepBack": { "$ref": "#/$defs/dapCapability" }, + "stepInTargets": { "$ref": "#/$defs/dapCapability" }, + "gotoTargets": { "$ref": "#/$defs/dapCapability" }, + "readMemory": { "$ref": "#/$defs/dapCapability" }, + "writeMemory": { "$ref": "#/$defs/dapCapability" }, + "disassemble": { "$ref": "#/$defs/dapCapability" }, + "instructionBreakpoints": { "$ref": "#/$defs/dapCapability" }, + "instructionStepping": { "$ref": "#/$defs/dapCapability" }, + "hotCodeReplace": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["source"], + "properties": { "source": { "const": "disabled" } } + }, + { "$ref": "#/$defs/functionCapability" } + ] + } + } + }, + "adapter": { + "type": "object", + "additionalProperties": false, + "required": ["id", "displayName", "adapterID", "selectors", "requests", "capabilities", "session"], + "properties": { + "id": { "$ref": "#/$defs/id" }, + "displayName": { "type": "string", "minLength": 1 }, + "adapterID": { + "description": "DAP initialize.adapterID. Not a language ID, executable name, or global Provider identity.", + "type": "string", + "minLength": 1 + }, + "configurationTypes": { + "description": "Import aliases, for example launch.json type. Overlap requires ordinary Provider selection, not replacement.", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } + }, + "selectors": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/selector" } + }, + "platforms": { + "description": "Adapter host constraints, not debuggee architecture or runtime DAP capabilities.", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["os", "architectures"], + "properties": { + "os": { "enum": ["macos", "windows"] }, + "architectures": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "enum": ["arm64", "x86_64"] } + } + } + } + }, + "requests": { + "description": "Presence declares an available configuration shape, not the capabilities of a live DAP session.", + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "launch": { "$ref": "#/$defs/request" }, + "attach": { "$ref": "#/$defs/request" } + } + }, + "capabilities": { "$ref": "#/$defs/capabilities" }, + "session": { "$ref": "debug-composition.draft.schema.json#/$defs/workflow" } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json new file mode 100644 index 0000000000..4fc7d787c8 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-capability-state.draft.schema.json", + "title": "Effective debug capabilities review draft", + "description": "A host-computed snapshot, never a plugin assertion. It combines manifest policy, negotiated DAP/backend capabilities, host implementation and granted permissions.", + "type": "object", + "additionalProperties": false, + "required": ["draftVersion", "sessionID", "revision", "capabilities"], + "properties": { + "draftVersion": { "const": "1210-3" }, + "sessionID": { "type": "string", "minLength": 1 }, + "revision": { + "description": "Monotonically increasing within a session. Stale snapshots and snapshots from a replaced session are ignored.", + "type": "integer", + "minimum": 1 + }, + "capabilities": { + "description": "Session snapshot. Omitted capability IDs are not exposed; they are never assumed supported. Each revision replaces the previous map.", + "type": "object", + "propertyNames": { + "$ref": "debug-adapter-registration.draft.schema.json#/$defs/capabilityID" + }, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "required": ["state", "source"], + "properties": { + "state": { "enum": ["unknown", "supported", "unsupported"] }, + "source": { "enum": ["dap", "backend", "manifest", "host", "permission", "target"] }, + "provider": { + "type": "object", + "additionalProperties": false, + "required": ["pluginID", "export"], + "properties": { + "pluginID": { "$ref": "debug-adapter-registration.draft.schema.json#/$defs/id" }, + "export": { "$ref": "debug-composition.draft.schema.json#/$defs/id" } + } + }, + "reason": { + "enum": [ + "not_negotiated", "adapter_unsupported", "backend_unsupported", "not_exposed", + "host_not_supported", "permission_denied", "not_applicable" + ] + } + }, + "allOf": [ + { + "if": { "properties": { "source": { "const": "backend" } } }, + "then": { "required": ["provider"] }, + "else": { "not": { "required": ["provider"] } } + }, + { + "if": { "properties": { "state": { "const": "supported" } } }, + "then": { + "not": { "required": ["reason"] }, + "properties": { "source": { "enum": ["dap", "backend"] } } + }, + "else": { "required": ["reason"] } + }, + { + "if": { "properties": { "state": { "const": "unknown" } } }, + "then": { + "properties": { + "source": { "enum": ["dap", "backend"] }, + "reason": { "const": "not_negotiated" } + } + } + } + ] + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json new file mode 100644 index 0000000000..d2110d89db --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json @@ -0,0 +1,161 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-composition.draft.schema.json", + "title": "Plugin dependency and JSON composition review draft", + "description": "Proposed reusable composition layer, not a change to existing private plugin-function protocol versions. All schema paths belong to their exporting package.", + "$ref": "#/$defs/workflow", + "$defs": { + "id": { "type": "string", "pattern": "^[a-z][a-zA-Z0-9._-]*$" }, + "schemaPath": { + "type": "string", + "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" + }, + "dependency": { + "type": "object", + "additionalProperties": false, + "required": ["pluginID", "minimumVersion"], + "properties": { + "pluginID": { "$ref": "#/$defs/id" }, + "minimumVersion": { "type": "string", "pattern": "^[0-9]+[.][0-9]+[.][0-9]+$" }, + "maximumVersionExclusive": { "type": "string", "pattern": "^[0-9]+[.][0-9]+[.][0-9]+$" } + } + }, + "import": { + "description": "Only a declared direct dependency's explicitly exported contract can be used. The dependency may compose its own dependencies internally.", + "type": "object", + "additionalProperties": false, + "required": ["dependency", "export", "contractVersion"], + "properties": { + "dependency": { "$ref": "#/$defs/id" }, + "export": { "$ref": "#/$defs/id" }, + "contractVersion": { "type": "integer", "minimum": 1 } + } + }, + "use": { + "oneOf": [ + { "$ref": "#/$defs/import" }, + { + "description": "A function on this package's backend, invoked through lithe/function/invoke. An export's domain contract validates its inputs and result.", + "type": "object", + "additionalProperties": false, + "required": ["backendRef", "functionID"], + "properties": { + "backendRef": { "$ref": "#/$defs/id" }, + "functionID": { + "type": "string", + "maxLength": 128, + "pattern": "^[a-z][a-zA-Z0-9]*(?:[.][a-z][a-zA-Z0-9]*)*$" + } + } + }, + { + "description": "A versioned host service used by a JSON workflow. The host, rather than a blocked backend handler, drives the workflow.", + "type": "object", + "additionalProperties": false, + "required": ["host", "version"], + "properties": { + "host": { "$ref": "#/$defs/id" }, + "version": { "type": "integer", "minimum": 1 } + } + } + ] + }, + "value": { + "description": "JSON values with typed whole-value bindings. $value is a JSON Pointer into input/context/completed steps, not an expression or string interpolation. $literal escapes reserved objects.", + "oneOf": [ + { "type": ["null", "boolean", "number", "string"] }, + { "type": "array", "items": { "$ref": "#/$defs/value" } }, + { + "type": "object", + "additionalProperties": false, + "required": ["$value"], + "properties": { + "$value": { + "type": "string", + "pattern": "^/(?:input|context|steps)(?:/(?:[^~/]|~[01])*)*$" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["$literal"], + "properties": { "$literal": true } + }, + { + "type": "object", + "propertyNames": { "not": { "enum": ["$value", "$literal"] } }, + "additionalProperties": { "$ref": "#/$defs/value" } + } + ] + }, + "arguments": { + "type": "object", + "propertyNames": { "not": { "enum": ["$value", "$literal"] } }, + "additionalProperties": { "$ref": "#/$defs/value" } + }, + "call": { + "type": "object", + "additionalProperties": false, + "required": ["use"], + "properties": { + "use": { "$ref": "#/$defs/use" }, + "with": { "$ref": "#/$defs/arguments" } + } + }, + "workflow": { + "oneOf": [ + { "$ref": "#/$defs/call" }, + { + "description": "Bounded, sequential composition. A step may read only input/context and earlier results. A failure stops the flow and triggers owned-resource cleanup.", + "type": "object", + "additionalProperties": false, + "required": ["steps", "result"], + "properties": { + "steps": { + "type": "array", + "minItems": 1, + "maxItems": 64, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["id", "use"], + "properties": { + "id": { "$ref": "#/$defs/id" }, + "use": { "$ref": "#/$defs/use" }, + "with": { "$ref": "#/$defs/arguments" } + } + } + }, + "result": { "$ref": "#/$defs/value" } + } + } + ] + }, + "export": { + "description": "Public, typed dependency surface. This does not publish a plugin's private runtime function registry.", + "type": "object", + "additionalProperties": false, + "required": ["contract", "implementation"], + "properties": { + "contract": { + "description": "Known contracts resolve through Core's versioned catalog. Custom IDs must supply both packaged schemas; changing either schema incompatibly requires a contract version change.", + "type": "object", + "additionalProperties": false, + "required": ["id", "version"], + "properties": { + "id": { "$ref": "#/$defs/id" }, + "version": { "type": "integer", "minimum": 1 }, + "inputSchema": { "$ref": "#/$defs/schemaPath" }, + "resultSchema": { "$ref": "#/$defs/schemaPath" } + }, + "dependentRequired": { + "inputSchema": ["resultSchema"], + "resultSchema": ["inputSchema"] + } + }, + "implementation": { "$ref": "#/$defs/workflow" } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json new file mode 100644 index 0000000000..10db9d29f1 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-configuration.draft.schema.json", + "title": "Debug configuration review draft", + "description": "Normalized input after existing Run configuration resolution. This is not a replacement workspace file format.", + "type": "object", + "additionalProperties": false, + "required": ["draftVersion", "id", "name", "request", "target", "parameters"], + "properties": { + "draftVersion": { "const": "1210-3" }, + "id": { "$ref": "#/$defs/reference" }, + "name": { "type": "string", "minLength": 1 }, + "provider": { + "type": "object", + "additionalProperties": false, + "required": ["pluginID", "id"], + "properties": { + "pluginID": { "$ref": "#/$defs/reference" }, + "id": { "$ref": "#/$defs/reference" } + } + }, + "request": { "enum": ["launch", "attach"] }, + "target": { "$ref": "#/$defs/target" }, + "parameters": { + "description": "Validated against the selected Provider's packaged request schema. Unknown upstream fields are preserved by import, not silently discarded.", + "type": "object" + }, + "steppingFilters": { "$ref": "#/$defs/steppingFilters" } + }, + "$defs": { + "reference": { "type": "string", "minLength": 1 }, + "workspacePath": { + "description": "Workspace-relative identity. Native conversion, symlink checks and external-resource authorization belong to the host.", + "type": "string", + "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" + }, + "target": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["kind", "path"], + "properties": { + "kind": { "enum": ["file", "executable"] }, + "path": { "$ref": "#/$defs/workspacePath" }, + "languageID": { "$ref": "#/$defs/reference" } + } + }, + { + "description": "Existing Run identity, including upstream-owned build products and project targets.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "configurationID"], + "properties": { + "kind": { "const": "runTarget" }, + "configurationID": { "$ref": "#/$defs/reference" }, + "languageID": { "$ref": "#/$defs/reference" } + } + }, + { + "description": "Host-issued process reference, valid only in the captured workspace/operation. Never persisted or inferred from a process name.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "processRef"], + "properties": { + "kind": { "const": "process" }, + "processRef": { "$ref": "#/$defs/reference" }, + "languageID": { "$ref": "#/$defs/reference" } + } + }, + { + "description": "Host-authorized debuggee connection, distinct from the DAP adapter transport. Transient; contains no credentials.", + "type": "object", + "additionalProperties": false, + "required": ["kind", "connectionRef"], + "properties": { + "kind": { "const": "connection" }, + "connectionRef": { "$ref": "#/$defs/reference" }, + "languageID": { "$ref": "#/$defs/reference" } + } + } + ] + }, + "steppingFilters": { + "description": "Existing DebugSteppingFilters fields and omission semantics are retained.", + "type": "object", + "additionalProperties": false, + "properties": { + "classNameFilters": { "type": "array", "items": { "type": "string" } }, + "skipSynthetics": { "type": "boolean" }, + "skipStaticInitializers": { "type": "boolean" }, + "skipConstructors": { "type": "boolean" }, + "hideFilteredStackFrames": { "type": "boolean" } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json new file mode 100644 index 0000000000..b938832116 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-function-binding.draft.schema.json", + "title": "Debug contracts on the existing plugin-function transport review draft", + "description": "Versioned domain payloads bound by exports and decoded by Core. Reuses lithe/function/invoke, never a new Debug RPC transport. Dependency routing is a proposed host feature; private function protocol versions 1/2 remain unchanged.", + "$defs": { + "resolveInput": { + "type": "object", + "additionalProperties": false, + "required": ["contextToken", "configuration"], + "properties": { + "contextToken": { "type": "string", "minLength": 1 }, + "configuration": { "$ref": "debug-configuration.draft.schema.json" } + } + }, + "resolveResult": { "$ref": "debug-start-plan.draft.schema.json" }, + "hotCodeReplaceInput": { + "type": "object", + "additionalProperties": false, + "required": ["contextToken", "sessionID"], + "properties": { + "contextToken": { "type": "string", "minLength": 1 }, + "sessionID": { "type": "string", "minLength": 1 } + } + }, + "hotCodeReplaceResult": { + "type": "object", + "additionalProperties": false, + "required": ["classes"], + "properties": { + "classes": { "type": "array", "items": { "type": "string", "minLength": 1 } } + } + } + }, + "$ref": "#/$defs/resolveInput" +} diff --git a/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json new file mode 100644 index 0000000000..39c890daba --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-start-plan.draft.schema.json", + "title": "Debug start plan review draft", + "description": "A result from the declarative resolver or a dynamic Provider. The host validates ownership, trust, references and freshness before execution.", + "type": "object", + "required": ["draftVersion", "operationID", "contextToken", "outcome"], + "properties": { + "draftVersion": { "const": "1210-3" }, + "operationID": { "type": "string", "minLength": 1 }, + "contextToken": { + "description": "Host-issued reference binding workspace, configuration snapshot, plugin version and activation generation. Not authority granted by the Provider.", + "type": "string", + "minLength": 1 + }, + "outcome": { "enum": ["prepare", "ready", "failed"] } + }, + "oneOf": [ + { + "required": ["preparation"], + "properties": { + "outcome": { "const": "prepare" }, + "preparation": { + "description": "Ordered references to approved existing Build/Run preparation actions. Resolve again after successful completion; never reuse pre-build paths.", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } + } + } + }, + { + "required": ["transport", "configuration"], + "properties": { + "outcome": { "const": "ready" }, + "transport": { + "oneOf": [ + { "$ref": "debug-adapter-registration.draft.schema.json#/$defs/stdioTransport" }, + { + "type": "object", + "additionalProperties": false, + "required": ["kind", "endpointRef"], + "properties": { + "kind": { "const": "tcp" }, + "endpointRef": { + "description": "Host-issued lease for an authorized DAP endpoint, including cleanup ownership. A Provider cannot substitute an arbitrary address.", + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "configuration": { + "description": "Existing DebugLaunchConfiguration shape. adapterID comes from the registration, never from executable-name inference.", + "type": "object", + "additionalProperties": false, + "required": ["name", "request", "arguments"], + "properties": { + "name": { "type": "string", "minLength": 1 }, + "request": { "enum": ["launch", "attach"] }, + "arguments": { "type": "object" }, + "steppingFilters": { "$ref": "debug-configuration.draft.schema.json#/$defs/steppingFilters" } + } + } + } + }, + { + "required": ["error"], + "properties": { + "outcome": { "const": "failed" }, + "error": { + "type": "object", + "additionalProperties": false, + "required": ["code", "message"], + "properties": { + "code": { + "enum": ["invalid_request", "permission_denied", "not_supported", "runtime_missing", "process_start_failed", "process_failed", "cancelled", "timed_out", "unknown"] + }, + "message": { "type": "string", "minLength": 1 }, + "details": { "type": "object" } + } + } + } + } + ], + "unevaluatedProperties": false +} diff --git a/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json b/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json new file mode 100644 index 0000000000..64a0d7cdbe --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json @@ -0,0 +1,57 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.dap-runtime", + "exports": { + "stdioSession": { + "contract": { "id": "debug.session.stdio", "version": 1 }, + "implementation": { + "steps": [ + { + "id": "adapter", + "use": { "host": "debug.process.acquire", "version": 1 }, + "with": { "adapter": { "$value": "/input/adapter" } } + }, + { + "id": "plan", + "use": { "host": "debug.session.plan", "version": 1 }, + "with": { + "configuration": { "$value": "/input/configuration" }, + "transport": { + "kind": "stdio", + "processRef": { "$value": "/steps/adapter/processRef" } + } + } + } + ], + "result": { "$value": "/steps/plan" } + } + }, + "announcedTcpSession": { + "contract": { "id": "debug.session.announced-tcp", "version": 1 }, + "implementation": { + "steps": [ + { + "id": "endpoint", + "use": { "host": "debug.process.acquireTcp", "version": 1 }, + "with": { + "adapter": { "$value": "/input/adapter" }, + "endpointFormat": { "$value": "/input/endpointFormat" } + } + }, + { + "id": "plan", + "use": { "host": "debug.session.plan", "version": 1 }, + "with": { + "configuration": { "$value": "/input/configuration" }, + "transport": { + "kind": "tcp", + "endpointRef": { "$value": "/steps/endpoint/endpointRef" } + } + } + } + ], + "result": { "$value": "/steps/plan" } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json b/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json new file mode 100644 index 0000000000..ade823ec36 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json @@ -0,0 +1,48 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.java-runtime", + "pluginDependencies": { + "project": { + "pluginID": "example.java-project-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "backends": { + "jdt": { "kind": "hostIntegration", "languageID": "java", "integrationID": "jdt" } + }, + "exports": { + "debugSession": { + "contract": { "id": "debug.session.resolve", "version": 1 }, + "implementation": { + "steps": [ + { + "id": "target", + "use": { "dependency": "project", "export": "prepareDebugTarget", "contractVersion": 1 }, + "with": { "configuration": { "$value": "/input/configuration" } } + }, + { + "id": "session", + "use": { "backendRef": "jdt", "functionID": "debug.resolve" }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "configuration": { "$value": "/input/configuration" }, + "target": { "$value": "/steps/target" } + } + } + ], + "result": { "$value": "/steps/session" } + } + }, + "hotCodeReplace": { + "contract": { "id": "debug.hot-code-replace", "version": 1 }, + "implementation": { + "use": { "backendRef": "jdt", "functionID": "debug.hotCodeReplace" }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "sessionID": { "$value": "/input/sessionID" } + } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.capabilities.json b/shared/proposals/debug-adapters-1210/examples/java.capabilities.json new file mode 100644 index 0000000000..2c80adcf28 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.capabilities.json @@ -0,0 +1,21 @@ +{ + "draftVersion": "1210-3", + "sessionID": "example-java-session", + "revision": 1, + "capabilities": { + "sourceBreakpoints": { + "state": "unknown", + "source": "dap", + "reason": "not_negotiated" + }, + "hotCodeReplace": { + "state": "unknown", + "source": "backend", + "reason": "not_negotiated", + "provider": { + "pluginID": "example.java-runtime", + "export": "hotCodeReplace" + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.configuration.json b/shared/proposals/debug-adapters-1210/examples/java.configuration.json new file mode 100644 index 0000000000..851ff1e924 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.configuration.json @@ -0,0 +1,19 @@ +{ + "draftVersion": "1210-3", + "id": "example-run-java-main", + "name": "Java main", + "provider": { + "pluginID": "example.java-support", + "id": "java-debug" + }, + "request": "launch", + "target": { + "kind": "runTarget", + "configurationID": "example-run-java-main", + "languageID": "java" + }, + "parameters": { + "args": "--verbose", + "stopOnEntry": false + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.function-call.json b/shared/proposals/debug-adapters-1210/examples/java.function-call.json new file mode 100644 index 0000000000..f2175bdd15 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.function-call.json @@ -0,0 +1,18 @@ +{ + "method": "lithe/function/invoke", + "params": { + "functionID": "debug.resolve", + "operationID": "example-core-backend-operation", + "params": { + "contextToken": "example-host-authorized-context", + "configuration": { + "draftVersion": "1210-3", + "id": "example-run-java-main", + "name": "Java main", + "request": "launch", + "target": { "kind": "runTarget", "configurationID": "example-run-java-main", "languageID": "java" }, + "parameters": {} + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.prepare.json b/shared/proposals/debug-adapters-1210/examples/java.prepare.json new file mode 100644 index 0000000000..bd0c0aeed1 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.prepare.json @@ -0,0 +1,9 @@ +{ + "draftVersion": "1210-3", + "operationID": "example-debug-operation", + "contextToken": "example-host-context-before-build", + "outcome": "prepare", + "preparation": [ + "example-host-java-build-action" + ] +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.ready.json b/shared/proposals/debug-adapters-1210/examples/java.ready.json new file mode 100644 index 0000000000..99586a1b3c --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.ready.json @@ -0,0 +1,24 @@ +{ + "draftVersion": "1210-3", + "operationID": "example-debug-operation", + "contextToken": "example-host-context-after-build", + "outcome": "ready", + "transport": { + "kind": "tcp", + "endpointRef": "example-host-jdt-dap-endpoint" + }, + "configuration": { + "name": "Java main", + "request": "launch", + "arguments": { + "mainClass": "example.Main", + "projectName": "example-project", + "classPaths": [ + "${exampleHostResolvedClassPath}" + ], + "javaExec": "${exampleHostResolvedRunJavaExecutable}", + "args": "--verbose", + "stopOnEntry": false + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/java.registration.json b/shared/proposals/debug-adapters-1210/examples/java.registration.json new file mode 100644 index 0000000000..abded8d91c --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/java.registration.json @@ -0,0 +1,87 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.java-support", + "pluginDependencies": { + "java": { + "pluginID": "example.java-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "debugAdapters": [ + { + "id": "java-debug", + "displayName": "Java (JDT)", + "adapterID": "java", + "configurationTypes": [ + "java" + ], + "selectors": [ + { + "targetKinds": [ + "file", + "runTarget" + ], + "languageIDs": [ + "java" + ] + } + ], + "requests": { + "launch": { + "parametersSchema": "schemas/java-launch.schema.json" + } + }, + "capabilities": { + "sourceBreakpoints": { + "source": "dap" + }, + "conditionalBreakpoints": { + "source": "dap" + }, + "logPoints": { + "source": "dap" + }, + "exceptionInfo": { + "source": "dap" + }, + "setVariable": { + "source": "dap" + }, + "hotCodeReplace": { + "source": "function", + "invoke": { + "use": { + "dependency": "java", + "export": "hotCodeReplace", + "contractVersion": 1 + }, + "with": { + "contextToken": { + "$value": "/context/contextToken" + }, + "sessionID": { + "$value": "/input/sessionID" + } + } + } + } + }, + "session": { + "use": { + "dependency": "java", + "export": "debugSession", + "contractVersion": 1 + }, + "with": { + "contextToken": { + "$value": "/context/contextToken" + }, + "configuration": { + "$value": "/input/configuration" + } + } + } + } + ] +} diff --git a/shared/proposals/debug-adapters-1210/examples/native.capabilities.json b/shared/proposals/debug-adapters-1210/examples/native.capabilities.json new file mode 100644 index 0000000000..a63dfb1627 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/native.capabilities.json @@ -0,0 +1,26 @@ +{ + "draftVersion": "1210-3", + "sessionID": "example-native-session", + "revision": 2, + "capabilities": { + "sourceBreakpoints": { + "state": "supported", + "source": "dap" + }, + "readMemory": { + "state": "unsupported", + "source": "host", + "reason": "host_not_supported" + }, + "writeMemory": { + "state": "unsupported", + "source": "manifest", + "reason": "not_exposed" + }, + "disassemble": { + "state": "unsupported", + "source": "host", + "reason": "host_not_supported" + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/native.configuration.json b/shared/proposals/debug-adapters-1210/examples/native.configuration.json new file mode 100644 index 0000000000..67b9db5322 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/native.configuration.json @@ -0,0 +1,15 @@ +{ + "draftVersion": "1210-3", + "id": "example-run-native-attach", + "name": "Attach native process", + "provider": { + "pluginID": "example.native-debug", + "id": "lldb" + }, + "request": "attach", + "target": { + "kind": "process", + "processRef": "example-host-process-lease" + }, + "parameters": {} +} diff --git a/shared/proposals/debug-adapters-1210/examples/native.registration.json b/shared/proposals/debug-adapters-1210/examples/native.registration.json new file mode 100644 index 0000000000..cd61f82c61 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/native.registration.json @@ -0,0 +1,115 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.native-debug", + "pluginDependencies": { + "dap": { + "pluginID": "example.dap-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "backends": { + "adapter": { + "kind": "process", + "protocol": "dap", + "lifetime": "session", + "process": { + "launch": { + "kind": "systemCommand", + "commands": [ + "lldb-dap" + ] + }, + "arguments": [] + } + } + }, + "debugAdapters": [ + { + "id": "lldb", + "displayName": "Native (LLDB DAP)", + "adapterID": "lldb-dap", + "configurationTypes": [ + "lldb-dap" + ], + "selectors": [ + { + "targetKinds": [ + "executable", + "runTarget" + ], + "languageIDs": [ + "c", + "cpp", + "rust", + "asm" + ] + }, + { + "targetKinds": [ + "executable", + "process" + ] + } + ], + "requests": { + "launch": { + "parametersSchema": "schemas/native-launch.schema.json", + "targetBindings": { + "program": "target.path" + } + }, + "attach": { + "parametersSchema": "schemas/native-attach.schema.json", + "targetBindings": { + "pid": "target.processID" + } + } + }, + "capabilities": { + "sourceBreakpoints": { + "source": "dap" + }, + "conditionalBreakpoints": { + "source": "dap" + }, + "functionBreakpoints": { + "source": "dap" + }, + "dataBreakpoints": { + "source": "dap" + }, + "readMemory": { + "source": "dap" + }, + "disassemble": { + "source": "dap" + }, + "instructionBreakpoints": { + "source": "dap" + }, + "instructionStepping": { + "source": "dap" + }, + "writeMemory": { + "source": "disabled" + } + }, + "session": { + "use": { + "dependency": "dap", + "export": "stdioSession", + "contractVersion": 1 + }, + "with": { + "adapter": { + "backendRef": "adapter" + }, + "configuration": { + "$value": "/input/configuration" + } + } + } + } + ] +} diff --git a/shared/proposals/debug-adapters-1210/examples/node.registration.json b/shared/proposals/debug-adapters-1210/examples/node.registration.json new file mode 100644 index 0000000000..6786134d1c --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/node.registration.json @@ -0,0 +1,95 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.js-debug", + "pluginDependencies": { + "node": { + "pluginID": "example.node-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + }, + "dap": { + "pluginID": "example.dap-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "backends": { + "adapter": { + "kind": "process", + "protocol": "dap", + "lifetime": "session", + "process": { + "launch": { + "kind": "dependencyRuntime", + "use": { + "dependency": "node", + "export": "selectedRuntime", + "contractVersion": 1 + } + }, + "arguments": ["${pluginDir}/adapter/dapDebugServer.js"] + } + } + }, + "debugAdapters": [ + { + "id": "js-debug", + "displayName": "JavaScript / TypeScript", + "adapterID": "pwa-node", + "configurationTypes": [ + "pwa-node", + "node" + ], + "selectors": [ + { + "targetKinds": [ + "file", + "runTarget" + ], + "languageIDs": [ + "javascript", + "typescript" + ] + } + ], + "requests": { + "launch": { + "parametersSchema": "schemas/node-launch.schema.json" + } + }, + "capabilities": { + "sourceBreakpoints": { + "source": "dap" + }, + "conditionalBreakpoints": { + "source": "dap" + }, + "logPoints": { + "source": "dap" + }, + "exceptionInfo": { + "source": "dap" + }, + "restart": { + "source": "dap" + } + }, + "session": { + "use": { + "dependency": "dap", + "export": "announcedTcpSession", + "contractVersion": 1 + }, + "with": { + "adapter": { + "backendRef": "adapter" + }, + "configuration": { + "$value": "/input/configuration" + }, + "endpointFormat": "jsDebugStandalone" + } + } + } + ] +} diff --git a/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json b/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json new file mode 100644 index 0000000000..ce7d957a6a --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json @@ -0,0 +1,26 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.custom-debug-runtime", + "backends": { + "resolver": { + "kind": "process", + "protocol": "pluginFunctions", + "lifetime": "workspace", + "process": { + "launch": { "kind": "runtime", "tool": "node", "entry": "backend/debug.mjs" } + } + } + }, + "exports": { + "debugSession": { + "contract": { "id": "debug.session.resolve", "version": 1 }, + "implementation": { + "use": { "backendRef": "resolver", "functionID": "debug.resolve" }, + "with": { + "contextToken": { "$value": "/context/contextToken" }, + "configuration": { "$value": "/input/configuration" } + } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/python.configuration.json b/shared/proposals/debug-adapters-1210/examples/python.configuration.json new file mode 100644 index 0000000000..7869bee6f4 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/python.configuration.json @@ -0,0 +1,22 @@ +{ + "draftVersion": "1210-3", + "id": "example-run-python-main", + "name": "Python main", + "provider": { + "pluginID": "example.python-debug", + "id": "debugpy" + }, + "request": "launch", + "target": { + "kind": "file", + "path": "src/main.py", + "languageID": "python" + }, + "parameters": { + "args": [ + "--verbose" + ], + "justMyCode": true, + "console": "integratedTerminal" + } +} diff --git a/shared/proposals/debug-adapters-1210/examples/python.registration.json b/shared/proposals/debug-adapters-1210/examples/python.registration.json new file mode 100644 index 0000000000..390bec32f0 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/python.registration.json @@ -0,0 +1,105 @@ +{ + "draftVersion": "1210-3", + "pluginID": "example.python-debug", + "pluginDependencies": { + "python": { + "pluginID": "example.python-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + }, + "dap": { + "pluginID": "example.dap-runtime", + "minimumVersion": "1.0.0", + "maximumVersionExclusive": "2.0.0" + } + }, + "backends": { + "adapter": { + "kind": "process", + "protocol": "dap", + "lifetime": "session", + "process": { + "launch": { + "kind": "dependencyRuntime", + "use": { + "dependency": "python", + "export": "selectedInterpreter", + "contractVersion": 1 + } + }, + "arguments": [ + "-m", + "debugpy.adapter" + ] + } + } + }, + "debugAdapters": [ + { + "id": "debugpy", + "displayName": "Python (debugpy)", + "adapterID": "debugpy", + "configurationTypes": [ + "debugpy", + "python" + ], + "selectors": [ + { + "targetKinds": [ + "file", + "runTarget" + ], + "languageIDs": [ + "python" + ] + } + ], + "requests": { + "launch": { + "parametersSchema": "schemas/python-launch.schema.json", + "targetBindings": { + "program": "target.path" + } + } + }, + "capabilities": { + "sourceBreakpoints": { + "source": "dap" + }, + "conditionalBreakpoints": { + "source": "dap" + }, + "hitConditionalBreakpoints": { + "source": "dap" + }, + "logPoints": { + "source": "dap" + }, + "exceptionInfo": { + "source": "dap" + }, + "setVariable": { + "source": "dap" + }, + "restart": { + "source": "dap" + } + }, + "session": { + "use": { + "dependency": "dap", + "export": "stdioSession", + "contractVersion": 1 + }, + "with": { + "adapter": { + "backendRef": "adapter" + }, + "configuration": { + "$value": "/input/configuration" + } + } + } + } + ] +} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json new file mode 100644 index 0000000000..35c6f2f944 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Illustrative Java launch parameters resolved by the JDT integration", + "type": "object", + "properties": { + "args": { "type": "string" }, + "vmArgs": { "type": "string" }, + "stopOnEntry": { "type": "boolean" }, + "console": { "enum": ["internalConsole", "integratedTerminal", "externalTerminal"] } + }, + "additionalProperties": true +} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json new file mode 100644 index 0000000000..54e48125b1 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Illustrative LLDB attach parameters, not the complete upstream schema", + "type": "object", + "properties": { + "waitFor": { "type": "boolean" } + }, + "not": { "required": ["pid"] }, + "additionalProperties": true +} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json new file mode 100644 index 0000000000..6637e13194 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Illustrative LLDB launch parameters, not the complete upstream schema", + "type": "object", + "properties": { + "args": { "type": "array", "items": { "type": "string" } }, + "stopOnEntry": { "type": "boolean" } + }, + "not": { "required": ["program"] }, + "additionalProperties": true +} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json new file mode 100644 index 0000000000..2493736892 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Illustrative js-debug parameters, not the complete upstream schema", + "type": "object", + "properties": { + "args": { "type": "array", "items": { "type": "string" } }, + "sourceMaps": { "type": "boolean" }, + "stopOnEntry": { "type": "boolean" } + }, + "additionalProperties": true +} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json new file mode 100644 index 0000000000..00919554c0 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Illustrative debugpy launch parameters, not the complete upstream schema", + "type": "object", + "properties": { + "args": { "type": "array", "items": { "type": "string" } }, + "justMyCode": { "type": "boolean" }, + "stopOnEntry": { "type": "boolean" }, + "console": { "enum": ["internalConsole", "integratedTerminal", "externalTerminal"] } + }, + "not": { "required": ["program"] }, + "additionalProperties": true +} From cd76ab9f50643bfeb7447f36e51ad3a99fadf16b Mon Sep 17 00:00:00 2001 From: Yao Jingxi <23722032@bjtu.edu.cn> Date: Sun, 25 Oct 2026 22:43:15 +0800 Subject: [PATCH 2/3] docs(debug): narrow registry proposal and separate platform extensions (#1210) --- ...lic-extension-contract-and-provider-api.md | 2 +- ...r-provider-and-declarative-registration.md | 233 +++++--------- .../2026-10-25-native-debug-projections.md | 49 +++ ...6-10-25-plugin-dependencies-and-exports.md | 95 ++++++ .../proposals/debug-adapters-1210/README.md | 204 +++++------- ...bug-adapter-registration.draft.schema.json | 296 ------------------ .../debug-adapters.draft.schema.json | 207 ++++++++++++ .../debug-capability-state.draft.schema.json | 73 ----- .../debug-composition.draft.schema.json | 161 ---------- .../debug-configuration.draft.schema.json | 97 ------ .../debug-function-binding.draft.schema.json | 36 --- .../debug-start-plan.draft.schema.json | 88 ------ .../examples/dap-runtime.library.json | 57 ---- .../examples/java-runtime.library.json | 48 --- .../examples/java.capabilities.json | 21 -- .../examples/java.configuration.json | 19 -- .../examples/java.function-call.json | 18 -- .../examples/java.prepare.json | 9 - .../examples/java.ready.json | 24 -- .../examples/java.registration.json | 87 ----- .../examples/native.capabilities.json | 26 -- .../examples/native.configuration.json | 15 - .../examples/native.registration.json | 115 ------- .../examples/node.registration.json | 95 ------ .../examples/plugin-functions.library.json | 26 -- .../examples/python.configuration.json | 22 -- .../examples/python.registration.json | 105 ------- .../examples/schemas/java-launch.schema.json | 12 - .../schemas/native-attach.schema.json | 10 - .../schemas/native-launch.schema.json | 11 - .../examples/schemas/node-launch.schema.json | 11 - .../schemas/python-launch.schema.json | 13 - .../semantic-rejections.draft.json | 204 ++++++++++++ 33 files changed, 718 insertions(+), 1771 deletions(-) create mode 100644 .agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md create mode 100644 .agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md delete mode 100644 shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java-runtime.library.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.capabilities.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.configuration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.function-call.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.prepare.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.ready.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/java.registration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/native.capabilities.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/native.configuration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/native.registration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/node.registration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/python.configuration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/python.registration.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json delete mode 100644 shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json create mode 100644 shared/proposals/debug-adapters-1210/semantic-rejections.draft.json diff --git a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md index e7ca9b82cd..afdcd05dc8 100644 --- a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md +++ b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md @@ -32,7 +32,7 @@ PR #37 是第一阶段 UI Contribution(插件声明的界面入口)基础设 内置模块和插件尽量实现相同领域 Provider 契约。Build/Run/Test/Debug 等采用类型化 Registry(按能力类型登记和查询实现的目录),组合根负责装配通用适配器,不按新增插件名追加分支。先盘点并复用已有语言服务器、构建工具、运行/测试和 DAP(调试适配器协议)链路;上游拥有的项目、任务和依赖事实仍由原工具提供,避免再造一套解释器、工程模型或调试 UI。 -Debug 的具体边界、现有链路盘点、声明与动态准备的分工、API 兼容性约束及分阶段验收见[调试适配器的声明式注册与统一会话模型](2026-10-25-debug-adapter-provider-and-declarative-registration.md),跟踪当前仓库的 [#1210](https://github.com/1lck/Lithe-IDEA/issues/1210)。该提案没有开放新字段,也不改变本 Note 中其他领域 Provider 的设计。 +Debug 的最小声明、现有链路盘点、API 兼容性及 P1–P3 验收见[调试适配器 Registry 与第三方 DAP 接入](2026-10-25-debug-adapter-provider-and-declarative-registration.md),跟踪当前仓库的 [#1210](https://github.com/1lck/Lithe-IDEA/issues/1210)。插件依赖与导出另见[平台级独立提案](2026-10-25-plugin-dependencies-and-exports.md),原生指令和内存展示另见[后续投影提案](2026-10-25-native-debug-projections.md);两者不作为 #1210 的前置条件。这些提案没有开放新字段,也不改变其他领域 Provider 的设计。 ### 通用 Services 与资源所有权 diff --git a/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md b/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md index 55bce9b369..41947af7ac 100644 --- a/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md +++ b/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md @@ -1,235 +1,156 @@ -# Agent 笔记:调试适配器的声明式注册与统一会话模型 +# Agent 笔记:调试适配器 Registry 与第三方 DAP 接入 状态:提议中 ## 先说结论 -针对 [DebugAdapter Registry 与第三方 DAP 接入 #1210](https://github.com/1lck/Lithe-IDEA/issues/1210),以插件好写和逻辑复用为优先:JSON 声明依赖、导出、能力、后端入口与流程组合,公共插件可以继续依赖其他插件;动态计算复用插件函数调用,并通过类型化领域契约校验结果。宿主承担通用解释与适配复杂度,允许为此迭代 API。内置与第三方适配器进入同一个类型化 Registry(按能力登记和查询实现的目录),共用现有调试窗口和 DAP(Debug Adapter Protocol,编辑器与调试后端之间的标准协议)内核。 +[#1210](https://github.com/1lck/Lithe-IDEA/issues/1210) 只做两个目标:内置和第三方共用类型化 Registry(按稳定身份查找适配器的目录),第三方 DAP(Debug Adapter Protocol,编辑器与调试后端之间的标准协议)进入既有 Debug UI。插件在同一个 `plugin.json.debugAdapters` 里声明固定的进程和传输,匹配、参数映射及能力禁用都是可选项;不用理解依赖、导出或工作流。 -统一的是会话、操作和生命周期,不要求所有后端具备相同的功能;语言专属参数与扩展能力继续由对应后端解释。本提案没有开放任何新字段,也不改变现有插件、运行配置、构建接口或调试命令;下面的概念名须在实现时与契约、校验器和标准用例一起确定。 - -可讨论的 [JSON Schema 与示例](../../../../shared/proposals/debug-adapters-1210/README.md)单独放在 `shared/proposals/`,包含依赖与导出、JSON 组合、能力声明及有效状态、解析后的配置与启动方案。它们没有进入正式插件契约;保留现有进程启动定义的引用,解释器等运行时优先从依赖插件取得。 +依赖与跨包授权移到[插件平台独立提案](2026-10-25-plugin-dependencies-and-exports.md),原生指令和内存展示移到[独立后续提案](2026-10-25-native-debug-projections.md)。它们以及动态 resolver(运行前计算启动参数的可选函数)都不是本任务 P1–P3 的前置条件。本 PR 只提交设计,不改变已发布 API,也没有新增运行验证证据。 ## 问题 -### 当前实现与应当复用的部分 - -以下盘点基于 `preview` 提交 `e854cfd98e4a52fe5abacff2002efd9f68082da2`。它描述源码入口,不代表所有语言或两端都已完成运行时验收。 +### 现有系统可直接复用 -| 入口 | 已有责任 | 本次应如何使用 | -| --- | --- | --- | -| `rust/lithe-core/src/debug/` | DAP 分帧、请求关联、状态转换、断点、变量分页、取消、反向终端请求、Java 热替换 | 扩展已有内核,不再写第三套协议状态机 | -| `macos/Sources/LitheCoreContracts/Debug/` | 平台无关的会话、传输、启动参数、调试操作模型 | 公共模型的兼容入口,新增身份不能改写既有字段含义 | -| `macos/Sources/LitheDebugModule/Runtime/DebugAdapterSessionManager.swift` | 多会话、激活代次、事件、断点与停止 | 演进为从 Registry 选择目标,保留旧入口的兼容适配 | -| `macos/Sources/Lithe/Services/Debug/DebugAdapterRuntimeFactory.swift` 与 `MacServiceContainer.swift` | stdio 适配器,以及 Java、Go、Node 的专用构造 | 将语言字典逐步替换成 Provider 注册;平台进程和连接能力继续留在平台层 | -| `macos/Sources/Lithe/Services/Debug/DebugLaunchConfigurationResolver.swift` 与 `DebugLaunchPreparationCoordinator.swift` | 按语言准备启动参数、保存与 Java 启动目标解析 | 将策略放进对应 Provider,复用 Run 的准备流程与运行时选择 | -| `windows/tauri/src/features/debugger/` 与 `windows/tauri/src-tauri/src/debug.rs` | 调试界面、事件投影、进程与 TCP 传输、Rust Core 调用、资源释放 | 独立实现同一契约,保留已有调用信封和断点先于 launch 入队的顺序 | -| `shared/contracts/plugins/v1/` 与两端插件宿主 | 能力版本、安装审查、工具链与进程启动、插件禁用 | 增加独立 Debug 能力,不借语言或 UI 声明取得注册资格 | +以下源码盘点固定在 `preview` 提交 `e854cfd98e4a52fe5abacff2002efd9f68082da2`,说明代码责任,不代替平台验收。 -macOS 的通用工厂和 Go、Node 目前使用 Swift `DebugAdapterProtocolSession`,Java 使用 `CoreDebugAdapterProtocolSession`。迁移不能直接删掉前者:它已有子会话处理,Rust 路径需先覆盖对应行为和反向请求,再逐个切换。 +| 入口 | 现有能力与本次动作 | +| --- | --- | +| `rust/lithe-core/src/debug/` | 已有 DAP 分帧、请求序列、状态、断点、变量、取消和反向终端请求;不另写 DAP 引擎 | +| `macos/Sources/LitheCoreContracts/Debug/` | 已有平台无关的会话、传输及启动配置;保留兼容入口,新增 Registry 身份 | +| `macos/Sources/LitheDebugModule/Runtime/DebugAdapterSessionManager.swift` | 已有多会话和停止管理;改为从 Registry 获取 Provider,保留事件及失效代次 | +| `macos/Sources/Lithe/Services/Debug/DebugAdapterRuntimeFactory.swift` | 目前按语言装配 stdio 及专用工厂;改为通用适配器加内置 Provider 注册 | +| `DebugLaunchConfigurationResolver.swift`、`DebugLaunchPreparationCoordinator.swift` | 保留 Run 参数来源、保存、工程准备及编译失败决策;不复制 Build/Run 项目模型 | +| `windows/tauri/src/features/debugger/`、`windows/tauri/src-tauri/src/debug.rs` | 独立接入同一共享契约和现有界面;平台继续负责进程、socket 与终端 | +| `shared/contracts/plugins/v1/` | 复用能力版本、进程启动、安装审查与插件生命周期;纯 Debug 无需声明语言或 UI | -### 已有工具与缺口 +macOS 的 Java 走 Rust DAP,通用、Go 和 Node 仍有 Swift 会话路径。后者已有子会话行为,不能因为 Registry 新增就立即删除;先验证行为等价,再逐个迁移。 -| 目标 | 可复用的上游 | 当前版本或分发状态 | 接入前必须确认 | -| --- | --- | --- | --- | -| Java | JDT LS 与 Microsoft Java Debug Server | `third_party/jdtls/manifest.json` 固定 JDT LS 1.61.0、Java Debug Server 0.53.2;插件包提供资源 | 保留 JDT 工程事实、Java 测试与热替换,继续使用 Run 为同一目标选择的 JDK | -| Python | `debugpy` | 现有入口为 Python 执行 `-m debugpy.adapter`,没有统一锁定适配器版本 | 解释器、虚拟环境与适配器可用性;不在启动时静默安装依赖 | -| JavaScript / TypeScript | Microsoft `vscode-js-debug` standalone DAP server | 已有 Node TCP transport 与本地发现入口,没有统一锁定后端版本 | source map、`startDebugging` 子会话、终端与版本兼容范围;复用可独立使用的开源 server | -| Go | Delve DAP | 已有 `dlv` 发现和服务端 transport | 保留端口发现、取消和进程树回收行为 | -| C / C++ / Rust / 汇编 | `lldb-dap`,以及具备 DAP 支持的 GDB | Rust 已有 LLDB 发现和启动入口;其他目标与 GDB 不据此宣称可用 | 目标平台和架构、调试符号、DAP 构建能力、许可证、寄存器与反汇编支持 | +### 上游工具而不是新的调试引擎 -GCC 是编译器。Debug 应消费构建系统返回的可执行产物和符号,不把 GCC 当作调试适配器,也不按固定输出目录猜测程序路径。LLDB/GDB 可以服务多种语言,同一种语言也可以选择不同调试后端。 +- Java 复用 JDT LS 1.61.0 与 Java Debug Server 0.53.2(`third_party/jdtls/manifest.json`),工程路径、主类与测试事实继续来自 JDT,目标 JVM 使用 Run 选中的 JDK。 +- Python 复用 `debugpy.adapter`;解释器与虚拟环境来自 Run,不在调试时静默安装。当前代码未统一固定 debugpy 版本,实际接入需记录兼容范围。 +- JavaScript/TypeScript 复用开源 `vscode-js-debug` standalone server;Go 复用 Delve DAP。现有 TCP、source map、终端及子会话行为是迁移基线,后端版本仍需单独核实。 +- 已有 Rust 的 LLDB 启动可注册为内置 Provider;`lldb-dap` 或具备 DAP 的 GDB 可作为普通第三方适配器。GCC 是编译器,目标与符号来自 Build/Run,而不是增加一个名叫 GCC 的调试引擎。 -以上适配器的升级或启用应先于自研替代方案。新增打包资源前,必须固定来源、版本、哈希和许可证;用户工具链的版本则通过既有发现机制取得并核对兼容范围。本提案不新增下载入口、缓存或第三方依赖。 +本任务统一发现与接入方式,不承诺同一个模型让所有后端具有完全相同的能力。新增下载、打包资源及上游升级不是本设计 PR 的内容。 ## 提案 -### 1. 保留三条接口边界 - -| 边界 | 提供什么 | 不承担什么 | -| --- | --- | --- | -| 声明式注册与组合 | 稳定身份、依赖导出、能力策略、配置 schema、函数绑定与步骤组合 | 复制上游工程模型,凭静态布尔值断言某次会话必然可用 | -| 动态准备 | 复用依赖插件和函数,读取上游目标与工具链,引用现有构建动作,产生可校验的启动方案 | 各自重写公共启动、调用、取消、连接与清理机制 | -| 调试会话 | 执行 DAP,投影线程、栈和变量,管理取消、终端与停止 | 重新推算 Java classpath、构建产物或 source map | +### 1. 只增加 Debug 能力,不建立插件平台 -简单适配器和复杂适配器共用 `use` / `with` 调用及 `steps` 组合。实现来源可以是依赖插件导出、本包插件函数或通用宿主原语;返回同一种类型化结果。公共插件封装 stdio、TCP 端口发现、工程准备等流程,语言插件主要选择依赖与提供参数,不要求每个插件启动新的解析服务。复杂计算复用现有 `lithe/function/invoke`,不另建 `lithe/debug/*` 传输,也不强制纯 Debug 插件声明网页。 +沿用 [Build 的能力块与共享进程设计](../../implemented/architecture/2026-10-17-build-system-plugin-contract.md)和 [VCS 的运行时协商设计](2026-10-22-unified-vcs-provider-model.md)。完整清单只有一个,Debug 块只声明身份、启动前需要的事实及可选策略;能力状态由会话协商,不把 `supportsX` 全抄进清单。 -目前[插件函数契约](../../implemented/architecture/2026-10-20-plugin-function-contract.md)把函数限定为私有动作,领域结果走独立类型化方法。本提案在新的能力版本中增加显式导出和领域绑定:传输复用现有函数通道,Core 仍拥有领域计划和结果解码。依赖调用由宿主检查导出、契约、调用方和资源授权,再在被调用插件自己的会话上执行;旧私有函数及 `wrongPlugin` 规则不变。JDT 原始服务不被假定实现插件函数,由已有宿主集成适配同一调用模型。 +唯一的[评审 schema](../../../../shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json)及[字段边界](../../../../shared/proposals/debug-adapters-1210/README.md)保存在 `shared/proposals/`,并非正式插件契约。必需项仅为身份、显示名和固定 launch;无需依赖、导出、函数服务、步骤或额外配置文件。普通 JSON 参数不会被当作资源引用解释。 -依赖可以递归组合,但依赖图与导出调用图必须无环。流程由宿主驱动,步骤取消传递到本次子调用;等待中的后端处理器不再回调宿主调度自己。包版本限制与导出契约版本分别校验,依赖失效或导出撤回使关联计划立即失效。通用依赖、导出和流程机制应进入统一插件层,不在 Debug 内维护第二套插件管理器。 +选择拟定的 API 4、新 `debugAdapters: 1` 能力和 `debug.launch` / `debug.attach` 权限。普通进程沿用 `serverProcess: 1`;Run 选中运行时作为共享 `serverProcess: 2` 分支,由共享进程解析器拥有。这样 Python 不需要依赖平台才能用正确解释器,也不会在进程版本 1 下悄悄扩大支持范围。 -JSON 流程可以组合工具、前置动作、函数结果与连接资源;最终启动方案只含宿主理解的引用、参数和连接方式。前置动作走既有 Build/Run 调度,明确区分准备前输入与准备后结果,复用现有 Java 编译失败后的继续/取消决策。需要重新编译时,必须完成该决策后再次向事实拥有者取得目标,不能执行构建前缓存的产物或 classpath。先提供有界顺序组合和类型化取值,后续按实际插件需要迭代声明能力。 +这是待评审编号,不代表宿主支持;实施前核对编号是否被占用。API 1/2/3 和未使用 Debug 的能力原样保留。新增权限属于基础 API 演进,不能仅靠 `requires.debugAdapters` 绕过基础版本。安装、市场与运行前检查继续使用同一 `hostCapabilities`,只在宿主确实能运行时发布支持。 -### 2. 分开 Provider、语言、配置类型和会话身份 +### 2. Registry 统一身份和选择,不吞并配置 -Provider 的身份由插件身份与包内局部身份组合,不能覆盖宿主或另一个插件的条目。DAP `adapterID`、导入配置的 `type`、语言 ID、运行配置 ID 与会话 ID 各自保留自己的含义;兼容映射显式登记,不能从可执行文件名推导后端身份。 +内置 Provider 和第三方声明先转成同一种类型化描述,再进入 Registry。第三方身份由插件 ID 与局部 adapter ID 组成,内置身份使用宿主保留空间;DAP adapterID、语言、配置 type、Run 配置 ID 和会话 ID 分开。 -Registry 的发现阶段只读已验证的声明,不执行工作区程序。Provider 可匹配语言、运行目标、构建产物或用户明确选择的 attach 目标;文件扩展名只是一种条件。调试二进制、连接 JVM 或启动浏览器不需要伪造源文件,也不要求安装一个同名语言插件。 +选择顺序固定为配置显式选择、工作区已保存关联、匹配后的唯一候选。多个候选交给用户选择,列表按稳定身份排序,不让插件自报优先级抢占。缺省 selectors 表示只接受显式选择;发现阶段不执行程序。重复身份拒绝注册,选择项不可用时显示原因,不静默换后端。 -选择顺序为:配置显式选择、工作区已保存关联、平台及目标匹配后的唯一候选。多个同等候选由用户选择;列表按稳定身份排序,插件不能通过自报高优先级抢占内置实现。重复身份拒绝注册;匹配重叠不等于身份冲突。明确选择的 Provider 不可用时报告原因,不静默换后端。 +原有 Run 配置 ID、三层覆盖、导入参数与 `DebugLaunchConfiguration` 不变。声明默认参数后仍使用既有覆盖链,目标映射只补空缺值,绝不覆盖显式 program、args 或 classpath。对外部构建产物使用 Build/Run 的授权目标引用,平台解析执行路径;不要求所有目标都能写成工作区相对路径。 -注册记录绑定插件版本与启用代次。重新解析、更新或禁用会让旧记录失效;已解析但尚未执行的启动方案也必须再次检查,而不是拿着旧句柄启动程序。 +### 3. 固定启动形状足够覆盖基础 DAP -### 3. 配置保持公共外层与后端参数分离 +`launch.process` 共用现有 ServerProcess 的数据类型、校验、模板、工具发现及安装审查;`launch.transport` 为 stdio、公告端点 TCP 或固定端口 TCP。不引入通用 workflow、JSON Pointer 求值、宿主原语目录或按后端名选择的端口解析器。 -公共外层表达名称、Provider 引用、`launch` 或 `attach`、目标和配置来源;后端参数由其版本化 schema 校验。已有 `DebugLaunchConfiguration` 的 `name`、`request`、`arguments`、`steppingFilters` 含义不变,由适配层产生它;不把所有语言的字段塞进同一个必填结构体。 +公告端点使用字面量前缀和端口/hostPort 解码,限定 loopback、输出预算和期限。固定端口需检查占用与本次进程归属,不能连接到碰巧在同一端口的外部服务。平台未实现某种传输时明确拒绝,不因为 Core 能解析就发布支持。 -原有运行配置 ID、三层配置覆盖规则、导入的 `launch.json` 字段及参数优先级必须保留。尤其不能在合并时用缺失的公共 `program` 或 `args` 覆盖后端已给出的值。未知配置类型继续保留原文并显示不可用原因,不能自动改写成当前默认 Provider。 +Python/Java/Node 的 `runSelectedRuntime` 按同一目标复用 Run 选择结果,不增加第二套 runtime 设置;其他现有 packaged/system/runtime 分支保持旧含义。`${pluginDir}` 属于声明该进程的包,配置参数仍是普通 JSON。此版没有跨包可执行引用或对参数里特殊键名的猜测。 -Java 主类、模块路径和 classpath 来自 JDT;Python 解释器来自已选择的运行环境;C/C++ 与 Rust 产物来自 Build/Run 的结果。Debug 不维护另一份项目模型,也不增加独立的 JDK 选择链。 +### 4. 保留函数与宿主集成边界 -### 4. 公共会话支持能力差异与无源码位置 +Java 先作为内置 Provider 注册,继续走既有 JDT 工程准备、测试、热替换及生命周期;第三方 Debug JSON 不提供 `hostIntegration` 入口。宿主已知的内置实现可以注册,不等于允许每个新插件在组合根添加名称判断。 -能力进入 JSON:`source: dap` 绑定标准协议,`source: function` 绑定同一种依赖/函数组合,`source: disabled` 明确关闭。前者由 DAP 初始化及后续 `capabilities` 事件确认,后者由导出契约、函数注册与宿主适配确认;两者都经过权限及目标检查。有效能力以 JSON 返回,UI 区分尚未确定、已支持和不支持及原因。配置 schema 只校验参数,`requires` 仍只判断宿主契约版本,不把它当作能力支持证据。 +[已落地函数决策](../../implemented/architecture/2026-10-20-plugin-function-contract.md)保持不变:函数私有、领域结果类型化、后端不得请求宿主再次进入领域注册表。此版撤回跨插件函数、exports 和任意标准能力的函数实现,不修改那份已实现 Note 来声称新机制已生效。 -沿用已有会话、线程、栈帧、scope(变量分组)、变量和断点模型。原生调试扩展需补充会话内源码引用、指令位置、内存引用、指令断点、指令级单步、反汇编和内存读取;寄存器优先使用后端提供的 scope,不设计一个假定所有 CPU 都相同的寄存器列表。 +私有 resolver 也不是现成能力:后续独立版本先明确领域输入/结果、进程归属、权限和取消,修订函数决策后再开放。若结果需要 Build/Run 准备,只接受宿主已有 action 的类型化引用,成功后重新解析一次;第二次再要准备即拒绝,避免循环。`backend: 1` 仍为网页的全局进程,不改成工作区 Debug 后端。该后续版本不阻塞基础接入。 -无源码的栈帧不伪造源文件或行号,缺失位置按新模型显式表达。不能把既有必填数字字段直接改成 `null` 后要求旧消费者自动兼容;新增投影或版本化后,同时更新 Rust、Swift、TypeScript 与 fixtures(跨实现共用的标准输入和预期结果)。地址、内存引用与指令引用保持字符串,避免 JavaScript 数值精度损失;后端引用均为不透明值,不当作文件路径。 +### 5. 标准能力默认使用 DAP,不要求重复声明 -工作区源码的可持久化身份仍用相对路径;外部或远端源码通过有明确权限的映射或会话内引用取得,平台进程与 DAP 边界需要的绝对路径不变成跨工作区身份。变量引用和栈帧绑定会话及暂停代次,继续执行、重启或切换目标后不能复用。 +省略能力块时,按标准 DAP 默认值、initialize 和 capabilities 事件决定支持;宿主尚未实现的操作继续不可用。manifest 只允许 `capabilities.disabled` 关闭已知标准 capability,不允许 `source: function`,也不把 manifest 当作“已实现”的证据。 -Java 热替换等扩展保持已有调用与错误语义,通过 JSON 绑定版本化导出及函数。标准功能也允许使用函数适配,但其输入输出必须满足对应的公共操作契约;宿主未实现该适配时明确报告不支持。普通 UI 按有效能力显示操作,不按插件名称扩充组合根,不绕过会话校验。 +capability 名称以实施时固定的 DAP 定义为准,Core 检查名称存在,适配器不用维护另一份不完整能力清单。exception filters、completions、stepping granularity、cancel 等走同一协商规则;取消待处理操作和停止清理不受界面功能禁用影响。Java 热替换仍用已有 `redefineClasses` 的输入、结果及错误语义。 -### 5. 版本演进不能改变其他 API 的承诺 +### 6. 宿主继续拥有资源及停止策略 -[插件能力版本规则](../../implemented/architecture/2026-10-17-plugin-capability-versions.md)规定基础字段只随 `pluginAPIVersion` 演进,其中包括 `permissions` 和 `activationEvents`。因此前期讨论中的 `requires.debugAdapters: 1` 只是能力名草案,不能单凭它在 API 3 中加入新的顶层权限或激活事件。 +Provider 记录绑定包版本、启用代次、工作区和操作。准备及连接具有有界期限,调试会话本身没有总时长;禁用与启动交错时,执行前再确认,已创建资源进入同一清理链。取消、停止和失败丢弃晚到结果,重复停止共享完成状态。 -用户明确接受为了插件易写、依赖复用而增加通用适配器复杂度和 API 版本。本提案为独立 Debug 能力、依赖与导出、领域函数绑定及新授权分配相应版本,具体编号在实现时确定。调试授权覆盖读取与修改目标状态,不把已有 `process.run` 或 `languageServer.launch` 静默扩大为 attach、写内存权限。只有使用新特性的包升级;现有语言、Build、VCS、网页、设置和后端包继续使用原版本。 +adapter、debuggee、终端、共享服务和外部 attach 目标分别记录所有权。launch 停止自己拥有的程序,attach 默认只断开;Java Stop 不终止 JDT LS。子会话及 runInTerminal 沿用现有管理器;只在平台真正实现时向 DAP 公告反向请求支持。 -激活默认来自用户的启动或 attach 请求和 Registry 选择,无需为了“看起来一致”给所有旧包增加激活事件。若实现确实需要专用事件,其语法同样放进新 API 级别,不能让 API 1/2/3 接受过去会拒绝的输入。权限不是操作系统沙箱:原生调试程序的进程权限仍受平台和用户授权限制,安装审查必须准确说明它可访问调试目标。 +安装目录和插件包只读。日志、缓存、锁及临时状态通过平台存储 adapter 写入可写目录,会话结束回收会话资源,不影响签名或 Sparkle delta。实施新增下载/缓存时再同步 worktree 资源清单、校验路由及 CI 文档;本 PR 不产生资源。 -兼容性必须逐项核对: +### 7. P1–P3 独立完成 #1210 -| 现有表面 | 必须保留的行为 | +| 阶段 | 交付与退出条件 | | --- | --- | -| 插件 API 1/2/3 | 旧字段、缺省值、拒绝条件、错误优先级、规范化结果和支持范围;新字段不能被旧级别偷偷接受 | -| `requires` 与 `hostCapabilities` | 能校验不代表能运行;市场筛选、磁盘安装、启动扫描与运行前检查使用同一能力表 | -| `serverProcess: 1` | 只复用已有启动语义;DAP 的 TCP 发现或新启动形式放进 Debug 能力或明确的新进程能力版本 | -| Build/Run/Test 与语言服务 | 既有命令、选项来源、配置 ID、JDK 选择与工程事实不因 Registry 改变 | -| `debug.*`、JSON 信封与 C ABI | 保留原命令、载荷和错误语义;新增操作不能重解释旧枚举或破坏穷举解码器 | -| macOS 内置模块与 Windows Worker 插件 | 既有装配和包格式继续存在;Debug 声明式接入不要求迁移无关插件 | -| 插件后端 SDK | 复用现有函数、取消、进度及进程机制;依赖导出和领域绑定显式版本化,不强制 UI;协议扩展做 SDK 端到端验证 | - -### 6. 生命周期由宿主执行,资源所有权显式记录 - -每次准备与操作沿用 `operationID`、取消、超时和失效结果规则,并绑定工作区、Provider 注册代次及会话。启动准备、连接和交互请求分别设有界期限;不能给整个调试会话设总时长,也不能把已有 JDT 工程导入等待缩成普通交互请求的期限。 - -宿主在创建进程或连接前最后检查启用状态与信任;如果禁用与启动交错,已创建的资源立即进入同一清理链路。重复 Stop 共享同一个清理完成结果,完成前不报告资源已释放;晚到端口、子会话、终端或操作结果必须拒绝并清理。 - -必须区分 adapter 进程、被调试程序、终端、共享语言服务器和外部目标。`launch` 沿用已有终止所拥有程序的策略,`attach` 默认只断开;结束 Java 调试只释放调试连接及本次资源,不终止共享 JDT LS。插件禁用时清理自身会话,不通过名称或可执行路径批量结束用户独立启动的程序。 - -`runInTerminal` 继续由 Core 规范化、平台 PTY/ConPTY 创建终端;子会话走同一个管理器,明确父子关系和停止规则。只有两端相应宿主确实实现了反向请求,才在 DAP 初始化中声明支持。 - -插件包与安装目录均只读。解析过程产出的日志、锁、缓存和临时文件由平台存储 adapter 分配,按插件、工作区与会话隔离;会话内引用不跨 worktree 共享。新增下载或生成资源时,同步维护 `scripts/worktree-resources.json`、资源复用脚本校验路由、对应验证和 `docs/ci-builds.md`,并核对代码签名与 Sparkle 增量更新基线。 - -### 7. 分阶段替换,阶段之间保留回退能力 - -| 阶段 | 工作与退出条件 | 兼容性检查 | -| --- | --- | --- | -| P0:行为基线与契约评审 | 列出内置适配器完整启动、断点、变量、终端、子会话和停止序列;确定 Debug 权限及版本方案 | 记录旧输入的接受、拒绝和归一化结果;未完成评审不提前开放新能力 | -| P1:内部 Registry | 内置 Provider 进入类型化目录;通用目标入口与文件兼容入口共存;新增一种适配器不修改语言分支 | 原有 Provider ID 映射、Run 配置、断点与多会话行为通过原回归;两端消费相同选择 fixtures | -| P2:新能力契约 | schema、Core 校验与计划、依赖导出、JSON 组合、能力及函数绑定、安装审查与纯 Debug fixture 同批设计;分步实现真实流程 | 旧 API 与私有函数 fixture 不变;循环依赖、错误导出、撤回与不支持版本准确拒绝;宿主按实现公布能力 | -| P3:第三方纵向流程 | macOS 的纯 Debug 插件进入现有 UI,完成启动或 attach、断点、线程、栈、变量和停止;Windows 独立实现同一契约 | 完成禁用竞态、失败隔离、取消、晚到事件、恢复、安装目录哈希不变;双端各自提供证据 | -| P4:内置链路迁移 | Python、Java、Go、Node、Rust 逐个迁到 Registry 和现有 Rust DAP Core;先补齐被替代路径的能力 | Java Run JDK、JUnit/TestNG、热替换、Node 子会话与 source map、终端和停止均有实际回归;同一目标只启用一个实现 | -| P5:原生与汇编扩展 | 按 DAP 扩充无源码位置、反汇编、内存、指令断点与指令单步,接入经验证的 LLDB/GDB 组合 | 有符号源码调试与无源码指令调试分别验收;不把此阶段当作 #1210 基础 Registry 关闭的前提 | - -P1 至 P4 的每个行为改动都维护功能矩阵;某平台只有模型或源码时,运行验证保持 `pending`,不能根据另一端通过就标记完成。只有新入口行为与旧入口等价、所有消费者已迁移,才删除兼容包装;不能为切换方便先移除现有功能。 +| P1 内部 Registry | 内置适配器注册为类型化 Provider,保留兼容包装;明确身份、选择、冲突、失效代次及原有运行基线。Java 无需经过插件 JSON | +| P2 最小声明契约 | 正式 schema、Core 语义校验、拟定版本/权限、共享进程扩展、安装与市场审查同批落地;固定传输不需要函数或依赖平台。所有拒绝 fixture 接上实际 Core 测试 | +| P3 第三方纵向验收 | macOS 与 Windows 各自完成纯 Debug 插件安装、选择、launch/attach、断点、线程/栈/变量、停止和资源回收;两端提供独立证据,保留旧行为 | -### 正确做法 +Swift/Rust 内核整合可在 Provider 背后逐步做,不以删旧引擎为本任务前提。动态 resolver、依赖安装和指令/内存能力分别推进,不能成为 #1210 关闭的隐性条件。 -- Python 插件依赖运行时插件取得同 Run 的解释器,再依赖公共 DAP 插件完成 stdio 启动;主要写 JSON,断点、变量与停止进入现有链路。 -- Java 公共插件用 JSON 继续依赖工程插件,把准备结果传给已有 JDT 适配函数;其他 Java 插件直接引用其调试导出。 -- Java Provider 调用既有保存、工程同步和编译流程,向 JDT 读取当前目标,再使用 Run 已选择的 JDK;调试结束释放连接,不结束语言服务器。 -- 一个原生 Provider 同时匹配 C、C++、Rust 和汇编目标,用户明确选择 LLDB 或 GDB;没有源码的暂停显示指令位置,不创建假的文件。 +### 正确做法与反例 -### 不要这样做 +正确做法:一个只提供 stdio DAP 的插件声明自己的进程,用户显式选择它,现有窗口按协商结果显示断点与变量;没有 selectors、能力块或后端也能工作。Java 内置实现登记到同一目录,但继续向 JDT 读取工程事实。 -- 为每个语言插件重复实现端口、资源、取消和工程准备;为了宿主简单,强迫每个插件实现本可共享的后端。 -- 把旧私有函数全部开放为跨插件调用,或用任意函数返回值绕过领域结果校验。 -- 为纯 Debug 插件声明空语言或空工具窗口,或为了使用现有网页后端而强制生成网页。 -- 注册每个插件时都给 `MacServiceContainer`、Windows 前端或 Rust dispatcher 添加插件名称判断。 -- 把 `requires` 当权限,将 `process.run` 扩大为任意调试授权,或者在 API 3 下无版本地新增基础字段。 -- 仅让新模型跑通一个模拟会话,就删除 Java 测试、热替换、子会话或旧平台清理逻辑。 +反例:为了接入一个 stdio 进程,要求插件先写依赖包、导出、两步流程,再逐项列出全部 DAP 能力;或者允许第三方写一个 JDT 名称就访问宿主共享服务。这两种方式都超出基础接入的必要范围。 ## 考虑过的备选方案 -### JSON 组合与依赖优先 - -采用此方向。用户希望尽量把逻辑留在 JSON,允许宿主复杂和版本增加换取插件易写。公共流程和工程动作可以通过依赖、导出与步骤复用;真正需要计算时调用函数,结果经过同一个领域解码器。代价是宿主要实现版本化组合器、图检查和调用上下文,而不是把这部分成本转给每个插件作者。 - -### 所有插件都实现可编程 Provider - -表达力完整,也能覆盖 Java 和浏览器。没有作为默认入口,因为普通插件应能直接引用已有 JSON 流程和公共导出;不应为了启动 DAP 再写第二个服务。函数是统一组合模型中的实现来源,不是另一套必写协议。 - -### 直接复用语言字符串工厂作为公共 API - -迁移量最小。但无法表达一种后端支持多语言、一种语言有多个后端,也不能自然接入无源码目标或纯 Debug 插件。保留为迁移包装,不作为最终契约。 - -### 在 API 3 下只增加能力名,同时新增调试权限 - -看似只影响 Debug,但违反基础字段的版本规则。新能力可以独立演进,新增基础授权仍需要新的 API 级别;其他包继续使用原级别,避免要求整个生态升级。 - -### 为每个语言另做一套调试 UI 或改用统一自研调试引擎 - -短期可以绕过差异,但会复制已有 DAP 功能,或承担 Python、JVM、浏览器与原生代码的调试语义。复用成熟后端与现有窗口,通过协商表达差异。 +- Debug 同时建立依赖、导出与工作流:上一版采用;撤回,因为涉及市场、版本冲突、信任及所有领域,需要单独设计。并不否定未来通过依赖复用 JSON,只是不让 Debug 接入等待平台重构。 +- 第一期开放本包函数 resolver:比跨包调用简单,但仍改变领域结果边界和后端生命周期;后置到独立版本,先完成固定声明的真实流程。 +- 为所有能力显式标注 DAP/function/disabled:会让静态清单与运行时协商漂移。改为默认 DAP、只允许禁用,扩展函数有契约后再评审。 +- 继续按语言字符串工厂开放第三方接口:迁移最少,但无法支持一后端多语言、一语言多后端及无源文件目标。只留兼容包装,不作为最终公共 API。 +- 第三方自带另一套 UI 或自研统一调试器:重复现有 DAP、线程/栈/变量和资源管理,偏离本任务。 ## 验收标准 -- 无语言、无 UI 的 Debug 插件可以在支持对应契约的宿主安装并登记;不支持的宿主在安装和市场阶段拒绝,Core 校验成功不能绕过宿主能力检查。 -- 内置与第三方 Provider 使用同一 Registry;覆盖明确选择、工作区关联、重叠候选、重复身份、不可用工具链与禁用 Provider,不按插件名特判。 -- 覆盖插件依赖的二级组合、公共流程复用、显式函数导出与领域结果校验;拒绝循环、版本不兼容、未导出和错误资源归属,私有函数仍保持旧拒绝语义。 -- 至少一个真实第三方 DAP 完成从安装、选择目标、命中断点到线程、栈、变量和停止的完整流程;`launch` 与 `attach` 分别验证目标进程是否保留。 -- 在解析、构建、连接和终端创建的每个等待点禁用或取消,都不留下 adapter、debuggee、监听或晚到子会话;另一个会话和共享语言服务继续可用。 -- API 1/2/3、现有运行配置、Build/VCS/语言/UI/设置能力以及 JSON 调试信封的兼容 fixture 保持原结果;旧包无须增加 Debug 字段或更换 API 级别。 -- macOS 与 Windows 使用共享 fixtures,并各自给出真实流程证据;运行结束检查本次启动的 Lithe、调试程序及辅助进程均已清理,外部 attach 目标仍按既有策略保留。 -- P5 另行验证带符号与无源码程序、源码和指令单步、寄存器 scope、反汇编、只读内存查看与指令断点;后端不支持的功能明确显示不可用。 +- 同一 Registry 覆盖内置与第三方;明确选择、关联、候选歧义、重复身份、禁用失效均有标准输入/结果。纯 Debug 插件无需语言和 UI。 +- P2 先通过正式 Core 接受/拒绝 fixtures,包括完整清单版本、requires、权限、目标事实、资源路径和过期计划;结构 schema 通过不等于语义通过。 +- P3 至少一个真实第三方 DAP 完成安装到命中断点、查看线程/栈/变量和停止;launch 与 attach 分别验证所有权,失败、取消、禁用和迟到子会话不留下资源。 +- API 1/2/3、Run 配置、Build/VCS/语言/UI/设置、私有函数和既有 debug 命令的兼容结果保持不变。Node 子会话、Java 测试/JDK/热替换及终端不因接入回退。 +- 两端使用同一契约和 fixtures,各自实际验证。实施阶段更新功能矩阵,只有运行成功的平台才标记 verified;本设计 PR 不更改实现状态。 +- 独立依赖平台、私有 resolver 和原生扩展尚未完成,也可以在上述目标满足后关闭 #1210。 ## 风险 -- 组合器增加长期维护成本:以真实共享流程驱动版本演进,依赖和类型化函数覆盖复杂计算;不能以降低宿主成本为由把同一逻辑分散到所有插件。 -- Swift 与 Rust 路径能力不齐:先用同一输入与事件序列对照,再逐个迁移;未覆盖的适配器继续保留旧路径,不宣称完成统一内核。 -- 动态计划与权限脱节:安装审查、运行前检查及实际执行要验证同一个插件版本、获准程序和权限;不能信任 Provider 返回的任意命令或端点。 -- 版本方案与其他并行 API 工作冲突:实现前重新核对基础版本和能力表,只分配下一可用版本;本提案不预占正式版本号,不放宽其他能力校验。 -- 后端和平台支持不等价:GDB 的 DAP 构建能力、系统调试权限和架构必须实测;不能承诺一个模型让所有后端具备完全相同的行为。 -- 移除旧入口过早:保留按 Provider 控制的迁移开关,同一目标不双启动;回退不改用户配置、不重新绑定断点、不退回错误运行时。 +- 固定形状不能覆盖所有后端准备:复杂内置链路保留 Provider 实现;收集真实缺口后再设计 resolver,不用这一限制重建项目模型。 +- 固定 TCP 端口可能冲突或连接到错误进程:平台无法证明归属时拒绝,优先 stdio 或本次进程公告端点,不声称所有传输跨平台均可用。 +- DAP 协商与宿主投影不同步:有效支持取协商、宿主实现和授权的交集,功能未实现时不点亮按钮。 +- 拟定版本可能与并行工作冲突:实施前重新核对能力表,不改变任何已发布编号的语义。 +- 旧 Swift/Rust 能力不齐:保留可回退的 Provider 包装;完整行为等价后才移除旧路径。 ## 验证 -本提案阶段修改架构记录和独立评审 schema,使用本机已有的 Python `jsonschema` 离线检查 Draft 2020-12 schema、示例、参数与关键拒绝条件,再运行 `./scripts/verify-agent-notes.sh`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-runtime-bundle-immutability.sh` 和 `git diff --check`。这些检查不构成新增 Debug 功能或平台运行证据。 +本 PR 离线验证唯一 Draft 2020-12 schema 和结构拒绝输入;Core 语义 fixtures 只登记待实现的验收条件,不计为通过。运行 `./scripts/verify-agent-notes.sh`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-runtime-bundle-immutability.sh` 和 `git diff --check`。本阶段没有应用构建、后端启动或真实调试证据。 -实现阶段按改动范围运行: +实施阶段加载 `write-stable-tests`,按所属范围运行 `./scripts/verify-rust-core-comments.sh`、`./scripts/verify-rust-core.sh`、`./scripts/test-macos.sh`、`./scripts/verify-service-boundaries.sh` 与 `./scripts/verify-windows-boundaries.sh`。Windows 上另行执行 `./scripts/build-windows.ps1 -Configuration Release`、宿主 Rust 与前端测试。所有等待有界,失败也释放资源,结束后确认本次启动的 Lithe 与子进程已退出。 -- 契约与 Rust:`./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core-comments.sh`、`./scripts/verify-rust-core.sh`,以及所属插件和调试用例。 -- macOS:受影响调试、Run 配置、Java 测试与资源清理回归,通过 `./scripts/test-macos.sh` 和 `./scripts/verify-service-boundaries.sh` 验证边界。 -- Windows:`./scripts/verify-windows-boundaries.sh`;在 Windows 执行 `./scripts/build-windows.ps1 -Configuration Release`、宿主 Rust 测试及受影响前端回归,再运行真实 Debug 流程。 -- 测试实现:加载 `write-stable-tests` Skill,使用对应单测试计时 harness,所有等待有界、测试资源独立、退出清理可观测。 -- 功能与资源:`./scripts/verify-platform-feature-matrix-change.sh origin/preview HEAD`、`./scripts/verify-platform-feature-matrix.sh`、`./scripts/verify-runtime-bundle-immutability.sh`,并比较真实工作流前后的安装目录文件清单与哈希。 - -正式契约仍在主仓库与 Core 同批修改,合并后按[插件契约发布规则](../../implemented/architecture/2026-10-23-plugin-contract-publishing.md)同步到 `lithe-plugin-docs`;面向插件作者的指南写在该仓库。如果动态解析需要扩展插件后端协议,合并前在该仓库运行两个官方 SDK 的端到端验证,不能只靠主仓库测试。 +平台行为修改前运行功能矩阵变更门禁及 `./scripts/verify-platform-feature-matrix.sh`;真实工作流前后比较安装目录清单/哈希。正式契约与 Core 同批修改,合并后按[两仓库发布规则](../../implemented/architecture/2026-10-23-plugin-contract-publishing.md)同步 `lithe-plugin-docs`;若未来修改函数协议,先修订所属决策并在 docs 仓库验证两个 SDK。 ## 适用范围 - `rust/lithe-core/src/debug/` - `rust/lithe-core/src/plugins/` - `shared/contracts/plugins/v1/` -- `shared/proposals/debug-adapters-1210/` -- `shared/contracts/application-boundary.md` - `shared/contracts/rust-core-api.md` +- `shared/proposals/debug-adapters-1210/` - `shared/fixtures/debug/` -- `shared/platform-feature-matrix/features/` - `macos/Sources/LitheCoreContracts/Debug/` - `macos/Sources/LitheDebugModule/` - `macos/Sources/Lithe/Services/Debug/` - `macos/Sources/Lithe/Platform/MacOS/Debug/` -- `macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift` - `windows/tauri/src/features/debugger/` - `windows/tauri/src-tauri/src/debug.rs` -- `windows/tauri/src-tauri/src/plugin_host/` ## 依据 -- [公共扩展契约方向](2026-10-13-public-extension-contract-and-provider-api.md)、[构建 Provider 提案](2026-10-17-build-system-provider-api.md)。 -- [Java 构建与启动边界](../../implemented/architecture/2026-09-18-java-project-build-and-launch-boundary.md)、[Java Debug 与 Run 的 JDK](../../implemented/bug-fix/2026-10-14-java-debug-uses-the-run-jdk.md)。 -- [Windows Java 调试生命周期](../../implemented/bug-fix/2026-10-07-windows-java-debug-lifecycle.md)、[断点路径身份](../../implemented/bug-fix/2026-10-07-windows-debug-breakpoint-path-identity.md)、[Windows 声明式宿主](../../implemented/architecture/2026-10-22-windows-declarative-plugin-host.md)。 -- [DAP 标准](https://microsoft.github.io/debug-adapter-protocol/overview)、[DAP 协议定义](https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json)。 -- [debugpy](https://github.com/microsoft/debugpy)、[Java Debug Server](https://github.com/microsoft/java-debug)、[JavaScript standalone server](https://github.com/microsoft/vscode-js-debug)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)。 +- [公共扩展契约](2026-10-13-public-extension-contract-and-provider-api.md)、[能力版本](../../implemented/architecture/2026-10-17-plugin-capability-versions.md)、[Build Provider](2026-10-17-build-system-provider-api.md)。 +- [Java 构建与启动边界](../../implemented/architecture/2026-09-18-java-project-build-and-launch-boundary.md)、[Run JDK](../../implemented/bug-fix/2026-10-14-java-debug-uses-the-run-jdk.md)、[Windows Java 生命周期](../../implemented/bug-fix/2026-10-07-windows-java-debug-lifecycle.md)。 +- [DAP 标准](https://microsoft.github.io/debug-adapter-protocol/overview)、[DAP 定义](https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json)、[debugpy](https://github.com/microsoft/debugpy)、[Java Debug Server](https://github.com/microsoft/java-debug)、[js-debug](https://github.com/microsoft/vscode-js-debug)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)。 diff --git a/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md b/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md new file mode 100644 index 0000000000..564b59b45d --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md @@ -0,0 +1,49 @@ +# Agent 笔记:原生指令与内存调试的后续投影边界 + +状态:提议中 + +## 先说结论 + +原生程序的无源码栈帧、反汇编和内存展示是独立的 Debug UI 扩展,不是 [#1210 Registry 与第三方 DAP 接入](2026-10-25-debug-adapter-provider-and-declarative-registration.md)的关闭条件。基础接入先复用现有源码调试;本提案只保留未来如何表达指令位置和后端差异的边界,不修改旧字段或新增权限。 + +## 问题 + +LLDB/GDB 可以同时服务 C、C++、Rust 和汇编,但二进制不一定有源码或行号。当前会话模型以源码调试为主;若用假文件或零行号塞进现有模型,UI 会跳到错误位置,旧消费者也可能误解缺失值。 + +## 提案 + +后续从真实 DAP 结果出发,为会话内源码引用、指令位置、内存引用、指令断点和指令单步增加版本化投影。地址及引用保持字符串,避免 JavaScript 数值精度损失;它们是不透明后端引用,不是工作区文件路径。没有源码时明确表达缺失,不直接把旧必填数字改成 null 交给旧消费者。 + +寄存器优先展示后端给出的变量分组(scope),不假定所有 CPU 有统一寄存器表。反汇编、内存读取、写入和指令断点分别受后端协商、宿主实现与操作授权约束;写入权限需要单独设计,不从已有 launch 或读取能力推导。 + +源码身份仍为工作区相对路径,外部源码通过已授权映射或会话引用读取。栈帧、变量及内存引用绑定会话和暂停代次,继续执行或重启后重新获取。Rust、Swift、TypeScript 及 fixtures 一起演进,再接平台展示。 + +正确做法:没有源码的暂停展示指令地址,支持源码的帧仍跳转真实文件。反例:为让编辑器能跳转,给未知帧伪造一个工作区文件和第一行。 + +## 考虑过的备选方案 + +- 放回 #1210 的 P5:容易把基础 Registry 与新 UI、架构和权限绑定,已拆出,另行验收。 +- 复用现有必填文件位置并填默认值:字段少,但无法区别未知位置与真实第一行,不采用。 +- 自研统一原生调试器:重复 LLDB/GDB 的能力及平台权限处理;仍采用标准 DAP 和成熟上游。 + +## 验收标准 + +- 有符号源码调试、无源码指令调试分别验收;旧 Registry 与源码流程不要求启用新投影。 +- 覆盖未知位置、超出整数精度的地址、继续后引用失效和不支持能力;不得发生假跳转或旧解码器回归。 +- 两端分别验证反汇编、只读内存、寄存器分组及指令断点;写入只有在新权限与独立用例通过后开放。 + +## 风险 + +GDB 是否支持 DAP 取决于版本和构建,操作系统调试授权及指令集也各不相同。统一模型不意味着全部平台或后端都能实现这些功能,未验证的组合保持不可用。 + +## 验证 + +本次仅运行 `./scripts/verify-agent-notes.sh`,不提供原生 Debug 运行证据。实施前加载 `write-stable-tests`,增加共享 fixtures,运行 `./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core.sh` 及对应平台测试;更新功能矩阵并在真实原生调试流程后清理本次进程和资源。 + +## 适用范围 + +- `rust/lithe-core/src/debug/` +- `shared/fixtures/debug/` +- `macos/Sources/LitheCoreContracts/Debug/` +- `macos/Sources/LitheDebugModule/` +- `windows/tauri/src/features/debugger/` diff --git a/.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md b/.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md new file mode 100644 index 0000000000..a64ae1ef4f --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md @@ -0,0 +1,95 @@ +# Agent 笔记:插件依赖、导出与跨包授权的独立设计范围 + +状态:提议中 + +## 先说结论 + +插件之间复用运行时、JSON 声明和计算能力属于整个插件平台,不应由某个 Debug 格式顺带定义。本提案从 [Debug #1210](https://github.com/1lck/Lithe-IDEA/issues/1210) 拆出依赖、导出和授权,挂在[公共扩展契约](2026-10-13-public-extension-contract-and-provider-api.md)下;Debug 的 Registry 与第三方 DAP 接入不依赖它。 + +方向仍是插件好写、共享逻辑尽量复用,但安装闭包(某个插件及其全部间接依赖)、版本冲突和信任必须先有明确规则。以下只是待单独实施的决策边界,不开放 `pluginDependencies`、`exports`、跨包函数或工作流字段,也不更改现有私有函数契约。 + +## 问题 + +上一版 Debug 草案把依赖、导出、跨包函数和顺序工作流放进专用注册格式,却没有回答安装和卸载如何影响其他插件。仅校验引用存在不能处理菱形冲突(两个依赖分支要求同一个插件的不兼容版本),也不能证明社区调用方有权启动官方依赖里的程序。 + +现有市场已经负责平台、版本、来源、签名和安装确认,插件函数已经规定私有归属。新的复用机制必须扩展这些所有者,而不是增加第二个安装器、进程表或函数路由器。 + +## 提案 + +### 1. 先解决安装和失效,再开放导出调用 + +| 主题 | 拟采用的规则 | +| --- | --- | +| 插件身份与来源 | 依赖绑定插件 ID、允许版本范围及获准来源/发布者;不能仅按 ID 从任意市场寻找同名替代 | +| 安装解析 | 市场先按平台、宿主能力及信任策略过滤版本,再求整个依赖闭包;下载前展示统一计划,验证包内依赖与索引一致 | +| 单版本约束 | 同一插件 ID 只安装一个版本。多个范围取交集;交集为空就拒绝本次安装或更新,并显示两条冲突路径,不自动降级或替换其他已安装插件 | +| 固定结果 | 安装计划固定每个包的版本、来源和内容哈希;执行前重查目录快照。闭包全部准备、校验完成后一起发布,失败恢复旧闭包,不留下半安装状态 | +| 更新 | 显式更新重新计算所有受影响的反向依赖;旧约束不满足时整笔拒绝。用户可以另行批准一组兼容更新,不暗中更新无关插件 | +| 禁用与卸载 | 先算反向依赖闭包,提示受影响的插件。默认拒绝破坏仍启用的依赖方;用户确认后先停依赖方操作和资源,再禁用/卸载目标 | +| 启动时发现缺失 | 保留依赖方安装记录,标记阻塞及具体原因,不启动后端;恢复依赖后重新校验再允许激活 | +| 循环与预算 | 安装依赖和声明导出引用分别检查循环、深度及总量;具体上限、稳定错误码、并发安装锁与崩溃恢复日志是正式契约的前置验收 | + +第一版先不加入弱依赖、可选依赖和并存多版本,避免不能证明的解析语义。运行时动态缺失不是静默选择其他依赖版本的理由。 + +### 2. 信任不沿依赖关系传递 + +每个包独立验证签名、哈希、来源和 namespace。社区插件依赖官方包不会因此变为官方插件,官方包的签名也不是对调用方的背书。安装确认展示闭包新增包、各自权限、来源以及哪些公开导出将被调用;不能把间接依赖藏在顶层插件的一行名称后面。 + +若未来导出可以执行程序,审查必须同时展示调用者、资源所有者和实际执行的包/命令。被依赖方拥有可执行资源与进程生命周期,宿主依据导出用途、本次用户动作、工作区信任和双方授权批准执行;依赖方不能通过传路径替资源所有者更换程序。依赖更新后的资源也要重做来源、签名、权限和计划代次检查。 + +权限不做简单并集,也不能简单取交集后假装已解释语义:每个导出必须定义可接受的调用上下文及所需操作授权。某个导出没有这种定义时,不允许跨包调用,即使两个包都已安装。 + +### 3. 导出是明确选择的契约,不是公开全部函数 + +复用对象可以是只读声明、运行时描述或有类型的操作,但不能直接公开依赖包的私有函数表。包版本回答“装哪版”,导出契约版本回答“交换什么输入和结果”;不可兼容的变更需要新导出契约。 + +若需要跨包资源引用,正式契约使用显式带标签的类型,例如专门的 backend/lease 变体;不靠普通参数恰好叫 `backendRef` 来识别。宿主签发的租约记录资源所有者、调用链、操作与失效代次,跨包只传受限引用;`${pluginDir}` 永远按声明资源的包解析。用户参数里的同名字符串和对象仍然只是数据。 + +跨包操作只能由宿主在已授权的导出边界调度到资源所属会话,不能将调用方 pluginID 写入目标会话。后端回调宿主重新进入注册表的禁止规则保留;否则等待中的处理器可能等待自己。如何将新授权模型加入函数路由、如何区分私有与公开调用,需要单独版本化,不能删除旧 `wrongPlugin` 或 `recursiveCall` 检查来实现。 + +### 4. 不在此处偷改已实现决策 + +[插件函数契约](../../implemented/architecture/2026-10-20-plugin-function-contract.md)仍是当前行为真源:函数私有,领域结果走类型化契约。此提案没有修改它。若以后采用函数传输领域结果或依赖导出,先在实现 PR 中修订对应决策,给出输入/结果、授权、错误优先级与兼容 fixtures,再改 Core 和双端宿主。 + +新的字段属于统一 `plugin.json` 的能力演进;基础权限或身份语义变化需要新的基础 API。没有 Debug draftVersion,也不要求现有 Build/VCS/UI/语言插件迁移。现有 `backend: 1` 的全局、网页触发行为不变;新的进程共享方式另行版本化。 + +通用 workflow 尚无证明必要的真实输入,不在这个依赖提案里重新引入 steps 或取值语言。先通过实际导出契约完成复用,再判断是否有需要由宿主解释的公共流程。 + +### 正确做法与反例 + +正确做法:两个插件依赖同一个运行时,安装器先求兼容版本并展示共同资源的来源与权限,宿主只对获准导出执行调用。 + +反例:社区插件依赖官方运行时后,自动继承官方身份和全部权限;或冲突时静默换掉另一个已安装插件的依赖。签名和版本检查都不能支持这种行为。 + +## 考虑过的备选方案 + +- 每个领域自己定义依赖和安装:短期好实现,但同一插件的版本、信任和卸载会出现多套答案,不采用。 +- 同 ID 多版本并存:可缓解菱形冲突,但影响设置、存储、市场、UI 身份和进程共享,第一版不承担这一范围。 +- 依赖即授权、所有函数自动导出:声明短,但让社区包借到依赖方权限,破坏现有私有契约,不采用。 +- 只允许声明复用,不允许动态导出:更易验证,可作为第一阶段;是否增加动态操作须由真实插件证明,不为了“完整”预先开放。 + +## 验收标准 + +- 独立任务/PR 完成安装解析、版本冲突、来源固定、哈希校验、事务恢复及并发安装规则,之后才公布新能力。 +- 有共同兼容版本与不兼容菱形两组标准用例,冲突报告带确定排序的两条依赖路径;失败不修改原安装闭包。 +- 禁用/卸载、启动时依赖缺失、升级失效及恢复分别验证反向依赖与资源清理;任何失败不误停不相关插件。 +- 社区依赖官方、同名包来自不同来源、签名变化和导出撤回均有拒绝输入;旧私有函数的归属和递归拒绝语义不变。 +- 如涉及函数协议,在 `lithe-plugin-docs` 验证 Node/Java SDK;正式契约与 Core 一起落地后再同步副本。 +- #1210 的基础 Registry 和第三方 DAP 验收可以完全不安装依赖包而完成。 + +## 风险 + +依赖安装事务和信任会扩大影响面,必须单独评审,不能靠一个 Debug schema 推定已解决。单版本第一版会拒绝部分组合,但比静默替换可靠;多版本共存、导出目录及资源授权的完整 wire 形状仍待后续设计,不属于本次交付。 + +## 验证 + +本次只运行 `./scripts/verify-agent-notes.sh` 和文档检查,没有依赖解析器或跨包调用实现,不能声称安装或授权用例通过。实施时使用 `write-stable-tests`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core.sh`,并分别验证两个宿主和函数 SDK;新增资源时遵守工作树复用与安装目录只读要求。 + +## 适用范围 + +- `rust/lithe-core/src/plugins/` +- `rust/lithe-core/src/lsp/interface/plugin_function.rs` +- `shared/contracts/plugins/v1/` +- `macos/Sources/Lithe/Platform/MacOS/` +- `windows/tauri/src-tauri/src/plugin_host/` +- [插件契约与 SDK 仓库](https://github.com/Lithe-IDEA/lithe-plugin-docs) diff --git a/shared/proposals/debug-adapters-1210/README.md b/shared/proposals/debug-adapters-1210/README.md index a16c2d0a15..57909607d7 100644 --- a/shared/proposals/debug-adapters-1210/README.md +++ b/shared/proposals/debug-adapters-1210/README.md @@ -1,142 +1,108 @@ -# Debug JSON 组合评审草案(#1210) - -设计目标:**普通插件尽量只写 JSON,通过依赖插件复用运行时、工程准备、适配器启动和调试能力;宿主承担通用解释与适配的复杂度。** 动态部分使用现有插件函数调用,输入输出继续由版本化领域 schema 校验。这版将能力声明、依赖、动态函数与流程组合放进同一种 JSON 模型。 - -这是 `feat/1210-debug-adapter-provider` 上的设计文件,当前宿主尚不接受。`draftVersion: "1210-3"` 是评审编号;`lithe.invalid` 只用于离线引用。没有修改现有插件契约、函数协议、产品 API 或运行逻辑。 - -## 插件作者主要写什么 - -完整例子:[Python](examples/python.registration.json)、[Java](examples/java.registration.json)、[JS/TS](examples/node.registration.json)、[C/C++/Rust/汇编](examples/native.registration.json)。 - -```json -{ - "pluginDependencies": { - "java": { - "pluginID": "example.java-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "session": { - "use": { "dependency": "java", "export": "debugSession", "contractVersion": 1 }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "configuration": { "$value": "/input/configuration" } - } - }, - "capabilities": { - "sourceBreakpoints": { "source": "dap" }, - "hotCodeReplace": { - "source": "function", - "invoke": { - "use": { "dependency": "java", "export": "hotCodeReplace", "contractVersion": 1 }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "sessionID": { "$value": "/input/sessionID" } - } - } - } - } -} -``` - -上面为节选:依赖是包级字段,`session` 和 `capabilities` 属于适配器。Java 插件不需要再次实现 JDT 准备和热替换。Python 同样依赖运行时插件取得 Run 使用的解释器,再依赖公共 DAP 插件启动 stdio;JS/TS 复用公共 TCP 启动流程。GCC 产生的程序由 LLDB 或支持 DAP 的 GDB 调试,原生 Provider 可同时服务多语言及无源码目标。 - -## 依赖可以继续依赖其他插件 - -```text -Python Debug → Python Runtime(解释器) + DAP Runtime(stdio 会话) -JS/TS Debug → Node Runtime(运行时) + DAP Runtime(动态 TCP 会话) -Java Debug → Java Runtime → Java Project Runtime(工程准备) - → 既有 JDT 集成 -``` - -公共插件也主要写 JSON。见 [DAP 公共流程](examples/dap-runtime.library.json)和 [Java 二级依赖组合](examples/java-runtime.library.json)。例子里的 `example.*` 包及部分导出仅用于展示目标结构,不代表这些依赖已发布。Java Project、Python Runtime、Node Runtime 的具体包清单不在本次 Debug 草案中定义。 - -每个导出有稳定名称和版本化契约。依赖方调用导出,不复制依赖包的路径或后端实现。包版本约束解决安装哪一版;`contractVersion` 解决本次调用使用哪种输入输出。`pluginDependencies` 与现有 `requires` 分开:前者指依赖的插件,后者仍指宿主 API 能力。最终应使用统一插件依赖管理,不保留 Debug 特有的第二套依赖管理器。 - -## 一种调用结构,三种实现来源 - -所有调用都写成 `{ "use": ..., "with": ... }`: - -| use 的形式 | 谁提供实现 | 示例 | -| --- | --- | --- | -| `{dependency, export, contractVersion}` | 依赖插件导出的 JSON 流程或函数 | 复用 Java 的 debugSession | -| `{backendRef, functionID}` | 本包插件函数,或已有集成的类型化桥接 | 调用 debug.resolve | -| `{host, version}` | 通用宿主原语 | 创建适配器资源、生成启动方案 | - -简单调用可以直接返回结果;需要多步时使用 `steps`,每步结果通过 `$value` 引用: +# DebugAdapter Registry 评审草案(#1210) -```json -{ - "steps": [ - { - "id": "target", - "use": { "dependency": "project", "export": "prepareDebugTarget", "contractVersion": 1 }, - "with": { "configuration": { "$value": "/input/configuration" } } - }, - { - "id": "session", - "use": { "backendRef": "jdt", "functionID": "debug.resolve" }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "configuration": { "$value": "/input/configuration" }, - "target": { "$value": "/steps/target" } - } - } - ], - "result": { "$value": "/steps/session" } -} -``` +本目录只评审两件事:**内置与第三方共用 Registry(按身份查找适配器的目录),第三方 DAP 进入现有 Debug UI**。声明放在现有 `plugin.json.debugAdapters`,不是独立注册文件。没有 `draftVersion`,没有新的配置文件格式,也没有插件示例或开发教程。 -宿主按顺序执行,`$value` 使用 JSON Pointer 读取输入、上下文和已完成步骤,保留对象/数组/整数类型。缺失值报错,`$literal` 可转义保留字段。路径转换、参数合并、资源登记等通用行为放进共享原语,插件不重复拼接命令,也不重复实现流程执行器。这版先提供直接调用和顺序组合;后续确有需要可以版本化扩充条件等声明能力,不以减少宿主解释器复杂度为由要求每个插件另写一套后端。 +当前宿主不接受这些新增字段。本 PR 只提交计划,不改变正式契约或产品行为。 -`/context/contextToken` 由宿主签发,调用需要它的领域契约时通过 `with` 显式传入。进入依赖包后,宿主为当前被调用方建立受限上下文,不能把调用方 token 当成访问依赖全部资源的凭据。导出契约校验公共输入和结果;JDT 桥接还接收工程准备的 `target`,该内部输入由其独立的类型化适配契约校验。 +## 评审材料 -## 复用现有插件函数方案 +- [能力块 schema](debug-adapters.draft.schema.json):唯一一份新增 schema,只校验从完整清单提取的 `debugAdapters` 段。 +- [拒绝 fixtures](semantic-rejections.draft.json):合成的契约验收输入,不是可安装插件;区分 schema 能拒绝和待 Core 实现的语义拒绝。 +- [Debug 架构与 P1–P3 验收](../../../.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md)。 -动态后端仍使用现有进程启动、`litheFunctions` 协商、函数注册、`lithe/function/invoke`、进度、撤回、超时和取消机制,不新增 `lithe/debug/*` RPC。[自定义函数后端示例](examples/plugin-functions.library.json)展示普通后端如何导出调试启动能力;[调用消息示例](examples/java.function-call.json)展示复用的函数信封形状。 +插件依赖、导出与跨包授权移到[独立平台提案](../../../.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md);原生指令、反汇编和内存投影移到[独立后续提案](../../../.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md)。两者都不是 #1210 的依赖或关闭条件。 -当前函数协议 v1/v2 只允许插件私有调用,现有领域结果也不经插件函数传输。本提案新增的是**导出和依赖调用的领域绑定**:宿主校验调用方依赖、被调用方导出、契约及授权,然后在拥有该函数的目标插件会话上调用现有函数通道,最后由 Core 校验领域结果。不会把调用方的 pluginID 塞进目标会话,也不会删除旧 `wrongPlugin` 拒绝条件。旧函数继续私有;只有显式导出的新契约能被依赖方使用。 +## 版本与清单位置 -JSON 组合由宿主驱动,不让正在等待结果的后端处理器再递归调度自己。依赖图与导出调用图检查循环;取消传播至本次子调用;共享后端不因一个调用取消而退出。函数撤回、插件更新或依赖禁用会使对应调用失效,迟到结果不得恢复旧会话。依赖不会继承调用者全部权限:需要执行资源时,只传递当前操作获准的受限引用。 +以下是本次选择的**拟定版本**,不是已分配、已实现的正式版本。落地前核对并行契约,若编号被占用,整体调整而非改变已发布版本的含义。 -JDT 是宿主已有集成,原始 JDT LS 不会因此被假定支持 `litheFunctions`。`hostIntegration` 把现有 JDT 操作适配到同一种类型化调用入口,不更改共享语言服务器的插件归属。新增普通第三方插件不需要在组合根增加插件名称分支。 +| 完整 `plugin.json` 中的位置 | 本提案的选择 | +| --- | --- | +| `schemaVersion`、`id`、`version`、`vendor` 等 | 沿用现有清单;不在 Debug 段重复插件身份 | +| `pluginAPIVersion` | 拟定 `4`:基础权限集合新增 Debug 授权;API 1/2/3 不接受新权限或 Debug 段 | +| `requires.debugAdapters` | 拟定 `1`:固定进程/传输声明与 Registry 接入 | +| `requires.serverProcess` | 普通进程为 `1`;使用 `runSelectedRuntime` 为拟定的 `2`。后者由共享进程契约拥有,不在版本 1 偷加 Python | +| `permissions` | 拟定 `debug.launch`:运行 DAP 适配器、控制本次 launch 目标;声明 attach 还需 `debug.attach` | +| `debugAdapters[]` | 本目录唯一 schema 评审的能力块 | +| `activationEvents` | 不新增事件。发现只读清单;用户选择并开始 Debug 时才启动适配器 | -## 能力也在 JSON 里 +没有 UI 或语言也可注册。`debug.launch` 不暗含 Build、测试、网络下载或其他插件的调用权限;attach 必须展示独立风险并获准。调试本身可能修改目标状态,安装审查必须如实说明,不把它包装成只读权限。未来内存写入等新操作另行评审。 -- `source: "dap"`:使用标准 DAP 实现,按 initialize 和后续 capabilities 事件确定支持。 -- `source: "function"`:通过同一种 invoke 组合调用已导出的函数,结果使用该操作的标准契约。 -- `source: "disabled"`:明确关闭。省略的能力不展示。 +`requires` 继续恰好列出所用能力。Core 校验、磁盘安装、市场过滤、安装确认和运行前检查使用同一能力表;宿主实际实现后才公布 `hostCapabilities`。本目录的 schema 不替代完整清单校验,特别是版本、权限、签名和 `requires` 的交叉检查。 -断点、变量修改、重启、反向单步、内存、反汇编、指令断点等都能声明。线程、调用栈、变量读取及基本执行控制继续复用公共 DAP 会话。函数实现标准操作也必须满足对应契约;某种绑定尚未由宿主实现时返回 `host_not_supported`。热替换作为已有的非标准能力给出完整绑定例子;其他函数操作的输入输出定义随实际接入扩充。 +拒绝顺序沿用能力版本规则:基础格式/API 支持范围 → `requires` 的能力及宿主支持 → Debug 段结构与语义 → 权限及包内资源 → 运行前目标与代次。API 3 携带 Debug 能力时,支持 API 4 的新 Core 在 `requires.debugAdapters` 拒绝;旧 Core 保留自身原来的拒绝位置和优先级,不为草案改写历史结果。 -实际状态同样返回 JSON,区分 `unknown`、`supported`、`unsupported` 及原因。例如原生插件可以声明反汇编,但当前宿主未实现时,状态如 [native.capabilities.json](examples/native.capabilities.json),不会只凭清单点亮按钮。统一配置、可检查结果与动态确认可以同时存在。 +## 必需与可选 -## Schema 文件 +每个适配器只必填 `id`、`displayName`、`launch`;`launch` 只描述一个进程和一种传输。`process` 复用共享 `serverProcess` 的启动字段、模板、安装审查及校验,排除只适用于 LSP 的 `initializationOptions`。不要求后端、依赖、函数、流程或参数 schema。 -| 文件 | 责任 | +| 可选项 | 省略时的含义 | | --- | --- | -| [注册](debug-adapter-registration.draft.schema.json) | 依赖、导出、后端、目标匹配、能力与会话实现 | -| [JSON 组合](debug-composition.draft.schema.json) | 导入、导出、函数/宿主调用、步骤及类型化取值 | -| [配置](debug-configuration.draft.schema.json) | 现有 Run 配置解析后的标准 Debug 输入 | -| [启动方案](debug-start-plan.draft.schema.json) | prepare / ready / failed 与现有 DAP 配置 | -| [函数领域绑定](debug-function-binding.draft.schema.json) | 复用函数通道的 Debug 输入输出契约 | -| [有效能力状态](debug-capability-state.draft.schema.json) | 宿主计算并投影给双端的能力状态 | +| `adapterID` | DAP initialize 使用局部 `id`;Registry 身份始终是插件 ID 加局部 ID | +| `requests` | 只允许 `launch`;attach 必须显式开启 | +| `selectors` | 仅供显式选择,不自动匹配全部目标 | +| `configurationTypes` | 不认领导入配置的 `type` 别名 | +| `configurations.launch/attach` | 不提供额外默认参数、目标映射或参数 schema | +| `capabilities.disabled` | 标准能力默认全部跟随 DAP 的默认值、initialize 与后续 capabilities 事件 | + +局部适配器 ID 统一使用 `^[a-z][a-z0-9._-]{0,63}$`;插件 ID、语言 ID 沿用各自已有规则,它们不是同一种标识。身份、语言、DAP adapterID、导入 type、Run 配置 ID 和 sessionID 不相互替代。 + +## 固定启动声明,不引入工作流 + +`launch` 固定包含 `process` 和 `transport`: + +- `stdio`:适配器进程的标准输入输出直接传 DAP,stderr 仅记录诊断。 +- `tcpAnnounced`:从明确指定的 stdout/stderr 读取有界 UTF-8 行。字面量 `prefix` 后只接受端口或 `host:port`;IPv6 使用方括号,必须是 loopback。限制单行 4 KiB、总启动输出 1 MiB、连接准备 30 秒;未完整解出合法端点就不连接。没有 `jsDebugStandalone` 等按产品命名的解码档位。 +- `tcpPort`:连接本次适配器进程的固定 loopback 端口;进程先启动,端口占用则失败,不悄悄改端口。它不是 DAP attach 参数里的被调试程序端口。若无法证明连接对应本次启动的进程,平台应拒绝该传输,不公布支持。 + +TCP 启动期限只约束端口发现与连接,不限制整个调试会话。关闭、失败、取消和禁用都会关闭连接、清理本次创建的进程;已有共享服务和外部 attach 目标不属于这条进程清理链。 + +普通 process 沿用 `packaged`、`systemCommand`、Java/Node `runtime`;`runSelectedRuntime` 是共享进程版本 2 的新增分支,先支持 Python、Java、Node,取得 **Run 对同一目标选中的运行时**,然后执行声明的参数。没有独立 Debug 解释器偏好、隐式安装或静默切到 PATH。没有显式选择时沿用 Run 自己的发现链。一个包只声明一个 `serverProcess` 版本:包含该分支时为 2,并继续接受该包内其他进程的旧启动形式;完全不用新形式仍声明 1,避免无谓过滤旧宿主。 -已知契约由 Core 的版本目录提供 schema。插件自定义导出需提供成对的包内输入/结果 schema,引用只读包内资源;变更不兼容形状时升级契约版本。本目录没有替代 DAP 消息 schema,也不重新实现上游工程模型。 +已有 `${pluginDir}` 等启动模板保持原规则;此处永远指**声明该进程的当前包**。路径字段、模板展开及参数数组仍由共享解析器处理。`configuration.arguments` 是普通 JSON,不把其中的 `backendRef`、`$lease` 等同名字段解释为资源。此版没有资源引用输入、跨包租约或用户 JSON 中的隐藏句柄。 -## 保持已有行为与后续实现 +debugpy、lldb-dap 可以走 stdio,Delve/js-debug 可按真实启动方式选择 TCP;是否能完整调试仍要核对后端版本、端口输出和目标参数。Java 先由内置 Provider 接入 Registry,继续使用已有 JDT 集成,不把宿主服务暴露为第三方 JSON 字段。一个模型统一接入方式,不保证所有后端功能相同。 -用户确认优先保证插件好写和复用能力,允许通用适配器复杂度和 API 版本增加。正式接入时为依赖/导出、领域函数绑定、新权限及宿主原语分配明确版本,旧版本语义继续保留。不是在现有 API 3 或函数 v1/v2 下悄悄接受新字段;也不预占并行开发中的具体版本号。这一阶段只改变评审设计,现有 Build/VCS/UI/设置/Run API 不变。 +## 配置与能力 -Run 三层覆盖、配置 ID、导入参数与最终 `DebugLaunchConfiguration` 保持兼容。`targetBindings` 由宿主统一把目标事实映射到参数;重复显式字段报冲突,不能覆盖。Java 的准备动作继续走既有工程/构建流程和编译失败决策,使用 Run JDK;准备后从 JDT 读取新路径,调试结束不终止共享服务。 +保留现有 `DebugLaunchConfiguration`、Run 配置 ID、三层覆盖和导入参数。处理顺序是:适配器默认参数 → 现有 Run/导入/用户覆盖链 → 只补缺失的目标字段 → 可选参数 schema → Core 规范化。schema 的 `default` 是文档提示,实际默认值由 Core 实现。 -通用宿主原语示例 `debug.process.acquire`、`debug.process.acquireTcp`、`debug.session.plan` 目前也只是契约方向,需在实现时定义完整参数/结果、期限及所有权。TCP 例子的 `jsDebugStandalone` 指复用现有端口发现逻辑的解码档位,不代表可以信任任意日志地址。导入配置里的 backendRef 在入口被规范化为调用方资源描述并取得租约,不能按依赖包的局部 ID 误解析。最终方案跨包传递的是宿主签发的 processRef / endpointRef,这些引用绑定当前操作。launch 终止自己拥有的目标,attach 默认断开;失败和取消清理本次资源,插件及应用包只读。 +`targetBindings` 限定为 `program ← target.path`、`processId ← target.processID`、`cwd ← target.workingDirectory`;不允许把进程号当路径,也不引入任意表达式。如果所选目标缺少必需事实且显式参数也未提供,准备阶段失败,不启动进程。文件目标不会自动产生 `program`,插件需要选择映射或由现有 Run 配置提供参数;不能仅声明 selector 就声称能启动。 -`java.ready.json` 中的 `${exampleHostResolved...}` 只是避免写入机器绝对路径的展示占位值,实际结果必须是宿主已解析的值;它不引入新的字符串模板语法。 +路径身份和执行路径分开:工作区内源码的持久化身份仍为相对路径;Build/Run 可以提供用户已选择或授权的外部产物引用,平台在执行时解析为绝对路径。源码外构建和工作区外可执行文件无需伪造相对路径。本提案不新增 `workspacePath`、`configuration.id` 或 `target.configurationID` 的重复结构。 -新增下载或打包运行时的资源清单、工具链身份与复用验证,在实际新增资源时同步维护。本次没有下载资源,没有启动 Lithe 或后端进程,没有运行时跨平台验收证据。 +`capabilities.disabled` 只接受标准 DAP capability 名称或 `exceptionBreakpointFilters`,Core 按固定版本的 DAP 定义检查名称并映射到对应请求/数据。结构 schema 只检查名称形状,不能证明名称存在。completions、steppingGranularity、cancel 等随 DAP,而不是再维护一份静态支持列表。省略不隐藏功能,声明也不能让尚未实现该操作的宿主点亮按钮;会话取消和清理始终保留,不能用 suppression 关闭。 -离线校验覆盖 schema、正例、参数、局部引用和关键拒绝条件;依赖安装、图校验、函数授权、资源服务与两端执行器仍需实现。正式契约和 Core 同批落地,合并后同步 lithe-plugin-docs。 -架构理由见[对应 Agent Note](../../../.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md)。 +此版没有标准操作的 `source: function`,也没有公开扩展函数。Java 热替换保留现有类型化 `redefineClasses` 链路。将来只有先定义输入、输出、会话归属与错误语义的扩展才可能绑定函数,不能给任意标准能力填一个函数名。 + +## 动态 resolver 明确后置 + +本次**不开放 `resolver`、`backendRef`、`hostIntegration`、`preparation` 字段**。复杂内置适配器通过同一个内部 Provider 契约返回计划,不等于第三方可凭 JSON 调用 JDT。 + +本包私有 resolver 比跨插件调用范围小,但仍改变了“领域结果不走插件函数”的已落地决策。它是独立的后续 `debugAdapters` 版本:先修订函数决策、定义固定的 Debug 输入/结果及本包授权,再复用 `lithe/function/invoke`。旧 `backend: 1` 仍是全局、网页触发的进程,不能为了 Debug 改成工作区后端或要求空网页。 + +如需重新准备,后续结果只能引用宿主已解析的 Build/Run action 身份及版本,不接受任意字符串、脚本或再次进入 Registry 的命令。宿主执行成功后最多重入解析一次,第二次要求准备即拒绝;项目事实随后重新从拥有它的引擎读取。这个后续门槛不阻塞固定声明的 P1–P3。 + +## Schema 与 Core 校验分界 + +`semantic-rejections.draft.json` 以一个合成基线加 `set`/`remove` 描述单个拒绝输入,沿用已有 `invalid-manifests.json` 的 JSON Pointer fixture 约定,不新建编辑语法;路径只用于构造测试数据,**不是插件工作流语法**。每条记录标注校验层和预期稳定错误码,权限缺失沿用已有 `plugin.permission.undeclared`,新增 Debug 错误码仍为拟定;`expected.field` 是标准化后的错误位置,重复 ID 固定指向第二个条目。Core 计划也须验证输入目标快照与字段类型;无法从参数 schema 推断的后端必需字段,仍由 DAP 返回明确错误。无关基础清单字段按正式契约补足,不假装这些投影能安装。 + +| 规则 | 必须拒绝的情况 | Fixture | +| --- | --- | --- | +| S01 关闭新字段集合 | 旧依赖/导出/steps、resolver 或 hostIntegration 回流 | `removed-platform-fields`、`removed-resolver`、`removed-host-integration`、`removed-workflow` | +| S02 已知映射及实现 | program 绑定进程号,或标准能力绑定函数 | `program-from-process-id`、`function-for-step-back` | +| C01 版本入口 | API 3 使用 Debug 或新权限;Core/宿主不支持所需版本 | `old-api-debug`、`missing-host-capability` | +| C02 requires 精确匹配 | 少列 Debug/进程能力,或普通进程虚报版本 2 | `missing-debug-requirement`、`missing-process-requirement`、`unused-process-v2` | +| C03 身份唯一 | 同一插件重复 adapter id | `duplicate-adapter-id` | +| C04 请求与授权一致 | 缺 debug.launch、attach 缺授权、配置声明不支持的请求 | `missing-launch-permission`、`attach-without-permission`、`unsupported-request-config` | +| C05 运行时契约 | runSelectedRuntime 却声明 serverProcess 1,或选择结果失效 | `selected-runtime-v1`、`stale-selected-runtime` | +| C06 名称存在 | 拼写形似 DAP,但不是固定定义里的能力 | `unknown-dap-capability` | +| C07 目标事实完整 | program 映射缺路径,且合并后也无显式 program | `missing-target-path` | +| C08 包内资源归属 | 参数 schema 的符号链接逃出包 | `escaping-parameters-schema` | +| C09 运行前再确认 | 插件注册代次或计划已过期 | `stale-registration` | + +移除后的跨依赖和 step 引用不再进入语义解释器,直接因未知字段被拒绝;并不代表实现了依赖图或流程引用检查。 + +**验证口径:**离线检查只能证明本草案 schema 合法,且结构层 fixture 有预期结果。C01–C09 的输入已列出,但没有对应新增 Core 实现或执行证据;不得把它们计为“已通过的 Core 拒绝用例”。正式落地时把这些 fixtures 迁到正式契约并接上 Core 测试,每条校验错误码、字段、优先级及无副作用;双端运行验证另外提供。 + +本次没有启动应用、后端或调试程序。契约与 Core 同批落地后,按仓库规则同步 `lithe-plugin-docs`;教程、SDK、示例只在该仓库维护,主仓库保留正式契约和回归 fixtures。 diff --git a/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json deleted file mode 100644 index 6b05fda40b..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-adapter-registration.draft.schema.json +++ /dev/null @@ -1,296 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-adapter-registration.draft.schema.json", - "title": "Debug adapter registration review draft", - "description": "Issue 1210 review artifact. Not an installable plugin manifest or an allocated plugin API version.", - "type": "object", - "additionalProperties": false, - "required": ["draftVersion", "pluginID"], - "anyOf": [ - { "required": ["debugAdapters"] }, - { "required": ["exports"] } - ], - "properties": { - "draftVersion": { "const": "1210-3" }, - "pluginID": { "$ref": "#/$defs/id" }, - "pluginDependencies": { - "description": "Plugin package dependencies, distinct from requires (host API capabilities) and upstream project dependencies.", - "type": "object", - "propertyNames": { "$ref": "#/$defs/id" }, - "additionalProperties": { "$ref": "debug-composition.draft.schema.json#/$defs/dependency" } - }, - "exports": { - "type": "object", - "minProperties": 1, - "propertyNames": { "$ref": "debug-composition.draft.schema.json#/$defs/id" }, - "additionalProperties": { "$ref": "debug-composition.draft.schema.json#/$defs/export" } - }, - "backends": { - "description": "Same-plugin DAP or plugin-function resources. Dependencies reuse their own resources; importers never copy their paths or private handles.", - "type": "object", - "minProperties": 1, - "propertyNames": { "$ref": "#/$defs/id" }, - "additionalProperties": { "$ref": "#/$defs/backend" } - }, - "debugAdapters": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/adapter" } - } - }, - "$defs": { - "id": { "type": "string", "pattern": "^[a-z][a-z0-9._-]*$" }, - "packagePath": { - "description": "Read-only package-relative path. The host also rejects escaping symlinks and invalid platform paths.", - "type": "string", - "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" - }, - "serverProcess": { - "description": "Reuse serverProcess:1 launch semantics without its LSP initializationOptions field.", - "$ref": "../../contracts/plugins/v1/plugin-manifest.schema.json#/$defs/serverProcess", - "propertyNames": { - "enum": ["launch", "arguments", "validationArguments", "runtimeDependencies"] - }, - "unevaluatedProperties": false - }, - "debugProcess": { - "oneOf": [ - { "$ref": "#/$defs/serverProcess" }, - { - "description": "Reuse a runtime exported by a declared plugin dependency, without copying that plugin's executable paths or discovery rules.", - "type": "object", - "additionalProperties": false, - "required": ["launch", "arguments"], - "properties": { - "launch": { - "type": "object", - "additionalProperties": false, - "required": ["kind", "use"], - "properties": { - "kind": { "const": "dependencyRuntime" }, - "use": { "$ref": "debug-composition.draft.schema.json#/$defs/import" } - } - }, - "arguments": { "type": "array", "items": { "type": "string" } } - } - } - ] - }, - "stdioTransport": { - "type": "object", - "additionalProperties": false, - "required": ["kind", "processRef"], - "properties": { - "kind": { "const": "stdio" }, - "processRef": { - "description": "Host-issued process lease, scoped to the declaring package and current operation. Safe to pass through composed dependency calls.", - "type": "string", - "minLength": 1 - } - } - }, - "selector": { - "description": "Selectors are ORed. Fields within a selector are ANDed. No priority or executable discovery runs during matching.", - "type": "object", - "additionalProperties": false, - "required": ["targetKinds"], - "properties": { - "targetKinds": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { "enum": ["file", "executable", "runTarget", "process", "connection"] } - }, - "languageIDs": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { "$ref": "#/$defs/id" } - } - } - }, - "request": { - "type": "object", - "additionalProperties": false, - "required": ["parametersSchema"], - "properties": { - "parametersSchema": { - "description": "Packaged Draft 2020-12 schema for parameters. Local package refs only; no network fetching.", - "$ref": "#/$defs/packagePath" - }, - "targetBindings": { - "description": "DAP argument name to a typed, host-resolved target value. Applied by the host after resolution for every backend kind. Conflicting arguments are rejected, never overwritten.", - "type": "object", - "minProperties": 1, - "propertyNames": { "type": "string", "minLength": 1 }, - "additionalProperties": { - "enum": ["target.path", "target.processID", "target.host", "target.port"] - } - } - } - }, - "backend": { - "oneOf": [ - { - "description": "Reuse a same-plugin language server owned by that plugin and negotiating litheFunctions. A host-owned shared server must instead stay behind its typed host-integration adapter.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "languageID"], - "properties": { - "kind": { "const": "languageServer" }, - "languageID": { "$ref": "#/$defs/id" } - } - }, - { - "description": "Reuse an existing typed host integration, such as JDT. The same-plugin language server must declare that integration.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "languageID", "integrationID"], - "properties": { - "kind": { "const": "hostIntegration" }, - "languageID": { "$ref": "#/$defs/id" }, - "integrationID": { "$ref": "#/$defs/id" } - } - }, - { - "description": "DAP or the existing plugin-function process protocol. No separate Debug RPC protocol or UI backend is required.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "protocol", "process", "lifetime"], - "properties": { - "kind": { "const": "process" }, - "protocol": { "enum": ["dap", "pluginFunctions"] }, - "process": { "$ref": "#/$defs/debugProcess" }, - "lifetime": { "enum": ["session", "workspace"] } - }, - "if": { "properties": { "protocol": { "const": "dap" } } }, - "then": { - "properties": { "lifetime": { "const": "session" } } - } - } - ] - }, - "capabilityID": { - "enum": [ - "sourceBreakpoints", "conditionalBreakpoints", "hitConditionalBreakpoints", "logPoints", - "functionBreakpoints", "dataBreakpoints", "exceptionInfo", "setVariable", "restart", - "terminate", "stepBack", "stepInTargets", "gotoTargets", "readMemory", "writeMemory", - "disassemble", "instructionBreakpoints", "instructionStepping", "hotCodeReplace" - ] - }, - "dapCapability": { - "description": "A standard operation can use DAP or a typed function binding. Host and permission checks apply to both.", - "oneOf": [ - { - "type": "object", - "additionalProperties": false, - "required": ["source"], - "properties": { "source": { "enum": ["dap", "disabled"] } } - }, - { "$ref": "#/$defs/functionCapability" } - ] - }, - "functionCapability": { - "type": "object", - "additionalProperties": false, - "required": ["source", "invoke"], - "properties": { - "source": { "const": "function" }, - "invoke": { "$ref": "debug-composition.draft.schema.json#/$defs/workflow" } - } - }, - "capabilities": { - "description": "Manifest policy. Omitted features are not exposed through this registration. Basic threads, stack, scopes, variables and execution remain the common DAP session contract.", - "type": "object", - "additionalProperties": false, - "properties": { - "sourceBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "conditionalBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "hitConditionalBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "logPoints": { "$ref": "#/$defs/dapCapability" }, - "functionBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "dataBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "exceptionInfo": { "$ref": "#/$defs/dapCapability" }, - "setVariable": { "$ref": "#/$defs/dapCapability" }, - "restart": { "$ref": "#/$defs/dapCapability" }, - "terminate": { "$ref": "#/$defs/dapCapability" }, - "stepBack": { "$ref": "#/$defs/dapCapability" }, - "stepInTargets": { "$ref": "#/$defs/dapCapability" }, - "gotoTargets": { "$ref": "#/$defs/dapCapability" }, - "readMemory": { "$ref": "#/$defs/dapCapability" }, - "writeMemory": { "$ref": "#/$defs/dapCapability" }, - "disassemble": { "$ref": "#/$defs/dapCapability" }, - "instructionBreakpoints": { "$ref": "#/$defs/dapCapability" }, - "instructionStepping": { "$ref": "#/$defs/dapCapability" }, - "hotCodeReplace": { - "oneOf": [ - { - "type": "object", - "additionalProperties": false, - "required": ["source"], - "properties": { "source": { "const": "disabled" } } - }, - { "$ref": "#/$defs/functionCapability" } - ] - } - } - }, - "adapter": { - "type": "object", - "additionalProperties": false, - "required": ["id", "displayName", "adapterID", "selectors", "requests", "capabilities", "session"], - "properties": { - "id": { "$ref": "#/$defs/id" }, - "displayName": { "type": "string", "minLength": 1 }, - "adapterID": { - "description": "DAP initialize.adapterID. Not a language ID, executable name, or global Provider identity.", - "type": "string", - "minLength": 1 - }, - "configurationTypes": { - "description": "Import aliases, for example launch.json type. Overlap requires ordinary Provider selection, not replacement.", - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { "type": "string", "minLength": 1 } - }, - "selectors": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/selector" } - }, - "platforms": { - "description": "Adapter host constraints, not debuggee architecture or runtime DAP capabilities.", - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["os", "architectures"], - "properties": { - "os": { "enum": ["macos", "windows"] }, - "architectures": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { "enum": ["arm64", "x86_64"] } - } - } - } - }, - "requests": { - "description": "Presence declares an available configuration shape, not the capabilities of a live DAP session.", - "type": "object", - "additionalProperties": false, - "minProperties": 1, - "properties": { - "launch": { "$ref": "#/$defs/request" }, - "attach": { "$ref": "#/$defs/request" } - } - }, - "capabilities": { "$ref": "#/$defs/capabilities" }, - "session": { "$ref": "debug-composition.draft.schema.json#/$defs/workflow" } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json new file mode 100644 index 0000000000..9612ed4af2 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json @@ -0,0 +1,207 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-adapters.draft.schema.json", + "title": "Proposed plugin.json debugAdapters capability block", + "description": "Review-only projection of plugin.json.debugAdapters, not a second manifest. API 4, debugAdapters 1 and serverProcess 2 are proposed, not implemented. Full-manifest permissions, requires and semantic validation are specified in README.md.", + "type": "object", + "additionalProperties": false, + "required": ["debugAdapters"], + "properties": { + "debugAdapters": { + "type": "array", + "minItems": 1, + "maxItems": 16, + "items": { "$ref": "#/$defs/adapter" } + } + }, + "$defs": { + "localID": { "type": "string", "pattern": "^[a-z][a-z0-9._-]{0,63}$" }, + "packagePath": { + "description": "Read-only package-relative path. Core must additionally reject escaping symlinks and platform-specific path escapes.", + "type": "string", + "minLength": 1, + "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" + }, + "serverProcessV1": { + "$ref": "../../contracts/plugins/v1/plugin-manifest.schema.json#/$defs/serverProcess", + "description": "Reuse existing launch fields and validation. LSP initializationOptions have no meaning for a DAP transport and are excluded.", + "propertyNames": { "enum": ["launch", "arguments", "validationArguments", "runtimeDependencies"] }, + "unevaluatedProperties": false + }, + "runSelectedRuntimeProcess": { + "description": "Proposed serverProcess 2 branch. Resolve through Run's selected runtime for this target, not a plugin dependency or a separate Debug runtime preference.", + "type": "object", + "additionalProperties": false, + "required": ["launch"], + "properties": { + "launch": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "tool"], + "properties": { + "kind": { "const": "runSelectedRuntime" }, + "tool": { "enum": ["python", "java", "node"] } + } + }, + "arguments": { "$ref": "../../contracts/plugins/v1/plugin-manifest.schema.json#/$defs/serverProcess/properties/arguments" }, + "validationArguments": { "$ref": "../../contracts/plugins/v1/plugin-manifest.schema.json#/$defs/serverProcess/properties/validationArguments" } + } + }, + "process": { + "oneOf": [ + { "$ref": "#/$defs/serverProcessV1" }, + { "$ref": "#/$defs/runSelectedRuntimeProcess" } + ] + }, + "launch": { + "type": "object", + "required": ["process", "transport"], + "properties": { "process": { "$ref": "#/$defs/process" } }, + "oneOf": [ + { + "properties": { "transport": { "const": "stdio" } } + }, + { + "required": ["endpoint"], + "properties": { + "transport": { "const": "tcpAnnounced" }, + "endpoint": { + "description": "A bounded line decoder, not an executable-name-specific format or a regex engine. Only loopback endpoints are accepted.", + "type": "object", + "additionalProperties": false, + "required": ["stream", "prefix", "value"], + "properties": { + "stream": { "enum": ["stdout", "stderr"] }, + "prefix": { "type": "string", "minLength": 1, "maxLength": 256, "pattern": "^[^\\r\\n]+$" }, + "value": { "enum": ["port", "hostPort"] } + } + } + } + }, + { + "required": ["endpoint"], + "properties": { + "transport": { "const": "tcpPort" }, + "endpoint": { + "description": "A fixed loopback port for this adapter process, not the debuggee's attach port. Conflicts fail explicitly; no automatic port substitution.", + "type": "object", + "additionalProperties": false, + "required": ["port"], + "properties": { "port": { "type": "integer", "minimum": 1, "maximum": 65535 } } + } + } + } + ], + "unevaluatedProperties": false + }, + "selector": { + "description": "Optional automatic matching: OR between selectors, AND between fields. Omission means explicit selection only, not a wildcard registration.", + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "targetKinds": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "enum": ["file", "executable", "runTarget", "process", "connection"] } + }, + "languageIDs": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "pattern": "^[a-z0-9+_-]+$" } + } + } + }, + "configuration": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "arguments": { + "description": "Adapter-owned default DAP arguments. Ordinary JSON data; no embedded references, expressions or resource handles are interpreted.", + "type": "object" + }, + "parametersSchema": { + "description": "Optional packaged schema for final merged DAP arguments, with local read-only refs only. Not a new Debug configuration file.", + "$ref": "#/$defs/packagePath" + }, + "targetBindings": { + "description": "Typed projections into known DAP fields. They only fill missing arguments; explicit values retain their existing precedence.", + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "program": { "const": "target.path" }, + "processId": { "const": "target.processID" }, + "cwd": { "const": "target.workingDirectory" } + } + } + } + }, + "capabilities": { + "description": "Optional suppression only. Disabled entries are standard DAP initialize capability names plus exceptionBreakpointFilters. Omission follows DAP; true values and function implementations are not accepted.", + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "disabled": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "pattern": "^(supports[A-Z][A-Za-z0-9]*|exceptionBreakpointFilters)$" + } + } + } + }, + "adapter": { + "type": "object", + "additionalProperties": false, + "required": ["id", "displayName", "launch"], + "properties": { + "id": { "$ref": "#/$defs/localID" }, + "displayName": { "type": "string", "minLength": 1, "maxLength": 128 }, + "adapterID": { + "description": "DAP initialize adapterID. Defaults to the local adapter id; never substitutes for the qualified Registry identity.", + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "requests": { + "description": "Defaults to launch only. Attach must be explicitly declared and separately authorized.", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "enum": ["launch", "attach"] }, + "default": ["launch"] + }, + "selectors": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/selector" } + }, + "configurationTypes": { + "description": "Optional imported launch.json type aliases. Ambiguity requires selection; aliases do not override another provider.", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } + }, + "configurations": { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "properties": { + "launch": { "$ref": "#/$defs/configuration" }, + "attach": { "$ref": "#/$defs/configuration" } + } + }, + "capabilities": { "$ref": "#/$defs/capabilities" }, + "launch": { "$ref": "#/$defs/launch" } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json deleted file mode 100644 index 4fc7d787c8..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-capability-state.draft.schema.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-capability-state.draft.schema.json", - "title": "Effective debug capabilities review draft", - "description": "A host-computed snapshot, never a plugin assertion. It combines manifest policy, negotiated DAP/backend capabilities, host implementation and granted permissions.", - "type": "object", - "additionalProperties": false, - "required": ["draftVersion", "sessionID", "revision", "capabilities"], - "properties": { - "draftVersion": { "const": "1210-3" }, - "sessionID": { "type": "string", "minLength": 1 }, - "revision": { - "description": "Monotonically increasing within a session. Stale snapshots and snapshots from a replaced session are ignored.", - "type": "integer", - "minimum": 1 - }, - "capabilities": { - "description": "Session snapshot. Omitted capability IDs are not exposed; they are never assumed supported. Each revision replaces the previous map.", - "type": "object", - "propertyNames": { - "$ref": "debug-adapter-registration.draft.schema.json#/$defs/capabilityID" - }, - "additionalProperties": { - "type": "object", - "additionalProperties": false, - "required": ["state", "source"], - "properties": { - "state": { "enum": ["unknown", "supported", "unsupported"] }, - "source": { "enum": ["dap", "backend", "manifest", "host", "permission", "target"] }, - "provider": { - "type": "object", - "additionalProperties": false, - "required": ["pluginID", "export"], - "properties": { - "pluginID": { "$ref": "debug-adapter-registration.draft.schema.json#/$defs/id" }, - "export": { "$ref": "debug-composition.draft.schema.json#/$defs/id" } - } - }, - "reason": { - "enum": [ - "not_negotiated", "adapter_unsupported", "backend_unsupported", "not_exposed", - "host_not_supported", "permission_denied", "not_applicable" - ] - } - }, - "allOf": [ - { - "if": { "properties": { "source": { "const": "backend" } } }, - "then": { "required": ["provider"] }, - "else": { "not": { "required": ["provider"] } } - }, - { - "if": { "properties": { "state": { "const": "supported" } } }, - "then": { - "not": { "required": ["reason"] }, - "properties": { "source": { "enum": ["dap", "backend"] } } - }, - "else": { "required": ["reason"] } - }, - { - "if": { "properties": { "state": { "const": "unknown" } } }, - "then": { - "properties": { - "source": { "enum": ["dap", "backend"] }, - "reason": { "const": "not_negotiated" } - } - } - } - ] - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json deleted file mode 100644 index d2110d89db..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-composition.draft.schema.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-composition.draft.schema.json", - "title": "Plugin dependency and JSON composition review draft", - "description": "Proposed reusable composition layer, not a change to existing private plugin-function protocol versions. All schema paths belong to their exporting package.", - "$ref": "#/$defs/workflow", - "$defs": { - "id": { "type": "string", "pattern": "^[a-z][a-zA-Z0-9._-]*$" }, - "schemaPath": { - "type": "string", - "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" - }, - "dependency": { - "type": "object", - "additionalProperties": false, - "required": ["pluginID", "minimumVersion"], - "properties": { - "pluginID": { "$ref": "#/$defs/id" }, - "minimumVersion": { "type": "string", "pattern": "^[0-9]+[.][0-9]+[.][0-9]+$" }, - "maximumVersionExclusive": { "type": "string", "pattern": "^[0-9]+[.][0-9]+[.][0-9]+$" } - } - }, - "import": { - "description": "Only a declared direct dependency's explicitly exported contract can be used. The dependency may compose its own dependencies internally.", - "type": "object", - "additionalProperties": false, - "required": ["dependency", "export", "contractVersion"], - "properties": { - "dependency": { "$ref": "#/$defs/id" }, - "export": { "$ref": "#/$defs/id" }, - "contractVersion": { "type": "integer", "minimum": 1 } - } - }, - "use": { - "oneOf": [ - { "$ref": "#/$defs/import" }, - { - "description": "A function on this package's backend, invoked through lithe/function/invoke. An export's domain contract validates its inputs and result.", - "type": "object", - "additionalProperties": false, - "required": ["backendRef", "functionID"], - "properties": { - "backendRef": { "$ref": "#/$defs/id" }, - "functionID": { - "type": "string", - "maxLength": 128, - "pattern": "^[a-z][a-zA-Z0-9]*(?:[.][a-z][a-zA-Z0-9]*)*$" - } - } - }, - { - "description": "A versioned host service used by a JSON workflow. The host, rather than a blocked backend handler, drives the workflow.", - "type": "object", - "additionalProperties": false, - "required": ["host", "version"], - "properties": { - "host": { "$ref": "#/$defs/id" }, - "version": { "type": "integer", "minimum": 1 } - } - } - ] - }, - "value": { - "description": "JSON values with typed whole-value bindings. $value is a JSON Pointer into input/context/completed steps, not an expression or string interpolation. $literal escapes reserved objects.", - "oneOf": [ - { "type": ["null", "boolean", "number", "string"] }, - { "type": "array", "items": { "$ref": "#/$defs/value" } }, - { - "type": "object", - "additionalProperties": false, - "required": ["$value"], - "properties": { - "$value": { - "type": "string", - "pattern": "^/(?:input|context|steps)(?:/(?:[^~/]|~[01])*)*$" - } - } - }, - { - "type": "object", - "additionalProperties": false, - "required": ["$literal"], - "properties": { "$literal": true } - }, - { - "type": "object", - "propertyNames": { "not": { "enum": ["$value", "$literal"] } }, - "additionalProperties": { "$ref": "#/$defs/value" } - } - ] - }, - "arguments": { - "type": "object", - "propertyNames": { "not": { "enum": ["$value", "$literal"] } }, - "additionalProperties": { "$ref": "#/$defs/value" } - }, - "call": { - "type": "object", - "additionalProperties": false, - "required": ["use"], - "properties": { - "use": { "$ref": "#/$defs/use" }, - "with": { "$ref": "#/$defs/arguments" } - } - }, - "workflow": { - "oneOf": [ - { "$ref": "#/$defs/call" }, - { - "description": "Bounded, sequential composition. A step may read only input/context and earlier results. A failure stops the flow and triggers owned-resource cleanup.", - "type": "object", - "additionalProperties": false, - "required": ["steps", "result"], - "properties": { - "steps": { - "type": "array", - "minItems": 1, - "maxItems": 64, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["id", "use"], - "properties": { - "id": { "$ref": "#/$defs/id" }, - "use": { "$ref": "#/$defs/use" }, - "with": { "$ref": "#/$defs/arguments" } - } - } - }, - "result": { "$ref": "#/$defs/value" } - } - } - ] - }, - "export": { - "description": "Public, typed dependency surface. This does not publish a plugin's private runtime function registry.", - "type": "object", - "additionalProperties": false, - "required": ["contract", "implementation"], - "properties": { - "contract": { - "description": "Known contracts resolve through Core's versioned catalog. Custom IDs must supply both packaged schemas; changing either schema incompatibly requires a contract version change.", - "type": "object", - "additionalProperties": false, - "required": ["id", "version"], - "properties": { - "id": { "$ref": "#/$defs/id" }, - "version": { "type": "integer", "minimum": 1 }, - "inputSchema": { "$ref": "#/$defs/schemaPath" }, - "resultSchema": { "$ref": "#/$defs/schemaPath" } - }, - "dependentRequired": { - "inputSchema": ["resultSchema"], - "resultSchema": ["inputSchema"] - } - }, - "implementation": { "$ref": "#/$defs/workflow" } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json deleted file mode 100644 index 10db9d29f1..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-configuration.draft.schema.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-configuration.draft.schema.json", - "title": "Debug configuration review draft", - "description": "Normalized input after existing Run configuration resolution. This is not a replacement workspace file format.", - "type": "object", - "additionalProperties": false, - "required": ["draftVersion", "id", "name", "request", "target", "parameters"], - "properties": { - "draftVersion": { "const": "1210-3" }, - "id": { "$ref": "#/$defs/reference" }, - "name": { "type": "string", "minLength": 1 }, - "provider": { - "type": "object", - "additionalProperties": false, - "required": ["pluginID", "id"], - "properties": { - "pluginID": { "$ref": "#/$defs/reference" }, - "id": { "$ref": "#/$defs/reference" } - } - }, - "request": { "enum": ["launch", "attach"] }, - "target": { "$ref": "#/$defs/target" }, - "parameters": { - "description": "Validated against the selected Provider's packaged request schema. Unknown upstream fields are preserved by import, not silently discarded.", - "type": "object" - }, - "steppingFilters": { "$ref": "#/$defs/steppingFilters" } - }, - "$defs": { - "reference": { "type": "string", "minLength": 1 }, - "workspacePath": { - "description": "Workspace-relative identity. Native conversion, symlink checks and external-resource authorization belong to the host.", - "type": "string", - "pattern": "^(?!/)(?!.*(?:^|/)[.]{1,2}(?:/|$))[^\\\\:\\u0000]+$" - }, - "target": { - "oneOf": [ - { - "type": "object", - "additionalProperties": false, - "required": ["kind", "path"], - "properties": { - "kind": { "enum": ["file", "executable"] }, - "path": { "$ref": "#/$defs/workspacePath" }, - "languageID": { "$ref": "#/$defs/reference" } - } - }, - { - "description": "Existing Run identity, including upstream-owned build products and project targets.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "configurationID"], - "properties": { - "kind": { "const": "runTarget" }, - "configurationID": { "$ref": "#/$defs/reference" }, - "languageID": { "$ref": "#/$defs/reference" } - } - }, - { - "description": "Host-issued process reference, valid only in the captured workspace/operation. Never persisted or inferred from a process name.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "processRef"], - "properties": { - "kind": { "const": "process" }, - "processRef": { "$ref": "#/$defs/reference" }, - "languageID": { "$ref": "#/$defs/reference" } - } - }, - { - "description": "Host-authorized debuggee connection, distinct from the DAP adapter transport. Transient; contains no credentials.", - "type": "object", - "additionalProperties": false, - "required": ["kind", "connectionRef"], - "properties": { - "kind": { "const": "connection" }, - "connectionRef": { "$ref": "#/$defs/reference" }, - "languageID": { "$ref": "#/$defs/reference" } - } - } - ] - }, - "steppingFilters": { - "description": "Existing DebugSteppingFilters fields and omission semantics are retained.", - "type": "object", - "additionalProperties": false, - "properties": { - "classNameFilters": { "type": "array", "items": { "type": "string" } }, - "skipSynthetics": { "type": "boolean" }, - "skipStaticInitializers": { "type": "boolean" }, - "skipConstructors": { "type": "boolean" }, - "hideFilteredStackFrames": { "type": "boolean" } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json deleted file mode 100644 index b938832116..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-function-binding.draft.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-function-binding.draft.schema.json", - "title": "Debug contracts on the existing plugin-function transport review draft", - "description": "Versioned domain payloads bound by exports and decoded by Core. Reuses lithe/function/invoke, never a new Debug RPC transport. Dependency routing is a proposed host feature; private function protocol versions 1/2 remain unchanged.", - "$defs": { - "resolveInput": { - "type": "object", - "additionalProperties": false, - "required": ["contextToken", "configuration"], - "properties": { - "contextToken": { "type": "string", "minLength": 1 }, - "configuration": { "$ref": "debug-configuration.draft.schema.json" } - } - }, - "resolveResult": { "$ref": "debug-start-plan.draft.schema.json" }, - "hotCodeReplaceInput": { - "type": "object", - "additionalProperties": false, - "required": ["contextToken", "sessionID"], - "properties": { - "contextToken": { "type": "string", "minLength": 1 }, - "sessionID": { "type": "string", "minLength": 1 } - } - }, - "hotCodeReplaceResult": { - "type": "object", - "additionalProperties": false, - "required": ["classes"], - "properties": { - "classes": { "type": "array", "items": { "type": "string", "minLength": 1 } } - } - } - }, - "$ref": "#/$defs/resolveInput" -} diff --git a/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json deleted file mode 100644 index 39c890daba..0000000000 --- a/shared/proposals/debug-adapters-1210/debug-start-plan.draft.schema.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://lithe.invalid/proposals/1210/debug-start-plan.draft.schema.json", - "title": "Debug start plan review draft", - "description": "A result from the declarative resolver or a dynamic Provider. The host validates ownership, trust, references and freshness before execution.", - "type": "object", - "required": ["draftVersion", "operationID", "contextToken", "outcome"], - "properties": { - "draftVersion": { "const": "1210-3" }, - "operationID": { "type": "string", "minLength": 1 }, - "contextToken": { - "description": "Host-issued reference binding workspace, configuration snapshot, plugin version and activation generation. Not authority granted by the Provider.", - "type": "string", - "minLength": 1 - }, - "outcome": { "enum": ["prepare", "ready", "failed"] } - }, - "oneOf": [ - { - "required": ["preparation"], - "properties": { - "outcome": { "const": "prepare" }, - "preparation": { - "description": "Ordered references to approved existing Build/Run preparation actions. Resolve again after successful completion; never reuse pre-build paths.", - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { "type": "string", "minLength": 1 } - } - } - }, - { - "required": ["transport", "configuration"], - "properties": { - "outcome": { "const": "ready" }, - "transport": { - "oneOf": [ - { "$ref": "debug-adapter-registration.draft.schema.json#/$defs/stdioTransport" }, - { - "type": "object", - "additionalProperties": false, - "required": ["kind", "endpointRef"], - "properties": { - "kind": { "const": "tcp" }, - "endpointRef": { - "description": "Host-issued lease for an authorized DAP endpoint, including cleanup ownership. A Provider cannot substitute an arbitrary address.", - "type": "string", - "minLength": 1 - } - } - } - ] - }, - "configuration": { - "description": "Existing DebugLaunchConfiguration shape. adapterID comes from the registration, never from executable-name inference.", - "type": "object", - "additionalProperties": false, - "required": ["name", "request", "arguments"], - "properties": { - "name": { "type": "string", "minLength": 1 }, - "request": { "enum": ["launch", "attach"] }, - "arguments": { "type": "object" }, - "steppingFilters": { "$ref": "debug-configuration.draft.schema.json#/$defs/steppingFilters" } - } - } - } - }, - { - "required": ["error"], - "properties": { - "outcome": { "const": "failed" }, - "error": { - "type": "object", - "additionalProperties": false, - "required": ["code", "message"], - "properties": { - "code": { - "enum": ["invalid_request", "permission_denied", "not_supported", "runtime_missing", "process_start_failed", "process_failed", "cancelled", "timed_out", "unknown"] - }, - "message": { "type": "string", "minLength": 1 }, - "details": { "type": "object" } - } - } - } - } - ], - "unevaluatedProperties": false -} diff --git a/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json b/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json deleted file mode 100644 index 64a0d7cdbe..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/dap-runtime.library.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.dap-runtime", - "exports": { - "stdioSession": { - "contract": { "id": "debug.session.stdio", "version": 1 }, - "implementation": { - "steps": [ - { - "id": "adapter", - "use": { "host": "debug.process.acquire", "version": 1 }, - "with": { "adapter": { "$value": "/input/adapter" } } - }, - { - "id": "plan", - "use": { "host": "debug.session.plan", "version": 1 }, - "with": { - "configuration": { "$value": "/input/configuration" }, - "transport": { - "kind": "stdio", - "processRef": { "$value": "/steps/adapter/processRef" } - } - } - } - ], - "result": { "$value": "/steps/plan" } - } - }, - "announcedTcpSession": { - "contract": { "id": "debug.session.announced-tcp", "version": 1 }, - "implementation": { - "steps": [ - { - "id": "endpoint", - "use": { "host": "debug.process.acquireTcp", "version": 1 }, - "with": { - "adapter": { "$value": "/input/adapter" }, - "endpointFormat": { "$value": "/input/endpointFormat" } - } - }, - { - "id": "plan", - "use": { "host": "debug.session.plan", "version": 1 }, - "with": { - "configuration": { "$value": "/input/configuration" }, - "transport": { - "kind": "tcp", - "endpointRef": { "$value": "/steps/endpoint/endpointRef" } - } - } - } - ], - "result": { "$value": "/steps/plan" } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json b/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json deleted file mode 100644 index ade823ec36..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java-runtime.library.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.java-runtime", - "pluginDependencies": { - "project": { - "pluginID": "example.java-project-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "backends": { - "jdt": { "kind": "hostIntegration", "languageID": "java", "integrationID": "jdt" } - }, - "exports": { - "debugSession": { - "contract": { "id": "debug.session.resolve", "version": 1 }, - "implementation": { - "steps": [ - { - "id": "target", - "use": { "dependency": "project", "export": "prepareDebugTarget", "contractVersion": 1 }, - "with": { "configuration": { "$value": "/input/configuration" } } - }, - { - "id": "session", - "use": { "backendRef": "jdt", "functionID": "debug.resolve" }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "configuration": { "$value": "/input/configuration" }, - "target": { "$value": "/steps/target" } - } - } - ], - "result": { "$value": "/steps/session" } - } - }, - "hotCodeReplace": { - "contract": { "id": "debug.hot-code-replace", "version": 1 }, - "implementation": { - "use": { "backendRef": "jdt", "functionID": "debug.hotCodeReplace" }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "sessionID": { "$value": "/input/sessionID" } - } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.capabilities.json b/shared/proposals/debug-adapters-1210/examples/java.capabilities.json deleted file mode 100644 index 2c80adcf28..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.capabilities.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "draftVersion": "1210-3", - "sessionID": "example-java-session", - "revision": 1, - "capabilities": { - "sourceBreakpoints": { - "state": "unknown", - "source": "dap", - "reason": "not_negotiated" - }, - "hotCodeReplace": { - "state": "unknown", - "source": "backend", - "reason": "not_negotiated", - "provider": { - "pluginID": "example.java-runtime", - "export": "hotCodeReplace" - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.configuration.json b/shared/proposals/debug-adapters-1210/examples/java.configuration.json deleted file mode 100644 index 851ff1e924..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.configuration.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "draftVersion": "1210-3", - "id": "example-run-java-main", - "name": "Java main", - "provider": { - "pluginID": "example.java-support", - "id": "java-debug" - }, - "request": "launch", - "target": { - "kind": "runTarget", - "configurationID": "example-run-java-main", - "languageID": "java" - }, - "parameters": { - "args": "--verbose", - "stopOnEntry": false - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.function-call.json b/shared/proposals/debug-adapters-1210/examples/java.function-call.json deleted file mode 100644 index f2175bdd15..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.function-call.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "method": "lithe/function/invoke", - "params": { - "functionID": "debug.resolve", - "operationID": "example-core-backend-operation", - "params": { - "contextToken": "example-host-authorized-context", - "configuration": { - "draftVersion": "1210-3", - "id": "example-run-java-main", - "name": "Java main", - "request": "launch", - "target": { "kind": "runTarget", "configurationID": "example-run-java-main", "languageID": "java" }, - "parameters": {} - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.prepare.json b/shared/proposals/debug-adapters-1210/examples/java.prepare.json deleted file mode 100644 index bd0c0aeed1..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.prepare.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "draftVersion": "1210-3", - "operationID": "example-debug-operation", - "contextToken": "example-host-context-before-build", - "outcome": "prepare", - "preparation": [ - "example-host-java-build-action" - ] -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.ready.json b/shared/proposals/debug-adapters-1210/examples/java.ready.json deleted file mode 100644 index 99586a1b3c..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.ready.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "draftVersion": "1210-3", - "operationID": "example-debug-operation", - "contextToken": "example-host-context-after-build", - "outcome": "ready", - "transport": { - "kind": "tcp", - "endpointRef": "example-host-jdt-dap-endpoint" - }, - "configuration": { - "name": "Java main", - "request": "launch", - "arguments": { - "mainClass": "example.Main", - "projectName": "example-project", - "classPaths": [ - "${exampleHostResolvedClassPath}" - ], - "javaExec": "${exampleHostResolvedRunJavaExecutable}", - "args": "--verbose", - "stopOnEntry": false - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/java.registration.json b/shared/proposals/debug-adapters-1210/examples/java.registration.json deleted file mode 100644 index abded8d91c..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/java.registration.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.java-support", - "pluginDependencies": { - "java": { - "pluginID": "example.java-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "debugAdapters": [ - { - "id": "java-debug", - "displayName": "Java (JDT)", - "adapterID": "java", - "configurationTypes": [ - "java" - ], - "selectors": [ - { - "targetKinds": [ - "file", - "runTarget" - ], - "languageIDs": [ - "java" - ] - } - ], - "requests": { - "launch": { - "parametersSchema": "schemas/java-launch.schema.json" - } - }, - "capabilities": { - "sourceBreakpoints": { - "source": "dap" - }, - "conditionalBreakpoints": { - "source": "dap" - }, - "logPoints": { - "source": "dap" - }, - "exceptionInfo": { - "source": "dap" - }, - "setVariable": { - "source": "dap" - }, - "hotCodeReplace": { - "source": "function", - "invoke": { - "use": { - "dependency": "java", - "export": "hotCodeReplace", - "contractVersion": 1 - }, - "with": { - "contextToken": { - "$value": "/context/contextToken" - }, - "sessionID": { - "$value": "/input/sessionID" - } - } - } - } - }, - "session": { - "use": { - "dependency": "java", - "export": "debugSession", - "contractVersion": 1 - }, - "with": { - "contextToken": { - "$value": "/context/contextToken" - }, - "configuration": { - "$value": "/input/configuration" - } - } - } - } - ] -} diff --git a/shared/proposals/debug-adapters-1210/examples/native.capabilities.json b/shared/proposals/debug-adapters-1210/examples/native.capabilities.json deleted file mode 100644 index a63dfb1627..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/native.capabilities.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "draftVersion": "1210-3", - "sessionID": "example-native-session", - "revision": 2, - "capabilities": { - "sourceBreakpoints": { - "state": "supported", - "source": "dap" - }, - "readMemory": { - "state": "unsupported", - "source": "host", - "reason": "host_not_supported" - }, - "writeMemory": { - "state": "unsupported", - "source": "manifest", - "reason": "not_exposed" - }, - "disassemble": { - "state": "unsupported", - "source": "host", - "reason": "host_not_supported" - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/native.configuration.json b/shared/proposals/debug-adapters-1210/examples/native.configuration.json deleted file mode 100644 index 67b9db5322..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/native.configuration.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "draftVersion": "1210-3", - "id": "example-run-native-attach", - "name": "Attach native process", - "provider": { - "pluginID": "example.native-debug", - "id": "lldb" - }, - "request": "attach", - "target": { - "kind": "process", - "processRef": "example-host-process-lease" - }, - "parameters": {} -} diff --git a/shared/proposals/debug-adapters-1210/examples/native.registration.json b/shared/proposals/debug-adapters-1210/examples/native.registration.json deleted file mode 100644 index cd61f82c61..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/native.registration.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.native-debug", - "pluginDependencies": { - "dap": { - "pluginID": "example.dap-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "backends": { - "adapter": { - "kind": "process", - "protocol": "dap", - "lifetime": "session", - "process": { - "launch": { - "kind": "systemCommand", - "commands": [ - "lldb-dap" - ] - }, - "arguments": [] - } - } - }, - "debugAdapters": [ - { - "id": "lldb", - "displayName": "Native (LLDB DAP)", - "adapterID": "lldb-dap", - "configurationTypes": [ - "lldb-dap" - ], - "selectors": [ - { - "targetKinds": [ - "executable", - "runTarget" - ], - "languageIDs": [ - "c", - "cpp", - "rust", - "asm" - ] - }, - { - "targetKinds": [ - "executable", - "process" - ] - } - ], - "requests": { - "launch": { - "parametersSchema": "schemas/native-launch.schema.json", - "targetBindings": { - "program": "target.path" - } - }, - "attach": { - "parametersSchema": "schemas/native-attach.schema.json", - "targetBindings": { - "pid": "target.processID" - } - } - }, - "capabilities": { - "sourceBreakpoints": { - "source": "dap" - }, - "conditionalBreakpoints": { - "source": "dap" - }, - "functionBreakpoints": { - "source": "dap" - }, - "dataBreakpoints": { - "source": "dap" - }, - "readMemory": { - "source": "dap" - }, - "disassemble": { - "source": "dap" - }, - "instructionBreakpoints": { - "source": "dap" - }, - "instructionStepping": { - "source": "dap" - }, - "writeMemory": { - "source": "disabled" - } - }, - "session": { - "use": { - "dependency": "dap", - "export": "stdioSession", - "contractVersion": 1 - }, - "with": { - "adapter": { - "backendRef": "adapter" - }, - "configuration": { - "$value": "/input/configuration" - } - } - } - } - ] -} diff --git a/shared/proposals/debug-adapters-1210/examples/node.registration.json b/shared/proposals/debug-adapters-1210/examples/node.registration.json deleted file mode 100644 index 6786134d1c..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/node.registration.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.js-debug", - "pluginDependencies": { - "node": { - "pluginID": "example.node-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - }, - "dap": { - "pluginID": "example.dap-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "backends": { - "adapter": { - "kind": "process", - "protocol": "dap", - "lifetime": "session", - "process": { - "launch": { - "kind": "dependencyRuntime", - "use": { - "dependency": "node", - "export": "selectedRuntime", - "contractVersion": 1 - } - }, - "arguments": ["${pluginDir}/adapter/dapDebugServer.js"] - } - } - }, - "debugAdapters": [ - { - "id": "js-debug", - "displayName": "JavaScript / TypeScript", - "adapterID": "pwa-node", - "configurationTypes": [ - "pwa-node", - "node" - ], - "selectors": [ - { - "targetKinds": [ - "file", - "runTarget" - ], - "languageIDs": [ - "javascript", - "typescript" - ] - } - ], - "requests": { - "launch": { - "parametersSchema": "schemas/node-launch.schema.json" - } - }, - "capabilities": { - "sourceBreakpoints": { - "source": "dap" - }, - "conditionalBreakpoints": { - "source": "dap" - }, - "logPoints": { - "source": "dap" - }, - "exceptionInfo": { - "source": "dap" - }, - "restart": { - "source": "dap" - } - }, - "session": { - "use": { - "dependency": "dap", - "export": "announcedTcpSession", - "contractVersion": 1 - }, - "with": { - "adapter": { - "backendRef": "adapter" - }, - "configuration": { - "$value": "/input/configuration" - }, - "endpointFormat": "jsDebugStandalone" - } - } - } - ] -} diff --git a/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json b/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json deleted file mode 100644 index ce7d957a6a..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/plugin-functions.library.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.custom-debug-runtime", - "backends": { - "resolver": { - "kind": "process", - "protocol": "pluginFunctions", - "lifetime": "workspace", - "process": { - "launch": { "kind": "runtime", "tool": "node", "entry": "backend/debug.mjs" } - } - } - }, - "exports": { - "debugSession": { - "contract": { "id": "debug.session.resolve", "version": 1 }, - "implementation": { - "use": { "backendRef": "resolver", "functionID": "debug.resolve" }, - "with": { - "contextToken": { "$value": "/context/contextToken" }, - "configuration": { "$value": "/input/configuration" } - } - } - } - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/python.configuration.json b/shared/proposals/debug-adapters-1210/examples/python.configuration.json deleted file mode 100644 index 7869bee6f4..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/python.configuration.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "draftVersion": "1210-3", - "id": "example-run-python-main", - "name": "Python main", - "provider": { - "pluginID": "example.python-debug", - "id": "debugpy" - }, - "request": "launch", - "target": { - "kind": "file", - "path": "src/main.py", - "languageID": "python" - }, - "parameters": { - "args": [ - "--verbose" - ], - "justMyCode": true, - "console": "integratedTerminal" - } -} diff --git a/shared/proposals/debug-adapters-1210/examples/python.registration.json b/shared/proposals/debug-adapters-1210/examples/python.registration.json deleted file mode 100644 index 390bec32f0..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/python.registration.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "draftVersion": "1210-3", - "pluginID": "example.python-debug", - "pluginDependencies": { - "python": { - "pluginID": "example.python-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - }, - "dap": { - "pluginID": "example.dap-runtime", - "minimumVersion": "1.0.0", - "maximumVersionExclusive": "2.0.0" - } - }, - "backends": { - "adapter": { - "kind": "process", - "protocol": "dap", - "lifetime": "session", - "process": { - "launch": { - "kind": "dependencyRuntime", - "use": { - "dependency": "python", - "export": "selectedInterpreter", - "contractVersion": 1 - } - }, - "arguments": [ - "-m", - "debugpy.adapter" - ] - } - } - }, - "debugAdapters": [ - { - "id": "debugpy", - "displayName": "Python (debugpy)", - "adapterID": "debugpy", - "configurationTypes": [ - "debugpy", - "python" - ], - "selectors": [ - { - "targetKinds": [ - "file", - "runTarget" - ], - "languageIDs": [ - "python" - ] - } - ], - "requests": { - "launch": { - "parametersSchema": "schemas/python-launch.schema.json", - "targetBindings": { - "program": "target.path" - } - } - }, - "capabilities": { - "sourceBreakpoints": { - "source": "dap" - }, - "conditionalBreakpoints": { - "source": "dap" - }, - "hitConditionalBreakpoints": { - "source": "dap" - }, - "logPoints": { - "source": "dap" - }, - "exceptionInfo": { - "source": "dap" - }, - "setVariable": { - "source": "dap" - }, - "restart": { - "source": "dap" - } - }, - "session": { - "use": { - "dependency": "dap", - "export": "stdioSession", - "contractVersion": 1 - }, - "with": { - "adapter": { - "backendRef": "adapter" - }, - "configuration": { - "$value": "/input/configuration" - } - } - } - } - ] -} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json deleted file mode 100644 index 35c6f2f944..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/schemas/java-launch.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Illustrative Java launch parameters resolved by the JDT integration", - "type": "object", - "properties": { - "args": { "type": "string" }, - "vmArgs": { "type": "string" }, - "stopOnEntry": { "type": "boolean" }, - "console": { "enum": ["internalConsole", "integratedTerminal", "externalTerminal"] } - }, - "additionalProperties": true -} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json deleted file mode 100644 index 54e48125b1..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/schemas/native-attach.schema.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Illustrative LLDB attach parameters, not the complete upstream schema", - "type": "object", - "properties": { - "waitFor": { "type": "boolean" } - }, - "not": { "required": ["pid"] }, - "additionalProperties": true -} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json deleted file mode 100644 index 6637e13194..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/schemas/native-launch.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Illustrative LLDB launch parameters, not the complete upstream schema", - "type": "object", - "properties": { - "args": { "type": "array", "items": { "type": "string" } }, - "stopOnEntry": { "type": "boolean" } - }, - "not": { "required": ["program"] }, - "additionalProperties": true -} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json deleted file mode 100644 index 2493736892..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/schemas/node-launch.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Illustrative js-debug parameters, not the complete upstream schema", - "type": "object", - "properties": { - "args": { "type": "array", "items": { "type": "string" } }, - "sourceMaps": { "type": "boolean" }, - "stopOnEntry": { "type": "boolean" } - }, - "additionalProperties": true -} diff --git a/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json b/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json deleted file mode 100644 index 00919554c0..0000000000 --- a/shared/proposals/debug-adapters-1210/examples/schemas/python-launch.schema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Illustrative debugpy launch parameters, not the complete upstream schema", - "type": "object", - "properties": { - "args": { "type": "array", "items": { "type": "string" } }, - "justMyCode": { "type": "boolean" }, - "stopOnEntry": { "type": "boolean" }, - "console": { "enum": ["internalConsole", "integratedTerminal", "externalTerminal"] } - }, - "not": { "required": ["program"] }, - "additionalProperties": true -} diff --git a/shared/proposals/debug-adapters-1210/semantic-rejections.draft.json b/shared/proposals/debug-adapters-1210/semantic-rejections.draft.json new file mode 100644 index 0000000000..5969e75842 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/semantic-rejections.draft.json @@ -0,0 +1,204 @@ +{ + "description": "Synthetic rejection specifications; edits use the same JSON Pointer fixture convention as invalid-manifests.json. This is not plugin syntax or an executable Core test suite.", + "baseline": { + "block": { + "debugAdapters": [ + { + "id": "synthetic", + "displayName": "Synthetic contract input", + "launch": { + "process": { + "launch": { + "kind": "packaged", + "path": "bin/synthetic" + } + }, + "transport": "stdio" + } + } + ] + }, + "context": { + "manifestMetadata": { + "pluginAPIVersion": 4, + "requires": { + "debugAdapters": 1, + "serverProcess": 1 + }, + "permissions": [ + "debug.launch" + ] + }, + "hostCapabilities": { + "debugAdapters": [ + 1 + ], + "serverProcess": [ + 1, + 2 + ] + }, + "registration": { + "generation": 1, + "currentGeneration": 1 + }, + "runtimeSelection": { + "generation": 1, + "currentGeneration": 1 + }, + "target": { + "kind": "file" + }, + "packageResources": [] + } + }, + "cases": [ + { + "id": "removed-platform-fields", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/pluginDependencies", "value": {"missing": {"pluginID": "dev.lithe.fixture.absent"}}}], + "expected": {"code": "plugin.manifest.invalid", "field": "pluginDependencies"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "removed-resolver", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/resolver", "value": {"backendRef": "absent", "functionID": "debug.resolve"}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].resolver"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "removed-host-integration", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/hostIntegration", "value": {"integrationID": "jdt"}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].hostIntegration"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "removed-workflow", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/launch/steps", "value": [{"id": "same"}, {"id": "same"}]}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].launch.steps"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "program-from-process-id", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/configurations", "value": {"launch": {"targetBindings": {"program": "target.processID"}}}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].configurations.launch.targetBindings.program"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "function-for-step-back", + "layer": "schema", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/capabilities", "value": {"stepBack": {"source": "function", "functionID": "synthetic.stepBack"}}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].capabilities.stepBack"}, + "executionStatus": "offlineShapeOnly" + }, + { + "id": "old-api-debug", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/context/manifestMetadata/pluginAPIVersion", "value": 3}], + "expected": {"code": "plugin.api.unsupported", "field": "requires.debugAdapters"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "missing-host-capability", + "layer": "coreManifest", + "edits": [{"op": "remove", "path": "/context/hostCapabilities/debugAdapters"}], + "expected": {"code": "plugin.api.unsupported", "field": "requires.debugAdapters"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "missing-debug-requirement", + "layer": "coreManifest", + "edits": [{"op": "remove", "path": "/context/manifestMetadata/requires/debugAdapters"}], + "expected": {"code": "plugin.manifest.invalid", "field": "requires.debugAdapters"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "missing-process-requirement", + "layer": "coreManifest", + "edits": [{"op": "remove", "path": "/context/manifestMetadata/requires/serverProcess"}], + "expected": {"code": "plugin.manifest.invalid", "field": "requires.serverProcess"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "unused-process-v2", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/context/manifestMetadata/requires/serverProcess", "value": 2}], + "expected": {"code": "plugin.manifest.invalid", "field": "requires.serverProcess"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "duplicate-adapter-id", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/block/debugAdapters", "value": [{"id": "synthetic", "displayName": "Synthetic contract input", "launch": {"process": {"launch": {"kind": "packaged", "path": "bin/synthetic"}}, "transport": "stdio"}}, {"id": "synthetic", "displayName": "Different title, same identity", "launch": {"process": {"launch": {"kind": "packaged", "path": "bin/synthetic"}}, "transport": "stdio"}}]}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[1].id"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "missing-launch-permission", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/context/manifestMetadata/permissions", "value": []}], + "expected": {"code": "plugin.permission.undeclared", "field": "permissions"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "attach-without-permission", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/requests", "value": ["launch", "attach"]}], + "expected": {"code": "plugin.permission.undeclared", "field": "permissions"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "unsupported-request-config", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/configurations", "value": {"attach": {"arguments": {"port": 30000}}}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].configurations.attach"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "selected-runtime-v1", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/launch/process", "value": {"launch": {"kind": "runSelectedRuntime", "tool": "python"}}}], + "expected": {"code": "plugin.manifest.invalid", "field": "requires.serverProcess"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "stale-selected-runtime", + "layer": "corePlan", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/launch/process", "value": {"launch": {"kind": "runSelectedRuntime", "tool": "python"}}}, {"op": "set", "path": "/context/manifestMetadata/requires/serverProcess", "value": 2}, {"op": "set", "path": "/context/runtimeSelection/currentGeneration", "value": 2}], + "expected": {"code": "debug.runtime.stale", "field": "runtimeSelection"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "unknown-dap-capability", + "layer": "coreManifest", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/capabilities", "value": {"disabled": ["supportsSyntheticUnknownRequest"]}}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].capabilities.disabled[0]"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "missing-target-path", + "layer": "corePlan", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/configurations", "value": {"launch": {"targetBindings": {"program": "target.path"}}}}], + "expected": {"code": "debug.target.invalid", "field": "target.path"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "escaping-parameters-schema", + "layer": "coreInstall", + "edits": [{"op": "set", "path": "/block/debugAdapters/0/configurations", "value": {"launch": {"parametersSchema": "schemas/parameters.json"}}}, {"op": "set", "path": "/context/packageResources", "value": [{"path": "schemas/parameters.json", "kind": "symlink", "target": "../../../outside/parameters.json"}]}], + "expected": {"code": "plugin.manifest.invalid", "field": "debugAdapters[0].configurations.launch.parametersSchema"}, + "executionStatus": "pendingCoreImplementation" + }, + { + "id": "stale-registration", + "layer": "corePlan", + "edits": [{"op": "set", "path": "/context/registration/currentGeneration", "value": 2}], + "expected": {"code": "debug.provider.stale", "field": "registration"}, + "executionStatus": "pendingCoreImplementation" + } + ] +} From 83612dd617d0146a2e6a8b415af9a8fc1bc77a5a Mon Sep 17 00:00:00 2001 From: Yao Jingxi <23722032@bjtu.edu.cn> Date: Sun, 25 Oct 2026 22:55:15 +0800 Subject: [PATCH 3/3] docs(debug): redesign #1210 around a unified debug engine (#1210) - Replace the incremental Registry note with a unified Rust Core DAP engine plan: one kernel for both platforms, Swift session and per-language factories removed after P0 baseline parity (P0-P5). - Define required / recommended / optional capability tiers; #1210 closes on the required tier plus one third-party adapter (GDB DAP or lldb-dap) on both platforms. - Turn the native projections note into an optional extensions note covering all optional groups (breakpoints, expressions, stepping, sources, native, modules). - Add a session projection v2 draft schema with accept/reject examples: optional source/line/column, string addresses, presentationHint passthrough, stop generation and capability snapshot. - Update README and public extension note links. --- ...lic-extension-contract-and-provider-api.md | 2 +- ...r-provider-and-declarative-registration.md | 156 ------------- .../2026-10-25-native-debug-projections.md | 49 ----- .../2026-10-25-optional-debug-extensions.md | 112 ++++++++++ ...ified-debug-engine-and-adapter-registry.md | 207 ++++++++++++++++++ .../proposals/debug-adapters-1210/README.md | 21 +- ...debug-session-projection.draft.schema.json | 176 +++++++++++++++ .../projection-v2-examples.draft.json | 151 +++++++++++++ 8 files changed, 662 insertions(+), 212 deletions(-) delete mode 100644 .agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md delete mode 100644 .agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md create mode 100644 .agents/notes/proposed/architecture/2026-10-25-optional-debug-extensions.md create mode 100644 .agents/notes/proposed/architecture/2026-10-25-unified-debug-engine-and-adapter-registry.md create mode 100644 shared/proposals/debug-adapters-1210/debug-session-projection.draft.schema.json create mode 100644 shared/proposals/debug-adapters-1210/projection-v2-examples.draft.json diff --git a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md index afdcd05dc8..8293df7b1e 100644 --- a/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md +++ b/.agents/notes/proposed/architecture/2026-10-13-public-extension-contract-and-provider-api.md @@ -32,7 +32,7 @@ PR #37 是第一阶段 UI Contribution(插件声明的界面入口)基础设 内置模块和插件尽量实现相同领域 Provider 契约。Build/Run/Test/Debug 等采用类型化 Registry(按能力类型登记和查询实现的目录),组合根负责装配通用适配器,不按新增插件名追加分支。先盘点并复用已有语言服务器、构建工具、运行/测试和 DAP(调试适配器协议)链路;上游拥有的项目、任务和依赖事实仍由原工具提供,避免再造一套解释器、工程模型或调试 UI。 -Debug 的最小声明、现有链路盘点、API 兼容性及 P1–P3 验收见[调试适配器 Registry 与第三方 DAP 接入](2026-10-25-debug-adapter-provider-and-declarative-registration.md),跟踪当前仓库的 [#1210](https://github.com/1lck/Lithe-IDEA/issues/1210)。插件依赖与导出另见[平台级独立提案](2026-10-25-plugin-dependencies-and-exports.md),原生指令和内存展示另见[后续投影提案](2026-10-25-native-debug-projections.md);两者不作为 #1210 的前置条件。这些提案没有开放新字段,也不改变其他领域 Provider 的设计。 +Debug 的统一内核、三层能力、插件声明与迁移验收见[统一调试内核与调试适配器 Registry](2026-10-25-unified-debug-engine-and-adapter-registry.md),跟踪当前仓库的 [#1210](https://github.com/1lck/Lithe-IDEA/issues/1210)。寄存器、内存、反汇编等可选能力另见[可选调试扩展](2026-10-25-optional-debug-extensions.md),插件依赖与导出另见[平台级独立提案](2026-10-25-plugin-dependencies-and-exports.md);两者都不作为 #1210 的前置条件。这些提案没有开放新字段,也不改变其他领域 Provider 的设计。 ### 通用 Services 与资源所有权 diff --git a/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md b/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md deleted file mode 100644 index 41947af7ac..0000000000 --- a/.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md +++ /dev/null @@ -1,156 +0,0 @@ -# Agent 笔记:调试适配器 Registry 与第三方 DAP 接入 - -状态:提议中 - -## 先说结论 - -[#1210](https://github.com/1lck/Lithe-IDEA/issues/1210) 只做两个目标:内置和第三方共用类型化 Registry(按稳定身份查找适配器的目录),第三方 DAP(Debug Adapter Protocol,编辑器与调试后端之间的标准协议)进入既有 Debug UI。插件在同一个 `plugin.json.debugAdapters` 里声明固定的进程和传输,匹配、参数映射及能力禁用都是可选项;不用理解依赖、导出或工作流。 - -依赖与跨包授权移到[插件平台独立提案](2026-10-25-plugin-dependencies-and-exports.md),原生指令和内存展示移到[独立后续提案](2026-10-25-native-debug-projections.md)。它们以及动态 resolver(运行前计算启动参数的可选函数)都不是本任务 P1–P3 的前置条件。本 PR 只提交设计,不改变已发布 API,也没有新增运行验证证据。 - -## 问题 - -### 现有系统可直接复用 - -以下源码盘点固定在 `preview` 提交 `e854cfd98e4a52fe5abacff2002efd9f68082da2`,说明代码责任,不代替平台验收。 - -| 入口 | 现有能力与本次动作 | -| --- | --- | -| `rust/lithe-core/src/debug/` | 已有 DAP 分帧、请求序列、状态、断点、变量、取消和反向终端请求;不另写 DAP 引擎 | -| `macos/Sources/LitheCoreContracts/Debug/` | 已有平台无关的会话、传输及启动配置;保留兼容入口,新增 Registry 身份 | -| `macos/Sources/LitheDebugModule/Runtime/DebugAdapterSessionManager.swift` | 已有多会话和停止管理;改为从 Registry 获取 Provider,保留事件及失效代次 | -| `macos/Sources/Lithe/Services/Debug/DebugAdapterRuntimeFactory.swift` | 目前按语言装配 stdio 及专用工厂;改为通用适配器加内置 Provider 注册 | -| `DebugLaunchConfigurationResolver.swift`、`DebugLaunchPreparationCoordinator.swift` | 保留 Run 参数来源、保存、工程准备及编译失败决策;不复制 Build/Run 项目模型 | -| `windows/tauri/src/features/debugger/`、`windows/tauri/src-tauri/src/debug.rs` | 独立接入同一共享契约和现有界面;平台继续负责进程、socket 与终端 | -| `shared/contracts/plugins/v1/` | 复用能力版本、进程启动、安装审查与插件生命周期;纯 Debug 无需声明语言或 UI | - -macOS 的 Java 走 Rust DAP,通用、Go 和 Node 仍有 Swift 会话路径。后者已有子会话行为,不能因为 Registry 新增就立即删除;先验证行为等价,再逐个迁移。 - -### 上游工具而不是新的调试引擎 - -- Java 复用 JDT LS 1.61.0 与 Java Debug Server 0.53.2(`third_party/jdtls/manifest.json`),工程路径、主类与测试事实继续来自 JDT,目标 JVM 使用 Run 选中的 JDK。 -- Python 复用 `debugpy.adapter`;解释器与虚拟环境来自 Run,不在调试时静默安装。当前代码未统一固定 debugpy 版本,实际接入需记录兼容范围。 -- JavaScript/TypeScript 复用开源 `vscode-js-debug` standalone server;Go 复用 Delve DAP。现有 TCP、source map、终端及子会话行为是迁移基线,后端版本仍需单独核实。 -- 已有 Rust 的 LLDB 启动可注册为内置 Provider;`lldb-dap` 或具备 DAP 的 GDB 可作为普通第三方适配器。GCC 是编译器,目标与符号来自 Build/Run,而不是增加一个名叫 GCC 的调试引擎。 - -本任务统一发现与接入方式,不承诺同一个模型让所有后端具有完全相同的能力。新增下载、打包资源及上游升级不是本设计 PR 的内容。 - -## 提案 - -### 1. 只增加 Debug 能力,不建立插件平台 - -沿用 [Build 的能力块与共享进程设计](../../implemented/architecture/2026-10-17-build-system-plugin-contract.md)和 [VCS 的运行时协商设计](2026-10-22-unified-vcs-provider-model.md)。完整清单只有一个,Debug 块只声明身份、启动前需要的事实及可选策略;能力状态由会话协商,不把 `supportsX` 全抄进清单。 - -唯一的[评审 schema](../../../../shared/proposals/debug-adapters-1210/debug-adapters.draft.schema.json)及[字段边界](../../../../shared/proposals/debug-adapters-1210/README.md)保存在 `shared/proposals/`,并非正式插件契约。必需项仅为身份、显示名和固定 launch;无需依赖、导出、函数服务、步骤或额外配置文件。普通 JSON 参数不会被当作资源引用解释。 - -选择拟定的 API 4、新 `debugAdapters: 1` 能力和 `debug.launch` / `debug.attach` 权限。普通进程沿用 `serverProcess: 1`;Run 选中运行时作为共享 `serverProcess: 2` 分支,由共享进程解析器拥有。这样 Python 不需要依赖平台才能用正确解释器,也不会在进程版本 1 下悄悄扩大支持范围。 - -这是待评审编号,不代表宿主支持;实施前核对编号是否被占用。API 1/2/3 和未使用 Debug 的能力原样保留。新增权限属于基础 API 演进,不能仅靠 `requires.debugAdapters` 绕过基础版本。安装、市场与运行前检查继续使用同一 `hostCapabilities`,只在宿主确实能运行时发布支持。 - -### 2. Registry 统一身份和选择,不吞并配置 - -内置 Provider 和第三方声明先转成同一种类型化描述,再进入 Registry。第三方身份由插件 ID 与局部 adapter ID 组成,内置身份使用宿主保留空间;DAP adapterID、语言、配置 type、Run 配置 ID 和会话 ID 分开。 - -选择顺序固定为配置显式选择、工作区已保存关联、匹配后的唯一候选。多个候选交给用户选择,列表按稳定身份排序,不让插件自报优先级抢占。缺省 selectors 表示只接受显式选择;发现阶段不执行程序。重复身份拒绝注册,选择项不可用时显示原因,不静默换后端。 - -原有 Run 配置 ID、三层覆盖、导入参数与 `DebugLaunchConfiguration` 不变。声明默认参数后仍使用既有覆盖链,目标映射只补空缺值,绝不覆盖显式 program、args 或 classpath。对外部构建产物使用 Build/Run 的授权目标引用,平台解析执行路径;不要求所有目标都能写成工作区相对路径。 - -### 3. 固定启动形状足够覆盖基础 DAP - -`launch.process` 共用现有 ServerProcess 的数据类型、校验、模板、工具发现及安装审查;`launch.transport` 为 stdio、公告端点 TCP 或固定端口 TCP。不引入通用 workflow、JSON Pointer 求值、宿主原语目录或按后端名选择的端口解析器。 - -公告端点使用字面量前缀和端口/hostPort 解码,限定 loopback、输出预算和期限。固定端口需检查占用与本次进程归属,不能连接到碰巧在同一端口的外部服务。平台未实现某种传输时明确拒绝,不因为 Core 能解析就发布支持。 - -Python/Java/Node 的 `runSelectedRuntime` 按同一目标复用 Run 选择结果,不增加第二套 runtime 设置;其他现有 packaged/system/runtime 分支保持旧含义。`${pluginDir}` 属于声明该进程的包,配置参数仍是普通 JSON。此版没有跨包可执行引用或对参数里特殊键名的猜测。 - -### 4. 保留函数与宿主集成边界 - -Java 先作为内置 Provider 注册,继续走既有 JDT 工程准备、测试、热替换及生命周期;第三方 Debug JSON 不提供 `hostIntegration` 入口。宿主已知的内置实现可以注册,不等于允许每个新插件在组合根添加名称判断。 - -[已落地函数决策](../../implemented/architecture/2026-10-20-plugin-function-contract.md)保持不变:函数私有、领域结果类型化、后端不得请求宿主再次进入领域注册表。此版撤回跨插件函数、exports 和任意标准能力的函数实现,不修改那份已实现 Note 来声称新机制已生效。 - -私有 resolver 也不是现成能力:后续独立版本先明确领域输入/结果、进程归属、权限和取消,修订函数决策后再开放。若结果需要 Build/Run 准备,只接受宿主已有 action 的类型化引用,成功后重新解析一次;第二次再要准备即拒绝,避免循环。`backend: 1` 仍为网页的全局进程,不改成工作区 Debug 后端。该后续版本不阻塞基础接入。 - -### 5. 标准能力默认使用 DAP,不要求重复声明 - -省略能力块时,按标准 DAP 默认值、initialize 和 capabilities 事件决定支持;宿主尚未实现的操作继续不可用。manifest 只允许 `capabilities.disabled` 关闭已知标准 capability,不允许 `source: function`,也不把 manifest 当作“已实现”的证据。 - -capability 名称以实施时固定的 DAP 定义为准,Core 检查名称存在,适配器不用维护另一份不完整能力清单。exception filters、completions、stepping granularity、cancel 等走同一协商规则;取消待处理操作和停止清理不受界面功能禁用影响。Java 热替换仍用已有 `redefineClasses` 的输入、结果及错误语义。 - -### 6. 宿主继续拥有资源及停止策略 - -Provider 记录绑定包版本、启用代次、工作区和操作。准备及连接具有有界期限,调试会话本身没有总时长;禁用与启动交错时,执行前再确认,已创建资源进入同一清理链。取消、停止和失败丢弃晚到结果,重复停止共享完成状态。 - -adapter、debuggee、终端、共享服务和外部 attach 目标分别记录所有权。launch 停止自己拥有的程序,attach 默认只断开;Java Stop 不终止 JDT LS。子会话及 runInTerminal 沿用现有管理器;只在平台真正实现时向 DAP 公告反向请求支持。 - -安装目录和插件包只读。日志、缓存、锁及临时状态通过平台存储 adapter 写入可写目录,会话结束回收会话资源,不影响签名或 Sparkle delta。实施新增下载/缓存时再同步 worktree 资源清单、校验路由及 CI 文档;本 PR 不产生资源。 - -### 7. P1–P3 独立完成 #1210 - -| 阶段 | 交付与退出条件 | -| --- | --- | -| P1 内部 Registry | 内置适配器注册为类型化 Provider,保留兼容包装;明确身份、选择、冲突、失效代次及原有运行基线。Java 无需经过插件 JSON | -| P2 最小声明契约 | 正式 schema、Core 语义校验、拟定版本/权限、共享进程扩展、安装与市场审查同批落地;固定传输不需要函数或依赖平台。所有拒绝 fixture 接上实际 Core 测试 | -| P3 第三方纵向验收 | macOS 与 Windows 各自完成纯 Debug 插件安装、选择、launch/attach、断点、线程/栈/变量、停止和资源回收;两端提供独立证据,保留旧行为 | - -Swift/Rust 内核整合可在 Provider 背后逐步做,不以删旧引擎为本任务前提。动态 resolver、依赖安装和指令/内存能力分别推进,不能成为 #1210 关闭的隐性条件。 - -### 正确做法与反例 - -正确做法:一个只提供 stdio DAP 的插件声明自己的进程,用户显式选择它,现有窗口按协商结果显示断点与变量;没有 selectors、能力块或后端也能工作。Java 内置实现登记到同一目录,但继续向 JDT 读取工程事实。 - -反例:为了接入一个 stdio 进程,要求插件先写依赖包、导出、两步流程,再逐项列出全部 DAP 能力;或者允许第三方写一个 JDT 名称就访问宿主共享服务。这两种方式都超出基础接入的必要范围。 - -## 考虑过的备选方案 - -- Debug 同时建立依赖、导出与工作流:上一版采用;撤回,因为涉及市场、版本冲突、信任及所有领域,需要单独设计。并不否定未来通过依赖复用 JSON,只是不让 Debug 接入等待平台重构。 -- 第一期开放本包函数 resolver:比跨包调用简单,但仍改变领域结果边界和后端生命周期;后置到独立版本,先完成固定声明的真实流程。 -- 为所有能力显式标注 DAP/function/disabled:会让静态清单与运行时协商漂移。改为默认 DAP、只允许禁用,扩展函数有契约后再评审。 -- 继续按语言字符串工厂开放第三方接口:迁移最少,但无法支持一后端多语言、一语言多后端及无源文件目标。只留兼容包装,不作为最终公共 API。 -- 第三方自带另一套 UI 或自研统一调试器:重复现有 DAP、线程/栈/变量和资源管理,偏离本任务。 - -## 验收标准 - -- 同一 Registry 覆盖内置与第三方;明确选择、关联、候选歧义、重复身份、禁用失效均有标准输入/结果。纯 Debug 插件无需语言和 UI。 -- P2 先通过正式 Core 接受/拒绝 fixtures,包括完整清单版本、requires、权限、目标事实、资源路径和过期计划;结构 schema 通过不等于语义通过。 -- P3 至少一个真实第三方 DAP 完成安装到命中断点、查看线程/栈/变量和停止;launch 与 attach 分别验证所有权,失败、取消、禁用和迟到子会话不留下资源。 -- API 1/2/3、Run 配置、Build/VCS/语言/UI/设置、私有函数和既有 debug 命令的兼容结果保持不变。Node 子会话、Java 测试/JDK/热替换及终端不因接入回退。 -- 两端使用同一契约和 fixtures,各自实际验证。实施阶段更新功能矩阵,只有运行成功的平台才标记 verified;本设计 PR 不更改实现状态。 -- 独立依赖平台、私有 resolver 和原生扩展尚未完成,也可以在上述目标满足后关闭 #1210。 - -## 风险 - -- 固定形状不能覆盖所有后端准备:复杂内置链路保留 Provider 实现;收集真实缺口后再设计 resolver,不用这一限制重建项目模型。 -- 固定 TCP 端口可能冲突或连接到错误进程:平台无法证明归属时拒绝,优先 stdio 或本次进程公告端点,不声称所有传输跨平台均可用。 -- DAP 协商与宿主投影不同步:有效支持取协商、宿主实现和授权的交集,功能未实现时不点亮按钮。 -- 拟定版本可能与并行工作冲突:实施前重新核对能力表,不改变任何已发布编号的语义。 -- 旧 Swift/Rust 能力不齐:保留可回退的 Provider 包装;完整行为等价后才移除旧路径。 - -## 验证 - -本 PR 离线验证唯一 Draft 2020-12 schema 和结构拒绝输入;Core 语义 fixtures 只登记待实现的验收条件,不计为通过。运行 `./scripts/verify-agent-notes.sh`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-runtime-bundle-immutability.sh` 和 `git diff --check`。本阶段没有应用构建、后端启动或真实调试证据。 - -实施阶段加载 `write-stable-tests`,按所属范围运行 `./scripts/verify-rust-core-comments.sh`、`./scripts/verify-rust-core.sh`、`./scripts/test-macos.sh`、`./scripts/verify-service-boundaries.sh` 与 `./scripts/verify-windows-boundaries.sh`。Windows 上另行执行 `./scripts/build-windows.ps1 -Configuration Release`、宿主 Rust 与前端测试。所有等待有界,失败也释放资源,结束后确认本次启动的 Lithe 与子进程已退出。 - -平台行为修改前运行功能矩阵变更门禁及 `./scripts/verify-platform-feature-matrix.sh`;真实工作流前后比较安装目录清单/哈希。正式契约与 Core 同批修改,合并后按[两仓库发布规则](../../implemented/architecture/2026-10-23-plugin-contract-publishing.md)同步 `lithe-plugin-docs`;若未来修改函数协议,先修订所属决策并在 docs 仓库验证两个 SDK。 - -## 适用范围 - -- `rust/lithe-core/src/debug/` -- `rust/lithe-core/src/plugins/` -- `shared/contracts/plugins/v1/` -- `shared/contracts/rust-core-api.md` -- `shared/proposals/debug-adapters-1210/` -- `shared/fixtures/debug/` -- `macos/Sources/LitheCoreContracts/Debug/` -- `macos/Sources/LitheDebugModule/` -- `macos/Sources/Lithe/Services/Debug/` -- `macos/Sources/Lithe/Platform/MacOS/Debug/` -- `windows/tauri/src/features/debugger/` -- `windows/tauri/src-tauri/src/debug.rs` - -## 依据 - -- [公共扩展契约](2026-10-13-public-extension-contract-and-provider-api.md)、[能力版本](../../implemented/architecture/2026-10-17-plugin-capability-versions.md)、[Build Provider](2026-10-17-build-system-provider-api.md)。 -- [Java 构建与启动边界](../../implemented/architecture/2026-09-18-java-project-build-and-launch-boundary.md)、[Run JDK](../../implemented/bug-fix/2026-10-14-java-debug-uses-the-run-jdk.md)、[Windows Java 生命周期](../../implemented/bug-fix/2026-10-07-windows-java-debug-lifecycle.md)。 -- [DAP 标准](https://microsoft.github.io/debug-adapter-protocol/overview)、[DAP 定义](https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json)、[debugpy](https://github.com/microsoft/debugpy)、[Java Debug Server](https://github.com/microsoft/java-debug)、[js-debug](https://github.com/microsoft/vscode-js-debug)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)。 diff --git a/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md b/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md deleted file mode 100644 index 564b59b45d..0000000000 --- a/.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md +++ /dev/null @@ -1,49 +0,0 @@ -# Agent 笔记:原生指令与内存调试的后续投影边界 - -状态:提议中 - -## 先说结论 - -原生程序的无源码栈帧、反汇编和内存展示是独立的 Debug UI 扩展,不是 [#1210 Registry 与第三方 DAP 接入](2026-10-25-debug-adapter-provider-and-declarative-registration.md)的关闭条件。基础接入先复用现有源码调试;本提案只保留未来如何表达指令位置和后端差异的边界,不修改旧字段或新增权限。 - -## 问题 - -LLDB/GDB 可以同时服务 C、C++、Rust 和汇编,但二进制不一定有源码或行号。当前会话模型以源码调试为主;若用假文件或零行号塞进现有模型,UI 会跳到错误位置,旧消费者也可能误解缺失值。 - -## 提案 - -后续从真实 DAP 结果出发,为会话内源码引用、指令位置、内存引用、指令断点和指令单步增加版本化投影。地址及引用保持字符串,避免 JavaScript 数值精度损失;它们是不透明后端引用,不是工作区文件路径。没有源码时明确表达缺失,不直接把旧必填数字改成 null 交给旧消费者。 - -寄存器优先展示后端给出的变量分组(scope),不假定所有 CPU 有统一寄存器表。反汇编、内存读取、写入和指令断点分别受后端协商、宿主实现与操作授权约束;写入权限需要单独设计,不从已有 launch 或读取能力推导。 - -源码身份仍为工作区相对路径,外部源码通过已授权映射或会话引用读取。栈帧、变量及内存引用绑定会话和暂停代次,继续执行或重启后重新获取。Rust、Swift、TypeScript 及 fixtures 一起演进,再接平台展示。 - -正确做法:没有源码的暂停展示指令地址,支持源码的帧仍跳转真实文件。反例:为让编辑器能跳转,给未知帧伪造一个工作区文件和第一行。 - -## 考虑过的备选方案 - -- 放回 #1210 的 P5:容易把基础 Registry 与新 UI、架构和权限绑定,已拆出,另行验收。 -- 复用现有必填文件位置并填默认值:字段少,但无法区别未知位置与真实第一行,不采用。 -- 自研统一原生调试器:重复 LLDB/GDB 的能力及平台权限处理;仍采用标准 DAP 和成熟上游。 - -## 验收标准 - -- 有符号源码调试、无源码指令调试分别验收;旧 Registry 与源码流程不要求启用新投影。 -- 覆盖未知位置、超出整数精度的地址、继续后引用失效和不支持能力;不得发生假跳转或旧解码器回归。 -- 两端分别验证反汇编、只读内存、寄存器分组及指令断点;写入只有在新权限与独立用例通过后开放。 - -## 风险 - -GDB 是否支持 DAP 取决于版本和构建,操作系统调试授权及指令集也各不相同。统一模型不意味着全部平台或后端都能实现这些功能,未验证的组合保持不可用。 - -## 验证 - -本次仅运行 `./scripts/verify-agent-notes.sh`,不提供原生 Debug 运行证据。实施前加载 `write-stable-tests`,增加共享 fixtures,运行 `./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core.sh` 及对应平台测试;更新功能矩阵并在真实原生调试流程后清理本次进程和资源。 - -## 适用范围 - -- `rust/lithe-core/src/debug/` -- `shared/fixtures/debug/` -- `macos/Sources/LitheCoreContracts/Debug/` -- `macos/Sources/LitheDebugModule/` -- `windows/tauri/src/features/debugger/` diff --git a/.agents/notes/proposed/architecture/2026-10-25-optional-debug-extensions.md b/.agents/notes/proposed/architecture/2026-10-25-optional-debug-extensions.md new file mode 100644 index 0000000000..85940b4a89 --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-10-25-optional-debug-extensions.md @@ -0,0 +1,112 @@ +# Agent 笔记:可选调试扩展 + +状态:提议中 + +## 先说结论 + +除断点、线程与调用栈、变量这些必选能力外,调试功能都是**可选扩展**:寄存器、内存、反汇编、反编译源码、条件断点、子会话等。每个扩展都挂在[统一调试内核](2026-10-25-unified-debug-engine-and-adapter-registry.md)上,由三部分组成:内核请求处理器、它允许内核声明的客户端能力、平台界面入口。扩展各自排期、各自验收,都不是 #1210 的关闭条件。 + +某个功能是否可用,由三个条件同时决定:适配器在 DAP 协商中声明支持、本平台已注册对应扩展、操作已获授权。插件清单不逐项声明这些功能,最多用 `capabilities.disabled` 关掉一项。 + +## 问题 + +GDB、LLDB 可以调试 C、C++、Rust 和汇编,但二进制不一定有源码或行号;Java 调试器可以返回反编译源码;js-debug 会发起子会话。这些功能在 DAP 里都是可选的,不同适配器支持的组合各不相同。如果为了显示它们去改必选层的数据结构,或者按适配器名称写分支,每接一个调试器就要改一次宿主。 + +现在 Rust Core 已经实现 `setVariable`、各类断点(含数据断点)、`stepBack`、`runInTerminal`;尚未实现 `readMemory`、`writeMemory`、`disassemble`、`setInstructionBreakpoints`、指令粒度单步、`modules`、`loadedSources` 和 `startDebugging`。macOS 的 Node 子会话目前在 Swift 会话里实现。 + +## 提案 + +### 扩展分组 + +| 分组 | DAP 请求与能力 | 内核允许声明的客户端能力 | 界面入口 | +| --- | --- | --- | --- | +| 断点增强 | 条件断点、命中次数、日志点(`supportsConditionalBreakpoints`、`supportsHitConditionalBreakpoints`、`supportsLogPoints`);`setFunctionBreakpoints`;`setExceptionBreakpoints` 与过滤项;`dataBreakpointInfo` / `setDataBreakpoints` | — | 断点编辑、异常过滤、监视点 | +| 表达式与变量 | `setVariable`、`setExpression`、`completions`;变量的 `presentationHint`(只读、懒加载) | `supportsVariableType` | 变量编辑、控制台补全 | +| 执行控制增强 | `stepBack` / `reverseContinue`、`restart`、`restartFrame`、`gotoTargets` / `goto`、`stepInTargets` | — | 工具栏与栈帧菜单 | +| 无源码与生成代码 | `source`(`sourceReference`);`loadedSources` | — | 只读源码标签页 | +| 原生调试 | 寄存器(scope 的 `presentationHint: "registers"`);`readMemory` / `writeMemory`;`disassemble`;`setInstructionBreakpoints`;`granularity: "instruction"` 单步 | `supportsMemoryReferences`、`supportsInvalidatedEvent`、`supportsMemoryEvent` | 寄存器、内存、反汇编视图 | +| 进程与模块 | `modules`;`startDebugging` 子会话;`runInTerminal`;`attach` 到进程列表 | `supportsStartDebuggingRequest`、`supportsRunInTerminalRequest`、`supportsProgressReporting` | 模块列表、子会话树、终端 | +| 语言专属 | Java 热替换(`redefineClasses`)等非标准请求 | 由内置 Provider 描述列出 | 由对应扩展提供 | + +### 反编译与反汇编是两件事 + +- **反编译**由适配器完成:例如 Java 调试器从 jar 里的 class 生成源码,通过 `sourceReference` 返回文本。宿主只用只读标签页显示它,不自己反编译。 +- **反汇编**是 `disassemble` 请求,返回指令列表,属于原生调试分组。 + +两者使用不同的界面,也分别验收。 + +### 无源码位置 + +- 栈帧可以没有 `source`、`line`、`column`,只有名称和 `instructionPointerReference`。界面显示“无源码”,有反汇编扩展时可以跳到反汇编视图;不伪造文件,也不跳到第 1 行。 +- 源码身份三选一:工作区相对路径、会话内 `sourceReference`、已授权的外部路径。会话结束后 `sourceReference` 失效,标签页转为只读快照或关闭。 +- 地址和引用(`instructionPointerReference`、`memoryReference`、`address`)都是不透明字符串,宿主不做算术。确实需要偏移时,由内核按字符串解析为 128 位以内的整数,再生成新字符串。 + +### 寄存器 + +寄存器直接使用适配器给的 scope:按 `presentationHint: "registers"` 筛选,适配器没给提示时按普通 scope 显示。宿主不内置任何 CPU 的寄存器表,也不按架构名写分支。 + +### 写操作单独授权 + +`writeMemory`、`setVariable`、`setExpression`、热替换都会修改被调试程序。读取能力不代表允许写入:写入类扩展各有独立的授权与确认规则,且只有对应的用例通过后才开放。具体权限名在实施时按能力版本规则申请。 + +### 引用失效 + +栈帧、变量、内存、反汇编结果都绑定会话 ID 和暂停代次。继续执行、单步、重启后,界面重新获取;收到 `invalidated` 或 `memory` 事件时,只刷新受影响的区域。晚到的旧结果直接丢弃。 + +### 实现顺序建议 + +1. 断点增强、表达式与变量:Rust Core 已有实现,迁到新内核后补界面即可。 +2. 无源码与生成代码:Java 反编译源码和 Node eval 代码依赖这一组,同时也是原生调试的前提。 +3. 进程与模块:`startDebugging` 要先于删除 Swift 会话完成,否则 Node 子会话会回退。 +4. 原生调试:寄存器 → 反汇编 → 只读内存 → 指令断点与单步 → 写内存。 + +第 3 项实际上是 P5 删除旧路径的前置条件:Node 子会话迁到新内核之前,不能删 Swift 会话。 + +### 正确做法 + +- 新增反汇编:内核注册 `disassemble` 处理器,两端增加视图,入口只看能力快照里的 `supportsDisassembleRequest`。GDB、LLDB 自动获得,插件不改。 +- 断在没有符号的函数里:调用栈显示函数名和地址,编辑器保持原位;打开反汇编视图后定位到当前指令。 + +### 不要这样做 + +- 为了让旧解码器能用,给无源码帧填一个假路径和第 1 行。 +- 在宿主里内置 x86 / ARM 寄存器表,或者按 `adapterID` 判断是否显示内存视图。 +- 已经能读内存,就顺带允许写内存。 +- 适配器没有声明支持时仍显示入口,等用户点了再报错。 + +## 考虑过的备选方案 + +- **把原生调试放回 #1210:** 会把 Registry 接入和新界面、权限、多架构验证绑在一起,拖慢必选层落地。已拆出。 +- **插件用函数实现扩展:** 插件函数不能实现领域操作,而且会让同一个 DAP 请求出现两条执行路径。扩展只做宿主内核模块。 +- **自研反汇编器或内存解析:** 重复上游已有的能力,并且受架构限制。只显示适配器返回的结果。 + +## 验收标准 + +- 每个分组单独验收,至少用一个声明支持的真实适配器在两个平台各跑一次;不支持的适配器上,界面入口隐藏,或明确显示为不可用。 +- 未注册扩展时,initialize 不声明对应的客户端能力,适配器也不会发来相关引用。 +- 无源码帧、超过 2^53 的地址、`sourceReference` 会话结束后失效、继续执行后引用失效、未知 `presentationHint`,都有共享 fixtures,三端解码一致;不出现假跳转。 +- 写入类操作有独立的授权和确认用例,拒绝时不发出请求。 +- 进程与模块分组通过 Node 子会话的现有基线后,才允许删除 Swift 会话。 + +## 风险 + +- GDB 是否带 DAP 取决于版本和构建方式;系统调试授权(macOS 的调试权限、Windows 的进程访问权限)和指令集差异会限制原生调试,未验证的组合保持不可用。 +- 适配器声明了能力但实现不完整时,要按请求失败显示错误,不能让会话卡住;所有扩展请求都有期限,并且可以取消。 + +## 验证 + +本次只修改文档,运行 `./scripts/verify-agent-notes.sh`,不提供运行时证据。实施时加载 `write-stable-tests`,增加 `shared/fixtures/debug/*-v2.json`,运行 `./scripts/verify-shared-contracts.sh`、`./scripts/verify-rust-core.sh` 和对应平台测试;更新功能矩阵,真实调试流程结束后清理本次启动的进程和资源。 + +## 适用范围 + +- `rust/lithe-core/src/debug/` +- `shared/fixtures/debug/` +- `shared/proposals/debug-adapters-1210/` +- `macos/Sources/LitheCoreContracts/Debug/` +- `macos/Sources/LitheDebugModule/` +- `windows/tauri/src/features/debugger/` + +## 依据 + +- [统一调试内核与调试适配器 Registry](2026-10-25-unified-debug-engine-and-adapter-registry.md) +- [DAP 规范](https://microsoft.github.io/debug-adapter-protocol/specification)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html) diff --git a/.agents/notes/proposed/architecture/2026-10-25-unified-debug-engine-and-adapter-registry.md b/.agents/notes/proposed/architecture/2026-10-25-unified-debug-engine-and-adapter-registry.md new file mode 100644 index 0000000000..2dc94db3ee --- /dev/null +++ b/.agents/notes/proposed/architecture/2026-10-25-unified-debug-engine-and-adapter-registry.md @@ -0,0 +1,207 @@ +# Agent 笔记:统一调试内核与调试适配器 Registry + +状态:提议中 + +## 先说结论 + +[#1210](https://github.com/1lck/Lithe-IDEA/issues/1210) 不在现有两套调试会话上继续打补丁,而是**重新设计一个统一调试内核**。Rust Core 里只保留一个 DAP 客户端(DAP,Debug Adapter Protocol:编辑器与调试后端之间的标准协议),macOS 和 Windows 都通过 `debug.*` 命令使用它;平台只负责进程、socket、终端和界面。内置适配器和第三方插件进入同一个类型化 Registry(按稳定身份查找调试适配器的目录),插件只需声明“怎么启动这个调试器”。 + +调试能力分三层。断点、线程与调用栈、变量是**必选层**:每个适配器、两个平台都必须做到,也是 #1210 的关闭条件。监视表达式与调试控制台是**推荐层**。寄存器、内存、反汇编、反编译源码、子会话等是**可选扩展**:按适配器协商的结果显示,各自单独推进,见[可选调试扩展](2026-10-25-optional-debug-extensions.md)。可选功能可以晚做,但新内核第一版的数据模型就要为它们留好位置,以后只做增量,不改已有结构。 + +## 问题 + +### 现在是两套内核,按语言接线 + +以下盘点基于 `preview` 提交 `e854cfd98e4a52fe5abacff2002efd9f68082da2`。 + +| 现状 | 位置 | 带来的问题 | +| --- | --- | --- | +| Rust Core `debug.*` 内核:DAP 分帧、请求序列、断点、变量分页、取消、`runInTerminal`、Java 热替换 | `rust/lithe-core/src/debug/` | Windows 的全部调试和 macOS 的 Java 走这里 | +| Swift `DebugAdapterProtocolSession`:通用 stdio、Go、Node(含子会话) | `macos/Sources/LitheDebugModule/Runtime/` | 同一个功能要在 Swift 和 Rust 各写一遍,两边行为容易分叉 | +| 按语言装配的工厂 | `macos/Sources/Lithe/Services/Debug/DebugAdapterRuntimeFactory.swift`、`MacServiceContainer.swift` | 每接一种调试器都要改组合根(Composition Root,负责组装依赖的地方) | +| 以源码为中心的投影 | `rust/lithe-core/src/debug/types.rs`:`DebugStackFrame.line/column` 是必填 `i64`,`DebugScope` 没有 `presentationHint`;initialize 固定声明 `supportsMemoryReferences: false` | 无源码栈帧、寄存器、内存都没有地方表达;以后再放宽必填字段,就是 Rust、Swift、TypeScript 三端同时的破坏性变更 | + +### 为什么重写,而不是继续扩展 + +上一版的方案是“Registry 先接入,内核整合以后在 Provider 背后慢慢做”。这样 Registry 会把两套内核的差异一起固定下来;之后每加一个能力,都要实现两遍、解码三遍。Lithe 的目标是兼容 GDB、LLDB、debugpy、Delve、js-debug 等多种调试器,难点在于 DAP 客户端是否完整,不在插件怎么声明。所以先把内核做成一个,再让所有适配器接到它上面。 + +### 哪些东西不重写 + +- **不自研调试器。** 符号解析、ptrace / Mach 异常端口 / Windows Debug API、各 CPU 架构的断点和单步,都由 GDB、LLDB 等上游负责。GCC 是编译器;GCC 编出来的程序用 GDB 或 LLDB 调试。 +- **不重建项目模型。** Java 的主类和 classpath 来自 JDT,Python 解释器来自 Run,C/C++/Rust 产物来自 Build/Run。 +- **不另造插件协议。** 启动声明复用 `serverProcess`、启动模板、能力版本和安装审查,详见[声明草案](../../../../shared/proposals/debug-adapters-1210/README.md)。 +- **现有行为是迁移基线,不能丢。** 包括 Java 热替换、JUnit/TestNG、调试使用 Run 选中的 JDK、Node 子会话与 source map、断点先于 launch 入队、停止与清理顺序。 + +## 提案 + +### 1. 内核、平台、插件、调试器各管什么 + +| 角色 | 负责 | 不负责 | +| --- | --- | --- | +| 统一内核(Rust Core) | DAP 分帧和请求关联;会话状态机;能力协商;断点存储与位置修正;暂停代次(每次暂停递增的编号)与引用失效;请求处理器注册表;规范化事件与投影;父子会话关系 | 启动进程、打开 socket、创建终端、读文件、画界面 | +| 平台(macOS / Windows) | 按内核给出的计划启动进程和传输;PTY / ConPTY 终端;路径映射与文件授权;界面展示 | 解析 DAP、维护断点或变量状态、按语言写分支 | +| 插件 | 声明调试器怎么启动:进程、传输、可选的参数映射和能力禁用 | 实现 DAP 状态,或声明自己支持哪些标准能力 | +| 调试器(上游) | 语言和平台语义 | — | + +平台和内核之间沿用现有 JSON 信封与 C ABI:平台调用 `debug.createSession`,把返回的 `outboundFrames` 写给适配器,再把适配器的输出交给 `debug.receive`。Windows 已经这样工作;macOS 的 Swift 会话在迁移完成后删除。 + +### 2. 会话模型 v2:第一版就为扩展留位置 + +新内核发布投影版本 2,草案见 [`debug-session-projection.draft.schema.json`](../../../../shared/proposals/debug-adapters-1210/debug-session-projection.draft.schema.json) 和[样例](../../../../shared/proposals/debug-adapters-1210/projection-v2-examples.draft.json)。与 v1 相比: + +| 预留 | 规则 | 为什么第一版就要定 | +| --- | --- | --- | +| 栈帧的 `source`、`line`、`column` 可选 | 无源码帧不伪造文件,也不填第 1 行;可以带 `instructionPointerReference` | v1 的必填 `line` 分不清“位置未知”和“第 1 行” | +| 源码身份三选一 | 工作区相对路径 / 会话内 `sourceReference` / 已授权的外部路径 | 反编译出来的源码、eval 生成的代码、系统库源码都能表达 | +| 地址与引用一律用字符串 | `instructionPointerReference`、`memoryReference` 等都是不透明字符串 | 64 位地址超出 JavaScript 的安全整数范围 | +| scope 透传 `presentationHint` | `arguments`、`locals`、`registers`、`returnValue` 及未知值原样保留 | 寄存器视图直接按提示筛选,不假定所有 CPU 都有同一张寄存器表 | +| 引用绑定会话和暂停代次 | 继续、单步、重启后,旧的 `variablesReference` 和栈帧 ID 失效 | 晚到的结果不会写进新的暂停状态 | +| 能力快照 | 有效支持 = 适配器协商结果 ∧ 本平台已注册的扩展 ∧ 授权;带递增 `revision` | 界面只看快照,不看插件名或清单 | +| 未知值不丢弃 | DAP 新增的枚举值、未知 `presentationHint`、未知停止原因原样保留 | 上游升级时不必先改三端解码器 | + +v1 投影和命令保留到两端都迁到 v2 为止,然后在同一个 PR 里删除 v1、Swift 会话和按语言的工厂。Rust、Swift、TypeScript 共用 `shared/fixtures/debug/*-v2.json`。 + +### 3. 能力分三层 + +**必选层。** 这些请求和事件 DAP 规范本来就要求,不靠 capability 开关。每个注册的适配器都要跑通,两个平台都必须实现: + +| 类别 | 内容 | +| --- | --- | +| 会话生命周期 | `initialize`;`launch` 或 `attach` 至少一种;`configurationDone`;`disconnect` / `terminate`;停止与资源清理 | +| 断点 | 行断点 `setBreakpoints`;断点确认与位置修正(`verified`、移到有效行) | +| 执行控制 | `continue`、`pause`、`next`、`stepIn`、`stepOut` | +| 线程与调用栈 | `threads`(调用栈按线程获取)、`stackTrace` | +| 变量 | `scopes`、`variables`(嵌套展开与分页) | +| 事件 | `stopped`(含停止原因)、`continued`、`exited` / `terminated`、`output` | + +**推荐层。** `evaluate` 的 `watch`、`hover`、`repl` 三种上下文,也就是监视表达式、悬停求值和调试控制台。它们不是 #1210 的关闭条件,但应先于可选扩展完成:用户通常把它们当作“变量追踪”的一部分,GDB/LLDB 的大量功能也要靠控制台命令。 + +**可选扩展。** 断点增强、表达式与变量、执行控制增强、无源码代码(含反编译)、原生调试(寄存器、内存、反汇编、指令断点与单步)、进程与模块、语言专属扩展。分组和各自的验收见[可选调试扩展](2026-10-25-optional-debug-extensions.md)。 + +Registry 注册时不启动程序做验证。一个适配器在接入验收中跑通必选层的标准流程后,才能标记为可用。 + +### 4. 扩展机制:内核模块,不是插件 JSON + +每个可选扩展是一组宿主代码,包括三部分: + +1. 在内核里注册请求处理器和投影解码器; +2. 声明它允许内核在 initialize 里告诉适配器的客户端能力,例如 `supportsMemoryReferences`、`supportsStartDebuggingRequest`、`supportsInvalidatedEvent`; +3. 提供平台界面入口。 + +具体规则: + +- 内核只声明已注册扩展对应的客户端能力。没有内存扩展时,继续声明 `supportsMemoryReferences: false`,适配器就不会发来内存引用。 +- 界面入口只看能力快照,不看适配器名称。 +- 扩展不写进插件清单。插件最多用 `capabilities.disabled` 关掉某个标准能力。 +- 语言专属扩展(如 Java 热替换的 `redefineClasses`)挂在内置 Provider 的描述上:Provider 描述列出它使用的扩展,组合根不按名字判断。第三方的非标准请求不在本提案中开放。 + +### 5. Registry 与插件声明 + +完整字段和拒绝规则见[声明草案](../../../../shared/proposals/debug-adapters-1210/README.md),这里只记录决策: + +- 插件只写一个 `plugin.json.debugAdapters` 块,必填 `id`、`displayName`、`launch`。`launch` 由两部分组成:复用 `serverProcess` 的进程,加上 `stdio`、`tcpAnnounced` 或 `tcpPort` 三种传输之一。 +- 拟定 API 4、`requires.debugAdapters: 1`、`debug.launch` / `debug.attach` 权限。需要 Run 选中的运行时时,使用 `serverProcess: 2` 的 `runSelectedRuntime`。 +- 标准能力跟随 DAP 协商,清单只能禁用。没有依赖、导出、工作流、resolver 或 `hostIntegration` 字段;插件依赖另见[独立平台提案](2026-10-25-plugin-dependencies-and-exports.md)。 +- 内置 Provider(Java、Go、Node、Python、LLDB)和第三方声明转成同一种描述后进入 Registry。身份由插件 ID 加局部 ID 组成,内置 Provider 使用保留空间。 +- 选择顺序为:配置里的显式选择 → 工作区已保存的关联 → 唯一匹配的候选。多个候选时由用户选择,插件不能自报优先级。 +- Run 配置 ID、三层覆盖规则和导入的 `launch.json` 参数保持不变;目标映射只补缺失的值,不覆盖显式写出的 `program`、`args`。 + +### 6. 资源与生命周期 + +- 每次准备和连接都绑定工作区、Provider 注册代次和操作,并设有期限;调试会话本身不设总时长。 +- 禁用与启动同时发生时,执行前再确认一次;已经创建的资源进入同一条清理链。取消、停止、失败后丢弃晚到的结果;重复点击停止共享同一个完成状态。 +- adapter 进程、被调试程序、终端、共享语言服务器和外部 attach 目标分别记录所有权。`launch` 结束自己启动的程序,`attach` 默认只断开;结束 Java 调试不终止 JDT LS。 +- 插件包和安装目录只读。日志、缓存、锁文件和临时状态由平台存储 adapter 写到可写目录,不影响代码签名和 Sparkle 增量更新。 + +### 7. 分阶段交付 + +| 阶段 | 交付与退出条件 | +| --- | --- | +| P0 行为基线 | 把现有两套内核的行为录成 v1 基线 fixtures:启动序列、断点先于 launch、断点位置修正、变量分页、停止与断开策略、`runInTerminal`、Node 子会话、Java 热替换 / 测试 / Run JDK、取消与晚到事件 | +| P1 新内核与 v2 投影 | 新内核实现必选层和推荐层、v2 投影、能力快照、扩展注册表;三端都能解码 v2 fixtures;通过全部 P0 基线 | +| P2 内置迁移与 Registry | 内置适配器逐个注册为 Provider 并切到新内核,建议顺序:通用 stdio → Go → Node → Python → Java。每个都有可回退的开关,同一目标只启用一个实现;Windows 同步迁移 | +| P3 第三方声明契约 | 正式 schema、Core 语义校验、版本号、权限、安装审查一起落地;声明草案里的拒绝 fixtures 接上 Core 测试 | +| P4 第三方纵向验收 | 两个平台各用一个真实第三方适配器(GDB DAP `gdb -i=dap` 或 `lldb-dap`)完成安装、选择、launch / attach、必选层全流程和资源回收 | +| P5 删除旧路径 | 所有消费者迁到 v2 之后,在同一个 PR 里删除 Swift 会话、按语言的工厂和 v1 投影 | + +P0–P5 完成后关闭 #1210。可选扩展、插件依赖和私有 resolver 都不是关闭条件。 + +### 正确做法 + +- 接入 GDB:插件声明 `systemCommand: ["gdb"]`、参数 `["-i=dap"]`、`stdio` 传输。断点、线程、栈、变量直接出现在现有调试窗口里,插件不列任何能力。 +- 新增内存查看:在内核注册 `readMemory` 处理器,允许内核声明 `supportsMemoryReferences`,再在两端加界面入口。GDB 和 LLDB 都会自动获得这项功能,插件不需要改动。 +- 调试一个没有符号的汇编程序:栈帧只有名称和 `instructionPointerReference`,界面显示“无源码”,不跳到某个文件的第 1 行。 + +### 不要这样做 + +- 在 Swift 和 Rust 里分别补同一个能力,或者在组合根按语言名再加一个工厂分支。 +- 给无源码帧填一个假文件和第 1 行,让旧解码器“看起来能用”。 +- 让插件在清单里逐项声明 `supportsX`,或者用插件函数实现标准 DAP 请求。 +- 在 P0 基线全部通过之前删除旧会话,或者为了切换方便先去掉 Java 测试、热替换、子会话等现有功能。 + +## 考虑过的备选方案 + +### 在现有两套内核上增量扩展 + +这是上一版的方案。它的吸引力是迁移量小,Registry 可以先上线。不采用的原因:每加一个能力都要实现两遍、解码三遍;以源码为中心的 v1 模型迟早要做破坏性修改,越晚改受影响的消费者越多。 + +### 每个平台各自实现 DAP 客户端 + +在 Swift 和 TypeScript 里各写一套,可以最贴近各自平台的界面框架。不采用的原因:状态机、断点修正、暂停代次这些语义会在两端分叉,现有 Windows 已经证明 Rust 内核加平台传输的分工可行。 + +### 直接引入第三方 DAP 客户端库 + +可以省去手写协议类型。不采用整套库,因为会话状态机、暂停代次、资源所有权、取消与晚到结果是 Lithe 自己的语义,现成的库不提供。可以只复用协议类型:从 DAP 官方 JSON 定义生成,减少手写错误。 + +### 自研调试器 + +可以完全掌控功能。不采用的原因:要重复实现 GDB/LLDB 几十年积累的符号解析、平台调试接口和架构细节,还要处理系统调试授权,偏离本任务。 + +### 插件 JSON 工作流与插件依赖 + +更早一版曾在 Debug 声明里加入依赖、导出、跨插件函数和 `steps` 流程。已撤回:这些属于插件平台,涉及市场依赖解析、版本冲突和信任传递;而且示例里没有证明必要的真实流程。依赖部分移到[独立平台提案](2026-10-25-plugin-dependencies-and-exports.md)。 + +## 验收标准 + +- macOS 和 Windows 都只使用统一内核;Swift 会话、按语言工厂和 v1 投影在 P5 中删除,删除前全部 P0 基线 fixtures 通过。 +- 必选层的每一项都有共享 fixtures,覆盖正常流程、取消、晚到事件和引用失效;推荐层有独立用例。 +- v2 fixtures 至少包含:有源码帧、无源码帧、`sourceReference` 源码、`registers` scope、超过 2^53 的地址字符串、未知 `presentationHint`;三端解码结果一致。 +- 能力快照只在适配器协商、扩展注册和授权都满足时报告 supported;未注册扩展时,initialize 不声明对应的客户端能力。 +- 内置与第三方共用 Registry;显式选择、工作区关联、候选歧义、重复身份、禁用失效都有标准输入和结果;组合根里没有按插件名或语言名的分支。 +- 至少一个真实第三方适配器在两个平台上各自完成安装、选择、launch 与 attach、必选层全流程和停止;结束后本次启动的 Lithe、适配器和被调试程序都已退出,外部 attach 目标保留。 +- API 1/2/3、Run 配置、Build/VCS/语言/UI/设置、私有函数的现有兼容结果保持不变;Java 测试、Run JDK、热替换,以及 Node 子会话和终端不回退。 + +## 风险 + +- **重写周期长,期间两套内核并存。** P2 按适配器用开关切换,未迁移的继续走旧路径;同一个目标从不同时启用两个实现。 +- **基线漏录导致功能回退。** P0 以现有测试和真实流程为来源逐项列清单,评审时检查清单,而不只检查 fixture 数量。 +- **v1 和 v2 并存的维护成本。** 只在迁移期并存,P5 统一删除;迁移期间新功能只加在 v2 上。 +- **后端差异。** GDB 是否带 DAP 取决于版本和构建方式(需要 GDB 14 及以上),Windows 上要实测 MinGW 版本;未验证的组合不标记为可用。 +- **拟定版本号冲突。** 实施前重新核对能力表,只取下一个可用编号,不改变已发布编号的含义。 + +## 验证 + +本阶段只修改设计文档和草案 schema。运行 `./scripts/verify-agent-notes.sh`、`./scripts/verify-shared-contracts.sh`、`./scripts/verify-runtime-bundle-immutability.sh` 和 `git diff --check`,并用 Draft 2020-12 离线校验草案 schema 与样例。这些检查不构成运行时证据。 + +实施阶段加载 `write-stable-tests`,按改动范围运行 `./scripts/verify-rust-core-comments.sh`、`./scripts/verify-rust-core.sh`、`./scripts/test-macos.sh`、`./scripts/verify-service-boundaries.sh` 和 `./scripts/verify-windows-boundaries.sh`;Windows 另外执行 `./scripts/build-windows.ps1 -Configuration Release`、宿主 Rust 测试和前端测试。所有等待都有上限,失败时也释放资源,结束后确认本次启动的进程都已退出。平台行为变化时同步功能矩阵,运行 `./scripts/verify-platform-feature-matrix.sh`。正式契约与 Core 一起修改,合并后按[两仓库发布规则](../../implemented/architecture/2026-10-23-plugin-contract-publishing.md)同步 `lithe-plugin-docs`。 + +## 适用范围 + +- `rust/lithe-core/src/debug/` +- `rust/lithe-core/src/plugins/` +- `shared/contracts/plugins/v1/` +- `shared/contracts/rust-core-api.md` +- `shared/proposals/debug-adapters-1210/` +- `shared/fixtures/debug/` +- `macos/Sources/LitheCoreContracts/Debug/` +- `macos/Sources/LitheDebugModule/` +- `macos/Sources/Lithe/Services/Debug/` +- `macos/Sources/Lithe/Platform/MacOS/MacServiceContainer.swift` +- `windows/tauri/src/features/debugger/` +- `windows/tauri/src-tauri/src/debug.rs` + +## 依据 + +- [公共扩展契约](2026-10-13-public-extension-contract-and-provider-api.md)、[能力版本](../../implemented/architecture/2026-10-17-plugin-capability-versions.md)、[插件函数契约](../../implemented/architecture/2026-10-20-plugin-function-contract.md)。 +- [Java 构建与启动边界](../../implemented/architecture/2026-09-18-java-project-build-and-launch-boundary.md)、[Java Debug 使用 Run 的 JDK](../../implemented/bug-fix/2026-10-14-java-debug-uses-the-run-jdk.md)、[Windows Java 调试生命周期](../../implemented/bug-fix/2026-10-07-windows-java-debug-lifecycle.md)。 +- [DAP 标准](https://microsoft.github.io/debug-adapter-protocol/overview)、[DAP 定义](https://github.com/microsoft/debug-adapter-protocol/blob/main/debugAdapterProtocol.json)、[GDB DAP](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)、[LLDB DAP](https://lldb.llvm.org/use/lldbdap.html)。 diff --git a/shared/proposals/debug-adapters-1210/README.md b/shared/proposals/debug-adapters-1210/README.md index 57909607d7..9e148fc9ad 100644 --- a/shared/proposals/debug-adapters-1210/README.md +++ b/shared/proposals/debug-adapters-1210/README.md @@ -1,16 +1,25 @@ -# DebugAdapter Registry 评审草案(#1210) +# 调试适配器声明评审草案(#1210) -本目录只评审两件事:**内置与第三方共用 Registry(按身份查找适配器的目录),第三方 DAP 进入现有 Debug UI**。声明放在现有 `plugin.json.debugAdapters`,不是独立注册文件。没有 `draftVersion`,没有新的配置文件格式,也没有插件示例或开发教程。 +本目录评审 #1210 中两份**跨端契约草案**: + +1. 插件怎么声明调试适配器:放在现有 `plugin.json.debugAdapters`,不是独立注册文件; +2. 统一调试内核交给两个平台的会话投影 v2。 + +调试内核本身怎么重写、能力怎么分层,以 Agent Note 为准;本目录不重复这部分内容。 当前宿主不接受这些新增字段。本 PR 只提交计划,不改变正式契约或产品行为。 ## 评审材料 -- [能力块 schema](debug-adapters.draft.schema.json):唯一一份新增 schema,只校验从完整清单提取的 `debugAdapters` 段。 +- [统一调试内核与调试适配器 Registry](../../../.agents/notes/proposed/architecture/2026-10-25-unified-debug-engine-and-adapter-registry.md):内核重写、必选 / 推荐 / 可选三层能力、P0–P5 迁移与验收。 +- [可选调试扩展](../../../.agents/notes/proposed/architecture/2026-10-25-optional-debug-extensions.md):寄存器、内存、反汇编、反编译源码、子会话等,各自单独验收。 +- [能力块 schema](debug-adapters.draft.schema.json):只校验从完整清单提取的 `debugAdapters` 段。 - [拒绝 fixtures](semantic-rejections.draft.json):合成的契约验收输入,不是可安装插件;区分 schema 能拒绝和待 Core 实现的语义拒绝。 -- [Debug 架构与 P1–P3 验收](../../../.agents/notes/proposed/architecture/2026-10-25-debug-adapter-provider-and-declarative-registration.md)。 +- [会话投影 v2 schema](debug-session-projection.draft.schema.json) 与[样例](projection-v2-examples.draft.json):可选的源码位置、字符串地址、`presentationHint` 透传、暂停代次与能力快照。 + +插件依赖、导出与跨包授权移到[独立平台提案](../../../.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md),不是 #1210 的依赖或关闭条件。 -插件依赖、导出与跨包授权移到[独立平台提案](../../../.agents/notes/proposed/architecture/2026-10-25-plugin-dependencies-and-exports.md);原生指令、反汇编和内存投影移到[独立后续提案](../../../.agents/notes/proposed/architecture/2026-10-25-native-debug-projections.md)。两者都不是 #1210 的依赖或关闭条件。 +插件声明只描述“怎么启动调试器”。断点、调用栈、变量等标准能力由新内核与适配器通过 DAP 协商,清单不逐项声明;寄存器、内存等扩展是宿主内核模块,不出现在清单里。 ## 版本与清单位置 @@ -81,7 +90,7 @@ debugpy、lldb-dap 可以走 stdio,Delve/js-debug 可按真实启动方式选 本包私有 resolver 比跨插件调用范围小,但仍改变了“领域结果不走插件函数”的已落地决策。它是独立的后续 `debugAdapters` 版本:先修订函数决策、定义固定的 Debug 输入/结果及本包授权,再复用 `lithe/function/invoke`。旧 `backend: 1` 仍是全局、网页触发的进程,不能为了 Debug 改成工作区后端或要求空网页。 -如需重新准备,后续结果只能引用宿主已解析的 Build/Run action 身份及版本,不接受任意字符串、脚本或再次进入 Registry 的命令。宿主执行成功后最多重入解析一次,第二次要求准备即拒绝;项目事实随后重新从拥有它的引擎读取。这个后续门槛不阻塞固定声明的 P1–P3。 +如需重新准备,后续结果只能引用宿主已解析的 Build/Run action 身份及版本,不接受任意字符串、脚本或再次进入 Registry 的命令。宿主执行成功后最多重入解析一次,第二次要求准备即拒绝;项目事实随后重新从拥有它的引擎读取。这个后续门槛不阻塞固定声明的 P3–P4(见主 Note 的分阶段交付)。 ## Schema 与 Core 校验分界 diff --git a/shared/proposals/debug-adapters-1210/debug-session-projection.draft.schema.json b/shared/proposals/debug-adapters-1210/debug-session-projection.draft.schema.json new file mode 100644 index 0000000000..ee7af63fbd --- /dev/null +++ b/shared/proposals/debug-adapters-1210/debug-session-projection.draft.schema.json @@ -0,0 +1,176 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://lithe.invalid/proposals/1210/debug-session-projection.draft.schema.json", + "title": "Proposed debug session projection version 2", + "description": "Review-only shape of the normalized projections the unified Rust Core debug engine returns to macOS and Windows. Version 2 reserves room for optional extensions (no-source frames, session sources, registers, memory) so they can be added later without breaking changes. Not implemented; v1 stays in place until every consumer migrates.", + "type": "object", + "additionalProperties": false, + "required": ["projectionVersion", "sessionID", "stopGeneration", "projection"], + "properties": { + "projectionVersion": { "const": 2 }, + "sessionID": { "$ref": "#/$defs/opaqueID" }, + "stopGeneration": { + "description": "Incremented on every stop. References from an older generation are invalid after continue, step or restart; late results carrying them are dropped.", + "type": "integer", + "minimum": 0 + }, + "projection": { + "oneOf": [ + { "$ref": "#/$defs/stackTrace" }, + { "$ref": "#/$defs/scopes" }, + { "$ref": "#/$defs/capabilities" } + ] + } + }, + "$defs": { + "opaqueID": { "type": "string", "minLength": 1, "maxLength": 256 }, + "opaqueReference": { + "description": "Adapter-owned address or reference kept as a string. Hosts never do arithmetic on it; 64-bit addresses exceed the JavaScript safe integer range.", + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "openString": { + "description": "DAP enumerations are open; unknown values are preserved instead of rejected.", + "type": "string", + "minLength": 1, + "maxLength": 64 + }, + "source": { + "description": "Exactly one source identity.", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["kind", "path"], + "properties": { + "kind": { "const": "workspace" }, + "path": { + "description": "Workspace-relative path; absolute paths and parent segments are rejected.", + "type": "string", + "minLength": 1, + "pattern": "^(?!/)(?![A-Za-z]:)(?!(.*/)?\\.\\.(/|$)).+$" + }, + "name": { "type": "string" } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["kind", "sourceReference", "name"], + "properties": { + "kind": { "const": "session" }, + "sourceReference": { + "description": "Session-bound DAP sourceReference, fetched with the source request. Invalid after the session ends.", + "type": "integer", + "minimum": 1, + "maximum": 2147483647 + }, + "name": { "type": "string", "minLength": 1 }, + "origin": { "type": "string" } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["kind", "grantID", "name"], + "properties": { + "kind": { "const": "external" }, + "grantID": { + "description": "Host-issued grant for an authorized path outside the workspace; the raw path is not exposed to the UI layer.", + "$ref": "#/$defs/opaqueID" + }, + "name": { "type": "string", "minLength": 1 } + } + } + ] + }, + "stackFrame": { + "type": "object", + "additionalProperties": false, + "required": ["id", "name"], + "properties": { + "id": { "$ref": "#/$defs/opaqueID" }, + "name": { "type": "string" }, + "source": { "$ref": "#/$defs/source" }, + "line": { "type": "integer", "minimum": 1 }, + "column": { "type": "integer", "minimum": 1 }, + "endLine": { "type": "integer", "minimum": 1 }, + "endColumn": { "type": "integer", "minimum": 1 }, + "instructionPointerReference": { "$ref": "#/$defs/opaqueReference" }, + "moduleID": { "type": "string" }, + "presentationHint": { "$ref": "#/$defs/openString" }, + "isFiltered": { "type": "boolean" } + }, + "dependentRequired": { + "line": ["source"], + "column": ["line"], + "endLine": ["line"], + "endColumn": ["endLine"] + } + }, + "stackTrace": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "threadID", "frames"], + "properties": { + "kind": { "const": "stackTrace" }, + "threadID": { "type": "integer" }, + "frames": { "type": "array", "items": { "$ref": "#/$defs/stackFrame" } }, + "totalFrames": { "type": "integer", "minimum": 0 } + } + }, + "scope": { + "type": "object", + "additionalProperties": false, + "required": ["name", "variablesReference", "expensive"], + "properties": { + "name": { "type": "string" }, + "presentationHint": { + "description": "Passed through as reported: arguments, locals, registers, returnValue or any unknown value.", + "$ref": "#/$defs/openString" + }, + "variablesReference": { "type": "integer", "minimum": 0 }, + "namedVariables": { "type": "integer", "minimum": 0 }, + "indexedVariables": { "type": "integer", "minimum": 0 }, + "expensive": { "type": "boolean" }, + "source": { "$ref": "#/$defs/source" } + } + }, + "scopes": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "frameID", "scopes"], + "properties": { + "kind": { "const": "scopes" }, + "frameID": { "$ref": "#/$defs/opaqueID" }, + "scopes": { "type": "array", "items": { "$ref": "#/$defs/scope" } } + } + }, + "capabilityState": { + "type": "object", + "additionalProperties": false, + "required": ["adapter", "extension", "authorized", "supported"], + "properties": { + "adapter": { "type": "boolean", "description": "Reported by the adapter in initialize or a capabilities event." }, + "extension": { "type": "boolean", "description": "The host extension handling it is registered on this platform." }, + "authorized": { "type": "boolean" }, + "supported": { "type": "boolean", "description": "Must equal adapter AND extension AND authorized; Core enforces this." } + } + }, + "capabilities": { + "type": "object", + "additionalProperties": false, + "required": ["kind", "revision", "capabilities"], + "properties": { + "kind": { "const": "capabilities" }, + "revision": { "type": "integer", "minimum": 0 }, + "capabilities": { + "type": "object", + "propertyNames": { "pattern": "^supports[A-Z][A-Za-z0-9]*$" }, + "additionalProperties": { "$ref": "#/$defs/capabilityState" } + } + } + } + } +} diff --git a/shared/proposals/debug-adapters-1210/projection-v2-examples.draft.json b/shared/proposals/debug-adapters-1210/projection-v2-examples.draft.json new file mode 100644 index 0000000000..0551a34988 --- /dev/null +++ b/shared/proposals/debug-adapters-1210/projection-v2-examples.draft.json @@ -0,0 +1,151 @@ +{ + "description": "Synthetic projection v2 inputs for review. accept entries must validate against debug-session-projection.draft.schema.json; reject entries must fail schema validation. Semantic rules (supported equals the conjunction, stale generations are dropped) belong to Core tests.", + "accept": [ + { + "name": "source frame and no-source assembly frame on one thread", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "stopGeneration": 3, + "projection": { + "kind": "stackTrace", + "threadID": 1, + "frames": [ + { + "id": "f-0", + "name": "parse_header", + "source": { "kind": "workspace", "path": "src/parse.c" }, + "line": 42, + "column": 5, + "instructionPointerReference": "0x0000000100003f2c" + }, + { + "id": "f-1", + "name": "memcpy", + "instructionPointerReference": "0xffffffff81002a10", + "presentationHint": "subtle" + } + ], + "totalFrames": 2 + } + } + }, + { + "name": "session-bound decompiled source", + "value": { + "projectionVersion": 2, + "sessionID": "s-2", + "stopGeneration": 1, + "projection": { + "kind": "stackTrace", + "threadID": 17, + "frames": [ + { + "id": "f-0", + "name": "ArrayList.add", + "source": { "kind": "session", "sourceReference": 1001, "name": "ArrayList.class", "origin": "decompiled" }, + "line": 467, + "column": 1 + } + ] + } + } + }, + { + "name": "registers scope and unknown presentation hint", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "stopGeneration": 3, + "projection": { + "kind": "scopes", + "frameID": "f-1", + "scopes": [ + { "name": "Locals", "presentationHint": "locals", "variablesReference": 11, "expensive": false }, + { "name": "General Purpose Registers", "presentationHint": "registers", "variablesReference": 12, "namedVariables": 33, "expensive": true }, + { "name": "Vector", "presentationHint": "x-vendor-simd", "variablesReference": 13, "expensive": true } + ] + } + } + }, + { + "name": "capability snapshot without memory extension", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "stopGeneration": 0, + "projection": { + "kind": "capabilities", + "revision": 2, + "capabilities": { + "supportsConfigurationDoneRequest": { "adapter": true, "extension": true, "authorized": true, "supported": true }, + "supportsDisassembleRequest": { "adapter": true, "extension": false, "authorized": true, "supported": false }, + "supportsReadMemoryRequest": { "adapter": true, "extension": false, "authorized": true, "supported": false } + } + } + } + } + ], + "reject": [ + { + "name": "address as JSON number loses precision", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "stopGeneration": 3, + "projection": { + "kind": "stackTrace", + "threadID": 1, + "frames": [{ "id": "f-1", "name": "memcpy", "instructionPointerReference": 18446744071562078736 }] + } + } + }, + { + "name": "line without source fakes a location", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "stopGeneration": 3, + "projection": { + "kind": "stackTrace", + "threadID": 1, + "frames": [{ "id": "f-1", "name": "memcpy", "line": 1 }] + } + } + }, + { + "name": "two source identities at once", + "value": { + "projectionVersion": 2, + "sessionID": "s-2", + "stopGeneration": 1, + "projection": { + "kind": "stackTrace", + "threadID": 1, + "frames": [{ "id": "f-0", "name": "m", "source": { "kind": "workspace", "path": "a.java", "sourceReference": 3 } }] + } + } + }, + { + "name": "workspace path escapes the workspace", + "value": { + "projectionVersion": 2, + "sessionID": "s-2", + "stopGeneration": 1, + "projection": { + "kind": "stackTrace", + "threadID": 1, + "frames": [{ "id": "f-0", "name": "m", "source": { "kind": "workspace", "path": "src/../../etc/passwd" }, "line": 1 }] + } + } + }, + { + "name": "projection without stop generation", + "value": { + "projectionVersion": 2, + "sessionID": "s-1", + "projection": { "kind": "scopes", "frameID": "f-0", "scopes": [] } + } + } + ] +}