{"_id":"@buddhilive/dsh-api-remotes","name":"@buddhilive/dsh-api-remotes","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-api-remotes","description":"Remote BFF assembly for application-selected Host capabilities","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/api/remotes"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./client":{"types":"./lib/types/client/index.d.ts","default":"./lib/client.js"},"./types":{"types":"./lib/types/types.d.ts","default":"./lib/types/types.js"},"./src/*":"./src/*","./package.json":"./package.json"},"dsh":{"client":{"inject":["@buddhilive/dsh-api-gateway"],"platform":"web","immediately":true}},"license":"MIT","dependencies":{"@buddhilive/dsh-session":"^0.1.2-alpha.3","@buddhilive/dsh-util-values":"^0.1.2-alpha.3","@buddhilive/dsh-deque":"^0.1.2-alpha.3"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-scope":"^0.1.2-alpha.3"},"devDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-agent-presets":"^0.1.2-alpha.3","@buddhilive/dsh-api-gateway":"^0.1.2-alpha.3","@buddhilive/dsh-api-settings-controller":"^0.1.2-alpha.3","@buddhilive/dsh-api-workspace-controller":"^0.1.2-alpha.3","@buddhilive/dsh-commands":"^0.1.2-alpha.3","@buddhilive/dsh-cordis-host-runner":"^0.1.2-alpha.3","@buddhilive/dsh-credentials":"^0.1.2-alpha.3","@buddhilive/dsh-file-reference":"^0.1.2-alpha.3","@buddhilive/dsh-goal":"^0.1.2-alpha.3","@buddhilive/dsh-host-plugin-inventory":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-llm":"^0.1.2-alpha.3","@buddhilive/dsh-message-feedback":"^0.1.2-alpha.3","@buddhilive/dsh-session-reference":"^0.1.2-alpha.3","@buddhilive/dsh-settings":"^0.1.2-alpha.3","@buddhilive/dsh-subagent":"^0.1.2-alpha.3","@buddhilive/dsh-user-approval":"^0.1.2-alpha.3","@buddhilive/dsh-user-questions":"^0.1.2-alpha.3","@buddhilive/dsh-client-connection":"^0.1.2-alpha.3","@buddhilive/dsh-typert-protocol":"^0.1.2-alpha.3","@buddhilive/dsh-scope":"^0.1.2-alpha.3","@buddhilive/dsh-api-session-controller":"^0.1.2-alpha.3"},"scripts":{"bundle":"tsdown","watch":"tsdown --watch"},"_id":"@buddhilive/dsh-api-remotes@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-+kxczCQmCphnnklbh3GySlUJhCgefAvMmVGF08PvfyqHxqM9cL3C81xnqCmyX1Yn39TJI9wkA3HsGBQ9skSSSg==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-api-remotes-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-api-remotes-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-+kxczCQmCphnnklbh3GySlUJhCgefAvMmVGF08PvfyqHxqM9cL3C81xnqCmyX1Yn39TJI9wkA3HsGBQ9skSSSg==","shasum":"06860b3e3196764e4839e264a6a161c07473dc1d","tarball":"https://registry.npmjs.org/@buddhilive/dsh-api-remotes/-/dsh-api-remotes-0.1.2-alpha.3.tgz","fileCount":18,"unpackedSize":350641,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGTB7WbEbKxnyuBSQRBiXC/aUxIWp+jTF3Lni/kWQqyFAiB+DhIa8/UipZfI5If/VKw9MpmdxwuT300BiBles8nURg=="}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-api-remotes_0.1.2-alpha.3_1788165365749_0.9256858778910251"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:36:04.363Z","0.1.2-alpha.3":"2026-08-31T08:36:05.908Z","modified":"2026-08-31T08:36:06.954Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Remote BFF assembly for application-selected Host capabilities","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/api/remotes"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"应用 Remote 装配：为 Client 消费方选择带类型的 Host 能力与转发事件。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-api-remotes\n\n[English](README.md) | 中文\n\n## 概述\n\n为本应用选定的 Host Remote 能力提供双侧 BFF。Host 入口拥有转发事件名单并向 API Gateway 注册应用事件 source；Client 入口以运行时值形式导入生成的 `/remote` 产物，通过 `ctx.remote.$mount()` 挂载每项贡献，并重新导出对应的声明合并。Client 业务包依赖该外观，而不依赖 Gateway 实现或单独的 Remote 运行时入口。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [转发的 Host 事件](#forwarded-host-events)\n- [构建边界](#build-boundary)\n- [模型体验](#model-experience)\n- [已知限制与暂缓事项](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n[`@buddhilive/dsh-api-session-controller`](../session-controller/README.zh.md) 拥有 Agent 与 Session 身份策略，包括供其他 namespace 使用的 Typert lookup resolver。本包只选择并挂载生成的 Session contribution，不复制激活策略。\n\nClient 组合挂载 Commands、凭据、settings、Goal、动态 Cordis、文件与 Session 引用、只读 Host 插件清单、消息反馈、Session Controller 和 Workspace Controller contribution。该组合卸载时，Cordis effect 的所有权机制会撤回所有贡献；`@buddhilive/dsh-api-gateway/client` 负责描述符校验、可追踪 namespace Service、直接与作用域方法、调用、流与取消。Client 入口通过 Cordis 消费共享的 `TypertClientRemote` 接口，不导入具体 Gateway；它只以 type-only 形式重新导出 Gateway Client face 的声明合并，因此消费端经由本外观取到转发事件词汇时，运行时不会多出一条通往 Gateway 实现的边。\n\n本 facade 同时是 Client 包指称 wire 类型词汇的正门。它以 type-only 方式转出 Remote 失败词汇（`RemoteResult`、`RemoteFailure`、`RemoteErrorCode`、`RemoteErrorDetailsMap`）、Host 事实（`RemoteHostFacts`），以及各已选领域的浏览器安全载荷类型，因此 Client 功能包只 import 一个 specifier，不必伸手进 `dsh-typert-protocol`、Gateway 或某个拥有方的 Host 入口。有两类包刻意不走这道门：本装配自己选中的 api 层包——反向 import 会形成依赖环——以及它们的测试，后者直接从 `dsh-typert-protocol` 取失败词汇。UI 包的测试则从 [`dsh-client-test-runtime`](../../test-support/client-runtime/README.zh.md) 取 `RemoteError` 构造器。\n\n本包不拥有物理传输或 Host 服务发现。它只把应用选择投影为生成的 Remote contribution 和唯一的 Host Cordis event source；API Gateway 负责 endpoint、carrier、取消与重连。Web 或未来的 TUI 只要提供同一份不依赖 React 的 `ctx.remote` 约定，均可复用其 Client face。\n\n-----\n\n<a id=\"forwarded-host-events\"></a>\n## 转发的 Host 事件\n\n`src/remote-events.ts` 持有 `API_REMOTE_FORWARDED_EVENTS`，即本应用不改名转发给消费端的 Host Cordis 事件名单；每个条目还会选择普通发送或 Agent-scoped waterfall 投递。该名单同时就是 `ctx.remote.$on` 的合法键集，只含类型的 `src/types.ts` 派生其选择面。多转发一个事件只需在该数组里加一项：类型投影、消费端键面与 Host 转发循环全部由它派生。\n\n监听器签名不在此处重写。名单内每条事件的 Cordis `Events` 声明都住在其 owner 包 client-safe 的 `./types` 出口，本包两个 face 都把那些声明纳入编译面。Host face 还会把每个条目断言给 `TypertForwardableEventEntry`：`emit` 条目必须是已声明的单向事件，`waterfall` 条目则必须是已声明的 Agent-scoped waterfall，且其最后一个参数是返回相同结果类型的 `next()` 回调。\n\nHost entry 为每条 Client stream 独立注册 allowlist listener 和队列，并在普通事件入队前拒绝非 JSON 参数。对于 waterfall，它只投影顶层 Agent 身份与 JSON 请求字段；Client 结果也必须能无损表示为 JSON，而 `next()` 会委托给后续 Host listener。该 source 在 `ctx.typertGateway.registerRemoteEvents()` 暴露 Gateway 内部的 `$events` logical stream 前同步挂好所有 listener，因此首个 `ready` 项既能证明增量投递已就绪，也会携带供 Client 显示路径的 Host home。撤回注册会中止活动 stream。\n\n<a id=\"build-boundary\"></a>\n## 构建边界\n\n仓库中的多数包只属于一个 TypeScript face：Host 包登记在根 `tsconfig.host.json`，Client 包登记在根 `tsconfig.client.json`。本包需要拆分，因为 Host 入口要参与 Host Typert 图，而 `src/client/index.ts` 必须等 Host tsdown 生成业务包的 `/remote` 声明后才能编译。\n\n本包根 `tsconfig.json` 只是引用 `tsconfig.host.json` 与 `tsconfig.client.json` 的 solution。Host aggregate 和 Host 直接消费方引用前者，Client aggregate 和 Client 直接消费方引用后者；禁止把包根 solution 放进任一 aggregate 的依赖图。两个 project 拥有互不重叠的源码和 `.tsbuildinfo`，但共享 `lib/types` 输出目录——只有一处刻意的例外：`src/remote-events.ts` 与 `src/types.ts` **同时**列进两个 face 的 `files`，因为转发事件名单是「消费端能收到什么」的唯一控制点，Host 转发循环与 Client 的 `ctx.remote.$on` 键面必须读同一份声明，而不是两份可能彼此漂移的声明。\n\n这条例外不止是一行 `files`。根 `tsconfig.base.json` 把 `@buddhilive/dsh-api-remotes/types` 映射到 `src/types.ts`——**源平面**，与其余所有 workspace 子路径一致，也与生成的 `/remote` 产物相反（后者没有 `paths` 条目，靠 `exports` 命中构建产物）。于是两个 face 都把同一份名单与类型投影收进各自的 program，并向 `lib/types` 发射逐字相同的 `remote-events` 与 `types` 输出；`.tsbuildinfo` 仍各自独立。没有任何门禁强制两个 face 的源文件互不重叠——`scripts/project-reference-faces.ts` 只校验「引用一个 split project 必须指到对应 face」——因此本段记录这次双列为何是有意的。\n\n包内 `clientBundle(..., { hostPhase: true })` 让 Host tsdown 打包 Host 入口，让后续 Client tsdown 只打包 browser 入口。普通 Client 插件仍使用单一 Client project，并在 Client tsdown 阶段一起生成 Node loader 入口和 browser bundle；只有两组源码需要不同 compiler face 时才拆分。\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n无，因为该 BFF 只选择 Remote 应用方法和转发事件，不注册任何模型接口。\n\n#### KV Cache 影响\n\n无直接影响；其触发的任何模型可见行为均由已挂载的 Host 能力负责。\n\n## 已知限制与暂缓事项\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n- 能力集合由构建时显式导入的值固定确定；Client 不会在运行时发现 Host 中已启用的服务或 Remote 定义。\n- 若要增加能力，必须显式导入相应的 `/remote` 值并在此组合中挂载。\n- 只有仍在等待的作用域 waterfall 会在重连后重放；单向通知仍是相互隔离的 best-effort 投递。\n\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者工作上下文——点击展开</summary>\n\n无。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-4e2ab233cfc87dd0b8d15d158613f7c8"}