From f81f342cdecde732e1179ac2df8f264ca3d08eac Mon Sep 17 00:00:00 2001 From: mesalogo Date: Sun, 27 Sep 2026 08:38:00 +0800 Subject: [PATCH] feat: open local runtime clients from the composer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add composer shortcuts for local Continue and OpenCode terminals and the official DeepSeek Harness Web client, using the current project and model bridge. Manage browser service reuse, stop actions and terminal cleanup. Upgrade DeepSeek Harness to 0.1.7-rc.2 and Cordis to 4.0.4. Include the coordinated IPC handler extraction and related tests and documentation. Remote native-client coordinator wiring, managed Node consolidation, Ask MCP mappings and full desktop/package acceptance remain unfinished; this commit records the implemented local workflow and supporting SSH groundwork. Validation: typecheck and lint passed; 267 focused tests passed and 5 skipped. No new real-provider calls were made for this commit. Prior real-model evidence and remaining acceptance work are documented in the feature progress files. Release note: 本地项目选择 Continue 或 OpenCode 后,可从输入框下方打开原生终端;选择 DS 后,可打开使用当前项目和模型的官方 Web 客户端。客户端使用独立会话,DS 网页关闭后服务继续运行,可在 GoodBuddy 中停止;远程入口尚未完成。 --- build/deepseek-harness-utility-smoke.cjs | 2 +- build/native-dsh-resources.cjs | 65 + build/run-deepseek-harness-utility-smoke.cjs | 2 +- build/runtime-hooks.cjs | 2 + docs/features/assistant-workbar/README.md | 1 + docs/features/assistant-workbar/progress.md | 70 + .../runtime-native-client-proposal.md | 393 + .../runtime-process-reuse-technical-design.md | 3 + docs/features/deepseek-harness/README.md | 9 + docs/features/deepseek-harness/progress.md | 86 + .../deepseek-harness/technical-design.md | 8 +- .../external-knowledge-technical-design.md | 2 +- .../features/local-tool-environment/README.md | 9 + docs/features/magic-notes/progress.md | 26 + docs/features/magic-notes/technical-design.md | 26 +- docs/features/obsidian/progress.md | 2 +- docs/features/obsidian/technical-design.md | 2 +- package-lock.json | 7609 +++++++++++++++-- package.json | 55 +- src/main/agent/bundled-runtimes.ts | 2 +- .../agent/deepseek-harness-acp-e2e.test.ts | 27 +- .../agent/deepseek-harness-runtime.test.ts | 2 +- .../dsh-extension-marketplace.e2e.test.ts | 2 +- .../goodbuddy-harness-control-plane.test.ts | 56 +- .../agent/goodbuddy-harness-control-plane.ts | 46 +- .../agent/native-client-coordinator.test.ts | 119 + src/main/agent/native-client-coordinator.ts | 229 + src/main/agent/native-dsh-web-client.test.ts | 226 + src/main/agent/native-dsh-web-client.ts | 232 + src/main/agent/native-dsh-web-policy.ts | 74 + .../agent/native-terminal-client.e2e.test.ts | 94 + src/main/agent/native-terminal-client.test.ts | 94 + src/main/agent/native-terminal-client.ts | 213 + src/main/agent/runtime-discovery.test.ts | 4 +- src/main/capabilities/capability-ipc.ts | 382 + src/main/deepseek-harness-host.test.ts | 15 +- ...eek-harness-third-party-plugin.e2e.test.ts | 2 +- src/main/index.ts | 22 +- src/main/ipc.test.ts | 263 +- src/main/ipc.ts | 1800 +--- src/main/knowledge/knowledge-ipc.ts | 841 ++ .../local-tool-environment-ipc.ts | 90 + .../magic-notes/magic-notes-analysis-ipc.ts | 253 + src/main/magic-notes/magic-notes-ipc.ts | 154 + src/main/ssh/ssh-connection-pool.test.ts | 1 + src/main/ssh/ssh-connection-pool.ts | 63 +- .../ssh/ssh-host-directory-browser.test.ts | 1 + .../terminal/local-terminal-session.test.ts | 18 + src/main/terminal/local-terminal-session.ts | 23 +- .../terminal/ssh-terminal-session.test.ts | 1 + src/main/terminal/ssh-terminal-session.ts | 4 +- src/main/terminal/terminal-ipc.ts | 111 + .../terminal/terminal-session-manager.test.ts | 22 + src/main/terminal/terminal-session-manager.ts | 47 +- src/main/window-ipc.ts | 59 + src/preload/index.ts | 3 + src/renderer/src/App.test.tsx | 85 +- src/renderer/src/App.tsx | 51 +- src/renderer/src/RightAssistantSidebar.tsx | 14 + .../src/RuntimeNativeClientActions.test.tsx | 104 + .../src/RuntimeNativeClientActions.tsx | 100 + src/renderer/src/SettingsPanel.test.tsx | 6 +- src/renderer/src/WorkspacePrimitives.test.tsx | 8 +- src/renderer/src/i18n/locales/en-US/app.ts | 7 + src/renderer/src/i18n/locales/zh-CN/app.ts | 7 + src/renderer/src/styles.css | 29 +- src/shared/contracts.ts | 3 + src/shared/ipc-channels.ts | 3 + src/shared/runtime-native-client-contracts.ts | 13 + tests/build-release.test.ts | 17 +- tsconfig.node.json | 7 + 71 files changed, 11943 insertions(+), 2478 deletions(-) create mode 100644 build/native-dsh-resources.cjs create mode 100644 docs/features/assistant-workbar/runtime-native-client-proposal.md create mode 100644 src/main/agent/native-client-coordinator.test.ts create mode 100644 src/main/agent/native-client-coordinator.ts create mode 100644 src/main/agent/native-dsh-web-client.test.ts create mode 100644 src/main/agent/native-dsh-web-client.ts create mode 100644 src/main/agent/native-dsh-web-policy.ts create mode 100644 src/main/agent/native-terminal-client.e2e.test.ts create mode 100644 src/main/agent/native-terminal-client.test.ts create mode 100644 src/main/agent/native-terminal-client.ts create mode 100644 src/main/capabilities/capability-ipc.ts create mode 100644 src/main/knowledge/knowledge-ipc.ts create mode 100644 src/main/local-tool-environment/local-tool-environment-ipc.ts create mode 100644 src/main/magic-notes/magic-notes-analysis-ipc.ts create mode 100644 src/main/magic-notes/magic-notes-ipc.ts create mode 100644 src/main/terminal/terminal-ipc.ts create mode 100644 src/main/window-ipc.ts create mode 100644 src/renderer/src/RuntimeNativeClientActions.test.tsx create mode 100644 src/renderer/src/RuntimeNativeClientActions.tsx create mode 100644 src/shared/runtime-native-client-contracts.ts 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" ] }