pi2dsh 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +54 -14
  2. package/README.zh.md +43 -14
  3. package/cordis.patch.yml +3 -0
  4. package/dist/cli.mjs +1 -1
  5. package/dist/compat/pi-ai.mjs +1 -1
  6. package/dist/compat/pi-coding-agent.mjs +1 -1
  7. package/dist/credentials-oauth.mjs +3 -3
  8. package/dist/host.mjs +2 -2
  9. package/dist/index.d.mts +30 -1
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +98 -2
  12. package/dist/index.mjs.map +1 -0
  13. package/dist/{mcp-config-B3h5jTBb.mjs → mcp-config-vU1LZ7fC.mjs} +6 -6
  14. package/dist/mcp-config-vU1LZ7fC.mjs.map +1 -0
  15. package/dist/{oauth-bridge-C6fL1qSv.mjs → oauth-bridge-CfyImWx4.mjs} +2 -2
  16. package/dist/{oauth-bridge-C6fL1qSv.mjs.map → oauth-bridge-CfyImWx4.mjs.map} +1 -1
  17. package/dist/{pi-ai-B_88Wb0r.mjs → pi-ai-7HR3ciAs.mjs} +4 -42
  18. package/dist/{pi-ai-B_88Wb0r.mjs.map → pi-ai-7HR3ciAs.mjs.map} +1 -1
  19. package/dist/{pi-coding-agent-COMX0KHL.mjs → pi-coding-agent-CznNsOnV.mjs} +3 -3
  20. package/dist/{pi-coding-agent-COMX0KHL.mjs.map → pi-coding-agent-CznNsOnV.mjs.map} +1 -1
  21. package/dist/{runtime-B7mEIRf-.mjs → runtime-xNd10ACP.mjs} +194 -21
  22. package/dist/runtime-xNd10ACP.mjs.map +1 -0
  23. package/dist/runtime.d.mts.map +1 -1
  24. package/dist/runtime.mjs +1 -1
  25. package/package.json +9 -2
  26. package/dist/all-DSpxKvHa.mjs +0 -28512
  27. package/dist/all-DSpxKvHa.mjs.map +0 -1
  28. package/dist/anthropic-messages-BL9N1Idv.mjs +0 -6438
  29. package/dist/anthropic-messages-BL9N1Idv.mjs.map +0 -1
  30. package/dist/azure-openai-responses-A67VbaZ1.mjs +0 -209
  31. package/dist/azure-openai-responses-A67VbaZ1.mjs.map +0 -1
  32. package/dist/deferred-tools-BD4g5QUx.mjs +0 -32
  33. package/dist/deferred-tools-BD4g5QUx.mjs.map +0 -1
  34. package/dist/diagnostics-CJye1UFh.mjs +0 -99
  35. package/dist/diagnostics-CJye1UFh.mjs.map +0 -1
  36. package/dist/dist-BYA74yh_.mjs +0 -1246
  37. package/dist/dist-BYA74yh_.mjs.map +0 -1
  38. package/dist/dist-DeonWo7m.mjs +0 -1089
  39. package/dist/dist-DeonWo7m.mjs.map +0 -1
  40. package/dist/error-body-DKA3lknR.mjs +0 -104
  41. package/dist/error-body-DKA3lknR.mjs.map +0 -1
  42. package/dist/github-copilot-headers-CZo2QHrt.mjs +0 -25
  43. package/dist/github-copilot-headers-CZo2QHrt.mjs.map +0 -1
  44. package/dist/google-generative-ai-DT5S8D8y.mjs +0 -358
  45. package/dist/google-generative-ai-DT5S8D8y.mjs.map +0 -1
  46. package/dist/google-shared-DYP_9cnK.mjs +0 -29042
  47. package/dist/google-shared-DYP_9cnK.mjs.map +0 -1
  48. package/dist/google-vertex-Dpq7O7Be.mjs +0 -402
  49. package/dist/google-vertex-Dpq7O7Be.mjs.map +0 -1
  50. package/dist/hash-Dbggamac.mjs +0 -19
  51. package/dist/hash-Dbggamac.mjs.map +0 -1
  52. package/dist/headers-CPzZhJQn.mjs +0 -17
  53. package/dist/headers-CPzZhJQn.mjs.map +0 -1
  54. package/dist/images-models-DJtHo9Rp.mjs +0 -1068
  55. package/dist/images-models-DJtHo9Rp.mjs.map +0 -1
  56. package/dist/json-parse-Dz5sKMTv.mjs +0 -384
  57. package/dist/json-parse-Dz5sKMTv.mjs.map +0 -1
  58. package/dist/mcp-config-B3h5jTBb.mjs.map +0 -1
  59. package/dist/mistral-conversations-BsxbCCWx.mjs +0 -42007
  60. package/dist/mistral-conversations-BsxbCCWx.mjs.map +0 -1
  61. package/dist/multipart-parser-woKCuALW.mjs +0 -301
  62. package/dist/multipart-parser-woKCuALW.mjs.map +0 -1
  63. package/dist/openai-DkzRh5_G.mjs +0 -6732
  64. package/dist/openai-DkzRh5_G.mjs.map +0 -1
  65. package/dist/openai-codex-responses-C7vviVT2.mjs +0 -1169
  66. package/dist/openai-codex-responses-C7vviVT2.mjs.map +0 -1
  67. package/dist/openai-completions-By8QNX1P.mjs +0 -947
  68. package/dist/openai-completions-By8QNX1P.mjs.map +0 -1
  69. package/dist/openai-prompt-cache-BDWtZRKh.mjs +0 -11
  70. package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +0 -1
  71. package/dist/openai-responses-DboJUcFN.mjs +0 -247
  72. package/dist/openai-responses-DboJUcFN.mjs.map +0 -1
  73. package/dist/openai-responses-shared-BDzn7nJY.mjs +0 -572
  74. package/dist/openai-responses-shared-BDzn7nJY.mjs.map +0 -1
  75. package/dist/openrouter-images-fG3Aj6M4.mjs +0 -127
  76. package/dist/openrouter-images-fG3Aj6M4.mjs.map +0 -1
  77. package/dist/otel-PimLMoiV.mjs +0 -24935
  78. package/dist/otel-PimLMoiV.mjs.map +0 -1
  79. package/dist/pi-messages-B-7Xo_I0.mjs +0 -306
  80. package/dist/pi-messages-B-7Xo_I0.mjs.map +0 -1
  81. package/dist/provider-env-D-cCRWzv.mjs +0 -40
  82. package/dist/provider-env-D-cCRWzv.mjs.map +0 -1
  83. package/dist/provider-retry-Cw6YJ4cr.mjs +0 -80
  84. package/dist/provider-retry-Cw6YJ4cr.mjs.map +0 -1
  85. package/dist/runtime-B7mEIRf-.mjs.map +0 -1
  86. package/dist/sanitize-unicode-wLA11KvZ.mjs +0 -29
  87. package/dist/sanitize-unicode-wLA11KvZ.mjs.map +0 -1
  88. package/dist/src-BEl3QrGL.mjs +0 -5031
  89. package/dist/src-BEl3QrGL.mjs.map +0 -1
  90. package/dist/transform-messages-DGq9mvhA.mjs +0 -379
  91. package/dist/transform-messages-DGq9mvhA.mjs.map +0 -1
  92. package/dist/uuid-DtFT7tOE.mjs +0 -65
  93. package/dist/uuid-DtFT7tOE.mjs.map +0 -1
package/README.md CHANGED
@@ -5,11 +5,18 @@
5
5
  **Bridging the Pi and DeepSeek Harness ecosystems.** pi2dsh is dedicated to connecting [Pi](https://pi.dev/)'s extension ecosystem with [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH): one general **Pi Host ABI compatibility layer** that runs unmodified Pi extensions as native DSH plugins — not per-package patches.
6
6
 
7
7
  ```sh
8
- # one bundle, any Pi packages, no conversion
9
- pi2dsh host --packages '@juicesharp/rpiv-web-tools@2.4.0,pi-simplify@0.2.3' --out ./my-pi-host
10
- dsh plugin --profile headless add file:$PWD/my-pi-host
8
+ # install the engine once, then install Pi packages straight from npm
9
+ dsh plugin --profile headless add pi2dsh
10
+ dsh plugin --profile headless add @kassing/pi-vision
11
+ dsh plugin --profile headless add pi-vision-tool
11
12
  ```
12
13
 
14
+ No conversion step, no generated bundles: the engine discovers every Pi
15
+ package you added to the profile and mounts them all through one bridge
16
+ instance. Remove with `dsh plugin remove <pkg>`; upgrade the engine with
17
+ `dsh plugin add pi2dsh@latest` (your plugins are untouched), upgrade a
18
+ plugin with `dsh plugin add <pkg>@latest` (the engine is untouched).
19
+
13
20
  ## Architecture
14
21
 
15
22
  The bridge implements Pi's public extension surface **once**, mapping every call onto DSH's native services. A package that sticks to Pi's public API runs verbatim; capabilities with no safe mapping fail explicitly instead of faking success.
@@ -34,14 +41,29 @@ Pi package (unmodified npm dependency)
34
41
  DeepSeek Harness native services (Cordis composition)
35
42
  ```
36
43
 
37
- Three delivery modes:
44
+ Delivery modes:
38
45
 
39
46
  | Mode | What it does |
40
47
  |---|---|
41
- | **Host bundle** (recommended) | One installable DSH bundle mounts any list of unmodified Pi packages as ordinary npm dependencies |
42
- | **Convert** | A reviewable per-package bundle: vendored source snapshot + machine-readable compatibility report, for supply-chain-sensitive installs |
48
+ | **Engine** (default) | `dsh plugin add pi2dsh` installs the bridge once as a DSH plugin. Every Pi package you then `dsh plugin add` is discovered from the profile's dependency manifest (each entry is an explicit add — never a node_modules scan) and mounted through ONE bridge instance: one model directory, one `/login`, one credential store, one upgrade unit |
49
+ | **Host bundle** | One generated DSH bundle mounts a fixed list of Pi packages as npm dependencies — for pinned, reproducible compositions |
50
+ | **Convert** | A reviewable per-package bundle: vendored source snapshot + machine-readable compatibility report, for supply-chain-sensitive or unpublished/local packages |
43
51
  | **MCP config translation** | Pi's six `mcpServers` layers → official `@deepseek-ai/dsh-mcp-client` patch entries. The Pi MCP adapter's code never runs; `$VAR` becomes `!!js process.env.VAR`, literal secrets are warned about |
44
52
 
53
+ Engine config (optional, in the profile's `cordis.patch.yml`): `packages:
54
+ [a, b]` mounts exactly that list instead of discovering; `exclude: [c]`
55
+ skips individual dependencies.
56
+
57
+ **Plugin upgrades and compatibility.** Installed plugin versions are locked
58
+ by pnpm's lockfile — a plugin never upgrades behind your back; only an
59
+ explicit `dsh plugin add <pkg>@latest` moves it. Before upgrading, run
60
+ `pi2dsh inspect <pkg>@<version>` for the compatibility report. The bridge
61
+ intercepts the Pi runtime imports (`pi-coding-agent`/`pi-tui`/`pi-ai` are
62
+ served by its shims), so a plugin's own Pi dependency pins never load — the
63
+ only drift that can bite is a plugin adopting a Pi host API the bridge does
64
+ not cover yet, which the report shows and which fails loudly, package-
65
+ isolated, at runtime.
66
+
45
67
  Three hard rules keep it general:
46
68
 
47
69
  1. The core contains **no `if (packageName === …)`** branching.
@@ -84,16 +106,34 @@ The screener models **load-time vs lazy reachability**: only an unresolvable dep
84
106
  Requires Node.js 22.19+ and DeepSeek Harness.
85
107
 
86
108
  ```sh
87
- git clone https://github.com/weijiafu14/pi2dsh.git && cd pi2dsh
88
- corepack pnpm@11.7.0 install && pnpm build
89
-
90
- node dist/cli.mjs inspect @narumitw/pi-lsp # compatibility report
91
- node dist/cli.mjs convert @narumitw/pi-lsp --out ./dsh-pi-lsp
92
- node dist/cli.mjs host --packages 'pi-simplify' --out ./pi-host
93
- node dist/cli.mjs mcp-config # Pi mcpServers → DSH patch
94
- dsh plugin --profile headless add file:$PWD/pi-host
109
+ # Engine (default): install once, then add Pi packages directly
110
+ dsh plugin --profile headless add pi2dsh
111
+ dsh plugin --profile headless add @kassing/pi-vision
112
+
113
+ # Optional CLI (inspect / convert / host / mcp-config)
114
+ npx pi2dsh inspect @narumitw/pi-lsp # compatibility report
115
+ npx pi2dsh convert @narumitw/pi-lsp --out ./dsh-pi-lsp # vendored snapshot
116
+ npx pi2dsh host --packages 'pi-simplify' --out ./pi-host # pinned bundle
117
+ npx pi2dsh mcp-config # Pi mcpServers → DSH patch
95
118
  ```
96
119
 
120
+ ## Examples: copy-paste working capabilities
121
+
122
+ **Every verified capability ships as a complete, runnable example under
123
+ [`examples/`](examples/)** — clone the repo, follow one example's README from
124
+ zero to seeing the feature run. Every command in an example has actually been
125
+ executed against a real DSH loop (CLI and web) before landing here; nothing
126
+ is aspirational.
127
+
128
+ | Example | What you get |
129
+ |---|---|
130
+ | [`examples/vision-bridge`](examples/vision-bridge/) | A text-only model answers questions about images: mention an image path, a configured vision model reads it, the analysis is injected into the conversation (works in CLI and the DSH web app; probe images included) |
131
+ | [`examples/custom-models`](examples/custom-models/) | Define a provider once in Pi's standard `models.json` — it becomes a native DSH llm route: visible in the DSH web model picker, usable as the main model, and resolvable/callable by every Pi plugin through one directory |
132
+
133
+ More verified capabilities (approval guardian, cross-session memory,
134
+ interactive OAuth, MCP config conversion, host mode) get their examples as
135
+ each one is re-verified end to end under the same bar.
136
+
97
137
  ## Interactive OAuth: sign in with your subscription
98
138
 
99
139
  DSH ships static HTTP headers only; pi2dsh adds the interactive OAuth layer from the Pi ecosystem. Any Pi provider package that registers an `oauth` block gets a working `/login <provider>` command on DSH, driven by the package's own protocol code. Pi's four official flows ship built in (vendored byte-identical): **OpenAI Codex (ChatGPT Plus/Pro)**, **Anthropic**, **GitHub Copilot**, **Kimi Code**.
package/README.zh.md CHANGED
@@ -5,11 +5,17 @@
5
5
  **打通 Pi 与 DeepSeek Harness 生态。** pi2dsh 致力于连接 [Pi](https://pi.dev/) 的扩展生态与 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH):用一层通用的 **Pi Host ABI 兼容层**,让未经修改的 Pi 扩展作为原生 DSH 插件运行——一次开发、批量兼容,不做逐包补丁。
6
6
 
7
7
  ```sh
8
- # 一个 bundle 装任意 Pi 包,零转换
9
- pi2dsh host --packages '@juicesharp/rpiv-web-tools@2.4.0,pi-simplify@0.2.3' --out ./my-pi-host
10
- dsh plugin --profile headless add file:$PWD/my-pi-host
8
+ # 装一次引擎,然后 Pi 包直接从 npm
9
+ dsh plugin --profile headless add pi2dsh
10
+ dsh plugin --profile headless add @kassing/pi-vision
11
+ dsh plugin --profile headless add pi-vision-tool
11
12
  ```
12
13
 
14
+ 没有转换步骤、没有生成产物:引擎自动发现你加进 profile 的每个 Pi 包,
15
+ 全部经一份桥实例挂载。卸载用 `dsh plugin remove <包>`;升级引擎
16
+ `dsh plugin add pi2dsh@latest`(插件不动),升级插件
17
+ `dsh plugin add <包>@latest`(引擎不动)。
18
+
13
19
  ## 架构
14
20
 
15
21
  桥只实现**一次** Pi 的公共扩展面,把每个调用映射到 DSH 原生服务。只用公共 API 的包原样运行;无法安全映射的能力显式失败,绝不伪装成功。
@@ -34,14 +40,25 @@ Pi 包(未经修改的 npm 依赖)
34
40
  DeepSeek Harness 原生服务(Cordis 组合)
35
41
  ```
36
42
 
37
- 三种使用方式:
43
+ 使用方式:
38
44
 
39
45
  | 方式 | 作用 |
40
46
  |---|---|
41
- | **Host bundle**(推荐) | 单一可安装 DSH bundle,把任意 Pi 包列表作为普通 npm 依赖挂载 |
42
- | **Convert** | 逐包可审查产物:vendored 源码快照 + 机器可读兼容报告,适合供应链敏感场景 |
47
+ | **引擎**(默认) | `dsh plugin add pi2dsh` 装一次桥。之后每个 `dsh plugin add` 的 Pi 包都会从 profile 的依赖清单被发现(清单里每一项都是你显式 add 的——绝不扫 node_modules)并经**一份**桥实例挂载:一个模型目录、一个 `/login`、一个凭证存储、一个升级单元 |
48
+ | **Host bundle** | 生成一个固定包清单的 DSH bundle——适合钉死版本、可复现的组合 |
49
+ | **Convert** | 逐包可审查产物:vendored 源码快照 + 机器可读兼容报告,适合供应链敏感或未发布/本地包 |
43
50
  | **MCP 配置转换** | Pi 的六层 `mcpServers` 配置 → 官方 `@deepseek-ai/dsh-mcp-client` patch 条目。不运行 pi-mcp-adapter 的代码;`$VAR` 转成 `!!js process.env.VAR`,字面量密钥会告警 |
44
51
 
52
+ 引擎可选配置(profile 的 `cordis.patch.yml`):`packages: [a, b]` 只挂
53
+ 指定清单(跳过发现);`exclude: [c]` 排除个别依赖。
54
+
55
+ **插件升级与兼容。** 已装插件的版本被 pnpm lockfile 锁定——插件永远不会
56
+ 背着你升级,只有显式 `dsh plugin add <包>@latest` 才会动。升级前先跑
57
+ `pi2dsh inspect <包>@<版本>` 看兼容报告。桥拦截了 Pi 运行时 import
58
+ (`pi-coding-agent`/`pi-tui`/`pi-ai` 由 shim 提供),插件自己锁的 Pi 依赖
59
+ 版本根本不会被加载——唯一可能咬人的漂移是插件用了桥还没覆盖的 Pi 新
60
+ API,这在报告里能看到,运行时也会按包隔离、显式报错。
61
+
45
62
  保持通用性的三条硬规则:
46
63
 
47
64
  1. 核心**没有任何 `if (packageName === …)`** 包名分支。
@@ -84,16 +101,28 @@ v6 版黑盒装置同时强化了探测方法论本身:桥自带的宿主固
84
101
  需要 Node.js 22.19+ 与 DeepSeek Harness。
85
102
 
86
103
  ```sh
87
- git clone https://github.com/weijiafu14/pi2dsh.git && cd pi2dsh
88
- corepack pnpm@11.7.0 install && pnpm build
89
-
90
- node dist/cli.mjs inspect @narumitw/pi-lsp # 兼容报告
91
- node dist/cli.mjs convert @narumitw/pi-lsp --out ./dsh-pi-lsp
92
- node dist/cli.mjs host --packages 'pi-simplify' --out ./pi-host
93
- node dist/cli.mjs mcp-config # Pi mcpServers → DSH patch
94
- dsh plugin --profile headless add file:$PWD/pi-host
104
+ # 引擎(默认):装一次,然后直接加 Pi
105
+ dsh plugin --profile headless add pi2dsh
106
+ dsh plugin --profile headless add @kassing/pi-vision
107
+
108
+ # 可选 CLI(inspect / convert / host / mcp-config)
109
+ npx pi2dsh inspect @narumitw/pi-lsp # 兼容报告
110
+ npx pi2dsh convert @narumitw/pi-lsp --out ./dsh-pi-lsp # vendored 快照
111
+ npx pi2dsh host --packages 'pi-simplify' --out ./pi-host # 钉版本 bundle
112
+ npx pi2dsh mcp-config # Pi mcpServers → DSH patch
95
113
  ```
96
114
 
115
+ ## Examples:每个能力都有完整可跑的示例
116
+
117
+ **每个已验证的能力,都在 [`examples/`](examples/) 下有一份完整可直接运行的示例**——克隆仓库,照任意一个示例的 README 从零走到看到效果。示例里的每条命令都在真实 DSH loop(CLI 和 Web 双端)上实际执行过才收录,没有"理论上可以"的内容。
118
+
119
+ | 示例 | 你得到什么 |
120
+ |---|---|
121
+ | [`examples/vision-bridge`](examples/vision-bridge/) | 纯文本模型回答图片问题:消息里带图片路径,配置的视觉模型识图,分析结果注入对话(CLI 与 DSH Web 都能用;附探针测试图) |
122
+ | [`examples/custom-models`](examples/custom-models/) | 在 Pi 标准 `models.json` 里定义一次 provider——它成为原生 DSH llm 路由:出现在 DSH Web 模型选择器、可当主模型对话、所有 Pi 插件经同一个目录可见可调 |
123
+
124
+ 更多已验证能力(审批 guardian、跨会话记忆、交互式 OAuth、MCP 配置转换、host 模式)的示例,将按同一标准逐个重新端到端验证后补齐。
125
+
97
126
  ## 交互式 OAuth:用你的订阅账号登录
98
127
 
99
128
  DSH 原生只有静态 HTTP headers;pi2dsh 把 Pi 生态的交互式 OAuth 层带了过来。任何注册了 `oauth` 块的 Pi provider 包,在 DSH 上都直接获得可用的 `/login <provider>` 命令,登录流程由包自己的协议代码驱动。Pi 的四条官方流内建(vendored 字节级):**OpenAI Codex(ChatGPT Plus/Pro)**、**Anthropic**、**GitHub Copilot**、**Kimi Code**。
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: pi2dsh
3
+ name: "pi2dsh"
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as analyzePackage, c as EVENT_RULES, i as generateBundle, l as HOST_IMPORT_RULES, n as convertPiMcpConfig, o as API_RULES, p as UI_CONTEXT_RULES, r as renderMcpPatch, s as CONTEXT_RULES } from "./mcp-config-B3h5jTBb.mjs";
3
2
  import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
3
+ import { a as analyzePackage, c as EVENT_RULES, i as generateBundle, l as HOST_IMPORT_RULES, n as convertPiMcpConfig, o as API_RULES, p as UI_CONTEXT_RULES, r as renderMcpPatch, s as CONTEXT_RULES } from "./mcp-config-vU1LZ7fC.mjs";
4
4
  import { writeFileSync } from "node:fs";
5
5
  import { parseArgs } from "node:util";
6
6
  //#region src/cli.ts
@@ -1,4 +1,4 @@
1
1
 
2
- import { A as anthropicOAuth, B as isContextOverflow, C as realBuiltinProvider, D as unregisterApiProviders, E as stream, F as createProvider, I as lazyApi, L as lazyStream, M as generatePKCE, N as pollOAuthDeviceCodeFlow, O as kimiCodingOAuth, P as ModelsError, R as AssistantMessageEventStream, S as openAIResponsesApi, T as registerProvider, V as isRecoverableLength, _ as loadGitHubCopilotOAuth, a as builtinProviders, b as modelsAreEqual, c as contentText, d as getModel, f as getModels, g as loadAnthropicOAuth, h as getSupportedThinkingLevels, i as anthropicMessagesApi, j as openaiCodexOAuth, k as githubCopilotOAuth, l as getApiProvider, m as getProviders, n as Type, o as clampThinkingLevel, p as getProvider, r as __setPiAiLlmBridge, s as complete, t as StringEnum, u as getApiProviders, v as loadKimiCodingOAuth, w as registerApiProvider, x as openAICompletionsApi, y as loadOpenAICodexOAuth, z as isRetryableAssistantError } from "../pi-ai-B_88Wb0r.mjs";
2
+ import { A as anthropicOAuth, B as isContextOverflow, C as realBuiltinProvider, D as unregisterApiProviders, E as stream, F as createProvider, I as lazyApi, L as lazyStream, M as generatePKCE, N as pollOAuthDeviceCodeFlow, O as kimiCodingOAuth, P as ModelsError, R as AssistantMessageEventStream, S as openAIResponsesApi, T as registerProvider, V as isRecoverableLength, _ as loadGitHubCopilotOAuth, a as builtinProviders, b as modelsAreEqual, c as contentText, d as getModel, f as getModels, g as loadAnthropicOAuth, h as getSupportedThinkingLevels, i as anthropicMessagesApi, j as openaiCodexOAuth, k as githubCopilotOAuth, l as getApiProvider, m as getProviders, n as Type, o as clampThinkingLevel, p as getProvider, r as __setPiAiLlmBridge, s as complete, t as StringEnum, u as getApiProviders, v as loadKimiCodingOAuth, w as registerApiProvider, x as openAICompletionsApi, y as loadOpenAICodexOAuth, z as isRetryableAssistantError } from "../pi-ai-7HR3ciAs.mjs";
3
3
  import { t as uuidv7 } from "../pi-uuid-Db8ShZsK.mjs";
4
4
  export { AssistantMessageEventStream, ModelsError, StringEnum, Type, __setPiAiLlmBridge, anthropicMessagesApi, anthropicOAuth, builtinProviders, clampThinkingLevel, complete, contentText, createProvider, generatePKCE, getApiProvider, getApiProviders, getModel, getModels, getProvider, getProviders, getSupportedThinkingLevels, githubCopilotOAuth, isContextOverflow, isRecoverableLength, isRetryableAssistantError, kimiCodingOAuth, lazyApi, lazyStream, loadAnthropicOAuth, loadGitHubCopilotOAuth, loadKimiCodingOAuth, loadOpenAICodexOAuth, modelsAreEqual, openAICompletionsApi, openAIResponsesApi, openaiCodexOAuth, pollOAuthDeviceCodeFlow, realBuiltinProvider, registerApiProvider, registerProvider, stream, unregisterApiProviders, uuidv7 };
@@ -1,4 +1,4 @@
1
1
 
2
2
  import { t as getAgentDir } from "../pi-config-shim-CZ1wFzqM.mjs";
3
- import { $ as isBashToolResult, $t as buildSessionContext, A as copyToClipboard, At as createGrepToolDefinition, B as generateSummary, Bt as createLocalBashOperations, C as ToolExecutionComponent, Ct as wrapRegisteredTool, D as calculateContextTokens, Dt as createFindTool, E as __setSubagentSessionFactory, Et as createLsToolDefinition, F as defineTool, Ft as createReadTool, G as getPackageDir, Gt as formatSize, H as getBinDir, Ht as withFileMutationQueue, I as ensureTool, It as createReadToolDefinition, J as getSettingsListTheme, Jt as truncateTail, K as getReadmePath, Kt as truncateHead, L as estimateTokens, Lt as bashToolSystemPromptContribution, M as createCodingTools, Mt as createWriteToolDefinition, N as createEventBus, Nt as createEditTool, O as compact, Ot as createFindToolDefinition, P as createReadOnlyTools, Pt as createEditToolDefinition, Q as initTheme, Qt as buildContextEntries, R as findCutPoint, Rt as createBashTool, S as Theme, St as truncateToVisualLines, T as VERSION, Tt as createLsTool, U as getLanguageFromPath, Ut as DEFAULT_MAX_BYTES, V as generateSummaryWithUsage, Vt as createExtensionRuntime, W as getMarkdownTheme, Wt as DEFAULT_MAX_LINES, X as getToolPath, Xt as SessionManager, Y as getShellConfig, Yt as CURRENT_SESSION_VERSION, Z as highlightCode, Zt as assertValidSessionId, _ as ModelRegistry, _t as resizeImage, a as CustomMessageComponent, an as parseSessionEntries, at as isToolCallEventType, b as SettingsManager, bt as stripFrontmatter, c as DefaultResourceLoader, cn as BRANCH_SUMMARY_SUFFIX, ct as keyText, d as ExtensionInputComponent, dn as bashExecutionToText, dt as parseFrontmatter, en as findMostRecentSession, et as isEditToolResult, f as ExtensionRunner, fn as convertToLlm, ft as parseSkillBlock, g as InMemorySettingsStorage, gt as renderDiff, h as FooterComponent, hn as createCustomMessage, ht as readStoredCredential, i as CustomEditor, in as migrateSessionEntries, it as isReadToolResult, j as createAgentSession, jt as createWriteTool, k as convertToPng, kt as createGrepTool, l as DynamicBorder, ln as COMPACTION_SUMMARY_PREFIX, lt as loadSkills, m as FileSettingsStorage, mn as createCompactionSummaryMessage, mt as rawKeyHint, n as BorderedLoader, nn as getLatestCompactionEntry, nt as isGrepToolResult, o as DEFAULT_COMPACTION_SETTINGS, on as sessionEntryToContextMessages, ot as isWriteToolResult, p as ExtensionSelectorComponent, pn as createBranchSummaryMessage, pt as processImage, q as getSelectListTheme, qt as truncateLine, r as CONFIG_DIR_NAME, rn as loadEntriesFromFile, rt as isLsToolResult, s as DefaultPackageManager, sn as BRANCH_SUMMARY_PREFIX, st as keyHint, t as AssistantMessageComponent, tn as getDefaultSessionDir, tt as isFindToolResult, u as ExtensionEditorComponent, un as COMPACTION_SUMMARY_SUFFIX, ut as loadSkillsFromDir, v as ModelRuntime, vt as serializeConversation, w as UserMessageComponent, wt as formatSkillsForPrompt, x as SettingsSelectorComponent, xt as theme, y as ProjectTrustStore, yt as shouldCompact, z as generateBranchSummary, zt as createBashToolDefinition } from "../pi-coding-agent-COMX0KHL.mjs";
3
+ import { $ as isBashToolResult, $t as buildSessionContext, A as copyToClipboard, At as createGrepToolDefinition, B as generateSummary, Bt as createLocalBashOperations, C as ToolExecutionComponent, Ct as wrapRegisteredTool, D as calculateContextTokens, Dt as createFindTool, E as __setSubagentSessionFactory, Et as createLsToolDefinition, F as defineTool, Ft as createReadTool, G as getPackageDir, Gt as formatSize, H as getBinDir, Ht as withFileMutationQueue, I as ensureTool, It as createReadToolDefinition, J as getSettingsListTheme, Jt as truncateTail, K as getReadmePath, Kt as truncateHead, L as estimateTokens, Lt as bashToolSystemPromptContribution, M as createCodingTools, Mt as createWriteToolDefinition, N as createEventBus, Nt as createEditTool, O as compact, Ot as createFindToolDefinition, P as createReadOnlyTools, Pt as createEditToolDefinition, Q as initTheme, Qt as buildContextEntries, R as findCutPoint, Rt as createBashTool, S as Theme, St as truncateToVisualLines, T as VERSION, Tt as createLsTool, U as getLanguageFromPath, Ut as DEFAULT_MAX_BYTES, V as generateSummaryWithUsage, Vt as createExtensionRuntime, W as getMarkdownTheme, Wt as DEFAULT_MAX_LINES, X as getToolPath, Xt as SessionManager, Y as getShellConfig, Yt as CURRENT_SESSION_VERSION, Z as highlightCode, Zt as assertValidSessionId, _ as ModelRegistry, _t as resizeImage, a as CustomMessageComponent, an as parseSessionEntries, at as isToolCallEventType, b as SettingsManager, bt as stripFrontmatter, c as DefaultResourceLoader, cn as BRANCH_SUMMARY_SUFFIX, ct as keyText, d as ExtensionInputComponent, dn as bashExecutionToText, dt as parseFrontmatter, en as findMostRecentSession, et as isEditToolResult, f as ExtensionRunner, fn as convertToLlm, ft as parseSkillBlock, g as InMemorySettingsStorage, gt as renderDiff, h as FooterComponent, hn as createCustomMessage, ht as readStoredCredential, i as CustomEditor, in as migrateSessionEntries, it as isReadToolResult, j as createAgentSession, jt as createWriteTool, k as convertToPng, kt as createGrepTool, l as DynamicBorder, ln as COMPACTION_SUMMARY_PREFIX, lt as loadSkills, m as FileSettingsStorage, mn as createCompactionSummaryMessage, mt as rawKeyHint, n as BorderedLoader, nn as getLatestCompactionEntry, nt as isGrepToolResult, o as DEFAULT_COMPACTION_SETTINGS, on as sessionEntryToContextMessages, ot as isWriteToolResult, p as ExtensionSelectorComponent, pn as createBranchSummaryMessage, pt as processImage, q as getSelectListTheme, qt as truncateLine, r as CONFIG_DIR_NAME, rn as loadEntriesFromFile, rt as isLsToolResult, s as DefaultPackageManager, sn as BRANCH_SUMMARY_PREFIX, st as keyHint, t as AssistantMessageComponent, tn as getDefaultSessionDir, tt as isFindToolResult, u as ExtensionEditorComponent, un as COMPACTION_SUMMARY_SUFFIX, ut as loadSkillsFromDir, v as ModelRuntime, vt as serializeConversation, w as UserMessageComponent, wt as formatSkillsForPrompt, x as SettingsSelectorComponent, xt as theme, y as ProjectTrustStore, yt as shouldCompact, z as generateBranchSummary, zt as createBashToolDefinition } from "../pi-coding-agent-CznNsOnV.mjs";
4
4
  export { AssistantMessageComponent, BRANCH_SUMMARY_PREFIX, BRANCH_SUMMARY_SUFFIX, BorderedLoader, COMPACTION_SUMMARY_PREFIX, COMPACTION_SUMMARY_SUFFIX, CONFIG_DIR_NAME, CURRENT_SESSION_VERSION, CustomEditor, CustomMessageComponent, DEFAULT_COMPACTION_SETTINGS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DefaultPackageManager, DefaultResourceLoader, DynamicBorder, ExtensionEditorComponent, ExtensionInputComponent, ExtensionRunner, ExtensionSelectorComponent, FileSettingsStorage, FooterComponent, InMemorySettingsStorage, ModelRegistry, ModelRuntime, ProjectTrustStore, SessionManager, SettingsManager, SettingsSelectorComponent, Theme, ToolExecutionComponent, UserMessageComponent, VERSION, __setSubagentSessionFactory, assertValidSessionId, bashExecutionToText, bashToolSystemPromptContribution, buildContextEntries, buildSessionContext, calculateContextTokens, compact, convertToLlm, convertToPng, copyToClipboard, createAgentSession, createBashTool, createBashToolDefinition, createBranchSummaryMessage, createCodingTools, createCompactionSummaryMessage, createCustomMessage, createEditTool, createEditToolDefinition, createEventBus, createExtensionRuntime, createFindTool, createFindToolDefinition, createGrepTool, createGrepToolDefinition, createLocalBashOperations, createLsTool, createLsToolDefinition, createReadOnlyTools, createReadTool, createReadToolDefinition, createWriteTool, createWriteToolDefinition, defineTool, ensureTool, estimateTokens, findCutPoint, findMostRecentSession, formatSize, formatSkillsForPrompt, generateBranchSummary, generateSummary, generateSummaryWithUsage, getAgentDir, getBinDir, getDefaultSessionDir, getLanguageFromPath, getLatestCompactionEntry, getMarkdownTheme, getPackageDir, getReadmePath, getSelectListTheme, getSettingsListTheme, getShellConfig, getToolPath, highlightCode, initTheme, isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, keyHint, keyText, loadEntriesFromFile, loadSkills, loadSkillsFromDir, migrateSessionEntries, parseFrontmatter, parseSessionEntries, parseSkillBlock, processImage, rawKeyHint, readStoredCredential, renderDiff, resizeImage, serializeConversation, sessionEntryToContextMessages, shouldCompact, stripFrontmatter, theme, truncateHead, truncateLine, truncateTail, truncateToVisualLines, withFileMutationQueue, wrapRegisteredTool };
@@ -1,8 +1,8 @@
1
1
 
2
- import { a as builtinProviders } from "./pi-ai-B_88Wb0r.mjs";
2
+ import { a as builtinProviders } from "./pi-ai-7HR3ciAs.mjs";
3
3
  import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
4
- import "./pi-coding-agent-COMX0KHL.mjs";
5
- import { i as resolveOAuthApiKey, o as storedOAuthCredential, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-C6fL1qSv.mjs";
4
+ import "./pi-coding-agent-CznNsOnV.mjs";
5
+ import { i as resolveOAuthApiKey, o as storedOAuthCredential, r as providerSupportsOAuth, t as FileCredentialStore } from "./oauth-bridge-CfyImWx4.mjs";
6
6
  import { join } from "node:path";
7
7
  import { CredentialProvider } from "@deepseek-ai/dsh-credentials";
8
8
  //#region src/credentials-oauth.ts
package/dist/host.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
 
2
- import { t as applyPiPackage } from "./runtime-B7mEIRf-.mjs";
2
+ import { t as applyPiPackage } from "./runtime-xNd10ACP.mjs";
3
3
  import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { cp, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
6
+ import { existsSync } from "node:fs";
6
7
  import { basename, dirname, join, relative } from "node:path";
7
8
  import { fileURLToPath, pathToFileURL } from "node:url";
8
- import { existsSync } from "node:fs";
9
9
  //#region src/host.ts
10
10
  function parseFrontmatter(text) {
11
11
  const normalized = text.replace(/\r\n?/gu, "\n");
package/dist/index.d.mts CHANGED
@@ -1,6 +1,35 @@
1
1
 
2
2
  import { a as GeneratedRuntimeManifest, c as ResourceInventory, i as GenerateOptions, n as CompatibilityLevel, o as PackageIdentity, r as CompatibilityReport, s as ResolvedPiPackage, t as CompatibilityFinding } from "./types-7IWJPPvS.mjs";
3
3
  import { applyPiHost, generateHostBundle, manifestForInstalled } from "./host.mjs";
4
+ import { Context } from "@deepseek-ai/cordis";
5
+ //#region src/engine.d.ts
6
+ interface EngineConfig {
7
+ /** Mount exactly these packages (skips discovery). */
8
+ packages?: string[];
9
+ /** Never mount these packages even when discovered. */
10
+ exclude?: string[];
11
+ }
12
+ /** Locate the DSH profile root: the nearest ancestor holding cordis.yml. */
13
+ declare function findProfileRoot(start: string): string | undefined;
14
+ interface DiscoveredPackage {
15
+ name: string;
16
+ dir: string;
17
+ }
18
+ /**
19
+ * The profile's direct dependencies that identify as Pi packages: not the
20
+ * engine itself, not a `dsh.bundle` (those are DSH plugins, not Pi
21
+ * packages), carrying either Pi's `pi` manifest field or extension sources
22
+ * under Pi's directory conventions.
23
+ */
24
+ declare function discoverProfilePiPackages(profileRoot: string, options?: {
25
+ exclude?: string[];
26
+ warn?: (message: string) => void;
27
+ }): Promise<DiscoveredPackage[]>;
28
+ /** Cordis plugin surface: `dsh plugin add pi2dsh` mounts this. */
29
+ declare const name = "pi2dsh";
30
+ declare const inject: string[];
31
+ declare function apply(ctx: Context, config?: EngineConfig): Promise<void>;
32
+ //#endregion
4
33
  //#region src/analyzer.d.ts
5
34
  declare function analyzePackage(pkg: ResolvedPiPackage): Promise<CompatibilityReport>;
6
35
  //#endregion
@@ -65,5 +94,5 @@ declare function renderMcpPatch(result: McpConversionResult): string;
65
94
  //#region src/source.d.ts
66
95
  declare function resolvePiPackage(source: string, cwd?: string): Promise<ResolvedPiPackage>;
67
96
  //#endregion
68
- export { API_RULES, CONTEXT_RULES, type CompatibilityFinding, type CompatibilityLevel, type CompatibilityReport, EVENT_RULES, type GenerateOptions, type GeneratedRuntimeManifest, HOST_IMPORT_RULES, PI_AI_PACKAGES, PI_CODING_AGENT_PACKAGES, PI_TUI_PACKAGES, type PackageIdentity, type ResolvedPiPackage, type ResourceInventory, UI_CONTEXT_RULES, analyzePackage, applyPiHost, collectPiMcpServers, convertPiMcpConfig, generateBundle, generateHostBundle, manifestForInstalled, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
97
+ export { API_RULES, CONTEXT_RULES, type CompatibilityFinding, type CompatibilityLevel, type CompatibilityReport, EVENT_RULES, type EngineConfig, type GenerateOptions, type GeneratedRuntimeManifest, HOST_IMPORT_RULES, PI_AI_PACKAGES, PI_CODING_AGENT_PACKAGES, PI_TUI_PACKAGES, type PackageIdentity, type ResolvedPiPackage, type ResourceInventory, UI_CONTEXT_RULES, analyzePackage, apply, applyPiHost, collectPiMcpServers, convertPiMcpConfig, discoverProfilePiPackages, findProfileRoot, generateBundle, generateHostBundle, inject, manifestForInstalled, name, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
69
98
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/analyzer.ts","../src/compatibility.ts","../src/generator.ts","../src/mcp-config.ts","../src/source.ts"],"mappings":";;;;iBAgbsB,eAAe,KAAK,oBAAoB,QAAQ;;;UC9a5D;EACR,OAAO;EACP;;cAKW;cAKA;cAKA;cAWA,mBAAmB,SAAS,eAAe,SAAS,eAAe;cAmNnE,eAAe,SAAS,eAAe;cA4BvC,kBAAkB,SAAS,eAAe;cA+B1C,WAAW,SAAS,eAAe;cAgHnC,aAAa,SAAS,eAAe;iBA6FlC,WAAW,iBAAiB;iBAI5B,aAAa,gBAAgB;iBAO7B,kBAAkB,qBAAqB,uBAAuB;iBAS9D,uBAAuB,mBAAmB;iBAI1C,yBAAyB,mBAAmB;;;iBC3LtC,eACpB,KAAK,mBACL,SAAS,kBACR;EAAU;EAAgB,QAAQ;EAAqB;;;;KC5UrD,gBAAgB;UAEJ;EACf;EACA;EACA;EACA;EACA;EACA,MAAM;EACN;EACA;EACA,UAAU;EACV;;UAGe;EACf;EACA;;UAGe;EACf,SAAS;EACT,SAAS;EACT,UAAU;EACV;;iBA6Cc,oBAAoB,aAAa;EAA8B,SAAS,YAAY;EAAc;;iBAoElG,mBAAmB,aAAa,wBAA4B;;iBAsD5D,eAAe,QAAQ;;;iBC5EjB,iBAAiB,gBAAgB,eAAsB,QAAQ"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/engine.ts","../src/analyzer.ts","../src/compatibility.ts","../src/generator.ts","../src/mcp-config.ts","../src/source.ts"],"mappings":";;;;;UA4BiB;;EAEf;;EAEA;;;iBAIc,gBAAgB;UAUtB;EACR;EACA;;;;;;;;iBAgBoB,0BACpB,qBACA;EAAW;EAAoB,QAAQ;IACtC,QAAQ;;cA4CE;cACA;iBAES,MAAM,KAAK,SAAS,SAAQ,eAAoB;;;iBC8ThD,eAAe,KAAK,oBAAoB,QAAQ;;;UC9a5D;EACR,OAAO;EACP;;cAKW;cAKA;cAKA;cAWA,mBAAmB,SAAS,eAAe,SAAS,eAAe;cAmNnE,eAAe,SAAS,eAAe;cA4BvC,kBAAkB,SAAS,eAAe;cA+B1C,WAAW,SAAS,eAAe;cAgHnC,aAAa,SAAS,eAAe;iBA6FlC,WAAW,iBAAiB;iBAI5B,aAAa,gBAAgB;iBAO7B,kBAAkB,qBAAqB,uBAAuB;iBAS9D,uBAAuB,mBAAmB;iBAI1C,yBAAyB,mBAAmB;;;iBC3LtC,eACpB,KAAK,mBACL,SAAS,kBACR;EAAU;EAAgB,QAAQ;EAAqB;;;;KC5UrD,gBAAgB;UAEJ;EACf;EACA;EACA;EACA;EACA;EACA,MAAM;EACN;EACA;EACA,UAAU;EACV;;UAGe;EACf;EACA;;UAGe;EACf,SAAS;EACT,SAAS;EACT,UAAU;EACV;;iBA6Cc,oBAAoB,aAAa;EAA8B,SAAS,YAAY;EAAc;;iBAoElG,mBAAmB,aAAa,wBAA4B;;iBAsD5D,eAAe,QAAQ;;;iBC5EjB,iBAAiB,gBAAgB,eAAsB,QAAQ"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,101 @@
1
1
 
2
- import { _ as ruleForHostImport, a as analyzePackage, c as EVENT_RULES, d as PI_CODING_AGENT_PACKAGES, f as PI_TUI_PACKAGES, g as ruleForEvent, h as ruleForContextProperty, i as generateBundle, l as HOST_IMPORT_RULES, m as ruleForApi, n as convertPiMcpConfig, o as API_RULES, p as UI_CONTEXT_RULES, r as renderMcpPatch, s as CONTEXT_RULES, t as collectPiMcpServers, u as PI_AI_PACKAGES, v as ruleForUiContextProperty } from "./mcp-config-B3h5jTBb.mjs";
3
2
  import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
4
3
  import { applyPiHost, generateHostBundle, manifestForInstalled } from "./host.mjs";
5
- export { API_RULES, CONTEXT_RULES, EVENT_RULES, HOST_IMPORT_RULES, PI_AI_PACKAGES, PI_CODING_AGENT_PACKAGES, PI_TUI_PACKAGES, UI_CONTEXT_RULES, analyzePackage, applyPiHost, collectPiMcpServers, convertPiMcpConfig, generateBundle, generateHostBundle, manifestForInstalled, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
4
+ import { _ as ruleForHostImport, a as analyzePackage, c as EVENT_RULES, d as PI_CODING_AGENT_PACKAGES, f as PI_TUI_PACKAGES, g as ruleForEvent, h as ruleForContextProperty, i as generateBundle, l as HOST_IMPORT_RULES, m as ruleForApi, n as convertPiMcpConfig, o as API_RULES, p as UI_CONTEXT_RULES, r as renderMcpPatch, s as CONTEXT_RULES, t as collectPiMcpServers, u as PI_AI_PACKAGES, v as ruleForUiContextProperty } from "./mcp-config-vU1LZ7fC.mjs";
5
+ import { readFile } from "node:fs/promises";
6
+ import { existsSync } from "node:fs";
7
+ import { dirname, join } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ //#region src/engine.ts
10
+ /** Locate the DSH profile root: the nearest ancestor holding cordis.yml. */
11
+ function findProfileRoot(start) {
12
+ let dir = start;
13
+ for (;;) {
14
+ if (existsSync(join(dir, "cordis.yml")) && existsSync(join(dir, "package.json"))) return dir;
15
+ const parent = dirname(dir);
16
+ if (parent === dir) return void 0;
17
+ dir = parent;
18
+ }
19
+ }
20
+ function resolveDependencyDir(profileRoot, name) {
21
+ const dir = join(profileRoot, "node_modules", name);
22
+ return existsSync(join(dir, "package.json")) ? dir : void 0;
23
+ }
24
+ /**
25
+ * The profile's direct dependencies that identify as Pi packages: not the
26
+ * engine itself, not a `dsh.bundle` (those are DSH plugins, not Pi
27
+ * packages), carrying either Pi's `pi` manifest field or extension sources
28
+ * under Pi's directory conventions.
29
+ */
30
+ async function discoverProfilePiPackages(profileRoot, options = {}) {
31
+ const warn = options.warn ?? (() => {});
32
+ const excluded = new Set(options.exclude ?? []);
33
+ const manifestText = await readFile(join(profileRoot, "package.json"), "utf8");
34
+ const manifest = JSON.parse(manifestText);
35
+ const discovered = [];
36
+ for (const name of Object.keys(manifest.dependencies ?? {})) {
37
+ if (name === "pi2dsh" || excluded.has(name)) continue;
38
+ const dir = resolveDependencyDir(profileRoot, name);
39
+ if (dir === void 0) {
40
+ warn(`[pi2dsh engine] dependency ${JSON.stringify(name)} is not installed under the profile; skipping`);
41
+ continue;
42
+ }
43
+ let packageJson;
44
+ try {
45
+ packageJson = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
46
+ } catch (error) {
47
+ warn(`[pi2dsh engine] cannot read ${name}/package.json (${error instanceof Error ? error.message : String(error)}); skipping`);
48
+ continue;
49
+ }
50
+ if (packageJson.dsh?.bundle !== void 0) continue;
51
+ if (packageJson.pi !== void 0 && typeof packageJson.pi === "object") {
52
+ discovered.push({
53
+ name,
54
+ dir
55
+ });
56
+ continue;
57
+ }
58
+ try {
59
+ const pkg = await resolvePiPackage(dir);
60
+ try {
61
+ if (pkg.resources.extensions.length > 0) discovered.push({
62
+ name,
63
+ dir
64
+ });
65
+ } finally {
66
+ await pkg.dispose();
67
+ }
68
+ } catch {}
69
+ }
70
+ return discovered;
71
+ }
72
+ /** Cordis plugin surface: `dsh plugin add pi2dsh` mounts this. */
73
+ const name = "pi2dsh";
74
+ const inject = [
75
+ "tools",
76
+ "systemPrompt",
77
+ "commands",
78
+ "skills"
79
+ ];
80
+ async function apply(ctx, config = {}) {
81
+ const log = ctx.logger;
82
+ const warn = log?.warn?.bind(log) ?? console.warn;
83
+ const info = log?.info?.bind(log) ?? console.log;
84
+ const baseUrl = ctx.baseUrl;
85
+ const profileRoot = (baseUrl !== void 0 ? findProfileRoot(fileURLToPath(new URL(".", baseUrl))) : void 0) ?? findProfileRoot(dirname(fileURLToPath(import.meta.url)));
86
+ if (profileRoot === void 0) throw new Error("pi2dsh engine: no DSH profile root (cordis.yml + package.json) above the installed engine — is pi2dsh installed via `dsh plugin add pi2dsh`?");
87
+ const packages = Array.isArray(config.packages) && config.packages.length > 0 ? config.packages.map((name) => ({ name })) : await discoverProfilePiPackages(profileRoot, {
88
+ ...Array.isArray(config.exclude) ? { exclude: config.exclude } : {},
89
+ warn
90
+ });
91
+ if (packages.length === 0) {
92
+ info("[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>");
93
+ return;
94
+ }
95
+ info(`[pi2dsh engine] mounting ${packages.length} Pi package(s): ${packages.map((pkg) => pkg.name).join(", ")}`);
96
+ await applyPiHost(ctx, { packages: packages.map((pkg) => ({ name: pkg.name })) }, join(profileRoot, "package.json"));
97
+ }
98
+ //#endregion
99
+ export { API_RULES, CONTEXT_RULES, EVENT_RULES, HOST_IMPORT_RULES, PI_AI_PACKAGES, PI_CODING_AGENT_PACKAGES, PI_TUI_PACKAGES, UI_CONTEXT_RULES, analyzePackage, apply, applyPiHost, collectPiMcpServers, convertPiMcpConfig, discoverProfilePiPackages, findProfileRoot, generateBundle, generateHostBundle, inject, manifestForInstalled, name, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
100
+
101
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/engine.ts"],"sourcesContent":["// The pi2dsh engine: ONE installed copy of the bridge that mounts every Pi\n// package the user has added to their DSH profile.\n//\n// dsh plugin --profile p add pi2dsh ← the engine (this plugin)\n// dsh plugin --profile p add @kassing/pi-vision ← plain npm dependency\n// dsh plugin --profile p add pi-vision-tool ← plain npm dependency\n//\n// DSH's plugin manager records only packages that declare `dsh.bundle` as\n// profile layers; everything else stays an ordinary dependency (\"a plain\n// library is fine\"). The engine reads the profile manifest's DIRECT\n// dependencies — every entry there was an explicit `dsh plugin add` — and\n// mounts each package that identifies as a Pi package, all through one\n// bridge instance: one model ledger, one command space, one upgrade unit.\n//\n// Discovery is manifest-driven, never a node_modules scan (the lesson from\n// Prettier 3 dropping directory-based plugin discovery): the dependency list\n// is the user's explicit intent, and package identification uses the same\n// Pi markers `resolvePiPackage` has always used (the `pi` manifest field,\n// with Pi's directory conventions as fallback).\n\nimport { readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { applyPiHost } from './host.js'\nimport { resolvePiPackage } from './source.js'\n\nexport interface EngineConfig {\n /** Mount exactly these packages (skips discovery). */\n packages?: string[]\n /** Never mount these packages even when discovered. */\n exclude?: string[]\n}\n\n/** Locate the DSH profile root: the nearest ancestor holding cordis.yml. */\nexport function findProfileRoot(start: string): string | undefined {\n let dir = start\n for (;;) {\n if (existsSync(join(dir, 'cordis.yml')) && existsSync(join(dir, 'package.json'))) return dir\n const parent = dirname(dir)\n if (parent === dir) return undefined\n dir = parent\n }\n}\n\ninterface DiscoveredPackage {\n name: string\n dir: string\n}\n\nfunction resolveDependencyDir(profileRoot: string, name: string): string | undefined {\n // Direct dependencies of the profile live under its node_modules by name\n // (pnpm links them there); resolving by path needs no exports gymnastics.\n const dir = join(profileRoot, 'node_modules', name)\n return existsSync(join(dir, 'package.json')) ? dir : undefined\n}\n\n/**\n * The profile's direct dependencies that identify as Pi packages: not the\n * engine itself, not a `dsh.bundle` (those are DSH plugins, not Pi\n * packages), carrying either Pi's `pi` manifest field or extension sources\n * under Pi's directory conventions.\n */\nexport async function discoverProfilePiPackages(\n profileRoot: string,\n options: { exclude?: string[], warn?: (message: string) => void } = {},\n): Promise<DiscoveredPackage[]> {\n const warn = options.warn ?? (() => {})\n const excluded = new Set(options.exclude ?? [])\n const manifestText = await readFile(join(profileRoot, 'package.json'), 'utf8')\n const manifest = JSON.parse(manifestText) as { dependencies?: Record<string, string> }\n const discovered: DiscoveredPackage[] = []\n for (const name of Object.keys(manifest.dependencies ?? {})) {\n if (name === 'pi2dsh' || excluded.has(name)) continue\n const dir = resolveDependencyDir(profileRoot, name)\n if (dir === undefined) {\n warn(`[pi2dsh engine] dependency ${JSON.stringify(name)} is not installed under the profile; skipping`)\n continue\n }\n let packageJson: Record<string, unknown>\n try {\n packageJson = JSON.parse(await readFile(join(dir, 'package.json'), 'utf8')) as Record<string, unknown>\n } catch (error) {\n warn(`[pi2dsh engine] cannot read ${name}/package.json (${error instanceof Error ? error.message : String(error)}); skipping`)\n continue\n }\n // A dsh.bundle-declaring package is a DSH plugin layer, never a Pi package.\n if ((packageJson.dsh as { bundle?: unknown } | undefined)?.bundle !== undefined) continue\n if (packageJson.pi !== undefined && typeof packageJson.pi === 'object') {\n discovered.push({ name, dir })\n continue\n }\n // No `pi` field: fall back to Pi's directory conventions via the same\n // resolver every other mount path uses (a package with zero extension\n // sources is a plain library and stays unmounted).\n try {\n const pkg = await resolvePiPackage(dir)\n try {\n if (pkg.resources.extensions.length > 0) discovered.push({ name, dir })\n } finally {\n await pkg.dispose()\n }\n } catch {\n // Not resolvable as a Pi package — a plain library.\n }\n }\n return discovered\n}\n\n/** Cordis plugin surface: `dsh plugin add pi2dsh` mounts this. */\nexport const name = 'pi2dsh'\nexport const inject = ['tools', 'systemPrompt', 'commands', 'skills']\n\nexport async function apply(ctx: Context, config: EngineConfig = {}): Promise<void> {\n const log = (ctx as unknown as { logger?: { info?(m: string): void, warn?(m: string): void } }).logger\n const warn = log?.warn?.bind(log) ?? console.warn\n const info = log?.info?.bind(log) ?? console.log\n\n // The loader resolves plugins against the profile's baseUrl; that IS the\n // profile root. The ancestor walk from the installed engine is the\n // fallback for compositions without a loader (tests, hand-built hosts).\n const baseUrl = (ctx as unknown as { baseUrl?: string }).baseUrl\n const profileRoot = (baseUrl !== undefined ? findProfileRoot(fileURLToPath(new URL('.', baseUrl))) : undefined)\n ?? findProfileRoot(dirname(fileURLToPath(import.meta.url)))\n if (profileRoot === undefined) {\n throw new Error('pi2dsh engine: no DSH profile root (cordis.yml + package.json) above the installed engine — is pi2dsh installed via `dsh plugin add pi2dsh`?')\n }\n\n const packages = Array.isArray(config.packages) && config.packages.length > 0\n ? config.packages.map(name => ({ name }))\n : await discoverProfilePiPackages(profileRoot, {\n ...(Array.isArray(config.exclude) ? { exclude: config.exclude } : {}),\n warn,\n })\n if (packages.length === 0) {\n info('[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>')\n return\n }\n info(`[pi2dsh engine] mounting ${packages.length} Pi package(s): ${packages.map(pkg => pkg.name).join(', ')}`)\n await applyPiHost(\n ctx,\n { packages: packages.map(pkg => ({ name: pkg.name })) },\n join(profileRoot, 'package.json'),\n )\n}\n"],"mappings":";;;;;;;;;;AAoCA,SAAgB,gBAAgB,OAAmC;CACjE,IAAI,MAAM;CACV,SAAS;EACP,IAAI,WAAW,KAAK,KAAK,YAAY,CAAC,KAAK,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG,OAAO;EACzF,MAAM,SAAS,QAAQ,GAAG;EAC1B,IAAI,WAAW,KAAK,OAAO,KAAA;EAC3B,MAAM;CACR;AACF;AAOA,SAAS,qBAAqB,aAAqB,MAAkC;CAGnF,MAAM,MAAM,KAAK,aAAa,gBAAgB,IAAI;CAClD,OAAO,WAAW,KAAK,KAAK,cAAc,CAAC,IAAI,MAAM,KAAA;AACvD;;;;;;;AAQA,eAAsB,0BACpB,aACA,UAAoE,CAAC,GACvC;CAC9B,MAAM,OAAO,QAAQ,eAAe,CAAC;CACrC,MAAM,WAAW,IAAI,IAAI,QAAQ,WAAW,CAAC,CAAC;CAC9C,MAAM,eAAe,MAAM,SAAS,KAAK,aAAa,cAAc,GAAG,MAAM;CAC7E,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,aAAkC,CAAC;CACzC,KAAK,MAAM,QAAQ,OAAO,KAAK,SAAS,gBAAgB,CAAC,CAAC,GAAG;EAC3D,IAAI,SAAS,YAAY,SAAS,IAAI,IAAI,GAAG;EAC7C,MAAM,MAAM,qBAAqB,aAAa,IAAI;EAClD,IAAI,QAAQ,KAAA,GAAW;GACrB,KAAK,8BAA8B,KAAK,UAAU,IAAI,EAAE,8CAA8C;GACtG;EACF;EACA,IAAI;EACJ,IAAI;GACF,cAAc,KAAK,MAAM,MAAM,SAAS,KAAK,KAAK,cAAc,GAAG,MAAM,CAAC;EAC5E,SAAS,OAAO;GACd,KAAK,+BAA+B,KAAK,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,YAAY;GAC7H;EACF;EAEA,IAAK,YAAY,KAA0C,WAAW,KAAA,GAAW;EACjF,IAAI,YAAY,OAAO,KAAA,KAAa,OAAO,YAAY,OAAO,UAAU;GACtE,WAAW,KAAK;IAAE;IAAM;GAAI,CAAC;GAC7B;EACF;EAIA,IAAI;GACF,MAAM,MAAM,MAAM,iBAAiB,GAAG;GACtC,IAAI;IACF,IAAI,IAAI,UAAU,WAAW,SAAS,GAAG,WAAW,KAAK;KAAE;KAAM;IAAI,CAAC;GACxE,UAAU;IACR,MAAM,IAAI,QAAQ;GACpB;EACF,QAAQ,CAER;CACF;CACA,OAAO;AACT;;AAGA,MAAa,OAAO;AACpB,MAAa,SAAS;CAAC;CAAS;CAAgB;CAAY;AAAQ;AAEpE,eAAsB,MAAM,KAAc,SAAuB,CAAC,GAAkB;CAClF,MAAM,MAAO,IAAmF;CAChG,MAAM,OAAO,KAAK,MAAM,KAAK,GAAG,KAAK,QAAQ;CAC7C,MAAM,OAAO,KAAK,MAAM,KAAK,GAAG,KAAK,QAAQ;CAK7C,MAAM,UAAW,IAAwC;CACzD,MAAM,eAAe,YAAY,KAAA,IAAY,gBAAgB,cAAc,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,IAAI,KAAA,MAChG,gBAAgB,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC;CAC5D,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,8IAA8I;CAGhK,MAAM,WAAW,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IACxE,OAAO,SAAS,KAAI,UAAS,EAAE,KAAK,EAAE,IACtC,MAAM,0BAA0B,aAAa;EAC3C,GAAI,MAAM,QAAQ,OAAO,OAAO,IAAI,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACnE;CACF,CAAC;CACL,IAAI,SAAS,WAAW,GAAG;EACzB,KAAK,wHAAwH;EAC7H;CACF;CACA,KAAK,4BAA4B,SAAS,OAAO,kBAAkB,SAAS,KAAI,QAAO,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG;CAC7G,MAAM,YACJ,KACA,EAAE,UAAU,SAAS,KAAI,SAAQ,EAAE,MAAM,IAAI,KAAK,EAAE,EAAE,GACtD,KAAK,aAAa,cAAc,CAClC;AACF"}
@@ -2,12 +2,12 @@
2
2
  import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
3
3
  import { builtinModules } from "node:module";
4
4
  import { cp, lstat, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
5
+ import { existsSync, readFileSync } from "node:fs";
5
6
  import { basename, dirname, extname, join, relative, resolve } from "node:path";
6
- import ts from "typescript";
7
7
  import { fileURLToPath } from "node:url";
8
- import { parse } from "yaml";
9
- import { existsSync, readFileSync } from "node:fs";
10
8
  import { homedir } from "node:os";
9
+ import ts from "typescript";
10
+ import { parse } from "yaml";
11
11
  //#region src/compatibility.ts
12
12
  const rule = (level, detail) => ({
13
13
  level,
@@ -244,8 +244,8 @@ const CONTEXT_RULES = Object.freeze({
244
244
  getSystemPromptOptions: rule("partial", "Returns an empty Pi option projection in command contexts."),
245
245
  waitForIdle: rule("partial", "Mapped to the DSH agent idle boundary when available."),
246
246
  sessionManager: rule("partial", "A real read-only projection: DSH durable messages plus pi2dsh sidecar entries, exposed through Pi's exact 14-method surface as a single-branch tree."),
247
- modelRegistry: rule("partial", "A live registry over the ONE model directory: every Pi provider (package-registered or ~/.pi/agent/models.json) is a DSH llm route, and the registry is that directory's exact Pi projection — Pi-native entries keep api/baseUrl and the full Model shape. getProviderAuth/getApiKeyAndHeaders run Pi's full credential chain (models.json keys resolve with Pi's $ENV/!command semantics); DSH-owned routes keep their credentials inside their adapters by design."),
248
- model: rule("partial", "The agent's real provider/model route (a setModel() override wins), enriched from the projected catalog."),
247
+ modelRegistry: rule("partial", "A live registry over the ONE model directory: every Pi provider (package-registered or ~/.pi/agent/models.json) is a DSH llm route, and the registry is that directory's exact Pi projection — Pi-native entries keep api/baseUrl and the full Model shape. getProviderAuth/getApiKeyAndHeaders run Pi's full credential chain (models.json keys resolve with Pi's $ENV/!command semantics); DSH-owned routes keep their credentials inside their adapters by design. A models.json entry carrying ONLY modelOverrides that declare input:[\"text\",\"image\"] for an existing route registers a \"<route>-vision\" image-admission companion: a real DSH route that admits images, replaces image blocks with an explicit text notice, and forwards to the original route (Pi itself has no admission layer, so this projection is bridge-defined). Stored attachments are materialized to temp files and the notice names the path — Pi's image vocabulary is inline-or-path, so a path lets any path-taking tool (Pi's read, vision tools) reach the image."),
248
+ model: rule("partial", "The agent's real provider/model route (a setModel() override wins), enriched from the projected catalog. When the selected route is an image-admission companion, ctx.model reports the ORIGINAL route with its true modalities — the generating model is the original text-only one, which is the truth extensions branching on input modalities (a vision bridge's activation check) need."),
249
249
  scopedModels: rule("partial", "The projected model catalog (DSH llm directory plus package-registered providers)."),
250
250
  hasConfiguredAuth: rule("partial", "Configuration check on the projected registry: true when the model's provider has a live route or package registration (not a key-liveness probe)."),
251
251
  thinkingLevel: rule("partial", "Reflects the level recorded by setThinkingLevel(); applied as reasoningEffort on the next request."),
@@ -1615,4 +1615,4 @@ function renderMcpPatch(result) {
1615
1615
  //#endregion
1616
1616
  export { ruleForHostImport as _, analyzePackage as a, EVENT_RULES as c, PI_CODING_AGENT_PACKAGES as d, PI_TUI_PACKAGES as f, ruleForEvent as g, ruleForContextProperty as h, generateBundle as i, HOST_IMPORT_RULES as l, ruleForApi as m, convertPiMcpConfig as n, API_RULES as o, UI_CONTEXT_RULES as p, renderMcpPatch as r, CONTEXT_RULES as s, collectPiMcpServers as t, PI_AI_PACKAGES as u, ruleForUiContextProperty as v };
1617
1617
 
1618
- //# sourceMappingURL=mcp-config-B3h5jTBb.mjs.map
1618
+ //# sourceMappingURL=mcp-config-vU1LZ7fC.mjs.map