diff --git a/build/deepseek-harness-utility-smoke.cjs b/build/deepseek-harness-utility-smoke.cjs index cbad044d..e4f3f52d 100644 --- a/build/deepseek-harness-utility-smoke.cjs +++ b/build/deepseek-harness-utility-smoke.cjs @@ -184,7 +184,7 @@ async function run() { model: 'qwen-plus', supportsImageInput: false, requestHeaders: {}, - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_HARNESS_MODEL_API_KEY'], skillPackages: [], extensionPackages: [], diff --git a/build/native-dsh-resources.cjs b/build/native-dsh-resources.cjs new file mode 100644 index 00000000..f382b71a --- /dev/null +++ b/build/native-dsh-resources.cjs @@ -0,0 +1,65 @@ +const { cp, mkdir, readFile, rm } = require('node:fs/promises'); +const { existsSync } = require('node:fs'); +const { dirname, join, relative } = require('node:path'); +const tar = require('tar'); + +// Preserve npm's installed layout (including nested versions) and every package +// asset. The official loader discovers plugins and browser assets at runtime. +async function prepareNativeDshResources(projectDir, platform, architecture, downloadPackage, lockedIntegrity) { + const target = join(projectDir, '.runtime-resources', `dsh-${architecture}`); + await rm(target, { recursive: true, force: true }); + await mkdir(target, { recursive: true }); + const visited = new Set(); + function locate(name, from) { + for (let directory = from; ; directory = dirname(directory)) { + const candidate = join(directory, 'node_modules', name); + if (existsSync(join(candidate, 'package.json'))) return candidate; + if (dirname(directory) === directory) return undefined; + } + } + async function copyPackage(directory) { + if (visited.has(directory)) return; + visited.add(directory); + const manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8')); + await cp(directory, join(target, relative(projectDir, directory)), { recursive: true }); + const optional = manifest.optionalDependencies ?? {}; + for (const name of Object.keys({ ...manifest.dependencies, ...manifest.peerDependencies, ...optional })) { + const dependency = locate(name, directory); + if (dependency) await copyPackage(dependency); + else if (!(name in optional) && !manifest.peerDependenciesMeta?.[name]?.optional) { + throw new Error(`DS Web bundle is missing ${name} required by ${manifest.name}`); + } + } + } + await copyPackage(join(projectDir, 'node_modules', '@deepseek-ai', 'dsh')); + // Cross-architecture packaging cannot rely on the build host's npm optional + // selection. Fetch the exact target Sharp packages from the existing lock. + const sharp = JSON.parse(await readFile(join(projectDir, 'node_modules', 'sharp', 'package.json'), 'utf8')); + const lock = JSON.parse(await readFile(join(projectDir, 'package-lock.json'), 'utf8')); + const nativePackages = [`@img/sharp-${platform}-${architecture}`]; + if (platform !== 'win32') nativePackages.push(`@img/sharp-libvips-${platform}-${architecture}`); + for (const name of nativePackages) { + const version = sharp.optionalDependencies[name]; + if (!version) throw new Error(`DS Web Sharp does not support ${platform}/${architecture}`); + const destination = join(target, 'node_modules', 'sharp', 'node_modules', name); + if (existsSync(join(destination, 'package.json'))) continue; + const locked = lock.packages[`node_modules/sharp/node_modules/${name}`] ?? lock.packages[`node_modules/${name}`]; + if (locked?.version !== version || !locked.integrity) throw new Error(`Missing locked ${name}@${version}`); + const integrity = locked.integrity; + const archive = await downloadPackage(projectDir, name, version, integrity); + await mkdir(destination, { recursive: true }); + await tar.x({ file: archive, cwd: destination, strip: 1 }); + } + const koffi = JSON.parse(await readFile(join(projectDir, 'node_modules', 'koffi', 'package.json'), 'utf8')); + const koffiName = `@koromix/koffi-${platform}-${architecture}`; + const koffiDestination = join(target, 'node_modules', koffiName); + if (!existsSync(join(koffiDestination, 'package.json'))) { + const integrity = await lockedIntegrity(projectDir, koffiName, koffi.version); + const archive = await downloadPackage(projectDir, koffiName, koffi.version, integrity); + await mkdir(koffiDestination, { recursive: true }); + await tar.x({ file: archive, cwd: koffiDestination, strip: 1 }); + } + return target; +} + +module.exports = { prepareNativeDshResources }; diff --git a/build/run-deepseek-harness-utility-smoke.cjs b/build/run-deepseek-harness-utility-smoke.cjs index 5a847304..13de9036 100644 --- a/build/run-deepseek-harness-utility-smoke.cjs +++ b/build/run-deepseek-harness-utility-smoke.cjs @@ -88,7 +88,7 @@ async function main() { `${JSON.stringify( { name: '@deepseek-ai/dsh-llm', - version: '0.1.2-rc.1', + version: '0.1.7-rc.2', private: true, type: 'module' }, diff --git a/build/runtime-hooks.cjs b/build/runtime-hooks.cjs index a72cc2b7..deb459c2 100644 --- a/build/runtime-hooks.cjs +++ b/build/runtime-hooks.cjs @@ -18,6 +18,7 @@ const { prepareBundledOpenCodeConfig, } = require("./opencode-config.cjs"); const { npmInvocation } = require("./npm-invocation.cjs"); +const { prepareNativeDshResources } = require("./native-dsh-resources.cjs"); const architectureNames = { 1: "x64", @@ -184,6 +185,7 @@ module.exports = async function prepareBundledRuntimes(context) { architecture === "x64" ? `${architecture}-baseline` : architecture; const packageName = `opencode-${packagePlatform}-${suffix}`; const projectDir = context.packager.projectDir; + await prepareNativeDshResources(projectDir, platform, architecture, downloadPackage, lockedIntegrity); await prepareBundledOpenCodeConfig(projectDir); const projectPackage = JSON.parse( await readFile(join(projectDir, "package.json"), "utf8"), diff --git a/docs/features/assistant-workbar/README.md b/docs/features/assistant-workbar/README.md index 957c0d62..ae73ed62 100644 --- a/docs/features/assistant-workbar/README.md +++ b/docs/features/assistant-workbar/README.md @@ -18,6 +18,7 @@ | [执行记录存储与升级回收](./execution-history-storage.md) | 子任务差量存储、远程去重、旧库转换、会话置顶、摘要与完整历史按需读取、内存引用释放 | | [Runtime 交互边界](./runtime-interactions.md) | 原生权限、结构化问答、后台拒绝、终端交互、并行与输出、消息请求状态及资源生命周期规则 | | [Runtime 进程复用技术设计](./runtime-process-reuse-technical-design.md) | 跨 Runtime 资源调研、锁定协议证据、进程与会话拆分、远端模型桥、实施顺序和性能验收 | +| [Runtime 原生客户端启动方案](./runtime-native-client-proposal.md) | Local terminal/DS Web shortcut requirements, startup rules, current integration, validation boundaries and remaining remote/resource work | | [Runtime 执行清单技术设计](./runtime-checklist-technical-design.md) | OC/CN 原生清单提取、远程 Agent 传递复用、消息恢复与真实部署验收;尚未实现 | 当前尚未拆出独立 User Stories、功能逻辑和 UI 设计文档;产品场景与验收保留在现有 PRD, diff --git a/docs/features/assistant-workbar/progress.md b/docs/features/assistant-workbar/progress.md index 43bd89ec..09f7ff25 100644 --- a/docs/features/assistant-workbar/progress.md +++ b/docs/features/assistant-workbar/progress.md @@ -1,5 +1,75 @@ # 工作栏实现与验证进度 +## 2026-09-27 Local Native Client Validation + +Scope: [native client proposal](./runtime-native-client-proposal.md), FR-2/3/5/6/7/8, +US-2/4/5/6/8, local portions of P1/P2/P3/P5. Source baseline: +`55efca3ee1d8a491c4d9709888e302188cd988bd` plus the concurrent working tree. + +- Fixed the coordinator's browser-open failure path: a ready DS service and its + gateway remain available for owner-scoped reopen/stop. Startup failures still + release their gateway. Focused regressions cover current credentials, work mode, + Node selection, concurrent open, owner isolation and retry. + The DS service also includes the coordinator configuration key in its own match + hash; updated skill digests or launch settings cannot reuse an older instance. +- DS Ask now maps built-in gateway read grants to the official MCP tool names. + Custom MCP remains Execute-only, following existing Runtime behavior. The real + DS process test loads an assigned directory containing `SKILL.md`, rather than + only a synthetic loose Markdown skill file. +- Custom standard Node uses the current local tool environment selection without + a separate npm install. The managed Node fallback still has a bespoke pinned npm + install and remains a delivery gap; it was not exercised by this real-model run. +- The opt-in IPC integration test uses the production action component, preload + methods, registered handlers, saved project/model stores, coordinator, official + DS Web process, and real Continue/OpenCode PTYs. Electron transport is simulated + by the existing IPC test harness and the action component runs in jsdom; this is + not a full desktop-window or packaged-app acceptance result. DS Web itself was + driven in real headless Edge. The hook retains credentials only in process + memory; the temporary settings file stores opaque test-cipher identifiers. + +| Client | Configured Model | Supplier HTTP Dispatches | Result | +| --- | --- | ---: | --- | +| DS Web 0.1.7-rc.2 | `deepseek-flash` | 2 | Workspace/model selected automatically; Web displayed `NATIVE_WEB_OK` | +| Continue 1.5.47 | `gpt-6-astra` | 4 | Two prompts and two title requests; second transcript confirms the assistant response, with underscores consumed by Markdown rendering | +| OpenCode 1.18.29 | `gpt-6-astra` | 1 | Native TUI displayed `NATIVE_OPENCODE_OK`; supplier response also contains it | +| Total | | 7 | All HTTP 200; no further dispatches needed | + +The first terminal assertion matched echoed prompt text and was rejected as +evidence. The second prompt did not contain the expected joined answer. The +OpenCode probe waits for the rendered TUI and uses bracketed paste before Enter. +The initial six-dispatch bound was increased to eight to cover the remaining +OpenCode path; seven were used in total. The host environment supplied +`NODE_TLS_REJECT_UNAUTHORIZED=0`, so this run does not verify strict TLS. + +Evidence under the approved temporary `opencode/dsh-017-verify` directory: +`native-live-evidence.json`, `native-main-result.json`, `native-web.png`, and +`native-{continue,opencode}-terminal.txt`. `native-live-run.cjs` composes the existing +encrypted settings snapshot/safeStorage bootstrap with the production IPC test. +Original `runtime-settings.json` remained byte-identical. The final test verifies +DS stop/reopen/owner isolation and failed fetch after stop, closes both terminal +sessions, and removes its temporary workspace/configuration. Owned live client +processes were absent after completion. + +Checks: official DS/coordinator focused tests passed (12) under standard Node 24.19.0; +the opt-in UI/preload/IPC test passed both without provider calls and with the live +hooks. Four installed Continue/OpenCode Ask/Execute tests passed with real clients +and deterministic supplier responses; these made zero external supplier calls. +Repository lint and Agent/Renderer TypeScript checks passed. Main typecheck is +currently blocked by concurrent SSH +test doubles missing `forwardLoopback`; no local native-client type errors remain. +The full `npm test` run finished with 5,285 passed, 79 skipped and one failure: +the desktop runtime-hook fixture lacked the new DS Web package tree. The fixture +was corrected and all 44 build-release tests then passed in a focused rerun. The +full run began before the final configuration-key regression and fixture updates; +the final DS/coordinator and UI/preload/IPC paths were rerun separately and passed. +This is not a claim of a subsequent all-green full-suite run. Full output is in +`native-full-tests.log` beside the live evidence. + +Remaining: remote coordinator wiring and real Host acceptance belong to the +concurrent remote implementation; Continue/OpenCode Ask built-in MCP mappings, +managed standard Node distribution, full Electron/packaged UI acceptance and other +platforms are not verified here. `ipc.ts` was not edited in this work. + ## 2026-09-26 结构升级与历史回收分离(未发布) - schema 45/46 的回归先复现普通结构升级执行 `VACUUM`,修复后不转换历史、 diff --git a/docs/features/assistant-workbar/runtime-native-client-proposal.md b/docs/features/assistant-workbar/runtime-native-client-proposal.md new file mode 100644 index 00000000..c62dd81a --- /dev/null +++ b/docs/features/assistant-workbar/runtime-native-client-proposal.md @@ -0,0 +1,393 @@ +# Runtime 原生客户端启动方案 + +日期:2026-09-26 +Status: Local shortcut/coordinator paths and configured-model responses verified on Windows; remote integration and packaged Node delivery remain open. +范围:Continue、OpenCode 的交互终端,以及 DeepSeek Harness(DS)的官方 Web 客户端。 + +本文集中维护该新增入口的需求、场景、行为规则、接入设计和验收计划。既有终端行为由 +[多终端页签 PRD](./terminal-tabs-prd.md)维护,既有 Runtime 权限和资源边界由 +[Runtime 交互边界](./runtime-interactions.md)维护;本文描述新增客户端路径,不宣称它已经具备后台 Runtime 的全部能力。 + +## 1. 方案选择 + +在聊天输入区“压缩上下文”左侧增加原生客户端入口。Continue 和 OpenCode 打开 GoodBuddy +工作栏中的交互终端;DS 启动官方 Web 服务并在系统默认浏览器中打开。使用当前项目目录和 +当前模型,默认建立独立客户端会话,不自动复制 GoodBuddy 聊天历史。 + +| 当前 Runtime | 按钮文字 | 打开目标 | 本轮计划范围 | +| --- | --- | --- | --- | +| Continue | 在终端中打开 | 工作栏新终端页签,启动原生 CLI | 本地和托管 SSH 项目 | +| OpenCode | 在终端中打开 | 工作栏新终端页签,启动原生 TUI | 本地和托管 SSH 项目 | +| DeepSeek Harness | 在浏览器中打开 | 系统默认浏览器,访问官方 Web 应用 | 本地项目 | +| 内置模型 | 不显示此快捷入口 | 无 | 保持现状 | + +DS 采用官方 `@deepseek-ai/dsh` Web 应用,不开发新的 DS 终端前端,也不在首轮嵌入 +GoodBuddy 浏览器工作栏。远程 DS 不在本轮范围:当前共享远程启动契约只接受 +`opencode` 和 `continue`,不能通过快捷按钮绕过该范围。 + +## 2. 调研依据与证据范围 + +下表保留早期测试报告,作为技术选型线索。2026-09-26 新增的 DS 0.1.7-rc.2 +实测单列在表后;Continue、OpenCode 和远程交互终端本轮未复测。 + +| 历史报告项目 | 报告结果 | 尚需验证 | +| --- | --- | --- | +| Continue 1.5.47 | 标准 Node 与真实 PTY 可显示交互输入、配置和模型名称;直接用 Electron 启动失败 | 启动路径错误、当前模型注入、真实请求和权限 | +| OpenCode 1.18.29 | 随包二进制可显示 TUI,响应终端尺寸变化 | 排除已有用户配置干扰,验证指定模型实际生效 | +| DS Web 0.1.5-rc.3 | Node 24.19.0 启动;Edge 可访问页面及模型设置 | 项目自动选中、模型桥、真实对话、工作模式 | +| DS Windows 依赖 | 首次缺少 Sharp 原生包,补装后可启动 | 正式资源中预先带齐各目标平台依赖 | +| DS 工作目录 | 指定 cwd 后仍要求选择工作区 | 工作区创建及页面选中的完整路径 | +| 终端相关回归 | 报告为 5 个文件、29 项通过 | 新入口尚无回归或端到端验收 | +| 远程 Host | 两条网络路线 SSH 端口可达 | 登录后的当前源码、Runtime、模型桥真实验证 | + +早期文档整理和依赖升级报告的真实模型调用为 0 次。本轮核查另发现临时目录 +`dsh-017-live` 的 7 次历史 dispatch 记录;本轮在独立 `dsh-017-verify` 目录新增 +9 次,两个计数分别保留。测试过程和结果以 [DS 实现进度](../deepseek-harness/progress.md#2026-09-26-真实模型与官方-web-验证)为准。 + +本轮直接检查了以下仓库材料: + +- `src/main/terminal/terminal-session-manager.ts`:已有本地与 SSH 会话创建、窗口归属、事件转发和关闭管理,当前创建路径启动普通终端。 +- `src/shared/remote-runtime-launch-contracts.ts`:远程 Runtime 枚举包含 Continue 和 OpenCode。 +- `UI-DESIGN.md`:规定 Composer 元信息区、工作栏、通知、键盘及响应式规则。其聊天章节仍写远程只支持 OpenCode,与当前共享契约不一致;实施时需沿 UI 到执行路径核实并同步修正,不能单凭枚举认定远程交互已可用。 + +上游参考:[官方仓库](https://github.com/deepseek-ai/deepseek-harness)、 +[CLI 文档](https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/cli/README.md)、 +[使用指南](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/guide/index.md)。 +这些链接随上游变化;实施时须为选定包版本补充对应源码 revision、启动参数和接口依据。 +历史测试版本是候选版本,不作为未经复测的最终发布版本。 + +2026-09-26 仓库内后台 DS Runtime 已升级至 `0.1.7-rc.2`,Cordis 升级至 +`4.0.4`,验证记录见 [DS 实现进度](../deepseek-harness/progress.md)。此版本来自 +npm `next` 标签;查询时 `latest` 仍为较旧的 `0.1.0-rc.6`。本轮另用官方 +`@deepseek-ai/dsh@0.1.7-rc.2` 验证 Web。Prepared Web resources and backend validation are recorded in section 9.1. + +### 2.1 DS 0.1.7-rc.2 实测结论 + +Windows x64、标准 Node 24.19.0、Edge 154.0.4258.37 下,官方 Web 可承接当前 +工作区和已配置模型,完成页面真实对话。Main 使用 safeStorage 解密隔离副本中的模型 +配置,经现有 managed model bridge、AgentModelGateway 和 loopback proxy 转发。 +浏览器与 DS 只取得本地桥接信息,原始 `runtime-settings.json` 测前测后逐字节一致。 + +| 实测路径 | 结果 | 供应商 HTTP dispatch | +| --- | --- | ---: | +| 后台 Ask → `read` | 返回文件中未写入 prompt 的随机校验码,收到工具完成及用量事件 | 2 | +| 同一后台会话切 Execute → `write` | 创建测试文件,内容校验通过 | 2 | +| Execute → `pwsh` | PowerShell 读回该文件,结果正确 | 2 | +| 官方 Web → 当前模型 → 文件读取 → 回答 | 页面返回另一随机校验码,刷新后保留结果 | 3 | +| 合计 | 请求中的模型均为 `deepseek-flash`,HTTP 均为 200 | 9 | + +`0.1.7-rc.2` 是 Harness/Web 包版本;`deepseek-flash` 是实际配置和请求中的模型 ID。 +Web 的 3 次请求包含 1 次未携带工具的请求,计数没有只按用户提交次数计算。 +后台使用当前源码的真实 ACP、Host、控制面和供应商流式响应,但 Host 在测试进程内组合; +该结果不等于重新验收 GoodBuddy 完整 UI 或 Utility Process。Web 使用真实 CLI 子进程和 +浏览器自动化,未通过尚未实现的快捷按钮。测试继承了环境中的 +`NODE_TLS_REJECT_UNAUTHORIZED=0`,因此没有验证严格 TLS 证书校验。 + +工作区和模型自动准备已验证;官方 Web 到 GoodBuddy Ask/Execute 的工具执行适配、 +Skills/MCP 承接、取消和产品生命周期仍待实现与验证。此次可行性验证不要求完成按钮。 + +## 3. 产品需求 + +| ID | 要求 | 用户可见的验收结果 | +| --- | --- | --- | +| FR-1 | 在压缩按钮左侧提供 Runtime 对应入口 | 无历史、无压缩能力时仍能打开客户端 | +| FR-2 | 按项目执行空间启动 | 本地使用本地目录,SSH 使用绑定 Host 与远端目录;目录失效时说明原因 | +| FR-3 | 注入点击时选定模型 | 客户端首轮直接使用该模型,无需重复输入供应商密钥 | +| FR-4 | 创建独立客户端会话 | 不修改原聊天历史,不把打开操作伪装成当前聊天的续接 | +| FR-5 | 保持所选工作模式的执行边界 | Ask 的 AI 工具路径只读;Execute 使用相应账号已有权限 | +| FR-6 | 管理启动、重开和关闭 | 不因收起工作栏或切换项目中断;关闭对应客户端资源时释放其桥接 | +| FR-7 | 保留可处理的失败信息 | 启动、模型和远程错误可区分,允许修正后重试,不清空聊天草稿 | +| FR-8 | 明确原生能力与 GoodBuddy 能力差异 | 已分配的 Skills、MCP 等逐项接入并验证;未接入项有明确说明 | +| FR-9 | 交付可直接运行的客户端资源 | 用户无需自行运行 npx、补装 Sharp 或查找 Node | + +聊天附件、知识范围、专家提示及历史不自动移入独立客户端。首轮不提供聊天双向同步、 +Task 关联恢复或客户端历史导入。原生客户端产生的历史由对应客户端保存,不能在 GoodBuddy +活动记录中显示为已经同步的聊天内容。 + +FR-8 的实施清单须区分原生工具、GoodBuddy 分配的 Skills、自定义 MCP、内置 MCP、知识工具 +以及需要 GoodBuddy 原生确认的配置工具。支持情况以真实调用为准;现有 DS 宿主插件能力不能 +直接算作 DS Web 能力。发现现有分配无法承接时,在实施评审中明确差异和处理方式,不能默默忽略。 + +## 4. 场景与状态规则 + +### 4.1 用户场景 + +| ID | 前提与动作 | 预期结果 | 需求 | +| --- | --- | --- | --- | +| US-1 | 本地项目选中 Continue 或 OpenCode,点击入口 | 展开工作栏,新建带 Runtime 与项目名称的终端,进入可输入的原生界面 | FR-1~4 | +| US-2 | 本地项目选中 DS,首次点击入口 | 服务就绪后打开浏览器,当前项目已选中、模型可直接使用 | FR-2~4、9 | +| US-3 | 在支持的 SSH 项目点击终端入口 | 使用已保存 Host 连接,在远端项目目录启动对应 Runtime | FR-2、3 | +| US-4 | 启动期间连续点击 | 同一启动只创建一次;按钮显示启动中 | FR-6 | +| US-5 | 已打开客户端后切换项目或模式 | 旧客户端保持原项目和启动模式;新操作使用新选择 | FR-5、6 | +| US-6 | 启动失败或模型请求失败 | 保留原因与可操作的重试方式;聊天内容和草稿不变 | FR-7 | +| US-7 | Ask 下从原生界面请求写文件、执行写命令或使用写入 MCP | AI 执行边界拒绝写入,不能通过客户端模式开关绕过 | FR-5、8 | +| US-8 | 关闭终端、停止 DS 服务或退出 GoodBuddy | 对应进程和桥接释放,其他会话不受影响;原生历史保留 | FR-4、6 | + +### 4.2 行为决策 + +启动参数按点击时的项目、执行空间、Runtime、模型和工作模式确定。界面后续切换不修改已运行 +客户端。这里只需保留进程运行所需的内存记录,不增加持久启动快照、恢复日志或数据库迁移。 + +Continue 和 OpenCode 启动成功后,每次新的点击创建独立终端。启动中的重复点击合并到同一 +进行中操作。终端会话数量沿用现有管理器规则,不新增一套数量控制。 + +DS 按项目、模型配置及工作模式匹配运行服务。配置相同且服务可用时重新打开原服务;配置变更后 +新建匹配实例,保留原实例直到用户停止或应用退出,避免在已有页面中静默改变模型和权限。 +同一匹配项并发启动只执行一次。服务已退出则清除内存记录,下一次点击重新启动。 + +| 事件 | 处理 | 关联场景 | +| --- | --- | --- | +| 启动中切换项目 | 操作仍属于原项目;完成时不抢占新项目的工作栏焦点 | US-4、5 | +| 收起工作栏、切换页面 | 保留终端与其模型桥 | US-5 | +| 关闭终端页签 | 停止该 PTY/远端进程,释放相应配置和桥接 | US-8 | +| 关闭 DS 浏览器标签 | 不推断服务已停止;再次点击可重开 | US-2、8 | +| 用户停止 DS 服务 | 停止该服务和桥接;浏览器页面失去连接;保留原生历史 | US-8 | +| GoodBuddy 退出 | 清理自己创建的进程与桥接,不停止用户其他进程 | US-8 | +| SSH 断开 | 显示断开;收束对应请求,重试时重建连接,不宣称原会话已恢复 | US-3、6 | +| 系统浏览器打开失败 | 保留可重开的就绪服务,通知用户重试;不复制含令牌地址到普通日志 | US-6 | +| 服务启动失败 | 清理本次创建的临时资源,再允许重试;不删除用户原生历史 | US-6 | + +Ask 沿用现有 Runtime 按工具命令名判断的只读规则,不改变用户手动终端的已有权限。 +DS 后台的 `read` 和原生 `skill` 可在 Ask 执行;`write`、`edit`、`pwsh`/`bash` +在 Ask 拒绝,在 Execute 放行,代理工具沿用现有分类。工具出现在模型请求目录中不等于 +获准执行,判断仍在 `tools/execute` 路径。Web 接入复用这些规则,不增加 Shell 文本分析、 +目录围栏、逐工具二次确认或新的权限等级。Execute 使用当前账号已有的文件、进程和网络权限。 + +官方 `dsh-plan-mode@0.1.7-rc.2` 的 Plan 只改变规划提示和状态,工具目录不随之变化; +权限预设由另外的 sandbox/approval 组件处理。因此不能把 Plan 名称当成 Ask 实现, +也不能把官方默认“工作区内修改”当成 GoodBuddy Execute。接入时将启动模式接到现有 +工具名规则,原生页面的模式选择保持同一语义。 + +这些规则覆盖普通启动、使用、关闭和已知失败。尚需技术验证的项目见第 7 节;它们不构成新增 +授权层级或通用恢复框架的理由。 + +## 5. 界面设计 + +输入区下方从左到右排列“在终端中打开/在浏览器中打开”“压缩上下文”和现有用量信息。 +两个按钮独立判断可用性。采用同一轻量操作组,避免两组绝对定位相互覆盖;窄输入区允许 +操作组换行,保留模式说明、用量信息和对称边距。稳定预留元信息高度的实现应与 +[统一 UI 规范](../../../UI-DESIGN.md)一起更新并验证。 + +按钮使用原生 `button`、共享主题令牌和焦点环,支持 Tab、Enter 与 Space。打开终端后焦点 +进入新终端;外部浏览器由系统处理焦点。启动期间保留按钮宽度并显示“正在打开…”,完成后 +恢复原文案。缺少项目目录时在相关位置提供选择目录的操作;其他异步失败进入全局通知视口。 + +DS 服务运行后,在入口旁提供轻量菜单“重新打开”“停止此服务”;操作指向当前匹配服务。 +若正在生成,停止前说明会中断该服务中的请求。页面附近简短说明“独立会话;关闭网页后服务 +仍运行,可在此停止,退出 GoodBuddy 时停止”。不在每次启动时增加确认弹窗。 + +按钮快捷入口根据所选 Runtime 显示,不改变工作栏“+”中的普通终端和浏览器入口。已有服务 +的停止入口应在切换回来后仍可找到。 + +## 6. 技术接入 + +### 6.1 进程职责 + +Renderer 仅提交当前会话或项目标识及选择标识。Main 重新解析项目、模型配置、工作模式与 +程序路径,通过共享 Zod 契约和显式 preload 方法完成调用。保留已有可信发送方校验,供应商 +密钥留在 Main 加密设置和模型请求路径中。 + +建议新增小型原生客户端启动服务,负责配置准备、启动去重和资源释放。终端会话仍由 +`TerminalSessionManager` 管理;DS 服务只需内存中的子进程、地址和桥接引用。不要新建平行 +终端管理器或通用进程恢复引擎。 + +共享接口应返回可供界面使用的启动状态、终端标识或 DS 服务标识。外部 URL 由 Main 打开, +不允许 Renderer 提交任意程序、命令行、凭据或任意服务地址。错误保留组件、阶段和脱敏原因。 + +### 6.2 Continue 与 OpenCode + +Continue 使用已解析的标准 Node 启动固定版本 CLI,不能直接假定 Electron 的 +`process.execPath` 等于 Node。OpenCode 使用已有平台对应可执行资源,启动交互 TUI。 +两者均复用现有配置生成机制,但单独验证原生交互模式可接受的参数、模型 ID、环境变量及 +Skills/MCP 配置,避免继承测试机器的全局默认模型。 + +本地 PTY 创建需接受 Main 生成的可执行路径、参数、环境和 cwd,不能先打开普通 Shell 再 +模拟键入一段含凭据的启动命令。退出 CLI 后是否保留终端输出沿用既有终端体验;其桥接应 +随 CLI 生命周期收束,不等到整个聊天结束。 + +模型桥作为客户端会话资源保持有效。复用前检查当前桥接是否依赖单轮请求、单一消息 ID +或短时授权;必要时只提取所需的会话级资源接口。真实供应商密钥不写入 CLI 配置,客户端 +仅获得桥接所需的局部连接信息。 + +### 6.3 DS Web + +使用固定版本的官方 Web 包,通过标准 Node 在回环地址启动。以下命令已在 +`@deepseek-ai/dsh@0.1.7-rc.2`、Windows x64、Node 24.19.0 下启动成功: + +```text + web --no-open --host 127.0.0.1 --port 0 +``` + +生产环境直接使用已准备的资源,不在用户点击时执行不固定版本的 `npx`。Web 资源与当前 +DeepSeek Harness 后台 Host 依赖分开管理,避免为了 Web UI 升级而隐式替换后台 Agent 库。 +沿用既有受管工具环境和资源分发机制,不新增下载体系。若需在线分发,按该功能文档规范 +明确下载源设置范围、固定版本、大小和 SHA-256;镜像与原地址使用相同字节内容。 + +使用 GoodBuddy 管理的独立 `DSH_HOME`,与用户已有 DS 安装隔离。原生历史和用户设置属于 +持久数据,服务退出只删除可重建启动配置。多个运行实例不得共享不支持并发访问的数据库; +在验证官方存储行为后确定按项目及配置分目录的最小方案。 + +启动后经官方支持的配置/API 创建或查找项目工作区,初始化模型连接,再打开已选中目标 +工作区的页面。仅设置 cwd 或成功创建后台工作区都不足以完成该步骤。不得直接修改未经 +确认的 DS 私有数据库结构。 + +本轮验证使用 `$DSH_HOME/cordis.patch.yml` 配置 `llm-pi-ai` 的 `goodbuddy` provider, +设置 `api: openai-completions`、本地桥 `baseURL`、`apiKeyEnv` 和模型列表; +`agent-default-model` 指向同一 provider/model。环境变量中只放本地桥接标识。 +官方 CLI 的 `profile-boot` 代码将该 patch 作为用户配置层加载。 + +取得官方启动地址并建立认证 cookie 后,调用 `POST /api/workspace/create`,请求形态为: + +```json +{ + "type": "client-request", + "rpcId": "", + "method": "workspace/create", + "payload": { "args": { "request": { "path": "" } } } +} +``` + +该接口在首次运行返回 `created: true`,重开同一测试目录时返回 `created: false`。 +随后访问根页面,两次均自动选中 `workspace` 和 `deepseek-flash`,没有手动选择模型或 +再次输入供应商密钥。此证据覆盖单项目、独立 `DSH_HOME`;多项目共享服务的选中规则未测。 +首次页面保留官方“内测声明”的“继续”操作;测试通过原生按钮继续,没有伪造接受记录。 +官方默认权限显示“工作区内修改”,本轮只验证读取;权限适配按第 4.2 节另行接入。 + +Main 检查服务就绪后,使用 Electron `shell.openExternal` 打开官方规定的访问地址。 +如地址带认证令牌,沿用官方认证方式,不写入普通日志。浏览器只访问本机服务;模型请求 +通过 Main 中的桥接到达供应商。HTTP、流式响应、取消和错误映射都需实测。 + +### 6.4 远程 Continue / OpenCode + +沿用 SSH Host 身份、凭据存储和 SSH PTY,并通过既有 GoodBuddy Agent 部署资源定位远端 +Runtime。远端配置与模型桥需要客户端生命周期,不能直接复用一次聊天请求结束即释放的 +桥接实例。远端使用已有模型桥协议及传输路径,是否需要补充生命周期接口由源码验证决定。 + +开发时必须在共享 Linux x64 Host 上运行当前改动,按 +[远程主机技术设计](../remote-host/technical-design.md)执行真实启动、模型请求、取消、 +断开和清理。端口可达不等于验证通过;若 Host 不可达,应记录阻塞,不能宣布远程功能完成。 + +远程 DS 将来若扩展,可评估远端 Web 加 SSH 本地端口转发;本轮不修改 DS 远程能力声明。 + +## 7. 实施顺序与技术验证 + +| 阶段 | 工作与应提交证据 | 通过条件 | +| --- | --- | --- | +| P1 原生配置验证 | 固定三个客户端版本;保存脱敏命令、环境与程序路径;隔离已有全局配置 | Continue/OpenCode 使用指定模型;DS 自动选中目标项目 | +| P2 模型与模式 | 每个客户端发送最小真实请求;验证流式、取消、Ask 写入拒绝及 Execute 专用目录写入 | 请求确实经过 GoodBuddy 模型桥;客户端模式切换不能破坏 Ask 边界 | +| P3 生命周期接入 | 配置、PTY、DS 进程和模型桥接入现有管理路径 | 重开、失败重试、关闭及退出能释放对应资源,原生历史保留 | +| P4 远程验证 | 在共享 Host 部署当前代码,验证 Continue/OpenCode 的 SSH PTY 与模型桥 | 启动、请求、取消、断开和重试均有真实 Host 证据 | +| P5 UI 与交付资源 | 接入按钮、通知、停止 DS 服务;完善平台资源与文档 | 从真实按钮到客户端完成对话,无手动补依赖步骤 | + +P1、P2 是实施前段的实验任务,完成后继续交付完整入口,不将实验程序或不可用按钮作为最终功能。 + +DS 单项目工作区选中和当前模型桥协议已通过本轮验证。后续优先接入三个客户端的既有 +Ask/Execute 工具规则、Skills/MCP 配置及客户端生命周期,再完成快捷入口和交付资源。 +官方 DS 首次预览声明保留原生“继续”流程,模型配置提前准备。 + +## 8. 验收计划 + +| 验收面 | 检查内容 | 需求与场景 | +| --- | --- | --- | +| 实际使用 | 每个本地客户端从 GoodBuddy 按钮进入当前项目,使用当前模型完成一轮真实对话 | FR-1~4、US-1、2 | +| 配置隔离 | 预置另一套全局模型后,仍使用当前选择;两个项目不串目录或配置 | FR-2、3、US-5 | +| 工作模式 | Ask 尝试文件写入、Shell 写入和 MCP 写入均不执行;Execute 在专用测试目录成功写入 | FR-5、8、US-7 | +| 能力复用 | 为声明支持的 Skills、MCP 各验证实际加载及最小调用;列出未承接能力 | FR-8 | +| 生命周期 | 连点启动、切项目、隐藏工作栏、关闭页签、重开 DS、停止服务及退出 | FR-6、US-4、5、8 | +| 已知失败 | Node/原生依赖缺失、失效目录、模型错误、浏览器打开失败、SSH 中断 | FR-7、9、US-6 | +| 远程 | 当前源码在共享 Linux x64 Host 上完成 Continue/OpenCode 的 Ask/Execute、模型和断开场景 | FR-2、3、5、US-3 | +| UI | 浅深色、键盘操作、窄输入区、无压缩按钮、空对话、200% 文字缩放 | FR-1、US-1、2 | +| 平台资源 | 对实际交付的 Windows、macOS、Linux 架构逐项验证 Node、PTY、CLI 和 DS 原生依赖 | FR-9 | + +完成源码后执行 `npm test`、`npm run typecheck`、`npm run lint`。修改生产构建资源时再按 +仓库开发规则执行构建验证。单元测试覆盖行为和回归,不能代替真实按钮、模型和远程 Host 路径。 +每份实测报告记录日期、源码 commit、包版本、平台、结果、脱敏证据位置及实际模型调用次数。 + +## 9. 文档交付状态 + +本轮完成 DS 后台真实模型与官方 Web 主流程验证,更新方案和 +[DS 进度证据](../deepseek-harness/progress.md#2026-09-26-真实模型与官方-web-验证)。 +P1 中 DS 单项目启动、模型预配置和工作区选中,以及 P2 中 DS 模型桥请求已实测。 +The DS Web backend implementation and its focused validation are recorded below. Current local shortcut evidence is recorded in [workbar progress](./progress.md#2026-09-27-local-native-client-validation); full Electron UI acceptance remains separate. +后续入口交付事实写入工作栏 [progress.md](./progress.md),按 FR、US 和阶段编号关联本方案。 + +实施时同步更新工作栏产品范围、终端规范、Runtime 交互边界及根 UI 规范;DS Web 的版本、 +依赖与兼容性写入 [DeepSeek Harness 文档](../deepseek-harness/README.md),远程部署事实写入 +[远程主机文档](../remote-host/README.md)。保持各自职责,不复制多个相互冲突的支持矩阵。 + +### 9.1 DS Web Backend, 2026-09-26 + +`src/main/agent/native-dsh-web-client.ts` exports `NativeDshWebClientService`. +Construct it with `rootDirectory`, an async `resolveLaunchEnvironment` returning +`{ nodeExecutablePath, environment }`, and `resourcesPath` in packaged builds. +`start({ projectId, workspace, profile, workMode, configurationKey?, skillDirectories?, mcpServers? })` +returns `{ id, url }`. Main opens this URL with `shell.openExternal`; it must not +log the token-bearing URL or pass it to Renderer. `stop(id)` and `dispose()` close +the owned process tree and bridge. A browser-open failure leaves the service ready +for another call. Matching concurrent starts reuse one instance; changed model +credentials, project, mode, or capability assignments create a separate instance. + +The service uses the existing managed model bridge, AgentModelGateway, and loopback +proxy. Provider credentials stay in Main. Each matching configuration has its own +persistent DSH_HOME. Shutdown removes launch configuration and the bridge ledger, +while retaining native history and settings. Startup authenticates through the +official launch URL and calls `workspace/create` before returning. + +The host-level `tools/execute` hook permits native `read` and `skill` in Ask. +Assigned MCP servers supply their already-classified `readOnlyTools` as raw MCP +tool names; all other tool names are denied in Ask. Execute uses native full-access +permissions with no additional approval. The native permission picker is hidden; +changing Plan or creating another native session does not change the launch policy. +Skill directories and stdio/streamable-HTTP MCP configurations use official plugins. +Knowledge, built-in MCP, and GoodBuddy confirmation/configuration tools require a +caller-owned MCP adapter and are not automatically exposed by this service. + +`@deepseek-ai/dsh@0.1.7-rc.2` is a pinned build dependency. The existing packaging +hook copies its installed dependency tree, including frontend assets and nested +dependency versions, to `resources/runtimes/dsh` outside ASAR. Target Sharp and +Koffi packages come from exact lockfile entries through the existing artifact +preparation code. The Web package itself needs no click-time npm install. The +coordinator now honors the current custom Node selection from the local tool +environment. Its managed fallback still installs `node--@22.22.0` +through npm; this does not yet satisfy the prepared-resource delivery requirement +in section 6.3. No new download setting was added. + +Focused tests use standard Node 24.19.0 on Windows x64 and the prepared resource +tree. They exercise Web startup, authentication, project creation, reuse, +mode isolation, stop/restart, retained history, and real Web API tool execution. +Deterministic model responses travel through the production model bridge: Ask +rejects writes, Execute creates the expected file, assigned skills load, read-only +MCP executes, and writing MCP is rejected before dispatch in Ask. These backend +tests make zero external model-provider calls. This evidence does not claim a +signed installer, other platforms, or the complete shortcut UI has been verified. + +Validation: seven focused tests passed against the prepared resource tree; +the copied Sharp 0.35.4 native module encoded a PNG successfully; Main TypeScript +checking and `npm run build:bundle` passed. Full `npm run build`/typecheck and +`npm run lint` encountered concurrent Renderer errors in App.test.tsx and +RightAssistantSidebar.tsx; the backend files passed focused lint. Remote Agent +launch paths are unchanged because this service supports local DS Web only. + +### 9.2 Local Coordinator Integration + +The production coordinator resolves the saved conversation/project and current +settings for both `get` and `open`. Matching includes the selected model profile +and credentials, work mode, capability assignments, knowledge scope, Obsidian +settings and local Node selection. Ready services keep their MCP gateway after an +OS browser-open error and can be reopened or explicitly stopped by their owner. +The coordinator passes its configuration key into the service's existing match +hash, so the inner DS reuse decision also observes updated skill digests and +launch settings even when directory paths are unchanged. + +For DS Ask, the built-in gateway's existing read grant supplies the allowed raw +tool names; the Web adapter maps these through the official MCP naming contract. +Custom MCP is exposed in Execute, matching the existing Runtime behavior; custom +`readOnlyHint` annotations do not introduce a separate Ask permission rule. +Assigned skill directories containing `SKILL.md` load through the official skill +plugin. Continue/OpenCode native Ask currently omit MCP endpoints, including +built-ins; extending their existing native name mappings remains separate work. + +The coordinator remains local-only at this checkpoint. The remote implementation +is being developed separately and must be connected and verified on the shared +Host before remote shortcut support can be claimed. Current checks and exact +supplier counts are maintained in the workbar progress record linked above. diff --git a/docs/features/assistant-workbar/runtime-process-reuse-technical-design.md b/docs/features/assistant-workbar/runtime-process-reuse-technical-design.md index eca5ce94..f4cd2455 100644 --- a/docs/features/assistant-workbar/runtime-process-reuse-technical-design.md +++ b/docs/features/assistant-workbar/runtime-process-reuse-technical-design.md @@ -70,6 +70,9 @@ schema 35 的存储修复与本方案独立,不能回退或删历史来改善 | Cordis | 4.0.2 | Host 根组件与 Agent scope 的生命周期 | | Continue CLI | 1.5.47 | 实际受管补丁入口的单 `M.session`、QuizService 和权限状态 | +本表保留进程复用探针执行时的版本。2026-09-26 DS 已升级为 `0.1.7-rc.2`, +Cordis 为 `4.0.4`;当前依赖及升级回归见 [DS 实现进度](../deepseek-harness/progress.md)。 + 已通过的三个隔离探针: 1. **OpenCode HTTP**:调用当前生产 Server launcher,只有一次 spawn;同一个 SDK client diff --git a/docs/features/deepseek-harness/README.md b/docs/features/deepseek-harness/README.md index db433567..6a16d29d 100644 --- a/docs/features/deepseek-harness/README.md +++ b/docs/features/deepseek-harness/README.md @@ -16,3 +16,12 @@ [Runtime 进程复用技术设计](../assistant-workbar/runtime-process-reuse-technical-design.md) 统一维护;本 Runtime 的生命周期见[技术设计 §9](./technical-design.md#9-runtime-生命周期), 未发布实现的验收状态见[工作栏进度](../assistant-workbar/progress.md#2026-09-14-runtime-进程复用实施中)。 + +The separate official Web client is pinned to `@deepseek-ai/dsh@0.1.7-rc.2`. +Its Main service API, Ask/Execute policy, capability adapters, packaged resource +layout, and Windows validation are documented in +[Native Client Proposal, section 9.1](../assistant-workbar/runtime-native-client-proposal.md#91-ds-web-backend-2026-09-26). +This Web resource tree is prepared separately from the background Harness Host. +Current shortcut/coordinator behavior and configured-model evidence are tracked in +[local native client progress](../assistant-workbar/progress.md#2026-09-27-local-native-client-validation), +including the remaining managed Node delivery gap. diff --git a/docs/features/deepseek-harness/progress.md b/docs/features/deepseek-harness/progress.md index 602070dd..1d5b88b1 100644 --- a/docs/features/deepseek-harness/progress.md +++ b/docs/features/deepseek-harness/progress.md @@ -1,5 +1,91 @@ # DeepSeek Harness 实现进度 +## 2026-09-26 真实模型与官方 Web 验证 + +本轮验证 `0.1.7-rc.2` 后台对话/工具路径与同版本官方 Web 的本地接入可行性,关联 +[原生客户端方案](../assistant-workbar/runtime-native-client-proposal.md)的 FR-2、3、5, +US-2 和 P1/P2。快捷按钮与完整客户端集成本轮未实现。 + +环境:Windows x64,标准 Node `24.19.0`,Edge `154.0.4258.37`,官方 +`@deepseek-ai/dsh@0.1.7-rc.2`,仓库 HEAD `51166136157a646530e1ad9f6a0242c1c6390e95` +加当前未提交修改。源码哈希记录在本机临时报告 `dsh-017-verify/source.json`。 +供应商实际模型为当前 DS 配置中的 `deepseek-flash`,协议为 `openai-chat-completions`。 + +| 场景 | 实测结果 | HTTP dispatch | +| --- | --- | ---: | +| 后台 Ask | `read` 返回未出现在 prompt 中的随机校验码 | 2 | +| 同会话切 Execute | `write` 创建文件,实际内容为 `DSH_EXECUTE_OK` | 2 | +| Execute Shell | `pwsh` 执行 `Get-Content execute-marker.txt`,返回正确内容 | 2 | +| 官方 Web 页面提交 | 当前模型读工作区文件并返回另一随机校验码;刷新仍保留回答 | 3 | +| 本轮合计 | 9 次均请求 `deepseek-flash`,9 次均返回 HTTP 200 | 9 | + +计数在 `AgentModelGateway` 向供应商执行 `fetch` 时记录,包含 Web 的 1 次无工具请求; +4 次用户提交实际产生 9 次供应商请求。后台 3 轮均收到 `done`、工具 `completed` +和每轮 2 个用量事件。调用经过现有 `createManagedModelBridge`、`AgentModelGateway` +和 `ModelBridgeLoopbackProxy`,由隔离 Electron profile 中的 safeStorage 解密配置副本。 +供应商凭据未写入 Web 配置或报告;正式 `runtime-settings.json` 测前测后逐字节一致。 +环境继承 `NODE_TLS_REJECT_UNAUTHORIZED=0`,本轮不证明严格 TLS 证书校验可用。 + +官方 Web 以标准 Node、独立 `DSH_HOME` 和回环随机端口启动。通过官方 patch 配置 provider +和默认模型,再调用 `workspace/create`;首次创建和已有目录复用均通过。根页面自动选中 +测试工作区和当前模型,无需手动填供应商密钥。保留并通过官方“内测声明”的“继续”按钮, +真实页面输入、发送、回答、刷新及截图检查通过。配置/API 细节统一维护在方案第 6.3 节。 + +本轮驱动曾因缺少 `skillPackages` 默认值和临时目录动态模块解析失败退出,均为 0 次请求; +修正驱动后后台成功。首次 Web `fill` 后发送按钮未启用,没有发出 Web 模型请求;改为键盘 +输入并仅重跑 Web 后成功,未重复后台调用。本轮 9 次 dispatch 逐次记录于同一 `calls.json`。 + +补查发现此前 `dsh-017-live/calls.json` 已有 7 次 HTTP 200 记录,其中后台 4 次、Web 3 次; +对应历史报告记录模型 `deepseek-flash`、工作区与模型选中、文件结果及配置未改。本轮保留 +这些文件,未覆盖或重算为新增调用。该历史批次与本轮合计可核查 16 次,下面依赖升级阶段 +“0 次”仅指升级回归本身。 + +定向命令使用标准 Node 执行 `node_modules/vitest/vitest.mjs run`,目标为 +`src/main/agent/deepseek-harness-acp-e2e.test.ts`、 +`src/main/agent/goodbuddy-harness-control-plane.test.ts` 和 +`src/main/agent/deepseek-harness-runtime.test.ts`:3 个文件、52 项通过、3 项跳过,11.12 秒。 +3 个环境开关 live case 未在 Vitest 中启用;上表为独立真实模型驱动结果,不把跳过项算通过。 +确定性回归包含 Ask 写入拒绝和 Execute 工作区外写入,无需为验证重复调用真实模型。 + +本机证据位于临时 `dsh-017-verify/`:`calls.json`、`backend-result.json`、`result.json`、 +`main-result.json`、`source.json` 和 `web-conversation.png`。报告保留首次 Web 驱动失败, +最终 Web 结果另见 `result.json`。桥接、worker、Web 和浏览器已关闭,进程检查未发现本轮 +目录所属的残留进程;临时 profile、测试工作区和 DS home 清理后仅保留脚本及脱敏证据。 +这些本机临时文件不作为仓库长期资源。 + +证据范围:后台运行真实 ACP/Host/控制面和供应商模型,Host 在测试进程内组合;Web 为 +官方 CLI 子进程与真实浏览器页面。未重新验收 GoodBuddy Composer/Utility Process, +也未实现 Web 的 GoodBuddy Ask/Execute 适配。官方 Plan 只控制规划状态,默认 +“工作区内修改”也不等同于 Execute;后续复用现有工具命令名判断,不增加权限层级、 +目录限制或逐工具二次授权。Skills/MCP 承接、取消、产品生命周期及交付资源仍待验证。 +未改远程源码;DS 仍不支持 SSH execution space,本轮没有远程模型调用或 Linux Host 验证。 + +## 2026-09-26 依赖升级至 0.1.7-rc.2 + +23 个直接引用的 `@deepseek-ai/dsh-*` 包统一锁定为 `0.1.7-rc.2`,Cordis +升级为上游要求的 `4.0.4`,同步更新依赖锁文件、Runtime 版本及打包测试夹具。 +版本取自 npm 发布列表与 `next` 标签;查询时 `latest` 仍指向 `0.1.0-rc.6`。 + +控制面改为监听 `agent/assistant-stream` 的 chunk 帧,以转发文本、推理和用量; +工具结果从 message 层读取 `toolCallId` 和 `isError`。测试同步适配新版本的 +Agent 配置、Shell 执行和系统消息接口。 + +- DS 定向回归:152 项通过、5 项跳过。 +- 最终复跑 DS、Runtime discovery 和发布打包夹具:12 个文件通过、2 个跳过, + 170 项通过、5 项跳过,耗时 19 秒。 +- 扩大至打包夹具和设置面板:196 项通过、5 项跳过;设置面板套件因并行 + Obsidian 修改缺少 `obsidian-tools` 模块而未能加载。 +- `npm run smoke:deepseek-harness`:开发构建通过,真实 Electron Utility Host 返回 `ready`。 +- 升级后的首次类型检查与 lint 通过;后续类型检查受到并行 Obsidian 修改中的 + 模块缺失、项目文件列表和类型错误阻塞,不能将当前整个工作区标为检查通过。 +- 全量测试两次运行分别在 200 秒、600 秒超时,期间出现 App、SupervisorActivity + 和 Electron UI 测试失败;未取得全量通过结果,未修改这些并行工作的文件。 + +本次依赖升级回归的真实供应商模型调用为 0 次;后续真实模型及 Web 实测见上节。上述升级验证不包含官方 Web 应用, +“在浏览器中打开”入口仍按[原生客户端方案](../assistant-workbar/runtime-native-client-proposal.md)实施。 +远程启动契约和资源打包仅支持 Continue、OpenCode,`create-runtime.ts` 拒绝 SSH +执行空间使用 DS,因此本次升级未改变远程 Runtime 路径,也未进行 Linux Host 验证。 + ## 2026-09-14 Windows 工作区路径修复 本机 Runtime 的 Host 启动与 `newSession.cwd` 已共用初始化时解析的 `realpath`, diff --git a/docs/features/deepseek-harness/technical-design.md b/docs/features/deepseek-harness/technical-design.md index 8ea8cc7c..231462b1 100644 --- a/docs/features/deepseek-harness/technical-design.md +++ b/docs/features/deepseek-harness/technical-design.md @@ -7,7 +7,7 @@ | 文档状态 | 实现与发布验收基线 | | 设计目标 | 将 DeepSeek Harness 作为 GoodBuddy 的第三个 Agent Runtime | | Runtime 标识 | `deepseek-harness` | -| 当前依赖基线 | 实际使用的 `@deepseek-ai/dsh-*` 底层库,精确锁定 `0.1.2-rc.1` | +| 当前依赖基线 | 实际使用的 `@deepseek-ai/dsh-*` 底层库,精确锁定 `0.1.7-rc.2`,Cordis 为 `4.0.4` | | 上游状态 | Developer Preview,允许出现破坏性变更 | | 上游许可证 | MIT | | GoodBuddy 目标平台 | Windows、macOS、Linux,x64 与 arm64 | @@ -145,7 +145,7 @@ Harness 子进程内控制面不能取代 Main 控制面,Main 控制面也不 Harness Session 只在当前 Runtime 进程生命周期内存在。释放 GoodBuddy 会话时必须同步释放对应 Harness Agent。 固定 Host 显式加载 `dsh-session-projection` 的内存 SessionProjectionRegistry,这是 -`0.1.2-rc.1` AgentLoop 的必需依赖;不加载 Session persistence,也不新增磁盘会话副本。 +`0.1.7-rc.2` AgentLoop 的必需依赖;不加载 Session persistence,也不新增磁盘会话副本。 该依赖与其余 DSH 依赖一起由 Vite 打入 Host,不能从 `app.asar.unpacked` 外部导入 仅存在于 `app.asar` 的 npm 包。最终打包检查及 Windows CI 的真实 UtilityProcess 启动探针见 [Runtime 资源与打包](../../../BUILD.md#runtime-资源)。 @@ -368,7 +368,7 @@ GoodBuddy conversationId -> Harness sessionId + workspace + process generation ### 9.5 跨项目复用 -锁定 0.1.2-rc.1 的文件和 Bash/PowerShell 工具已按原生 Session header.cwd 路由, +锁定 0.1.7-rc.2 的文件和 Bash/PowerShell 工具已按原生 Session header.cwd 路由, Provider 的根 cwd 只是默认值。不为每工作区复制本地 Provider; Main 的 Web/MCP ToolProvider 按工作区保存,最后一个对应 Session 释放时 dispose。 @@ -546,7 +546,7 @@ Runtime: GoodBuddy 内置 DeepSeek Harness 模型配置: 跟随 GoodBuddy · 企业网关(qwen-plus) 状态: 已就绪 路径: <受控 Host 路径> -版本: 0.1.2-rc.1 +版本: 0.1.7-rc.2 执行权限: 当前用户权限 Host 始终由当前 GoodBuddy 版本提供,不存在自定义 Host 入口。 diff --git a/docs/features/knowledge-base/external-knowledge-technical-design.md b/docs/features/knowledge-base/external-knowledge-technical-design.md index 219cf38b..d4e41f4e 100644 --- a/docs/features/knowledge-base/external-knowledge-technical-design.md +++ b/docs/features/knowledge-base/external-knowledge-technical-design.md @@ -33,7 +33,7 @@ | `src/shared/external-knowledge-contracts.ts` | Provider 配置、实例与绑定输入、目录、测试结果和外部引用定位契约 | | `src/shared/knowledge-contracts.ts`、`contracts.ts`、`assistant-contracts.ts` | 现有知识结果、列表和会话引用增加外部字段 | | `src/shared/knowledge-reference.ts` | 预检索与 MCP 共用的引用转换和去重键 | -| `src/main/ipc.ts`、`src/preload/index.ts`、`src/shared/ipc-channels.ts` | 可信发送方检查、Zod 输入解析、类型化跨进程调用 | +| `src/main/ipc.ts`、`src/main/knowledge/knowledge-ipc.ts`、`src/preload/index.ts`、`src/shared/ipc-channels.ts` | 可信发送方检查、Zod 输入解析、类型化跨进程调用 | | `src/renderer/src/ExternalKnowledge.tsx` | 实例 Modal、绑定表单、Provider 配置、外部详情与检索结果 | | `KnowledgeWorkspace.tsx`、`App.tsx`、`KnowledgeCitationDialog.tsx` | 统一列表、聊天选择、刷新及历史引用显示 | diff --git a/docs/features/local-tool-environment/README.md b/docs/features/local-tool-environment/README.md index cb2a59f7..8e4941b6 100644 --- a/docs/features/local-tool-environment/README.md +++ b/docs/features/local-tool-environment/README.md @@ -8,8 +8,17 @@ stdio MCP 提供明确、可诊断的 Node.js 与 Python 环境,同时允许 用户从设置中心的“能力与工具”进入,并在 `Skills`、`MCP`、`工具执行环境` 三个水平 Tab 之间切换。 +[Obsidian 接入](../obsidian/README.md)复用本功能的 `LaunchEnvironmentProvider` 启动 +随包交付的 MCPVault,不新增 Node 安装或下载源设置。生产组件自动化已覆盖真实 MCPVault +调用,Electron 托管 Node 离线冒烟仍待完成,具体见[验证记录](../obsidian/progress.md)。 + ## 文档导航 +Local native Continue and DS Web clients now honor the current custom Node +selection. They require standard Node rather than Electron's Node mode; the +remaining managed fallback and validation are tracked in +[native client progress](../assistant-workbar/progress.md#2026-09-27-local-native-client-validation). + | 文档 | 权威职责 | | --- | --- | | [PRD](./prd.md) | 用户问题、产品目标、范围、需求和产品验收 | diff --git a/docs/features/magic-notes/progress.md b/docs/features/magic-notes/progress.md index 33e63d05..c718a774 100644 --- a/docs/features/magic-notes/progress.md +++ b/docs/features/magic-notes/progress.md @@ -1,5 +1,31 @@ # Magic Notes Progress +## 2026-09-27: Analysis IPC Extraction + +The three analysis handlers now live in `magic-notes-analysis-ipc.ts`, with +the existing tracked registration injected at the original positions around +note and todo CRUD. Model selection and lifecycle are documented in +[Main IPC Ownership](./technical-design.md#main-ipc-ownership) and +[Canvas Analysis and Comments](./technical-design.md#canvas-analysis-and-comments). +No runtime factory, model-selection rule or Agent protocol changed. + +- Before and after extraction, with `GB_NOTES_LIVE=0`: + `npm test -- src/main/ipc.test.ts src/main/magic-notes src/preload/magic-notes-events.test.ts tests/magic-note-canvas-text.test.ts tests/magic-notes-analysis.electron.test.ts` + passed 8 files, 232 tests, with 1 skipped (96.49s baseline, 97.90s after). + Electron exercised vision and text-only analysis through production UI/preload/IPC + with a local model stub; real provider calls for these checks: 0. +- `npm run lint` passed. `npm run typecheck` stopped in the Node project with + 11 unrelated missing-`forwardLoopback` errors in `ssh-connection-pool.test.ts`, + `ssh-host-directory-browser.test.ts` and `ssh-terminal-session.test.ts`. + Separate `npx tsc --noEmit -p tsconfig.agent.json` and + `npx tsc --noEmit -p tsconfig.web.json` passed. +- A 120-second-bounded `npm test -- --bail=1` stopped after 94.45s: + 20 files passed, 1 failed; 1004 tests passed, 1 failed, 25 skipped. + `RightAssistantSidebar.resize.test.tsx:387` expected two persisted terminal + titles but received one. This was not a complete full-suite run, and the + unrelated failure was not changed. +- `git diff --check` passed with existing LF/CRLF warnings. + ## 2026-09-26: Conversation Capture and Compact Notes Panel - FR-1/FR-4: `notes` is an application-scoped optional singleton in the workbar. diff --git a/docs/features/magic-notes/technical-design.md b/docs/features/magic-notes/technical-design.md index 52d07d5e..cbe3912e 100644 --- a/docs/features/magic-notes/technical-design.md +++ b/docs/features/magic-notes/technical-design.md @@ -1,5 +1,23 @@ # Magic Notes Technical Design +## Main IPC Ownership + +[magic-notes-ipc.ts](../../../src/main/magic-notes/magic-notes-ipc.ts) owns +note search/list/get/create/update/delete, entry create/update/delete and todo +list/status/update handlers, including conversation-source validation and entry +content mapping. Its two registration functions receive the existing tracked +`registerHandler`, window and database from [ipc.ts](../../../src/main/ipc.ts), +preserving registration order: note CRUD, entry/draft analysis, todo CRUD, then +todo analysis. [magic-notes-analysis-ipc.ts](../../../src/main/magic-notes/magic-notes-analysis-ipc.ts) +owns the three analysis handlers through two registration functions. It receives +the window, database, settings readers, usage persistence callback and existing +error formatter; it imports `createDefaultModelRuntime` directly. `ipc.ts` retains +tracked registration/removal and shared usage persistence. +Sender checks and shared input schemas stay at each handler boundary. +[rich-content.ts](../../../src/main/magic-notes/rich-content.ts) remains shared +by CRUD and draft analysis. Analysis retains revision checks, hidden task status, +stream events, error causes and nested release/dispose cleanup. + ## Continuous Record Workspace The detail mounts every entry in a continuous newest-first stream. The left index @@ -252,7 +270,13 @@ Draft, saved-entry and todo analysis use the existing typed preload/IPC methods and `createDefaultModelRuntime`. Each canvas request reads the current default model profile's `supportsImageInput` (or the resolved default setting when no profile is selected). Main resolves settings again for the actual request. This -does not change an Agent runtime or desktop-to-Agent protocol. +does not change an Agent runtime or desktop-to-Agent protocol. All three handlers +read global resolved settings per request, without applying chat/project runtime +selection. The factory creates a tool-free direct `ModelAgentRuntime`, using the +resolved default model connection and that profile's headers, body options and +output limit. Environment-managed default credentials retain the settings store's +environment overrides. The existing context-compression configuration can select +a separate summary model; it does not select the main analysis model. `magicNoteCanvasPageCount` is an application preference: an integer from 1 to 8, defaulting to 1 when absent in historical settings. The application center and diff --git a/docs/features/obsidian/progress.md b/docs/features/obsidian/progress.md index ff793678..45a88ef3 100644 --- a/docs/features/obsidian/progress.md +++ b/docs/features/obsidian/progress.md @@ -71,7 +71,7 @@ node build/run-obsidian-packaged-acceptance.cjs "/win-unpacked | [共享工具测试](../../../src/shared/obsidian-tools.test.ts) | 19 工具集合和 18 个上游工具的字段、默认值、必填项与约束对应 | | [HTTP 网关测试](../../../src/main/agent/knowledge-mcp-gateway.obsidian.test.ts) | 实际 HTTP MCP 发现 19 工具,真实多仓库读写、删除及错误返回;另覆盖撤销、取消和等待 transport 关闭 | | [直连提供器测试](../../../src/main/agent/model-tool-provider.obsidian.test.ts) | 通过实际服务执行全部 19 个工具并核验文件,包含笔记移动、二进制附件移动和删除;覆盖 Ask、失效令牌、原生错误及关闭清理 | -| [index.ts](../../../src/main/index.ts) 与[ipc.ts](../../../src/main/ipc.ts) | 正式启动实例化、依赖注入和 IPC 注册;范围保存、开关及分配提交在持久化前撤销旧 Obsidian 请求授权 | +| [index.ts](../../../src/main/index.ts)、[ipc.ts](../../../src/main/ipc.ts) 与[capability-ipc.ts](../../../src/main/capabilities/capability-ipc.ts) | 正式启动实例化、依赖注入和 IPC 注册;能力处理器位于 `capability-ipc.ts`,范围保存、开关及分配提交在持久化前撤销旧 Obsidian 请求授权 | | [package-mcpvault.ts](../../../src/main/obsidian/package-mcpvault.ts) 与[构建配置](../../../electron.vite.config.ts) | 构建期递归复制运行依赖,并固定上游版本 | ## 验证记录 diff --git a/docs/features/obsidian/technical-design.md b/docs/features/obsidian/technical-design.md index 5877bcea..c6fed1fa 100644 --- a/docs/features/obsidian/technical-design.md +++ b/docs/features/obsidian/technical-design.md @@ -14,7 +14,7 @@ | 共享目录与直连 | [obsidian-tools.ts](../../../src/shared/obsidian-tools.ts) 定义 19 个工具;[model-tool-provider.ts](../../../src/main/agent/model-tool-provider.ts) 发现并调用同一目录,保留上游错误详情 | | 构建 | [package-mcpvault.ts](../../../src/main/obsidian/package-mcpvault.ts) 复制依赖树,[electron.vite.config.ts](../../../electron.vite.config.ts) 调用打包函数,[package.json](../../../package.json) 配置版本及解包资源 | -正式链路为设置页面经 Preload、受信任的 Main IPC 处理器到配置服务或 ObsidianService;会话经既有能力入口到 ObsidianService,再通过 stdio 到 MCPVault。[index.ts](../../../src/main/index.ts) 创建服务并注入工具启动环境、网关及 IPC;[ipc.ts](../../../src/main/ipc.ts) 已注册设置、测试和目录选择处理器,并在会话入口按保存设置及工作模式签发请求授权。 +正式链路为设置页面经 Preload、受信任的 Main IPC 处理器到配置服务或 ObsidianService;会话经既有能力入口到 ObsidianService,再通过 stdio 到 MCPVault。[index.ts](../../../src/main/index.ts) 创建服务并注入工具启动环境、网关及 IPC;[capability-ipc.ts](../../../src/main/capabilities/capability-ipc.ts) 注册设置、测试和目录选择处理器,接收 [ipc.ts](../../../src/main/ipc.ts) 的注册及刷新回调。`ipc.ts` 保留处理器跟踪、Runtime 重载和生命周期管理,并在会话入口按保存设置及工作模式签发请求授权。 ## 配置与 IPC diff --git a/package-lock.json b/package-lock.json index d7575857..162f8cd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,30 +10,30 @@ "license": "0BSD", "dependencies": { "@agentclientprotocol/sdk": "0.25.1", - "@deepseek-ai/cordis": "4.0.2", - "@deepseek-ai/dsh-agent": "0.1.2-rc.1", - "@deepseek-ai/dsh-agent-loop": "0.1.2-rc.1", - "@deepseek-ai/dsh-bash-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-credentials": "0.1.2-rc.1", - "@deepseek-ai/dsh-fs-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "0.1.2-rc.1", - "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1", - "@deepseek-ai/dsh-pwsh-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox-policy": "0.1.2-rc.1", - "@deepseek-ai/dsh-session": "0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "0.1.2-rc.1", - "@deepseek-ai/dsh-shell-env": "0.1.2-rc.1", - "@deepseek-ai/dsh-skill": "0.1.2-rc.1", - "@deepseek-ai/dsh-subprocess-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1", - "@deepseek-ai/dsh-token-meter": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-bash": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-fs": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-pwsh": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-skill": "0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "0.1.2-rc.1", + "@deepseek-ai/cordis": "4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.1.7-rc.2", + "@deepseek-ai/dsh-bash-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2", "@huggingface/tokenizers": "^0.1.3", "@modelcontextprotocol/sdk": "^1.30.0", "@napi-rs/canvas": "1.0.3", @@ -82,6 +82,7 @@ "@antv/g6": "^5.1.1", "@bitbonsai/mcpvault": "0.16.0", "@continuedev/cli": "1.5.47", + "@deepseek-ai/dsh": "0.1.7-rc.2", "@eslint/js": "^10.0.1", "@fontsource-variable/inter": "^5.3.0", "@fontsource-variable/noto-sans-sc": "^5.3.0", @@ -163,12 +164,13 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "version": "0.123.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.123.0.tgz", + "integrity": "sha512-Y9oX9mPNGZClHQOFqrWRk43Srcu/UHuPq3rfxxOq7JgW0gi+lJA2MAOK4Ul3k/+AUrwRWFJvd0tK3oC0Pw25dw==", "license": "MIT", "dependencies": { - "json-schema-to-ts": "^3.1.1" + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" }, "bin": { "anthropic-ai-sdk": "bin/cli" @@ -562,17 +564,17 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.977.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.9.tgz", - "integrity": "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA==", + "version": "3.978.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.1.tgz", + "integrity": "sha512-LbY9aGsEiznDWmUc30Nwv3aIX/+dbwTx8KfS0yOC3NPYMO+O91e6jkT1azf34FwjOndq8/Q+RcVVZz5xnerwdg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@aws-sdk/xml-builder": "^3.972.40", + "@aws-sdk/types": "^3.974.6", + "@aws-sdk/xml-builder": "^3.972.41", "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.33.3", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", + "@smithy/core": "^3.35.0", + "@smithy/signature-v4": "^5.7.3", + "@smithy/types": "^4.19.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -581,15 +583,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.70", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.70.tgz", - "integrity": "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw==", + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.72.tgz", + "integrity": "sha512-xTKO/FWJPozTIXbozVnVGoNBhaGba8TBcx+KyUjRVeOlXE+dUc7GTR1cLvu0uTdIdmemzaFbqqCshXeZA1fZew==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -597,17 +599,17 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.72", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.72.tgz", - "integrity": "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w==", + "version": "3.972.74", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.74.tgz", + "integrity": "sha512-u91E/hT8f4d1xy0Jl7VG4nVKJ3lxbrZkoBTeSVoJdWBiSEUMwMS/9+e0H/aJVQV//Lt5wuzP+E69v4aRSsNTmw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -629,23 +631,23 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.15.tgz", - "integrity": "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg==", + "version": "3.973.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.17.tgz", + "integrity": "sha512-ged4KXdBkvIC81bLvNHHuQKdKak/VXhQTR1NWYTTqW0474nlmsxy9O/vlgTIohDDWH3xpBdtVMZRyjb+DnocDA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/credential-provider-env": "^3.972.70", - "@aws-sdk/credential-provider-http": "^3.972.72", - "@aws-sdk/credential-provider-login": "^3.972.77", - "@aws-sdk/credential-provider-process": "^3.972.70", - "@aws-sdk/credential-provider-sso": "^3.973.14", - "@aws-sdk/credential-provider-web-identity": "^3.972.76", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/credential-provider-env": "^3.972.72", + "@aws-sdk/credential-provider-http": "^3.972.74", + "@aws-sdk/credential-provider-login": "^3.972.79", + "@aws-sdk/credential-provider-process": "^3.972.72", + "@aws-sdk/credential-provider-sso": "^3.973.16", + "@aws-sdk/credential-provider-web-identity": "^3.972.78", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -653,16 +655,16 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.77", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.77.tgz", - "integrity": "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ==", + "version": "3.972.79", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.79.tgz", + "integrity": "sha512-L+Z85anONJd8MaiuraO4wRxATCdEejBZ3K3eymzWI5JPXa9sOS9CkIm72PBKqXKX+Z9p9NGMX5AIMXm0LEflgw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -670,21 +672,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.82", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.82.tgz", - "integrity": "sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA==", + "version": "3.972.84", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.84.tgz", + "integrity": "sha512-oHt854odINVwzwsh+c5x69j0ajm4DbqqqVJ+O1ECsCIZeMDAbzFpXItaqP7UZstJj/ATdTk/KFSH0LaNAgV+kA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.70", - "@aws-sdk/credential-provider-http": "^3.972.72", - "@aws-sdk/credential-provider-ini": "^3.973.15", - "@aws-sdk/credential-provider-process": "^3.972.70", - "@aws-sdk/credential-provider-sso": "^3.973.14", - "@aws-sdk/credential-provider-web-identity": "^3.972.76", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", + "@aws-sdk/credential-provider-env": "^3.972.72", + "@aws-sdk/credential-provider-http": "^3.972.74", + "@aws-sdk/credential-provider-ini": "^3.973.17", + "@aws-sdk/credential-provider-process": "^3.972.72", + "@aws-sdk/credential-provider-sso": "^3.973.16", + "@aws-sdk/credential-provider-web-identity": "^3.972.78", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -692,15 +694,15 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.70", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.70.tgz", - "integrity": "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q==", + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.72.tgz", + "integrity": "sha512-rLIp2xbMjX/k9/od7APpqq1ZgXXnV0pOL1Th3ZsL8Wu0TRtBsDTVS8iPqcfRFcHakFxPvR04OSTv2ka2qOb/2A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -708,17 +710,17 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.14", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.14.tgz", - "integrity": "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA==", + "version": "3.973.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.16.tgz", + "integrity": "sha512-IGihaJfFZYacJJr/odqILCoK7W/mvrZ7cuK7ECn3sAu4vLC6u0V8bS7mCGbdugJ8Aum2tnvqmx0F2MRFp2rn9g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/token-providers": "3.1116.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/token-providers": "3.1138.0", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -726,16 +728,16 @@ } }, "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1116.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1116.0.tgz", - "integrity": "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q==", + "version": "3.1138.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1138.0.tgz", + "integrity": "sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -743,16 +745,16 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.76", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.76.tgz", - "integrity": "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA==", + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.78.tgz", + "integrity": "sha512-/y9WvNtlcPBGLR0qc1a+9J/xtYZfVczvLUOuXaVWylzttH7ewsxwHtjmiJSolNrVSDorIxHGHMU61CbonRkmwA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/nested-clients": "^3.997.46", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -760,14 +762,14 @@ } }, "node_modules/@aws-sdk/eventstream-handler-node": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.34.tgz", - "integrity": "sha512-cTeVzpu1xEAkryTZBYhGwnQ6gOGyp8ZYZvmn0Sg/nI/ABmy/CRHHxPDJDUi9PxwxUtGGaatvfRUB3FCgT/rSWw==", + "version": "3.972.35", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.35.tgz", + "integrity": "sha512-a8xilRoRaalvSPZdfrs0VY3/BPc0uYhXW56Z/k6nmZ5Vk430LHeowf9APIPq8utM3tMJSNGSSuJMlB9YrPsN+A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -775,14 +777,14 @@ } }, "node_modules/@aws-sdk/middleware-eventstream": { - "version": "3.972.29", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.29.tgz", - "integrity": "sha512-dlRzHCgyB8W6hLuDC5pcT5q+ziPt00n4QGgGBE17ucLVU4zMa6lsbuUdQ2Pm75Z5VA8GF+R/+SgrRcaTdIzSIQ==", + "version": "3.972.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.30.tgz", + "integrity": "sha512-B6gvZlcnRBNWraKgyEjKsbhv+VjtbyHmpU7hmtTHzXpDSxHPpCJnYLpglEOOsF+SFne20DbZC5IVC1aNr2Pb4A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -790,17 +792,17 @@ } }, "node_modules/@aws-sdk/middleware-websocket": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.52.tgz", - "integrity": "sha512-vsPPM+nMbKJlUCFU+eoGZbdxdxDIAX9LbpjSXaR5Ufpmqgp8TdYQnoExhLu4T3umW/JIIPny1ydbhWidZZYokQ==", + "version": "3.972.54", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.54.tgz", + "integrity": "sha512-bhESdru8u8KosziH8jcVta/NM/dNreeRz2+2aU86si5bfBYOiJ6IiqD+9U4URUcU5WJO3Yw+jO3GLDIHlscXMQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/signature-v4": "^5.7.3", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -808,18 +810,18 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.44", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.44.tgz", - "integrity": "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw==", + "version": "3.997.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.46.tgz", + "integrity": "sha512-oRxtBcka/JGHGs9l9p9IVajGoTP8vTPmoAzdHGy4Qcy9P5vPnDf6nhIeM/COQNY9k/OahImTRaLkHftoXvfcmQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/signature-v4-multi-region": "^3.996.46", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/signature-v4-multi-region": "^3.996.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -841,14 +843,14 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.46.tgz", - "integrity": "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==", + "version": "3.996.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.47.tgz", + "integrity": "sha512-Zk08macMvQTHzQJCLJVkOlviVoqwYMrpXv4lmLN7b7sAbiMoOK7Go0NYdR5UeF+MW8LIbRmwrNy9u/5VvX1U5g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/signature-v4": "^5.7.3", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -873,12 +875,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.974.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.5.tgz", - "integrity": "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==", + "version": "3.974.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.6.tgz", + "integrity": "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.17.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -898,12 +900,12 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.40", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.40.tgz", - "integrity": "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==", + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.41.tgz", + "integrity": "sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.17.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -1513,20 +1515,20 @@ } }, "node_modules/@deepseek-ai/cordis": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis/-/cordis-4.0.2.tgz", - "integrity": "sha512-asOnXP1TzFSFQlHb1iegDZp0z/8WD1c7YNrwJR/Tx2bzNuMXfcekE/I67Iv6SQXeLB4csxqCngzQKANP7gdw0g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis/-/cordis-4.0.4.tgz", + "integrity": "sha512-obgyxqWAmFn3Re8kvsuUnyW+ihrz6eJCnJO4fh1cQzDtmPYz/zzVeUkH9R94I0OwSVOocK67Kgakm04j/oQXzg==", "license": "MIT", "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.3", + "@deepseek-ai/cosmokit": "~1.8.5", "@standard-schema/spec": "^1.1.0" }, "bin": { "cordis": "bin.js" }, "peerDependencies": { - "@deepseek-ai/cordis-plugin-include": "^1.0.7", - "@deepseek-ai/cordis-plugin-loader": "^1.0.3" + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" }, "peerDependenciesMeta": { "@deepseek-ai/cordis-plugin-include": { @@ -1537,702 +1539,5309 @@ } } }, + "node_modules/@deepseek-ai/cordis-plugin-group": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.4.tgz", + "integrity": "sha512-/7tuY5pMQetHava4v6QUeOa4CwZA+mleNvbIoj+iqEmzkYUtlXbLqhzJIcbnDa/Hxgr1jaCwROrI77nuLyeCFg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-include": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.9.tgz", + "integrity": "sha512-Xmekm7u5Kpeym6nABL4T1/Mg6aQYFZxsipB0WycmCctvX1DqAv8nCFwRmg2XMx/f7EbZgNEbXQwJfabcMu8zxQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-loader": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.5.tgz", + "integrity": "sha512-200huL2ttWcjyeYllvPYn+qMR7I89qy8MhZasbHltPzB/KMrSfsyoCYKdCGc5KqPGj5iJugcmibQzjINMO9I+Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "node-addon-require-builtin": "^0.1.6" + }, + "peerDependenciesMeta": { + "node-addon-require-builtin": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-timer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.6.tgz", + "integrity": "sha512-/nZC7G637LIDF8G+lhF4OSXl1uFRuNAZqv1x11CDGLSjUpmIayePfzABEGTDEKAY+IBivg2DIXBr/sjjaLZxqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, "node_modules/@deepseek-ai/cosmokit": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@deepseek-ai/cosmokit/-/cosmokit-1.8.3.tgz", - "integrity": "sha512-qBo+ronVM6Eu2WNVJXi8JcMiqZ19T9BRIpV+5qJUFPXjGH/Z0QKcQMC/IZJ7L394YTOtJgcovbk9qP0w2GsBXQ==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@deepseek-ai/cosmokit/-/cosmokit-1.8.5.tgz", + "integrity": "sha512-LXsrlem9z8dq4sLflj2yuCuYX7KqhdzF5hZly3eZyuTo8d6oDSOXuEgC5DbQWKW+lksm6zmOutQLsP/ma6wR6A==", "license": "MIT" }, + "node_modules/@deepseek-ai/dsh": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.1.7-rc.2.tgz", + "integrity": "sha512-SQFhriLvza8GnFApnC5/32AgpcyKxrWnYXhvwDOLJdgWpkCX2EexyR9c8kCkMITJXnFLEN3Qb2CEh0W36vkLyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-acp-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-tool-presentation": "0.1.7-rc.2", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "@deepseek-ai/dsh-base": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-agent-preset": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-cordis": "0.1.7-rc.2", + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-compact": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.7-rc.2", + "@deepseek-ai/dsh-cordis-client-runner": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-agent-team-profile": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-auto-review": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-voice-input-bundle": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal-round-driver": "0.1.7-rc.2", + "@deepseek-ai/dsh-headless": "0.1.7-rc.2", + "@deepseek-ai/dsh-hmr": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-hooks-claude-code": "0.1.7-rc.2", + "@deepseek-ai/dsh-hooks-codex": "0.1.7-rc.2", + "@deepseek-ai/dsh-http-proxy": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-client": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.1.7-rc.2", + "@deepseek-ai/dsh-persona": "0.1.7-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.1.7-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-schedule": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-minimal": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-office": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-time-context": "0.1.7-rc.2", + "@deepseek-ai/dsh-tmux-context": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-ask-user": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-cordis": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-present": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-str-replace-editor": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-web": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-workspace-dependencies": "0.1.7-rc.2", + "@deepseek-ai/dsh-web-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-webhook": "0.1.7-rc.2", + "@deepseek-ai/dsh-webhook-github": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.6" + }, + "bin": { + "dsh": "lib/bin.js" + } + }, + "node_modules/@deepseek-ai/dsh-acp": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-acp/-/dsh-acp-0.1.7-rc.2.tgz", + "integrity": "sha512-pYA/KH4ks/q/S82PEwdpGQ+Bdmyx8G4aspd2N0BVM9KAfupEszrgZyfNX7L0+hvy4sYTjP5LyUr6/2QmQVhXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@agentclientprotocol/sdk": "1.4.0", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-client": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-token-meter": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-acp-app": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-acp-app/-/dsh-acp-app-0.1.7-rc.2.tgz", + "integrity": "sha512-7Km0Fchvx/PoL3/By4M6ykKkrmmIgelXq/1l0624Ixt3JgTtFNSgko3dpL/32Hv/a5Fn/wEsuujBHzmcBBcZ7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-acp": "0.1.7-rc.2", + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-acp-app/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@deepseek-ai/dsh-acp/node_modules/@agentclientprotocol/sdk": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-1.4.0.tgz", + "integrity": "sha512-/eufudw+aFY1LKLolT6yFE6UMmYRl7fMJ/DEONSIyR6wI3slHWITBsANRGqXEY8FRzqUxwh7QEaGiZHcJPVThg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "node_modules/@deepseek-ai/dsh-agent": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.2-rc.1.tgz", - "integrity": "sha512-lfaqN34vUCWvbn1kJVHrhfJ6Dvt1HDHCm33ZCpmKkl07/5q6FxWqVv6rOdVX5QnM/9xz/uYiN0nQwUtBg4+Skg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.7-rc.2.tgz", + "integrity": "sha512-9U/zHZvZqRR5S2FD9fjjAuoMh+WfDan+bE/cLBLSLpqftjZ0FhIlEBK99yonUkNkGemyHiH/lL3jCKYw35ahJA==", "license": "MIT", "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-agent-default-model": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.1.7-rc.2.tgz", + "integrity": "sha512-Ilvgi3Dsogn6X3GTd6ke8MrWV1jBTLIVep7xji7own/TVdhtu7pP7Zs0mFYDTuuP1INGGrcnS/dHEPayNyRm+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-config-editor": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-instructions": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.1.7-rc.2.tgz", + "integrity": "sha512-q6V4d4XIEmLiHgNg/z3jYV5K0f1qHvpuq1fatEHaLjTCZPXy4p3O7ge+PKQSoB8I/Gxy8HGXthZ4oJPXro5Klw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-agent-loop": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.2-rc.1.tgz", - "integrity": "sha512-4h16Gn/5oXLTFeorehdlKe5xmDKscR/eRsUu3cs6clKgaTrn6YvnWNB0XkYEg+AXiXbsyfl5MW5Bs4576t7vZw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.7-rc.2.tgz", + "integrity": "sha512-X+fegYY7yITQ5kAIayFrylMY9Vg6zHFLnP83rJVZ89juF9EBRm8soGAJHvyjat+mdk5a1WViWYdIPM0t9g/glA==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-persistence": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1", - "@deepseek-ai/dsh-settings": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-preset": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-preset/-/dsh-agent-preset-0.1.7-rc.2.tgz", + "integrity": "sha512-T3HKwuNf9S+FxZilyHw34bXilX+a8GqXfaoL8QqShghUyNYLLuAI9lUDdNpADf7huuTvBA1TO+ulUmVXAN/QhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-preset-registry": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-preset-registry/-/dsh-agent-preset-registry-0.1.7-rc.2.tgz", + "integrity": "sha512-qpB4H6uWuPx/Jqm2sLbNJPrWOtVhk3FLK+5PdqLBHqEDfCmpBZCBm6lUdSWsmnKmPnHiBeHSVZO9AZl9qJJlHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "js-yaml": "^4.2.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-settings": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.1.7-rc.2.tgz", + "integrity": "sha512-xKfJLdNhh91bO52qCAl9qCGJkEbuZdHg7sWGfY5dB+RsXxOGXxZwXQUOnPgbKS54f3Ydks93SmphzYKJHBSdxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-anonymous-user-id": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.1.7-rc.2.tgz", + "integrity": "sha512-krpu7wg/5+5MjeYml8TfViV6nXm3hzPvTBIa70tjcUTyLJidXmchwDr65HqYE2Mv+tRlrkGKZr6a+iOpdscEug==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-account-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-account-controller/-/dsh-api-account-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-0dQuFlmeoOcxvVg9UooR5ZztCZlLBq7V/APVTErIgZaMTbwV5myJSxlftc92Y3gxAM6lCpyjYa2eAq1mT09oww==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-account": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-gateway": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.1.7-rc.2.tgz", + "integrity": "sha512-CnM2kk7UQc/7MSEgNUG6V1CeWYoG7cS1b/IF7tpYEQihuswXGaBVPBsQSMZMAiU8uMyUFTBKm4POSJ/J6QiT2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "ws": "^8.21.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-job-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-job-controller/-/dsh-api-job-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-yO3bQ3fQ5G/SG3Mm/3kQHIB7YaXjSRufIvOtBWV321SN1NOrCuhncIWBzE7UmsnaqxhGGzNQ5lIUILtIxy1aGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-api-remotes": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.1.7-rc.2.tgz", + "integrity": "sha512-MYPFy7wb9wJE3CkeFum2aEHDaDTy8YIkRSJWIpkpsYTKSEFr2IZTU6TH8dFQf8eF58WAHr0YUCA0t7p/uQJPow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-session-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-session-controller/-/dsh-api-session-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-PB6Sk3h9g0ZGeIxUNcnZJIdWQxvhV4dh9g7KOd+Wu2YyqnA7TqweU9JRKitrDb4hYB1TFTDImGmdcAhiiMhbEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "mime-types": "^3.0.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-file-upload": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-file-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-native-command": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-settings": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-time": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-workspace-path": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-settings": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-api-session-controller/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@deepseek-ai/dsh-api-session-controller/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@deepseek-ai/dsh-api-settings-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-settings-controller/-/dsh-api-settings-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-6CWdSCOSjNx07WTlat3Oq2UIMlT/tqtMC9CHqIbLFEmumQcoFFIyr34IFEMyWxN8Lwf0yL5s5wJ6KcF9UOLb5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-native-command": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-settings": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-terminal-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-terminal-controller/-/dsh-api-terminal-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-SxsRrFEbi6uEmu3QHnus/pDPIUzlh40hwKonjomLZoZeceW9AjAo7G0kvU2xNQDX6RpieayOhYdSVyQjBRIQHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@xterm/addon-serialize": "^0.14.0", + "@xterm/headless": "^6.0.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-workspace-controller": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-workspace-controller/-/dsh-api-workspace-controller-0.1.7-rc.2.tgz", + "integrity": "sha512-BUeoGq1didny2GqiGsCDfQTp9QF+oeAzRCG3z6gjbkQ4AGzOWw5QoSS7eknI+BU5vUq0zrJoVPR1gOaKK/9fbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/dsh-native-command": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-api-workspace-files": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-api-workspace-files/-/dsh-api-workspace-files-0.1.7-rc.2.tgz", + "integrity": "sha512-ImRQDxH7s4imG+G3EgT3nNepUomobwriGZtf+V39hlimytIdFcV9lZjzMkx9sQgz/V+3ExovAcvr7TEnu8EA6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-deque": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-app-boot": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.1.7-rc.2.tgz", + "integrity": "sha512-d0QWMMXxT6kICO9QRrXTqJRKP6bWNes7SVGJK6OOEzX6Ua9mzCx1KghPIf7tjW/ZmX0b8n1FoySr4IHElBkrOg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "@deepseek-ai/dsh-package-manifest": "0.1.7-rc.2", + "@eslint-community/regexpp": "^4.12.2", + "ajv": "^8.20.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.6", + "resolve.exports": "^2.0.3", + "semver": "^7.8.5" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-group": "~1.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-app-boot/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@deepseek-ai/dsh-atomic-write": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.1.7-rc.2.tgz", + "integrity": "sha512-gdUVkVv5DXBgnEDB1Dh/lL+HV/8mKR3AGUqNjLhQJSEqE9MIYyiHC+3zwzaWjeWhiTdLXd5rkA4HVCiS3KIcUg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-attachment": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.2-rc.1.tgz", - "integrity": "sha512-QISKUjEITusLvAkqPLRn70xDUt+GjjY41pISjtPKYcZ4EGmayzhgZ3VJNYEcC+rbaF44hs2o/0VhOwHA7lyxjw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.7-rc.2.tgz", + "integrity": "sha512-g2SQ12Ki1l28T/H+fZKtSWDFF5Y1gavcKVBb2X4eOVX5uT5Jwumx+9Svelp1pHaknuAE1N2Yt9tMwj2quMkhDg==", "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-attachment-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.1.7-rc.2.tgz", + "integrity": "sha512-Z50ktA9dTTR6DfjwoRQac7BBfkCvyE+FUcbj68u3R0d4lZpYQ9a9r4uYrSF57wrxZCVjYw48HbTYegxvyFh5mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "sharp": "^0.35.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-authorization": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-authorization/-/dsh-authorization-0.1.2-rc.1.tgz", - "integrity": "sha512-ixmc2KAx27KS0Dx2zpjH9/cJAQi6IEmiN9bokUL7GdTAeAMu8uz6ajO59YDYYLZSUWemj5nEvRn/55B20fekcQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-authorization/-/dsh-authorization-0.1.7-rc.2.tgz", + "integrity": "sha512-20hFGce+wzzWQ9qG2BfLeO26550HVVEe5ApELvmA6J7QUVsHkGWQsldKsYUzZ6AkgzgeUz4mwuOFYDf0r4timQ==", "license": "MIT", - "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-credentials": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-base": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-base/-/dsh-base-0.1.7-rc.2.tgz", + "integrity": "sha512-LYwclGWi0SEZh0ZjnlJT/kHaOV0JDuI1mCHFCOQthYlabPp90Ohba+7wdIRX1oqcQN6erFzsQrrV1WFf+NhRYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-authorization": "0.1.7-rc.2", + "@deepseek-ai/dsh-bash-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-compact": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-image-offload": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.7-rc.2", + "@deepseek-ai/dsh-config-editor": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-account-platform": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-observation-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal-round-driver": "0.1.7-rc.2", + "@deepseek-ai/dsh-hmr": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek-account": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.1.7-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.1.7-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.1.7-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.1.7-rc.2", + "@deepseek-ai/dsh-plugin-package-inventory-deepseek": "0.1.7-rc.2", + "@deepseek-ai/dsh-ptc-runtime-node": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-repeat-tool-reminder": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-checkpoint-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-log-deepseek": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query-sqlite": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-telemetry-otel": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title-first-prompt-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-settings": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-badge": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.1.7-rc.2", + "@deepseek-ai/dsh-spill-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-spill-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-json": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent-fork-in-process": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent-spawn-in-process": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-call-timeout-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-present": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-web": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-loader": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-questions": "0.1.7-rc.2", + "@deepseek-ai/dsh-web": "0.1.7-rc.2", + "@deepseek-ai/dsh-web-fetch-http": "0.1.7-rc.2", + "@deepseek-ai/dsh-web-search-deepseek": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-bash-local": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.2-rc.1.tgz", - "integrity": "sha512-/3+AO2TSC5RUKzP0/UZuWhIdwUUd30fx35/eTn8+KlntD7gPgDRMIv1JfXVTxk2pCU3K1V9JX3XjdJ5dHpEObA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.7-rc.2.tgz", + "integrity": "sha512-8InocMSTIzUGuKXnSp05pTBfeQmUdC+L5T1I+2iESzPtrNh/F9jLQeCPknWZ7ren/XwDki79J9EqYaLE1vNiUg==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-settings": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell": "^0.1.2-rc.1", - "@deepseek-ai/dsh-subprocess": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-bash-sandbox": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.1.7-rc.2.tgz", + "integrity": "sha512-M4laxtYLPkXlvbtMpLm4hTWKmBb1xJuNMma/eA+xYTNdjHtV/ZJPxiKMVe1crjBp/dKuMTJR42p8rizLM1vkNg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-bash-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-brand": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.2-rc.1.tgz", - "integrity": "sha512-y2RHIag3kzLdY8kTBuSUSTsKzWPscJrysNObXTiNM7stXLpa3jXpshsB1caqGzNx50vYcmHeN1gFVECgx3NZHg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.7-rc.2.tgz", + "integrity": "sha512-cvcvlNRuiFqZNNqyxdu7wcpiBjd9xa/0MpuhRvee43zBp9uED2p5JolZr5/2EKJf57gYx9k9bedb+Zbyiqnpkw==", "license": "MIT", "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" } }, - "node_modules/@deepseek-ai/dsh-code-runtime": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-code-runtime/-/dsh-code-runtime-0.1.2-rc.1.tgz", - "integrity": "sha512-dv5UszPJb/AFcarZc2c6h5z/X80bsrSd3bfIOugwNVclSI6P+L3ixseoZKgyks7T0Ap0h6ngXGk2WeoUkmYxnQ==", + "node_modules/@deepseek-ai/dsh-chunked-list": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-chunked-list/-/dsh-chunked-list-0.1.7-rc.2.tgz", + "integrity": "sha512-fMpkkFPG9I9/wlQygbyPAdGKMK/RnD1p7/czm2hbzyAZtr/kDz+RThOWtlV1VDZ23NWkps98qTwlhM3NJ3LkXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-connection": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.1.7-rc.2.tgz", + "integrity": "sha512-Wc2ANM5NO3Ri+p8wBoVnPxTYxz++zYSuEoVOhd498WMY779w0RCgWfRzHekPY5ftJX/G02qzWNHe0yBIoTpXXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-client-file-upload": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-file-upload/-/dsh-client-file-upload-0.1.7-rc.2.tgz", + "integrity": "sha512-jjXlNn0pANLGO+VzW1ABmtGgM/9z6rvg/Dj4y1LVliGQD5bQBw+xCp2faKjpe3C/LEu2lAv9FMjUjB9YrukzVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-client-hmr": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.1.7-rc.2.tgz", + "integrity": "sha512-5Qx01rqP8uq3l2hKW3bCNPzvNZ0KdAQHM/KDGSX24LCgYQRejV4BC7VOacMRCZFZAOLVU+RlFnPXIucF6v0C9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-locale": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.1.7-rc.2.tgz", + "integrity": "sha512-zkRt/JrBvS7w1TPi/dOo0QCqjkcAApq7nNoeIL2lX0VlzwHD86Hrg/n/YJJlg1i0nvOEtZDibR9FGwa/X2wpvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-modules": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.1.7-rc.2.tgz", + "integrity": "sha512-+ePHhpZr3H7bWbbQxiYq/B4oINmot11O2A+IeVMmkwMGClGi2ZumO5BWuIYZLlS1Aof9ANSez+uoX5BeVjqAdg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-resources": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-resources/-/dsh-client-resources-0.1.7-rc.2.tgz", + "integrity": "sha512-gbfYcakpo6BhOH4/XAiNVYrpHroH3xJhSb0LUOwPLhZEOFBgDAyAy1dtlBj+o+CNPraI3j+8SCt/oHVOu5y6mw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-shortcuts": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-shortcuts/-/dsh-client-shortcuts-0.1.7-rc.2.tgz", + "integrity": "sha512-yM52NmuHZcDkV1pbvD9f+Me5W+SgMz2jc1K8Iu9VZOgL5sy4EtMre6kPoHYMT4g1kcYpbVaqyygDXjA/guRW/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-crypto": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-store": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-store/-/dsh-client-store-0.1.7-rc.2.tgz", + "integrity": "sha512-8nF4gqy/3yvSN3KsuHX61DVP1Z2YjC93wkB2uGVS5xg4iyD1KgCqWB2S+fVAdQ7END9PDzWhZTk71AYnkSh7LA==", + "dev": true, "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.1.7-rc.2.tgz", + "integrity": "sha512-dE0Ua4Ke8yDo31BPEdTK+a3mrbuTRPLbdEK3LDWwUYQ9L0V2vYjHikQle4p/Asmx2Z/g2P87Wyx/016CnXHFNw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-approval": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-approval/-/dsh-client-ui-approval-0.1.7-rc.2.tgz", + "integrity": "sha512-zM8k2o504kLz9jDzqKze36W6Opb1voDwsO+YgWFmTrGQIjMXLmxdyuLxbMco9ER4cygUeJf8weH92FKQDw5CeA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-attachment": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.1.7-rc.2.tgz", + "integrity": "sha512-PG5bsHJ6WioVegi8K7GuXsoPZ3wd4rQBZ9OwSPjB4L6G2Zzln3UuBlNuAVpaTJL8lvxB5IBnUdw++4yQ8DvAWw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.1.7-rc.2.tgz", + "integrity": "sha512-pdWYHX/xRFMIWkT+IfemhTTOZVAJiA3CAlesUJpTDhbu6MEXQcPeBnsd3iPKswzCiVSPanvaj9Vv/057oXWfUA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-chat": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-chat/-/dsh-client-ui-chat-0.1.7-rc.2.tgz", + "integrity": "sha512-mH4Womiv1jFMdhNQQvvlF2t8T7rcQNDuR5e2YSJvJdVpZ2+9CxZOd/56hBURTciYX9p8QnCe+Qb1zj/A0ilWqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-commands": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.1.7-rc.2.tgz", + "integrity": "sha512-bw6+g4uSNYMoRtkzE8gqzRK6F38Qxa5HQonGf1KcAGWkQ79k8MtTcE9MOS++SBEr4pxokuwRncjPH+Ywjh/m2w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-conversation": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.1.7-rc.2.tgz", + "integrity": "sha512-bPC3RNBF2TgMwoueaRuFLMIrRVA/k9iqZQ6Lre8GPpn5c8uhmtTV5D1TlKNHQPNtnKv/Gn5BGw2Kh16ItbY83Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-cordis": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.1.7-rc.2.tgz", + "integrity": "sha512-v1ktLqwVQJq1Mjcml4jZpFeN0VcbePH2Pg7IkI25bAHaF2fn2afsf8hRYJdR2nfL9Us0mIwlo6/M/EkkfUGIXA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.1.7-rc.2.tgz", + "integrity": "sha512-/7eOaMsDJQgOYtPRHFHoyY9wwDOgM0af8Ihy8EtvnQjr7VqeluJvX2B3L55wOW0aBnCp0llHL4MZlYa+f7Z3SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.1.7-rc.2.tgz", + "integrity": "sha512-rpUbd6d2ZJs/uVa36ATa2y+QlX5i/RQ+24VZTWmz70hj/UhxiRWq3E6hXc2trOHIpHnXI8I3cfKYdP9BJPBb7w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.1.7-rc.2.tgz", + "integrity": "sha512-zEK/4cg6HKjqOabLRtcXWyPxsB0Q34RKulg6bYuOh58eQBEYBLlY6inyFESEVjP30fVkYx2qvrBuzBEVZ1A6Mg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-goal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.1.7-rc.2.tgz", + "integrity": "sha512-1h3u/5FNEuui+31lCklla2q+Df7EAribAwuY/O3lv8Gf/kT9seQfrJNkxwaZMoLh/9wnx/mAAnQT6K7v4OWmMg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.1.7-rc.2.tgz", + "integrity": "sha512-m2uKSOFijUI7gW66LjsThuPbHt67ezvL+nfKL+IpoBSc5596/WFcj6HysFdiGBv0bv7Gd0pNXUVTOJ2Z6Jhg4Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-jobs": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.1.7-rc.2.tgz", + "integrity": "sha512-QIFavpfsmMjmD/lb2nAoJNHpuaf7TQyWlpN3BNUVe2iBURu0+KviSnRQLOR8PxBztobo0AYtrAMNrmAACfLnuA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-layout": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.1.7-rc.2.tgz", + "integrity": "sha512-od2Q5A3SxiOO5V1Mi35lmm64LQLNjew+HgigjTC9oLpCkb+es739VQeWPdUnzWP/+4WVIyQ2+SbHMLZiyB5jVg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.1.7-rc.2.tgz", + "integrity": "sha512-6WbWPtxFc3NpFqsGlU02z+UzLaAaKZkOeD046T+DG3WXf9eAjWHs7nwyxo//kYtWOGYVFyvXI+To9knby78TXw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.1.7-rc.2.tgz", + "integrity": "sha512-kazoUL2VstZZs1Pvd+IliHIHqgNVKOHPmiXehUCBxc4pqwUV6v84X+aH4W6dxFCFojd1zqzgfp7dA2RwkNBfsA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-open-in-app": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-open-in-app/-/dsh-client-ui-open-in-app-0.1.7-rc.2.tgz", + "integrity": "sha512-cIZ8Q1v/HdPMSe1fouJMNTyIYRz9VKtN96I5Q8PwgRHKUIwoIQ1qDIxMaeCaOkYBnDftmafDVGxNSsvQ7XjfDg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.1.7-rc.2.tgz", + "integrity": "sha512-RUt06rwzQ1oYX74I5Va/y+nGOJC0l0i29EL5UEzfnz1RH26OGMw11PZnVDFQZbDE6QFpp44Rh8RF6H0MBlKttA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plan": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.1.7-rc.2.tgz", + "integrity": "sha512-IYw6lMWvMZ0gCHStZYAKqUuimSIgns1iShTOqNJBsyL82u99iRLUCOjTePRNVcn+OPSD0MpJEUPA4wPa1t3byw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plugin-manager": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-plugin-manager/-/dsh-client-ui-plugin-manager-0.1.7-rc.2.tgz", + "integrity": "sha512-y2BlSTNqiFKxvtx86r/xaskWhjc6OYfHmtbJGI6BVfquqrHBhKeHJ7D1vNURamOFdouJjurWdc6UclrM/6D4OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-primitives": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-primitives/-/dsh-client-ui-primitives-0.1.7-rc.2.tgz", + "integrity": "sha512-ymIUil9ivHcIDgaAmF88lOygC7dJ0UsUgdbIvXT5bymPZDzvDJIoorOKhlMsCqPEG1ZawCMVhUatnIPi4xdlMQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-reference": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.1.7-rc.2.tgz", + "integrity": "sha512-6gfOeDM/Z9hJRDP+m777VPgiFvjhVvbjnCxkXlG8rsXQBcdO4SSqCBWX0ioQ+2tIGMuMypfVNdFPOk8pxoR7FA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-renderer": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.1.7-rc.2.tgz", + "integrity": "sha512-GdOE1zyespclxrcCGPTWk8+TQKQy3tUNC2Ch+4eoAyzp1GD4hmQNyzwFIiQDLB6Bwc7kv+8cWc51sbjr5/2vNg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-schedule": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-schedule/-/dsh-client-ui-schedule-0.1.7-rc.2.tgz", + "integrity": "sha512-MIdo7fTNZ+kNOO0fp9oiw3D6qJ1O8xyjnYyJlZ1gqDFjuT+IdH65BEOoeGyT5atYYJnwMDWD7vL3sUMh5l5lqw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-session": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-session/-/dsh-client-ui-session-0.1.7-rc.2.tgz", + "integrity": "sha512-gr7hwtWpgqU1mJwFFtugxH2QOYw+j/RvU/h8719mGYjkmBbOxzy3wgTL00tf0WFHLZh8pPMKQMg/eG3bEb0Z/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.1.7-rc.2.tgz", + "integrity": "sha512-RAZXUt25mVibi2fnZyHhRArAtmNYIbyEUcAx/nc0i01V8dabnZkUCuGDRLjUeB4X6aPAOrlqLCliNcATuHD+hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-account": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-account/-/dsh-client-ui-settings-account-0.1.7-rc.2.tgz", + "integrity": "sha512-bMrSAJjkGGW1NCRS5I7rYFpUrTtl+6d3rUGWAJQlFRB3GCBDICfyAd2ZjLC+8NtklqyG8sXlmKPZr29N5mh61A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-agent-loop": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-agent-loop/-/dsh-client-ui-settings-agent-loop-0.1.7-rc.2.tgz", + "integrity": "sha512-qD0C+CK8KJ02B7URv7lsnddT1exlv9imvt7e6wAb5nkmzIdptXfLs2MfL5CXoH+b7NGx9sGYFHR9hRqKU3OMUA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.1.7-rc.2.tgz", + "integrity": "sha512-Qy7nobyQqUuXoTwe0QckrikCAFmX8JJ5RT5Wt7J2ZZ+soesDnaEkMkAfO1ZTxJi6MKzntuwwMwjF+Z330FFmAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.1.7-rc.2.tgz", + "integrity": "sha512-WDHuCh0cVJiSUyaa31OiXSSgpwWD9TAW2gEWBWUrF8eO+hyQEA8Q5f3wzVvea1ltiOmjqU0IBFMQRtpSckyDPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.1.7-rc.2.tgz", + "integrity": "sha512-TweCas4hY0NPl6m4TFeE9OVNSNGH6BjRCSzRfKVddZ6qm54aCW3pxy0fprJLLRVIkVckushjbfl+vaxyYGHoFA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.1.7-rc.2.tgz", + "integrity": "sha512-eLljHiQ6fR0K/yXDiHeyiWkCsmg1eQucoMAKcwerh8sjtyKPTpqLFQDmOn/O7znJz+b/V89yshkyyHw8ZvC38Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-shell": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-shell/-/dsh-client-ui-settings-shell-0.1.7-rc.2.tgz", + "integrity": "sha512-+N2RZaN/WCA9vVqCdf4PnvuzmtGnzyacnlOe37g5NSpZGrg2MpPnUTuv9vJnygsQhYLHZxkJOojAnxEJ/dOgfQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-subagent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-subagent/-/dsh-client-ui-settings-subagent-0.1.7-rc.2.tgz", + "integrity": "sha512-c93MFjtSoffOCeVAUBOL9oTul1Hd5MhyUngGetBUv7APixG5zN6X13NjnS20mqOKRidSMc0xyizYiS30ygz2fQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-web-search": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-settings-web-search/-/dsh-client-ui-settings-web-search-0.1.7-rc.2.tgz", + "integrity": "sha512-/EwngqLFH4tBnF8GXMVRDpR0Lfwk3uhJ103UFSLq+p4E46yv2zxH6S3AcKIWR8YdntB8i0nj2Xr/5Cs4IbK+yQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-shortcuts": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-shortcuts/-/dsh-client-ui-shortcuts-0.1.7-rc.2.tgz", + "integrity": "sha512-Bo5Z0j6Xcm5NHWmrgJwMP9vehsfUcNQvZ0IT6WAT5z51cEza3iIXfpfEa/3GTos68cv9R5i14wjAJL9a3Go7Ow==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.1.7-rc.2.tgz", + "integrity": "sha512-/rzmtzk5Wg89zkT03nPGD/yYx9x1MD2ircBb9zIaLB9+DMBUFNjHJh5htYmYFxN7ldNEa6zDnmcx0N6jg1xnPg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-browser": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-browser/-/dsh-client-ui-sidebar-browser-0.1.7-rc.2.tgz", + "integrity": "sha512-Mnn+EVIy2YGIEyHcJf5ifAhLKUdeYjhv1XA4fMhfGUmadq0QYGMN+K9j0mWb6eBCSXoujBzfwiClhCT11dN+3w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-documentpreview": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-documentpreview/-/dsh-client-ui-sidebar-documentpreview-0.1.7-rc.2.tgz", + "integrity": "sha512-5SRZ9SgYIq0GB4q9PQPY7uInG+WKaVLv7V9kQn58YWjwzzEVDDcGMDbgCP5lBLq/Hj+fZ7jI70na1M8hMCjf1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-files": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-files/-/dsh-client-ui-sidebar-files-0.1.7-rc.2.tgz", + "integrity": "sha512-5H9kFhSFoZDj19YE8BYue3Ux1anPOGC4JNAYZJI9cmYLXB/Onb8nndFUxt+9HKJhQaRaLXgYBMrBQxg+Wig6Bg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-right": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-right/-/dsh-client-ui-sidebar-right-0.1.7-rc.2.tgz", + "integrity": "sha512-CXTONIEGrMJA7Aj9OK5K7XSv6Qa/f+yK8UqKHvrT03m1FAqLJZGVqj2OUUbCgoB6Yf3wBTrNh5D4RqTE0rLpVw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar-terminal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-sidebar-terminal/-/dsh-client-ui-sidebar-terminal-0.1.7-rc.2.tgz", + "integrity": "sha512-1nr+HVNXkxnJ1eSxkIt2NnIaotyjTHvX2tHNaV6Fy7T/KoxcDecCW3sFFqIFnhZqR61SsQ8yNIP79DV65xWfog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-skill": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.1.7-rc.2.tgz", + "integrity": "sha512-DQhYOWGid/KIX9Pg4vCngO5vIOrtxxaL6v12RIV3PWJlZQ70JB2j8UEfayN3qtfHpbmWo15UTDJ56sA71lf/Mg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-slots": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-slots/-/dsh-client-ui-slots-0.1.7-rc.2.tgz", + "integrity": "sha512-83cd5owHfNMGIc5THEkMw1L6iKj/tl2m3thQhVGWp2p3Y+QAPh2hIrIQCNI+i97cH+7SsIsUIoCIoB0mu51aqQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-subagent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.1.7-rc.2.tgz", + "integrity": "sha512-iXO910+1CQ+AMrRkrzuG6XYDH/lH3iIXIU0YvEt844Vmp3r3GJ+HrEQAo5E1CXgctBwQtMDmocyhIUQNlYV7iA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-theme": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.1.7-rc.2.tgz", + "integrity": "sha512-sgI50PPgGwhxXR+xEUa0zTAg80S2RaQOLsuuVdfliZPbVLjodme7/bbc8cnPQ+ZV9oU5Q3to+yXxAQByuIKjRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-tool": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.1.7-rc.2.tgz", + "integrity": "sha512-0HDXXfaqw6u2tB0HES+XvOO+QRKGHP2gRUU5+9gE0uDcJWawj7SXX6Dj27hJ3rztT2xAAu4W2fA2S9vjxzw8MA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.1.7-rc.2.tgz", + "integrity": "sha512-RteqWWQuqj/2VGQYeNo+nKkuPPd/bv7ejJxHnMRtHEuYrnwObkBUqhZ4+7CbhZuM9m0Jv26+tg9SxIp7GzO03Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.1.7-rc.2.tgz", + "integrity": "sha512-cmZOeVspzKrD2r87xvXSGbQ7j18VwznKKkvA1lukBCpsHYfFYKdqg5vt3tbW4UJYPGa9Ch0j8qX0zpRGD0YBUg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.1.7-rc.2.tgz", + "integrity": "sha512-241DeEeaF8vp8vC54rrENDNA0R2n+nRRPvUCg4OYNi5MKLp0p7jgbeQ1lIcTaCuabRr1wYM0AZdoMyBaCkpaCQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workspace": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.1.7-rc.2.tgz", + "integrity": "sha512-iaf28XLl3+1WTgVMsykV8HVvGPH8VXv+CQD7Z5koejk0EJZVXtMB9nosUKX810qF+CVJKL04en9a8mOm8dIsFg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-cmdline": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.7-rc.2.tgz", + "integrity": "sha512-IULzGaZowx/xNJkWDwGTFTEP2wdjPZ7FT1uCW0gwvQdkN4MWEsbC9B1BMCenAoER1n6rs+GqIWmj3z8celngWQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5" + } + }, + "node_modules/@deepseek-ai/dsh-command-compact": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.1.7-rc.2.tgz", + "integrity": "sha512-vSDXWGW9Gh7hFrCCkfdMwut2kseS6HYOD89X5X43cnIxBayofenKfnMb/ZuN+NTGIWRr74FihtAe6mg0FxTtSw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-command-feedback": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.1.7-rc.2.tgz", + "integrity": "sha512-BczHqimHOdWQYNfpGfVtMPEBhFh1AhDia88cVDxLENfSXfaF8xUagSb2cJKXxS4iG8Xco6lz8lnnZAGOdLX2JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-anonymous-user-id": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-command-goal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.1.7-rc.2.tgz", + "integrity": "sha512-NSBwTXaU3eFiOjHFHdxllLE2h5CJSWBcIeKIONBMZqYW2q1myAdldTv9NHY5uPSYDQU1ew4hMt47OigpJ8Vicg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-commands": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.2-rc.1.tgz", - "integrity": "sha512-uBh4JTX7pOkFhmbWjXjVLnOQOawyccC7+DazbHrLRN6/wy4OgTRH+DaW0+ibLq+XRAO19OvBTtuoh3x/KkJx1Q==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.7-rc.2.tgz", + "integrity": "sha512-wVAHwHNDLDNBKXJZU2rHnwc+e3mhi6EuazAfJmqtbzU/ldQVEoJ9f5eXqesBcdQbRIrWQlpjfjdlw3nCJfK2HQ==", "license": "MIT", - "peer": true, "dependencies": { - "@deepseek-ai/dsh-util-crypto": "^0.1.2-rc.1", + "@deepseek-ai/dsh-util-crypto": "0.1.7-rc.2", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-attachment": "^0.1.2-rc.1", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-compaction": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.2-rc.1.tgz", - "integrity": "sha512-omzrM2EQdoUvQ41PbbXiFERC7I4FYiLNmHIYrlCZfCAdxo0G4u3kt7eahhVaSSi2YsinL7sW79C7cTVaUWlZVg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.7-rc.2.tgz", + "integrity": "sha512-NOrFYDM6EdvO+UBioNcpiZ+Klv5v2xvOxLXDWKtA0rjKKW8IvW7Rui2hBnOpchsWe5So5vwBvu4lNjTdl5/2CA==", "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-commands": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-basic": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.1.7-rc.2.tgz", + "integrity": "sha512-8I2TzEDZA9MhbjmSTanw4nM4Ud6mZTUy0Xe9Zy8oQ7GCbYpVhAe3grb5MHnpS0WYisrW1ws063Kj8hHZerdaEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-compaction-tool-result-pruner": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-compaction-image-offload": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-image-offload/-/dsh-compaction-image-offload-0.1.7-rc.2.tgz", + "integrity": "sha512-IraXZq6uR88RbJcxkK7vfDViIB4WCxm8Kf9s43VWoias9Tr//w0s8oHZWTfNuy8kVgpw4cBze6DeExZooMALrw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.1.7-rc.2.tgz", + "integrity": "sha512-ih1YpOuUNTZQR1epsZ2SgfT7+VsBrTBypl37DTbCqWZo3nO7LvTHILvdd+Kd2B/DkV1gKpXpBt4H493UNtXJOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-config-editor": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-config-editor/-/dsh-config-editor-0.1.7-rc.2.tgz", + "integrity": "sha512-UgNqOUqI9ZNABnb7TvoJ9d6EbaScVymL54YV/s8rU06cl4bTKuz/ahA8uLclyutCoRANkwh/eMiA+othLyhooA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "js-yaml": "^4.1.0", + "yaml": "^2.8.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-hmr": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-hmr": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-cordis-client-runner": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.1.7-rc.2.tgz", + "integrity": "sha512-cYRPl4Ftu8Gwbi7gDmAB11wgRvt4hiqdkRNCLq+988jU6q7p9h6lRYpvR4G/5YodP0Bs0fSdyRaZgHrpF2LOoA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-host-runner": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.1.7-rc.2.tgz", + "integrity": "sha512-Rts8lOjeJyVAkth7ezDpDPAXOjr0GHplqUz1BmWcAotErQWZGkVxJK6hqiVMlFKB24JMQwr/UWH4474iZUiZKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-credentials": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.2-rc.1.tgz", - "integrity": "sha512-e7DGpuYQqiD4dOWGQeY/XAWPTjbax/MkrXBwsB8wBtNpoPiAKiLYgd+iFiQc66BGOlutSRFz31IKdbduqPbTxA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.7-rc.2.tgz", + "integrity": "sha512-Zi5MCL+o2bphuvWcfFsaRmg6eIafkjCa758+DVB2ac2tt5hzXLoKhwSku4YVhvhZYJan8TP87abIzyGr5z1X5g==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1" + "@deepseek-ai/dsh-brand": "0.1.7-rc.2" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-credentials-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.1.7-rc.2.tgz", + "integrity": "sha512-pl3PRh+y9iLpwxZZmtxZzRTahiNGO6xNVC9nsN9h3eLu0ECetUkqRl2ByxLY/3ZcahSRzsad4eHjwKH5Prt7/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-account": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-account/-/dsh-deepseek-account-0.1.7-rc.2.tgz", + "integrity": "sha512-nJ142OEH8XPF2j9vCLBba9aQAQbO/eb3kfkZr/YdtXr3soYeConxveNFFXgIVLqevItKJReo0sa0P0l5E1xZiQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-account-platform": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-account-platform/-/dsh-deepseek-account-platform-0.1.7-rc.2.tgz", + "integrity": "sha512-ppvmTdigUDtljfuZZkPkElscjOB3EA9C2hpgBMY1Y58j7F/8pYAD1OCiuFot4C+lb6uk90NbZE2M3th7NxP5mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-authorization": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-account": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-deepseek-llm-api-extensions": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deepseek-llm-api-extensions/-/dsh-deepseek-llm-api-extensions-0.1.7-rc.2.tgz", + "integrity": "sha512-RCUarjaYUQDuyQzQ47qDyngMKbOkALMa7P8i3jZd5SsGK67eZd49O72ClFGd/r6CeO7JNQK4s1/W+C0orosUuw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-deque": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-deque/-/dsh-deque-0.1.7-rc.2.tgz", + "integrity": "sha512-a4zFfo+D7+BhV7hQzFQgIMtD65Hm3DQTLGRRd1EkI2O5TjrvBgVHOanyGJYK6VAgj07eIxIira8ws1KKNbbT+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-agent-team": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-agent-team/-/dsh-experimental-agent-team-0.1.7-rc.2.tgz", + "integrity": "sha512-N3/M+Wc1p50jKNF4fxJIP4m3iL4T4MiZelpIneVwwxVxoCTPlzdz0E5tKyN+p5x318aOxsibsa98D4N13Q4uoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-agent-team-profile": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-agent-team-profile/-/dsh-experimental-agent-team-profile-0.1.7-rc.2.tgz", + "integrity": "sha512-WdcCnmEflVTWK4HRtJGnLDZxZFd00cCqB2kNc80XA60SB71/r+umYU2JACtTbslLlThD5OzADG0c/3LAYuW1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-experimental-agent-team": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-client-ui-agent-team": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-tool-agent-team": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-api-speech-to-text": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-api-speech-to-text/-/dsh-experimental-api-speech-to-text-0.1.7-rc.2.tgz", + "integrity": "sha512-OWvVO1iG1ypxR3XKvAU8HH3To7NU9dt5AAI+g9Xb9QJ2AIbmI2qXklbm3vvrYaJyxW24p9pnEkuwuTJWcIBbWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-auto-review": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-auto-review/-/dsh-experimental-auto-review-0.1.7-rc.2.tgz", + "integrity": "sha512-qycXHx0+rxiu15vN3d5VOK5mIsKxk6yFteISHaMrEd7A+Y7aLAnJBhnKtBV0GObEfpuUjAsEbB0/N6htIxSMLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-instructions": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-client-ui-agent-team": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-client-ui-agent-team/-/dsh-experimental-client-ui-agent-team-0.1.7-rc.2.tgz", + "integrity": "sha512-K74WkKbc5ctqjVYxO3HHdBnINWvlVM39aMFIZntIH7PMK9HVRzzD0D51keigWAZhdvUVWwcX1IO7VW5ALg9TPg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-workspace": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-agent-team": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-client-ui-voice-input": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-client-ui-voice-input/-/dsh-experimental-client-ui-voice-input-0.1.7-rc.2.tgz", + "integrity": "sha512-JuFJgrCoG+4gePKZlJjmCAgZN4l7TGMT7xnGEY8jr4cnKHjdyB5buMRGqNo6gF6Bu6UCJVtc1+oqsFuCz2vbHA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-store": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-speech-to-text": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-speech-to-text/-/dsh-experimental-speech-to-text-0.1.7-rc.2.tgz", + "integrity": "sha512-AYsU6xhb/Y2lBoHU+qBB4X3NKYnCOmJhP6lLhh8xl2hAxY8UPcOKMeUFatTQtMUXD3lL2flg4UwXM7vJAApj0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-settings": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-experimental-speech-to-text-sensevoice": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-speech-to-text-sensevoice/-/dsh-experimental-speech-to-text-sensevoice-0.1.7-rc.2.tgz", + "integrity": "sha512-SVg4+Bz1QnP4bRr6lBmV39fxyDPiy6mg5f9loAM+RUI4mC6suKjDnt3A0VLhJ5TTIziFe5r5tfPRsCH6Ts2zzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "sherpa-onnx-node": "1.13.8", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-tool-agent-team": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-tool-agent-team/-/dsh-experimental-tool-agent-team-0.1.7-rc.2.tgz", + "integrity": "sha512-WQ4NkWo6c1WPv5D6VP3wIhWyEkFk5+ShsBk+ecwhzNKWi4Q8v92rqwoIBy0xtPiCkHdVcrjlD37H3PS8oAUQYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-agent-team": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-experimental-voice-input-bundle": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-experimental-voice-input-bundle/-/dsh-experimental-voice-input-bundle-0.1.7-rc.2.tgz", + "integrity": "sha512-IoaMPoVxuTFx+SRrXWeuClKCBlpeQGUKFiNozmRLM63/EzZmTqB8yLxzSkHtL3TYfnx6gMU6m31RRKUYbdjimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-client-ui-voice-input": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2", + "@deepseek-ai/dsh-experimental-speech-to-text-sensevoice": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.1.7-rc.2.tgz", + "integrity": "sha512-kjtnauKgQSnoQ6acOhVrRFFsIiIb2NnLXV08Inow34is6oANH0Ti2EqJmOVFlt/7mqcEYHxBvJUbh/DY6h/vmQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.1.7-rc.2.tgz", + "integrity": "sha512-DRsbWY4NCWIeyhnnGpbGKsbiXf0m/FB51SI/4xdGL/TLZbZjIdROtBzXthL2IYG62QDtQMzEVs+jsg9zaBAuUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-file-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-fs": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.2-rc.1.tgz", - "integrity": "sha512-BSIB2j8WvATQ1mf7wUIpHPftDwbzz246qp6aUpLGSzBWGmLBdX3O1oDhyNV1YhgPmDQlwovac2odcAb62tuDdw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.7-rc.2.tgz", + "integrity": "sha512-3ES1FKLM4asLvFS+yBcatzRNGINfUx/Cl+x+JzGhEK5QWX3aCxpH8Oa9Z4T9k0McBStWg1CTfHziRR8trHPYyw==", "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-fs-local": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.2-rc.1.tgz", - "integrity": "sha512-tFHHKtD11tIk3FpkWF0vBKdX05zKbwqXQW9LhreA5hErCKEsulUsQLamf+kF1D8fuKqa8Yb+yWQIfYS93cy39w==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.7-rc.2.tgz", + "integrity": "sha512-7XlSqUY2nk1S0GQNU7f7rimhBnYZYdtOtW5xr3oApHuaiWyP2Qj9D2Y0Xq5+jyFz7kQ9hoNHq3gA+g5IK1Dofw==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", "koffi": "^3.1.0" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-fs": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs-observation-policy": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.1.7-rc.2.tgz", + "integrity": "sha512-htzbOb2krclujHcSMu4eLiMxE1zl1fNlQylN7RReU3ais5J08pJPzenNLH+M18zecRWr7IljxI/mrGAXlH0Upw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-fs-sandbox": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.1.7-rc.2.tgz", + "integrity": "sha512-E1f+stkuTefmMeOQ1lEQJum42igtOeg+V5J5P92dZp5QObt3VT1EcIkywe9zFHtEJ+jExVzACLIxj8XNmisiiA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-goal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-goal/-/dsh-goal-0.1.7-rc.2.tgz", + "integrity": "sha512-9ULU4IMWGBkUTzOoQC+3tuyy7J/oFq5J05rv2PyxpLZyJGf5lRRDfhNjm/PAfbKzuXAPGEB2aOQ8eAdZ1RCnHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-goal-round-driver": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.1.7-rc.2.tgz", + "integrity": "sha512-pIIDOhEGMr/BMLsRa+L7Q+qZgQupeAcT5wA7z3GEoZB/ABH4KTsepg0BZadZyuGEen4t0x6AG2pK2K+evonJLQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-headless": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-headless/-/dsh-headless-0.1.7-rc.2.tgz", + "integrity": "sha512-3M2QA46ATJNwdz2AYB5MpQMZot1ehwH36AqRBU2mNu9Iv8kC9cjsSST0eBnk1EyjF4jTqh5h6PZAkgLOBOExyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-headless/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@deepseek-ai/dsh-hmr": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hmr/-/dsh-hmr-0.1.7-rc.2.tgz", + "integrity": "sha512-+Zz8Fz9wwaOQ1h2KYc8BHPsCNIifRZVb+mPMRgl8N2ECByO8ZlarN0He4NjwWR9T/zgMEOvvhRf1aumPLs6TIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^4.0.3", + "picomatch": "^4.0.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-include": "~1.0.9", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-home-paths": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.2-rc.1.tgz", - "integrity": "sha512-DeDXxvrhAlkS+hxNLSFvWp8LDFhn26pO8gcutptOgSkrObM0yYW5119kyduwD1ExW0v1geToX+uDjBxO/SS/pQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.7-rc.2.tgz", + "integrity": "sha512-LafnefS9IttUziet9cQfCNfyBVce+aCPBGFrZGxsQJZYZXvkDQH94QHzDIxOIJfwwHuKC36fP5riD+Eajpx5jw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-hook-protocol": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hook-protocol/-/dsh-hook-protocol-0.1.7-rc.2.tgz", + "integrity": "sha512-MoTAuM84wpxOQX5N56PQFgWYS8mqxjJ7CbIvP+3KSa//+z6Ob7MWQAwi36S5VLGvywFMbzxpImCz9EawRuE5fQ==", + "dev": true, "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-hooks-claude-code": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hooks-claude-code/-/dsh-hooks-claude-code-0.1.7-rc.2.tgz", + "integrity": "sha512-TJx0FUFm6GZEjJKz4o8HiuBfk3qbOEAAEoIfEIy0Kgo2JDWgl04o/c7ZOf9KgurdZt/WpfVt2dG6nEQg6UJ7mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-hook-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-hooks-codex": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-hooks-codex/-/dsh-hooks-codex-0.1.7-rc.2.tgz", + "integrity": "sha512-xsGEcQOvt42vdkCQtJgV4/w136EJKALjs7TkljeeWKkQKJyEWvPjaUV3vJtJetd/wdqcv2vof1eNxfRzRybIRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-hook-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.1.7-rc.2.tgz", + "integrity": "sha512-J/by0v0yRI5LHPPaHCokDXEJNKNEPCaDziJueGI+fxpXfXwFvpoHp3hjwdWiN+bLPDdZL6DSQLh1evC46wobtQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.1.7-rc.2.tgz", + "integrity": "sha512-o2YCHr3uioc4HyB/s24gKDr1ZktEAHsuhqQocfTWPLivwe2Uozdvh/Kjq1LU9pBNeBGTHzUvtkhgVMTCpQXedg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker-browse": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker-native": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.1.7-rc.2.tgz", + "integrity": "sha512-XV+iP2MXbeQ6nRKCiTGLE7ntDX6/SbJJ7hK0f8UO7WbC6TrbaCWtLTiCQ3xgqC314Zc3YpOVZPs7LGUS3P013w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.1.7-rc.2.tgz", + "integrity": "sha512-97pxHwk3bhMRgBlTH36W3fEyLI6JeuG6oaKLEVCyS8xduhAeWGVAv3M3JxmeTAQsKvIxaqwlVJ18bgHc7Qw6tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "0.1.7-rc.2", + "@deepseek-ai/dsh-native-command": "0.1.7-rc.2", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-frontend-static": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.1.7-rc.2.tgz", + "integrity": "sha512-G1DHZONOfyxiPyvEMyJns3EFPANz5svjxh+gRK0PDC7WJv6fivvJ0agR3D2wa0RIRhQLML7FMw9C1MD2Hzrfxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-host-open-in-app": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-open-in-app/-/dsh-host-open-in-app-0.1.7-rc.2.tgz", + "integrity": "sha512-bozNEbEAeCmk6fny4qaDioLYLvX9xLmHPYVAeXdXoLRML7qiwIP88BbH8NxpibreCcFKFi9uMpx/GdoiwK2bMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-native-command": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.1.7-rc.2.tgz", + "integrity": "sha512-krS/FKI7cacoUtjpIaZnFQZy4cM2DnshsP//jafFdC1LyKyh5gG97MPmQ37jRM5Gm4VDJfDj3ojqWzx3BrP1sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-host-webserver": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.1.7-rc.2.tgz", + "integrity": "sha512-0ex5NsJFvpqchfnar/IPtNOG5Tx7PmtUO3/zVptT4MJs5OOrvtjNYHpZ6DGntmnpupgXnci1cUsQJIfG3D+U+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "compression": "^1.8.1", + "negotiator": "^1.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-http-proxy": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-http-proxy/-/dsh-http-proxy-0.1.7-rc.2.tgz", + "integrity": "sha512-sG0bj5U6CX54BLWizf/6QtqYgtbv56qSe7wW/0B+DxmN+TtOr4s+6TRWLLMUxH2SCR9th20SwiEDHvuLf17Q7Q==", + "license": "MIT", + "dependencies": { + "undici": "^8.10.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-http-proxy/node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" } }, "node_modules/@deepseek-ai/dsh-invariants": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.2-rc.1.tgz", - "integrity": "sha512-zSjuFJYcEB94kPwn7SicqAV1dfVWZkjt1I8luDboxtjfp5CN6ziwJhLv3KaB+Dh9tgkyGY4mvo886W/HhE9L9g==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.7-rc.2.tgz", + "integrity": "sha512-GY2lY2TUUH2Qk1ZnrB3Q5+lXSh4webn1kbt5nQfhojVmNbist/f3dJC8JJa7XXOUNvqAgqRN9IZ4egbDZ9LLxQ==", "license": "MIT", - "peer": true, "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-jobs": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.2-rc.1.tgz", - "integrity": "sha512-VuNPXosjgRbEg0tp+GXsdAqkicwSk5Ynl2AezUQheJgpmw5cvWy3rLEg79B686xGc72tIA6pCW6eBbZGnKOmIg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.7-rc.2.tgz", + "integrity": "sha512-bzbdcQ1dzCAGjYDs2J+YiwG58cDpASecJ4N6euUJNl0CCmnDETwCUhCpyMKDKCWcExdG3XcHmCjaCnL2hZIC0g==", "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-jobs-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.1.7-rc.2.tgz", + "integrity": "sha512-DE0HLEuI15Vw1ncXLDESUIBTdWhrXgKWV3g/jupEGCwmm6GCqC9W9cjJPmbLP7JQGB7UPkui5DrIft+8MYL6Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-launch-environment": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.2-rc.1.tgz", - "integrity": "sha512-f9yDccTKrbClo71pIiAGqBxPsYf+vvcYA5zxkfgmjphpxI3HMwdDl+LNyqTHBe9UxpbgBzQNYQGtfWO0kDTefg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.7-rc.2.tgz", + "integrity": "sha512-i8U15ebCS4tWtL2mnuhfl0h5XXBagtbiGO63/OMeHpfWb5sHUvTYBNWTDxmlMjLDkTNQgPsXmRl0UrbWKCSJwg==", "license": "MIT", - "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-lazy-require": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-lazy-require/-/dsh-lazy-require-0.1.7-rc.2.tgz", + "integrity": "sha512-tJGmGfJzr+zXK9ZoDLFF9r8ZI5X5ARz945rl+tHTEDcgtm2NavkRbx4qjOg3kXoBasYGXtp18RGlBB2rWT7vGQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-llm": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.2-rc.1.tgz", - "integrity": "sha512-7VYsha5AXsVLnsAwYJffWXz9bwUbElw8i5N8tlTSdai9Bupk3sMbsotzPf8ZbsuGAxQYErahMwQwgGEu4qZO6g==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.7-rc.2.tgz", + "integrity": "sha512-hNT3ovFnbNDQ8g544bh2Q9ORX40aI6Y+jhjer1lETeHS4g0jTjqUUVfARCTA7uAFvHucSBg2rFgbisIktmJCxw==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1", - "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-crypto": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-crypto": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.1.7-rc.2.tgz", + "integrity": "sha512-bFHhDxegsawOI2uqGHAbPoYiRM9Lpq5g31TeqVYAMcMCpa5qbk1wGUsAzCP+eJM/Sbb19VHJpsJj/Op6UbBESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "eventsource-parser": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-anonymous-user-id": "0.1.7-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek-account": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek-account/-/dsh-llm-deepseek-account-0.1.7-rc.2.tgz", + "integrity": "sha512-Yq3oVAYih7b+kvb4S82fqcKkOmVtoT1WoxCQ7Y27SYbir2gO6g/QqVk3CsLS0Xqnq1CwBAH4xU3r2m+siq2o6A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-deepseek-account": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + }, + "@deepseek-ai/dsh-deepseek-account": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek-api-key": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-deepseek-api-key/-/dsh-llm-deepseek-api-key-0.1.7-rc.2.tgz", + "integrity": "sha512-Djc3LE0fZ73U+T75P81obElk9c5Fd7G25uNubtcFcSDKuo+tuJi8qEqvSTScCQVvTAsCPRQh7Ti5YjPKQdO29g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } } }, "node_modules/@deepseek-ai/dsh-llm-pi-ai": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.2-rc.1.tgz", - "integrity": "sha512-aT+21AUbZ1JYco9bBcmCgLYG85LLeWTCWUysBqcAkZADb7Vfn5F77LEpztE6BvRHKCtzVvsgp/HKKESwkK0zNA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.7-rc.2.tgz", + "integrity": "sha512-pkRHMAAu9v7Ko2yo+UzZmGg0rNlVymF3KjTch/z6kT9BfIxpI4dtNDkeibamszRvjqz3Oywm8uGm+Iwz0zW2sA==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2", - "@earendil-works/pi-ai": "^0.84.2" + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@earendil-works/pi-ai": "^0.85.1" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-attachment": "^0.1.2-rc.1", - "@deepseek-ai/dsh-authorization": "^0.1.2-rc.1", - "@deepseek-ai/dsh-credentials": "^0.1.2-rc.1", - "@deepseek-ai/dsh-fs": "^0.1.2-rc.1", - "@deepseek-ai/dsh-launch-environment": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-settings": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-authorization": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } } }, "node_modules/@deepseek-ai/dsh-llm-retry": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.2-rc.1.tgz", - "integrity": "sha512-WRpanzi4u2Z2X2uv/rwRZh5HTYUtd5smFTBMT4jYd1UpFOmjoMY/grDboZG9KI1OsgaS1vadiBJT4vvixFDEAA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.7-rc.2.tgz", + "integrity": "sha512-t3RP8ftkHFUXPRnpUGLogKsgXykJWPDad251qk8PvOHpWw/ex6HY8GqXm5YWSgbLHpEKHz+0gR7u6MyIdpqtxA==", "license": "MIT", - "peer": true, "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/schemastery": "~3.18.4", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-mcp-client": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.1.7-rc.2.tgz", + "integrity": "sha512-AUEhxqk8rPl41cIfi07/9dbIKKDOT0LWifX3K7xRki57X3Hd3XCT4PRiYekqt9sOJ7863d2t/knWk4pryieZtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@modelcontextprotocol/client": "2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-mcp-resources": { + "optional": true + }, + "@deepseek-ai/dsh-system-prompt": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-mcp-resources": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-mcp-resources/-/dsh-mcp-resources-0.1.7-rc.2.tgz", + "integrity": "sha512-V6G8Hdmh5gtvzzvlV8RgM43LbTOnoQnfmMdd8dBNoHKZLvv0XvcpmqZWNZVqpDP8NUx3/PGjo9SQK7R3gwROYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-system-prompt": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-message-feedback": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.1.7-rc.2.tgz", + "integrity": "sha512-XYgpXXr9iqgiuCzpFzdoNR55tT+kyZ7xEYC0DuxdcK9JNHpQdQcckOZkJU8+MzJ1FjoYGijTSV+y5jSuhX2UlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-native-command": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.1.7-rc.2.tgz", + "integrity": "sha512-XObRF7I6fVAXWSWvAK0HVp+nT9ZLR6g6mPss6j2ciovW6wBiAm71O2wzi2S1YqmQXYNaGwvudolqJyMRtCSCxg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-office-to-pdf": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-office-to-pdf/-/dsh-office-to-pdf-0.1.7-rc.2.tgz", + "integrity": "sha512-4FQi4gTiSgPg6oCYcYv5eT8hewoOK1Y3sYBAMGmYwBcJXuy7e37qOGOAu9bKaowhTAc1bi0yofdNruBm7595eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/libreoffice-kit": "^0.1.1", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-output-retention": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.1.7-rc.2.tgz", + "integrity": "sha512-hQodzFmVrANIiDw3i662XkA++Jmj0TCFW2aG3/9RYpiR+wkxmEx1bmWv5MuTX9t5QZ7vdyaAUn3t8c11OGyxhw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-package-manifest": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-package-manifest/-/dsh-package-manifest-0.1.7-rc.2.tgz", + "integrity": "sha512-oS6OD0emk+HD25B8FomvuAkqCg0aEooQEs/Tk7sZj9ww0uMXwYtU69Wnh4rFBQzp8pkZBYv9HeIzw67iBwDH0w==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-permission-presets": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.1.7-rc.2.tgz", + "integrity": "sha512-ci5LzPdhsaxUSMq43a1LOF5wixuFWECf3BzrUSlnOHp4q+cssd6Pf50LADe/CukHJkP7yf+ns8EXhT20iDwvrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-persona": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-persona/-/dsh-persona-0.1.7-rc.2.tgz", + "integrity": "sha512-1PceaaPx/xlZpCOJmcHVs2nAxdtgGTNo4mpytrmeEstxxc1ZEno7AoDKeTuZcnC4HIdSXBsTZHTWndNUW+SeDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-plan-mode": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.1.7-rc.2.tgz", + "integrity": "sha512-Lj4btqbwnSaXC2mQkk8VHnOPqx/HFNQyuLLB/n6RgeEjbAVDeGzDWcjEy3vpT+7K9YY1zU0FxMwp7ON3cGDX7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-questions": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-commands": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plugin-manager/-/dsh-plugin-manager-0.1.7-rc.2.tgz", + "integrity": "sha512-jYMEyz8fJWa099wvs7meXCOC+W9n2N5mxDL4hze/GDU+t9+brMrpnif6Ind8ENTu/RXVx8O40iCCsPcUXGwa2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "execa": "^10.0.0", + "yaml": "^2.9.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-hmr": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-plugin-inventory": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-hmr": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/execa": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-10.0.1.tgz", + "integrity": "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "figures": "^6.1.0", + "get-stream": "^9.0.1", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.3.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "which-command": "^0.1.0", + "yoctocolors": "^2.1.2" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-manager/node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@deepseek-ai/dsh-plugin-package-inventory-deepseek": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-plugin-package-inventory-deepseek/-/dsh-plugin-package-inventory-deepseek-0.1.7-rc.2.tgz", + "integrity": "sha512-Y+3VG3feOpjrwFupkr6jAncASs4As82VswGclr7FzqnzGz6GS2YIlALe3EaQ4sBygN1gE3cnXPFLFUhFXOzEtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-ptc-runtime": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-ptc-runtime/-/dsh-ptc-runtime-0.1.7-rc.2.tgz", + "integrity": "sha512-zRFwSSUgTpKuFQTVwnuNO4067Gyi//4C4RRLaUntXaHkZv3z1S07f1fTaYwX4+ubIIAuAVeEsczxf6tPgZ8P5g==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-ptc-runtime-node": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-ptc-runtime-node/-/dsh-ptc-runtime-node-0.1.7-rc.2.tgz", + "integrity": "sha512-E+c60QE0Lh4GCw7yDkvO56E17uRqbiT1ehJxdmFMmpu7hg3wbTT4rNB+w6qVsy5RUs8LSW7bsoSIk9ibW4R9ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-pwsh-local": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.2-rc.1.tgz", - "integrity": "sha512-jFJQOWkQ3qHWj4xg5he0pjJtzktZYnrjMmDTJmxI4vyMK8UxpEoR0tD4p6eNAJoxZusot9o1/SUqe+HJcjoSrw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.7-rc.2.tgz", + "integrity": "sha512-OJlGS7JLJe5CcLMvVdbxryS6bKW5pfYN2emIeTYhSu+tBsKAiah8kdD+2EOwC0XMq24NcwgKO7xlNmS8oIrurQ==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-settings": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell": "^0.1.2-rc.1", - "@deepseek-ai/dsh-subprocess": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.1.7-rc.2.tgz", + "integrity": "sha512-c3kXLNhf8fNL7nt8NfJwcHU0jPvRiy6IPF+DHtT/Tp7+NhytHwj8vR3Ln7GIwsXGNU2hJbaD63S2IStjWLaylQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-pwsh-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.1.7-rc.2.tgz", + "integrity": "sha512-tuG5xgqXth+CfNJiEMhsW+HTXfy14vMkuKx+J+47792P9AdxHr/a/Gi8qj6Err7TRU+Tz+d/VdzfsY+6+oWkkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-sandbox": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.2-rc.1.tgz", - "integrity": "sha512-nTO350NlVo9cvKzbeILcPIRIk9ijidrv29snRjTOx7kP5aO/BI2b4KxsRCYoXg8WGAMbIkGbsmZKUD4qz7hyXQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.7-rc.2.tgz", + "integrity": "sha512-7aP893mtTvnuZfCKD6hUN5gYchi6Wogn4W3mg/rGMvogmhbWgrCs00boJx/eHK4KvVJmEW1e8kO5N+GtsesptA==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1" + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.1.7-rc.2.tgz", + "integrity": "sha512-Xfyj+z5QZbbAU3nGU5JMpoJpL+mHkNCueMO8nzbBPiDvJBNeHvNefEvKmBRgtQmaxeHrpG9NRU6P/81KfqajlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-sandbox-windows-acl": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/node-addon-system": "~0.1.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-sandbox-policy": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.2-rc.1.tgz", - "integrity": "sha512-nLARL84X6K4DCUJsqRWINg3+1EVxsw70hbP+Yl92W/PsquQVs/UJQc55gnhYGmIMf6eJ0vQv39fziNSnAxdx5A==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.7-rc.2.tgz", + "integrity": "sha512-pIhCaOEqYjNoKy/c7dYYgYzK+zp8/FxnEeaBA5e6fTmNROb+/qSFsC4hY3Qu+PVU9IdbH/4fa6TbT2jnqoDPQw==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/schemastery": "~3.18.4", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.1.7-rc.2.tgz", + "integrity": "sha512-QOi5DSTDdEXTI2qhfx/uRZ+2zo3ssDG+r8uHWCor8Hg3VK28JICO1nWNbl3SDevvHqcKsM2oxNdwr5XTSC14jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "@deepseek-ai/dsh-win32-process": "0.1.7-rc.2", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-schedule": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.1.7-rc.2.tgz", + "integrity": "sha512-GR9m2V923qZkgvkEGcF/XN47hxs5By/3XahtJjqSRnqnUdMjUZ1k2C0XL4dDsluJLefrpFAK3sRx0LPJXxer3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@js-temporal/polyfill": "0.5.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-scope": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.2-rc.1.tgz", - "integrity": "sha512-GHwbzWrGbmE0ZGzAZsXBudpyCM9ENCpXxlKODIaPFbIWhRePh6nH2jW47TAOqCIsPPedWC2p3w8Tx5WAa3I/2A==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.7-rc.2.tgz", + "integrity": "sha512-rk/OM5ej6/V8pCNczEqQ3BkKx3DuPeFGzNUsEZo8hF+tnkF/EhsxMWSXC/yP/uLKeNkSsVHzjFpaQR0qr0J3gQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-app": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-app/-/dsh-sdk-app-0.1.7-rc.2.tgz", + "integrity": "sha512-H+SUCfCrHAIHUSSM3jnxUqUf3frSdtsUDBDcQ0SjybfyWuq4P3w/L3hfmvVK26EitireKOYkhoOpEB5I/PzXlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-office": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-workspace-dependencies": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-app/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-jsonrpc-server": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-jsonrpc-server/-/dsh-sdk-jsonrpc-server-0.1.7-rc.2.tgz", + "integrity": "sha512-2eOJZ/Ml3p4LnASEGydxUq+qTild9E6mcbBQmMElRfmiy0Po5b42L0Ds+8V0uRxVKZbvKooq8XNhDywQ4ZCcQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-minimal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-minimal/-/dsh-sdk-minimal-0.1.7-rc.2.tgz", + "integrity": "sha512-nxvJQXkrA9PvgGh96GAel2mpW4XCR6D9VTgYb1UzVTX6ja6kJT+IR2SIRHf9BnqWdDHxQXw7kGdcxd9GywE2WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-timer": "~1.1.6", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.1.7-rc.2", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-deepseek-api-key": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.1.7-rc.2", + "@deepseek-ai/dsh-mcp-resources": "0.1.7-rc.2", + "@deepseek-ai/dsh-plugin-package-inventory-deepseek": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-log-deepseek": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-sdk-protocol": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-sdk-protocol/-/dsh-sdk-protocol-0.1.7-rc.2.tgz", + "integrity": "sha512-jt75g7h8cxypjL6uXGiWlsvSpO8dY/aUo5Me4wnxpeslVyItYQurkIk35rYBlVG4fdlFep9/FAy+pRhnK/TKUA==", + "dev": true, "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-session": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session/-/dsh-session-0.1.2-rc.1.tgz", - "integrity": "sha512-jRGNPTbQcvIx1F2MVmmkoiHLgpC3Btqo1wkl/3JDLlOWRVWKOuaC+5fQiMrFPOYfno6YiX/c2UvmA0td8qB92w==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session/-/dsh-session-0.1.7-rc.2.tgz", + "integrity": "sha512-0dXv1t4Zox/yHkZ4PfPNSBWJfIc72PDqOvjz43EMoHpbmoKTVpit2UpUI+yTtX01e4MVBbDMxBZ95oJW/Oydnw==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1" + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.1.7-rc.2.tgz", + "integrity": "sha512-2V+o25gPkQNeBXD2E9zSTCxZzEnIKmClnQwhXEMKFWwS6Ibm99GFc51DFjIvhdu/I0/YawOS637KsrPznHILpQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-format": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format/-/dsh-session-format-0.1.7-rc.2.tgz", + "integrity": "sha512-ayk2VoX3r7m8U9rVc+F70qx76Eq3Mi3ToLySi29hDZPFLy8ujjSOO5LVCC1xmon8uukfcnScvElNPoP/mKTkBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-catalog": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-catalog/-/dsh-session-format-catalog-0.1.7-rc.2.tgz", + "integrity": "sha512-PMwm6M713ZWMqV0NVRFGeP0eYoBBCe0n4l5k8g1sRI+e2wD5xVoTEn8ZduG0vxnrVrGneJRDPQjZ4TiMi/fgDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-compaction-image-offload": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v1-to-v2": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v2-to-v3": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v3-to-v4": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v0-to-v1": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v0-to-v1/-/dsh-session-format-v0-to-v1-0.1.7-rc.2.tgz", + "integrity": "sha512-2JjUnl5+00N8/eda1s47VXP8wEl0HFqLRKk3MgEcRb6PEH3NH3Mvxb6jmkF6EeH0mMLLvzYHbpfDazOhECkXRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v1-to-v2": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v1-to-v2/-/dsh-session-format-v1-to-v2-0.1.7-rc.2.tgz", + "integrity": "sha512-a7Rsv7z2zeIyWpwRWkdtbi1T8r9zBGvbcoQVQEPpmpMFH9qu5hZmzYUGNFS1qRW5KW2cZoOU+qRxHwRoKI0dcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v2-to-v3": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v2-to-v3/-/dsh-session-format-v2-to-v3-0.1.7-rc.2.tgz", + "integrity": "sha512-che+x4X57f4MPWYWjj3UkcDs4qU0sQspUvy0Ie8w+iMFPkH0C7f/629l6ubZXRFrGF/k6djbyLR/NYH7nArZaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v0-to-v1": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v1-to-v2": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-format-v3-to-v4": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-format-v3-to-v4/-/dsh-session-format-v3-to-v4-0.1.7-rc.2.tgz", + "integrity": "sha512-PpGsFntVbc6HEnIlTRMluk55YPAFGmbz7SSyYMXDaz7N+jzWTa54AuMg9gUthHxPwZyj7KF2QtJAJnSQ2+GPGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v2-to-v3": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-deepseek": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-log-deepseek/-/dsh-session-log-deepseek-0.1.7-rc.2.tgz", + "integrity": "sha512-DOSb50EoF9ZGojLyCf+WCgHgz98aHXjQR7fX22EN7g7jDaOF7iFkFyBxJr7cHkkCwMGXgGXqvVlVb2r/Xmsyiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-deepseek-llm-api-extensions": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-export": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.1.7-rc.2.tgz", + "integrity": "sha512-y7Gt5ud52yFZM+v9sdmNyxUWEbGh3xIlXg5MWo9+159KBqyLyfO9yfA8MkTL8PouqNNvHwvN3Ea5ZZm9gWFthA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "fflate": "^0.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-session-persistence": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.2-rc.1.tgz", - "integrity": "sha512-8dnQGgqA8yK7SIxyC2utRdkHhM7mxw9iidDlPOx4GRO4fgY8+UpjxFvWPshkKsY2WNYY/nYcZQt5NNoE/Br4Dw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.7-rc.2.tgz", + "integrity": "sha512-xZXMo8hYMnh96UyxpkmDqvfxpmVNWbTlXqSuJray7S2kW8AkugKDc+FMy2+/znoBHhZsi+2/uKJRPj6dwDBIsg==", "license": "MIT", "peer": true, "dependencies": { - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1" + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.1.7-rc.2.tgz", + "integrity": "sha512-Dymapt+M11rJKQgsisfod2LSf0HvyUN/8QTv+g3BAXlRh5YFXvRcSVsY3XWj5NnUs3tlbU2aauBE7OXbMSP4vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-catalog": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-format-v3-to-v4": "0.1.7-rc.2", + "@deepseek-ai/node-addon-system": "~0.1.2", + "@deepseek-ai/schemastery": "~3.18.4", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-session-projection": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.2-rc.1.tgz", - "integrity": "sha512-qVWlIzPm4u9vzQ5G/QtE6jeSJ3b3b42hWVJj664BurEZlHbAfdqkhYc1QsoBU+5k5kUEJFHh07z8HxuXA9kTnQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.7-rc.2.tgz", + "integrity": "sha512-s5T8oHBEh+GeOTJ+wehD4CGZkTiWgczZZA+NDbfbqUO0k5L+dk0kk3fN+/srAg77rhR7UeeDSR8ZNcpYx/VUdw==", "license": "MIT", "dependencies": { "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection-cache": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.1.7-rc.2.tgz", + "integrity": "sha512-7SRuNDAzOVMbKoXyK0GAA8xMYVRAHUCoYiR56+4hHUkU7YQ5JuRjQiHxG6dEtYqibp3AI8E+oXgOJhkpB5Gl8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-query": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.1.7-rc.2.tgz", + "integrity": "sha512-dS9+GFdXBS0UWiSMiloD6IpSb7cDy7ig//h0LaGZAro8xcfs+rY+78Eu5JKrTObTCTL4p6x70cxAJdbRaIxzGw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-session-format-catalog": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-query-sqlite": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.1.7-rc.2.tgz", + "integrity": "sha512-Yxer7MvfvJ6mi9Gkvl+NZyKLZkVuA8eMwhQW8O7EL6AK4I+Xb8tCJymvgD4ev/EFzuoQJHgtlwtD4x86qQp/GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-reference": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.1.7-rc.2.tgz", + "integrity": "sha512-Yo+/foHDI5JitZl/+Pt76QpwytkkDjv5vwSKtMQBXXLXPRJSuXz+xtSkEqQCQ1667RbksGZz8mVzWSZWb0IpYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection-cache": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-spill": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-spill": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-stats": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.1.7-rc.2.tgz", + "integrity": "sha512-BT3X9w6REGTkc5bRH5jLiQ6Hv+jkiqhxzSQnnwJKmskowthLwsigN9cn760IBBCPZNyPNGghixAMxm9pl0/yIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.1.7-rc.2.tgz", + "integrity": "sha512-JyCrRnTlA5tKU+8MVP3+byoA3ducZjZpSJp/2t0GofbvyAhYdvQVoR3hb4h4OxUxPiW+dPUtC95gCr+snM42Ug==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.1.7-rc.2.tgz", + "integrity": "sha512-rgWtlx4Wc+F9grOeun9tt9R0u6HSbToxapkxEeJFtkSIm4TFAUKRP7osv2I7LEleUNmc7dpQtp87aHrWpnXXKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.220.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/resources": "^2.9.0", + "@opentelemetry/sdk-logs": "^0.220.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-anonymous-user-id": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-message-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-telemetry": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.1.7-rc.2.tgz", + "integrity": "sha512-UsbFH2ESc8lY2YgSb9OPsXOBryOc7qq0f57FYccb3yOAez27afERWwvcPGZY8D9YTJKZCf0Q3ae/NZMQU15AJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.1.7-rc.2.tgz", + "integrity": "sha512-I7O64gk/HLoBjPWu1ikDd6kEz7QZKfI+njyLGaGapLITycRMYWDaSCQGKXqPvTlMPTNQL8ym/kKXbFrG61j/Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title-llm": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-llm": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.1.7-rc.2.tgz", + "integrity": "sha512-KmHI4hvuY5lpeMJLq2sR8vxTXvakgSA96DbqmqX3zbE8neCM+pojZBcUeDKdYwV6TfiT2oWJno1n7QGwoT9fdw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-session-turn-outline": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-session-turn-outline/-/dsh-session-turn-outline-0.1.7-rc.2.tgz", + "integrity": "sha512-Ouag8143h3+exBd8Q7iQ4XI22VcR+0rfDgOjzsVC3WMq6ckHLeo3SrxLFLXMuLn+UpBTBnjy1b2q6uaLemQsIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-settings": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.2-rc.1.tgz", - "integrity": "sha512-wMmJ2w5S6I7hgmgPppuAVemltEcTmAa8gvii7fk4T2KGVCuBYgig8xPwQ8Lp2ukLZSzzE6ZVCQxhdYZyJX/USA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.7-rc.2.tgz", + "integrity": "sha512-xS48//SMs3xp5qI+brj0T4BsJ1vgcv2LteZO6lW4X0YZVUOIe6H9aS2sRPh2OAWTFHrzPep4NwVkAOCD8NvBzQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1" + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/cosmokit": "~1.8.5", + "@deepseek-ai/dsh-config-editor": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "yaml": "^2.8.1" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" } }, "node_modules/@deepseek-ai/dsh-shell": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.2-rc.1.tgz", - "integrity": "sha512-uFrSY0nNKzh5orGl2B0B4RfK7wTdIlwhPQc7aLA44jyjioLlqhF7PUek/NWtye2scwp3YHOw158XeOQUD8qTFg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.7-rc.2.tgz", + "integrity": "sha512-l/CdrpqFG3SNPKBm7/zJkqn8gODxMLcTOg57zSqyDi5VdJXb8dlRQNHH4KfhxfWM9rZSH5AC94g6Il2n3sOQ+w==", "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1", - "@deepseek-ai/dsh-settings": "^0.1.2-rc.1", - "@deepseek-ai/dsh-subprocess": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-shell-env": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.2-rc.1.tgz", - "integrity": "sha512-o1VqxyHp1OrMB8aHnzYAPwuU4giUErCxBg0yr035r6f3Le36viS0sUHsnjcAsMdbaQJf/XvzbaokYDVrdVHE4A==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.7-rc.2.tgz", + "integrity": "sha512-Zu31yhGgnB+WMah0Qb/+adZTeUr1MQLmNMU8lV6YVt20tCnbA+HFI/akPTIoc9Ux8+Lqf6/fyv4e63OniPXaRw==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-home-paths": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-persistence": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-skill": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.2-rc.1.tgz", - "integrity": "sha512-oaHunkTZ9gtlxp66GcqZ3tQmPXEgbu/KNCnc9JipaIwfLHFYiU3CKuFjVAiu82qtSr9w7umRMFKAstkr1R30jw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.7-rc.2.tgz", + "integrity": "sha512-m1SFnBjx8F4upZObk13d3MC6QsiNA3kWHJ5dOZu+Z9oB5BudzNnFJWXZf2gcZclWai9lOiKxCb1ibPio1inwUg==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" } }, - "node_modules/@deepseek-ai/dsh-subprocess": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.2-rc.1.tgz", - "integrity": "sha512-roTna1QHNpR5NsOLBWRai+GxW1hQAUyIyXOg5tsAIPXt7dug/kZJXeryiR9e92Fc/yoXzHMgrBQCThuXuo97LA==", + "node_modules/@deepseek-ai/dsh-skill-badge": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.1.7-rc.2.tgz", + "integrity": "sha512-l3jIjc7m9xqARMO3uGp/exH7S76T5A7y4e33dAFeFdIdJgy4D37pLWfy1UY8drIP91TgaIniqz4RO1jfWjPg1A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.1.7-rc.2.tgz", + "integrity": "sha512-k+I8mictkO+g8JMm8EM13yDtG4MqeES88DJq7TJNKRT4o7tD2vkDqr8Ep3KN4EYH5KDGd0h6HabIwvEqhbx37A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "chokidar": "^5.0.0", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-office": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-skill-office/-/dsh-skill-office-0.1.7-rc.2.tgz", + "integrity": "sha512-kU6bggLhVzqxYYXZHS2dCVRxa3MlofoLbtT1cdLC0D8qmJ2S8juja4PEm7HI8100PH9y7WSsAkQLqcsJgVsJGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/libreoffice-kit": "^0.1.1", + "@deepseek-ai/schemastery": "~3.18.4", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill/-/dsh-spill-0.1.7-rc.2.tgz", + "integrity": "sha512-OV3T73WDjz9x8Zc/Qwfjui1I/bVWO7UVWNK4FjujZABJi/61PMyUYmrWMBjF22VGS4V1f2foSJ0TVzd/1mq+gQ==", + "dev": true, "license": "MIT", "peer": true, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill-local": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.1.7-rc.2.tgz", + "integrity": "sha512-ls6vTHb2GHUbi2Es2/sBdtS0A3k3Wrfyq2uVbMI5XNARoMnftezcIcxyGME+s/7cCtAof7Sy5LK6BnY2vOWuUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-spill": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-spill-policy": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.1.7-rc.2.tgz", + "integrity": "sha512-n4CrVMlS/kK4bQMHBlhrr9V9z3UuZdynwpXKKq1j+7Wl0GbqIyimGyzfVCVd0u5L84geVbI825ltleBqirwNFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-spill": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-storage": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage/-/dsh-storage-0.1.7-rc.2.tgz", + "integrity": "sha512-BZ5MZY44KCUoQEy8FJTpSOXfGGPQ3sJS3xrwxF9rARIqHwtsR5WR6rXY/JmsFNc3nI0djGmJ0bF81U0q7EbDLA==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-storage-domain": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.1.7-rc.2.tgz", + "integrity": "sha512-Ch+k8iYvxMtmxxcVFZQ75griJMdj7RX49mbgRXLbr0s5IvCY2RYPNVDLyB1e/2wXysT1rP08FsH8nH7PoVABRg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-storage-json": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.1.7-rc.2.tgz", + "integrity": "sha512-dmzUEcCPkvCppdZFv4TC9OlVNbb+oJdl20ybtENbIy967/kYVnJryyRBtAR6ajm2hQ2MmK9XyOD/XTZpZHy+Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-storage": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.1.7-rc.2.tgz", + "integrity": "sha512-wIl53frMLSQI+QXfKTHBdyKT/hslFH9LT0DUDeiNyShGkiewYG1wSY1rnmv+p57Q+zS/SfDYjt0s0MGK1tUL0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-chunked-list": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-query": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-time": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-preset-registry": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-permission-presets": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-query": { + "optional": true + }, + "@deepseek-ai/dsh-settings": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + }, + "@deepseek-ai/dsh-workspace": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.1.7-rc.2.tgz", + "integrity": "sha512-tGJ06AG1JXXTLQBdskJRaggA/gg601+lr52kxvuT1sx/L404hRdw18OdPOebDh9wrj8gt2zxeVEkHA0QY6Hkhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent-in-process-driver": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.1.7-rc.2.tgz", + "integrity": "sha512-4NroGWZydU4INXIyPGFKL4Zy1XfMphGDqAJyz/bVTNdrMi6M/8XdRASzTKvsud8TP6IMklAGxcEyEw0pD+AKmg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.1.7-rc.2.tgz", + "integrity": "sha512-xEWjgl/wMalKHGlckmTZ8B0UuwPUGAUathXaeVvs/stqLgmX5IFa1t2/KAN/guLOfeK0rHYvqQGSQhBJkCGxxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent-in-process-driver": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.7-rc.2.tgz", + "integrity": "sha512-HgELZIXAEDvlqI4ThbaJ7bJi2ytotxjcaAoXgiKstFGyyf9EAHOSmLkmJZ1G4nunF7cop2YclSEpAvGNTofBTg==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-http-proxy": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-subprocess-local": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.2-rc.1.tgz", - "integrity": "sha512-Spc/IXWvjEteGysifGr6JvCokcH8T88z0mdxIGcu9SFdgDyY8HKR+h5yq73+rbo4RYzT7+TBE43TIZy5LfmzgQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.7-rc.2.tgz", + "integrity": "sha512-1JKUC4YriYbuyNsDcOwb+WQVaxy6I8CWeTVP/UoEc6uXPSMQdS3GJArDYyFdC2NzjOEmAxpTr4awTNNrpA6Gmw==", "hasInstallScript": true, "license": "MIT", "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "@deepseek-ai/dsh-win32-process": "0.1.7-rc.2", "koffi": "^3.1.0", "node-pty": "1.2.0-beta.15" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-subprocess": "^0.1.2-rc.1", - "@deepseek-ai/dsh-timeout": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-system-prompt": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.2-rc.1.tgz", - "integrity": "sha512-7W93PZKIk4CHvjZGgLIxrrEKpk+6t8nQXje1vKR5vG73dfXH0t1MJ5WWH/fngadYc7c6KzM84ihQ66tJqJqyNQ==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.7-rc.2.tgz", + "integrity": "sha512-vxKcADh7XOuWJOfa0WeEOhvFiUbMOdoK4w6M7KVCI0S99c9ktxrgY4wKdmAxap+nQjwTEPme3QuOlY3Na+cz9w==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" } }, - "node_modules/@deepseek-ai/dsh-timeout": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.2-rc.1.tgz", - "integrity": "sha512-llz11yxWeJB8suKCa6hRLjNBWVaPn3Fbd0XoBS0bkZLhPFzO1mDorx/XMca2GhI7XF9A86CURQcDt+aGjjvqJA==", + "node_modules/@deepseek-ai/dsh-terminal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.1.7-rc.2.tgz", + "integrity": "sha512-8C7Ua0DZY2dikN1zPthvlYcxWAmB2bPMup/LJXsnD+2CK3D1QSGEsxkjIUtpGZo0HnapJY1JixzgOU3/fab5Og==", + "dev": true, "license": "MIT", "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2" } }, - "node_modules/@deepseek-ai/dsh-token-meter": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.2-rc.1.tgz", - "integrity": "sha512-6mlC89JNGudPvR9LekEo2mnEo/DXf60ZjekIKXxZqpf66AOQ2/pa2HJuFikEd9WWRvu2D96Qvx3rILxi1vXVww==", + "node_modules/@deepseek-ai/dsh-terminal-bash": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.1.7-rc.2.tgz", + "integrity": "sha512-6dlzgzSoClNcW/th0iapYjWq7gGfSQqIUTqHxZXKwvOR2g1x51uagRctQ7AamNw4iOStQzLFGQ3ctLDg8WSQfw==", + "dev": true, "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@xterm/headless": "^6.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-time-context": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.1.7-rc.2.tgz", + "integrity": "sha512-YemKiNNbS+y7H80aHDSahYlgwlgQR1UU/8SabAbFLepWqrGH07O0HdSoZ8WVmXD3wBX+X+hAJyWw3zTT52jDMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", "zod": "^4.4.3" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-compaction": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm-retry": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-timeout": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.7-rc.2.tgz", + "integrity": "sha512-YunLoLZSF8Ld9eYwyvKoBnxgy3GZrIQpw98HfFS15ZfZlqcFiZcchFhYmStLtUbtX+gjhoeXc8Xz913YbVifNA==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-tmux-context": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.1.7-rc.2.tgz", + "integrity": "sha512-DYRsMMTgQicntevipFcV6k5LyTMm+UDmo46b9MRK0hc34y5RXCSdX9uIrC0GErDm1K8N1OufPjTXwJIgMe65MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-token-meter": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.7-rc.2.tgz", + "integrity": "sha512-9Ig2EI16amhKyiitkWqMzvCocTc8O7Z1bHZbHEQUMeKRlp7F0t1l3hUT/JSd9DQ7UzRcjSAhVavXGwke5lWYGQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-compaction": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-image-offload": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-retry": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ask-user": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.1.7-rc.2.tgz", + "integrity": "sha512-qOdhDY9GD6ibSKFNNcRN3i/FHj1csnStK3DHg/5Gagz4W4i3YmpfK+5bOPp/wrhPgzRDCh/wLYjRo4SiyKujWA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-questions": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-tool-bash": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.2-rc.1.tgz", - "integrity": "sha512-xKc4oXVDBwM/PaicpjGdWEaJ1N14B7KPmOzdpQ7ynE4gKUnvGU/eTg18EHamdyDOidh5ox0fNUnxk0rQjVo2+Q==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.7-rc.2.tgz", + "integrity": "sha512-pdFYrdnX2OlMN9nI0XT5MZwMkR58x4Z5j9qyTfMYLvtbuZxHwxcdHq2PJU3vAuVQj14F7TJiFEan2EXq+X1mFg==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-jobs": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell-env": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.1.7-rc.2.tgz", + "integrity": "sha512-aFNJWg2MW+cpyv7yOOl3sfpE7q4e9hE+DmODYiBxXtdTEKfDuKMnIY7Z8TT9sb/wonmUNaneG6LpNUzz6lV+og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.1.7-rc.2.tgz", + "integrity": "sha512-k8UaAZqeeYmcY2G03o8mD6ks8LL/yy9FpxAaskcAsVF2kJxMNS3+lSajbKc2APSYExG3jJxPN2OuiZ3EOUljLw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-cordis": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.1.7-rc.2.tgz", + "integrity": "sha512-hCZzHeHj2fy+fUnW9aVj4DkMao1KFuzfO249n+7Mkdo5WEEy9s9XlNAgZA6BKST6VuE6opIRbj1HqxEkMUqZuw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-cordis-host-runner": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-tool-fs": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.2-rc.1.tgz", - "integrity": "sha512-9a1lcPGD4Z3p7OLTMkkCdwN0w7Gl96Jlypq6qopUA0WMkKai83VfeLZvramPnTJo6ezpuPXcLFWGm/2UDSlbcA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.7-rc.2.tgz", + "integrity": "sha512-/6wYrqHH1530tncA7DxC3IxLN2iI8kyhCPR/NfaugL09yGPpBwxm455bMvITSjIAvINWpJfMQvaijPui6goY2Q==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2", + "@deepseek-ai/dsh-util-code-language": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", "diff": "^9.0.0" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-attachment": "^0.1.2-rc.1", - "@deepseek-ai/dsh-fs": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs-search": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.1.7-rc.2.tgz", + "integrity": "sha512-wVxBYba8b9CgnNWUZx6Es10FrM5sP1JbAN/wq3Rv1Qgt/Z5cb3CJwubqvMg5sxpohkqM0y/bXENAgxzh/hbKIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "@vscode/ripgrep": "^1.18.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-spill": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-goal": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.1.7-rc.2.tgz", + "integrity": "sha512-Otb3HOlyZA+44nDXrMi9PW4vlurudOaRYdA7hu4MZBtqvmFEty5loJAzrtDbAhwImhA/UM9M+7Qa2ijwm68qCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-jobs": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.1.7-rc.2.tgz", + "integrity": "sha512-FAqhI8Hf1InawbrJF/XUjIlQHV11vRMWbX7ofrekJcX0OBk/Og/h8SUzy1knGBVULEm8m2PDLxggXoMu+HVlvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-present": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-present/-/dsh-tool-present-0.1.7-rc.2.tgz", + "integrity": "sha512-9TcVuL6qaQmKA89ACmPyToorvrLYmiJRVEbMr31WmcnvTyOBYLvQjcM39HWVPS50FKuYmHqlsyh3EkVUOkhTQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-tool-pwsh": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.2-rc.1.tgz", - "integrity": "sha512-LaImOCdizIGkQnxzzkoaqzRWGZLsuDuqqF2adgJ3zeG0nDwan4Sz+1wYz4YSp0Gg6mJ79CYacsbYmGhYYyKY/g==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.7-rc.2.tgz", + "integrity": "sha512-GMFZT35QKoFOXzFV576FbohrdfcXtrMJlOPqdQvNvUdMLYPiiJEIR4WSuqQuGBoez0bLxKVwtodGzwcvPBP+dQ==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-jobs": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "^0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell": "^0.1.2-rc.1", - "@deepseek-ai/dsh-shell-env": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.1.7-rc.2.tgz", + "integrity": "sha512-Qmfs0hRjuy6UJXS5f+qyNhtVphZzINQlIbZ8vUCBnBJdByIRbHq8P2Qf97gvndv4XExKQ5vH+i3SwyR7UdK/GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ralph": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.1.7-rc.2.tgz", + "integrity": "sha512-D4AVzhOUVvN3GhM/grIC61acOgMzdka1dsRbPNPsSTAq2b9iocEGWlWexa4QK90fv1O0+r18RrsuLg9CHiWOLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-tool-skill": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.2-rc.1.tgz", - "integrity": "sha512-H4dORZoB2wuTcHjE1uMvos7D850mE9X1ETjXdzr6+1JTTw8uOeDsHhmNfpOMjhA4/ztFEW7QAQlymI25Er6yAg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.7-rc.2.tgz", + "integrity": "sha512-mAhFhl7dmP5VZGsnvr36R/tAbhv1nyWRhdWmCpkkAc/zUNjn4ItqVe8eCeho9rkCfC4d0JmqBLQxY0bR6gVgIQ==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-skill": "^0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.1.7-rc.2.tgz", + "integrity": "sha512-3ul3GhzjcPYu455d7UncHYi3k3j0oNaJrOi/Xa5Nu/cu6XFD1RNS+r3oeXoKsnQhhLvamvRNUbZo4+Rf2g3WIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-output-retention": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.1.7-rc.2.tgz", + "integrity": "sha512-tsClP3op2uxw3itf/L2EQ37QLS6LEdcKuBKUmq0XNnOvAjut4xUByDzI52W94leJ2hVbWYipmDzlGis27mo95g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-control": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.1.7-rc.2.tgz", + "integrity": "sha512-GQASFI77x8ly7HSJ64Uxd281LqnPlnuQnF860Xx0z36OPHLzDzdFksFiFeT8nI1llun6FoqkZli3EUsPAXme1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-todo": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.1.7-rc.2.tgz", + "integrity": "sha512-W5H6XKw7C9MzEtq+tliiAe2cI8hkbg1QA/yJLpRnm2z0xPZwaaX3I3o76gJa6tQPY7TvkFu8WQYOwtToAI8fwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-web": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.1.7-rc.2.tgz", + "integrity": "sha512-vFjWk841utlC8M9LMj+Qy1ZQF0skcbnt07vP5guH68UbL3zjDix0+LShpbd/mluQyJ3LhzRpKmqveysnna2hAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@joplin/turndown-plugin-gfm": "^1.0.67", + "turndown": "^7.2.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-web": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workflow": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.1.7-rc.2.tgz", + "integrity": "sha512-VFo7mhhUu+tHS4sLCMejWexhQPYguoiOainwYBCuxd0fCmkgIFnSEH+AmMfsWYAbtUxhMNaoktB4RNnl8QmXmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workspace-dependencies": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tool-workspace-dependencies/-/dsh-tool-workspace-dependencies-0.1.7-rc.2.tgz", + "integrity": "sha512-soBNUme9Pfp/rLTM8t4tUqYe6jJHD5rUQWvAr/z3AckuhbkBu+d9BpBij8oinJoM7fRz0uUywzxGtfaFBD42mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-tools": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.2-rc.1.tgz", - "integrity": "sha512-W9kUio00s7WbM8kEwniyd4hfb3CeUxVczsjXbOcKtakfiTywNLeyRWkpx2fvwRAH2rBfg3qCgczVfS0DOw1csg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.7-rc.2.tgz", + "integrity": "sha512-c3dTdKnslKxVTgjjPLwMKLqGUMwnZH5P8RUsucMQlWn2GViyFW/+5AIUuZHBjjE6Y7NAYl+lVVE/R4LgTp5KWA==", "license": "MIT", "dependencies": { - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-util-values": "^0.1.2-rc.1", - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-code-runtime": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-typert-loader": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.1.7-rc.2.tgz", + "integrity": "sha512-oA8oXl4tMfhJcaPfi0ZhxZjixCKirLvYpRG09yM1t3oIgm8sG9JlCLwJlNo/jEOlxnO9EDoxLZ2IW5saU7ANrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-typert-registry": "0.1.7-rc.2" } }, "node_modules/@deepseek-ai/dsh-typert-protocol": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.2-rc.1.tgz", - "integrity": "sha512-vBWD0NpriPd96ltbWaAw+iKeWFIEjiAcCWYtmqEcV1Ms+FaV02usjjm7LCmhSQhMZpBSBc7EZUX0spGlpjI1bA==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.7-rc.2.tgz", + "integrity": "sha512-oJm03zqMQlvt16Ejw7VWy3/gqlJGrBCZj3Z4KL8ydLJeeTToKIR49WVCxMbJTlH0F9QFljruLtHguA5B99AeUQ==", "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2" + }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-typert-registry": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.1.7-rc.2.tgz", + "integrity": "sha512-fU6+xBn1BmFeWR0TlJUrOH3Vek21Wz1XHZvC+y1Ftc/cc4VNRBEQp3tvUSTKC0n3TBELqO9yY0uQP+l0JhlAHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-user-approval": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.2-rc.1.tgz", - "integrity": "sha512-oYkLE4a/TwqVNi299pUf/QP1Yku6KScdUCTUyYbjaRBcN+/pXPpHikl2aoE2thH9D0uT/Kj6T2kz+wDDcFd9Xg==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.7-rc.2.tgz", + "integrity": "sha512-RQ6GB+C4G6VY/eJrFfS89+89DfHFAJ5G1abhmutfKBhZcYSnGNZyPIzpr5mKbl2xNMIhvCJOb9WiFz2fUPW2HA==", "license": "MIT", "dependencies": { - "@deepseek-ai/schemastery": "^3.18.2" + "@deepseek-ai/schemastery": "~3.18.4" }, "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2", - "@deepseek-ai/dsh-agent": "^0.1.2-rc.1", - "@deepseek-ai/dsh-brand": "^0.1.2-rc.1", - "@deepseek-ai/dsh-invariants": "^0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "^0.1.2-rc.1", - "@deepseek-ai/dsh-scope": "^0.1.2-rc.1", - "@deepseek-ai/dsh-session": "^0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "^0.1.2-rc.1" + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-user-questions": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.1.7-rc.2.tgz", + "integrity": "sha512-Z7rfQTXNRgPEt0gEcetoM7iO9CVxsUCeDwHVj59ArFmUGS4491Y2AxXg8NP6Hu5x79XAZ0N49sHh7FiJBPYUWQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-scope": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-util-code-language": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-code-language/-/dsh-util-code-language-0.1.7-rc.2.tgz", + "integrity": "sha512-/NcCcgFXbTfV4sse5HoYO6SyKfcn9GFHeCP/bPkFsACZSv1dhosFivnz8jkkS1esbQe97jiki+UQcZBd+O6Usw==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-util-crypto": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-crypto/-/dsh-util-crypto-0.1.2-rc.1.tgz", - "integrity": "sha512-gE8FznQ1hkknw9QMrHNSlm3UEyRYuj3MLVvlJ6NyH1kmOsdjnbrVbSs+Pn72k2oIV4Fiyu3Umg0sLznUEcsiXw==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-crypto/-/dsh-util-crypto-0.1.7-rc.2.tgz", + "integrity": "sha512-BGc55/bSj/1LcDTQ5fpok4U24X9SFyN+TB23/hBlbe2TBUKVuwO8+X5FFKKje2MLO8PWYEDkXv/LrV6jRVKZEg==", "license": "MIT", "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-time": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-time/-/dsh-util-time-0.1.7-rc.2.tgz", + "integrity": "sha512-+bj6L7zdTybkmhEnIlv8ZR1pOm1S+I569CMCtIfbdIg88334hWxRyygCksvNC/VG3Lk3jeO0HzThkv3R7OIsxw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" } }, "node_modules/@deepseek-ai/dsh-util-values": { - "version": "0.1.2-rc.1", - "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-values/-/dsh-util-values-0.1.2-rc.1.tgz", - "integrity": "sha512-FQdgoK+KYVR0pBQb9fTsajvGb3gzUxEzJQEYnFOt+Qdwc4nkxJOPwJJdIvXuqvZaQ33DaOoqpnpcr2p5HpLu4g==", + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-values/-/dsh-util-values-0.1.7-rc.2.tgz", + "integrity": "sha512-UX8nh5SbtZcPVVEvjd+9PCPcbybA6OpVzJGgFxYn59ao/7QQGyYbByS8KXr+THU5JtqmDDVb9xGUSJaF2IYmeQ==", "license": "MIT", "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.2" + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-util-workspace-path": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-util-workspace-path/-/dsh-util-workspace-path-0.1.7-rc.2.tgz", + "integrity": "sha512-opp6TTeRvZHPi2bsXNK66TwUBh4uNECZJp/qK35ffLQRNa3L+RoPsGgOJZuRjkXdNygytM26P/CWjaBX65oKXg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-web": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web/-/dsh-web-0.1.7-rc.2.tgz", + "integrity": "sha512-iMKo3ZeF3OEl0shHmPo/k7UmRQdynPdhLyoHGuSduMj5qPSTnRzZEYCJ4OErvCaxRSY9gSlcVEiOATKhCgUwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-app": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.1.7-rc.2.tgz", + "integrity": "sha512-3cMgHys6X9N063HcjhFN2a3azGoWWDtH42/io33gcBZMZxbYP5Kevc4l/erwKa5hAzXtJ2FArjJAytJmy8WSKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent-instructions": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-tool-presentation": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-account-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-job-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-settings-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-terminal-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-workspace-controller": "0.1.7-rc.2", + "@deepseek-ai/dsh-api-workspace-files": "0.1.7-rc.2", + "@deepseek-ai/dsh-app-boot": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-file-upload": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-hmr": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-modules": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-resources": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-shortcuts": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-agent-preset": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-approval": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-attachment": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-brand-official": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-chat": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-commands": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-cordis": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-deliverables": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-input-trigger": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-layout": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-message-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-model-selection": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-open-in-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-permission-presets": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-plan": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-schedule": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-account": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-agent-loop": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-general": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-models": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-shell": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-settings-web-search": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-shortcuts": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-browser": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-documentpreview": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-files": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-right": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-sidebar-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-theme": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-tool": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-trajectory": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-user-questions": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-workflow-run": "0.1.7-rc.2", + "@deepseek-ai/dsh-client-ui-workspace": "0.1.7-rc.2", + "@deepseek-ai/dsh-cmdline": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-compact": "0.1.7-rc.2", + "@deepseek-ai/dsh-command-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-basic": "0.1.7-rc.2", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "0.1.7-rc.2", + "@deepseek-ai/dsh-cordis-client-runner": "0.1.7-rc.2", + "@deepseek-ai/dsh-cordis-host-runner": "0.1.7-rc.2", + "@deepseek-ai/dsh-file-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-file-reference-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker-auto": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker-browse": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-directory-picker-native": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-frontend-static": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-open-in-app": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-plugin-inventory": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-message-feedback": "0.1.7-rc.2", + "@deepseek-ai/dsh-office-to-pdf": "0.1.7-rc.2", + "@deepseek-ai/dsh-persona": "0.1.7-rc.2", + "@deepseek-ai/dsh-plan-mode": "0.1.7-rc.2", + "@deepseek-ai/dsh-plugin-manager": "0.1.7-rc.2", + "@deepseek-ai/dsh-schedule": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-log-export": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-reference": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-stats": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-turn-outline": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill-filesystem": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal": "0.1.7-rc.2", + "@deepseek-ai/dsh-terminal-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-time-context": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-ask-user": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-cordis": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs-search": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-goal": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-jobs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-present": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh-persistent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-ralph": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-subagent-control": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-todo": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-web": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-workflow": "0.1.7-rc.2", + "@deepseek-ai/dsh-web-frontend": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow-ptc": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace-changes": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "commander": "^15.0.0", + "open": "^11.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/cordis-plugin-loader": "~1.0.5", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-app/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@deepseek-ai/dsh-web-fetch-http": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-fetch-http/-/dsh-web-fetch-http-0.1.7-rc.2.tgz", + "integrity": "sha512-fz1aBg58oqigPDkmePUjlONK4u345fd7BF2q/sD2LGnTafrBBQqeiJ5BZQrjPLYoLywsATveRt9h/tLqU4XD3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "ipaddr.js": "^2.5.0", + "undici": "^8.10.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-http-proxy": "0.1.7-rc.2", + "@deepseek-ai/dsh-timeout": "0.1.7-rc.2", + "@deepseek-ai/dsh-web": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-web-fetch-http/node_modules/ipaddr.js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", + "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@deepseek-ai/dsh-web-fetch-http/node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/dsh-web-frontend": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.1.7-rc.2.tgz", + "integrity": "sha512-E9OgyYxFAeVaymPWzlqluWcX2KLmE107FXDB9nUrn/ADitlaEqGlReotK6g9LXqTY5m9TMp+WcTB71qbkg2U5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh-web-search-deepseek": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.1.7-rc.2.tgz", + "integrity": "sha512-xkDMbKm8Bu/PzoUO7pc3q2ME5p8HQo0NVbT67dGY0jtdwX2klaMMCDkkkMDkPvKJi+HjpVIDLH7eMdtMqQbShw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-web": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-webhook": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-webhook/-/dsh-webhook-0.1.7-rc.2.tgz", + "integrity": "sha512-2ZIAdQBN6XxC2aN247m/3Q9qacEJiSE5KINhdYfWDVALt8c7cTMjWwqhIBjQhr8G0LdFUHp9PIUXNnRxNzKezA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-default-model": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-preset-registry": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-permission-presets": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-title": "0.1.7-rc.2", + "@deepseek-ai/dsh-workspace": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-webhook-github": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-webhook-github/-/dsh-webhook-github-0.1.7-rc.2.tgz", + "integrity": "sha512-PwGhpHa4FiYErVE0Hd905Q50qXty+0WMK+1XXLevEjOHdFyj81m8F+VB5RSw3nNjDhkGzYVmBMlplLwl2drLFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4", + "@octokit/webhooks": "^14.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-webhook": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-win32-process": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-win32-process/-/dsh-win32-process-0.1.7-rc.2.tgz", + "integrity": "sha512-sa3z0camBZEQsf2g5XK8SLsNqTY5OYli0nUCG8j6yzkWOb52cBpDA0hSNo5hP6IhVba5N8hT/DfjS3IbktGz1Q==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-lazy-require": "0.1.7-rc.2", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4" + } + }, + "node_modules/@deepseek-ai/dsh-workflow": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.1.7-rc.2.tgz", + "integrity": "sha512-PJ8IH48HKPporTG5tGHPWs8pRHADMI/tp147OY09oD5FNQw3MjrVTF38TzhZp3FCjhHCxnbdhcayCxh1QzThFg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workflow-ptc": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workflow-ptc/-/dsh-workflow-ptc-0.1.7-rc.2.tgz", + "integrity": "sha512-INiZ8OUrrQGYgF/YfbDi6ajwkOaFHwp0YhlSDVZQWiJY+HnG8QY9XEydCyf+wdMkayCwqLHBFSLNzHh4OsM5LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "@deepseek-ai/dsh-util-values": "0.1.7-rc.2", + "@deepseek-ai/schemastery": "~3.18.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-ptc-runtime": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subagent": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-workflow": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workspace": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.1.7-rc.2.tgz", + "integrity": "sha512-RgSIGkcJnAB6stdJ73yvRT1sXbYtcrYIz9PadVrxTHvcScffaLpXGp8NUNjQgCG0n28CfnCNPdj2qHCbG4yo1g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-brand": "0.1.7-rc.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-invariants": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage": "0.1.7-rc.2", + "@deepseek-ai/dsh-storage-domain": "0.1.7-rc.2", + "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh-workspace-changes": { + "version": "0.1.7-rc.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/dsh-workspace-changes/-/dsh-workspace-changes-0.1.7-rc.2.tgz", + "integrity": "sha512-5CnBghKfz/Q3bzE8hcwc02GsYpg7BnobUJO7eIrlmCG9764ja+ij5xeuotoNegP9n19+lg7+3A3HKerz2B6m/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "~3.18.4", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "~4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2" + } + }, + "node_modules/@deepseek-ai/dsh/node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit/-/libreoffice-kit-0.1.2.tgz", + "integrity": "sha512-PM3GtAr8/nG7mY22yoYQgRTfkhzQ72v1sDME/46I/Kl7S4+yOFYC1h0hRT8JL9p9vjdEwXW9icdhUQK0QPz+YQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "fflate": "0.8.2", + "fontkit": "2.0.4", + "saxes": "6.0.0" + }, + "bin": { + "libreoffice-kit": "lib/cli.js" + }, + "engines": { + "node": ">=22.19.0" + }, + "optionalDependencies": { + "@deepseek-ai/libreoffice-kit-darwin-arm64": "0.1.1", + "@deepseek-ai/libreoffice-kit-darwin-x64": "0.1.1", + "@deepseek-ai/libreoffice-kit-wasm": "0.1.1", + "@deepseek-ai/libreoffice-kit-win32-arm64": "0.1.2", + "@deepseek-ai/libreoffice-kit-win32-x64": "0.1.2" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-darwin-arm64/-/libreoffice-kit-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-D6NBvtoNpm9pOgBXGQTdxpds1tYMeiFKhGJgnXF/SE0124ZM8j0AOXI7cZ8CErHctqIoVYP+gKWCrnQl4we41A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-darwin-x64/-/libreoffice-kit-darwin-x64-0.1.1.tgz", + "integrity": "sha512-VcAqzmzDbRySLBnpRNYSEd+fDmAtdgL1hQMjRf4sFnQuz7m1vipQ00DtlqFG/T+9uCc20bMIyiDWh8zfYObW3w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-wasm/-/libreoffice-kit-wasm-0.1.1.tgz", + "integrity": "sha512-YuKZJdDhR/0GeTZUHJsJvachJR8ZiS4lcrL+lxUF2GLRwXcMikN0zAQOA+6kD/nRI+vlHsCkX0KvHaKvfae79Q==", + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-win32-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-win32-arm64/-/libreoffice-kit-win32-arm64-0.1.2.tgz", + "integrity": "sha512-+JMKIDfLfpQEIeWWJBkKeAGJ8Niiv6SLQ1SFMh8K28eUOSaLLGPt4j7ywEWtyKCtXenD+VRlKo5gZlqDmCtNCg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit-win32-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/libreoffice-kit-win32-x64/-/libreoffice-kit-win32-x64-0.1.2.tgz", + "integrity": "sha512-EUuTMnFF404uVVZz0j2oAoHY0Xhobdg0jChUUm74sudwaqxTM9rvgUYEWbeJd95oVjIParMdsb4hLdAhZ10BIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@deepseek-ai/libreoffice-kit/node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@deepseek-ai/node-addon-system": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system/-/node-addon-system-0.1.2.tgz", + "integrity": "sha512-EFn8K+mXIXiw6s3rxX+cgp2hZTEAQdVIsURhrXnBxycSXvtQ1EQpsSVzoNKtKAQI0I0VqkEcVEjHzS/PeaGsvw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@deepseek-ai/node-addon-system-darwin-arm64": "0.1.2", + "@deepseek-ai/node-addon-system-darwin-x64": "0.1.2", + "@deepseek-ai/node-addon-system-linux-arm64": "0.1.2", + "@deepseek-ai/node-addon-system-linux-x64": "0.1.2" + } + }, + "node_modules/@deepseek-ai/node-addon-system-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-darwin-arm64/-/node-addon-system-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-IR0cx8um19mLCZaJ+H5PLblKr6Eg3PWvVo8eTQBr/SwH2nh5tM9CD9/5fHweNS9Pjt15UdFlGqnvLSd/w+O6Rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-darwin-x64/-/node-addon-system-darwin-x64-0.1.2.tgz", + "integrity": "sha512-XDbmquNapk9aT28y4EKn9lbONVr9YNs1NM/GKH1Gi5gUhjOT9wgRaTv72FJdNaVIInbPAYbPoyn7/y+MzQMNNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-linux-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-linux-arm64/-/node-addon-system-linux-arm64-0.1.2.tgz", + "integrity": "sha512-Z/DQtqgEYzjBzb2ocHGjMzx51W7xDILkJKKj89nyErr8gZMNiLs+JNL1uKzJqc3VLZB+vYCPaHGyQ3oX6EzEmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-system-linux-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@deepseek-ai/node-addon-system-linux-x64/-/node-addon-system-linux-x64-0.1.2.tgz", + "integrity": "sha512-S2aPVHvYCpNCppCFyNlooMYuTB7ucK5lvD9oXQQ42v5Z2s5AoaiCdjz9r2l+ED2rI5oS1x0cUZmKjJH2dxV0pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" } }, "node_modules/@deepseek-ai/schemastery": { - "version": "3.18.2", - "resolved": "https://registry.npmjs.org/@deepseek-ai/schemastery/-/schemastery-3.18.2.tgz", - "integrity": "sha512-njDtZsznjYxok7KLLlHOPyuv2efdWVbSflAHgztSfbMsg+CVraEoRe2DjOCgClYv3ZCSm7WXoaUkbB/+RY7tWQ==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@deepseek-ai/schemastery/-/schemastery-3.18.4.tgz", + "integrity": "sha512-SSXO6tYuyrIqKVbmOnIq0s+riUywYzouFMcnBluHF9n4KMo2G8HvEzhCYj6pj2617/glOjbJuVInJ9hfONsjkg==", "license": "MIT", "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.3", + "@deepseek-ai/cosmokit": "~1.8.5", "@standard-schema/spec": "^1.1.0" } }, "node_modules/@earendil-works/pi-ai": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.4.tgz", - "integrity": "sha512-AClAZxf5+c4RRu44NJPS6wyQy+Nmq+Mzyyrdvm4ZVMNuixelO02RZX4G4Aq1F145Yzp43wnM5S+hLlSI7ypfVw==", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.85.1.tgz", + "integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==", "license": "MIT", "dependencies": { - "@anthropic-ai/sdk": "0.91.1", + "@anthropic-ai/sdk": "0.123.0", "@aws-sdk/client-bedrock-runtime": "3.1048.0", - "@earendil-works/pi-telemetry": "^0.84.4", + "@earendil-works/pi-telemetry": "^0.85.1", "@google/genai": "1.52.0", "@smithy/node-http-handler": "4.7.3", "http-proxy-agent": "7.0.2", @@ -2249,9 +6858,9 @@ } }, "node_modules/@earendil-works/pi-telemetry": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.4.tgz", - "integrity": "sha512-8e2CuxM+ht+hedQXTZmi5JVl6/xDK9RpSDL2+MbITevKYQhMZ/z6lJOTFgox3HQyGxO8mOZEtYGVeQNaD4OzqA==", + "version": "0.85.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.85.1.tgz", + "integrity": "sha512-Bg/YN6kA7Swja/NQxka8xFdecb4E/auIEGF2G5A25EaQXhRnPj300/7/KpgsDDMYUzHTDAv4RyUxaQPJKW81Rw==", "license": "MIT", "engines": { "node": ">=22.19.0" @@ -2574,6 +7183,17 @@ "node": ">=14.14" } }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -3052,7 +7672,6 @@ "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -3307,6 +7926,16 @@ "import-meta-resolve": "^4.2.0" } }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", @@ -3353,6 +7982,26 @@ "@img/sharp-libvips-darwin-x64": "1.0.4" } }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz", + "integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-darwin-arm64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", @@ -3427,6 +8076,66 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz", + "integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz", + "integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz", + "integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-libvips-linux-x64": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", @@ -3447,6 +8156,46 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz", + "integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz", + "integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-linux-arm": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", @@ -3499,6 +8248,84 @@ "@img/sharp-libvips-linux-arm64": "1.0.4" } }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz", + "integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.3" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz", + "integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.3" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz", + "integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.3" + } + }, "node_modules/@img/sharp-linux-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", @@ -3525,6 +8352,135 @@ "@img/sharp-libvips-linux-x64": "1.0.4" } }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz", + "integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz", + "integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.3" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz", + "integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz", + "integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.4" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz", + "integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz", + "integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-win32-x64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", @@ -3558,6 +8514,13 @@ "node": ">=18.0.0" } }, + "node_modules/@joplin/turndown-plugin-gfm": { + "version": "1.0.68", + "resolved": "https://registry.npmjs.org/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.68.tgz", + "integrity": "sha512-m8DfAQNC/V7g0j5H6Jv60WhekBBjodD+zTPGrU+g2m+ux/z8ZX07KQIl6kaAmbKwfvsQhC04op52g63I78sVgg==", + "dev": true, + "license": "MIT" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -3608,6 +8571,19 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@js-temporal/polyfill": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@js-temporal/polyfill/-/polyfill-0.5.1.tgz", + "integrity": "sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "jsbi": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@koromix/koffi-darwin-arm64": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.4.tgz", @@ -3912,6 +8888,45 @@ "@chevrotain/types": "~11.1.2" } }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@modelcontextprotocol/client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/client/-/client-2.0.0.tgz", + "integrity": "sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/core": "2.0.0", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "jose": "^6.1.3", + "pkce-challenge": "^5.0.0", + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@modelcontextprotocol/client/node_modules/@modelcontextprotocol/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz", + "integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.2.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@modelcontextprotocol/core": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.1.0.tgz", @@ -4372,6 +9387,68 @@ "node": ">= 8" } }, + "node_modules/@octokit/openapi-types": { + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/openapi-webhooks-types": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-12.1.0.tgz", + "integrity": "sha512-WiuzhOsiOvb7W3Pvmhf8d2C6qaLHXrWiLBP4nJ/4kydu+wpagV5Fkz9RfQwV2afYzv3PB+3xYgp4mAdNGjDprA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/request-error": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz", + "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^18.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^29.0.1" + } + }, + "node_modules/@octokit/webhooks": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-14.2.0.tgz", + "integrity": "sha512-da6KbdNCV5sr1/txD896V+6W0iamFWrvVl8cHkBSPT+YlvmT3DwXa4jxZnQc+gnuTEqSWbBeoSZYTayXH9wXcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-webhooks-types": "12.1.0", + "@octokit/request-error": "^7.0.0", + "@octokit/webhooks-methods": "^6.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/webhooks-methods": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-6.0.0.tgz", + "integrity": "sha512-MFlzzoDJVw/GcbfzVC1RLR36QqkTLUf79vLVO3D+xn7r0QgxnFoLZgtrzxiQErAjFUOdH6fas2KeQJ1yr/qaXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, "node_modules/@opencode-ai/plugin": { "version": "1.18.29", "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.18.29.tgz", @@ -4418,6 +9495,268 @@ "cross-spawn": "7.0.6" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.9.0.tgz", + "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.220.0.tgz", + "integrity": "sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-exporter-base": "0.220.0", + "@opentelemetry/otlp-transformer": "0.220.0", + "@opentelemetry/sdk-logs": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", + "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-transformer": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", + "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/sdk-logs": "0.220.0", + "@opentelemetry/sdk-metrics": "2.9.0", + "@opentelemetry/sdk-trace": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.11.0.tgz", + "integrity": "sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.11.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.11.0.tgz", + "integrity": "sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", + "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", + "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", + "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@peculiar/asn1-schema": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz", @@ -4923,6 +10262,13 @@ "win32" ] }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.12.0.tgz", @@ -4979,12 +10325,12 @@ } }, "node_modules/@smithy/core": { - "version": "3.33.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.33.3.tgz", - "integrity": "sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.35.0.tgz", + "integrity": "sha512-zRMhfkByhT2snNdr1si24vJitU6Cr9ix2MikUfWmkAgp4jrNP0GcKSP5YvwQ+TlI8AZXER5QOGJn3JsVtSD9/A==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.17.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -5046,13 +10392,13 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.3.tgz", - "integrity": "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==", + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.4.tgz", + "integrity": "sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { @@ -5060,9 +10406,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.18.0.tgz", - "integrity": "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.19.0.tgz", + "integrity": "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5097,6 +10443,12 @@ "node": ">=14.0.0" } }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -5113,6 +10465,16 @@ "node": ">=8" } }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -6375,12 +11737,29 @@ "integrity": "sha512-9OeuBFu0/uZJPu+9AHKY6g/w0Czyb/Ut0A5t79I4ULoU4IfU5BEpPFVGQxP4zTTMdfZEYkVIRYbHBX1xWwjeSA==", "license": "MIT" }, + "node_modules/@xterm/addon-serialize": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.14.0.tgz", + "integrity": "sha512-uteyTU1EkrQa2Ux6P/uFl2fzmXI46jy5uoQMKEOM0fKTyiW7cSn0WrFenHm5vO5uEXX/GpwW/FgILvv3r0WbkA==", + "dev": true, + "license": "MIT" + }, "node_modules/@xterm/addon-webgl": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.19.0.tgz", "integrity": "sha512-b3fMOsyLVuCeNJWxolACEUED0vm7qC0cy4wRvf3oURSzDTYVQiGPhTnhWZwIHdvC48Y+oLhvYXnY4XDXPoJo6A==", "license": "MIT" }, + "node_modules/@xterm/headless": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-6.0.0.tgz", + "integrity": "sha512-5Yj1QINYCyzrZtf8OFIHi47iQtI+0qYFPHmouEfG8dHNxbZ9Tb9YGSuLcsEwj9Z+OL75GJqPyJbyoFer80a2Hw==", + "dev": true, + "license": "MIT", + "workspaces": [ + "addons/*" + ] + }, "node_modules/@xterm/xterm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz", @@ -6720,7 +12099,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -7047,6 +12425,16 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/browserslist": { "version": "4.28.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", @@ -7175,6 +12563,22 @@ "node": ">=12.0.0" } }, + "node_modules/bundle-name": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -7404,6 +12808,21 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", @@ -7465,6 +12884,16 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-response": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", @@ -7556,6 +12985,91 @@ "node": ">=0.10.0" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz", + "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "destroy": "1.2.0", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -8628,6 +14142,36 @@ "node": ">=16.0.0" } }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -8657,6 +14201,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -8712,12 +14269,23 @@ "node": ">=6" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "devOptional": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -8743,6 +14311,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/diff": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", @@ -10098,6 +15673,12 @@ "pako": "^2.1.0" } }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fast-uri": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", @@ -10178,6 +15759,22 @@ "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", "license": "MIT" }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -10335,6 +15932,24 @@ } } }, + "node_modules/fontkit": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", + "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.12", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, "node_modules/form-data": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", @@ -11333,6 +16948,16 @@ "node": ">= 14" } }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/i18next": { "version": "25.10.10", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.10.10.tgz", @@ -11623,6 +17248,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -11703,6 +17341,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-wsl": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", @@ -11793,7 +17444,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, "funding": [ { "type": "github", @@ -11812,6 +17462,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbi": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.2.tgz", + "integrity": "sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/jsdom": { "version": "30.0.1", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", @@ -13610,6 +19267,175 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, + "node_modules/node-addon-native-custom-loader": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.6.tgz", + "integrity": "sha512-QaW7d8lTcGCXrpNVyFDtID3vrpa7vFdpcY9pql2/9FGFSe7tcSnhQOKZX+1aOWq+pB1d2ZwNnKAdQI5nD9wAXA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin/-/node-addon-require-builtin-0.1.6.tgz", + "integrity": "sha512-P9ZGMDkloktirLJSggfpxsJ9jog5FItE1Omxpj50UBn3LhD6TS6/yx0jEBXsCGK3P9EtW1EpQVA1QL5gb11GaQ==", + "license": "MIT", + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "node-addon-require-builtin-darwin-arm64": "0.1.6", + "node-addon-require-builtin-darwin-x64": "0.1.6", + "node-addon-require-builtin-linux-arm64-gnu": "0.1.6", + "node-addon-require-builtin-linux-x64-gnu": "0.1.6", + "node-addon-require-builtin-win32-arm64-msvc": "0.1.6", + "node-addon-require-builtin-win32-ia32-msvc": "0.1.6", + "node-addon-require-builtin-win32-x64-msvc": "0.1.6" + } + }, + "node_modules/node-addon-require-builtin-darwin-arm64": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.6.tgz", + "integrity": "sha512-KpaAh0mDcIScoJs7gD/mjXREcENJ023/DgWW3GrlLXFVzCE6bK6wFrTFpNfnkxZZP8yWsEWOg1o5T+uQ7olgTQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-darwin-x64": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.6.tgz", + "integrity": "sha512-lh9o5rCvmkH8MZgBBmhyKzJRc1M1hJzgXLTFzB6iomRXNH9P1DKjN2nAJLmvGrdTij47Wcch1JVnlV5AG0cRCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-arm64-gnu": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.6.tgz", + "integrity": "sha512-DrQA3aS1LBn4NgrewbZkzSAWdSSRPD/fYO5AkQfvriQ/TQD3E2adB012sZ5eac6p9TAcTjUIYhk395AYVxo4Zw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-x64-gnu": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.6.tgz", + "integrity": "sha512-8wCxrFlB2Ld5DhxIm2P+nNFnQ0wjzDE5sXF68EUhLH0X+z313B07TUQFMBKCOkyhZIIBh590dBmhHCuA43No2A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-arm64-msvc": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.6.tgz", + "integrity": "sha512-NET6DiLnKrK2DHuO4NNN+zJz0CFas+RwpJlGY0d3A3A3tc5dJQqZXgw8DzLOn4cSTAQCaDq6+LbPyYX7jE2F3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-ia32-msvc": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.6.tgz", + "integrity": "sha512-oj4G51r81kJ3E2t5KknKhBNb8TmTWzc/t9x7jkBF9JeRd+1a0kr99mVJVYwJNxq9d3jpt7dgBdI8mxaomuXOEQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20 <23" + } + }, + "node_modules/node-addon-require-builtin-win32-x64-msvc": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.6.tgz", + "integrity": "sha512-ZQ+6thVzQBOFamW7s3t2YqHsw99EEPBNH1uAjvCx4QfnjFJTsu6I/H3prpN8i6cSt6gjnQtArfWc2LXN2ufcJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.6" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/node-api-version": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", @@ -15667,6 +21493,16 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -15712,6 +21548,57 @@ "protobufjs": "^7.2.4" } }, + "node_modules/open": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openai": { "version": "6.40.0", "resolved": "https://registry.npmjs.org/openai/-/openai-6.40.0.tgz", @@ -16106,6 +21993,19 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse5": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", @@ -16645,6 +22545,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-ms": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/proc-log": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", @@ -17216,6 +23132,19 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -17387,6 +23316,15 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -17400,6 +23338,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restructure": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", + "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", + "dev": true, + "license": "MIT" + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -17551,6 +23496,19 @@ "license": "MIT", "optional": true }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -17775,6 +23733,307 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/sharp": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz", + "integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.4", + "@img/sharp-darwin-x64": "0.35.4", + "@img/sharp-freebsd-wasm32": "0.35.4", + "@img/sharp-libvips-darwin-arm64": "1.3.3", + "@img/sharp-libvips-darwin-x64": "1.3.3", + "@img/sharp-libvips-linux-arm": "1.3.3", + "@img/sharp-libvips-linux-arm64": "1.3.3", + "@img/sharp-libvips-linux-ppc64": "1.3.3", + "@img/sharp-libvips-linux-riscv64": "1.3.3", + "@img/sharp-libvips-linux-s390x": "1.3.3", + "@img/sharp-libvips-linux-x64": "1.3.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.3", + "@img/sharp-libvips-linuxmusl-x64": "1.3.3", + "@img/sharp-linux-arm": "0.35.4", + "@img/sharp-linux-arm64": "0.35.4", + "@img/sharp-linux-ppc64": "0.35.4", + "@img/sharp-linux-riscv64": "0.35.4", + "@img/sharp-linux-s390x": "0.35.4", + "@img/sharp-linux-x64": "0.35.4", + "@img/sharp-linuxmusl-arm64": "0.35.4", + "@img/sharp-linuxmusl-x64": "0.35.4", + "@img/sharp-webcontainers-wasm32": "0.35.4", + "@img/sharp-win32-arm64": "0.35.4", + "@img/sharp-win32-ia32": "0.35.4", + "@img/sharp-win32-x64": "0.35.4" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/sharp/node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz", + "integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.3" + } + }, + "node_modules/sharp/node_modules/@img/sharp-darwin-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz", + "integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.3" + } + }, + "node_modules/sharp/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz", + "integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz", + "integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz", + "integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz", + "integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz", + "integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/@img/sharp-linux-arm": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz", + "integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.3" + } + }, + "node_modules/sharp/node_modules/@img/sharp-linux-arm64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz", + "integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.3" + } + }, + "node_modules/sharp/node_modules/@img/sharp-linux-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz", + "integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.3" + } + }, + "node_modules/sharp/node_modules/@img/sharp-win32-x64": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz", + "integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -17802,6 +24061,105 @@ "integrity": "sha512-KnfQkA+LxbptrWX1gd7upGDyFkLslJVlOudUWPkwveHwYIXo5Qq97Tx02NF5aE0G3cgKpHBh2z+CR+s6ywZPPQ==", "license": "Apache-2.0" }, + "node_modules/sherpa-onnx-darwin-arm64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-darwin-arm64/-/sherpa-onnx-darwin-arm64-1.13.8.tgz", + "integrity": "sha512-FPNgJMgnWVl/KhRTIhG3KL3A4Om63Rn4YKXc9/uHY7SzLcvqLJLc/h7UBWJwduXvv7K18t5NpxHR6XgXn4sjWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sherpa-onnx-darwin-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-darwin-x64/-/sherpa-onnx-darwin-x64-1.13.8.tgz", + "integrity": "sha512-7BLRpjM6w4f9W46/nmkmq8lEKUayhebvcpslCVQ+6QN2uReYlZEMDZlSpXMjme+hUFrPfRz8P3UNq8ep/4d19g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sherpa-onnx-linux-arm64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-linux-arm64/-/sherpa-onnx-linux-arm64-1.13.8.tgz", + "integrity": "sha512-Tlg7a70b/Wge3OF8IgTHF9jhSVCsLyKQKhwc4BsJ5A+dL/SrFtGBjzuHp4XeLhiiOT7afCxX5PdSn/D4c8Lnuw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sherpa-onnx-linux-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-linux-x64/-/sherpa-onnx-linux-x64-1.13.8.tgz", + "integrity": "sha512-6plnhjagsSeTntCgnlag86hWbs/uZE9Crms1LgOb68/1nKsIQjMd+WG519m+aPwT6TrsBOiEMzrx41t8sL5L5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sherpa-onnx-node": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-node/-/sherpa-onnx-node-1.13.8.tgz", + "integrity": "sha512-MsDMBdhLFTZ1GwvcGSSQhnS7g/EA8OMH6IYysCVUOM7j8Icty9KRc0E6YT1A5fWBsZwRfKOeh88QC95aRvS8ag==", + "dev": true, + "license": "Apache-2.0", + "optionalDependencies": { + "sherpa-onnx-darwin-arm64": "^1.13.8", + "sherpa-onnx-darwin-x64": "^1.13.8", + "sherpa-onnx-linux-arm64": "^1.13.8", + "sherpa-onnx-linux-x64": "^1.13.8", + "sherpa-onnx-win-ia32": "^1.13.8", + "sherpa-onnx-win-x64": "^1.13.8" + } + }, + "node_modules/sherpa-onnx-win-ia32": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-win-ia32/-/sherpa-onnx-win-ia32-1.13.8.tgz", + "integrity": "sha512-H0Ojln9hfvM+pxWqW0cnjB/XK8/JPq4/k0IWu2JpY5Z458M3zv+XC3Hu+wmot3AoH/K1Bgt23n/tTKtPV9x8qg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/sherpa-onnx-win-x64": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/sherpa-onnx-win-x64/-/sherpa-onnx-win-x64-1.13.8.tgz", + "integrity": "sha512-oZF1c9VPOKtMwn83Bboc5XSWL+76BRoyB3eUuVnCknBKxwSULZU2Foia9VHWzU+n4I12rPsP6z6H9Rp1hD9o8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/side-channel": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", @@ -18067,6 +24425,16 @@ "node": ">=0.1.14" } }, + "node_modules/standardwebhooks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.1.1.tgz", + "integrity": "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/stat-mode": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", @@ -18395,6 +24763,13 @@ "semver": "bin/semver" } }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "dev": true, + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -18636,6 +25011,20 @@ "node": "*" } }, + "node_modules/turndown": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz", + "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + }, + "engines": { + "node": ">=18", + "npm": ">=9" + } + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -18784,6 +25173,35 @@ "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", "license": "MIT" }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true, + "license": "MIT" + }, "node_modules/unicorn-magic": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", @@ -19892,6 +26310,22 @@ "node": ">= 8" } }, + "node_modules/which-command": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/which-command/-/which-command-0.1.0.tgz", + "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==", + "dev": true, + "license": "MIT", + "bin": { + "which-command": "cli.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/which-command?sponsor=1" + } + }, "node_modules/which-module": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", @@ -20127,6 +26561,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", diff --git a/package.json b/package.json index f45cd889..f4e143cc 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,10 @@ "!node_modules/npm{,/**/*}" ], "extraResources": [ + { + "from": ".runtime-resources/dsh-${arch}", + "to": "runtimes/dsh" + }, { "from": "resources/skills", "to": "skills", @@ -297,30 +301,30 @@ }, "dependencies": { "@agentclientprotocol/sdk": "0.25.1", - "@deepseek-ai/cordis": "4.0.2", - "@deepseek-ai/dsh-agent": "0.1.2-rc.1", - "@deepseek-ai/dsh-agent-loop": "0.1.2-rc.1", - "@deepseek-ai/dsh-bash-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-credentials": "0.1.2-rc.1", - "@deepseek-ai/dsh-fs-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-llm": "0.1.2-rc.1", - "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1", - "@deepseek-ai/dsh-pwsh-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox": "0.1.2-rc.1", - "@deepseek-ai/dsh-sandbox-policy": "0.1.2-rc.1", - "@deepseek-ai/dsh-session": "0.1.2-rc.1", - "@deepseek-ai/dsh-session-projection": "0.1.2-rc.1", - "@deepseek-ai/dsh-shell-env": "0.1.2-rc.1", - "@deepseek-ai/dsh-skill": "0.1.2-rc.1", - "@deepseek-ai/dsh-subprocess-local": "0.1.2-rc.1", - "@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1", - "@deepseek-ai/dsh-token-meter": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-bash": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-fs": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-pwsh": "0.1.2-rc.1", - "@deepseek-ai/dsh-tool-skill": "0.1.2-rc.1", - "@deepseek-ai/dsh-tools": "0.1.2-rc.1", - "@deepseek-ai/dsh-user-approval": "0.1.2-rc.1", + "@deepseek-ai/cordis": "4.0.4", + "@deepseek-ai/dsh-agent": "0.1.7-rc.2", + "@deepseek-ai/dsh-agent-loop": "0.1.7-rc.2", + "@deepseek-ai/dsh-bash-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-credentials": "0.1.7-rc.2", + "@deepseek-ai/dsh-fs-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm": "0.1.7-rc.2", + "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.2", + "@deepseek-ai/dsh-pwsh-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox": "0.1.7-rc.2", + "@deepseek-ai/dsh-sandbox-policy": "0.1.7-rc.2", + "@deepseek-ai/dsh-session": "0.1.7-rc.2", + "@deepseek-ai/dsh-session-projection": "0.1.7-rc.2", + "@deepseek-ai/dsh-shell-env": "0.1.7-rc.2", + "@deepseek-ai/dsh-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-subprocess-local": "0.1.7-rc.2", + "@deepseek-ai/dsh-system-prompt": "0.1.7-rc.2", + "@deepseek-ai/dsh-token-meter": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-bash": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-fs": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-pwsh": "0.1.7-rc.2", + "@deepseek-ai/dsh-tool-skill": "0.1.7-rc.2", + "@deepseek-ai/dsh-tools": "0.1.7-rc.2", + "@deepseek-ai/dsh-user-approval": "0.1.7-rc.2", "@huggingface/tokenizers": "^0.1.3", "@modelcontextprotocol/sdk": "^1.30.0", "@napi-rs/canvas": "1.0.3", @@ -369,6 +373,7 @@ "@antv/g6": "^5.1.1", "@bitbonsai/mcpvault": "0.16.0", "@continuedev/cli": "1.5.47", + "@deepseek-ai/dsh": "0.1.7-rc.2", "@eslint/js": "^10.0.1", "@fontsource-variable/inter": "^5.3.0", "@fontsource-variable/noto-sans-sc": "^5.3.0", @@ -408,7 +413,7 @@ "@koromix/koffi-win32-x64": "3.1.4" }, "allowScripts": { - "@deepseek-ai/dsh-subprocess-local@0.1.2-rc.1": true, + "@deepseek-ai/dsh-subprocess-local@0.1.7-rc.2": true, "@google/genai@1.52.0": true, "cpu-features@0.0.10": true, "electron-winstaller@5.4.0": true, diff --git a/src/main/agent/bundled-runtimes.ts b/src/main/agent/bundled-runtimes.ts index 4e2d04b3..86dc29c9 100644 --- a/src/main/agent/bundled-runtimes.ts +++ b/src/main/agent/bundled-runtimes.ts @@ -9,7 +9,7 @@ export type BundledRuntimePaths = { } export const bundledContinueVersion = '1.5.47' -export const bundledDeepSeekHarnessVersion = '0.1.2-rc.1' +export const bundledDeepSeekHarnessVersion = '0.1.7-rc.2' export function resolveBundledRuntimePaths(input: { appPath: string diff --git a/src/main/agent/deepseek-harness-acp-e2e.test.ts b/src/main/agent/deepseek-harness-acp-e2e.test.ts index 9fae535d..ecf2c4bd 100644 --- a/src/main/agent/deepseek-harness-acp-e2e.test.ts +++ b/src/main/agent/deepseek-harness-acp-e2e.test.ts @@ -126,19 +126,13 @@ function toolResultText( callId: string ): string | undefined { for (const message of options.messages) { - for (const block of message.content) { - if ( - block.type !== 'tool-result' || - block.toolCallId !== callId - ) { - continue - } - return block.content + if (message.role === 'tool' && message.toolCallId === callId) { + return message.content .filter( ( content ): content is Extract< - (typeof block.content)[number], + (typeof message.content)[number], { type: 'text' } > => content.type === 'text' ) @@ -154,7 +148,7 @@ function latestUserText(options: GenerateOptions): string { .filter( (message) => message.role === 'user' && - message.source.kind === 'user' + message.source?.kind === 'user' ) .flatMap((message) => message.content @@ -396,7 +390,7 @@ function createInProcessLaunch( model: options.model, supportsImageInput: options.supportsImageInput, requestHeaders: options.requestHeaders, - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: options.credentialRefs, skillPackages: options.skillPackages, extensionPackages: options.extensionPackages, @@ -838,9 +832,14 @@ describe('DeepSeek Harness real ACP control-plane E2E', () => { ) expect(observedRequest?.maxTokens).toBeUndefined() - expect(observedRequest?.system).toContain( - 'act through the available tools' - ) + expect( + observedRequest?.messages + .filter((message) => message.role === 'system') + .flatMap((message) => message.content) + .filter((block) => block.type === 'text') + .map((block) => block.text) + .join('\n') + ).toContain('act through the available tools') expect(reasoning).toHaveLength(8) expect( reasoning.map((event) => event.delta).join('') diff --git a/src/main/agent/deepseek-harness-runtime.test.ts b/src/main/agent/deepseek-harness-runtime.test.ts index 83292293..af27d934 100644 --- a/src/main/agent/deepseek-harness-runtime.test.ts +++ b/src/main/agent/deepseek-harness-runtime.test.ts @@ -159,7 +159,7 @@ function setup( if (method === 'goodbuddy/handshake') { return { controlProtocolVersion: 1, - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', acpProtocolVersion: 1, supports: { cancellation: true, diff --git a/src/main/agent/dsh-extension-marketplace.e2e.test.ts b/src/main/agent/dsh-extension-marketplace.e2e.test.ts index 669bb7a3..7abe7a1d 100644 --- a/src/main/agent/dsh-extension-marketplace.e2e.test.ts +++ b/src/main/agent/dsh-extension-marketplace.e2e.test.ts @@ -95,7 +95,7 @@ describe.skipIf(!enabled)('DSH marketplace live E2E', () => { api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [], extensionPackages: extensions, diff --git a/src/main/agent/goodbuddy-harness-control-plane.test.ts b/src/main/agent/goodbuddy-harness-control-plane.test.ts index 2b560c8e..bf0bbb01 100644 --- a/src/main/agent/goodbuddy-harness-control-plane.test.ts +++ b/src/main/agent/goodbuddy-harness-control-plane.test.ts @@ -22,7 +22,7 @@ function controlPlane() { provider: 'goodbuddy', model: 'deepseek-test', workspace: resolve('workspace'), - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', execution: { mode: 'host' }, credentialRefs: ['GOODBUDDY_API_KEY'], skills: [] @@ -75,7 +75,7 @@ function stubAgentContext() { provider: 'goodbuddy', model: 'deepseek-test', workspace: resolve('workspace'), - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', execution: { mode: 'host' }, credentialRefs: ['GOODBUDDY_API_KEY'], skills: [], @@ -169,7 +169,7 @@ describe('GoodBuddy Harness internal control plane', () => { model: 'vision-test', supportsImageInput: true, workspace: resolve('workspace'), - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', execution: { mode: 'host' }, credentialRefs: ['GOODBUDDY_API_KEY'], skills: [] @@ -337,37 +337,33 @@ describe('GoodBuddy Harness internal control plane', () => { it('delivers more than 4 MiB of cumulative output without cancelling', async () => { const { listeners, extNotification, handle, internals } = stubAgentContext() - const sessionEvent = listeners.get('session/event')! + const assistantStream = listeners.get('agent/assistant-stream')! for (let index = 0; index < 65; index++) { - sessionEvent( - handle.agent.session, - { - type: 'assistant/chunk', - data: { - chunk: { - type: 'text-delta', - text: 'x'.repeat(65_536) + assistantStream({ + agent: handle.agent, + frame: { + type: 'chunk', + chunk: { + type: 'text-delta', + text: 'x'.repeat(65_536) + } + } + }) + assistantStream({ + agent: handle.agent, + frame: { + type: 'chunk', + chunk: { + type: 'usage', + usage: { + inputTokens: 1, + outputTokens: 1, + cacheReadTokens: 0, + cacheWriteTokens: 0 } } } - ) - sessionEvent( - handle.agent.session, - { - type: 'assistant/chunk', - data: { - chunk: { - type: 'usage', - usage: { - inputTokens: 1, - outputTokens: 1, - cacheReadTokens: 0, - cacheWriteTokens: 0 - } - } - } - } - ) + }) await internals.sessions.get('session-output')!.inflight.eventTail } diff --git a/src/main/agent/goodbuddy-harness-control-plane.ts b/src/main/agent/goodbuddy-harness-control-plane.ts index adb42e1f..9b327982 100644 --- a/src/main/agent/goodbuddy-harness-control-plane.ts +++ b/src/main/agent/goodbuddy-harness-control-plane.ts @@ -730,6 +730,26 @@ export class GoodBuddyHarnessControlPlane { } return next() }) + this.ctx.on('agent/assistant-stream', ({ agent, frame }) => { + const record = this.sessions.get(agent.session.id) + if ( + record?.handle.agent !== agent || + !record.inflight || + frame.type !== 'chunk' + ) { + return + } + const chunk = frame.chunk + if (chunk.type === 'text-delta' || chunk.type === 'reasoning-delta') { + this.queueDelta( + agent.session.id, + chunk.type === 'text-delta' ? 'text' : 'reasoning', + chunk.text + ) + } else if (chunk.type === 'usage') { + this.queueUsage(agent.session.id, chunk.usage) + } + }) this.ctx.on( 'session/event', (session, event: SessionEvent) => { @@ -741,23 +761,7 @@ export class GoodBuddyHarnessControlPlane { if (!inflight) { return } - if (event.type === 'assistant/chunk') { - const chunk = event.data.chunk - if ( - chunk.type === 'text-delta' || - chunk.type === 'reasoning-delta' - ) { - this.queueDelta( - session.header.id, - chunk.type === 'text-delta' - ? 'text' - : 'reasoning', - chunk.text - ) - } else if (chunk.type === 'usage') { - this.queueUsage(session.header.id, chunk.usage) - } - } else if (event.type === 'tool/call') { + if (event.type === 'tool/call') { this.queueEvent(session.header.id, { type: 'tool', callId: event.data.callId, @@ -769,15 +773,13 @@ export class GoodBuddyHarnessControlPlane { ) }) } else if (event.type === 'tool/result') { - const toolResult = event.data.message.content.find( - (content) => content.type === 'tool-result' - ) + const toolResult = event.data.message this.queueEvent(session.header.id, { type: 'tool', - callId: toolResult?.toolCallId ?? 'unknown-tool-call', + callId: toolResult.toolCallId, name: 'tool', state: - event.data.error || toolResult?.isError === true + event.data.error || toolResult.isError === true ? 'failed' : 'completed', output: boundedJson(event.data.message.content) diff --git a/src/main/agent/native-client-coordinator.test.ts b/src/main/agent/native-client-coordinator.test.ts new file mode 100644 index 00000000..73229b69 --- /dev/null +++ b/src/main/agent/native-client-coordinator.test.ts @@ -0,0 +1,119 @@ +// @vitest-environment node +import { afterEach, describe, expect, it, vi } from 'vitest' +import { NativeClientCoordinator } from './native-client-coordinator' +import { NativeDshWebClientService, type NativeDshWebClientOptions } from './native-dsh-web-client' +import type { LocalToolRuntimeSelection } from '../../shared/local-tool-environment-contracts' + +const coordinators: NativeClientCoordinator[] = [] +afterEach(async () => { + await Promise.all(coordinators.splice(0).map(coordinator => coordinator.dispose())) + vi.restoreAllMocks() +}) + +function fixture() { + const profile = { id: 'selected', name: 'Selected', protocol: 'openai-chat-completions', + authentication: 'api-key', apiKey: 'secret', baseUrl: 'https://example.com/v1', modelName: 'selected-model' } + const settings = { provider: 'deepseek-harness', modelProfiles: [profile], deepseekHarnessModelProfile: profile } + const conversation = { projectId: 'project', knowledgeLibraryIds: ['library'], workMode: 'ask' } + const project = { id: 'project', runtimeSelection: { provider: 'deepseek-harness', profileId: profile.id } } + const application = { magicNotesEnabled: true, localToolEnvironment: { node: { source: 'managed' } as LocalToolRuntimeSelection } } + const gateway = { start: vi.fn(), dispose: vi.fn(), grant: vi.fn(() => 'builtin-token'), + grantCustomMcp: vi.fn(() => 'custom-token'), getEndpoint: () => 'http://127.0.0.1:1234/mcp', + getAvailableToolNames: vi.fn(() => ['knowledge_search', 'obsidian_read_note']) } + const handles = new Map() + const start = vi.spyOn(NativeDshWebClientService.prototype, 'start').mockImplementation(async () => { + const handle = { id: `service-${handles.size}`, url: 'http://127.0.0.1:1234/?token=private' } + handles.set(handle.id, handle) + return handle + }) + vi.spyOn(NativeDshWebClientService.prototype, 'get').mockImplementation(async id => handles.get(id) ?? null) + const stop = vi.spyOn(NativeDshWebClientService.prototype, 'stop').mockImplementation(async id => { handles.delete(id) }) + const openExternal = vi.fn(async () => {}) + const coordinator = new NativeClientCoordinator({ + database: { getConversation: () => conversation, getProject: () => project }, + settingsStore: { getResolvedSettings: async () => settings }, + applicationSettingsStore: { get: async () => application }, + capabilities: { getRuntimeSkillContext: async () => ({ packages: [{ directory: '/skills/test', id: 'test', digest: 'one' }] }), + getResolvedMcpServers: async () => [{ id: 'custom' }], getEnabledBuiltinMcpServerIds: async () => ['knowledge-base', 'obsidian'], + getObsidianSettings: async () => ({}) }, + executionSpaceResolver: { resolveProject: () => ({ kind: 'local', rootPath: '/workspace', cacheIdentity: '/workspace' }) }, + terminalManager: { closeOwner: vi.fn() }, localEnvironment: { launchEnvironmentProvider: () => process.env }, + rootDirectory: '/clients', createGateway: () => gateway, openExternal + } as unknown as ConstructorParameters[0]) + coordinators.push(coordinator) + return { coordinator, profile, conversation, application, gateway, start, stop, openExternal } +} + +describe('native client coordinator', () => { + it('retains a ready service and its gateway after browser failure, then reopens and stops it', async () => { + const { coordinator, gateway, start, stop, openExternal } = fixture() + openExternal.mockRejectedValueOnce(new Error('Browser unavailable')) + await expect(coordinator.open(1, 'conversation')).rejects.toThrow('Browser unavailable') + expect(await coordinator.get(1, 'conversation')).toEqual({ serviceId: 'service-0' }) + expect(gateway.dispose).not.toHaveBeenCalled() + expect(stop).not.toHaveBeenCalled() + await expect(coordinator.open(1, 'conversation')).resolves.toEqual({ kind: 'browser', serviceId: 'service-0' }) + expect(start).toHaveBeenCalledOnce() + await coordinator.stop(2, 'service-0') + expect(stop).not.toHaveBeenCalled() + await coordinator.stop(1, 'service-0') + expect(gateway.dispose).toHaveBeenCalledOnce() + expect(await coordinator.get(1, 'conversation')).toBeNull() + }) + + it('matches get and reuse against current credentials, mode and Node selection', async () => { + const { coordinator, profile, conversation, application, start } = fixture() + await Promise.all([coordinator.open(1, 'conversation'), coordinator.open(1, 'conversation')]) + expect(start).toHaveBeenCalledOnce() + profile.apiKey = 'rotated' + expect(await coordinator.get(1, 'conversation')).toBeNull() + await coordinator.open(1, 'conversation') + expect(start.mock.calls[1]![0].profile.apiKey).toBe('rotated') + expect(start.mock.calls[1]![0].configurationKey).not.toBe(start.mock.calls[0]![0].configurationKey) + conversation.workMode = 'execute' + expect(await coordinator.get(1, 'conversation')).toBeNull() + conversation.workMode = 'ask' + expect(await coordinator.get(1, 'conversation')).toEqual({ serviceId: 'service-1' }) + application.localToolEnvironment.node = { source: 'custom', executablePath: '/new/node' } + expect(await coordinator.get(1, 'conversation')).toBeNull() + expect(await coordinator.get(2, 'conversation')).toBeNull() + }) + + it('maps gateway read grants in Ask and custom MCP only in Execute', async () => { + const { coordinator, gateway, start, conversation } = fixture() + await coordinator.open(1, 'conversation') + expect(gateway.grantCustomMcp).not.toHaveBeenCalled() + expect(start.mock.calls[0]![0]).toMatchObject({ skillDirectories: ['/skills/test'], mcpServers: [ + { serverName: 'goodbuddy-0', readOnlyTools: ['knowledge_search', 'obsidian_read_note'] } + ] }) + conversation.workMode = 'execute' + await coordinator.open(1, 'conversation') + expect(gateway.grantCustomMcp).toHaveBeenCalledOnce() + expect(start.mock.calls[1]![0].mcpServers).toHaveLength(2) + await coordinator.closeOwner(1) + await expect(coordinator.open(1, 'conversation')).rejects.toThrow('closed') + }) + + it('releases the gateway after startup failure and allows retry', async () => { + const { coordinator, start, gateway } = fixture() + start.mockRejectedValueOnce(new Error('DS startup failed')) + await expect(coordinator.open(1, 'conversation')).rejects.toThrow('DS startup failed') + expect(gateway.dispose).toHaveBeenCalledOnce() + await expect(coordinator.open(1, 'conversation')).resolves.toMatchObject({ kind: 'browser' }) + }) + + it('uses the current custom Node selection without installing a separate runtime', async () => { + const { coordinator, application, start } = fixture() + const resolved: string[] = [] + start.mockImplementation(async function (this: NativeDshWebClientService) { + const options = (this as unknown as { options: NativeDshWebClientOptions }).options + resolved.push((await options.resolveLaunchEnvironment()).nodeExecutablePath) + return { id: `custom-${resolved.length}`, url: 'http://127.0.0.1:1234/' } + }) + application.localToolEnvironment.node = { source: 'custom', executablePath: '/selected/node' } + await coordinator.open(1, 'conversation') + application.localToolEnvironment.node = { source: 'custom', executablePath: '/changed/node' } + await coordinator.open(1, 'conversation') + expect(resolved).toEqual(['/selected/node', '/changed/node']) + }) +}) diff --git a/src/main/agent/native-client-coordinator.ts b/src/main/agent/native-client-coordinator.ts new file mode 100644 index 00000000..e68a075b --- /dev/null +++ b/src/main/agent/native-client-coordinator.ts @@ -0,0 +1,229 @@ +import { execFile } from 'node:child_process' +import { createHash, randomUUID } from 'node:crypto' +import { mkdir, stat } from 'node:fs/promises' +import { join } from 'node:path' +import { promisify } from 'node:util' +import { normalizeInteractiveWorkMode } from '../../shared/assistant-contracts' +import { getDefaultRuntimeSelection } from '../../shared/runtime-selection-contracts' +import type { RuntimeNativeClientResult } from '../../shared/runtime-native-client-contracts' +import type { AssistantDatabase } from '../assistant/assistant-database' +import type { ApplicationSettingsStore } from '../application-settings-store' +import type { CapabilityService } from '../capabilities/capability-service' +import type { ExecutionSpaceResolver } from '../execution-space/execution-space-resolver' +import type { LocalToolEnvironmentService } from '../local-tool-environment/local-tool-environment-service' +import type { RuntimeSettingsStore } from '../runtime-settings-store' +import type { TerminalSessionManager } from '../terminal/terminal-session-manager' +import type { BundledRuntimePaths } from './bundled-runtimes' +import type { KnowledgeMcpGateway } from './knowledge-mcp-gateway' +import { NativeDshWebClientService } from './native-dsh-web-client' +import { NativeTerminalClient } from './native-terminal-client' +import { applyRuntimeSelection } from './runtime-selection' + +type Options = { + database: AssistantDatabase + settingsStore: RuntimeSettingsStore + applicationSettingsStore: ApplicationSettingsStore + capabilities: CapabilityService + executionSpaceResolver: ExecutionSpaceResolver + terminalManager: TerminalSessionManager + localEnvironment: LocalToolEnvironmentService + bundledRuntimePaths: BundledRuntimePaths + rootDirectory: string + managedNodeDirectory: string + npmCliPath: string + resourcesPath?: string + createGateway: () => KnowledgeMcpGateway + openExternal: (url: string) => Promise +} + +export class NativeClientCoordinator { + private readonly browser: NativeDshWebClientService + private readonly services = new Map Promise }>() + private readonly pending = new Map>() + private readonly closedOwners = new Set() + private nodePreparation?: Promise + private readonly controller = new AbortController() + + constructor(private readonly options: Options) { + this.browser = new NativeDshWebClientService({ + rootDirectory: join(options.rootDirectory, 'dsh'), + resourcesPath: options.resourcesPath, + resolveLaunchEnvironment: async () => ({ + nodeExecutablePath: await this.prepareNode(), + environment: options.localEnvironment.launchEnvironmentProvider() + }) + }) + } + + private async prepareNode(): Promise { + const selection = (await this.options.applicationSettingsStore.get()).localToolEnvironment.node + if (selection.source === 'custom') return selection.executablePath + this.nodePreparation ??= (async () => { + const directory = this.options.managedNodeDirectory + const packageName = `node-${process.platform === 'win32' ? 'win' : process.platform}-${process.arch}` + const executable = join(directory, 'node_modules', packageName, 'bin', process.platform === 'win32' ? 'node.exe' : 'node') + if (!(await stat(executable).catch(() => undefined))?.isFile()) { + await mkdir(directory, { recursive: true }) + await promisify(execFile)(process.execPath, [this.options.npmCliPath, 'install', '--prefix', directory, + '--no-save', '--no-package-lock', '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-offline', `${packageName}@22.22.0`], { + env: { ...this.options.localEnvironment.launchEnvironmentProvider(), ELECTRON_RUN_AS_NODE: '1' }, + cwd: directory, windowsHide: true, timeout: 180_000, signal: this.controller.signal, maxBuffer: 1024 * 1024 + }) + } + const { stdout } = await promisify(execFile)(executable, ['-p', 'JSON.stringify({node:process.versions.node,electron:process.versions.electron})'], { + env: { ...this.options.localEnvironment.launchEnvironmentProvider() }, + windowsHide: true, timeout: 5_000, signal: this.controller.signal + }) + const runtime = JSON.parse(stdout.trim()) as { node?: string; electron?: string } + if (runtime.node !== '22.22.0' || runtime.electron) throw new Error('Native clients require managed standard Node 22.22.0') + return executable + })().catch(error => { this.nodePreparation = undefined; throw error }) + return this.nodePreparation + } + + private async resolve(conversationId: string) { + const conversation = this.options.database.getConversation(conversationId) + if (!conversation.projectId) throw new Error('Native clients require a saved project conversation') + const project = this.options.database.getProject(conversation.projectId) + const settings = await this.options.settingsStore.getResolvedSettings() + const saved = conversation.runtimeSelection ?? project.runtimeSelection + const selected = applyRuntimeSelection(settings, saved && saved.provider !== 'auto' ? saved : getDefaultRuntimeSelection(settings)) + const space = this.options.executionSpaceResolver.resolveProject(project) + const workMode = normalizeInteractiveWorkMode(conversation.workMode ?? project.defaultWorkMode) + const [skills, mcpServers, builtin, application, obsidian] = await Promise.all([ + this.options.capabilities.getRuntimeSkillContext(selected.target), + this.options.capabilities.getResolvedMcpServers(selected.target), + this.options.capabilities.getEnabledBuiltinMcpServerIds(selected.target), + this.options.applicationSettingsStore.get(), + this.options.capabilities.getObsidianSettings() + ]) + const key = createHash('sha256').update(JSON.stringify({ projectId: project.id, space: space.cacheIdentity, + target: selected.target, profile: selected.target === 'deepseek-harness' ? selected.settings.deepseekHarnessModelProfile + : selected.target === 'continue' ? selected.settings.continueModelProfile : selected.settings.opencodeModelProfile, + workMode, skills, mcpServers, builtin, + libraries: conversation.knowledgeLibraryIds, magicNotes: application.magicNotesEnabled, obsidian, + node: application.localToolEnvironment.node, + binary: selected.target === 'continue' ? selected.settings.continueBinaryPath + : selected.target === 'opencode' ? selected.settings.opencodeBinaryPath : undefined, + config: selected.target === 'continue' ? selected.settings.continueConfigPath : undefined })).digest('hex') + return { conversation, project, selected, space, workMode, skills, mcpServers, builtin, application, obsidian, key } + } + + async get(ownerId: number, conversationId: string): Promise<{ serviceId: string } | null> { + const context = await this.resolve(conversationId) + const entry = this.services.get(`${ownerId}:${context.key}`) + if (!entry) return null + if (await this.browser.get(entry.id)) return { serviceId: entry.id } + await entry.dispose() + this.services.delete(`${ownerId}:${context.key}`) + return null + } + + async open(ownerId: number, conversationId: string): Promise { + this.assertOwner(ownerId) + const context = await this.resolve(conversationId) + this.assertOwner(ownerId) + const key = `${ownerId}:${context.key}` + const pending = this.pending.get(key) + if (pending) return pending + const operation = this.launch(ownerId, key, context).finally(() => this.pending.delete(key)) + this.pending.set(key, operation) + return operation + } + + private assertOwner(ownerId: number): void { + this.controller.signal.throwIfAborted() + if (this.closedOwners.has(ownerId)) throw new Error('Native client window is closed') + } + + private async launch(ownerId: number, key: string, context: Awaited>): Promise { + const { project, selected, space, workMode, skills, mcpServers, builtin, application, conversation, obsidian } = context + if (selected.target === 'model') throw new Error('This runtime has no native client') + if (space.kind !== 'local') throw new Error('Native client requires a local execution space') + const existing = this.services.get(key) + if (existing) { + const handle = await this.browser.get(existing.id) + if (handle) { + this.assertOwner(ownerId) + await this.options.openExternal(handle.url) + return { kind: 'browser', serviceId: handle.id } + } + await existing.dispose() + this.services.delete(key) + } + const gateway = this.options.createGateway() + const controller = new AbortController() + const signal = AbortSignal.any([controller.signal, this.controller.signal]) + const dispose = async (): Promise => { controller.abort(); await gateway.dispose() } + try { + await gateway.start() + const requestId = randomUUID() + const access = workMode === 'execute' ? 'write' : 'read' + const token = gateway.grant(requestId, builtin.includes('knowledge-base') ? conversation.knowledgeLibraryIds ?? [] : [], signal, + builtin.includes('magic-notes') && application.magicNotesEnabled ? access : 'none', + builtin.includes('goodbuddy-config') ? { access, workspacePath: space.rootPath } : undefined, + undefined, undefined, undefined, builtin.includes('obsidian') ? { settings: obsidian, access } : undefined) + const customToken = workMode === 'execute' ? gateway.grantCustomMcp(requestId, mcpServers, signal) : undefined + const endpoints = [token, customToken].flatMap((value, index) => value ? [{ name: `goodbuddy-${index}`, url: gateway.getEndpoint()!, headers: { Authorization: `Bearer ${value}` } }] : []) + if (selected.target === 'deepseek-harness') { + const profile = selected.settings.deepseekHarnessModelProfile + if (!profile) throw new Error('DS Web requires a text model connection') + const readOnlyTools = token && workMode === 'ask' ? gateway.getAvailableToolNames(token) : [] + const handle = await this.browser.start({ projectId: project.id, ownerId, configurationKey: context.key, workspace: space.rootPath, profile, workMode, + skillDirectories: skills.packages.map(skill => skill.directory), + mcpServers: endpoints.map(endpoint => ({ serverName: endpoint.name, transport: 'streamable-http', url: endpoint.url, headers: endpoint.headers, + readOnlyTools: endpoint.name === 'goodbuddy-0' ? readOnlyTools : [] })) }) + this.services.set(key, { ownerId, id: handle.id, dispose }) + this.assertOwner(ownerId) + await this.options.openExternal(handle.url) + return { kind: 'browser', serviceId: handle.id } + } + const nodeExecutable = selected.target === 'continue' ? await this.prepareNode() : undefined + this.assertOwner(ownerId) + const terminal = await new NativeTerminalClient({ + rootDirectory: join(this.options.rootDirectory, 'terminal'), bundledRuntimePaths: this.options.bundledRuntimePaths, + nodeExecutable, launchEnvironmentProvider: this.options.localEnvironment.launchEnvironmentProvider, + terminalManager: { create: async (owner, input, launch) => { + if (!launch) throw new Error('Native terminal launch is missing') + return this.options.terminalManager.create(owner, input, { ...launch, dispose: async () => { + try { await launch.dispose() } finally { await dispose() } + } }) + } } + }).open(ownerId, { projectId: project.id, projectName: project.name, directory: space.rootPath, + runtime: selected.target, settings: selected.settings, workMode, skillPackages: skills.packages, mcpServers: endpoints }) + if (this.closedOwners.has(ownerId) || this.controller.signal.aborted) { + await this.options.terminalManager.closeOwner(ownerId) + throw new Error('Native client window is closed') + } + return { kind: 'terminal', terminal } + } catch (error) { + // Once ready, the service owns its gateway even if the OS browser cannot open. + if (!this.services.has(key)) await dispose() + throw error + } + } + + async stop(ownerId: number, serviceId: string): Promise { + for (const [key, entry] of this.services) { + if (entry.id !== serviceId || entry.ownerId !== ownerId) continue + await this.browser.stop(entry.id) + await entry.dispose() + this.services.delete(key) + } + } + + async closeOwner(ownerId: number): Promise { + this.closedOwners.add(ownerId) + await Promise.allSettled([...this.pending.entries()].filter(([key]) => key.startsWith(`${ownerId}:`)).map(([, operation]) => operation)) + await Promise.all([...this.services.values()].filter(entry => entry.ownerId === ownerId).map(entry => this.stop(ownerId, entry.id))) + await this.options.terminalManager.closeOwner(ownerId) + } + + async dispose(): Promise { + this.controller.abort() + await this.browser.dispose() + await Promise.allSettled(this.pending.values()) + await Promise.all([...this.services.values()].map(entry => entry.dispose())) + this.services.clear() + } +} diff --git a/src/main/agent/native-dsh-web-client.test.ts b/src/main/agent/native-dsh-web-client.test.ts new file mode 100644 index 00000000..81abad6e --- /dev/null +++ b/src/main/agent/native-dsh-web-client.test.ts @@ -0,0 +1,226 @@ +// @vitest-environment node +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { pathToFileURL } from 'node:url' +import { createServer } from 'node:http' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { NativeDshWebClientService, resolveNativeDshCli, type NativeDshWebRequest } from './native-dsh-web-client' +import { nativeDshMcpToolName, nativeDshWebPolicySource } from './native-dsh-web-policy' + +const roots: string[] = [] +const services: NativeDshWebClientService[] = [] +afterEach(async () => { + await Promise.all(services.splice(0).map(service => service.dispose())) + await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))) +}) +async function temporary(): Promise { + const root = await mkdtemp(join(tmpdir(), 'goodbuddy-native-dsh-')) + roots.push(root) + return root +} +const profile: NativeDshWebRequest['profile'] = { + id: 'test', name: 'Test', protocol: 'openai-chat-completions', + authentication: 'api-key', apiKey: 'provider-secret-must-stay-in-main', + baseUrl: 'http://127.0.0.1:1', modelName: 'test-model' +} + +describe('native DS Web mode', () => { + it('enforces Ask tool names independently of agent mode and permits Execute', async () => { + const root = await temporary() + const file = join(root, 'policy.mjs') + await writeFile(file, nativeDshWebPolicySource) + const plugin = await import(/* @vite-ignore */ pathToFileURL(file).href) + for (const mode of ['ask', 'execute']) { + let execute!: (execution: unknown, next: () => string) => string + plugin.apply({ on: (_name: string, callback: typeof execute) => { execute = callback } }, { + workMode: mode, readOnlyTools: ['mcp__docs__lookup'] + }) + for (const name of ['read', 'skill', 'mcp__docs__lookup']) { + expect(execute({ name, agent: { mode: 'execute' } }, () => 'ran')).toBe('ran') + } + for (const name of ['write', 'edit', 'pwsh', 'bash', 'subagent', 'mcp__docs__delete']) { + const run = () => execute({ name, agent: { mode: 'execute' } }, () => 'ran') + if (mode === 'ask') expect(run).toThrow('GoodBuddy Ask mode') + else expect(run()).toBe('ran') + } + } + }) + it('matches official MCP names without collisions after normalization', () => { + expect(nativeDshMcpToolName('docs', 'lookup')).toBe('mcp__docs__lookup') + expect(nativeDshMcpToolName('docs', 'a.b')).not.toBe(nativeDshMcpToolName('docs', 'a_b')) + expect(nativeDshMcpToolName('docs', 'a'.repeat(100))).toHaveLength(64) + }) + it('resolves the packaged CLI outside ASAR', () => { + expect(resolveNativeDshCli('/resources')).toBe(join('/resources', 'runtimes/dsh/node_modules/@deepseek-ai/dsh/lib/bin.js')) + }) +}) + +const standardNode = process.env.NATIVE_DSH_TEST_NODE ?? (!process.versions.electron ? process.execPath : undefined) +describe.skipIf(!standardNode)('official DS Web process', () => { + it('initializes the workspace, coalesces starts, isolates modes and preserves history on stop', async () => { + const root = await temporary() + const workspace = join(root, 'workspace') + await mkdir(workspace) + const service = new NativeDshWebClientService({ + rootDirectory: join(root, 'homes'), + cliPath: process.env.NATIVE_DSH_TEST_CLI, + resolveLaunchEnvironment: async () => ({ nodeExecutablePath: standardNode!, environment: process.env }) + }) + services.push(service) + const request: NativeDshWebRequest = { projectId: 'one', workspace, profile, workMode: 'ask' } + const [first, repeated] = await Promise.all([service.start(request), service.start(request)]) + expect(first).toEqual(repeated) + const config = await readFile(join(root, 'homes', first.id, 'cordis.patch.yml'), 'utf8') + expect(config).toContain('test-model') + expect(config).not.toContain(profile.apiKey) + const auth = await fetch(first.url, { redirect: 'manual' }) + const cookie = auth.headers.getSetCookie().map(value => value.split(';')[0]).join('; ') + const page = await fetch(new URL('/', first.url), { headers: { cookie } }) + expect(page.status).toBe(200) + expect(await page.text()).toContain(' { + const root = await temporary() + const skills = join(root, 'skills') + await mkdir(skills) + await writeFile(join(skills, 'SKILL.md'), '---\nname: native-test\ndescription: Native test skill\n---\nSKILL_LOADED_MARKER') + const toolResults: string[] = [] + let mcpCalls = 0 + const mcp = createServer(async (request, response) => { + if (request.method !== 'POST') { response.writeHead(405).end(); return } + let body = '' + for await (const chunk of request) body += chunk + const message = JSON.parse(body) + if (message.id === undefined) { response.writeHead(202).end(); return } + let result: unknown = {} + if (message.method === 'initialize') result = { protocolVersion: message.params.protocolVersion, + capabilities: { tools: {} }, serverInfo: { name: 'test', version: '1' } } + if (message.method === 'tools/list') result = { tools: [ + { name: 'lookup', description: 'Read test data', inputSchema: { type: 'object', properties: {} } }, + { name: 'mutate', description: 'Write test data', inputSchema: { type: 'object', properties: {} } } + ] } + if (message.method === 'tools/call') { mcpCalls++; result = { content: [{ type: 'text', text: 'MCP_CALLED_MARKER' }] } } + response.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ jsonrpc: '2.0', id: message.id, result })) + }) + await new Promise(resolve => mcp.listen(0, '127.0.0.1', resolve)) + const address = mcp.address() as { port: number } + const fetcher: typeof fetch = async (_url, init) => { + expect(new Headers(init?.headers).get('authorization')).toBe(`Bearer ${profile.apiKey}`) + const body = JSON.parse(String(init?.body)) + expect(body.model).toBe(profile.modelName) + const toolResult = body.messages.findLast((message: { role: string }) => message.role === 'tool') + const user = JSON.stringify(body.messages) + const toolName = user.includes('Load skill') ? 'skill' : user.includes('MCP read') ? 'mcp__test__lookup' + : user.includes('MCP write') ? 'mcp__test__mutate' : 'write' + const write = !toolResult && body.tools?.some((tool: { function: { name: string } }) => tool.function.name === toolName) + if (toolResult) toolResults.push(JSON.stringify(toolResult.content)) + const delta = write ? { role: 'assistant', tool_calls: [{ index: 0, id: 'call_write', type: 'function', + function: { name: toolName, arguments: JSON.stringify(toolName === 'write' + ? { file_path: join(root, 'written.txt'), content: 'EXECUTED' } : toolName === 'skill' ? { name: 'native-test' } : {}) } }] } + : { role: 'assistant', content: 'Finished' } + const event = (value: unknown) => `data: ${JSON.stringify(value)}\n\n` + return new Response(event({ id: 'test', object: 'chat.completion.chunk', model: profile.modelName, + choices: [{ index: 0, delta, finish_reason: null }] }) + event({ id: 'test', object: 'chat.completion.chunk', + choices: [{ index: 0, delta: {}, finish_reason: write ? 'tool_calls' : 'stop' }], + usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 } }) + 'data: [DONE]\n\n', + { headers: { 'content-type': 'text/event-stream' } }) + } + const service = new NativeDshWebClientService({ rootDirectory: join(root, 'homes'), fetcher, + cliPath: process.env.NATIVE_DSH_TEST_CLI, + resolveLaunchEnvironment: async () => ({ nodeExecutablePath: standardNode!, environment: process.env }) }) + services.push(service) + try { + for (const workMode of ['ask', 'execute'] as const) { + const handle = await service.start({ projectId: 'tools', workspace: root, profile, workMode, + skillDirectories: [skills], mcpServers: [{ serverName: 'test', transport: 'streamable-http', + url: `http://127.0.0.1:${address.port}/mcp`, readOnlyTools: ['lookup'] }] }) + const auth = await fetch(handle.url, { redirect: 'manual' }) + const cookie = auth.headers.getSetCookie().map(value => value.split(';')[0]).join('; ') + async function rpc(method: string, request: unknown): Promise> { + const response = await fetch(new URL(`/api/${method}`, handle.url), { method: 'POST', + headers: { 'content-type': 'application/json', cookie, origin: new URL(handle.url).origin }, + body: JSON.stringify({ type: 'client-request', rpcId: crypto.randomUUID(), method, payload: { args: { request } } }) }) + const payload = await response.json() as { result?: { ok?: boolean; value: Record } } + expect(payload.result?.ok, JSON.stringify(payload)).toBe(true) + return payload.result!.value + } + const session = await rpc('session/create', { cwd: root }) + const previous = toolResults.length + await rpc('session/prompt', { sessionId: session.sessionId, requestId: crypto.randomUUID(), mode: 'queue', + content: [{ type: 'text', text: 'Write the requested marker file.' }] }) + await vi.waitFor(() => expect(toolResults.length).toBeGreaterThan(previous), { timeout: 15_000 }) + if (workMode === 'ask') { + expect(toolResults.at(-1)).toContain('GoodBuddy Ask mode') + await expect(readFile(join(root, 'written.txt'))).rejects.toThrow() + } else { + expect(await readFile(join(root, 'written.txt'), 'utf8')).toBe('EXECUTED') + } + for (const prompt of ['Load skill', 'MCP read', 'MCP write']) { + const next = await rpc('session/create', { cwd: root }) + const before = toolResults.length + const callsBefore = mcpCalls + await rpc('session/prompt', { sessionId: next.sessionId, requestId: crypto.randomUUID(), mode: 'queue', + content: [{ type: 'text', text: prompt }] }) + await vi.waitFor(() => expect(toolResults.length).toBeGreaterThan(before), { timeout: 15_000 }) + if (prompt === 'Load skill') await vi.waitFor(() => expect(toolResults.slice(before).join()).toContain('SKILL_LOADED_MARKER'), { timeout: 15_000 }) + else if (prompt === 'MCP write' && workMode === 'ask') { + await vi.waitFor(() => expect(toolResults.slice(before).join()).toContain('does not allow tool: mcp__test__mutate'), { timeout: 15_000 }) + expect(mcpCalls).toBe(callsBefore) + } else { + await vi.waitFor(() => expect(toolResults.slice(before).join()).toContain('MCP_CALLED_MARKER'), { timeout: 15_000 }) + expect(mcpCalls).toBe(callsBefore + 1) + } + } + } + } finally { + await service.dispose() + mcp.closeAllConnections() + await new Promise(resolve => mcp.close(() => resolve())) + } + }, 60_000) + + it('cleans failed launches and permits retry', async () => { + const root = await temporary() + const service = new NativeDshWebClientService({ rootDirectory: join(root, 'homes'), cliPath: join(root, 'missing.js'), + resolveLaunchEnvironment: async () => ({ nodeExecutablePath: standardNode!, environment: process.env }) }) + services.push(service) + const request: NativeDshWebRequest = { projectId: 'one', workspace: root, profile, workMode: 'ask' } + await expect(service.start(request)).rejects.toThrow() + await expect(service.start(request)).rejects.toThrow() + }) + + it('cancels an in-progress launch when disposed', async () => { + const root = await temporary() + const cliPath = join(root, 'waiting.mjs') + await writeFile(cliPath, 'setInterval(() => {}, 1000)') + const service = new NativeDshWebClientService({ rootDirectory: join(root, 'homes'), cliPath, + resolveLaunchEnvironment: async () => ({ nodeExecutablePath: standardNode!, environment: process.env }) }) + services.push(service) + const starting = service.start({ projectId: 'pending', workspace: root, profile, workMode: 'ask' }) + const rejected = expect(starting).rejects.toThrow() + await new Promise(resolve => setTimeout(resolve, 200)) + await service.dispose() + await rejected + }) +}) diff --git a/src/main/agent/native-dsh-web-client.ts b/src/main/agent/native-dsh-web-client.ts new file mode 100644 index 00000000..f1727364 --- /dev/null +++ b/src/main/agent/native-dsh-web-client.ts @@ -0,0 +1,232 @@ +import { execFile, spawn, type ChildProcess } from 'node:child_process' +import { createHash, randomUUID } from 'node:crypto' +import { mkdir, realpath, rm, stat, writeFile } from 'node:fs/promises' +import { createRequire } from 'node:module' +import { dirname, join } from 'node:path' +import { promisify } from 'node:util' +import { AgentModelCallLedger, AgentModelGateway } from '../../agent-daemon/agent-model-gateway' +import { MODEL_BRIDGE_SDK_AUTH_SENTINEL, ModelBridgeLoopbackProxy } from '../../agent-daemon/model-bridge-helper' +import { canonicalJson } from '../../shared/agent-protocol/canonical' +import type { ResolvedModelProfile } from '../runtime-settings-store' +import { createManagedModelBridge } from '../remote-agent/managed-model-bridge' +import { terminateProcessTreeAndWait } from './child-process-termination' +import { buildCredentialFilteredUserEnvironment } from './process-environment' +import { nativeDshMcpToolName, nativeDshWebPatch, nativeDshWebPolicySource, type NativeDshMcpServer } from './native-dsh-web-policy' + +export type { NativeDshMcpServer } from './native-dsh-web-policy' + +export type NativeDshWebRequest = { + projectId: string + ownerId?: number + /** Includes the coordinator's current capability digests and launch settings. */ + configurationKey?: string + workspace: string + profile: ResolvedModelProfile + workMode: 'ask' | 'execute' + /** Directories containing SKILL.md, or roots containing skill bundles. */ + skillDirectories?: string[] + /** Already resolved by Main; GoodBuddy-only tools need a caller-owned MCP adapter. */ + mcpServers?: NativeDshMcpServer[] +} + +export type NativeDshWebHandle = { id: string; url: string } +export type NativeDshWebClientOptions = { + rootDirectory: string + resolveLaunchEnvironment: () => Promise<{ + nodeExecutablePath: string + environment: Readonly + }> + /** Packaged: process.resourcesPath. Omit in development. */ + resourcesPath?: string + cliPath?: string + startupTimeoutMs?: number + /** Existing gateway supports injecting fetch for focused protocol tests. */ + fetcher?: typeof fetch +} + +type Instance = { + id: string + controller: AbortController + ready: Promise + child?: ChildProcess + proxy?: ModelBridgeLoopbackProxy + ledger?: AgentModelCallLedger + cleanup?: Promise + home: string +} + +export function resolveNativeDshCli(resourcesPath?: string): string { + return resourcesPath + ? join(resourcesPath, 'runtimes', 'dsh', 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js') + : join(dirname(createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json')), 'lib', 'bin.js') +} + +export class NativeDshWebClientService { + private readonly instances = new Map() + private disposed = false + + constructor(private readonly options: NativeDshWebClientOptions) {} + + async start(input: NativeDshWebRequest): Promise { + if (this.disposed) throw new Error('DS Web service is disposed') + const request = structuredClone(input) + request.workspace = await realpath(request.workspace) + if (!(await stat(request.workspace)).isDirectory()) throw new Error('DS Web workspace is not a directory') + if (this.disposed) throw new Error('DS Web service is disposed') + // Include credentials in the in-memory match hash so credential rotation starts + // a fresh bridge. Only the digest is used as a directory name. + const key = createHash('sha256').update(canonicalJson(JSON.parse(JSON.stringify(request)))).digest('hex') + const existing = this.instances.get(key) + if (existing) { + if (existing.controller.signal.aborted || (existing.child && + (existing.child.exitCode !== null || existing.child.signalCode !== null))) { + await existing.ready.catch(() => undefined) + await this.cleanup(existing) + return this.start(request) + } + return existing.ready + } + const instance: Instance = { + id: key, controller: new AbortController(), + home: join(this.options.rootDirectory, key), + ready: Promise.resolve({ id: key, url: '' }) + } + this.instances.set(key, instance) + instance.ready = this.launch(instance, request).catch(async error => { + await this.cleanup(instance) + throw error + }) + return instance.ready + } + + async stop(id: string): Promise { + const instance = this.instances.get(id) + if (!instance) return + instance.controller.abort(new Error('DS Web service stopped')) + await instance.ready.catch(() => undefined) + await this.cleanup(instance) + } + + async get(id: string): Promise { + const instance = this.instances.get(id) + if (!instance || instance.controller.signal.aborted) return null + const handle = await instance.ready.catch(() => null) + return instance.controller.signal.aborted || (instance.child && + (instance.child.exitCode !== null || instance.child.signalCode !== null)) ? null : handle + } + + async dispose(): Promise { + this.disposed = true + await Promise.all([...this.instances.keys()].map(id => this.stop(id))) + } + + private async cleanup(instance: Instance): Promise { + instance.cleanup ??= (async () => { + instance.controller.abort(new Error('DS Web service stopped')) + if (instance.child && instance.child.signalCode === null) { + await terminateProcessTreeAndWait(instance.child, { processGroup: process.platform !== 'win32' }) + } + await instance.proxy?.close() + instance.ledger?.close() + // Native history and profile settings are persistent; only launch material is disposable. + await Promise.all(['cordis.patch.yml', 'goodbuddy-mode.mjs', 'bridge.sqlite', 'bridge.sqlite-wal', 'bridge.sqlite-shm'] + .map(name => rm(join(instance.home, name), { force: true }))) + if (this.instances.get(instance.id) === instance) this.instances.delete(instance.id) + })() + return instance.cleanup + } + + private async launch(instance: Instance, request: NativeDshWebRequest): Promise { + const signal = AbortSignal.any([instance.controller.signal, AbortSignal.timeout(this.options.startupTimeoutMs ?? 60_000)]) + const launch = await this.options.resolveLaunchEnvironment() + signal.throwIfAborted() + if (!launch.nodeExecutablePath) throw new Error('DS Web requires a standard Node executable from the local tool environment') + const environment = buildCredentialFilteredUserEnvironment({ ...launch.environment }) + const { stdout } = await promisify(execFile)(launch.nodeExecutablePath, + ['-p', 'JSON.stringify({node:process.versions.node,electron:process.versions.electron})'], + { env: { ...environment, ELECTRON_RUN_AS_NODE: '1' }, signal, timeout: 5_000, windowsHide: true }) + const runtime = JSON.parse(stdout.trim()) as { node?: string; electron?: string } + if (!runtime.node || runtime.electron) throw new Error('DS Web requires standard Node, not Electron') + const cli = this.options.cliPath ?? resolveNativeDshCli(this.options.resourcesPath) + await stat(cli) + await mkdir(instance.home, { recursive: true, mode: 0o700 }) + const managed = createManagedModelBridge({ profile: request.profile }) + instance.ledger = new AgentModelCallLedger(join(instance.home, 'bridge.sqlite')) + const gateway = new AgentModelGateway({ ledger: instance.ledger, fetcher: this.options.fetcher }) + const operationId = randomUUID() + let roundIndex = 0 + instance.proxy = new ModelBridgeLoopbackProxy({ exchange: (message, context) => gateway.dispatch({ + bindingId: instance.id, operationId, promptSequence: 0, roundIndex: roundIndex++, + profileDigest: managed.profile.modelProfileDigest, profile: managed.profile + }, message, context.signal) }) + const origin = await instance.proxy.listen() + const policyPath = join(instance.home, 'goodbuddy-mode.mjs') + const mcpServers = request.mcpServers ?? [] + const patch = nativeDshWebPatch({ + model: request.profile.modelName, + api: request.profile.protocol === 'anthropic-messages' ? 'anthropic-messages' + : request.profile.protocol === 'openai-responses' ? 'openai-responses' : 'openai-completions', + baseURL: `${origin}/v1`, workMode: request.workMode, policyPath, + skillDirectories: request.skillDirectories ?? [], mcpServers, + readOnlyTools: mcpServers.flatMap(server => (server.readOnlyTools ?? []).map(name => nativeDshMcpToolName(server.serverName, name))) + }) + await writeFile(policyPath, nativeDshWebPolicySource, 'utf8') + await writeFile(join(instance.home, 'cordis.patch.yml'), JSON.stringify(patch), 'utf8') + signal.throwIfAborted() + for (const name of Object.keys(environment)) if (name.startsWith('DSH_')) delete environment[name] + instance.child = spawn(launch.nodeExecutablePath, [cli, 'web', '--no-open', '--host', '127.0.0.1', '--port', '0'], { + cwd: request.workspace, shell: false, windowsHide: true, + detached: process.platform !== 'win32', stdio: ['ignore', 'pipe', 'pipe'], + env: { ...environment, DSH_HOME: instance.home, DSH_TELEMETRY_DISABLED: '1', + DSH_PERMISSION_MODE: 'danger-full-access', GOODBUDDY_DSH_MODEL_KEY: MODEL_BRIDGE_SDK_AUTH_SENTINEL } + }) + const child = instance.child + const url = await new Promise((resolve, reject) => { + let output = '' + const finish = (error?: Error, address?: string): void => { + signal.removeEventListener('abort', onAbort) + child.removeListener('error', onError) + child.removeListener('exit', onExit) + child.stdout?.removeListener('data', onData) + child.stderr?.removeListener('data', onData) + if (error) reject(error) + else resolve(address!) + } + const onAbort = (): void => finish(new Error('DS Web startup cancelled or timed out', { cause: signal.reason })) + const onError = (error: Error): void => finish(new Error(`DS Web process could not start: ${error.message}`)) + const onExit = (code: number | null): void => finish(new Error(`DS Web exited during startup (${code})`)) + const onData = (chunk: Buffer): void => { + output = (output + chunk.toString()).slice(-32_768) + // Wait for the full line; stdout can split in the middle of the token. + // eslint-disable-next-line no-control-regex + const match = output.match(/http:\/\/127\.0\.0\.1:\d+[^\s\x1b]*(?=[\s\x1b])/u) + if (match) finish(undefined, match[0]) + } + child.once('error', onError) + child.once('exit', onExit) + child.stdout?.on('data', onData) + child.stderr?.on('data', onData) + signal.addEventListener('abort', onAbort, { once: true }) + if (signal.aborted) onAbort() + }) + // Drain subsequent logs without retaining token-bearing output. + child.stdout?.resume() + child.stderr?.resume() + child.once('exit', () => { void this.cleanup(instance) }) + const auth = await fetch(url, { redirect: 'manual', signal }) + if (auth.status !== 303) throw new Error(`DS Web authentication failed (HTTP ${auth.status})`) + const cookie = auth.headers.getSetCookie().map(value => value.split(';')[0]).join('; ') + const response = await fetch(new URL('/api/workspace/create', url), { + method: 'POST', signal, + headers: { 'content-type': 'application/json', cookie, origin: new URL(url).origin }, + body: JSON.stringify({ type: 'client-request', rpcId: randomUUID(), method: 'workspace/create', + payload: { args: { request: { path: request.workspace } } } }) + }) + if (!response.ok) throw new Error(`DS Web workspace creation failed (HTTP ${response.status})`) + const result = await response.json() as { result?: { ok?: boolean } } + if (result.result?.ok !== true) throw new Error('DS Web workspace creation was rejected') + signal.throwIfAborted() + if (child.exitCode !== null || child.signalCode !== null) throw new Error('DS Web exited during workspace initialization') + return { id: instance.id, url } + } +} diff --git a/src/main/agent/native-dsh-web-policy.ts b/src/main/agent/native-dsh-web-policy.ts new file mode 100644 index 00000000..1bd2db8a --- /dev/null +++ b/src/main/agent/native-dsh-web-policy.ts @@ -0,0 +1,74 @@ +import { createHash } from 'node:crypto' + +// Official dsh-mcp-client 0.1.7-rc.2 naming contract; its helper is private. +export function nativeDshMcpToolName(serverName: string, rawName: string): string { + const joined = `mcp__${serverName}__${rawName}` + const normalized = joined.replace(/[^A-Za-z0-9_-]/gu, '_') + if (joined === normalized && normalized.length <= 64) return joined + const hash = createHash('sha256').update(`${serverName}\0${rawName}`).digest('hex').slice(0, 12) + return `${normalized.slice(0, 51)}_${hash}` +} + +export type NativeDshMcpServer = { + serverName: string + readOnlyTools?: string[] +} & ( + | { transport: 'stdio'; command: string; args?: string[]; env?: Record; cwd?: string } + | { transport: 'streamable-http'; url: string; headers?: Record } +) + +// Loaded by the official Cordis loader, outside Electron and its ASAR bundle. +// The launch mode applies to every session, including delegated agents. +export const nativeDshWebPolicySource = ` +export const name = 'goodbuddy-native-mode'; +export function apply(ctx, config) { + const allowed = new Set(['read', 'skill', ...config.readOnlyTools]); + ctx.on('tools/execute', (exec, next) => { + if (config.workMode === 'ask' && !allowed.has(exec.name)) { + throw new Error('GoodBuddy Ask mode does not allow tool: ' + exec.name); + } + return next(); + }); +} +` + +export function nativeDshWebPatch(options: { + model: string + api: string + baseURL: string + workMode: 'ask' | 'execute' + policyPath: string + skillDirectories: string[] + mcpServers: NativeDshMcpServer[] + readOnlyTools: string[] +}): unknown[] { + return [ + { + id: 'llm-pi-ai', + config: { providers: { goodbuddy: { + displayName: 'GoodBuddy', api: options.api, + apiKeyEnv: 'GOODBUDDY_DSH_MODEL_KEY', baseURL: options.baseURL, + models: [{ id: options.model, name: options.model }] + } } } + }, + { id: 'agent-default-model', config: { provider: 'goodbuddy', model: options.model } }, + { id: 'sandbox-policy', config: { mode: 'danger-full-access' } }, + { id: 'approval', config: { policy: 'never' } }, + // The launch mode owns permissions. Native Plan remains a planning aid. + { id: 'ui-permission', disabled: true }, + { insert: [ + { id: 'goodbuddy-native-mode', name: options.policyPath, + config: { workMode: options.workMode, readOnlyTools: options.readOnlyTools } }, + ...(options.skillDirectories.length ? [{ + id: 'goodbuddy-skills', name: '@deepseek-ai/dsh-skill-filesystem', + config: { providerName: 'goodbuddy', includeDefaultRoots: false, + customSkillDirs: options.skillDirectories } + }] : []), + ...options.mcpServers.map((server, index) => { + const config = { ...server, failOnStartupError: true } + delete config.readOnlyTools + return { id: `goodbuddy-mcp-${index}`, name: '@deepseek-ai/dsh-mcp-client', config } + }) + ] } + ] +} diff --git a/src/main/agent/native-terminal-client.e2e.test.ts b/src/main/agent/native-terminal-client.e2e.test.ts new file mode 100644 index 00000000..c8ba0dfc --- /dev/null +++ b/src/main/agent/native-terminal-client.e2e.test.ts @@ -0,0 +1,94 @@ +// @vitest-environment node +import { spawn } from 'node:child_process' +import { mkdtemp, rm, stat } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { describe, expect, it } from 'vitest' +import type { ResolvedRuntimeSettings } from '../runtime-settings-store' +import type { TerminalSnapshot } from '../../shared/terminal-contracts' +import type { NativeTerminalLaunch } from '../terminal/terminal-session-manager' +import { LocalTerminalSession } from '../terminal/local-terminal-session' +import { resolveBundledRuntimePaths } from './bundled-runtimes' +import { NativeTerminalClient } from './native-terminal-client' + +// Opt-in because these tests execute the installed native clients and a real PTY. +describe.skipIf(!process.env.GOODBUDDY_NATIVE_NODE)('installed native terminal clients', () => { + for (const runtime of ['continue', 'opencode'] as const) { + for (const workMode of ['ask', 'execute'] as const) { + it(`${runtime} ${workMode} enforces tool mode and starts its interactive PTY`, async () => { + const root = await mkdtemp(join(tmpdir(), 'native-client-e2e-')) + let launch: NativeTerminalLaunch | undefined + let pty: LocalTerminalSession | undefined + const requests: Array> = [] + const profile = { id: 'native-test', name: 'Native Test Model', modelName: 'native-test-model', baseUrl: 'https://native-test.invalid/v1', protocol: 'openai-chat-completions' as const, authentication: 'api-key' as const, apiKey: 'test-provider-secret' } + const client = new NativeTerminalClient({ + rootDirectory: root, + nodeExecutable: process.env.GOODBUDDY_NATIVE_NODE, + bundledRuntimePaths: resolveBundledRuntimePaths({ appPath: process.cwd(), resourcesPath: '', packaged: false }), + fetcher: async (_url, options) => { + const request = JSON.parse(String(options?.body)) + requests.push(request) + if (!request.stream) return new Response(JSON.stringify({ id: 'native-test', object: 'chat.completion', created: 1, model: profile.modelName, choices: [{ index: 0, message: { role: 'assistant', content: 'NATIVE_BRIDGE_OK' }, finish_reason: 'stop' }], usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 } }), { headers: { 'content-type': 'application/json' } }) + const chunk = (delta: object, finish_reason: string | null) => `data: ${JSON.stringify({ id: 'native-test', object: 'chat.completion.chunk', created: 1, model: profile.modelName, choices: [{ index: 0, delta, finish_reason }] })}\n\n` + if (requests.length === 1) return new Response(chunk({ role: 'assistant', tool_calls: [{ index: 0, id: 'write-attempt', type: 'function', function: { name: runtime === 'continue' ? 'Bash' : 'bash', arguments: JSON.stringify({ command: 'echo NATIVE_WRITE > native-write-probe.txt', description: 'Write the test-owned marker' }) } }] }, null) + chunk({}, 'tool_calls') + 'data: [DONE]\n\n', { headers: { 'content-type': 'text/event-stream' } }) + return new Response(chunk({ role: 'assistant', content: 'NATIVE_BRIDGE_OK' }, null) + chunk({}, 'stop') + 'data: [DONE]\n\n', { headers: { 'content-type': 'text/event-stream' } }) + }, + terminalManager: { create: async (_owner, _request, prepared) => { + launch = prepared + return { sessionId: 'native-test', state: 'running' } as TerminalSnapshot + } } + }) + try { + await client.open(1, { + projectId: 'project', projectName: 'Native Test', directory: root, runtime, workMode, + settings: { continueBinaryPath: '', opencodeBinaryPath: '', continueConfigPath: '', continueModelProfile: profile, opencodeModelProfile: profile } as ResolvedRuntimeSettings + }) + const spec = launch!.spawnSpec + spec.env.NODE_ENV = 'production' + delete spec.env.VITEST + delete spec.env.VITEST_WORKER_ID + delete spec.env.VITEST_POOL_ID + const output = await new Promise((resolve, reject) => { + const child = spawn(spec.executable, [...spec.args, ...(runtime === 'continue' ? ['-p', 'Reply with NATIVE_BRIDGE_OK'] : ['--print-logs', 'run', 'Reply with NATIVE_BRIDGE_OK'])], { cwd: root, env: spec.env, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] }) + let text = '' + const timeout = setTimeout(() => { child.kill(); reject(new Error(`Native CLI timeout: ${text.slice(-2000)}`)) }, 45_000) + child.stdout.on('data', data => { text += data }) + child.stderr.on('data', data => { text += data }) + child.on('error', error => { clearTimeout(timeout); reject(error) }) + child.on('close', code => { clearTimeout(timeout); if (code === 0) resolve(text); else reject(new Error(`Native CLI exit ${code}: ${text.slice(-2000)}`)) }) + }) + expect(output, `requests: ${requests.length}; executable: ${spec.executable}; args: ${JSON.stringify(spec.args)}`).toContain('NATIVE_BRIDGE_OK') + expect(requests.length).toBeGreaterThan(0) + expect(requests.every(request => request.model === profile.modelName)).toBe(true) + if (runtime === 'continue') { + const tools = requests.flatMap(request => (request.tools ?? []) as Array<{ function: { name: string } }>).map(tool => tool.function.name) + expect(tools).toContain('Read') + if (workMode === 'ask') expect(tools).not.toContain('Write') + } + if (workMode === 'ask') await expect(stat(join(root, 'native-write-probe.txt'))).rejects.toThrow() + else expect((await stat(join(root, 'native-write-probe.txt'))).isFile()).toBe(true) + expect(requests.length).toBeGreaterThan(1) + pty = await LocalTerminalSession.create({ target: { type: 'project', projectId: 'project' }, targetLabel: 'Native Test', title: runtime, size: { cols: 100, rows: 30 }, projectDirectory: root, spawnSpec: spec }) + expect(pty.snapshot().state).toBe('running') + const session = pty + await new Promise((resolve, reject) => { + let text = '' + const timeout = setTimeout(() => { remove(); reject(new Error(`Interactive PTY did not become ready: ${text.slice(-1000)}`)) }, 15_000) + const remove = session.onEvent(event => { + session.acknowledge(event.sequence) + if (event.type === 'output') { + text += event.data + if (/Continue|OpenCode|opencode|Native Test Model|native-test-model/u.test(text)) { clearTimeout(timeout); resolve() } + } + if (event.type === 'exit') { clearTimeout(timeout); reject(new Error(`Interactive PTY exited: ${text.slice(-1000)}`)) } + }) + }) + } finally { + await pty?.close() + await launch?.dispose() + await rm(root, { recursive: true, force: true }) + } + }, 70_000) + } + } +}) diff --git a/src/main/agent/native-terminal-client.test.ts b/src/main/agent/native-terminal-client.test.ts new file mode 100644 index 00000000..1ae6c4f6 --- /dev/null +++ b/src/main/agent/native-terminal-client.test.ts @@ -0,0 +1,94 @@ +// @vitest-environment node +import { mkdtemp, readFile, readdir, rm } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, it, vi } from 'vitest' +import type { ResolvedRuntimeSettings } from '../runtime-settings-store' +import type { NativeTerminalLaunch } from '../terminal/terminal-session-manager' +import type { TerminalSnapshot } from '../../shared/terminal-contracts' +import { NativeTerminalClient, type NativeTerminalClientInput } from './native-terminal-client' + +const roots: string[] = [] +const launches: NativeTerminalLaunch[] = [] +afterEach(async () => { + await Promise.all(launches.splice(0).map(launch => launch.dispose())) + await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))) +}) + +async function fixture() { + const root = await mkdtemp(join(tmpdir(), 'native-terminal-test-')) + roots.push(root) + const create = vi.fn(async (_owner, _request, launch: NativeTerminalLaunch | undefined) => { + launches.push(launch!) + return { sessionId: 'terminal', state: 'running' } as TerminalSnapshot + }) + const fetcher = vi.fn(async () => new Response(JSON.stringify({ choices: [{ message: { role: 'assistant', content: 'ok' } }] }), { headers: { 'content-type': 'application/json' } })) + const client = new NativeTerminalClient({ + terminalManager: { create }, rootDirectory: root, + bundledRuntimePaths: { opencode: process.execPath, continue: process.execPath, ripgrep: '', deepseekHarness: '' }, fetcher + }) + const profile = { id: 'selected', name: 'Selected model', modelName: 'selected-model', baseUrl: 'https://provider.example/v1', authentication: 'api-key' as const, protocol: 'openai-chat-completions' as const, apiKey: 'provider-secret', requestHeaders: { 'x-provider-option': 'configured' } } + const input: NativeTerminalClientInput = { + projectId: 'project', projectName: 'Project', directory: root, runtime: 'opencode', workMode: 'ask', + settings: { opencodeBinaryPath: '', opencodeModelProfile: profile } as unknown as ResolvedRuntimeSettings + } + return { root, client, create, fetcher, input } +} + +describe('native terminal client', () => { + it('bridges successive native requests with the selected model and keeps credentials in Main', async () => { + const { client, input, create, fetcher, root } = await fixture() + const first = client.open(1, input) + expect(client.open(1, input)).toBe(first) + await first + expect(create).toHaveBeenCalledOnce() + const launch = launches[0]! + expect(JSON.stringify(launch.spawnSpec)).not.toContain('provider-secret') + const config = JSON.parse(launch.spawnSpec.env.OPENCODE_CONFIG_CONTENT!) + const provider = Object.values(config.provider)[0] as { options: { baseURL: string; apiKey: string } } + for (let i = 0; i < 2; i++) { + const response = await fetch(`${provider.options.baseURL}/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${provider.options.apiKey}` }, body: JSON.stringify({ model: 'selected-model', messages: [{ role: 'user', content: 'hi' }] }) }) + expect(response.status).toBe(200) + expect(await response.text()).toContain('ok') + } + expect(fetcher).toHaveBeenCalledTimes(2) + expect(String(fetcher.mock.calls[0]?.[0])).toBe('https://provider.example/v1/chat/completions') + const headers = new Headers(fetcher.mock.calls[0]?.[1]?.headers) + expect(headers.get('authorization')).toBe('Bearer provider-secret') + expect(headers.get('x-provider-option')).toBe('configured') + const configDirectory = launch.spawnSpec.env.OPENCODE_CONFIG_DIR! + const pluginPath = new URL(config.plugin[0]) + const plugin = await import(/* @vite-ignore */ pluginPath.href) + const hooks = await plugin.default() + await expect(hooks['tool.execute.before']({ tool: 'read' })).resolves.toBeUndefined() + await expect(hooks['tool.execute.before']({ tool: 'bash' })).rejects.toThrow('read-only') + await expect(hooks['tool.execute.before']({ tool: 'mcp_write' })).rejects.toThrow('read-only') + await launch.dispose() + await expect(readdir(configDirectory)).rejects.toThrow() + expect(await readdir(join(root, 'opencode'))).toHaveLength(1) + await expect(fetch(`${provider.options.baseURL}/chat/completions`, { method: 'POST' })).rejects.toThrow() + await client.open(1, input) + expect(create).toHaveBeenCalledTimes(2) + }) + + it('releases prepared resources after terminal creation fails and permits retry', async () => { + const { client, input, create, root } = await fixture() + create.mockImplementationOnce(async (_owner, _request, launch) => { + launches.push(launch!) + throw new Error('PTY unavailable') + }) + await expect(client.open(1, input)).rejects.toThrow('PTY unavailable') + expect((await readdir(root)).filter(name => name.startsWith('launch-'))).toEqual([]) + await expect(client.open(1, input)).resolves.toMatchObject({ state: 'running' }) + }) + + it('uses Execute permissions and explicit session MCP endpoints', async () => { + const { client, input } = await fixture() + await client.open(1, { ...input, workMode: 'execute', mcpServers: [{ name: 'tools', url: 'http://127.0.0.1:12345/mcp', headers: { Authorization: 'Bearer local-token' } }] }) + const launch = launches[0]! + const config = JSON.parse(launch.spawnSpec.env.OPENCODE_CONFIG_CONTENT!) + expect(config.permission).toBe('allow') + expect(config.mcp.tools.url).toBe('http://127.0.0.1:12345/mcp') + expect(await readFile(new URL(config.plugin[0]), 'utf8')).toContain('execute') + }) +}) diff --git a/src/main/agent/native-terminal-client.ts b/src/main/agent/native-terminal-client.ts new file mode 100644 index 00000000..182e48c0 --- /dev/null +++ b/src/main/agent/native-terminal-client.ts @@ -0,0 +1,213 @@ +import { randomUUID } from 'node:crypto' +import { execFile } from 'node:child_process' +import { cp, mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises' +import { dirname, join } from 'node:path' +import { pathToFileURL } from 'node:url' +import { promisify } from 'node:util' +import { AgentModelCallLedger, AgentModelGateway } from '../../agent-daemon/agent-model-gateway' +import { + ModelBridgeLoopbackProxy, + MODEL_BRIDGE_SDK_AUTH_SENTINEL, + createOpenCodeModelBridgeProviderConfig +} from '../../agent-daemon/model-bridge-helper' +import type { TerminalSize, TerminalSnapshot } from '../../shared/terminal-contracts' +import type { ResolvedRuntimeSettings } from '../runtime-settings-store' +import type { RuntimeSkillPackage } from '../capabilities/capability-service' +import type { LaunchEnvironmentProvider } from '../local-tool-environment/launch-environment-provider' +import { createManagedModelBridge, createResolvedModelProfileDigest } from '../remote-agent/managed-model-bridge' +import type { TerminalSessionManager, NativeTerminalLaunch } from '../terminal/terminal-session-manager' +import type { BundledRuntimePaths } from './bundled-runtimes' +import { ContinueHostAdapter, loadContinueConfig } from './continue-host-adapter' +import { detectRuntimeBinary } from './runtime-discovery' +import { applyLaunchEnvironmentPath, buildCredentialFilteredUserEnvironment, runtimePrivacyEnvironment } from './process-environment' +import { stageRuntimeSkillPackages } from './runtime-skill-packages' + +export type NativeTerminalClientInput = { + projectId: string + projectName: string + directory: string + runtime: 'continue' | 'opencode' + workMode: 'ask' | 'execute' + settings: ResolvedRuntimeSettings + size?: TerminalSize + skillPackages?: RuntimeSkillPackage[] + /** Session-lived, Main-owned MCP endpoints, such as the existing knowledge gateway. */ + mcpServers?: Array<{ name: string; url: string; headers: Record }> +} + +export type NativeTerminalClientOptions = { + terminalManager: Pick + /** GoodBuddy user-data directory; native history is retained here. */ + rootDirectory: string + bundledRuntimePaths: BundledRuntimePaths + /** Standard Node resolved by the local tool environment, never Electron. */ + nodeExecutable?: string + launchEnvironmentProvider?: LaunchEnvironmentProvider + fetcher?: typeof fetch +} + +// Same native read permissions as the existing remote OpenCode adapter. +const openCodeReadTools = ['read', 'glob', 'grep', 'list', 'lsp', 'webfetch', 'websearch', 'codesearch', 'question', 'external_directory'] +const continueReadTools = ['Read', 'List', 'Search', 'Fetch', 'Diff', 'AskQuestion', 'CheckBackgroundJob', 'Skills'] + +export class NativeTerminalClient { + private readonly pending = new Map>() + + constructor(private readonly options: NativeTerminalClientOptions) {} + + open(ownerId: number, input: NativeTerminalClientInput): Promise { + const profile = input.runtime === 'continue' + ? input.settings.continueModelProfile + : input.settings.opencodeModelProfile + if (!profile) return Promise.reject(new Error('Native client requires the selected text model connection')) + const key = JSON.stringify([ownerId, input.projectId, input.runtime, input.workMode, createResolvedModelProfileDigest(profile)]) + const existing = this.pending.get(key) + if (existing) return existing + const operation = this.launch(ownerId, structuredClone(input)).finally(() => this.pending.delete(key)) + this.pending.set(key, operation) + return operation + } + + private async launch(ownerId: number, input: NativeTerminalClientInput): Promise { + const launch = await this.prepare(input) + try { + const snapshot = await this.options.terminalManager.create(ownerId, { + target: { type: 'project', projectId: input.projectId }, + ...(input.size ?? { cols: 100, rows: 30 }) + }, launch) + if (snapshot.state === 'failed') { + await launch.dispose() + throw new Error(snapshot.error?.message ?? 'Native terminal failed to start') + } + return snapshot + } catch (error) { + await launch.dispose() + throw error + } + } + + private async prepare(input: NativeTerminalClientInput): Promise { + if (!(await stat(input.directory)).isDirectory()) throw new Error('Native client project directory is unavailable') + const selected = input.runtime === 'continue' ? input.settings.continueModelProfile : input.settings.opencodeModelProfile + if (!selected) throw new Error('Native client requires a model connection') + const managed = createManagedModelBridge({ profile: selected }) + const detection = await detectRuntimeBinary({ + binaryPath: input.runtime === 'continue' ? input.settings.continueBinaryPath : input.settings.opencodeBinaryPath, + bundledPath: this.options.bundledRuntimePaths[input.runtime], + binaryNames: input.runtime === 'continue' ? ['cn'] : ['opencode'], + label: input.runtime, + validation: 'canonical-file' + }) + if (!detection.path) throw new Error(detection.detail) + const env = applyLaunchEnvironmentPath({ + ...buildCredentialFilteredUserEnvironment(), ...runtimePrivacyEnvironment + }, this.options.launchEnvironmentProvider) + // Do not inherit another native client's provider/config selection. + for (const name of Object.keys(env)) { + if (/^(OPENCODE_|CONTINUE_)/u.test(name)) delete env[name] + } + let executable = detection.path + const args: string[] = [] + if (input.runtime === 'continue') { + const node = this.options.nodeExecutable + if (!node) throw new Error('Continue interactive terminal requires a standard Node executable from the local tool environment') + const { stdout } = await promisify(execFile)(node, ['-p', 'JSON.stringify({node:process.versions.node,electron:process.versions.electron})'], { env, timeout: 5_000, windowsHide: true }) + const version = JSON.parse(stdout.trim()) as { node?: string; electron?: string } + if (!version.node || version.electron) throw new Error('Continue interactive terminal requires standard Node, not Electron') + executable = node + args.push(detection.path) + } + const root = this.options.rootDirectory + await mkdir(root, { recursive: true }) + const temporary = await mkdtemp(join(root, 'launch-')) + const history = join(root, input.runtime, randomUUID()) + let ledger: AgentModelCallLedger | undefined + let gateway: AgentModelGateway + const bindingId = randomUUID() + const proxy = new ModelBridgeLoopbackProxy({ exchange: (request, context) => gateway.dispatch({ + bindingId, operationId: context.requestId, promptSequence: 0, roundIndex: 0, + profileDigest: managed.profile.modelProfileDigest, profile: managed.profile + }, request, context.signal) }) + let disposal: Promise | undefined + const dispose = (): Promise => disposal ??= (async () => { + try { await proxy.close() } finally { + ledger?.close() + await rm(temporary, { recursive: true, force: true }) + } + })() + try { + ledger = new AgentModelCallLedger(join(temporary, 'model-calls.sqlite')) + gateway = new AgentModelGateway({ ledger, fetcher: this.options.fetcher }) + await mkdir(history, { recursive: true }) + const origin = await proxy.listen() + const skills = input.skillPackages ?? [] + const mcp = input.workMode === 'execute' ? input.mcpServers ?? [] : [] + if (input.runtime === 'continue') { + // Reuse the pinned adapter's protocol, permission-order and Windows fixes. + const adapter = new ContinueHostAdapter({ binaryPath: detection.path, + configPath: '', workspace: input.directory, cacheRoot: temporary, mode: 'chat' }) + const prepared = await adapter.getPreparedHost() + const bundlePath = join(dirname(prepared.entryPath), 'index.js') + const bundle = await readFile(bundlePath, 'utf8') + const executionMarker = 'async function hti(e,t={parallelToolCallCount:1}){' + if (bundle.split(executionMarker).length !== 2) throw new Error('Continue native tool execution entry point is incompatible') + await writeFile(bundlePath, bundle.replace(executionMarker, `${executionMarker}if(${JSON.stringify(input.workMode)}==="ask"&&!${JSON.stringify(continueReadTools)}.includes(e.name))throw new Error("GoodBuddy Ask mode is read-only");`)) + args[0] = prepared.entryPath + const configured = input.settings.continueConfigPath.trim() + ? await loadContinueConfig(input.settings.continueConfigPath.trim()) : {} + const configPath = join(temporary, 'continue.json') + await writeFile(configPath, JSON.stringify({ + name: 'GoodBuddy Native Client', version: '1.0.0', schema: 'v1', + models: [{ name: selected.name, model: selected.modelName, + provider: selected.protocol === 'anthropic-messages' ? 'anthropic' : 'openai', + apiBase: `${origin}/v1`, apiKey: MODEL_BRIDGE_SDK_AUTH_SENTINEL, + roles: ['chat'], capabilities: selected.supportsImageInput ? ['image_input'] : [], + ...(selected.protocol !== 'anthropic-messages' ? { useResponsesApi: selected.protocol === 'openai-responses' } : {}) + }], + ...(configured.rules ? { rules: configured.rules } : {}), + ...(configured.prompts ? { prompts: configured.prompts } : {}), + mcpServers: mcp.map(server => ({ name: server.name, type: 'streamable-http', url: server.url, requestOptions: { headers: server.headers } })) + }), { mode: 0o600 }) + await stageRuntimeSkillPackages(history, skills, 'Continue') + Object.assign(env, { CONTINUE_GLOBAL_DIR: history, GOODBUDDY_DISABLE_CONTINUE_UPDATES: '1', CONTINUE_CLI_AUTO_UPDATED: '1', CONTINUE_CLI_ENABLE_TELEMETRY: '0', CONTINUE_METRICS_ENABLED: '0', CONTINUE_CLI_DISABLE_COMMIT_SIGNATURE: '1' }) + args.push('--config', configPath) + if (input.workMode === 'execute') args.push('--auto') + else args.push('--readonly', ...continueReadTools.flatMap(name => ['--allow', name]), '--exclude', '*') + } else { + const configDirectory = join(temporary, 'config') + if (this.options.bundledRuntimePaths.opencodeConfig) { + await cp(this.options.bundledRuntimePaths.opencodeConfig, configDirectory, { recursive: true }) + } + const skillsRoot = await stageRuntimeSkillPackages(configDirectory, skills, 'OpenCode') + const config = createOpenCodeModelBridgeProviderConfig({ + protocol: managed.profile.protocol, model: selected.modelName, name: selected.name, + loopbackOrigin: origin, supportsImageInput: selected.supportsImageInput, workMode: input.workMode + }) + const permission = input.workMode === 'execute' ? 'allow' : Object.fromEntries([ + ['*', 'deny'], ...openCodeReadTools.map(name => [name, 'allow']), ['skill', 'allow'] + ]) + // A tool hook keeps the launch mode fixed even when the TUI changes agents. + const pluginPath = join(temporary, 'work-mode.mjs') + await writeFile(pluginPath, `export default async () => ({'tool.execute.before': async ({tool}) => { if (${JSON.stringify(input.workMode)} === 'ask' && !${JSON.stringify([...openCodeReadTools, 'skill'])}.includes(tool)) throw new Error('GoodBuddy Ask mode is read-only'); }});`, { mode: 0o600 }) + Object.assign(env, { + OPENCODE_CONFIG_DIR: configDirectory, + OPENCODE_CONFIG_CONTENT: JSON.stringify({ ...config, permission, + agent: { ...config.agent, build: { permission }, plan: { permission } }, + plugin: [pathToFileURL(pluginPath).href], skills: { paths: [skillsRoot] }, + mcp: Object.fromEntries(mcp.map(server => [server.name, { type: 'remote', url: server.url, headers: server.headers, enabled: true }])) + }), + OPENCODE_DISABLE_AUTOUPDATE: '1', OPENCODE_DISABLE_PROJECT_CONFIG: '1', + OPENCODE_DISABLE_CLAUDE_CODE_SKILLS: '1', OPENCODE_DISABLE_EXTERNAL_SKILLS: '1', + OPENCODE_DISABLE_MODELS_FETCH: '1', OPENCODE_DISABLE_LSP_DOWNLOAD: '1', OPENCODE_DISABLE_SHARE: '1', + XDG_CONFIG_HOME: join(temporary, 'xdg-config'), XDG_CACHE_HOME: join(root, 'cache'), + XDG_DATA_HOME: join(history, 'data'), XDG_STATE_HOME: join(history, 'state') + }) + args.push('--model', config.model) + } + return { spawnSpec: { executable, args, cwd: input.directory, env, label: input.runtime }, title: `${input.runtime} · ${input.projectName}`, dispose } + } catch (error) { + await dispose() + throw error + } + } +} diff --git a/src/main/agent/runtime-discovery.test.ts b/src/main/agent/runtime-discovery.test.ts index c4298a10..5ffdab13 100644 --- a/src/main/agent/runtime-discovery.test.ts +++ b/src/main/agent/runtime-discovery.test.ts @@ -219,7 +219,7 @@ describe('runtime discovery', () => { binaryPath: '', bundledPath: bundledScript, bundledValidation: 'canonical-file', - bundledVersion: '0.1.2-rc.1', + bundledVersion: '0.1.7-rc.2', binaryNames: [], label: 'GoodBuddy DeepSeek Harness Host' }) @@ -227,7 +227,7 @@ describe('runtime discovery', () => { expect(detection).toMatchObject({ available: true, path: await realpath(bundledScript), - version: '0.1.2-rc.1', + version: '0.1.7-rc.2', source: 'bundled' }) expect(detection.detail).toContain('内置') diff --git a/src/main/capabilities/capability-ipc.ts b/src/main/capabilities/capability-ipc.ts new file mode 100644 index 00000000..6d73a056 --- /dev/null +++ b/src/main/capabilities/capability-ipc.ts @@ -0,0 +1,382 @@ +import { dialog, type BrowserWindow, type ipcMain } from 'electron' +import { z } from 'zod' +import { ipcChannels } from '../../shared/ipc-channels' +import { + browserProfileCreateInputSchema, + browserProfileRenameInputSchema, + browserProfileSelectionInputSchema, + builtinMcpServerAssignmentsInputSchema, + builtinMcpServerToggleInputSchema, + computerCapabilityConfigInputSchema, + computerCapabilityIdSchema, + computerCapabilityToggleInputSchema, + mcpServerIdSchema, + mcpServerInputSchema, + obsidianSettingsSchema, + obsidianConnectionTestResultSchema, + skillAssignmentsInputSchema, + skillIdSchema, + skillImportKindSchema, + skillToggleInputSchema, + type CapabilitySnapshot, + type CapabilityDiagnosticReport, + type McpServerTestResult, + type WebSearchTestResult +} from '../../shared/capability-contracts' +import { + runtimeExtensionActionSchema, + type RuntimeExtensionMarketplaceSnapshot +} from '../../shared/runtime-extension-contracts' +import type { KnowledgeMcpGateway } from '../agent/knowledge-mcp-gateway' +import type { RuntimeExtensionStore } from '../agent/runtime-extension-store' +import type { LocalToolEnvironmentService } from '../local-tool-environment' +import type { ObsidianService } from '../obsidian' +import { assertTrustedSender } from '../trusted-ipc-sender' +import type { CapabilityService } from './capability-service' +import { testMcpServer } from './mcp-tester' +import { testWebSearch } from './web-search-tester' + +const mcpServerSaveSchema = z + .object({ + serverId: mcpServerIdSchema.optional(), + input: mcpServerInputSchema + }) + .strict() + +export function registerCapabilityIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + { + capabilityService, + refreshCapabilities, + onRuntimeSettingsChanged, + runtimeExtensionStore, + knowledgeGateway, + obsidianService, + localToolEnvironmentService + }: { + capabilityService: CapabilityService + refreshCapabilities: ( + operation: Promise, + reconfigureRuntime?: boolean + ) => Promise + onRuntimeSettingsChanged: () => Promise + runtimeExtensionStore?: RuntimeExtensionStore + knowledgeGateway?: Pick + obsidianService?: Pick + localToolEnvironmentService?: Pick + } +): void { + registerHandler( + ipcChannels.capabilitiesSnapshot, + (event): Promise => { + assertTrustedSender(event, window) + return capabilityService.getSnapshot() + } + ) + + registerHandler( + ipcChannels.runtimeExtensionsSnapshot, + (event): Promise => { + assertTrustedSender(event, window) + if (!runtimeExtensionStore) { + throw new Error('DSH 插件市场不可用') + } + return runtimeExtensionStore.getSnapshot() + } + ) + + registerHandler( + ipcChannels.runtimeExtensionsApply, + async ( + event, + input: unknown + ): Promise => { + assertTrustedSender(event, window) + if (!runtimeExtensionStore) { + throw new Error('DSH 插件市场不可用') + } + const action = runtimeExtensionActionSchema.parse(input) + const result = + await runtimeExtensionStore.applyWithResult(action) + if ( + result.changed && + action.type !== 'set-marketplace-enabled' + ) { + await onRuntimeSettingsChanged() + } + return result.snapshot + } + ) + + registerHandler( + ipcChannels.capabilitiesImportSkill, + async (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const kind = skillImportKindSchema.parse(input) + const result = await dialog.showOpenDialog( + window, + kind === 'zip' + ? { + title: '选择 Skill ZIP 文件', + properties: ['openFile'], + filters: [{ name: 'Skill ZIP', extensions: ['zip'] }] + } + : { + title: '选择包含 SKILL.md 的目录', + properties: ['openDirectory'] + } + ) + if (result.canceled || !result.filePaths[0]) { + return capabilityService.getSnapshot() + } + return refreshCapabilities( + capabilityService.importSkill(result.filePaths[0]) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesRemoveSkill, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + return refreshCapabilities( + capabilityService.removeSkill(skillIdSchema.parse(input)) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesToggleSkill, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = skillToggleInputSchema.parse(input) + return refreshCapabilities( + capabilityService.setSkillEnabled( + value.skillId, + value.enabled + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesAssignSkill, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = skillAssignmentsInputSchema.parse(input) + return refreshCapabilities( + capabilityService.setSkillAssignments( + value.skillId, + value.assignments + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesUpdateObsidianSettings, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const settings = obsidianSettingsSchema.parse(input) + knowledgeGateway?.revokeObsidianCapabilities() + return refreshCapabilities( + capabilityService.updateObsidianSettings(settings) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesTestObsidianConnection, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const settings = obsidianSettingsSchema.parse(input) + if (!obsidianService) throw new Error('Obsidian 服务不可用') + return obsidianConnectionTestResultSchema.parse( + await obsidianService.testConnection(settings) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesSelectObsidianVault, + async (event): Promise => { + assertTrustedSender(event, window) + const result = await dialog.showOpenDialog(window, { + properties: ['openDirectory'] + }) + return result.canceled ? null : result.filePaths[0] ?? null + } + ) + + registerHandler( + ipcChannels.capabilitiesToggleBuiltinMcp, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = builtinMcpServerToggleInputSchema.parse(input) + if (value.serverId === 'obsidian') knowledgeGateway?.revokeObsidianCapabilities() + return refreshCapabilities( + capabilityService.setBuiltinMcpServerEnabled( + value.serverId, + value.enabled + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesAssignBuiltinMcp, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = builtinMcpServerAssignmentsInputSchema.parse(input) + if (value.serverId === 'obsidian') knowledgeGateway?.revokeObsidianCapabilities() + return refreshCapabilities( + capabilityService.setBuiltinMcpServerAssignments( + value.serverId, + value.assignments + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesSaveMcp, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = mcpServerSaveSchema.parse(input) + return refreshCapabilities( + capabilityService.saveMcpServer(value.serverId, value.input) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesRemoveMcp, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + return refreshCapabilities( + capabilityService.removeMcpServer( + mcpServerIdSchema.parse(input) + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesTestMcp, + async (event, input: unknown): Promise => { + assertTrustedSender(event, window) + return testMcpServer( + await capabilityService.getResolvedMcpServer( + mcpServerIdSchema.parse(input) + ), + undefined, + localToolEnvironmentService?.launchEnvironmentProvider + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesToggleWebSearch, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + return refreshCapabilities( + capabilityService.setWebSearchEnabled(z.boolean().parse(input)) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesTestWebSearch, + (event): Promise => { + assertTrustedSender(event, window) + return testWebSearch() + } + ) + + registerHandler( + ipcChannels.capabilitiesToggleComputer, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = computerCapabilityToggleInputSchema.parse(input) + return refreshCapabilities( + capabilityService.setComputerCapabilityEnabled( + value.capabilityId, + value.enabled + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesConfigureComputer, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = computerCapabilityConfigInputSchema.parse(input) + return refreshCapabilities( + capabilityService.setComputerCapabilityBrowserProfile( + value.capabilityId, + value.browserProfileId + ) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesDiagnoseComputer, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + return capabilityService.diagnoseComputerCapability( + computerCapabilityIdSchema.parse(input) + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesCreateBrowserProfile, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = browserProfileCreateInputSchema.parse(input) + return refreshCapabilities( + capabilityService.createBrowserProfile(value.name), + false + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesRenameBrowserProfile, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = browserProfileRenameInputSchema.parse(input) + return refreshCapabilities( + capabilityService.renameBrowserProfile(value.profileId, value.name), + false + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesDefaultBrowserProfile, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = browserProfileSelectionInputSchema.parse(input) + return refreshCapabilities( + capabilityService.setDefaultBrowserProfile(value.profileId), + false + ) + } + ) + + registerHandler( + ipcChannels.capabilitiesRemoveBrowserProfile, + (event, input: unknown): Promise => { + assertTrustedSender(event, window) + const value = browserProfileSelectionInputSchema.parse(input) + return refreshCapabilities( + capabilityService.removeBrowserProfile(value.profileId), + false + ) + } + ) +} diff --git a/src/main/deepseek-harness-host.test.ts b/src/main/deepseek-harness-host.test.ts index abc47aae..ddfe07ce 100644 --- a/src/main/deepseek-harness-host.test.ts +++ b/src/main/deepseek-harness-host.test.ts @@ -33,7 +33,7 @@ describe('controlled DeepSeek Harness host', () => { api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], dshHome: 'C:\\controlled-dsh-home', skillPackages: [] @@ -82,7 +82,7 @@ describe('controlled DeepSeek Harness host', () => { provider: 'goodbuddy', model: 'qwen-plus', supportsImageInput: true, - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [], stream: { @@ -103,7 +103,7 @@ describe('controlled DeepSeek Harness host', () => { command: 'echo goodbuddy-host-execution' }).workdir ).toBe(root) - const execution = await host.context.shell.run( + const processHandle = await host.context.shell.execute( host.context.shell.resolve({ command: process.platform === 'win32' @@ -111,6 +111,7 @@ describe('controlled DeepSeek Harness host', () => { : 'printf goodbuddy-host-execution' }) ) + const execution = await processHandle.result() expect(execution).toMatchObject({ exitCode: 0, timedOut: false, @@ -143,7 +144,7 @@ describe('controlled DeepSeek Harness host', () => { api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [], stream: { @@ -181,7 +182,7 @@ describe('controlled DeepSeek Harness host', () => { api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [], extensionPackages: [ @@ -237,7 +238,7 @@ describe('controlled DeepSeek Harness host', () => { api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [ { id: 'web-3d-game', directory: skillDirectory } @@ -256,7 +257,6 @@ describe('controlled DeepSeek Harness host', () => { isolate: ['skills', 'tools'] }) createdContext = agentContext - await options.setup?.(agentContext) const agent = { options: options.agentOptions ?? {}, session: { @@ -268,6 +268,7 @@ describe('controlled DeepSeek Harness host', () => { ctx: agentContext, cancel: vi.fn() } + await options.setup?.(agentContext, agent as never) createdAgent = agent as never return { agent, diff --git a/src/main/deepseek-harness-third-party-plugin.e2e.test.ts b/src/main/deepseek-harness-third-party-plugin.e2e.test.ts index 7c7b7136..5280b0fb 100644 --- a/src/main/deepseek-harness-third-party-plugin.e2e.test.ts +++ b/src/main/deepseek-harness-third-party-plugin.e2e.test.ts @@ -31,7 +31,7 @@ describe.skipIf(!entrypoint)( api: 'openai-completions', provider: 'goodbuddy', model: 'deepseek-test', - harnessVersion: '0.1.2-rc.1', + harnessVersion: '0.1.7-rc.2', credentialRefs: ['GOODBUDDY_API_KEY'], skillPackages: [], extensionPackages: [ diff --git a/src/main/index.ts b/src/main/index.ts index 633b9cb7..5e7ec0f2 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,4 +1,5 @@ import { localInferenceService } from './local-inference-service' +import { NativeClientCoordinator } from './agent/native-client-coordinator' import { createEmbeddingUtilityTransport } from './knowledge/embedding-utility-transport' import { app, @@ -229,6 +230,7 @@ let stopRuntimeReconfiguration: (() => Promise) | undefined let dshExtensionInstaller: DshNpmExtensionInstaller | undefined let remoteAgentServices: RemoteAgentServices | undefined let terminalSessionManager: TerminalSessionManager | undefined +let nativeClientCoordinator: NativeClientCoordinator | undefined let managedRemoteExecutionServices: | ManagedRemoteExecutionServices | undefined @@ -1424,6 +1426,22 @@ if (hasSingleInstanceLock) { } } }) + nativeClientCoordinator = new NativeClientCoordinator({ + database: startupAssistantDatabase, settingsStore, applicationSettingsStore, + capabilities: capabilityService, executionSpaceResolver, terminalManager: terminalSessionManager, + localEnvironment: startupLocalToolEnvironmentService, bundledRuntimePaths, + rootDirectory: join(app.getPath('userData'), 'native-clients'), + managedNodeDirectory: join(toolEnvironmentRoot, 'native-node-22.22.0'), + npmCliPath: npmCliPaths.npmCliPath, + resourcesPath: app.isPackaged ? process.resourcesPath : undefined, + openExternal: (url) => shell.openExternal(url), + createGateway: () => new KnowledgeMcpGateway(startupKnowledgeService, { + // This dedicated gateway lives until native-client disposal, not a chat request timeout. + now: () => 0, + magicNotesDatabase: startupAssistantDatabase, configService: goodbuddyConfigService, + obsidianService, launchEnvironmentProvider: startupLocalToolEnvironmentService.launchEnvironmentProvider + }) + }) removeIpcHandlers = registerIpcHandlers( mainWindow, runtime, @@ -1485,7 +1503,8 @@ if (hasSingleInstanceLock) { terminalSessionManager, startupLocalToolEnvironmentService, imageGenerationService, - obsidianService + obsidianService, + nativeClientCoordinator ) removeFeedbackIpcHandler = registerFeedbackIpcHandler( mainWindow, @@ -1583,6 +1602,7 @@ app.on('before-quit', (event) => { () => dshExtensionInstaller?.dispose(), () => imageGenerationService?.dispose(), () => knowledgeService?.beginShutdown(), + () => nativeClientCoordinator?.dispose(), () => removeIpcHandlers?.() ], [() => stopRuntimeReconfiguration?.()], diff --git a/src/main/ipc.test.ts b/src/main/ipc.test.ts index f3714fc0..e45becc5 100644 --- a/src/main/ipc.test.ts +++ b/src/main/ipc.test.ts @@ -80,14 +80,10 @@ describe('embedding IPC boundary', () => { describe('local tool environment IPC boundary', () => { it('trust-checks every operation and accepts only shared bounded schemas', async () => { - const source = await readFile( - join(process.cwd(), 'src', 'main', 'ipc.ts'), + const region = await readFile( + join(process.cwd(), 'src', 'main', 'local-tool-environment', 'local-tool-environment-ipc.ts'), 'utf8' ) - const region = - source.match( - /const requireLocalToolEnvironmentService[\s\S]*?registerHandler\(ipcChannels\.shortcutSettingsGet/u - )?.[0] ?? '' expect(region.match(/assertTrustedSender\(event, window\)/gu)).toHaveLength(8) expect(region).toContain('localToolEnvironmentSettingsSchema.parse(input)') expect(region).toContain('localToolKindInputSchema.parse(input)') @@ -335,6 +331,7 @@ const electronMocks = vi.hoisted(() => { const handlers = new Map() return { handlers, + invoke: vi.fn(), handle: vi.fn((channel: string, handler: InvokeHandler) => { handlers.set(channel, handler) }), @@ -1008,6 +1005,40 @@ describe('registerIpcHandlers computer capabilities', () => { ) expect(onRuntimeSettingsChanged).toHaveBeenCalledTimes(5) + const capabilityChannels = [ + ipcChannels.capabilitiesSnapshot, + ipcChannels.runtimeExtensionsSnapshot, + ipcChannels.runtimeExtensionsApply, + ipcChannels.capabilitiesImportSkill, + ipcChannels.capabilitiesRemoveSkill, + ipcChannels.capabilitiesToggleSkill, + ipcChannels.capabilitiesAssignSkill, + ipcChannels.capabilitiesUpdateObsidianSettings, + ipcChannels.capabilitiesTestObsidianConnection, + ipcChannels.capabilitiesSelectObsidianVault, + ipcChannels.capabilitiesToggleBuiltinMcp, + ipcChannels.capabilitiesAssignBuiltinMcp, + ipcChannels.capabilitiesSaveMcp, + ipcChannels.capabilitiesRemoveMcp, + ipcChannels.capabilitiesTestMcp, + ipcChannels.capabilitiesToggleWebSearch, + ipcChannels.capabilitiesTestWebSearch, + ipcChannels.capabilitiesToggleComputer, + ipcChannels.capabilitiesConfigureComputer, + ipcChannels.capabilitiesDiagnoseComputer, + ipcChannels.capabilitiesCreateBrowserProfile, + ipcChannels.capabilitiesRenameBrowserProfile, + ipcChannels.capabilitiesDefaultBrowserProfile, + ipcChannels.capabilitiesRemoveBrowserProfile + ] + const registrations = electronMocks.handle.mock.calls.map(([channel]) => channel) + const start = registrations.indexOf(ipcChannels.capabilitiesSnapshot) + expect(registrations.slice(start - 1, start + capabilityChannels.length + 1)).toEqual([ + ipcChannels.expertsRemove, + ...capabilityChannels, + ipcChannels.contextSelectFiles + ]) + expect(() => electronMocks.handlers.get( ipcChannels.capabilitiesDiagnoseComputer @@ -1020,6 +1051,10 @@ describe('registerIpcHandlers computer capabilities', () => { ) ).toThrow('拒绝来自未知窗口的 IPC 请求') await dispose() + for (const channel of capabilityChannels) { + expect(electronMocks.removeHandler).toHaveBeenCalledWith(channel) + expect(electronMocks.handlers.has(channel)).toBe(false) + } }) }) @@ -1329,6 +1364,9 @@ describe('registerIpcHandlers model download source routing', () => { }) vi.mock('electron', () => ({ + contextBridge: { exposeInMainWorld: (name: string, value: unknown) => vi.stubGlobal(name, value) }, + ipcRenderer: { invoke: electronMocks.invoke }, + webUtils: {}, nativeImage: { createFromBuffer: (buffer: Buffer) => ({ isEmpty: () => false, toPNG: () => buffer }) }, app: { getAppPath: vi.fn(() => process.cwd()), @@ -5116,7 +5154,9 @@ describe('registerIpcHandlers agent terminal state', () => { imageService?: ImageGenerationService, imageDatabase?: AssistantDatabase, heartbeatEnabled?: boolean, - obsidianService?: ObsidianService + obsidianService?: ObsidianService, + nativeClientCoordinator?: Parameters[45], + nativeTerminalManager?: Parameters[41] ) { const assistantDatabase = { createTask: vi.fn(), @@ -5240,7 +5280,10 @@ describe('registerIpcHandlers agent terminal state', () => { id: 9, mainFrame: { url: 'file:///goodbuddy/index.html' }, getURL: vi.fn(() => 'file:///goodbuddy/index.html'), - send: vi.fn() + send: vi.fn(), + once: vi.fn(), + removeListener: vi.fn(), + isDestroyed: vi.fn(() => false) } const window = { webContents, @@ -5348,6 +5391,8 @@ describe('registerIpcHandlers agent terminal state', () => { ] args[43] = imageService args[44] = obsidianService + args[45] = nativeClientCoordinator + args[41] = nativeTerminalManager const dispose = registerIpcHandlers(...args) return { approvalBroker, @@ -5952,6 +5997,35 @@ describe('registerIpcHandlers agent terminal state', () => { } finally { finish(); await harness.dispose(); database.close() } }) + it('routes native clients through validated owner-scoped IPC and cleans up the window', async () => { + const coordinator = { + open: vi.fn(async () => ({ kind: 'browser' as const, serviceId: 'native-service' })), + get: vi.fn(async () => ({ serviceId: 'native-service' })), + stop: vi.fn(async () => {}), + closeOwner: vi.fn(async () => {}) + } + const harness = createHarness({}, undefined, 'always', undefined, false, undefined, + undefined, undefined, false, undefined, undefined, undefined, undefined, undefined, false, undefined, coordinator) + const event = trustedEvent(harness.webContents) + const input = { conversationId: '00000000-0000-4000-8000-000000000401' } + const open = electronMocks.handlers.get(ipcChannels.runtimeNativeClientOpen)! + const get = electronMocks.handlers.get(ipcChannels.runtimeNativeClientGet)! + const stop = electronMocks.handlers.get(ipcChannels.runtimeNativeClientStop)! + await expect(open(event, input)).resolves.toEqual({ kind: 'browser', serviceId: 'native-service' }) + expect(coordinator.open).toHaveBeenCalledWith(9, input.conversationId) + await expect(get(event, input)).resolves.toEqual({ serviceId: 'native-service' }) + expect(coordinator.get).toHaveBeenCalledWith(9, input.conversationId) + await stop(event, { serviceId: 'native-service' }) + expect(coordinator.stop).toHaveBeenCalledWith(9, 'native-service') + await expect(open(event, { ...input, runtime: 'continue' })).rejects.toThrow() + await expect(open({ ...event, sender: { id: 99 } }, input)).rejects.toThrow() + await expect(stop(event, { serviceId: '' })).rejects.toThrow() + expect(coordinator.open).toHaveBeenCalledTimes(1) + expect(harness.webContents.once).toHaveBeenCalledWith('destroyed', expect.any(Function)) + await harness.dispose() + expect(coordinator.closeOwner).toHaveBeenCalledWith(9) + }) + it('production supervision IPC pauses in-flight work and resumes saved batches without replaying them', async () => { const database = new AssistantDatabase(':memory:') database.initialize(process.cwd()) @@ -8637,6 +8711,179 @@ describe('registerIpcHandlers agent terminal state', () => { } }) + it.skipIf(!process.env.GOODBUDDY_NATIVE_CLIENT_INTEGRATION)('opens and stops official native clients from the real UI through preload, IPC and saved project settings', async () => { + const { createElement } = await import('react') + const { render, fireEvent, waitFor, cleanup } = await import('@testing-library/react/pure') + const rendererModule = '../renderer/src/RuntimeNativeClientActions' + const { RuntimeNativeClientActions } = await import(rendererModule) as { + RuntimeNativeClientActions: import('react').ComponentType<{ + browser: boolean; contextKey: string; conversationId: string; prepareConversation: () => Promise + onTerminal: (value: import('../shared/terminal-contracts').TerminalSnapshot) => void; notify: (value: unknown) => void + }> + } + const { default: i18n } = await import('i18next') + const { NativeClientCoordinator } = await import('./agent/native-client-coordinator') + const { RuntimeSettingsStore } = await import('./runtime-settings-store') + const { ApplicationSettingsStore } = await import('./application-settings-store') + const { ExecutionSpaceResolver } = await import('./execution-space/execution-space-resolver') + const { KnowledgeMcpGateway } = await import('./agent/knowledge-mcp-gateway') + const { TerminalSessionManager } = await import('./terminal/terminal-session-manager') + const { resolveNpmCliPaths } = await import('./local-tool-environment') + const { resolveBundledRuntimePaths } = await import('./agent/bundled-runtimes') + const root = await mkdtemp(join(tmpdir(), 'goodbuddy-native-ui-')) + const database = new AssistantDatabase(join(root, 'assistant.sqlite')) + const liveModule = process.env.GOODBUDDY_NATIVE_CLIENT_LIVE_MODULE + const { createRequire } = await import('node:module') + const live = liveModule ? createRequire(import.meta.url)(liveModule) as { + begin: (fetcher: typeof fetch) => typeof fetch + profile: (runtime: string) => import('./runtime-settings-store').ResolvedModelProfile + web: (url: string, workspace: string) => Promise + terminal: (runtime: string, write: (data: string) => Promise, output: () => string) => Promise + finish: () => Promise + } : undefined + if (live) vi.stubGlobal('fetch', live.begin(fetch)) + let coordinator: InstanceType | undefined + let harness: ReturnType | undefined + let terminalManager: InstanceType | undefined + try { + database.initialize(root) + const secrets = new Map() + const cipher = { isAvailable: () => true, + encrypt: (value: string) => { const id = crypto.randomUUID(); secrets.set(id, value); return Buffer.from(id) }, + decrypt: (value: Buffer) => secrets.get(value.toString())! } + const settingsStore = new RuntimeSettingsStore(join(root, 'settings.json'), cipher, {}) + const profileId = '00000000-0000-4000-8000-000000000221' + const inputDefaults = { ...defaultRuntimeSettings } as Record + delete inputDefaults.supportsImageInput + const selectedProfile = live?.profile('deepseek-harness') + await settingsStore.update(runtimeSettingsInputSchema.parse({ ...inputDefaults, apiKey: { action: 'keep' }, + provider: 'deepseek-harness', workspacePath: root, + modelProfiles: [{ name: 'Native UI Test', baseUrl: 'http://127.0.0.1:1', modelName: 'native-ui-model', + protocol: 'openai-chat-completions', authentication: 'api-key', imageGenerationQuality: 'auto', + ...selectedProfile, id: profileId, apiKey: { action: 'replace', value: selectedProfile?.apiKey ?? 'native-ui-secret' } }], + defaultModelProfileId: profileId, deepseekHarnessModelSource: { kind: 'profile', profileId } + })) + const project = database.createProject({ name: 'Native UI', description: '', rootPath: root, + defaultWorkMode: 'ask', runtimeSelection: { provider: 'deepseek-harness', profileId } }) + const conversationId = '00000000-0000-4000-8000-000000000222' + const now = Date.now() + const save = async (): Promise => { + database.saveLocalConversations([{ header: { id: conversationId, projectId: project.id, title: 'Native UI', updatedAt: now }, messages: [] }]) + return conversationId + } + await save() + const capabilities = new CapabilityService(join(root, 'capabilities.json'), join(root, 'builtin'), join(root, 'imported'), cipher) + const opened: string[] = [] + const terminalEvents: import('../shared/terminal-contracts').TerminalEvent[] = [] + terminalManager = new TerminalSessionManager({ database, executionSpaceResolver: new ExecutionSpaceResolver(), + targetResolver: {} as never, sshPool: {} as never, remoteEnabled: () => false, + deliverEvent: (ownerId, event) => { + expect(ownerId).toBe(9) + terminalEvents.push(event) + terminalManager!.acknowledge(ownerId, event.sessionId, event.sequence) + } + }) + const applicationSettingsStore = new ApplicationSettingsStore(join(root, 'application.json')) + if (process.env.NATIVE_DSH_TEST_NODE) await applicationSettingsStore.update({ + localToolEnvironment: { ...(await applicationSettingsStore.get()).localToolEnvironment, + node: { source: 'custom', executablePath: process.env.NATIVE_DSH_TEST_NODE } } + }) + coordinator = new NativeClientCoordinator({ database, settingsStore, + applicationSettingsStore, + capabilities, executionSpaceResolver: new ExecutionSpaceResolver(), terminalManager, + localEnvironment: { launchEnvironmentProvider: () => process.env } as never, + rootDirectory: join(root, 'clients'), managedNodeDirectory: join(root, 'node'), + bundledRuntimePaths: resolveBundledRuntimePaths({ appPath: process.cwd(), resourcesPath: '', packaged: false }), + npmCliPath: resolveNpmCliPaths({ appPath: process.cwd(), resourcesPath: '', packaged: false }).npmCliPath, + createGateway: () => new KnowledgeMcpGateway({} as never, { now: () => 0 }), + openExternal: async (url) => { opened.push(url) } + }) + harness = createHarness({}, undefined, 'always', undefined, false, undefined, undefined, undefined, + false, undefined, undefined, undefined, undefined, undefined, false, undefined, coordinator, terminalManager) + const event = trustedEvent(harness.webContents) + electronMocks.invoke.mockImplementation((channel: string, input: unknown) => electronMocks.handlers.get(channel)!(event, input)) + await import('../preload/index') + const notify = vi.fn() + const view = render(createElement(RuntimeNativeClientActions, { browser: true, contextKey: project.id, + conversationId, prepareConversation: save, onTerminal: vi.fn(), notify })) + fireEvent.click(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.browser') })) + await waitFor(() => { + expect(notify).not.toHaveBeenCalled() + expect(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.reopen') })).toBeEnabled() + }, { timeout: 120_000 }) + expect(opened).toHaveLength(1) + const handle = await coordinator.get(9, conversationId) + expect(handle?.serviceId).toBeTruthy() + expect(await coordinator.get(10, conversationId)).toBeNull() + await coordinator.stop(10, handle!.serviceId) + expect(await coordinator.get(9, conversationId)).toEqual(handle) + database.saveLocalConversations([{ header: { id: conversationId, projectId: project.id, title: 'Native UI', updatedAt: now + 1, workMode: 'execute' }, messages: [] }]) + expect(await coordinator.get(9, conversationId)).toBeNull() + database.saveLocalConversations([{ header: { id: conversationId, projectId: project.id, title: 'Native UI', updatedAt: now + 2, workMode: 'ask' }, messages: [] }]) + expect(await coordinator.get(9, conversationId)).toEqual(handle) + const config = await readFile(join(root, 'clients', 'dsh', handle!.serviceId, 'cordis.patch.yml'), 'utf8') + expect(config).toContain(selectedProfile?.modelName ?? 'native-ui-model') + expect(config).not.toContain('native-ui-secret') + if (selectedProfile?.apiKey) expect(config).not.toContain(selectedProfile.apiKey) + const auth = await fetch(opened[0]!, { redirect: 'manual' }) + expect(auth.status).toBe(303) + const cookie = auth.headers.getSetCookie().map(value => value.split(';')[0]).join('; ') + const page = await fetch(new URL('/', opened[0]!), { headers: { cookie } }) + expect(page.status).toBe(200) + expect(await page.text()).toContain(' expect(opened).toHaveLength(2)) + expect(await coordinator.get(9, conversationId)).toEqual(handle) + await waitFor(() => expect(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.stop') })).toBeEnabled()) + fireEvent.click(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.stop') })) + fireEvent.click(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.confirmStop') })) + await waitFor(() => expect(view.queryByRole('button', { name: i18n.t('app:composer.nativeClient.stop') })).not.toBeInTheDocument(), { timeout: 10_000 }) + expect(await coordinator.get(9, conversationId)).toBeNull() + await expect(fetch(new URL('/', opened[0]!))).rejects.toThrow() + + const terminals: import('../shared/terminal-contracts').TerminalSnapshot[] = [] + for (const provider of ['continue', 'opencode'] as const) { + if (live) { + const profile = live.profile(provider) + await settingsStore.update(runtimeSettingsInputSchema.parse({ ...inputDefaults, apiKey: { action: 'keep' }, + provider, workspacePath: root, defaultModelProfileId: profileId, + modelProfiles: [{ ...profile, id: profileId, imageGenerationQuality: 'auto', apiKey: { action: 'replace', value: profile.apiKey } }], + [`${provider}ModelSource`]: { kind: 'profile', profileId } + })) + } + database.updateProject(project.id, { ...project, runtimeSelection: { provider, profileId } }) + const onTerminal = vi.fn<(value: import('../shared/terminal-contracts').TerminalSnapshot) => void>() + notify.mockClear() + view.rerender(createElement(RuntimeNativeClientActions, { browser: false, contextKey: `${project.id}:${provider}`, + conversationId, prepareConversation: save, onTerminal, notify })) + fireEvent.click(view.getByRole('button', { name: i18n.t('app:composer.nativeClient.terminal') })) + await waitFor(() => { + expect(notify).not.toHaveBeenCalled() + expect(onTerminal).toHaveBeenCalledWith(expect.objectContaining({ state: 'running', workingDirectory: root })) + }, { timeout: 30_000 }) + const terminal = onTerminal.mock.calls[0]![0] + terminals.push(terminal) + await waitFor(() => expect(terminalEvents.some(event => event.sessionId === terminal.sessionId && event.type === 'output' && /Continue|OpenCode|opencode|Native UI Test|native-ui-model/u.test(event.data))).toBe(true), { timeout: 20_000 }) + await live?.terminal(provider, + data => (globalThis as unknown as { goodbuddy: import('../shared/contracts').DesktopApi }).goodbuddy.terminal.write({ sessionId: terminal.sessionId, data }), + () => terminalEvents.flatMap(event => event.sessionId === terminal.sessionId && event.type === 'output' ? [event.data] : []).join('')) + } + await harness.dispose() + harness = undefined + for (const terminal of terminals) expect(() => terminalManager!.snapshot(9, terminal.sessionId)).toThrow() + } finally { + cleanup() + vi.unstubAllGlobals() + await harness?.dispose() + await coordinator?.dispose() + await terminalManager?.dispose() + database.close() + await rm(root, { recursive: true, force: true }) + await live?.finish() + } + }, 360_000) + it('tests an unsaved Obsidian UI draft through registered IPC and bundled MCPVault, then saves and refreshes', async () => { const { createElement } = await import('react') const { render, fireEvent, waitFor, cleanup } = await import('@testing-library/react/pure') diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 454974ed..5ee9fba6 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -1,18 +1,18 @@ -import { externalKnowledgeInstanceInputSchema, externalKnowledgeInstanceEnabledInputSchema, externalKnowledgeInstanceSaveInputSchema, externalKnowledgeCatalogListInputSchema, externalKnowledgeCatalogGetInputSchema, externalKnowledgeBindingSaveInputSchema, externalKnowledgeBindingUpdateInputSchema, externalKnowledgeBindingTestInputSchema } from '../shared/external-knowledge-contracts' +import { registerKnowledgeIpcHandlers } from './knowledge/knowledge-ipc' import { knowledgeReferenceKey, toKnowledgeReference } from '../shared/knowledge-reference' import { localInferenceService } from './local-inference-service' import { inferenceActionSchema, inferenceCancelSchema } from '../shared/local-inference-contracts' +import type { NativeClientCoordinator } from './agent/native-client-coordinator' +import { runtimeNativeClientInputSchema, runtimeNativeClientServiceSchema, runtimeNativeClientResultSchema } from '../shared/runtime-native-client-contracts' import { app, BrowserWindow, - clipboard, dialog, ipcMain, shell, type IpcMainInvokeEvent } from 'electron' import { - lstat, mkdir, readFile, realpath, @@ -47,17 +47,9 @@ import { browserStopLoadingRequestSchema, browserStopRequestSchema, browserTypeRequestSchema, - clipboardTextSchema, contextImportFilesSchema, conversationQueueUserInputSchema, defaultRuntimeSettings, - knowledgeCreateSchema, - knowledgeEntityUpdateSchema, - knowledgeIdSchema, - knowledgeImportPathsSchema, - knowledgeRelationInputSchema, - knowledgeUpdateLibrarySchema, - knowledgeUrlImportSchema, isAgentRuntimeModelProtocol, modelProfileIdSchema, pastedImageInputSchema, @@ -82,64 +74,18 @@ import { type ConversationQueueDispatch, type ConversationQueueUserInput, type KnowledgeSearchReference, - type KnowledgeSnapshot, type RuntimeSettings } from '../shared/contracts' import { stripKnowledgeHighlightTags } from '../shared/knowledge-text' -import { - knowledgeChunkDeleteInputSchema, - knowledgeChunkPageSchema, - knowledgeChunksListInputSchema, - knowledgeChunkUpdateInputSchema, - knowledgeDocumentOpenInputSchema, - knowledgeDocumentRebuildInputSchema, - knowledgeLibraryRebuildInputSchema, - knowledgeReferenceContextInputSchema, - knowledgeReferenceContextSchema, - knowledgeReferenceOpenInputSchema, - knowledgeRetrieveInputSchema, - knowledgeRetrievalResponseSchema, - knowledgeSettingsUpdateInputSchema, - type KnowledgeRetrievalResponse -} from '../shared/knowledge-contracts' -import { - knowledgeTaskActionInputSchema, - knowledgeTaskItemSchema -} from '../shared/knowledge-task-contracts' +import type { KnowledgeRetrievalResponse } from '../shared/knowledge-contracts' import { ipcChannels } from '../shared/ipc-channels' +import { registerTerminalIpcHandlers } from './terminal/terminal-ipc' import { - terminalAckRequestSchema, - terminalCloseRequestSchema, - terminalCreateRequestSchema, - terminalResizeRequestSchema, - terminalSnapshotRequestSchema, - terminalWriteRequestSchema -} from '../shared/terminal-contracts' -import { - browserProfileCreateInputSchema, - browserProfileRenameInputSchema, - browserProfileSelectionInputSchema, - builtinMcpServerAssignmentsInputSchema, builtinMcpServerIdSchema, - builtinMcpServerToggleInputSchema, - computerCapabilityConfigInputSchema, - computerCapabilityIdSchema, - computerCapabilityToggleInputSchema, - mcpServerIdSchema, - mcpServerInputSchema, - obsidianSettingsSchema, - obsidianConnectionTestResultSchema, - skillAssignmentsInputSchema, - skillIdSchema, - skillImportKindSchema, - skillToggleInputSchema, runtimeTargetSchema, type BuiltinMcpServerId, type CapabilitySnapshot, - type CapabilityDiagnosticReport, - type McpServerTestResult, - type ObsidianSettings, - type WebSearchTestResult + type ObsidianSettings } from '../shared/capability-contracts' import { channelSettingsApplySchema, @@ -148,12 +94,8 @@ import { } from '../shared/channel-settings-contracts' import { applicationSettingsUpdateSchema, defaultSupervisionTimeoutSeconds, defaultSupervisorModelConcurrency } from '../shared/application-settings-contracts' import { SupervisionModelPool } from './assistant/supervision-model-pool' -import { - localToolDiagnoseInputSchema, - localToolEnvironmentProgressSchema, - localToolEnvironmentSettingsSchema, - localToolKindInputSchema -} from '../shared/local-tool-environment-contracts' +import { localToolEnvironmentProgressSchema } from '../shared/local-tool-environment-contracts' +import { registerLocalToolEnvironmentIpcHandlers } from './local-tool-environment/local-tool-environment-ipc' import { agentPackageArchitectureRequestSchema, agentPackageDownloadProgressSchema, @@ -176,10 +118,7 @@ import { embeddingModelInstallInputSchema, embeddingModelProgressSnapshotSchema, embeddingModelSnapshotSchema, - embeddingSettingsSnapshotSchema, - knowledgeEmbeddingIndexCancelRequestSchema, - knowledgeEmbeddingIndexRequestSchema, - knowledgeEmbeddingIndexSnapshotSchema + embeddingSettingsSnapshotSchema } from '../shared/embedding-contracts' import { documentOcrModelActionInputSchema, @@ -195,20 +134,8 @@ import { getDefaultRuntimeSelection, type AgentRuntimeSelection } from '../shared/runtime-selection-contracts' -import { - magicNoteAnalyzeSchema, - magicNoteCreateSchema, - magicNoteSearchSchema, - type MagicNoteSource, - magicNoteDeleteSchema, - magicNoteDraftAnalyzeSchema, - magicNoteEntryCreateSchema, - magicNoteEntryDeleteSchema, - magicNoteEntryUpdateSchema, - magicNoteUpdateSchema, - magicTodoIdSchema, - magicTodoUpdateSchema -} from '../shared/magic-notes-contracts' +import { registerMagicNotesAnalysisIpcHandlers, registerMagicTodosAnalysisIpcHandlers } from './magic-notes/magic-notes-analysis-ipc' +import { registerMagicNotesIpcHandlers, registerMagicTodosIpcHandlers } from './magic-notes/magic-notes-ipc' import { assistantIdSchema, executionStatsInputSchema, @@ -247,7 +174,6 @@ import type { } from './agent/runtime' import { detectAgentRuntimes } from './agent/runtime-discovery' import { - createDefaultModelRuntime, createModelProfileRuntime } from './agent/create-runtime' import { @@ -271,12 +197,7 @@ import { type KnowledgeMcpGateway } from './agent/knowledge-mcp-gateway' import type { CapabilityService } from './capabilities/capability-service' -import { testMcpServer } from './capabilities/mcp-tester' -import { testWebSearch } from './capabilities/web-search-tester' -import { - runtimeExtensionActionSchema, - type RuntimeExtensionMarketplaceSnapshot -} from '../shared/runtime-extension-contracts' +import { registerCapabilityIpcHandlers } from './capabilities/capability-ipc' import type { RuntimeExtensionStore } from './agent/runtime-extension-store' import type { ShortcutSettingsService } from './shortcut-settings-service' import { @@ -331,7 +252,7 @@ import { } from './knowledge/document-parser' import type { RuntimeSettingsStore } from './runtime-settings-store' import type { ToolApprovalBroker } from './tool-approval-broker' -import { showWindow } from './window' +import { registerClipboardIpcHandlers, registerWindowIpcHandlers } from './window-ipc' import type { AssistantDatabase, RecoverableRemoteTask @@ -400,17 +321,8 @@ import type { GoodBuddyConfigApplyEvent, GoodBuddyConfigService } from './goodbuddy-config-service' -import { - magicNotePlainText, - validateMagicNoteContent -} from './magic-notes/rich-content' import { weixinVerificationInputSchema } from '../shared/weixin-channel-contracts' import type { RemoteChannelActivity } from '../shared/remote-channel-contracts' -import { - analyzeMagicNoteDraft, - analyzeMagicNoteEntry, - analyzeMagicTodo -} from './magic-notes/magic-note-analyzer' import { AgentEventBuffer } from './agent-event-buffer' import { withImageConversationContext } from './agent/image-conversation-context' import type { ImageGenerationService } from './agent/image-generation-service' @@ -906,66 +818,6 @@ function createSafeHtmlPreview(source: string): string { '' return `${policy}${withoutDangerousElements}` } -const mcpServerSaveSchema = z - .object({ - serverId: mcpServerIdSchema.optional(), - input: mcpServerInputSchema - }) - .strict() -const knowledgeSearchSchema = z - .object({ - libraryIds: z.array(knowledgeIdSchema).max(20), - query: z.string().trim().min(1).max(512) - }) - .strict() -const knowledgeSelectionSchema = z - .object({ - libraryId: knowledgeIdSchema, - graphStrategy: z.enum(['rules', 'model', 'hybrid']).optional() - }) - .strict() -const knowledgeEntityPayloadSchema = z - .object({ - entityId: knowledgeIdSchema, - update: knowledgeEntityUpdateSchema - }) - .strict() -const knowledgeCreateEntitySchema = z - .object({ - libraryId: knowledgeIdSchema, - input: knowledgeEntityUpdateSchema - }) - .strict() -const knowledgeMoveEntitySchema = z - .object({ - entityId: knowledgeIdSchema, - position: z - .object({ - x: z.number().finite().min(-100_000).max(100_000), - y: z.number().finite().min(-100_000).max(100_000) - }) - .strict() - }) - .strict() -const knowledgeMergeSchema = z - .object({ - sourceEntityId: knowledgeIdSchema, - targetEntityId: knowledgeIdSchema - }) - .strict() -const knowledgeCreateRelationSchema = z - .object({ - libraryId: knowledgeIdSchema, - input: knowledgeRelationInputSchema - }) - .strict() -const knowledgeUpdateRelationSchema = z - .object({ - relationId: knowledgeIdSchema, - input: knowledgeRelationInputSchema - }) - .strict() - function sendValidatedProgress( owner: { isDestroyed(): boolean }, channel: string, @@ -1018,132 +870,6 @@ async function readArtifactImportFile( ) } -function getKnowledgeSnapshot( - service: KnowledgeService, - selectedLibraryId?: string -): KnowledgeSnapshot { - const snapshot = service.snapshot(selectedLibraryId) - const activeLibraryId = - selectedLibraryId ?? snapshot.libraries[0]?.id - const documentsById = new Map( - snapshot.documents.map((document) => [document.id, document]) - ) - const evidenceByEntity = new Map() - const evidenceByRelation = new Map() - for (const item of snapshot.evidence) { - if (item.entityId) { - evidenceByEntity.set(item.entityId, [ - ...(evidenceByEntity.get(item.entityId) ?? []), - item.id - ]) - } - if (item.relationId) { - evidenceByRelation.set(item.relationId, [ - ...(evidenceByRelation.get(item.relationId) ?? []), - item.id - ]) - } - } - const bindingsByLibraryId = new Map( - service.database.externalStore - .listBindings() - .map((binding) => [binding.knowledgeBaseId, binding]) - ) - return { - libraries: snapshot.libraries.map((library) => ({ - kind: bindingsByLibraryId.has(library.id) ? 'external' : 'local', - external: bindingsByLibraryId.get(library.id), - id: library.id, - name: library.name, - description: library.description ?? '', - storageMode: library.storageMode, - graphEnabled: library.graphEnabled, - graphStrategy: library.graphStrategy, - sourceCount: library.sourceCount, - documentCount: library.documentCount, - indexedDocumentCount: library.indexedDocumentCount, - processingDocumentCount: library.processingDocumentCount, - failedDocumentCount: library.failedDocumentCount, - retrievalSettings: library.retrievalSettings, - chunkingSettings: library.chunkingSettings, - chunkingRebuildRequired: library.chunkingRebuildRequired, - ontologySettings: library.ontologySettings, - ontologyRebuildRequired: library.ontologyRebuildRequired, - updatedAt: library.updatedAt - })), - selectedLibraryId: activeLibraryId, - sources: snapshot.sources.map((source) => ({ - id: source.id, - libraryId: source.knowledgeBaseId, - name: source.displayName, - kind: source.type, - location: source.location, - status: - source.status === 'pending' - ? 'queued' - : source.status === 'indexing' - ? 'syncing' - : source.status === 'error' - ? 'failed' - : source.status, - progress: source.progress, - documentCount: source.documentCount, - lastSyncedAt: source.lastSyncedAt, - error: source.lastError - })), - documents: snapshot.documents.map((document) => ({ - id: document.id, - libraryId: document.knowledgeBaseId, - sourceId: document.sourceId, - name: document.title, - resultId: typeof document.metadata.parsedResultId === 'string' ? document.metadata.parsedResultId : undefined, - path: document.sourceLocation, - status: document.status, - textIndexStatus: document.textIndexStatus, - vectorIndexStatus: document.vectorIndexStatus, - graphIndexStatus: document.graphIndexStatus, - indexProgress: document.status === 'ready' ? 100 : 0, - chunkCount: document.chunkCount, - size: document.size, - updatedAt: document.updatedAt, - error: document.error - })), - graphNodes: snapshot.entities.map((entity, index) => ({ - id: entity.id, - label: entity.name, - type: entity.type, - description: entity.description, - aliases: entity.aliases, - x: - typeof entity.properties.x === 'number' - ? entity.properties.x - : 120 + (index % 5) * 150, - y: - typeof entity.properties.y === 'number' - ? entity.properties.y - : 100 + Math.floor(index / 5) * 120, - evidenceIds: evidenceByEntity.get(entity.id) - })), - graphRelations: snapshot.relations.map((relation) => ({ - id: relation.id, - sourceId: relation.sourceEntityId, - targetId: relation.targetEntityId, - type: relation.type, - description: relation.label, - evidenceIds: evidenceByRelation.get(relation.id) - })), - evidence: snapshot.evidence.map((item) => ({ - id: item.id, - documentId: item.documentId, - documentName: - documentsById.get(item.documentId)?.title ?? '未知文档', - excerpt: item.quote ?? '', - location: item.location - })), - tasks: snapshot.tasks.map((task) => knowledgeTaskItemSchema.parse(task)) - } -} - function buildForcedKnowledgeEvidence( entries: ReadonlyArray<{ libraryId: string @@ -1385,7 +1111,8 @@ export function registerIpcHandlers( terminalSessionManager?: TerminalSessionManager, localToolEnvironmentService?: LocalToolEnvironmentService, imageGenerationService?: ImageGenerationService, - obsidianService?: ObsidianService + obsidianService?: ObsidianService, + nativeClientCoordinator?: Pick ): () => Promise { type ActiveRequestLease = { controller: AbortController @@ -1407,12 +1134,6 @@ export function registerIpcHandlers( } await activateRuntimeSettings() } - const requireTerminalSessionManager = (): TerminalSessionManager => { - if (!terminalSessionManager) { - throw new Error('终端服务不可用') - } - return terminalSessionManager - } const activeRequestConversations = new Map< string, ActiveRequestLease @@ -3586,15 +3307,7 @@ export function registerIpcHandlers( } }) - registerHandler(ipcChannels.clipboardReadText, (event) => { - assertTrustedSender(event, window) - return clipboardTextSchema.parse(clipboard.readText()) - }) - - registerHandler(ipcChannels.clipboardWriteText, (event, input) => { - assertTrustedSender(event, window) - clipboard.writeText(clipboardTextSchema.parse(input)) - }) + registerClipboardIpcHandlers(registerHandler, window) registerHandler( ipcChannels.appRendererPersistenceReady, @@ -3615,39 +3328,7 @@ export function registerIpcHandlers( false ) - registerHandler(ipcChannels.appShow, (event) => { - assertTrustedSender(event, window) - showWindow(window) - }) - - registerHandler(ipcChannels.appHide, (event) => { - assertTrustedSender(event, window) - window.hide() - }) - - registerHandler(ipcChannels.windowMinimize, (event) => { - assertTrustedSender(event, window) - window.minimize() - }) - - registerHandler(ipcChannels.windowToggleMaximize, (event) => { - assertTrustedSender(event, window) - if (window.isMaximized()) { - window.unmaximize() - } else { - window.maximize() - } - }) - - registerHandler(ipcChannels.windowClose, (event) => { - assertTrustedSender(event, window) - window.close() - }) - - registerHandler(ipcChannels.windowIsMaximized, (event): boolean => { - assertTrustedSender(event, window) - return window.isMaximized() - }) + registerWindowIpcHandlers(registerHandler, window) registerHandler(ipcChannels.appClearLocalData, (event) => { assertTrustedSender(event, window) @@ -3960,91 +3641,39 @@ export function registerIpcHandlers( } ) - registerHandler( - ipcChannels.terminalCreate, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const snapshot = await manager.create( - event.sender.id, - terminalCreateRequestSchema.parse(input) - ) + const nativeClientOwnerId = window.webContents.id + const closeNativeClients = (): void => { + void nativeClientCoordinator?.closeOwner(nativeClientOwnerId).catch(error => console.error('Native client cleanup failed', error)) + } + if (nativeClientCoordinator) window.webContents.once('destroyed', closeNativeClients) + registerHandler(ipcChannels.runtimeNativeClientOpen, async (event, input: unknown) => { + assertTrustedSender(event, window) + const request = runtimeNativeClientInputSchema.parse(input) + if (executionPaused || shuttingDown) throw new Error('Native client launch is unavailable during shutdown or data maintenance') + if (!nativeClientCoordinator) throw new Error('Native client service is unavailable') + const result = runtimeNativeClientResultSchema.parse(await nativeClientCoordinator.open(event.sender.id, request.conversationId)) + if (result.kind === 'terminal') { setImmediate(() => { - if ( - !window.isDestroyed() && - event.sender === window.webContents && - !event.sender.isDestroyed() - ) { - manager.enableEventDelivery( - event.sender.id, - snapshot.sessionId - ) + if (!window.isDestroyed() && event.sender === window.webContents && !event.sender.isDestroyed()) { + terminalSessionManager?.enableEventDelivery(event.sender.id, result.terminal.sessionId) } }) - return snapshot } - ) - - registerHandler(ipcChannels.terminalWrite, (event, input: unknown) => { + return result + }) + registerHandler(ipcChannels.runtimeNativeClientGet, async (event, input: unknown) => { assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const request = terminalWriteRequestSchema.parse(input) - manager.write( - event.sender.id, - request.sessionId, - request.data - ) + const request = runtimeNativeClientInputSchema.parse(input) + if (!nativeClientCoordinator) return null + return runtimeNativeClientServiceSchema.nullable().parse(await nativeClientCoordinator.get(event.sender.id, request.conversationId)) + }) + registerHandler(ipcChannels.runtimeNativeClientStop, async (event, input: unknown) => { + assertTrustedSender(event, window) + const request = runtimeNativeClientServiceSchema.parse(input) + await nativeClientCoordinator?.stop(event.sender.id, request.serviceId) }) - registerHandler(ipcChannels.terminalResize, (event, input: unknown) => { - assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const request = terminalResizeRequestSchema.parse(input) - manager.resize(event.sender.id, request.sessionId, { - cols: request.cols, - rows: request.rows - }) - }) - - registerHandler( - ipcChannels.terminalSnapshot, - (event, input: unknown) => { - assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const request = terminalSnapshotRequestSchema.parse(input) - return manager.snapshot( - event.sender.id, - request.sessionId - ) - } - ) - - registerHandler( - ipcChannels.terminalAck, - (event, input: unknown) => { - assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const request = terminalAckRequestSchema.parse(input) - manager.acknowledge( - event.sender.id, - request.sessionId, - request.sequence - ) - } - ) - - registerHandler( - ipcChannels.terminalClose, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const manager = requireTerminalSessionManager() - const request = terminalCloseRequestSchema.parse(input) - return manager.close( - event.sender.id, - request.sessionId - ) - } - ) + registerTerminalIpcHandlers(registerHandler, window, terminalSessionManager) registerHandler(ipcChannels.agentRun, async (event, input: unknown) => { assertTrustedSender(event, window) @@ -5998,78 +5627,10 @@ export function registerIpcHandlers( } ) - const requireLocalToolEnvironmentService = - (): LocalToolEnvironmentService => { - if (!localToolEnvironmentService) { - throw new Error('本地工具环境服务不可用') - } - return localToolEnvironmentService - } - - registerHandler( - ipcChannels.localToolEnvironmentGet, - (event, input: unknown) => { - assertTrustedSender(event, window) - z.undefined().parse(input) - return requireLocalToolEnvironmentService().getSnapshot() - } - ) - registerHandler( - ipcChannels.localToolEnvironmentUpdate, - (event, input: unknown) => { - assertTrustedSender(event, window) - return requireLocalToolEnvironmentService().updateSettings( - localToolEnvironmentSettingsSchema.parse(input) - ) - } - ) - registerHandler( - ipcChannels.localToolEnvironmentRefresh, - (event, input: unknown) => { - assertTrustedSender(event, window) - z.undefined().parse(input) - return requireLocalToolEnvironmentService().refreshCandidates() - } - ) - registerHandler( - ipcChannels.localToolEnvironmentSelectExecutable, - (event, input: unknown) => { - assertTrustedSender(event, window) - const { kind } = localToolKindInputSchema.parse(input) - return requireLocalToolEnvironmentService().selectExecutable(kind) - } - ) - registerHandler( - ipcChannels.localToolEnvironmentDiagnose, - (event, input: unknown) => { - assertTrustedSender(event, window) - const { kind } = localToolDiagnoseInputSchema.parse(input) - return requireLocalToolEnvironmentService().diagnose(kind) - } - ) - registerHandler( - ipcChannels.localToolEnvironmentInstallPython, - (event, input: unknown) => { - assertTrustedSender(event, window) - z.undefined().parse(input) - return requireLocalToolEnvironmentService().installPython() - } - ) - registerHandler( - ipcChannels.localToolEnvironmentCancelPython, - (event, input: unknown) => { - assertTrustedSender(event, window) - z.undefined().parse(input) - return requireLocalToolEnvironmentService().cancelPython() - } - ) - registerHandler( - ipcChannels.localToolEnvironmentRemovePython, - (event, input: unknown) => { - assertTrustedSender(event, window) - z.undefined().parse(input) - return requireLocalToolEnvironmentService().removePython() - } + registerLocalToolEnvironmentIpcHandlers( + registerHandler, + window, + localToolEnvironmentService ) registerHandler(ipcChannels.shortcutSettingsGet, (event) => { @@ -8058,318 +7619,15 @@ export function registerIpcHandlers( assistantDatabase.removeExpert(assistantIdSchema.parse(input)) }) - registerHandler( - ipcChannels.capabilitiesSnapshot, - (event): Promise => { - assertTrustedSender(event, window) - return capabilityService.getSnapshot() - } - ) - - registerHandler( - ipcChannels.runtimeExtensionsSnapshot, - (event): Promise => { - assertTrustedSender(event, window) - if (!runtimeExtensionStore) { - throw new Error('DSH 插件市场不可用') - } - return runtimeExtensionStore.getSnapshot() - } - ) - - registerHandler( - ipcChannels.runtimeExtensionsApply, - async ( - event, - input: unknown - ): Promise => { - assertTrustedSender(event, window) - if (!runtimeExtensionStore) { - throw new Error('DSH 插件市场不可用') - } - const action = runtimeExtensionActionSchema.parse(input) - const result = - await runtimeExtensionStore.applyWithResult(action) - if ( - result.changed && - action.type !== 'set-marketplace-enabled' - ) { - await onRuntimeSettingsChanged() - } - return result.snapshot - } - ) - - registerHandler( - ipcChannels.capabilitiesImportSkill, - async (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const kind = skillImportKindSchema.parse(input) - const result = await dialog.showOpenDialog( - window, - kind === 'zip' - ? { - title: '选择 Skill ZIP 文件', - properties: ['openFile'], - filters: [{ name: 'Skill ZIP', extensions: ['zip'] }] - } - : { - title: '选择包含 SKILL.md 的目录', - properties: ['openDirectory'] - } - ) - if (result.canceled || !result.filePaths[0]) { - return capabilityService.getSnapshot() - } - return refreshCapabilities( - capabilityService.importSkill(result.filePaths[0]) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesRemoveSkill, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - return refreshCapabilities( - capabilityService.removeSkill(skillIdSchema.parse(input)) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesToggleSkill, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = skillToggleInputSchema.parse(input) - return refreshCapabilities( - capabilityService.setSkillEnabled( - value.skillId, - value.enabled - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesAssignSkill, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = skillAssignmentsInputSchema.parse(input) - return refreshCapabilities( - capabilityService.setSkillAssignments( - value.skillId, - value.assignments - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesUpdateObsidianSettings, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const settings = obsidianSettingsSchema.parse(input) - knowledgeGateway?.revokeObsidianCapabilities() - return refreshCapabilities( - capabilityService.updateObsidianSettings(settings) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesTestObsidianConnection, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const settings = obsidianSettingsSchema.parse(input) - if (!obsidianService) throw new Error('Obsidian 服务不可用') - return obsidianConnectionTestResultSchema.parse( - await obsidianService.testConnection(settings) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesSelectObsidianVault, - async (event): Promise => { - assertTrustedSender(event, window) - const result = await dialog.showOpenDialog(window, { - properties: ['openDirectory'] - }) - return result.canceled ? null : result.filePaths[0] ?? null - } - ) - - registerHandler( - ipcChannels.capabilitiesToggleBuiltinMcp, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = builtinMcpServerToggleInputSchema.parse(input) - if (value.serverId === 'obsidian') knowledgeGateway?.revokeObsidianCapabilities() - return refreshCapabilities( - capabilityService.setBuiltinMcpServerEnabled( - value.serverId, - value.enabled - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesAssignBuiltinMcp, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = builtinMcpServerAssignmentsInputSchema.parse(input) - if (value.serverId === 'obsidian') knowledgeGateway?.revokeObsidianCapabilities() - return refreshCapabilities( - capabilityService.setBuiltinMcpServerAssignments( - value.serverId, - value.assignments - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesSaveMcp, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = mcpServerSaveSchema.parse(input) - return refreshCapabilities( - capabilityService.saveMcpServer(value.serverId, value.input) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesRemoveMcp, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - return refreshCapabilities( - capabilityService.removeMcpServer( - mcpServerIdSchema.parse(input) - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesTestMcp, - async (event, input: unknown): Promise => { - assertTrustedSender(event, window) - return testMcpServer( - await capabilityService.getResolvedMcpServer( - mcpServerIdSchema.parse(input) - ), - undefined, - localToolEnvironmentService?.launchEnvironmentProvider - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesToggleWebSearch, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - return refreshCapabilities( - capabilityService.setWebSearchEnabled(z.boolean().parse(input)) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesTestWebSearch, - (event): Promise => { - assertTrustedSender(event, window) - return testWebSearch() - } - ) - - registerHandler( - ipcChannels.capabilitiesToggleComputer, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = computerCapabilityToggleInputSchema.parse(input) - return refreshCapabilities( - capabilityService.setComputerCapabilityEnabled( - value.capabilityId, - value.enabled - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesConfigureComputer, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = computerCapabilityConfigInputSchema.parse(input) - return refreshCapabilities( - capabilityService.setComputerCapabilityBrowserProfile( - value.capabilityId, - value.browserProfileId - ) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesDiagnoseComputer, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - return capabilityService.diagnoseComputerCapability( - computerCapabilityIdSchema.parse(input) - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesCreateBrowserProfile, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = browserProfileCreateInputSchema.parse(input) - return refreshCapabilities( - capabilityService.createBrowserProfile(value.name), - false - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesRenameBrowserProfile, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = browserProfileRenameInputSchema.parse(input) - return refreshCapabilities( - capabilityService.renameBrowserProfile(value.profileId, value.name), - false - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesDefaultBrowserProfile, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = browserProfileSelectionInputSchema.parse(input) - return refreshCapabilities( - capabilityService.setDefaultBrowserProfile(value.profileId), - false - ) - } - ) - - registerHandler( - ipcChannels.capabilitiesRemoveBrowserProfile, - (event, input: unknown): Promise => { - assertTrustedSender(event, window) - const value = browserProfileSelectionInputSchema.parse(input) - return refreshCapabilities( - capabilityService.removeBrowserProfile(value.profileId), - false - ) - } - ) + registerCapabilityIpcHandlers(registerHandler, window, { + capabilityService, + refreshCapabilities, + onRuntimeSettingsChanged, + runtimeExtensionStore, + knowledgeGateway, + obsidianService, + localToolEnvironmentService + }) registerHandler(ipcChannels.contextSelectFiles, (event, input: unknown) => { assertTrustedSender(event, window) @@ -8432,948 +7690,24 @@ export function registerIpcHandlers( contextManager.remove(requestIdSchema.parse(input)) }) - const resolveMagicNoteSource = (source?: MagicNoteSource): MagicNoteSource | undefined => { - if (!source) return undefined - const conversation = assistantDatabase.getConversation(source.conversationId) - const messages = new Map(conversation.messages.map((message) => [message.id, message])) - for (const id of source.messageIds) { - const message = messages.get(id) - if (!message || (source.kind === 'message' && message.role !== 'assistant')) { - throw new Error('Invalid conversation source message') - } - } - const project = conversation.projectId ? assistantDatabase.getProject(conversation.projectId) : undefined - return { - kind: source.kind, - conversationId: conversation.id, - messageIds: source.messageIds, - capturedAt: source.capturedAt, - conversationTitle: conversation.title, - ...(project ? { projectId: project.id, projectName: project.name } : {}) - } + registerMagicNotesIpcHandlers(registerHandler, window, assistantDatabase) + + const magicNotesAnalysisDependencies = { + window, assistantDatabase, settingsStore, applicationSettingsStore, + persistModelUsage, safeRuntimeError } + registerMagicNotesAnalysisIpcHandlers(registerHandler, magicNotesAnalysisDependencies) - registerHandler(ipcChannels.magicNotesSearch, (event, input: unknown) => { - assertTrustedSender(event, window) - const { query, limit } = magicNoteSearchSchema.parse(input) - return assistantDatabase.searchMagicNoteSummaries(query, limit) - }) + registerMagicTodosIpcHandlers(registerHandler, window, assistantDatabase) - registerHandler(ipcChannels.magicNotesList, (event) => { - assertTrustedSender(event, window) - return { notes: assistantDatabase.listMagicNotes() } - }) + registerMagicTodosAnalysisIpcHandlers(registerHandler, magicNotesAnalysisDependencies) - registerHandler(ipcChannels.magicNotesGet, (event, input: unknown) => { - assertTrustedSender(event, window) - const { noteId } = magicNoteDeleteSchema.parse(input) - return assistantDatabase.getMagicNote(noteId) - }) - - registerHandler(ipcChannels.magicNotesCreate, (event, input: unknown) => { - assertTrustedSender(event, window) - const parsed = magicNoteCreateSchema.parse(input) - return assistantDatabase.createMagicNote({ ...parsed, source: resolveMagicNoteSource(parsed.source) }) - }) - - registerHandler(ipcChannels.magicNotesUpdate, (event, input: unknown) => { - assertTrustedSender(event, window) - return assistantDatabase.updateMagicNote( - magicNoteUpdateSchema.parse(input) - ) - }) - - registerHandler(ipcChannels.magicNotesDelete, (event, input: unknown) => { - assertTrustedSender(event, window) - const { noteId } = magicNoteDeleteSchema.parse(input) - assistantDatabase.deleteMagicNote(noteId) - }) - - registerHandler( - ipcChannels.magicNotesCreateEntry, - (event, input: unknown) => { - assertTrustedSender(event, window) - const parsed = magicNoteEntryCreateSchema.parse(input) - const content = validateMagicNoteContent(parsed.content) - return assistantDatabase.createMagicNoteEntry({ - noteId: parsed.noteId, - content, - source: resolveMagicNoteSource(parsed.source), - plainText: magicNotePlainText(content) - }) - } - ) - - registerHandler( - ipcChannels.magicNotesUpdateEntry, - (event, input: unknown) => { - assertTrustedSender(event, window) - const parsed = magicNoteEntryUpdateSchema.parse(input) - const content = validateMagicNoteContent(parsed.content) - return assistantDatabase.updateMagicNoteEntry({ - entryId: parsed.entryId, - expectedRevision: parsed.expectedRevision, - content, - plainText: magicNotePlainText(content) - }) - } - ) - - registerHandler( - ipcChannels.magicNotesDeleteEntry, - (event, input: unknown) => { - assertTrustedSender(event, window) - const { entryId } = magicNoteEntryDeleteSchema.parse(input) - return assistantDatabase.deleteMagicNoteEntry(entryId) - } - ) - - registerHandler( - ipcChannels.magicNotesAnalyze, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { entryId, requestId, direction, format, canvasImages, canvasPageText, expectedRevision } = - magicNoteAnalyzeSchema.parse(input) - const settings = await settingsStore.getResolvedSettings() - const entry = assistantDatabase.getMagicNoteEntry(entryId) - if (expectedRevision !== undefined && entry.revision !== expectedRevision) { - throw new Error('记录已被更新,请重新捕获并分析') - } - const note = assistantDatabase.getMagicNoteContext(entry.noteId) - const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 - const analysisRuntime = createDefaultModelRuntime( - settings.workspacePath, - settings - ) - assistantDatabase.createTask({ - id: requestId, - title: `分析笔记:${note.title}`, - instructions: '使用无工具模型对笔记记录进行只读分析', - workMode: 'ask', - origin: 'assistant', - visible: false - }) - try { - const comments = await analyzeMagicNoteEntry( - analysisRuntime, - entry, - { requestId, direction, format, canvasImages, canvasPageText }, - format === 'structured' - ? undefined - : (delta) => { - if (!window.isDestroyed()) { - window.webContents.send( - ipcChannels.magicNotesAnalysisEvent, - { - requestId, - type: 'text', - delta, - direction, - format - } - ) - } - }, - persistModelUsage, - { supportsImageInput: settings.supportsImageInput === true, canvasPageCount } - ) - const analyzedNote = assistantDatabase.saveMagicNoteAnalysis({ - entryId, - expectedRevision: entry.revision, - comments - }) - assistantDatabase.updateTaskStatus(requestId, 'completed') - return analyzedNote - } catch (error) { - const message = safeRuntimeError(error, '魔法笔记 AI 分析失败') - assistantDatabase.updateTaskStatus(requestId, 'failed', message) - throw new Error(message, { cause: error }) - } finally { - try { - await analysisRuntime.releaseConversation?.( - `magic-notes:${entry.id}` - ) - } finally { - await analysisRuntime.dispose() - } - } - } - ) - - registerHandler( - ipcChannels.magicNotesAnalyzeDraft, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const parsed = magicNoteDraftAnalyzeSchema.parse(input) - const content = validateMagicNoteContent(parsed.content) - const plainText = magicNotePlainText(content) - const settings = await settingsStore.getResolvedSettings() - const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 - const analysisRuntime = createDefaultModelRuntime( - settings.workspacePath, - settings - ) - const { requestId, direction, format, canvasImages, canvasPageText } = parsed - assistantDatabase.createTask({ - id: requestId, - title: '分析未保存笔记草稿', - instructions: '使用无工具模型对未保存笔记草稿进行只读分析', - workMode: 'ask', - origin: 'assistant', - visible: false - }) - try { - const comments = await analyzeMagicNoteDraft( - analysisRuntime, - plainText, - { requestId, direction, format, canvasImages, canvasPageText }, - format === 'structured' - ? undefined - : (delta) => { - if (!window.isDestroyed()) { - window.webContents.send( - ipcChannels.magicNotesAnalysisEvent, - { - requestId, - type: 'text', - delta, - direction, - format - } - ) - } - }, - persistModelUsage, - { supportsImageInput: settings.supportsImageInput === true, content, canvasPageCount } - ) - assistantDatabase.updateTaskStatus(requestId, 'completed') - return { - id: randomUUID(), - comments, - inputMode: comments[0]?.inputMode, - analyzedAt: new Date().toISOString() - } - } catch (error) { - const message = safeRuntimeError(error, '魔法笔记草稿 AI 分析失败') - assistantDatabase.updateTaskStatus(requestId, 'failed', message) - throw new Error(message, { cause: error }) - } finally { - try { - await analysisRuntime.releaseConversation?.( - `magic-note-drafts:${requestId}` - ) - } finally { - await analysisRuntime.dispose() - } - } - } - ) - - registerHandler( - ipcChannels.magicTodosList, - (event) => { - assertTrustedSender(event, window) - return { todos: assistantDatabase.listMagicTodos() } - } - ) - - registerHandler( - ipcChannels.magicTodosStatus, - (event) => { - assertTrustedSender(event, window) - return assistantDatabase.getMagicTodoStatus() - } - ) - - registerHandler( - ipcChannels.magicTodosUpdate, - (event, input: unknown) => { - assertTrustedSender(event, window) - const todo = assistantDatabase.updateMagicTodo( - magicTodoUpdateSchema.parse(input) - ) - return { - todo, - note: assistantDatabase.getMagicNote(todo.noteId) - } - } - ) - - registerHandler( - ipcChannels.magicTodosAnalyze, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { todoId, requestId, direction, format, canvasImages, canvasPageText, sourceEntryRevision } = - magicTodoIdSchema.parse(input) - const settings = await settingsStore.getResolvedSettings() - const todo = assistantDatabase.getMagicTodo(todoId) - const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 - const entry = assistantDatabase.getMagicNoteEntry(todo.entryId) - if (sourceEntryRevision !== undefined && entry.revision !== sourceEntryRevision) { - throw new Error('来源记录已被更新,请重新捕获并分析') - } - const analysisRuntime = createDefaultModelRuntime( - settings.workspacePath, - settings - ) - assistantDatabase.createTask({ - id: requestId, - title: `分析待办:${todo.title}`, - instructions: '使用无工具模型对魔法笔记待办进行只读分析', - workMode: 'ask', - origin: 'assistant', - visible: false - }) - try { - const comments = await analyzeMagicTodo( - analysisRuntime, - todo, - { requestId, direction, format, canvasImages, canvasPageText }, - format === 'structured' - ? undefined - : (delta) => { - if (!window.isDestroyed()) { - window.webContents.send( - ipcChannels.magicNotesAnalysisEvent, - { - requestId, - type: 'text', - delta, - direction, - format - } - ) - } - }, - persistModelUsage, - { supportsImageInput: settings.supportsImageInput === true, content: entry.content, canvasPageCount } - ) - const analyzedTodo = assistantDatabase.saveMagicTodoAnalysis({ - todoId, - expectedRevision: todo.revision, - sourceEntryRevision: entry.revision, - comments - }) - assistantDatabase.updateTaskStatus(requestId, 'completed') - return analyzedTodo - } catch (error) { - const message = safeRuntimeError(error, '魔法笔记待办 AI 分析失败') - assistantDatabase.updateTaskStatus(requestId, 'failed', message) - throw new Error(message, { cause: error }) - } finally { - try { - await analysisRuntime.releaseConversation?.( - `magic-todos:${todo.id}` - ) - } finally { - await analysisRuntime.dispose() - } - } - } - ) - - registerHandler(ipcChannels.externalInstancesList, (event) => {assertTrustedSender(event,window);return knowledgeService.external.listInstances()}) - registerHandler(ipcChannels.externalInstancesSave, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.saveInstance(externalKnowledgeInstanceSaveInputSchema.parse(input))}) - registerHandler(ipcChannels.externalInstancesTest, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.testInstance(externalKnowledgeInstanceInputSchema.parse(input).instanceId)}) - registerHandler(ipcChannels.externalInstancesSetEnabled, (event,input:unknown) => {assertTrustedSender(event,window);const value=externalKnowledgeInstanceEnabledInputSchema.parse(input);return knowledgeService.external.setEnabled(value.instanceId,value.enabled)}) - registerHandler(ipcChannels.externalInstancesDelete, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.deleteInstance(externalKnowledgeInstanceInputSchema.parse(input).instanceId)}) - registerHandler(ipcChannels.externalCatalogList, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.listCatalog(externalKnowledgeCatalogListInputSchema.parse(input))}) - registerHandler(ipcChannels.externalCatalogGet, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.getCatalog(externalKnowledgeCatalogGetInputSchema.parse(input))}) - registerHandler(ipcChannels.externalRetrievalTest, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.testRetrieval(externalKnowledgeBindingTestInputSchema.parse(input))}) - registerHandler(ipcChannels.externalBindingsCreate, async (event,input:unknown) => {assertTrustedSender(event,window);await knowledgeService.external.saveBinding(externalKnowledgeBindingSaveInputSchema.parse(input));return getKnowledgeSnapshot(knowledgeService)}) - registerHandler(ipcChannels.externalBindingsUpdate, async (event,input:unknown) => {assertTrustedSender(event,window);await knowledgeService.external.saveBinding(externalKnowledgeBindingUpdateInputSchema.parse(input));return getKnowledgeSnapshot(knowledgeService)}) - registerHandler(ipcChannels.knowledgeSnapshot, (event, input: unknown) => { - assertTrustedSender(event, window) - const libraryId = - input === undefined ? undefined : knowledgeIdSchema.parse(input) - return getKnowledgeSnapshot(knowledgeService, libraryId) - }) - - registerHandler( - ipcChannels.knowledgeCreateLibrary, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeCreateSchema.parse(input) - const library = knowledgeService.createLibrary(value) - const created = getKnowledgeSnapshot( - knowledgeService, - library.id - ).libraries.find((item) => item.id === library.id) - if (!created) { - throw new Error('知识库创建失败') - } - return created - } - ) - - registerHandler( - ipcChannels.knowledgeDeleteLibrary, - async (event, input: unknown) => { - assertTrustedSender(event, window) - await knowledgeService.deleteLibrary(knowledgeIdSchema.parse(input)) - } - ) - - registerHandler( - ipcChannels.knowledgeUpdateLibrary, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeUpdateLibrarySchema.parse(input) - knowledgeService.database.updateKnowledgeBase(value.libraryId, { - name: value.name, - description: value.description, - graphEnabled: value.graphEnabled, - graphStrategy: value.graphStrategy - }) - } - ) - - registerHandler( - ipcChannels.knowledgeReextractGraph, - async (event, input: unknown) => { - assertTrustedSender(event, window) - return knowledgeService.reextractGraph(knowledgeIdSchema.parse(input)) - } - ) - - registerHandler( - ipcChannels.knowledgeSelectFiles, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const selection = knowledgeSelectionSchema.parse(input) - const result = await dialog.showOpenDialog(window, { - properties: ['openFile', 'multiSelections'], - filters: [ - { - name: '支持的知识文档', - extensions: supportedDocumentExtensions.map((extension) => - extension.slice(1) - ) - } - ] - }) - if (!result.canceled) { - await knowledgeService.importPaths( - selection.libraryId, - result.filePaths, - selection.graphStrategy - ) - } - } - ) - - registerHandler( - ipcChannels.knowledgeSelectDirectory, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const selection = knowledgeSelectionSchema.parse(input) - const result = await dialog.showOpenDialog(window, { - properties: ['openDirectory'] - }) - if (!result.canceled && result.filePaths[0]) { - await knowledgeService.importPaths( - selection.libraryId, - [result.filePaths[0]], - selection.graphStrategy - ) - } - } - ) - - registerHandler( - ipcChannels.knowledgeImportPaths, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeImportPathsSchema.parse(input) - await knowledgeService.importPaths( - value.libraryId, - value.paths, - value.graphStrategy - ) - } - ) - - registerHandler( - ipcChannels.knowledgeImportUrl, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeUrlImportSchema.parse(input) - await knowledgeService.importUrl( - value.libraryId, - value.url, - new AbortController().signal, - undefined, - value.graphStrategy - ) - } - ) - - for (const [channel, action] of [ - [ - ipcChannels.knowledgeSyncSource, - (id: string) => knowledgeService.syncSource(id) - ], - [ - ipcChannels.knowledgePauseSource, - (id: string) => knowledgeService.pauseSource(id) - ], - [ - ipcChannels.knowledgeRetrySource, - (id: string) => knowledgeService.retrySource(id) - ], - [ - ipcChannels.knowledgeRemoveSource, - (id: string) => knowledgeService.removeSource(id) - ] - ] as const) { - registerHandler(channel, async (event, input: unknown) => { - assertTrustedSender(event, window) - await action(knowledgeIdSchema.parse(input)) - }) - } - - registerHandler(ipcChannels.knowledgeSearch, async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeSearchSchema.parse(input) - if (value.libraryIds.length === 0) { - return [] - } - const availableLibraries = - knowledgeService.database.listKnowledgeBases(100) - const libraries = [...new Set(value.libraryIds)] - const names = new Map( - availableLibraries.map((library) => [library.id, library.name]) - ) - const results = ( - await knowledgeService.retrieveMany( - libraries, - value.query - ) - ) - const failures = results.flatMap(item => item.response.diagnostics.failure ? [item.response.diagnostics.failure] : []) - if (failures.length === results.length) throw new Error(failures.join('; ')) - const references = results.flatMap(({ knowledgeBaseId, response }) => response.results.map(result => ({ - ...toKnowledgeReference(result, names.get(knowledgeBaseId) ?? '知识库'), - ...(failures.length ? { warnings: failures } : {}) - }))) - if (!references.length && failures.length) throw new Error(failures.join('; ')) - return [...new Map(references.map(reference => [knowledgeReferenceKey(reference), reference])).values()] - .sort((left, right) => left.rank - right.rank) - .slice(0, 8) - }) - - registerHandler( - ipcChannels.knowledgeRetrieve, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const response = await knowledgeService.retrieve( - knowledgeRetrieveInputSchema.parse(input) - ) - return knowledgeRetrievalResponseSchema.parse(response) - } - ) - - registerHandler( - ipcChannels.knowledgeUpdateSettings, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeSettingsUpdateInputSchema.parse(input) - knowledgeService.updateSettings(value) - const library = getKnowledgeSnapshot( - knowledgeService, - value.knowledgeBaseId - ).libraries.find((item) => item.id === value.knowledgeBaseId) - if (!library) { - throw new Error('知识库不存在') - } - return library - } - ) - - registerHandler( - ipcChannels.knowledgeListChunks, - (event, input: unknown) => { - assertTrustedSender(event, window) - const page = knowledgeService.listChunks( - knowledgeChunksListInputSchema.parse(input) - ) - return knowledgeChunkPageSchema.parse({ - items: page.items.map((chunk) => ({ - id: chunk.id, - ordinal: chunk.ordinal, - role: chunk.role, - parentChunkId: chunk.parentChunkId, - heading: chunk.heading, - locator: chunk.location, - characterCount: chunk.content.length, - enabled: chunk.enabled, - content: chunk.content, - manuallyEdited: chunk.manuallyEdited, - updatedAt: chunk.updatedAt - })), - page: page.page, - pageSize: page.pageSize, - totalItems: page.total - }) - } - ) - - registerHandler( - ipcChannels.knowledgeUpdateChunk, - async (event, input: unknown) => { - assertTrustedSender(event, window) - await knowledgeService.updateChunk( - knowledgeChunkUpdateInputSchema.parse(input) - ) - } - ) - - registerHandler( - ipcChannels.knowledgeDeleteChunk, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const deleted = await knowledgeService.deleteChunk( - knowledgeChunkDeleteInputSchema.parse(input) - ) - if (!deleted) { - throw new Error('知识分块不存在') - } - } - ) - - registerHandler( - ipcChannels.knowledgeRebuildDocument, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeDocumentRebuildInputSchema.parse(input) - await knowledgeService.rebuildDocument(value) - return getKnowledgeSnapshot( - knowledgeService, - value.knowledgeBaseId - ) - } - ) - - registerHandler( - ipcChannels.knowledgeRebuildLibrary, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeLibraryRebuildInputSchema.parse(input) - return knowledgeService.rebuildLibrary(value) - } - ) - - registerHandler( - ipcChannels.knowledgeCancelRebuild, - (event, input: unknown) => { - assertTrustedSender(event, window) - const knowledgeBaseId = knowledgeIdSchema.parse(input) - return knowledgeService.cancelLibraryRebuild(knowledgeBaseId) - } - ) - - registerHandler( - ipcChannels.knowledgeTaskCancel, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { taskId } = knowledgeTaskActionInputSchema.parse(input) - return knowledgeService.cancelTask(taskId) - } - ) - - registerHandler( - ipcChannels.knowledgeTaskRetry, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { taskId } = knowledgeTaskActionInputSchema.parse(input) - await knowledgeService.retryTask(taskId) - } - ) - - const embeddingConfiguration = async () => { - const settings = await settingsStore.getPublicSettings() - const connection = settings.embeddingConnections?.find( - (candidate) => - candidate.id === settings.activeEmbeddingConnectionId - ) - return connection?.kind === 'builtin' - ? { - provider: 'builtin', - model: 'granite-embedding-97m-multilingual-r2', - credentialConfigured: false - } - : { - provider: 'openai-compatible', - model: - connection?.modelName ?? - settings.knowledgeEmbeddingModel, - endpoint: - connection?.baseUrl ?? - settings.knowledgeEmbeddingBaseUrl, - credentialConfigured: - connection?.apiKeyConfigured ?? - settings.knowledgeEmbeddingApiKeyConfigured - } - } - - registerHandler( - ipcChannels.knowledgeEmbeddingIndexGet, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { knowledgeBaseId } = - knowledgeEmbeddingIndexRequestSchema.parse(input) - const settings = await settingsStore.getResolvedSettings() - return knowledgeEmbeddingIndexSnapshotSchema.parse( - await knowledgeService.getEmbeddingIndexSnapshot( - knowledgeBaseId, - settings.knowledgeEmbeddingEnabled - ? await embeddingConfiguration() - : undefined - ) - ) - } - ) - - registerHandler( - ipcChannels.knowledgeEmbeddingIndexRebuild, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { knowledgeBaseId } = - knowledgeEmbeddingIndexRequestSchema.parse(input) - const snapshot = await knowledgeService.rebuildEmbeddingIndex( - knowledgeBaseId, - await embeddingConfiguration() - ) - return knowledgeEmbeddingIndexSnapshotSchema.parse(snapshot) - } - ) - - registerHandler( - ipcChannels.knowledgeEmbeddingIndexCancel, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const { knowledgeBaseId, jobId } = - knowledgeEmbeddingIndexCancelRequestSchema.parse(input) - return knowledgeService.cancelEmbeddingIndex( - knowledgeBaseId, - jobId - ) - } - ) - - registerHandler( - ipcChannels.knowledgeOpenDocumentSource, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeDocumentOpenInputSchema.parse(input) - const reference = knowledgeService.getDocumentSource(value) - if (!reference) { - throw new Error('文档来源不存在') - } - if (reference.source.type === 'url') { - const target = new URL(reference.source.location) - if (!['http:', 'https:'].includes(target.protocol)) { - throw new Error('文档来源 URL 协议不受支持') - } - await shell.openExternal(target.href) - return - } - const storedPath = - reference.document.sourceLocation ?? reference.source.location - if (!isAbsolute(storedPath)) { - throw new Error('文档来源路径无效') - } - if ((await lstat(storedPath)).isSymbolicLink()) { - throw new Error('文档来源不能是符号链接') - } - const targetPath = await realpath(storedPath) - if (!(await stat(targetPath)).isFile()) { - throw new Error('文档来源不是可打开的文件') - } - const openError = await shell.openPath(targetPath) - if (openError) { - throw new Error('无法打开文档来源') - } - } - ) - - registerHandler( - ipcChannels.knowledgeReferenceContext, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeReferenceContextInputSchema.parse(input) - const reference = knowledgeService.getReferenceContext(value) - if (!reference) { - throw new Error('引用上下文不存在或已停用') - } - const fullContext = reference.contextChunks - .map((chunk) => chunk.content) - .join('\n\n') - return knowledgeReferenceContextSchema.parse({ - knowledgeBaseId: value.knowledgeBaseId, - documentId: value.documentId, - chunkId: value.chunkId, - documentTitle: reference.document.title, - sourceDisplayName: reference.source.displayName, - locator: reference.chunk.location, - matchedContent: reference.chunk.content.slice(0, 48_000), - contextContent: fullContext.slice(0, 48_000), - contextChunkIds: reference.contextChunks.map((chunk) => chunk.id), - truncated: - reference.chunk.content.length > 48_000 || - fullContext.length > 48_000 - }) - } - ) - - registerHandler( - ipcChannels.knowledgeOpenReferenceSource, - async (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeReferenceOpenInputSchema.parse(input) - const reference = knowledgeService.getReferenceContext(value) - if (!reference) { - throw new Error('引用来源不存在或已停用') - } - if (reference.source.type === 'url') { - const target = new URL(reference.source.location) - if (!['http:', 'https:'].includes(target.protocol)) { - throw new Error('引用来源 URL 协议不受支持') - } - await shell.openExternal(target.href) - return - } - const storedPath = - reference.document.sourceLocation ?? reference.source.location - if (!isAbsolute(storedPath)) { - throw new Error('引用来源路径无效') - } - if ((await lstat(storedPath)).isSymbolicLink()) { - throw new Error('引用来源不能是符号链接') - } - const targetPath = await realpath(storedPath) - const targetStat = await stat(targetPath) - if (!targetStat.isFile() && !targetStat.isDirectory()) { - throw new Error('引用来源不是可打开的文件或目录') - } - const openError = await shell.openPath(targetPath) - if (openError) { - throw new Error('无法打开引用来源') - } - } - ) - - registerHandler( - ipcChannels.knowledgeCreateEntity, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeCreateEntitySchema.parse(input) - knowledgeService.database.createEntity({ - knowledgeBaseId: value.libraryId, - name: value.input.label, - type: value.input.type, - description: value.input.description || undefined, - aliases: value.input.aliases, - locked: true - }) - } - ) - - registerHandler( - ipcChannels.knowledgeUpdateEntity, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeEntityPayloadSchema.parse(input) - knowledgeService.database.updateEntity(value.entityId, { - name: value.update.label, - type: value.update.type, - description: value.update.description || null, - aliases: value.update.aliases, - locked: true - }) - } - ) - - registerHandler( - ipcChannels.knowledgeMoveEntity, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeMoveEntitySchema.parse(input) - const entity = knowledgeService.database.getEntity(value.entityId) - if (!entity) { - throw new Error('图谱实体不存在') - } - knowledgeService.database.updateEntity(entity.id, { - properties: { - ...entity.properties, - x: value.position.x, - y: value.position.y - } - }) - } - ) - - registerHandler( - ipcChannels.knowledgeDeleteEntity, - (event, input: unknown) => { - assertTrustedSender(event, window) - knowledgeService.database.deleteEntity(knowledgeIdSchema.parse(input)) - } - ) - - registerHandler( - ipcChannels.knowledgeMergeEntities, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeMergeSchema.parse(input) - knowledgeService.database.mergeEntities( - value.targetEntityId, - value.sourceEntityId - ) - } - ) - - registerHandler( - ipcChannels.knowledgeCreateRelation, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeCreateRelationSchema.parse(input) - knowledgeService.database.createRelation({ - knowledgeBaseId: value.libraryId, - sourceEntityId: value.input.sourceId, - targetEntityId: value.input.targetId, - type: value.input.type, - label: value.input.description || undefined, - locked: true - }) - } - ) - - registerHandler( - ipcChannels.knowledgeUpdateRelation, - (event, input: unknown) => { - assertTrustedSender(event, window) - const value = knowledgeUpdateRelationSchema.parse(input) - knowledgeService.database.updateRelation(value.relationId, { - sourceEntityId: value.input.sourceId, - targetEntityId: value.input.targetId, - type: value.input.type, - label: value.input.description || null, - locked: true - }) - } - ) - - registerHandler( - ipcChannels.knowledgeDeleteRelation, - (event, input: unknown) => { - assertTrustedSender(event, window) - knowledgeService.database.deleteRelation(knowledgeIdSchema.parse(input)) - } - ) + registerKnowledgeIpcHandlers(registerHandler, window, knowledgeService, settingsStore) return async () => { shuttingDown = true + if (nativeClientCoordinator) window.webContents.removeListener('destroyed', closeNativeClients) + await nativeClientCoordinator?.closeOwner(nativeClientOwnerId) supervisionModelPool.dispose() for (const id of diagnosticOperations) documentParsingService?.cancelDiagnostic(id) if (contextImports > 0) contextManager.cancelImport(true) diff --git a/src/main/knowledge/knowledge-ipc.ts b/src/main/knowledge/knowledge-ipc.ts new file mode 100644 index 00000000..7dfb1cdc --- /dev/null +++ b/src/main/knowledge/knowledge-ipc.ts @@ -0,0 +1,841 @@ +import { dialog, shell, type BrowserWindow, type ipcMain } from 'electron' +import { lstat, realpath, stat } from 'node:fs/promises' +import { isAbsolute } from 'node:path' +import { z } from 'zod' +import { + externalKnowledgeInstanceInputSchema, + externalKnowledgeInstanceEnabledInputSchema, + externalKnowledgeInstanceSaveInputSchema, + externalKnowledgeCatalogListInputSchema, + externalKnowledgeCatalogGetInputSchema, + externalKnowledgeBindingSaveInputSchema, + externalKnowledgeBindingUpdateInputSchema, + externalKnowledgeBindingTestInputSchema +} from '../../shared/external-knowledge-contracts' +import { knowledgeReferenceKey, toKnowledgeReference } from '../../shared/knowledge-reference' +import { + knowledgeCreateSchema, + knowledgeEntityUpdateSchema, + knowledgeIdSchema, + knowledgeImportPathsSchema, + knowledgeRelationInputSchema, + knowledgeUpdateLibrarySchema, + knowledgeUrlImportSchema, + type KnowledgeSnapshot +} from '../../shared/contracts' +import { + knowledgeChunkDeleteInputSchema, + knowledgeChunkPageSchema, + knowledgeChunksListInputSchema, + knowledgeChunkUpdateInputSchema, + knowledgeDocumentOpenInputSchema, + knowledgeDocumentRebuildInputSchema, + knowledgeLibraryRebuildInputSchema, + knowledgeReferenceContextInputSchema, + knowledgeReferenceContextSchema, + knowledgeReferenceOpenInputSchema, + knowledgeRetrieveInputSchema, + knowledgeRetrievalResponseSchema, + knowledgeSettingsUpdateInputSchema +} from '../../shared/knowledge-contracts' +import { + knowledgeTaskActionInputSchema, + knowledgeTaskItemSchema +} from '../../shared/knowledge-task-contracts' +import { + knowledgeEmbeddingIndexCancelRequestSchema, + knowledgeEmbeddingIndexRequestSchema, + knowledgeEmbeddingIndexSnapshotSchema +} from '../../shared/embedding-contracts' +import { ipcChannels } from '../../shared/ipc-channels' +import { assertTrustedSender } from '../trusted-ipc-sender' +import type { RuntimeSettingsStore } from '../runtime-settings-store' +import type { KnowledgeService } from './knowledge-service' +import { supportedDocumentExtensions } from './document-parser' + +const knowledgeSearchSchema = z + .object({ + libraryIds: z.array(knowledgeIdSchema).max(20), + query: z.string().trim().min(1).max(512) + }) + .strict() +const knowledgeSelectionSchema = z + .object({ + libraryId: knowledgeIdSchema, + graphStrategy: z.enum(['rules', 'model', 'hybrid']).optional() + }) + .strict() +const knowledgeEntityPayloadSchema = z + .object({ + entityId: knowledgeIdSchema, + update: knowledgeEntityUpdateSchema + }) + .strict() +const knowledgeCreateEntitySchema = z + .object({ + libraryId: knowledgeIdSchema, + input: knowledgeEntityUpdateSchema + }) + .strict() +const knowledgeMoveEntitySchema = z + .object({ + entityId: knowledgeIdSchema, + position: z + .object({ + x: z.number().finite().min(-100_000).max(100_000), + y: z.number().finite().min(-100_000).max(100_000) + }) + .strict() + }) + .strict() +const knowledgeMergeSchema = z + .object({ + sourceEntityId: knowledgeIdSchema, + targetEntityId: knowledgeIdSchema + }) + .strict() +const knowledgeCreateRelationSchema = z + .object({ + libraryId: knowledgeIdSchema, + input: knowledgeRelationInputSchema + }) + .strict() +const knowledgeUpdateRelationSchema = z + .object({ + relationId: knowledgeIdSchema, + input: knowledgeRelationInputSchema + }) + .strict() + +function getKnowledgeSnapshot( + service: KnowledgeService, + selectedLibraryId?: string +): KnowledgeSnapshot { + const snapshot = service.snapshot(selectedLibraryId) + const activeLibraryId = + selectedLibraryId ?? snapshot.libraries[0]?.id + const documentsById = new Map( + snapshot.documents.map((document) => [document.id, document]) + ) + const evidenceByEntity = new Map() + const evidenceByRelation = new Map() + for (const item of snapshot.evidence) { + if (item.entityId) { + evidenceByEntity.set(item.entityId, [ + ...(evidenceByEntity.get(item.entityId) ?? []), + item.id + ]) + } + if (item.relationId) { + evidenceByRelation.set(item.relationId, [ + ...(evidenceByRelation.get(item.relationId) ?? []), + item.id + ]) + } + } + const bindingsByLibraryId = new Map( + service.database.externalStore + .listBindings() + .map((binding) => [binding.knowledgeBaseId, binding]) + ) + return { + libraries: snapshot.libraries.map((library) => ({ + kind: bindingsByLibraryId.has(library.id) ? 'external' : 'local', + external: bindingsByLibraryId.get(library.id), + id: library.id, + name: library.name, + description: library.description ?? '', + storageMode: library.storageMode, + graphEnabled: library.graphEnabled, + graphStrategy: library.graphStrategy, + sourceCount: library.sourceCount, + documentCount: library.documentCount, + indexedDocumentCount: library.indexedDocumentCount, + processingDocumentCount: library.processingDocumentCount, + failedDocumentCount: library.failedDocumentCount, + retrievalSettings: library.retrievalSettings, + chunkingSettings: library.chunkingSettings, + chunkingRebuildRequired: library.chunkingRebuildRequired, + ontologySettings: library.ontologySettings, + ontologyRebuildRequired: library.ontologyRebuildRequired, + updatedAt: library.updatedAt + })), + selectedLibraryId: activeLibraryId, + sources: snapshot.sources.map((source) => ({ + id: source.id, + libraryId: source.knowledgeBaseId, + name: source.displayName, + kind: source.type, + location: source.location, + status: + source.status === 'pending' + ? 'queued' + : source.status === 'indexing' + ? 'syncing' + : source.status === 'error' + ? 'failed' + : source.status, + progress: source.progress, + documentCount: source.documentCount, + lastSyncedAt: source.lastSyncedAt, + error: source.lastError + })), + documents: snapshot.documents.map((document) => ({ + id: document.id, + libraryId: document.knowledgeBaseId, + sourceId: document.sourceId, + name: document.title, + resultId: typeof document.metadata.parsedResultId === 'string' ? document.metadata.parsedResultId : undefined, + path: document.sourceLocation, + status: document.status, + textIndexStatus: document.textIndexStatus, + vectorIndexStatus: document.vectorIndexStatus, + graphIndexStatus: document.graphIndexStatus, + indexProgress: document.status === 'ready' ? 100 : 0, + chunkCount: document.chunkCount, + size: document.size, + updatedAt: document.updatedAt, + error: document.error + })), + graphNodes: snapshot.entities.map((entity, index) => ({ + id: entity.id, + label: entity.name, + type: entity.type, + description: entity.description, + aliases: entity.aliases, + x: + typeof entity.properties.x === 'number' + ? entity.properties.x + : 120 + (index % 5) * 150, + y: + typeof entity.properties.y === 'number' + ? entity.properties.y + : 100 + Math.floor(index / 5) * 120, + evidenceIds: evidenceByEntity.get(entity.id) + })), + graphRelations: snapshot.relations.map((relation) => ({ + id: relation.id, + sourceId: relation.sourceEntityId, + targetId: relation.targetEntityId, + type: relation.type, + description: relation.label, + evidenceIds: evidenceByRelation.get(relation.id) + })), + evidence: snapshot.evidence.map((item) => ({ + id: item.id, + documentId: item.documentId, + documentName: + documentsById.get(item.documentId)?.title ?? '未知文档', + excerpt: item.quote ?? '', + location: item.location + })), + tasks: snapshot.tasks.map((task) => knowledgeTaskItemSchema.parse(task)) + } +} + +export function registerKnowledgeIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + knowledgeService: KnowledgeService, + settingsStore: RuntimeSettingsStore +): void { + registerHandler(ipcChannels.externalInstancesList, (event) => {assertTrustedSender(event,window);return knowledgeService.external.listInstances()}) + registerHandler(ipcChannels.externalInstancesSave, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.saveInstance(externalKnowledgeInstanceSaveInputSchema.parse(input))}) + registerHandler(ipcChannels.externalInstancesTest, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.testInstance(externalKnowledgeInstanceInputSchema.parse(input).instanceId)}) + registerHandler(ipcChannels.externalInstancesSetEnabled, (event,input:unknown) => {assertTrustedSender(event,window);const value=externalKnowledgeInstanceEnabledInputSchema.parse(input);return knowledgeService.external.setEnabled(value.instanceId,value.enabled)}) + registerHandler(ipcChannels.externalInstancesDelete, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.deleteInstance(externalKnowledgeInstanceInputSchema.parse(input).instanceId)}) + registerHandler(ipcChannels.externalCatalogList, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.listCatalog(externalKnowledgeCatalogListInputSchema.parse(input))}) + registerHandler(ipcChannels.externalCatalogGet, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.getCatalog(externalKnowledgeCatalogGetInputSchema.parse(input))}) + registerHandler(ipcChannels.externalRetrievalTest, (event,input:unknown) => {assertTrustedSender(event,window);return knowledgeService.external.testRetrieval(externalKnowledgeBindingTestInputSchema.parse(input))}) + registerHandler(ipcChannels.externalBindingsCreate, async (event,input:unknown) => {assertTrustedSender(event,window);await knowledgeService.external.saveBinding(externalKnowledgeBindingSaveInputSchema.parse(input));return getKnowledgeSnapshot(knowledgeService)}) + registerHandler(ipcChannels.externalBindingsUpdate, async (event,input:unknown) => {assertTrustedSender(event,window);await knowledgeService.external.saveBinding(externalKnowledgeBindingUpdateInputSchema.parse(input));return getKnowledgeSnapshot(knowledgeService)}) + registerHandler(ipcChannels.knowledgeSnapshot, (event, input: unknown) => { + assertTrustedSender(event, window) + const libraryId = + input === undefined ? undefined : knowledgeIdSchema.parse(input) + return getKnowledgeSnapshot(knowledgeService, libraryId) + }) + + registerHandler( + ipcChannels.knowledgeCreateLibrary, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeCreateSchema.parse(input) + const library = knowledgeService.createLibrary(value) + const created = getKnowledgeSnapshot( + knowledgeService, + library.id + ).libraries.find((item) => item.id === library.id) + if (!created) { + throw new Error('知识库创建失败') + } + return created + } + ) + + registerHandler( + ipcChannels.knowledgeDeleteLibrary, + async (event, input: unknown) => { + assertTrustedSender(event, window) + await knowledgeService.deleteLibrary(knowledgeIdSchema.parse(input)) + } + ) + + registerHandler( + ipcChannels.knowledgeUpdateLibrary, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeUpdateLibrarySchema.parse(input) + knowledgeService.database.updateKnowledgeBase(value.libraryId, { + name: value.name, + description: value.description, + graphEnabled: value.graphEnabled, + graphStrategy: value.graphStrategy + }) + } + ) + + registerHandler( + ipcChannels.knowledgeReextractGraph, + async (event, input: unknown) => { + assertTrustedSender(event, window) + return knowledgeService.reextractGraph(knowledgeIdSchema.parse(input)) + } + ) + + registerHandler( + ipcChannels.knowledgeSelectFiles, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const selection = knowledgeSelectionSchema.parse(input) + const result = await dialog.showOpenDialog(window, { + properties: ['openFile', 'multiSelections'], + filters: [ + { + name: '支持的知识文档', + extensions: supportedDocumentExtensions.map((extension) => + extension.slice(1) + ) + } + ] + }) + if (!result.canceled) { + await knowledgeService.importPaths( + selection.libraryId, + result.filePaths, + selection.graphStrategy + ) + } + } + ) + + registerHandler( + ipcChannels.knowledgeSelectDirectory, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const selection = knowledgeSelectionSchema.parse(input) + const result = await dialog.showOpenDialog(window, { + properties: ['openDirectory'] + }) + if (!result.canceled && result.filePaths[0]) { + await knowledgeService.importPaths( + selection.libraryId, + [result.filePaths[0]], + selection.graphStrategy + ) + } + } + ) + + registerHandler( + ipcChannels.knowledgeImportPaths, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeImportPathsSchema.parse(input) + await knowledgeService.importPaths( + value.libraryId, + value.paths, + value.graphStrategy + ) + } + ) + + registerHandler( + ipcChannels.knowledgeImportUrl, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeUrlImportSchema.parse(input) + await knowledgeService.importUrl( + value.libraryId, + value.url, + new AbortController().signal, + undefined, + value.graphStrategy + ) + } + ) + + for (const [channel, action] of [ + [ + ipcChannels.knowledgeSyncSource, + (id: string) => knowledgeService.syncSource(id) + ], + [ + ipcChannels.knowledgePauseSource, + (id: string) => knowledgeService.pauseSource(id) + ], + [ + ipcChannels.knowledgeRetrySource, + (id: string) => knowledgeService.retrySource(id) + ], + [ + ipcChannels.knowledgeRemoveSource, + (id: string) => knowledgeService.removeSource(id) + ] + ] as const) { + registerHandler(channel, async (event, input: unknown) => { + assertTrustedSender(event, window) + await action(knowledgeIdSchema.parse(input)) + }) + } + + registerHandler(ipcChannels.knowledgeSearch, async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeSearchSchema.parse(input) + if (value.libraryIds.length === 0) { + return [] + } + const availableLibraries = + knowledgeService.database.listKnowledgeBases(100) + const libraries = [...new Set(value.libraryIds)] + const names = new Map( + availableLibraries.map((library) => [library.id, library.name]) + ) + const results = ( + await knowledgeService.retrieveMany( + libraries, + value.query + ) + ) + const failures = results.flatMap(item => item.response.diagnostics.failure ? [item.response.diagnostics.failure] : []) + if (failures.length === results.length) throw new Error(failures.join('; ')) + const references = results.flatMap(({ knowledgeBaseId, response }) => response.results.map(result => ({ + ...toKnowledgeReference(result, names.get(knowledgeBaseId) ?? '知识库'), + ...(failures.length ? { warnings: failures } : {}) + }))) + if (!references.length && failures.length) throw new Error(failures.join('; ')) + return [...new Map(references.map(reference => [knowledgeReferenceKey(reference), reference])).values()] + .sort((left, right) => left.rank - right.rank) + .slice(0, 8) + }) + + registerHandler( + ipcChannels.knowledgeRetrieve, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const response = await knowledgeService.retrieve( + knowledgeRetrieveInputSchema.parse(input) + ) + return knowledgeRetrievalResponseSchema.parse(response) + } + ) + + registerHandler( + ipcChannels.knowledgeUpdateSettings, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeSettingsUpdateInputSchema.parse(input) + knowledgeService.updateSettings(value) + const library = getKnowledgeSnapshot( + knowledgeService, + value.knowledgeBaseId + ).libraries.find((item) => item.id === value.knowledgeBaseId) + if (!library) { + throw new Error('知识库不存在') + } + return library + } + ) + + registerHandler( + ipcChannels.knowledgeListChunks, + (event, input: unknown) => { + assertTrustedSender(event, window) + const page = knowledgeService.listChunks( + knowledgeChunksListInputSchema.parse(input) + ) + return knowledgeChunkPageSchema.parse({ + items: page.items.map((chunk) => ({ + id: chunk.id, + ordinal: chunk.ordinal, + role: chunk.role, + parentChunkId: chunk.parentChunkId, + heading: chunk.heading, + locator: chunk.location, + characterCount: chunk.content.length, + enabled: chunk.enabled, + content: chunk.content, + manuallyEdited: chunk.manuallyEdited, + updatedAt: chunk.updatedAt + })), + page: page.page, + pageSize: page.pageSize, + totalItems: page.total + }) + } + ) + + registerHandler( + ipcChannels.knowledgeUpdateChunk, + async (event, input: unknown) => { + assertTrustedSender(event, window) + await knowledgeService.updateChunk( + knowledgeChunkUpdateInputSchema.parse(input) + ) + } + ) + + registerHandler( + ipcChannels.knowledgeDeleteChunk, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const deleted = await knowledgeService.deleteChunk( + knowledgeChunkDeleteInputSchema.parse(input) + ) + if (!deleted) { + throw new Error('知识分块不存在') + } + } + ) + + registerHandler( + ipcChannels.knowledgeRebuildDocument, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeDocumentRebuildInputSchema.parse(input) + await knowledgeService.rebuildDocument(value) + return getKnowledgeSnapshot( + knowledgeService, + value.knowledgeBaseId + ) + } + ) + + registerHandler( + ipcChannels.knowledgeRebuildLibrary, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeLibraryRebuildInputSchema.parse(input) + return knowledgeService.rebuildLibrary(value) + } + ) + + registerHandler( + ipcChannels.knowledgeCancelRebuild, + (event, input: unknown) => { + assertTrustedSender(event, window) + const knowledgeBaseId = knowledgeIdSchema.parse(input) + return knowledgeService.cancelLibraryRebuild(knowledgeBaseId) + } + ) + + registerHandler( + ipcChannels.knowledgeTaskCancel, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { taskId } = knowledgeTaskActionInputSchema.parse(input) + return knowledgeService.cancelTask(taskId) + } + ) + + registerHandler( + ipcChannels.knowledgeTaskRetry, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { taskId } = knowledgeTaskActionInputSchema.parse(input) + await knowledgeService.retryTask(taskId) + } + ) + + const embeddingConfiguration = async () => { + const settings = await settingsStore.getPublicSettings() + const connection = settings.embeddingConnections?.find( + (candidate) => + candidate.id === settings.activeEmbeddingConnectionId + ) + return connection?.kind === 'builtin' + ? { + provider: 'builtin', + model: 'granite-embedding-97m-multilingual-r2', + credentialConfigured: false + } + : { + provider: 'openai-compatible', + model: + connection?.modelName ?? + settings.knowledgeEmbeddingModel, + endpoint: + connection?.baseUrl ?? + settings.knowledgeEmbeddingBaseUrl, + credentialConfigured: + connection?.apiKeyConfigured ?? + settings.knowledgeEmbeddingApiKeyConfigured + } + } + + registerHandler( + ipcChannels.knowledgeEmbeddingIndexGet, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { knowledgeBaseId } = + knowledgeEmbeddingIndexRequestSchema.parse(input) + const settings = await settingsStore.getResolvedSettings() + return knowledgeEmbeddingIndexSnapshotSchema.parse( + await knowledgeService.getEmbeddingIndexSnapshot( + knowledgeBaseId, + settings.knowledgeEmbeddingEnabled + ? await embeddingConfiguration() + : undefined + ) + ) + } + ) + + registerHandler( + ipcChannels.knowledgeEmbeddingIndexRebuild, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { knowledgeBaseId } = + knowledgeEmbeddingIndexRequestSchema.parse(input) + const snapshot = await knowledgeService.rebuildEmbeddingIndex( + knowledgeBaseId, + await embeddingConfiguration() + ) + return knowledgeEmbeddingIndexSnapshotSchema.parse(snapshot) + } + ) + + registerHandler( + ipcChannels.knowledgeEmbeddingIndexCancel, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { knowledgeBaseId, jobId } = + knowledgeEmbeddingIndexCancelRequestSchema.parse(input) + return knowledgeService.cancelEmbeddingIndex( + knowledgeBaseId, + jobId + ) + } + ) + + registerHandler( + ipcChannels.knowledgeOpenDocumentSource, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeDocumentOpenInputSchema.parse(input) + const reference = knowledgeService.getDocumentSource(value) + if (!reference) { + throw new Error('文档来源不存在') + } + if (reference.source.type === 'url') { + const target = new URL(reference.source.location) + if (!['http:', 'https:'].includes(target.protocol)) { + throw new Error('文档来源 URL 协议不受支持') + } + await shell.openExternal(target.href) + return + } + const storedPath = + reference.document.sourceLocation ?? reference.source.location + if (!isAbsolute(storedPath)) { + throw new Error('文档来源路径无效') + } + if ((await lstat(storedPath)).isSymbolicLink()) { + throw new Error('文档来源不能是符号链接') + } + const targetPath = await realpath(storedPath) + if (!(await stat(targetPath)).isFile()) { + throw new Error('文档来源不是可打开的文件') + } + const openError = await shell.openPath(targetPath) + if (openError) { + throw new Error('无法打开文档来源') + } + } + ) + + registerHandler( + ipcChannels.knowledgeReferenceContext, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeReferenceContextInputSchema.parse(input) + const reference = knowledgeService.getReferenceContext(value) + if (!reference) { + throw new Error('引用上下文不存在或已停用') + } + const fullContext = reference.contextChunks + .map((chunk) => chunk.content) + .join('\n\n') + return knowledgeReferenceContextSchema.parse({ + knowledgeBaseId: value.knowledgeBaseId, + documentId: value.documentId, + chunkId: value.chunkId, + documentTitle: reference.document.title, + sourceDisplayName: reference.source.displayName, + locator: reference.chunk.location, + matchedContent: reference.chunk.content.slice(0, 48_000), + contextContent: fullContext.slice(0, 48_000), + contextChunkIds: reference.contextChunks.map((chunk) => chunk.id), + truncated: + reference.chunk.content.length > 48_000 || + fullContext.length > 48_000 + }) + } + ) + + registerHandler( + ipcChannels.knowledgeOpenReferenceSource, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeReferenceOpenInputSchema.parse(input) + const reference = knowledgeService.getReferenceContext(value) + if (!reference) { + throw new Error('引用来源不存在或已停用') + } + if (reference.source.type === 'url') { + const target = new URL(reference.source.location) + if (!['http:', 'https:'].includes(target.protocol)) { + throw new Error('引用来源 URL 协议不受支持') + } + await shell.openExternal(target.href) + return + } + const storedPath = + reference.document.sourceLocation ?? reference.source.location + if (!isAbsolute(storedPath)) { + throw new Error('引用来源路径无效') + } + if ((await lstat(storedPath)).isSymbolicLink()) { + throw new Error('引用来源不能是符号链接') + } + const targetPath = await realpath(storedPath) + const targetStat = await stat(targetPath) + if (!targetStat.isFile() && !targetStat.isDirectory()) { + throw new Error('引用来源不是可打开的文件或目录') + } + const openError = await shell.openPath(targetPath) + if (openError) { + throw new Error('无法打开引用来源') + } + } + ) + + registerHandler( + ipcChannels.knowledgeCreateEntity, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeCreateEntitySchema.parse(input) + knowledgeService.database.createEntity({ + knowledgeBaseId: value.libraryId, + name: value.input.label, + type: value.input.type, + description: value.input.description || undefined, + aliases: value.input.aliases, + locked: true + }) + } + ) + + registerHandler( + ipcChannels.knowledgeUpdateEntity, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeEntityPayloadSchema.parse(input) + knowledgeService.database.updateEntity(value.entityId, { + name: value.update.label, + type: value.update.type, + description: value.update.description || null, + aliases: value.update.aliases, + locked: true + }) + } + ) + + registerHandler( + ipcChannels.knowledgeMoveEntity, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeMoveEntitySchema.parse(input) + const entity = knowledgeService.database.getEntity(value.entityId) + if (!entity) { + throw new Error('图谱实体不存在') + } + knowledgeService.database.updateEntity(entity.id, { + properties: { + ...entity.properties, + x: value.position.x, + y: value.position.y + } + }) + } + ) + + registerHandler( + ipcChannels.knowledgeDeleteEntity, + (event, input: unknown) => { + assertTrustedSender(event, window) + knowledgeService.database.deleteEntity(knowledgeIdSchema.parse(input)) + } + ) + + registerHandler( + ipcChannels.knowledgeMergeEntities, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeMergeSchema.parse(input) + knowledgeService.database.mergeEntities( + value.targetEntityId, + value.sourceEntityId + ) + } + ) + + registerHandler( + ipcChannels.knowledgeCreateRelation, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeCreateRelationSchema.parse(input) + knowledgeService.database.createRelation({ + knowledgeBaseId: value.libraryId, + sourceEntityId: value.input.sourceId, + targetEntityId: value.input.targetId, + type: value.input.type, + label: value.input.description || undefined, + locked: true + }) + } + ) + + registerHandler( + ipcChannels.knowledgeUpdateRelation, + (event, input: unknown) => { + assertTrustedSender(event, window) + const value = knowledgeUpdateRelationSchema.parse(input) + knowledgeService.database.updateRelation(value.relationId, { + sourceEntityId: value.input.sourceId, + targetEntityId: value.input.targetId, + type: value.input.type, + label: value.input.description || null, + locked: true + }) + } + ) + + registerHandler( + ipcChannels.knowledgeDeleteRelation, + (event, input: unknown) => { + assertTrustedSender(event, window) + knowledgeService.database.deleteRelation(knowledgeIdSchema.parse(input)) + } + ) +} diff --git a/src/main/local-tool-environment/local-tool-environment-ipc.ts b/src/main/local-tool-environment/local-tool-environment-ipc.ts new file mode 100644 index 00000000..c3da6895 --- /dev/null +++ b/src/main/local-tool-environment/local-tool-environment-ipc.ts @@ -0,0 +1,90 @@ +import type { BrowserWindow, ipcMain } from 'electron' +import { z } from 'zod' +import { ipcChannels } from '../../shared/ipc-channels' +import { + localToolDiagnoseInputSchema, + localToolEnvironmentSettingsSchema, + localToolKindInputSchema +} from '../../shared/local-tool-environment-contracts' +import { assertTrustedSender } from '../trusted-ipc-sender' +import type { LocalToolEnvironmentService } from './local-tool-environment-service' + +export function registerLocalToolEnvironmentIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + localToolEnvironmentService?: LocalToolEnvironmentService +): void { + const requireLocalToolEnvironmentService = + (): LocalToolEnvironmentService => { + if (!localToolEnvironmentService) { + throw new Error('本地工具环境服务不可用') + } + return localToolEnvironmentService + } + + registerHandler( + ipcChannels.localToolEnvironmentGet, + (event, input: unknown) => { + assertTrustedSender(event, window) + z.undefined().parse(input) + return requireLocalToolEnvironmentService().getSnapshot() + } + ) + registerHandler( + ipcChannels.localToolEnvironmentUpdate, + (event, input: unknown) => { + assertTrustedSender(event, window) + return requireLocalToolEnvironmentService().updateSettings( + localToolEnvironmentSettingsSchema.parse(input) + ) + } + ) + registerHandler( + ipcChannels.localToolEnvironmentRefresh, + (event, input: unknown) => { + assertTrustedSender(event, window) + z.undefined().parse(input) + return requireLocalToolEnvironmentService().refreshCandidates() + } + ) + registerHandler( + ipcChannels.localToolEnvironmentSelectExecutable, + (event, input: unknown) => { + assertTrustedSender(event, window) + const { kind } = localToolKindInputSchema.parse(input) + return requireLocalToolEnvironmentService().selectExecutable(kind) + } + ) + registerHandler( + ipcChannels.localToolEnvironmentDiagnose, + (event, input: unknown) => { + assertTrustedSender(event, window) + const { kind } = localToolDiagnoseInputSchema.parse(input) + return requireLocalToolEnvironmentService().diagnose(kind) + } + ) + registerHandler( + ipcChannels.localToolEnvironmentInstallPython, + (event, input: unknown) => { + assertTrustedSender(event, window) + z.undefined().parse(input) + return requireLocalToolEnvironmentService().installPython() + } + ) + registerHandler( + ipcChannels.localToolEnvironmentCancelPython, + (event, input: unknown) => { + assertTrustedSender(event, window) + z.undefined().parse(input) + return requireLocalToolEnvironmentService().cancelPython() + } + ) + registerHandler( + ipcChannels.localToolEnvironmentRemovePython, + (event, input: unknown) => { + assertTrustedSender(event, window) + z.undefined().parse(input) + return requireLocalToolEnvironmentService().removePython() + } + ) +} diff --git a/src/main/magic-notes/magic-notes-analysis-ipc.ts b/src/main/magic-notes/magic-notes-analysis-ipc.ts new file mode 100644 index 00000000..cf55b184 --- /dev/null +++ b/src/main/magic-notes/magic-notes-analysis-ipc.ts @@ -0,0 +1,253 @@ +import { randomUUID } from 'node:crypto' +import type { BrowserWindow, ipcMain } from 'electron' +import { ipcChannels } from '../../shared/ipc-channels' +import { + magicNoteAnalyzeSchema, + magicNoteDraftAnalyzeSchema, + magicTodoIdSchema +} from '../../shared/magic-notes-contracts' +import { createDefaultModelRuntime } from '../agent/create-runtime' +import type { RuntimeModelUsageEvent } from '../agent/runtime' +import type { ApplicationSettingsStore } from '../application-settings-store' +import type { AssistantDatabase } from '../assistant/assistant-database' +import type { RuntimeSettingsStore } from '../runtime-settings-store' +import { assertTrustedSender } from '../trusted-ipc-sender' +import { + analyzeMagicNoteDraft, + analyzeMagicNoteEntry, + analyzeMagicTodo +} from './magic-note-analyzer' +import { magicNotePlainText, validateMagicNoteContent } from './rich-content' + +type AnalysisDependencies = { + window: BrowserWindow + assistantDatabase: AssistantDatabase + settingsStore: Pick + applicationSettingsStore?: Pick + persistModelUsage: (event: RuntimeModelUsageEvent) => void + safeRuntimeError: (error: unknown, fallback: string) => string +} + +export function registerMagicNotesAnalysisIpcHandlers( + registerHandler: typeof ipcMain.handle, + { window, assistantDatabase, settingsStore, applicationSettingsStore, persistModelUsage, safeRuntimeError }: AnalysisDependencies +): void { + registerHandler( + ipcChannels.magicNotesAnalyze, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { entryId, requestId, direction, format, canvasImages, canvasPageText, expectedRevision } = + magicNoteAnalyzeSchema.parse(input) + const settings = await settingsStore.getResolvedSettings() + const entry = assistantDatabase.getMagicNoteEntry(entryId) + if (expectedRevision !== undefined && entry.revision !== expectedRevision) { + throw new Error('记录已被更新,请重新捕获并分析') + } + const note = assistantDatabase.getMagicNoteContext(entry.noteId) + const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 + const analysisRuntime = createDefaultModelRuntime( + settings.workspacePath, + settings + ) + assistantDatabase.createTask({ + id: requestId, + title: `分析笔记:${note.title}`, + instructions: '使用无工具模型对笔记记录进行只读分析', + workMode: 'ask', + origin: 'assistant', + visible: false + }) + try { + const comments = await analyzeMagicNoteEntry( + analysisRuntime, + entry, + { requestId, direction, format, canvasImages, canvasPageText }, + format === 'structured' + ? undefined + : (delta) => { + if (!window.isDestroyed()) { + window.webContents.send( + ipcChannels.magicNotesAnalysisEvent, + { + requestId, + type: 'text', + delta, + direction, + format + } + ) + } + }, + persistModelUsage, + { supportsImageInput: settings.supportsImageInput === true, canvasPageCount } + ) + const analyzedNote = assistantDatabase.saveMagicNoteAnalysis({ + entryId, + expectedRevision: entry.revision, + comments + }) + assistantDatabase.updateTaskStatus(requestId, 'completed') + return analyzedNote + } catch (error) { + const message = safeRuntimeError(error, '魔法笔记 AI 分析失败') + assistantDatabase.updateTaskStatus(requestId, 'failed', message) + throw new Error(message, { cause: error }) + } finally { + try { + await analysisRuntime.releaseConversation?.( + `magic-notes:${entry.id}` + ) + } finally { + await analysisRuntime.dispose() + } + } + } + ) + + registerHandler( + ipcChannels.magicNotesAnalyzeDraft, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const parsed = magicNoteDraftAnalyzeSchema.parse(input) + const content = validateMagicNoteContent(parsed.content) + const plainText = magicNotePlainText(content) + const settings = await settingsStore.getResolvedSettings() + const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 + const analysisRuntime = createDefaultModelRuntime( + settings.workspacePath, + settings + ) + const { requestId, direction, format, canvasImages, canvasPageText } = parsed + assistantDatabase.createTask({ + id: requestId, + title: '分析未保存笔记草稿', + instructions: '使用无工具模型对未保存笔记草稿进行只读分析', + workMode: 'ask', + origin: 'assistant', + visible: false + }) + try { + const comments = await analyzeMagicNoteDraft( + analysisRuntime, + plainText, + { requestId, direction, format, canvasImages, canvasPageText }, + format === 'structured' + ? undefined + : (delta) => { + if (!window.isDestroyed()) { + window.webContents.send( + ipcChannels.magicNotesAnalysisEvent, + { + requestId, + type: 'text', + delta, + direction, + format + } + ) + } + }, + persistModelUsage, + { supportsImageInput: settings.supportsImageInput === true, content, canvasPageCount } + ) + assistantDatabase.updateTaskStatus(requestId, 'completed') + return { + id: randomUUID(), + comments, + inputMode: comments[0]?.inputMode, + analyzedAt: new Date().toISOString() + } + } catch (error) { + const message = safeRuntimeError(error, '魔法笔记草稿 AI 分析失败') + assistantDatabase.updateTaskStatus(requestId, 'failed', message) + throw new Error(message, { cause: error }) + } finally { + try { + await analysisRuntime.releaseConversation?.( + `magic-note-drafts:${requestId}` + ) + } finally { + await analysisRuntime.dispose() + } + } + } + ) +} + +export function registerMagicTodosAnalysisIpcHandlers( + registerHandler: typeof ipcMain.handle, + { window, assistantDatabase, settingsStore, applicationSettingsStore, persistModelUsage, safeRuntimeError }: AnalysisDependencies +): void { + registerHandler( + ipcChannels.magicTodosAnalyze, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const { todoId, requestId, direction, format, canvasImages, canvasPageText, sourceEntryRevision } = + magicTodoIdSchema.parse(input) + const settings = await settingsStore.getResolvedSettings() + const todo = assistantDatabase.getMagicTodo(todoId) + const canvasPageCount = (await applicationSettingsStore?.get())?.magicNoteCanvasPageCount ?? 1 + const entry = assistantDatabase.getMagicNoteEntry(todo.entryId) + if (sourceEntryRevision !== undefined && entry.revision !== sourceEntryRevision) { + throw new Error('来源记录已被更新,请重新捕获并分析') + } + const analysisRuntime = createDefaultModelRuntime( + settings.workspacePath, + settings + ) + assistantDatabase.createTask({ + id: requestId, + title: `分析待办:${todo.title}`, + instructions: '使用无工具模型对魔法笔记待办进行只读分析', + workMode: 'ask', + origin: 'assistant', + visible: false + }) + try { + const comments = await analyzeMagicTodo( + analysisRuntime, + todo, + { requestId, direction, format, canvasImages, canvasPageText }, + format === 'structured' + ? undefined + : (delta) => { + if (!window.isDestroyed()) { + window.webContents.send( + ipcChannels.magicNotesAnalysisEvent, + { + requestId, + type: 'text', + delta, + direction, + format + } + ) + } + }, + persistModelUsage, + { supportsImageInput: settings.supportsImageInput === true, content: entry.content, canvasPageCount } + ) + const analyzedTodo = assistantDatabase.saveMagicTodoAnalysis({ + todoId, + expectedRevision: todo.revision, + sourceEntryRevision: entry.revision, + comments + }) + assistantDatabase.updateTaskStatus(requestId, 'completed') + return analyzedTodo + } catch (error) { + const message = safeRuntimeError(error, '魔法笔记待办 AI 分析失败') + assistantDatabase.updateTaskStatus(requestId, 'failed', message) + throw new Error(message, { cause: error }) + } finally { + try { + await analysisRuntime.releaseConversation?.( + `magic-todos:${todo.id}` + ) + } finally { + await analysisRuntime.dispose() + } + } + } + ) +} diff --git a/src/main/magic-notes/magic-notes-ipc.ts b/src/main/magic-notes/magic-notes-ipc.ts new file mode 100644 index 00000000..5d2c758f --- /dev/null +++ b/src/main/magic-notes/magic-notes-ipc.ts @@ -0,0 +1,154 @@ +import type { BrowserWindow, ipcMain } from 'electron' +import { ipcChannels } from '../../shared/ipc-channels' +import { + magicNoteCreateSchema, + magicNoteSearchSchema, + type MagicNoteSource, + magicNoteDeleteSchema, + magicNoteEntryCreateSchema, + magicNoteEntryDeleteSchema, + magicNoteEntryUpdateSchema, + magicNoteUpdateSchema, + magicTodoUpdateSchema +} from '../../shared/magic-notes-contracts' +import type { AssistantDatabase } from '../assistant/assistant-database' +import { assertTrustedSender } from '../trusted-ipc-sender' +import { magicNotePlainText, validateMagicNoteContent } from './rich-content' + +export function registerMagicNotesIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + assistantDatabase: AssistantDatabase +): void { + const resolveMagicNoteSource = (source?: MagicNoteSource): MagicNoteSource | undefined => { + if (!source) return undefined + const conversation = assistantDatabase.getConversation(source.conversationId) + const messages = new Map(conversation.messages.map((message) => [message.id, message])) + for (const id of source.messageIds) { + const message = messages.get(id) + if (!message || (source.kind === 'message' && message.role !== 'assistant')) { + throw new Error('Invalid conversation source message') + } + } + const project = conversation.projectId ? assistantDatabase.getProject(conversation.projectId) : undefined + return { + kind: source.kind, + conversationId: conversation.id, + messageIds: source.messageIds, + capturedAt: source.capturedAt, + conversationTitle: conversation.title, + ...(project ? { projectId: project.id, projectName: project.name } : {}) + } + } + + registerHandler(ipcChannels.magicNotesSearch, (event, input: unknown) => { + assertTrustedSender(event, window) + const { query, limit } = magicNoteSearchSchema.parse(input) + return assistantDatabase.searchMagicNoteSummaries(query, limit) + }) + + registerHandler(ipcChannels.magicNotesList, (event) => { + assertTrustedSender(event, window) + return { notes: assistantDatabase.listMagicNotes() } + }) + + registerHandler(ipcChannels.magicNotesGet, (event, input: unknown) => { + assertTrustedSender(event, window) + const { noteId } = magicNoteDeleteSchema.parse(input) + return assistantDatabase.getMagicNote(noteId) + }) + + registerHandler(ipcChannels.magicNotesCreate, (event, input: unknown) => { + assertTrustedSender(event, window) + const parsed = magicNoteCreateSchema.parse(input) + return assistantDatabase.createMagicNote({ ...parsed, source: resolveMagicNoteSource(parsed.source) }) + }) + + registerHandler(ipcChannels.magicNotesUpdate, (event, input: unknown) => { + assertTrustedSender(event, window) + return assistantDatabase.updateMagicNote( + magicNoteUpdateSchema.parse(input) + ) + }) + + registerHandler(ipcChannels.magicNotesDelete, (event, input: unknown) => { + assertTrustedSender(event, window) + const { noteId } = magicNoteDeleteSchema.parse(input) + assistantDatabase.deleteMagicNote(noteId) + }) + + registerHandler( + ipcChannels.magicNotesCreateEntry, + (event, input: unknown) => { + assertTrustedSender(event, window) + const parsed = magicNoteEntryCreateSchema.parse(input) + const content = validateMagicNoteContent(parsed.content) + return assistantDatabase.createMagicNoteEntry({ + noteId: parsed.noteId, + content, + source: resolveMagicNoteSource(parsed.source), + plainText: magicNotePlainText(content) + }) + } + ) + + registerHandler( + ipcChannels.magicNotesUpdateEntry, + (event, input: unknown) => { + assertTrustedSender(event, window) + const parsed = magicNoteEntryUpdateSchema.parse(input) + const content = validateMagicNoteContent(parsed.content) + return assistantDatabase.updateMagicNoteEntry({ + entryId: parsed.entryId, + expectedRevision: parsed.expectedRevision, + content, + plainText: magicNotePlainText(content) + }) + } + ) + + registerHandler( + ipcChannels.magicNotesDeleteEntry, + (event, input: unknown) => { + assertTrustedSender(event, window) + const { entryId } = magicNoteEntryDeleteSchema.parse(input) + return assistantDatabase.deleteMagicNoteEntry(entryId) + } + ) +} + +export function registerMagicTodosIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + assistantDatabase: AssistantDatabase +): void { + registerHandler( + ipcChannels.magicTodosList, + (event) => { + assertTrustedSender(event, window) + return { todos: assistantDatabase.listMagicTodos() } + } + ) + + registerHandler( + ipcChannels.magicTodosStatus, + (event) => { + assertTrustedSender(event, window) + return assistantDatabase.getMagicTodoStatus() + } + ) + + registerHandler( + ipcChannels.magicTodosUpdate, + (event, input: unknown) => { + assertTrustedSender(event, window) + const todo = assistantDatabase.updateMagicTodo( + magicTodoUpdateSchema.parse(input) + ) + return { + todo, + note: assistantDatabase.getMagicNote(todo.noteId) + } + } + ) +} diff --git a/src/main/ssh/ssh-connection-pool.test.ts b/src/main/ssh/ssh-connection-pool.test.ts index 70e39010..6c501af1 100644 --- a/src/main/ssh/ssh-connection-pool.test.ts +++ b/src/main/ssh/ssh-connection-pool.test.ts @@ -59,6 +59,7 @@ function createConnection(identity: SshPoolConnectionIdentity) { return { identity, isUsable: vi.fn(() => true), + forwardLoopback: vi.fn(), onDisconnect: vi.fn(() => () => undefined), openTerminalShell: vi.fn(), openAgentAttach: vi.fn(), diff --git a/src/main/ssh/ssh-connection-pool.ts b/src/main/ssh/ssh-connection-pool.ts index 0a92d061..85f8af56 100644 --- a/src/main/ssh/ssh-connection-pool.ts +++ b/src/main/ssh/ssh-connection-pool.ts @@ -1,4 +1,5 @@ import { createHmac, getCiphers, randomBytes } from "node:crypto"; +import { connect as connectLoopback, type Socket } from "node:net"; import { Client } from "ssh2"; import type { ClientChannel, ConnectConfig, SFTPWrapper } from "ssh2"; import { @@ -69,12 +70,18 @@ export type SshTerminalShellOptions = { cols: number; rows: number; term?: string; + /** Main-generated native launch, not part of the renderer terminal contract. */ + command?: string; + pty?: false; }; +export type SshLoopbackForward = { port: number; close(): Promise }; + export interface AuthenticatedSshConnection { readonly identity: SshPoolConnectionIdentity; isUsable(): boolean; onDisconnect(listener: (error?: Error) => void): () => void; + forwardLoopback(localPort: number): Promise; openTerminalShell( options: SshTerminalShellOptions, signal?: AbortSignal, @@ -170,7 +177,7 @@ type InternalSshConnectionLease = SshTerminalConnectionLease & type ClientLike = Pick< Client, - "connect" | "end" | "destroy" | "exec" | "shell" | "sftp" | "on" | "once" + "connect" | "end" | "destroy" | "exec" | "shell" | "sftp" | "on" | "once" | "removeListener" | "forwardIn" | "unforwardIn" >; type SshConnectionDependencies = { @@ -468,20 +475,58 @@ export class Ssh2AuthenticatedConnection implements AuthenticatedSshConnection { finish(new Error("SSH 终端通道打开超时")); }, CHANNEL_OPEN_TIMEOUT_MS); signal?.addEventListener("abort", abort, { once: true }); - this.client.shell( - { + const pty = { term: options.term ?? "xterm-256color", cols: options.cols, rows: options.rows, width: 0, height: 0, - }, - { env: {}, x11: false }, - (error, channel) => finish(error, channel), - ); + }; + if (options.command) { + this.client.exec(options.command, { pty: options.pty === false ? false : pty, env: {}, x11: false }, (error, channel) => finish(error, channel)); + } else { + this.client.shell(pty, { env: {}, x11: false }, (error, channel) => finish(error, channel)); + } }); } + async forwardLoopback(localPort: number): Promise { + this.assertUsable(); + const port = await new Promise((resolve, reject) => { + this.client.forwardIn("127.0.0.1", 0, (error, allocated) => error ? reject(error) : resolve(allocated)); + }); + const streams = new Set(); + const acceptConnection = (details: { destPort: number }, accept: () => ClientChannel): void => { + if (details.destPort !== port) return; + const remote = accept(); + const local = connectLoopback({ host: "127.0.0.1", port: localPort }); + streams.add(remote); + streams.add(local); + const close = (): void => { + streams.delete(remote); + streams.delete(local); + remote.destroy(); + local.destroy(); + }; + remote.once("error", close); + local.once("error", close); + remote.once("close", close); + local.once("close", close); + remote.pipe(local).pipe(remote); + }; + this.client.on("tcp connection", acceptConnection); + let closing: Promise | undefined; + const removeDisconnect = this.onDisconnect(() => { void close(); }); + const close = (): Promise => closing ??= (async () => { + removeDisconnect(); + this.client.removeListener("tcp connection", acceptConnection); + for (const stream of streams) stream.destroy(); + streams.clear(); + if (this.isUsable()) await new Promise(resolve => this.client.unforwardIn("127.0.0.1", port, () => resolve())); + })(); + return { port, close }; + } + async openAgentAttach( installationId: VerifiedAgentInstallationId, signal?: AbortSignal, @@ -1023,6 +1068,10 @@ export class SshConnectionPool { assertActive(); return connection.openTerminalShell(options, signal); }, + forwardLoopback: (localPort) => { + assertActive(); + return connection.forwardLoopback(localPort); + }, openAgentAttach: (installationId, signal) => { assertActive(); return connection.openAgentAttach(installationId, signal); diff --git a/src/main/ssh/ssh-host-directory-browser.test.ts b/src/main/ssh/ssh-host-directory-browser.test.ts index b2339568..a144e839 100644 --- a/src/main/ssh/ssh-host-directory-browser.test.ts +++ b/src/main/ssh/ssh-host-directory-browser.test.ts @@ -52,6 +52,7 @@ function createLease( ...identity }, isUsable: vi.fn(() => true), + forwardLoopback: vi.fn(), openAgentAttach: vi.fn(), runAgentDoctor: vi.fn(), runAgentBootstrapProbe: vi.fn(), diff --git a/src/main/terminal/local-terminal-session.test.ts b/src/main/terminal/local-terminal-session.test.ts index f44d9e44..ec3ddf54 100644 --- a/src/main/terminal/local-terminal-session.test.ts +++ b/src/main/terminal/local-terminal-session.test.ts @@ -93,6 +93,24 @@ function sessionDependencies( } describe('local terminal launch resolution', () => { + it('spawns a Main-owned native executable directly without typing a shell command', async () => { + const pty = new FakePty() + const dependencies = sessionDependencies(pty) + const spawnSpec = { executable: '/managed/node', args: ['/managed/cn.js', '--config', '/config with spaces.json'], cwd: '/project', env: { PATH: '/managed' }, label: 'Continue' } + const session = await LocalTerminalSession.create({ ...baseOptions, spawnSpec, dependencies }) + expect(dependencies.spawn).toHaveBeenCalledWith(spawnSpec.executable, spawnSpec.args, expect.objectContaining({ cwd: '/project', env: spawnSpec.env })) + expect(pty.write).not.toHaveBeenCalled() + expect(session.snapshot()).toMatchObject({ state: 'running', shell: 'Continue', workingDirectory: '/project' }) + await session.close() + }) + + it('fails a native launch with an invalid project directory instead of falling back home', async () => { + const dependencies = sessionDependencies(new FakePty(), { directoryExists: async (path: string) => path === '/home/tester' }) + const session = await LocalTerminalSession.create({ ...baseOptions, dependencies, + spawnSpec: { executable: '/managed/opencode', args: [], cwd: '/missing', env: {}, label: 'OpenCode' } }) + expect(session.snapshot().state).toBe('failed') + expect(dependencies.spawn).not.toHaveBeenCalled() + }) it('prefers pwsh, then PowerShell, then COMSPEC on Windows', async () => { const available = new Set(['C:\\bin\\powershell.EXE']) const shell = await resolveLocalTerminalShell({ diff --git a/src/main/terminal/local-terminal-session.ts b/src/main/terminal/local-terminal-session.ts index 419d50f4..2264ff0d 100644 --- a/src/main/terminal/local-terminal-session.ts +++ b/src/main/terminal/local-terminal-session.ts @@ -29,6 +29,15 @@ export type LocalTerminalLaunch = { env: NodeJS.ProcessEnv } +/** Main-owned launch material. Never accepted by the terminal IPC contract. */ +export type NativeTerminalSpawnSpec = { + executable: string + args: string[] + cwd: string + env: NodeJS.ProcessEnv + label: string +} + export type LocalPtySpawn = ( file: string, args: string[], @@ -52,6 +61,7 @@ export type LocalTerminalSessionOptions = { title: string size: TerminalSize projectDirectory?: string + spawnSpec?: NativeTerminalSpawnSpec dependencies?: LocalTerminalDependencies } @@ -370,14 +380,23 @@ export class LocalTerminalSession { private async start(): Promise { try { - this.launch = await resolveLocalTerminalLaunch( + const spec = this.options.spawnSpec + if (spec && !(await (this.dependencies.directoryExists ?? defaultDirectoryExists)(spec.cwd))) { + throw new Error('Native client project directory is unavailable') + } + this.launch = spec ? { + shell: spec.executable, + shellLabel: spec.label, + cwd: spec.cwd, + env: spec.env + } : await resolveLocalTerminalLaunch( this.options.target.type === 'project' ? this.options.projectDirectory : undefined, this.dependencies ) const spawn = this.dependencies.spawn ?? nodePty.spawn - this.pty = spawn(this.launch.shell, [], { + this.pty = spawn(this.launch.shell, spec?.args ?? [], { name: 'xterm-256color', cols: this.size.cols, rows: this.size.rows, diff --git a/src/main/terminal/ssh-terminal-session.test.ts b/src/main/terminal/ssh-terminal-session.test.ts index f860d589..45f2892a 100644 --- a/src/main/terminal/ssh-terminal-session.test.ts +++ b/src/main/terminal/ssh-terminal-session.test.ts @@ -64,6 +64,7 @@ function createHarness(idleTimeoutMs = 60_000) { const connection = { identity, isUsable: vi.fn(() => usable), + forwardLoopback: vi.fn(), onDisconnect: vi.fn((listener: (error?: Error) => void) => { disconnectListeners.add(listener); return () => disconnectListeners.delete(listener); diff --git a/src/main/terminal/ssh-terminal-session.ts b/src/main/terminal/ssh-terminal-session.ts index 2a17c5bd..94c03c3f 100644 --- a/src/main/terminal/ssh-terminal-session.ts +++ b/src/main/terminal/ssh-terminal-session.ts @@ -25,6 +25,7 @@ export type SshTerminalSessionOptions = { targetLabel: string; title: string; shell?: string; + command?: string; workingDirectory?: string; size: TerminalSize; poolTarget: SshConnectionPoolTarget; @@ -95,7 +96,7 @@ export async function createSshTerminalSession( options: SshTerminalSessionOptions, ): Promise { const initialSize = terminalSizeSchema.parse(options.size); - const workingDirectoryCommand = options.workingDirectory + const workingDirectoryCommand = options.workingDirectory && !options.command ? `cd -- ${quotePosixShellArgument(options.workingDirectory)} || exit\r` : undefined; const lease = await pool.acquireTerminal(options.poolTarget, options.signal); @@ -106,6 +107,7 @@ export async function createSshTerminalSession( cols: initialSize.cols, rows: initialSize.rows, term: SSH_TERMINAL_TERM, + ...(options.command ? { command: options.command } : {}), }, options.signal, ); diff --git a/src/main/terminal/terminal-ipc.ts b/src/main/terminal/terminal-ipc.ts new file mode 100644 index 00000000..5eaaeebd --- /dev/null +++ b/src/main/terminal/terminal-ipc.ts @@ -0,0 +1,111 @@ +import type { BrowserWindow, ipcMain } from 'electron' +import { ipcChannels } from '../../shared/ipc-channels' +import { + terminalAckRequestSchema, + terminalCloseRequestSchema, + terminalCreateRequestSchema, + terminalResizeRequestSchema, + terminalSnapshotRequestSchema, + terminalWriteRequestSchema +} from '../../shared/terminal-contracts' +import { assertTrustedSender } from '../trusted-ipc-sender' +import type { TerminalSessionManager } from './terminal-session-manager' + +export function registerTerminalIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow, + terminalSessionManager?: TerminalSessionManager +): void { + const requireTerminalSessionManager = (): TerminalSessionManager => { + if (!terminalSessionManager) { + throw new Error('终端服务不可用') + } + return terminalSessionManager + } + + registerHandler( + ipcChannels.terminalCreate, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const snapshot = await manager.create( + event.sender.id, + terminalCreateRequestSchema.parse(input) + ) + setImmediate(() => { + if ( + !window.isDestroyed() && + event.sender === window.webContents && + !event.sender.isDestroyed() + ) { + manager.enableEventDelivery( + event.sender.id, + snapshot.sessionId + ) + } + }) + return snapshot + } + ) + + registerHandler(ipcChannels.terminalWrite, (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const request = terminalWriteRequestSchema.parse(input) + manager.write( + event.sender.id, + request.sessionId, + request.data + ) + }) + + registerHandler(ipcChannels.terminalResize, (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const request = terminalResizeRequestSchema.parse(input) + manager.resize(event.sender.id, request.sessionId, { + cols: request.cols, + rows: request.rows + }) + }) + + registerHandler( + ipcChannels.terminalSnapshot, + (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const request = terminalSnapshotRequestSchema.parse(input) + return manager.snapshot( + event.sender.id, + request.sessionId + ) + } + ) + + registerHandler( + ipcChannels.terminalAck, + (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const request = terminalAckRequestSchema.parse(input) + manager.acknowledge( + event.sender.id, + request.sessionId, + request.sequence + ) + } + ) + + registerHandler( + ipcChannels.terminalClose, + async (event, input: unknown) => { + assertTrustedSender(event, window) + const manager = requireTerminalSessionManager() + const request = terminalCloseRequestSchema.parse(input) + return manager.close( + event.sender.id, + request.sessionId + ) + } + ) +} diff --git a/src/main/terminal/terminal-session-manager.test.ts b/src/main/terminal/terminal-session-manager.test.ts index 7734456d..bbe8e8d0 100644 --- a/src/main/terminal/terminal-session-manager.test.ts +++ b/src/main/terminal/terminal-session-manager.test.ts @@ -160,6 +160,28 @@ function harness( } describe('TerminalSessionManager routing and delivery', () => { + it('releases native resources on exit before delivery, exactly once through close', async () => { + const test = harness() + const dispose = vi.fn(async () => undefined) + const launch = { spawnSpec: { executable: '/runtime', args: [], cwd: '/authoritative/root', env: {}, label: 'OpenCode' }, title: 'OpenCode', dispose } + const result = await test.manager.create(1, { target: { type: 'project', projectId }, cols: 80, rows: 24 }, launch) + expect(test.createLocalSession.mock.calls[0]?.[0]).toMatchObject({ spawnSpec: launch.spawnSpec, title: 'OpenCode' }) + test.localSessions[0]!.emit({ sessionId: result.sessionId, sequence: 2, type: 'state', state: 'exited' }) + expect(dispose).toHaveBeenCalledTimes(1) + expect(test.delivered).toHaveLength(0) + await test.manager.close(1, result.sessionId) + expect(dispose).toHaveBeenCalledTimes(1) + }) + + it('releases native resources when execution-space resolution disagrees', async () => { + const test = harness() + const dispose = vi.fn(async () => undefined) + await expect(test.manager.create(1, { target: { type: 'project', projectId }, cols: 80, rows: 24 }, { + spawnSpec: { executable: '/runtime', args: [], cwd: '/different', env: {}, label: 'OpenCode' }, title: 'OpenCode', dispose + })).rejects.toThrow('execution space') + expect(dispose).toHaveBeenCalledOnce() + expect(test.createLocalSession).not.toHaveBeenCalled() + }) it('routes Home local and authoritative local project roots', async () => { const test = harness() const local = await test.manager.create(1, { diff --git a/src/main/terminal/terminal-session-manager.ts b/src/main/terminal/terminal-session-manager.ts index 5530a924..c33a09dc 100644 --- a/src/main/terminal/terminal-session-manager.ts +++ b/src/main/terminal/terminal-session-manager.ts @@ -19,6 +19,7 @@ import type { } from '../ssh/ssh-connection-pool' import { LocalTerminalSession, + type NativeTerminalSpawnSpec, type LocalTerminalSessionOptions } from './local-terminal-session' import { @@ -73,6 +74,14 @@ type SessionRecord = { ready: Promise closePromise?: Promise removeEventListener?: () => void + releaseResources?: () => Promise +} + +export type NativeTerminalLaunch = { + spawnSpec: NativeTerminalSpawnSpec + title: string + dispose(): Promise + remote?: { hostId: string; hostRevision: number; hostKeyGeneration: number; command: string } } type ResolvedLaunch = @@ -103,7 +112,8 @@ export class TerminalSessionManager { async create( ownerWebContentsId: number, - request: TerminalCreateRequest + request: TerminalCreateRequest, + nativeLaunch?: NativeTerminalLaunch ): Promise { this.assertOwnerId(ownerWebContentsId) if (this.disposed) { @@ -130,16 +140,26 @@ export class TerminalSessionManager { closing: false, ready: Promise.resolve(undefined as never) } + if (nativeLaunch) { + let release: Promise | undefined + record.releaseResources = () => release ??= nativeLaunch.dispose() + } this.records.set(sessionId, record) - record.ready = this.createSession(record, request) + record.ready = this.createSession(record, request, nativeLaunch) try { const session = await record.ready + if (nativeLaunch && session.snapshot().state === 'failed') { + const message = session.snapshot().error?.message ?? 'Native terminal failed to start' + await this.closeRecord(record) + throw new Error(message) + } if (record.closing) { return await this.closeRecord(record) } return session.snapshot() } catch (error) { + await record.releaseResources?.() if (this.records.get(sessionId) === record) { this.records.delete(sessionId) } @@ -263,14 +283,24 @@ export class TerminalSessionManager { private async createSession( record: SessionRecord, - request: TerminalCreateRequest + request: TerminalCreateRequest, + nativeLaunch?: NativeTerminalLaunch ): Promise { const launch = await this.resolveLaunch(request) + if (nativeLaunch) { + const remote = nativeLaunch.remote + const matches = remote + ? launch.kind === 'ssh' && launch.workingDirectory === nativeLaunch.spawnSpec.cwd && + launch.poolTarget.host.id === remote.hostId && launch.poolTarget.hostRevision === remote.hostRevision && + launch.poolTarget.hostKeyGeneration === remote.hostKeyGeneration + : launch.kind === 'local' && launch.projectDirectory === nativeLaunch.spawnSpec.cwd + if (!matches) throw new Error('Native terminal launch does not match the project execution space') + } const common = { sessionId: record.sessionId, target: request.target, targetLabel: launch.targetLabel, - title: `终端 · ${launch.targetLabel}`, + title: nativeLaunch?.title ?? `终端 · ${launch.targetLabel}`, size: { cols: request.cols, rows: request.rows } } let session: ManagedTerminalSession @@ -284,7 +314,8 @@ export class TerminalSessionManager { TerminalCreateRequest['target'], { type: 'local' | 'project' } >, - projectDirectory: launch.projectDirectory + projectDirectory: launch.projectDirectory, + ...(nativeLaunch ? { spawnSpec: nativeLaunch.spawnSpec } : {}) }) record.session = session record.removeEventListener = session.onEvent?.((event) => @@ -299,6 +330,7 @@ export class TerminalSessionManager { ...common, workingDirectory: launch.workingDirectory, poolTarget: launch.poolTarget, + ...(nativeLaunch?.remote ? { command: nativeLaunch.remote.command, shell: nativeLaunch.spawnSpec.label } : {}), onEvent: (event) => this.handleEvent(record, event) }) record.session = session @@ -376,6 +408,10 @@ export class TerminalSessionManager { if (this.records.get(record.sessionId) !== record) { return } + if (event.type === 'state' && ['exited', 'failed', 'interrupted'].includes(event.state)) { + // Cleanup must also happen while event delivery is waiting for the IPC reply. + void record.releaseResources?.().catch(() => undefined) + } if (!record.deliveryEnabled) { record.delayedEvents.push(event) return @@ -413,6 +449,7 @@ export class TerminalSessionManager { try { const session = await record.ready const closed = await session.close() + await record.releaseResources?.() const snapshot = closed && typeof closed === 'object' && 'sessionId' in closed ? closed diff --git a/src/main/window-ipc.ts b/src/main/window-ipc.ts new file mode 100644 index 00000000..86b92768 --- /dev/null +++ b/src/main/window-ipc.ts @@ -0,0 +1,59 @@ +import { clipboard, type BrowserWindow, type ipcMain } from 'electron' +import { clipboardTextSchema } from '../shared/contracts' +import { ipcChannels } from '../shared/ipc-channels' +import { assertTrustedSender } from './trusted-ipc-sender' +import { showWindow } from './window' + +export function registerClipboardIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow +): void { + registerHandler(ipcChannels.clipboardReadText, (event) => { + assertTrustedSender(event, window) + return clipboardTextSchema.parse(clipboard.readText()) + }) + + registerHandler(ipcChannels.clipboardWriteText, (event, input) => { + assertTrustedSender(event, window) + clipboard.writeText(clipboardTextSchema.parse(input)) + }) +} + +export function registerWindowIpcHandlers( + registerHandler: typeof ipcMain.handle, + window: BrowserWindow +): void { + registerHandler(ipcChannels.appShow, (event) => { + assertTrustedSender(event, window) + showWindow(window) + }) + + registerHandler(ipcChannels.appHide, (event) => { + assertTrustedSender(event, window) + window.hide() + }) + + registerHandler(ipcChannels.windowMinimize, (event) => { + assertTrustedSender(event, window) + window.minimize() + }) + + registerHandler(ipcChannels.windowToggleMaximize, (event) => { + assertTrustedSender(event, window) + if (window.isMaximized()) { + window.unmaximize() + } else { + window.maximize() + } + }) + + registerHandler(ipcChannels.windowClose, (event) => { + assertTrustedSender(event, window) + window.close() + }) + + registerHandler(ipcChannels.windowIsMaximized, (event): boolean => { + assertTrustedSender(event, window) + return window.isMaximized() + }) +} diff --git a/src/preload/index.ts b/src/preload/index.ts index 938e0472..36d60fd9 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -210,6 +210,9 @@ import type { const desktopApi: DesktopApi = { + openRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientOpen, input), + getRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientGet, input), + stopRuntimeNativeClient: (input) => ipcRenderer.invoke(ipcChannels.runtimeNativeClientStop, input), storageUpgrade: { getProgress: () => ipcRenderer.invoke(ipcChannels.storageUpgradeProgress), act: async (action) => { diff --git a/src/renderer/src/App.test.tsx b/src/renderer/src/App.test.tsx index e0c38c2f..ebc3ef99 100644 --- a/src/renderer/src/App.test.tsx +++ b/src/renderer/src/App.test.tsx @@ -24,6 +24,7 @@ import { } from "../../shared/application-settings-contracts"; import type { GlobalShortcutSettingsSnapshot } from "../../shared/shortcut"; import type { TerminalSnapshot } from "../../shared/terminal-contracts"; +import type { RuntimeNativeClientApi } from "./RuntimeNativeClientActions"; import { loadBrandingPreferences, saveBrandingPreferences } from "./branding"; import type { AssistantProject, @@ -198,7 +199,10 @@ const terminalSnapshot: TerminalSnapshot = { error: null, }; -const api: DesktopApi = { +const api: DesktopApi & RuntimeNativeClientApi = { + openRuntimeNativeClient: vi.fn(async () => ({ kind: "terminal" as const, terminal: terminalSnapshot })), + getRuntimeNativeClient: vi.fn(async () => null), + stopRuntimeNativeClient: vi.fn(async () => undefined), localInference: { openSettings: vi.fn(async () => undefined), getSnapshot: vi.fn(async () => ({ services: [], tasks: [] })), @@ -1162,6 +1166,9 @@ describe("App", () => { document.documentElement.style.colorScheme = ""; vi.clearAllMocks(); vi.mocked(api.magicNotes.search).mockReset().mockResolvedValue([]); + vi.mocked(api.openRuntimeNativeClient).mockReset().mockResolvedValue({ kind: "terminal", terminal: terminalSnapshot }); + vi.mocked(api.getRuntimeNativeClient).mockReset().mockResolvedValue(null); + vi.mocked(api.stopRuntimeNativeClient).mockReset().mockResolvedValue(); vi.mocked(api.knowledge.getSnapshot).mockReset(); vi.mocked(api.knowledge.externalInstancesList).mockReset(); vi.mocked(api.agent.respondQuestion).mockReset().mockResolvedValue(); @@ -9663,6 +9670,77 @@ describe("App", () => { ); }); + it.each(["continue", "opencode"] as const)("opens the %s native terminal without compression or history and persists current settings", async (provider) => { + const conversationId = "00000000-0000-4000-8000-000000000731"; + vi.mocked(api.conversations.list).mockResolvedValueOnce([{ + id: conversationId, projectId, title: "Native client", updatedAt: Date.now(), + runtimeSelection: { provider }, workMode: "execute", messages: [], + }]); + render(); + const open = await screen.findByRole("button", { name: "在终端中打开" }); + expect(open).toBeEnabled(); + expect(screen.queryByRole("button", { name: "压缩上下文" })).not.toBeInTheDocument(); + fireEvent.change(screen.getByRole("textbox", { name: "向 GoodBuddy 提问" }), { target: { value: "Keep my draft" } }); + fireEvent.click(open); + await waitFor(() => { + expect(api.openRuntimeNativeClient).toHaveBeenCalledWith({ conversationId }); + expect(screen.getByRole("tab", { name: /终端 1/ })).toHaveAttribute("aria-selected", "true"); + expect(screen.getByRole("region", { name: "用户终端:终端 1" })).toBeInTheDocument(); + }); + expect(api.conversations.saveLocal).toHaveBeenCalledWith([{ + header: expect.objectContaining({ id: conversationId, runtimeSelection: { provider }, workMode: "execute" }), messages: [], + }]); + expect(screen.getByRole("textbox", { name: "向 GoodBuddy 提问" })).toHaveValue("Keep my draft"); + expect(api.terminal.create).not.toHaveBeenCalled(); + }); + + it("hides the native client shortcut for the built-in model", async () => { + render(); + await screen.findByRole("textbox", { name: "向 GoodBuddy 提问" }); + await waitFor(() => expect(api.settings.getRuntime).toHaveBeenCalled()); + expect(screen.queryByRole("button", { name: "在终端中打开" })).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: "在浏览器中打开" })).not.toBeInTheDocument(); + }); + + it("opens local DS in the external browser without opening the workbar", async () => { + const conversationId = "00000000-0000-4000-8000-000000000731"; + vi.mocked(api.conversations.list).mockResolvedValueOnce([{ + id: conversationId, projectId, title: "DS client", updatedAt: Date.now(), + runtimeSelection: { provider: "deepseek-harness" }, messages: [], + }]); + vi.mocked(api.openRuntimeNativeClient).mockResolvedValue({ kind: "browser", serviceId: "ds-service" }); + render(); + const open = await screen.findByRole("button", { name: "在浏览器中打开" }); + await waitFor(() => expect(api.getRuntimeNativeClient).toHaveBeenCalledWith({ conversationId })); + fireEvent.click(open); + await waitFor(() => { + expect(api.openRuntimeNativeClient).toHaveBeenCalledWith({ conversationId }); + expect(screen.getByRole("button", { name: "重新打开" })).toBeEnabled(); + expect(screen.getByRole("button", { name: "停止此服务" })).toBeEnabled(); + }); + expect(screen.getByRole("button", { name: "切换助手工作栏" })).toHaveAttribute("aria-expanded", "false"); + expect(api.terminal.create).not.toHaveBeenCalled(); + }); + + it("keeps a late native terminal without opening the workbar after switching conversations", async () => { + const conversationId = "00000000-0000-4000-8000-000000000731"; + vi.mocked(api.conversations.list).mockResolvedValueOnce([ + { id: conversationId, projectId, title: "Original native", updatedAt: 2, runtimeSelection: { provider: "continue" }, messages: [] }, + { id: "00000000-0000-4000-8000-000000000732", projectId, title: "Other conversation", updatedAt: 1, messages: [] }, + ]); + let finish!: (result: Awaited>) => void; + vi.mocked(api.openRuntimeNativeClient).mockImplementation(() => new Promise(resolve => { finish = resolve; })); + render(); + fireEvent.click(await screen.findByRole("button", { name: "在终端中打开" })); + await waitFor(() => expect(api.openRuntimeNativeClient).toHaveBeenCalledWith({ conversationId })); + fireEvent.click(screen.getByRole("button", { name: /^Other conversation/ })); + await waitFor(() => expect(screen.queryByRole("button", { name: "正在打开…" })).not.toBeInTheDocument()); + await act(async () => finish({ kind: "terminal", terminal: terminalSnapshot })); + expect(screen.getByRole("button", { name: "切换助手工作栏" })).toHaveAttribute("aria-expanded", "false"); + fireEvent.click(screen.getByRole("button", { name: "切换助手工作栏" })); + expect(await screen.findByRole("tab", { name: /终端 1/ })).toHaveAttribute("aria-selected", "false"); + }); + it("manually compacts Continue context and persists the summary state", async () => { const conversationId = "00000000-0000-4000-8000-000000000731"; const messages = [ @@ -9755,11 +9833,10 @@ describe("App", () => { name: "压缩上下文", }); expect(compactContext.parentElement).toHaveClass( - "composer-meta", - "composer-meta--with-context-compact", + "composer-meta__actions", ); expect(compactContext.parentElement?.firstElementChild).toBe( - compactContext, + screen.getByRole("button", { name: "在终端中打开" }), ); fireEvent.click(compactContext); await waitFor(() => diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 29c8037a..6c967cc5 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -3,6 +3,8 @@ import { MagicNotesPanel } from './MagicNotesPanel'; import { AnchoredMenu } from './AnchoredMenu'; import { useMagicNoteDraft } from './use-magic-note-draft'; import type { MagicNoteSource } from '../../shared/magic-notes-contracts'; +import { RuntimeNativeClientActions } from "./RuntimeNativeClientActions"; +import type { TerminalSnapshot } from "../../shared/terminal-contracts"; import LocalInferencePage from "./LocalInferencePage"; import { ApplicationMenu } from './ApplicationMenu'; import { AttachmentResultButton } from './AttachmentResultButton'; @@ -2440,6 +2442,7 @@ function App(): React.JSX.Element { loadPrimarySidebarWidth, ); const [primarySidebarResizing, setPrimarySidebarResizing] = useState(false); + const [nativeTerminals, setNativeTerminals] = useState<{ terminal: TerminalSnapshot; focus: boolean }[]>([]); const [assistantSidebarOpen, setAssistantSidebarOpen] = useState( () => window.innerWidth >= 1280, ); @@ -8903,6 +8906,32 @@ function App(): React.JSX.Element { activeRuntimeSelection?.provider === "continue") && runtimeNativeSnapshot?.context.manualCompact === true; + const nativeClientAvailable = activeRuntimeSelection?.provider === "continue" || + activeRuntimeSelection?.provider === "opencode" || + (activeRuntimeSelection?.provider === "deepseek-harness" && activeProject?.executionSpace.kind === "local"); + const nativeClientContextKey = useMemo(() => JSON.stringify([ + activeId, activeProjectId, activeRuntimeSelection, workMode, runtimeSettings, + ]), [activeId, activeProjectId, activeRuntimeSelection, workMode, runtimeSettings]); + const prepareNativeClientConversation = async (): Promise => { + let conversation = activeConversation; + if (!conversation) { + conversation = await new Promise((resolve, reject) => { + if (!startNewConversation(activeProjectId || undefined, { ready: resolve })) { + reject(new Error(t("notices.channelConversationAutomatic"))); + } + }); + setActiveId(conversation.id); + } + // Save the current selection before Main resolves the launch from its conversation ID. + const header = toLocalConversationHeader({ ...conversation, runtimeSelection: activeRuntimeSelection, workMode }); + const operation = conversationPersistenceQueueRef.current.then(() => + window.goodbuddy.conversations.saveLocal([{ header, messages: [] }]), + ); + conversationPersistenceQueueRef.current = operation.catch(() => undefined); + await operation; + return conversation.id; + }; + const composerContextMetrics = useMemo(() => { if ( !activeConversation || @@ -10995,12 +11024,22 @@ function App(): React.JSX.Element {
+
+ {nativeClientAvailable && { + const focus = activeProjectIdRef.current === activeProjectId && + activeConversationIdRef.current === activeId && viewRef.current === "chat"; + setNativeTerminals(current => [...current, { terminal, focus }]); + if (focus) setAssistantSidebarOpen(true); + }} + />} {runtimeContextCompactAvailable && (
{composerContextMetrics && (
requestAnimationFrame(() => { const trigger = noteCaptureTrigger.current; (trigger?.isConnected && !trigger.closest('[hidden], [inert]') ? trigger : noteTitleMenuRef.current)?.focus(); })} onOpenWorkspace={(noteId, entryId) => requestWorkspaceLeave('magic-notes', () => { setNotesNavigation({ noteId, entryId, requestId: Date.now() }); commitView('magic-notes'); })} />} + nativeTerminals={nativeTerminals} activeConversationId={activeId} conversationStats={statsConversation && executionStats.conversation ? { conversationId: statsConversation.id, diff --git a/src/renderer/src/RightAssistantSidebar.tsx b/src/renderer/src/RightAssistantSidebar.tsx index ada9da10..5324da37 100644 --- a/src/renderer/src/RightAssistantSidebar.tsx +++ b/src/renderer/src/RightAssistantSidebar.tsx @@ -125,6 +125,7 @@ export type RightAssistantSidebarProps = { notesOpenRequest?: number notesPanel?: React.ReactNode onBeforeCloseNotes?: () => Promise + nativeTerminals?: readonly { terminal: TerminalSnapshot; focus: boolean }[] open: boolean tab: AssistantSidebarTab approvals: PendingSidebarApproval[] @@ -815,6 +816,7 @@ export function RightAssistantSidebar({ notesOpenRequest = 0, notesPanel, onBeforeCloseNotes, + nativeTerminals, open, tab, approvals, @@ -1060,6 +1062,18 @@ export function RightAssistantSidebar({ const [terminalSnapshots, setTerminalSnapshots] = useState< Record >({}) + const [attachedNativeTerminalCount, setAttachedNativeTerminalCount] = useState(0) + if (nativeTerminals && nativeTerminals.length > attachedNativeTerminalCount) { + const additions = nativeTerminals.slice(attachedNativeTerminalCount) + setAttachedNativeTerminalCount(nativeTerminals.length) + setWorkbarInstances(current => [...current, ...additions.map(({ terminal }) => ({ + id: terminal.sessionId, appId: 'terminal' as const, title: terminal.title, targetRef: terminal.target + }))]) + setTerminalSessionIds(current => ({ ...current, ...Object.fromEntries(additions.map(({ terminal }) => [terminal.sessionId, terminal.sessionId])) })) + setTerminalSnapshots(current => ({ ...current, ...Object.fromEntries(additions.map(({ terminal }) => [terminal.sessionId, terminal])) })) + const focused = additions.findLast(entry => entry.focus) + if (focused) setActiveWorkbarInstanceId(focused.terminal.sessionId) + } const [terminalCloseConfirmation, setTerminalCloseConfirmation] = useState<{ instance: WorkbarTabInstance diff --git a/src/renderer/src/RuntimeNativeClientActions.test.tsx b/src/renderer/src/RuntimeNativeClientActions.test.tsx new file mode 100644 index 00000000..45c0e531 --- /dev/null +++ b/src/renderer/src/RuntimeNativeClientActions.test.tsx @@ -0,0 +1,104 @@ +import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { RuntimeNativeClientActions, type RuntimeNativeClientApi } from './RuntimeNativeClientActions' +import { changeUiLocale } from './i18n' +import type { TerminalSnapshot } from '../../shared/terminal-contracts' + +const terminal: TerminalSnapshot = { + sessionId: '00000000-0000-4000-8000-000000000123', target: { type: 'local' }, + title: 'Continue', targetLabel: 'Local', state: 'running', shell: 'continue', + workingDirectory: '/project', size: { cols: 80, rows: 24 }, lastSequence: 0, exit: null, error: null +} +const api = { + openRuntimeNativeClient: vi.fn(), + getRuntimeNativeClient: vi.fn(), + stopRuntimeNativeClient: vi.fn() +} +const props = { + browser: false, contextKey: 'first', conversationId: 'conversation', + prepareConversation: vi.fn(async () => 'conversation'), onTerminal: vi.fn(), notify: vi.fn() +} + +beforeEach(async () => { + vi.resetAllMocks() + await changeUiLocale('en-US') + props.prepareConversation.mockResolvedValue('conversation') + api.getRuntimeNativeClient.mockResolvedValue(null) + api.stopRuntimeNativeClient.mockResolvedValue() + vi.stubGlobal('goodbuddy', api) +}) +afterEach(() => { cleanup(); vi.unstubAllGlobals() }) + +describe('RuntimeNativeClientActions', () => { + it('saves the conversation before launch and prevents duplicate clicks while opening', async () => { + let finish!: (result: Awaited>) => void + api.openRuntimeNativeClient.mockImplementation(() => new Promise(resolve => { finish = resolve })) + render() + fireEvent.click(screen.getByRole('button', { name: 'Open in terminal' })) + await waitFor(() => expect(api.openRuntimeNativeClient).toHaveBeenCalledWith({ conversationId: 'conversation' })) + expect(props.prepareConversation.mock.invocationCallOrder[0]).toBeLessThan(api.openRuntimeNativeClient.mock.invocationCallOrder[0]!) + const pending = screen.getByRole('button', { name: 'Opening...' }) + expect(pending).toBeDisabled() + fireEvent.click(pending) + expect(api.openRuntimeNativeClient).toHaveBeenCalledTimes(1) + await act(async () => finish({ kind: 'terminal', terminal })) + expect(props.onTerminal).toHaveBeenCalledWith(terminal) + expect(screen.getByRole('button', { name: 'Open in terminal' })).toBeEnabled() + }) + + it('refreshes the matching DS service on selection changes and stops only that service', async () => { + api.getRuntimeNativeClient.mockResolvedValueOnce({ serviceId: 'first-service' }).mockResolvedValue({ serviceId: 'second-service' }) + const { rerender } = render() + await screen.findByRole('button', { name: 'Reopen' }) + rerender() + expect(screen.queryByRole('button', { name: 'Stop this service' })).not.toBeInTheDocument() + await screen.findByRole('button', { name: 'Reopen' }) + fireEvent.click(screen.getByRole('button', { name: 'Stop this service' })) + expect(api.stopRuntimeNativeClient).not.toHaveBeenCalled() + fireEvent.click(screen.getByRole('button', { name: 'Stop service' })) + await waitFor(() => { + expect(api.stopRuntimeNativeClient).toHaveBeenCalledWith({ serviceId: 'second-service' }) + expect(screen.getByRole('button', { name: 'Open in browser' })).toBeEnabled() + expect(screen.queryByRole('button', { name: 'Stop this service' })).not.toBeInTheDocument() + }) + }) + + it('reopens DS through Main and recovers the stop control after browser-open failure', async () => { + api.openRuntimeNativeClient.mockRejectedValueOnce(new Error('Browser could not open')) + render() + await waitFor(() => expect(api.getRuntimeNativeClient).toHaveBeenCalledTimes(1)) + api.getRuntimeNativeClient.mockResolvedValue({ serviceId: 'ready-service' }) + fireEvent.click(screen.getByRole('button', { name: 'Open in browser' })) + await waitFor(() => { + expect(props.notify).toHaveBeenCalledWith({ tone: 'error', message: 'Browser could not open' }) + expect(screen.getByRole('button', { name: 'Reopen' })).toBeEnabled() + }) + api.openRuntimeNativeClient.mockResolvedValue({ kind: 'browser', serviceId: 'ready-service' }) + fireEvent.click(screen.getByRole('button', { name: 'Reopen' })) + await waitFor(() => expect(api.openRuntimeNativeClient).toHaveBeenCalledTimes(2)) + expect(props.onTerminal).not.toHaveBeenCalled() + }) + + it('does not display a service returned for an old selection', async () => { + let finish!: (result: { serviceId: string }) => void + api.getRuntimeNativeClient.mockImplementationOnce(() => new Promise(resolve => { finish = resolve })) + const { rerender } = render() + await waitFor(() => expect(api.getRuntimeNativeClient).toHaveBeenCalledTimes(1)) + rerender() + await waitFor(() => expect(api.getRuntimeNativeClient).toHaveBeenCalledTimes(2)) + await act(async () => finish({ serviceId: 'old-service' })) + expect(screen.queryByRole('button', { name: 'Stop this service' })).not.toBeInTheDocument() + }) + + it('retains controls and reports stop errors for retry', async () => { + api.getRuntimeNativeClient.mockResolvedValue({ serviceId: 'service' }) + api.stopRuntimeNativeClient.mockRejectedValueOnce(new Error('Stop failed')) + render() + fireEvent.click(await screen.findByRole('button', { name: 'Stop this service' })) + fireEvent.click(screen.getByRole('button', { name: 'Stop service' })) + await waitFor(() => { + expect(props.notify).toHaveBeenCalledWith({ tone: 'error', message: 'Stop failed' }) + expect(screen.getByRole('button', { name: 'Stop service' })).toBeEnabled() + }) + }) +}) diff --git a/src/renderer/src/RuntimeNativeClientActions.tsx b/src/renderer/src/RuntimeNativeClientActions.tsx new file mode 100644 index 00000000..3ee080c9 --- /dev/null +++ b/src/renderer/src/RuntimeNativeClientActions.tsx @@ -0,0 +1,100 @@ +import { useEffect, useRef, useState } from 'react' +import { Globe, LoaderCircle, TerminalSquare } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import type { TerminalSnapshot } from '../../shared/terminal-contracts' + +export type RuntimeNativeClientApi = { + openRuntimeNativeClient: (input: { conversationId: string }) => Promise< + { kind: 'terminal'; terminal: TerminalSnapshot } | { kind: 'browser'; serviceId: string } + > + getRuntimeNativeClient: (input: { conversationId: string }) => Promise<{ serviceId: string } | null> + stopRuntimeNativeClient: (input: { serviceId: string }) => Promise +} + +type Props = { + browser: boolean + contextKey: string + conversationId?: string + prepareConversation: () => Promise + onTerminal: (terminal: TerminalSnapshot) => void + notify: (notification: { tone: 'error' | 'success'; message: string }) => void +} + +export function RuntimeNativeClientActions({ browser, contextKey, conversationId, prepareConversation, onTerminal, notify }: Props): React.JSX.Element { + const { t } = useTranslation('app') + const [pending, setPending] = useState<'open' | 'stop'>() + const busy = useRef(false) + const lookupGeneration = useRef(0) + const [service, setService] = useState<{ key: string; serviceId: string }>() + const [confirmStop, setConfirmStop] = useState() + const current = useRef({ contextKey, prepareConversation, notify }) + useEffect(() => { current.current = { contextKey, prepareConversation, notify } }) + const api = window.goodbuddy as typeof window.goodbuddy & RuntimeNativeClientApi + const serviceId = service?.key === contextKey ? service.serviceId : undefined + + useEffect(() => { + if (!browser || !conversationId) return + let cancelled = false + const refresh = async (): Promise => { + const generation = ++lookupGeneration.current + try { + const id = await current.current.prepareConversation() + if (cancelled) return + const result = await api.getRuntimeNativeClient({ conversationId: id }) + if (!cancelled && !busy.current && lookupGeneration.current === generation) setService(result ? { key: contextKey, ...result } : undefined) + } catch (error) { + if (!cancelled) current.current.notify({ tone: 'error', message: error instanceof Error ? error.message : t('composer.nativeClient.failed') }) + } + } + void refresh() + window.addEventListener('focus', refresh) + return () => { cancelled = true; window.removeEventListener('focus', refresh) } + }, [api, browser, contextKey, conversationId, t]) + + const run = async (stopServiceId?: string): Promise => { + if (busy.current) return + busy.current = true + lookupGeneration.current += 1 + setPending(stopServiceId ? 'stop' : 'open') + try { + if (stopServiceId) { + await api.stopRuntimeNativeClient({ serviceId: stopServiceId }) + setService(previous => previous?.serviceId === stopServiceId ? undefined : previous) + setConfirmStop(undefined) + notify({ tone: 'success', message: t('composer.nativeClient.stopped') }) + } else { + const id = await prepareConversation() + const result = await api.openRuntimeNativeClient({ conversationId: id }) + if (result.kind === 'terminal') onTerminal(result.terminal) + else if (current.current.contextKey === contextKey) setService({ key: contextKey, serviceId: result.serviceId }) + } + } catch (error) { + notify({ tone: 'error', message: error instanceof Error ? error.message : t('composer.nativeClient.failed') }) + // A browser-open failure can leave a ready service that the user can stop or reopen. + if (browser && !stopServiceId && current.current.contextKey === contextKey) { + try { + const id = await prepareConversation() + const result = await api.getRuntimeNativeClient({ conversationId: id }) + if (current.current.contextKey === contextKey) setService(result ? { key: contextKey, ...result } : undefined) + } catch { /* Keep the original operation error. */ } + } + } finally { + busy.current = false + setPending(undefined) + } + } + + return <> + + {browser && serviceId && } + {browser && {t('composer.nativeClient.description')}} + {serviceId && confirmStop === serviceId && + {t('composer.nativeClient.stopWarning')} + + + } + +} diff --git a/src/renderer/src/SettingsPanel.test.tsx b/src/renderer/src/SettingsPanel.test.tsx index fde43569..e14d5ecf 100644 --- a/src/renderer/src/SettingsPanel.test.tsx +++ b/src/renderer/src/SettingsPanel.test.tsx @@ -202,7 +202,7 @@ const detectAgentRuntimes = vi.fn< deepseekHarness: { available: true, path: 'bundled://deepseek-harness', - version: '0.1.2-rc.1', + version: '0.1.7-rc.2', source: 'bundled', detail: '内置 Harness Adapter 已就绪' } @@ -2974,11 +2974,11 @@ describe('SettingsPanel runtime files', () => { ) ).toHaveClass('runtime-overview__path') expect( - within(harnessOverview).getByText('0.1.2-rc.1') + within(harnessOverview).getByText('0.1.7-rc.2') ).toBeInTheDocument() expect( within(harnessOverview).getByText( - '内置 DeepSeek Harness 0.1.2-rc.1 已就绪' + '内置 DeepSeek Harness 0.1.7-rc.2 已就绪' ) ).toBeInTheDocument() expect( diff --git a/src/renderer/src/WorkspacePrimitives.test.tsx b/src/renderer/src/WorkspacePrimitives.test.tsx index a6859e60..0744f793 100644 --- a/src/renderer/src/WorkspacePrimitives.test.tsx +++ b/src/renderer/src/WorkspacePrimitives.test.tsx @@ -344,7 +344,7 @@ describe('WorkspacePrimitives', () => { ) }) - it('floats Runtime context compaction without shifting the composer', () => { + it('wraps native client and compaction actions without overlapping composer metadata', () => { expect(stylesheet).toMatch( /\.composer-wrap\s*\{[^}]*var\(--space-2\);[^}]*background:\s*var\(--surface-raised\);/u ) @@ -352,10 +352,10 @@ describe('WorkspacePrimitives', () => { /\.composer-meta\s*\{[^}]*position:\s*relative;[^}]*min-height:\s*26px;[^}]*margin:\s*var\(--space-1\) 0 0;/u ) expect(stylesheet).toMatch( - /\.composer-meta--with-context-compact\s*\{[^}]*padding-left:\s*calc\(/u + /\.composer-meta__actions\s*\{[^}]*display:\s*flex;[^}]*flex-wrap:\s*wrap;/u ) - expect(stylesheet).toMatch( - /\.composer-context-compact\s*\{[^}]*position:\s*absolute;[^}]*bottom:\s*0;[^}]*left:\s*0;/u + expect(stylesheet).not.toMatch( + /\.composer-context-compact\s*\{[^}]*position:\s*absolute;/u ) }) diff --git a/src/renderer/src/i18n/locales/en-US/app.ts b/src/renderer/src/i18n/locales/en-US/app.ts index fd6f5ae2..ae0b9aeb 100644 --- a/src/renderer/src/i18n/locales/en-US/app.ts +++ b/src/renderer/src/i18n/locales/en-US/app.ts @@ -570,6 +570,13 @@ export const app = { nothingToCompact: 'There is no earlier conversation history to compact', compactFailed: 'Context compaction failed' }, + nativeClient: { + terminal: 'Open in terminal', browser: 'Open in browser', opening: 'Opening...', stopping: 'Stopping...', + reopen: 'Reopen', stop: 'Stop this service', confirmStop: 'Stop service', cancel: 'Cancel', + description: 'Independent session. Closing the page keeps the service running; stop it here or quit GoodBuddy.', + stopWarning: 'Stopping disconnects this service and interrupts its requests.', + stopped: 'Native client service stopped', failed: 'Could not open the native client' + }, experts: { general: 'General assistant', generalDescription: 'Default single assistant', diff --git a/src/renderer/src/i18n/locales/zh-CN/app.ts b/src/renderer/src/i18n/locales/zh-CN/app.ts index 6f7db587..5be45268 100644 --- a/src/renderer/src/i18n/locales/zh-CN/app.ts +++ b/src/renderer/src/i18n/locales/zh-CN/app.ts @@ -546,6 +546,13 @@ export const app = { nothingToCompact: '当前没有可压缩的较早对话历史', compactFailed: '上下文压缩失败' }, + nativeClient: { + terminal: '在终端中打开', browser: '在浏览器中打开', opening: '正在打开…', stopping: '正在停止…', + reopen: '重新打开', stop: '停止此服务', confirmStop: '停止服务', cancel: '取消', + description: '独立会话;关闭网页后服务仍运行,可在此停止,退出 GoodBuddy 时停止。', + stopWarning: '停止后此服务的网页会断开,进行中的请求将中断。', + stopped: '原生客户端服务已停止', failed: '无法打开原生客户端' + }, experts: { general: '通用助手', generalDescription: '默认单助手', diff --git a/src/renderer/src/styles.css b/src/renderer/src/styles.css index 73ea3d62..6c13cec5 100644 --- a/src/renderer/src/styles.css +++ b/src/renderer/src/styles.css @@ -7911,10 +7911,26 @@ button > svg { line-height: 1.45; } -.composer-meta--with-context-compact { - padding-left: calc( - var(--composer-context-compact-width) + var(--space-3) - ); +.composer-meta__actions { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-2); + margin-right: auto; + min-width: 0; +} + +.composer-native-client-note, +.composer-native-client-confirm { + flex-basis: 100%; + color: var(--text-muted); +} + +.composer-native-client-confirm { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-2); } .composer-meta__error { @@ -7931,11 +7947,8 @@ button > svg { } .composer-context-compact { - position: absolute; - bottom: 0; - left: 0; display: inline-flex; - width: var(--composer-context-compact-width); + min-width: var(--composer-context-compact-width); min-height: 26px; padding: var(--space-1) var(--space-2); border: 1px solid var(--border-control); diff --git a/src/shared/contracts.ts b/src/shared/contracts.ts index a3dbad0e..1235ee4b 100644 --- a/src/shared/contracts.ts +++ b/src/shared/contracts.ts @@ -1766,6 +1766,9 @@ export type KnowledgeSearchReference = { } export type DesktopApi = { + openRuntimeNativeClient: (input: import('./runtime-native-client-contracts').RuntimeNativeClientInput) => Promise + getRuntimeNativeClient: (input: import('./runtime-native-client-contracts').RuntimeNativeClientInput) => Promise + stopRuntimeNativeClient: (input: import('./runtime-native-client-contracts').RuntimeNativeClientService) => Promise localInference: import('./local-inference-contracts').LocalInferenceApi storageUpgrade: { getProgress: () => Promise diff --git a/src/shared/ipc-channels.ts b/src/shared/ipc-channels.ts index eca63826..1cad78d1 100644 --- a/src/shared/ipc-channels.ts +++ b/src/shared/ipc-channels.ts @@ -54,6 +54,9 @@ export const ipcChannels = { browserStop: 'browser:stop', browserState: 'browser:state', terminalCreate: 'terminal:create', + runtimeNativeClientOpen: 'runtime-native-client:open', + runtimeNativeClientGet: 'runtime-native-client:get', + runtimeNativeClientStop: 'runtime-native-client:stop', terminalWrite: 'terminal:write', terminalResize: 'terminal:resize', terminalClose: 'terminal:close', diff --git a/src/shared/runtime-native-client-contracts.ts b/src/shared/runtime-native-client-contracts.ts new file mode 100644 index 00000000..4d0ab137 --- /dev/null +++ b/src/shared/runtime-native-client-contracts.ts @@ -0,0 +1,13 @@ +import { z } from 'zod' +import { assistantIdSchema } from './assistant-contracts' +import { terminalSnapshotSchema } from './terminal-contracts' + +export const runtimeNativeClientInputSchema = z.object({ conversationId: assistantIdSchema }).strict() +export const runtimeNativeClientServiceSchema = z.object({ serviceId: z.string().min(1).max(128) }).strict() +export const runtimeNativeClientResultSchema = z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('terminal'), terminal: terminalSnapshotSchema }).strict(), + runtimeNativeClientServiceSchema.extend({ kind: z.literal('browser') }) +]) +export type RuntimeNativeClientInput = z.infer +export type RuntimeNativeClientService = z.infer +export type RuntimeNativeClientResult = z.infer diff --git a/tests/build-release.test.ts b/tests/build-release.test.ts index ffcbd564..ed4c55ff 100644 --- a/tests/build-release.test.ts +++ b/tests/build-release.test.ts @@ -914,6 +914,18 @@ describe('release build arguments', () => { ) mkdirSync(configPlugin, { recursive: true }) writeFileSync(join(configPlugin, 'package.json'), JSON.stringify({ version: '1.18.29' })) + const webPackages = { + '@deepseek-ai/dsh': { version: '0.1.7-rc.2', dependencies: { sharp: '0.35.4', koffi: '3.1.4' } }, + sharp: { version: '0.35.4', optionalDependencies: { '@img/sharp-win32-x64': '0.35.4' } }, + 'sharp/node_modules/@img/sharp-win32-x64': { version: '0.35.4' }, + koffi: { version: '3.1.4', optionalDependencies: { '@koromix/koffi-win32-x64': '3.1.4' } }, + '@koromix/koffi-win32-x64': { version: '3.1.4' } + } + for (const [name, manifest] of Object.entries(webPackages)) { + const directory = join(projectRoot, 'node_modules', name) + mkdirSync(directory, { recursive: true }) + writeFileSync(join(directory, 'package.json'), JSON.stringify({ name, ...manifest })) + } mkdirSync(join(projectRoot, 'out', 'main'), { recursive: true }) @@ -925,7 +937,7 @@ describe('release build arguments', () => { join(projectRoot, 'package.json'), JSON.stringify({ dependencies: { - '@deepseek-ai/dsh-llm': '0.1.2-rc.1', + '@deepseek-ai/dsh-llm': '0.1.7-rc.2', '@vscode/ripgrep': '1.18.0' } }) @@ -993,6 +1005,7 @@ describe('release build arguments', () => { packager: { projectDir: projectRoot } }) ).resolves.toBeUndefined() + expect(existsSync(join(projectRoot, '.runtime-resources', 'dsh-x64', 'node_modules', '@deepseek-ai', 'dsh', 'package.json'))).toBe(true) expect( existsSync(join(projectRoot, '.agent-resources')) ).toBe(false) @@ -1005,7 +1018,7 @@ describe('release build arguments', () => { ) ).toMatchObject({ name: '@deepseek-ai/dsh-llm', - version: '0.1.2-rc.1' + version: '0.1.7-rc.2' }) } finally { rmSync(projectRoot, { recursive: true, force: true }) diff --git a/tsconfig.node.json b/tsconfig.node.json index 4df2a50b..7dea7fb2 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -18,6 +18,13 @@ "src/main/**/*.ts", "src/preload/**/*.ts", "src/shared/**/*.ts", + "src/agent-daemon/agent-model-gateway.ts", + "src/agent-daemon/model-bridge-helper.ts", + "src/agent-daemon/model-bridge-broker.ts", + "src/agent-daemon/managed-paths.ts", + "src/agent-daemon/errors.ts", + "src/agent-daemon/async-utils.ts", + "src/agent-daemon/opencode-subagent-plugin.ts", "tests/**/*.ts" ] }