pi2dsh 0.7.0 → 0.8.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 (100) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/dist/analyzer-CKTsWVzn.mjs +628 -0
  4. package/dist/analyzer-CKTsWVzn.mjs.map +1 -0
  5. package/dist/cli.mjs +3 -1
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/compat/pi-ai.d.mts +1 -11
  8. package/dist/compat/pi-ai.d.mts.map +1 -1
  9. package/dist/compat/pi-ai.mjs +2 -2
  10. package/dist/credentials-oauth.mjs +1 -1
  11. package/dist/generator-eyViezvs.mjs +300 -0
  12. package/dist/generator-eyViezvs.mjs.map +1 -0
  13. package/dist/host.d.mts +2 -0
  14. package/dist/host.d.mts.map +1 -1
  15. package/dist/host.mjs +2 -1
  16. package/dist/host.mjs.map +1 -1
  17. package/dist/index.d.mts +28 -10
  18. package/dist/index.d.mts.map +1 -1
  19. package/dist/index.mjs +27 -4
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/mcp-config-Dlou-ZA-.mjs +707 -0
  22. package/dist/mcp-config-Dlou-ZA-.mjs.map +1 -0
  23. package/dist/{pi-ai-B4hucafU.mjs → pi-ai-C6Xag6xt.mjs} +2 -74
  24. package/dist/pi-ai-C6Xag6xt.mjs.map +1 -0
  25. package/dist/{runtime-k3IlCgjQ.mjs → runtime-B-Mun-jX.mjs} +44 -947
  26. package/dist/runtime-B-Mun-jX.mjs.map +1 -0
  27. package/dist/runtime.d.mts +11 -6
  28. package/dist/runtime.d.mts.map +1 -1
  29. package/dist/runtime.mjs +2 -2
  30. package/package.json +6 -3
  31. package/dist/all-BChhwMVE.mjs +0 -28512
  32. package/dist/all-BChhwMVE.mjs.map +0 -1
  33. package/dist/anthropic-messages-Dlw4T0S4.mjs +0 -6438
  34. package/dist/anthropic-messages-Dlw4T0S4.mjs.map +0 -1
  35. package/dist/azure-openai-responses-vGUNukZ7.mjs +0 -209
  36. package/dist/azure-openai-responses-vGUNukZ7.mjs.map +0 -1
  37. package/dist/deferred-tools-BD4g5QUx.mjs +0 -32
  38. package/dist/deferred-tools-BD4g5QUx.mjs.map +0 -1
  39. package/dist/diagnostics-CJye1UFh.mjs +0 -99
  40. package/dist/diagnostics-CJye1UFh.mjs.map +0 -1
  41. package/dist/dist-DY2GeEQ6.mjs +0 -1089
  42. package/dist/dist-DY2GeEQ6.mjs.map +0 -1
  43. package/dist/dist-DYfTHu0C.mjs +0 -1246
  44. package/dist/dist-DYfTHu0C.mjs.map +0 -1
  45. package/dist/error-body-DKA3lknR.mjs +0 -104
  46. package/dist/error-body-DKA3lknR.mjs.map +0 -1
  47. package/dist/github-copilot-headers-CZo2QHrt.mjs +0 -25
  48. package/dist/github-copilot-headers-CZo2QHrt.mjs.map +0 -1
  49. package/dist/google-generative-ai-C30gRjRi.mjs +0 -358
  50. package/dist/google-generative-ai-C30gRjRi.mjs.map +0 -1
  51. package/dist/google-shared-W8g3Esep.mjs +0 -29042
  52. package/dist/google-shared-W8g3Esep.mjs.map +0 -1
  53. package/dist/google-vertex--O_gyVYA.mjs +0 -402
  54. package/dist/google-vertex--O_gyVYA.mjs.map +0 -1
  55. package/dist/hash-Dbggamac.mjs +0 -19
  56. package/dist/hash-Dbggamac.mjs.map +0 -1
  57. package/dist/headers-CPzZhJQn.mjs +0 -17
  58. package/dist/headers-CPzZhJQn.mjs.map +0 -1
  59. package/dist/images-models-DJtHo9Rp.mjs +0 -1068
  60. package/dist/images-models-DJtHo9Rp.mjs.map +0 -1
  61. package/dist/json-parse-C-vG4_qc.mjs +0 -384
  62. package/dist/json-parse-C-vG4_qc.mjs.map +0 -1
  63. package/dist/mcp-config-Cful6uUS.mjs +0 -1618
  64. package/dist/mcp-config-Cful6uUS.mjs.map +0 -1
  65. package/dist/mistral-conversations-LSDG9sjq.mjs +0 -42007
  66. package/dist/mistral-conversations-LSDG9sjq.mjs.map +0 -1
  67. package/dist/multipart-parser-CoM3rwav.mjs +0 -301
  68. package/dist/multipart-parser-CoM3rwav.mjs.map +0 -1
  69. package/dist/openai-codex-responses-JxII_OUX.mjs +0 -1169
  70. package/dist/openai-codex-responses-JxII_OUX.mjs.map +0 -1
  71. package/dist/openai-completions-Dp-VwLzJ.mjs +0 -947
  72. package/dist/openai-completions-Dp-VwLzJ.mjs.map +0 -1
  73. package/dist/openai-completions-lite-BrM7gJzs.mjs +0 -316
  74. package/dist/openai-completions-lite-BrM7gJzs.mjs.map +0 -1
  75. package/dist/openai-prompt-cache-BDWtZRKh.mjs +0 -11
  76. package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +0 -1
  77. package/dist/openai-responses-CWmNks8K.mjs +0 -247
  78. package/dist/openai-responses-CWmNks8K.mjs.map +0 -1
  79. package/dist/openai-responses-shared-CYgIDTf3.mjs +0 -572
  80. package/dist/openai-responses-shared-CYgIDTf3.mjs.map +0 -1
  81. package/dist/openrouter-images-DfAULV7l.mjs +0 -127
  82. package/dist/openrouter-images-DfAULV7l.mjs.map +0 -1
  83. package/dist/otel-Boafyju5.mjs +0 -24935
  84. package/dist/otel-Boafyju5.mjs.map +0 -1
  85. package/dist/pi-ai-B4hucafU.mjs.map +0 -1
  86. package/dist/pi-messages-HzGtvc5_.mjs +0 -306
  87. package/dist/pi-messages-HzGtvc5_.mjs.map +0 -1
  88. package/dist/provider-env-C9gOBFJi.mjs +0 -40
  89. package/dist/provider-env-C9gOBFJi.mjs.map +0 -1
  90. package/dist/provider-retry-Cw6YJ4cr.mjs +0 -80
  91. package/dist/provider-retry-Cw6YJ4cr.mjs.map +0 -1
  92. package/dist/runtime-k3IlCgjQ.mjs.map +0 -1
  93. package/dist/sanitize-unicode-wLA11KvZ.mjs +0 -29
  94. package/dist/sanitize-unicode-wLA11KvZ.mjs.map +0 -1
  95. package/dist/src-D0GRWCE8.mjs +0 -5031
  96. package/dist/src-D0GRWCE8.mjs.map +0 -1
  97. package/dist/transform-messages-DGq9mvhA.mjs +0 -379
  98. package/dist/transform-messages-DGq9mvhA.mjs.map +0 -1
  99. package/dist/uuid-DtFT7tOE.mjs +0 -65
  100. package/dist/uuid-DtFT7tOE.mjs.map +0 -1
package/README.md CHANGED
@@ -136,7 +136,7 @@ is aspirational.
136
136
  | Example | What you get |
137
137
  |---|---|
138
138
  | [`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) |
139
- | [`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 |
139
+ | [`examples/custom-gateways`](examples/custom-gateways/) | Add any OpenAI-compatible gateway the official DSH way (the `llm-pi-ai:` section of DSH settings) it appears in the DSH model picker, works as the main model, and every Pi plugin sees it through the bridge's registry projection; the bridge owns zero model configuration |
140
140
 
141
141
  More verified capabilities (approval guardian, cross-session memory,
142
142
  interactive OAuth, MCP config conversion, host mode) get their examples as
package/README.zh.md CHANGED
@@ -124,7 +124,7 @@ npx pi2dsh mcp-config # Pi mcpServers → DSH patc
124
124
  | 示例 | 你得到什么 |
125
125
  |---|---|
126
126
  | [`examples/vision-bridge`](examples/vision-bridge/) | 纯文本模型回答图片问题:消息里带图片路径,配置的视觉模型识图,分析结果注入对话(CLI 与 DSH Web 都能用;附探针测试图) |
127
- | [`examples/custom-models`](examples/custom-models/) | Pi 标准 `models.json` 里定义一次 provider——它成为原生 DSH llm 路由:出现在 DSH Web 模型选择器、可当主模型对话、所有 Pi 插件经同一个目录可见可调 |
127
+ | [`examples/custom-gateways`](examples/custom-gateways/) | DSH 官方方式(DSH settings `llm-pi-ai:` 段)接入任意 OpenAI 兼容网关——出现在 DSH 模型选择器、可当主模型、所有 Pi 插件经桥的 registry 投影看到同一路由;桥自身零模型配置 |
128
128
 
129
129
  更多已验证能力(审批 guardian、跨会话记忆、交互式 OAuth、MCP 配置转换、host 模式)的示例,将按同一标准逐个重新端到端验证后补齐。
130
130
 
@@ -0,0 +1,628 @@
1
+
2
+ import { R as __exportAll } from "./pi-ai-C6Xag6xt.mjs";
3
+ import { c as PI_AI_PACKAGES, f as ruleForApi, g as ruleForUiContextProperty, h as ruleForHostImport, l as PI_CODING_AGENT_PACKAGES, m as ruleForEvent, p as ruleForContextProperty, u as PI_TUI_PACKAGES } from "./mcp-config-Dlou-ZA-.mjs";
4
+ import { builtinModules } from "node:module";
5
+ import { lstat, readFile, readdir, stat } from "node:fs/promises";
6
+ import { basename, dirname, extname, join, relative, resolve } from "node:path";
7
+ import ts from "typescript";
8
+ //#region src/module-graph.ts
9
+ const SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
10
+ ".ts",
11
+ ".tsx",
12
+ ".mts",
13
+ ".cts",
14
+ ".js",
15
+ ".jsx",
16
+ ".mjs",
17
+ ".cjs"
18
+ ]);
19
+ const MODULE_EXTENSIONS = [
20
+ ".ts",
21
+ ".tsx",
22
+ ".mts",
23
+ ".cts",
24
+ ".js",
25
+ ".jsx",
26
+ ".mjs",
27
+ ".cjs",
28
+ ".json"
29
+ ];
30
+ function sourceKind(path) {
31
+ if (path.endsWith(".js") || path.endsWith(".mjs") || path.endsWith(".cjs")) return ts.ScriptKind.JS;
32
+ if (path.endsWith(".jsx")) return ts.ScriptKind.JSX;
33
+ if (path.endsWith(".tsx")) return ts.ScriptKind.TSX;
34
+ return ts.ScriptKind.TS;
35
+ }
36
+ function literalModule(node) {
37
+ return node !== void 0 && (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) ? node.text : void 0;
38
+ }
39
+ function isImportMetaUrl(node) {
40
+ return node !== void 0 && ts.isPropertyAccessExpression(node) && node.name.text === "url" && ts.isMetaProperty(node.expression) && node.expression.keywordToken === ts.SyntaxKind.ImportKeyword;
41
+ }
42
+ function localReferences(path, text) {
43
+ const source = ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, sourceKind(path));
44
+ const values = /* @__PURE__ */ new Map();
45
+ const createRequireNames = /* @__PURE__ */ new Set(["createRequire"]);
46
+ const requireNames = /* @__PURE__ */ new Set(["require"]);
47
+ const add = (kind, specifier, lazy) => {
48
+ if (!specifier.startsWith(".") && !specifier.startsWith("#")) return;
49
+ const key = `${kind}:${specifier}`;
50
+ const existing = values.get(key);
51
+ if (existing === void 0) values.set(key, {
52
+ kind,
53
+ specifier,
54
+ lazy
55
+ });
56
+ else if (existing.lazy && !lazy) existing.lazy = false;
57
+ };
58
+ function collectRequireAliases(node) {
59
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && (node.moduleSpecifier.text === "node:module" || node.moduleSpecifier.text === "module") && node.importClause?.namedBindings !== void 0 && ts.isNamedImports(node.importClause.namedBindings)) {
60
+ for (const element of node.importClause.namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "createRequire") createRequireNames.add(element.name.text);
61
+ } else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer !== void 0 && ts.isCallExpression(node.initializer) && ts.isIdentifier(node.initializer.expression) && createRequireNames.has(node.initializer.expression.text)) requireNames.add(node.name.text);
62
+ ts.forEachChild(node, collectRequireAliases);
63
+ }
64
+ collectRequireAliases(source);
65
+ function visit(node) {
66
+ if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier !== void 0 && ts.isStringLiteral(node.moduleSpecifier)) add("module", node.moduleSpecifier.text, false);
67
+ else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference) && ts.isStringLiteral(node.moduleReference.expression)) add("module", node.moduleReference.expression.text, false);
68
+ else if (ts.isCallExpression(node) && node.arguments.length > 0 && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && requireNames.has(node.expression.text))) {
69
+ const specifier = literalModule(node.arguments[0]);
70
+ if (specifier !== void 0) add("module", specifier, insideFunctionBody(node));
71
+ } else if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "URL" && isImportMetaUrl(node.arguments?.[1])) {
72
+ const specifier = literalModule(node.arguments?.[0]);
73
+ if (specifier !== void 0) add("asset", specifier, false);
74
+ }
75
+ ts.forEachChild(node, visit);
76
+ }
77
+ visit(source);
78
+ return [...values.values()];
79
+ }
80
+ function externalPackage(specifier) {
81
+ if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("#") || specifier.startsWith("node:") || specifier.startsWith("bun:") || builtinModules.includes(specifier)) return void 0;
82
+ const parts = specifier.split("/");
83
+ return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
84
+ }
85
+ function insideTry(node) {
86
+ let current = node.parent;
87
+ while (current !== void 0) {
88
+ if (ts.isTryStatement(current)) return true;
89
+ if (ts.isFunctionLike(current)) return false;
90
+ current = current.parent;
91
+ }
92
+ return false;
93
+ }
94
+ function insideFunctionBody(node) {
95
+ let current = node.parent;
96
+ while (current !== void 0) {
97
+ if (ts.isFunctionLike(current)) return true;
98
+ current = current.parent;
99
+ }
100
+ return false;
101
+ }
102
+ function runtimeExternalPackages(path, text) {
103
+ const source = ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, sourceKind(path));
104
+ const packages = /* @__PURE__ */ new Map();
105
+ const createRequireNames = /* @__PURE__ */ new Set(["createRequire"]);
106
+ const requireNames = /* @__PURE__ */ new Set(["require"]);
107
+ const add = (specifier, lazy) => {
108
+ const name = externalPackage(specifier);
109
+ if (name === void 0 || name.length === 0) return;
110
+ const existing = packages.get(name);
111
+ if (existing === void 0) packages.set(name, {
112
+ name,
113
+ lazy
114
+ });
115
+ else if (existing.lazy && !lazy) existing.lazy = false;
116
+ };
117
+ function collectRequireAliases(node) {
118
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && (node.moduleSpecifier.text === "node:module" || node.moduleSpecifier.text === "module") && node.importClause?.namedBindings !== void 0 && ts.isNamedImports(node.importClause.namedBindings)) {
119
+ for (const element of node.importClause.namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "createRequire") createRequireNames.add(element.name.text);
120
+ } else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer !== void 0 && ts.isCallExpression(node.initializer) && ts.isIdentifier(node.initializer.expression) && createRequireNames.has(node.initializer.expression.text)) requireNames.add(node.name.text);
121
+ ts.forEachChild(node, collectRequireAliases);
122
+ }
123
+ collectRequireAliases(source);
124
+ function visit(node) {
125
+ if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
126
+ const clause = node.importClause;
127
+ const named = clause?.namedBindings;
128
+ const namedImportsAreTypeOnly = named !== void 0 && ts.isNamedImports(named) && named.elements.length > 0 && named.elements.every((element) => element.isTypeOnly);
129
+ if (clause === void 0 || !clause.isTypeOnly && (clause.name !== void 0 || !namedImportsAreTypeOnly)) add(node.moduleSpecifier.text, false);
130
+ } else if (ts.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier !== void 0 && ts.isStringLiteral(node.moduleSpecifier)) add(node.moduleSpecifier.text, false);
131
+ else if (ts.isImportEqualsDeclaration(node) && !node.isTypeOnly && ts.isExternalModuleReference(node.moduleReference) && ts.isStringLiteral(node.moduleReference.expression)) add(node.moduleReference.expression.text, false);
132
+ else if (ts.isCallExpression(node) && node.arguments.length > 0 && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && requireNames.has(node.expression.text))) {
133
+ if (!insideTry(node)) {
134
+ const specifier = literalModule(node.arguments[0]);
135
+ if (specifier !== void 0) add(specifier, insideFunctionBody(node));
136
+ }
137
+ }
138
+ ts.forEachChild(node, visit);
139
+ }
140
+ visit(source);
141
+ return [...packages.values()];
142
+ }
143
+ function inside(rootDir, path) {
144
+ const pathRelative = relative(rootDir, path);
145
+ return pathRelative === "" || pathRelative !== ".." && !pathRelative.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
146
+ }
147
+ function sourceAlternates(base) {
148
+ const extension = extname(base);
149
+ const stem = extension.length > 0 ? base.slice(0, -extension.length) : base;
150
+ if (extension === ".js") return [`${stem}.ts`, `${stem}.tsx`];
151
+ if (extension === ".mjs") return [`${stem}.mts`, `${stem}.ts`];
152
+ if (extension === ".cjs") return [`${stem}.cts`, `${stem}.ts`];
153
+ if (extension === ".jsx") return [`${stem}.tsx`, `${stem}.ts`];
154
+ return [];
155
+ }
156
+ async function isFile(path) {
157
+ try {
158
+ return (await stat(path)).isFile();
159
+ } catch (error) {
160
+ if (error.code === "ENOENT") return false;
161
+ throw error;
162
+ }
163
+ }
164
+ function subpathImportTarget(rootDir, specifier, importsMap) {
165
+ const conditionValue = (value) => {
166
+ if (typeof value === "string") return value;
167
+ if (typeof value !== "object" || value === null) return void 0;
168
+ const record = value;
169
+ for (const condition of [
170
+ "import",
171
+ "node",
172
+ "default"
173
+ ]) {
174
+ const candidate = conditionValue(record[condition]);
175
+ if (candidate !== void 0) return candidate;
176
+ }
177
+ };
178
+ const direct = conditionValue(importsMap[specifier]);
179
+ if (direct !== void 0) return resolve(rootDir, direct);
180
+ for (const [pattern, value] of Object.entries(importsMap)) {
181
+ const star = pattern.indexOf("*");
182
+ if (star === -1) continue;
183
+ const prefix = pattern.slice(0, star);
184
+ const suffix = pattern.slice(star + 1);
185
+ if (!specifier.startsWith(prefix) || !specifier.endsWith(suffix)) continue;
186
+ const wildcard = specifier.slice(prefix.length, specifier.length - suffix.length);
187
+ const target = conditionValue(value);
188
+ if (target !== void 0) return resolve(rootDir, target.replace("*", wildcard));
189
+ }
190
+ }
191
+ async function packageImportsMap(rootDir) {
192
+ try {
193
+ const parsed = JSON.parse(await readFile(join(rootDir, "package.json"), "utf8"));
194
+ return typeof parsed.imports === "object" && parsed.imports !== null ? parsed.imports : {};
195
+ } catch {
196
+ return {};
197
+ }
198
+ }
199
+ async function resolveModule(fromFile, specifier, rootDir, importsMap) {
200
+ if (specifier.startsWith("#")) {
201
+ const target = subpathImportTarget(rootDir, specifier, importsMap);
202
+ if (target === void 0) throw new Error(`cannot resolve subpath import ${JSON.stringify(specifier)} through the package "imports" map`);
203
+ return resolveModule(fromFile, relative(dirname(fromFile), target).startsWith(".") ? relative(dirname(fromFile), target) : `./${relative(dirname(fromFile), target)}`, rootDir, importsMap);
204
+ }
205
+ const base = resolve(dirname(fromFile), specifier);
206
+ const candidates = [
207
+ base,
208
+ ...sourceAlternates(base),
209
+ ...extname(base) === "" ? MODULE_EXTENSIONS.map((extension) => `${base}${extension}`) : [],
210
+ ...MODULE_EXTENSIONS.map((extension) => join(base, `index${extension}`))
211
+ ];
212
+ for (const candidate of [...new Set(candidates)]) {
213
+ if (!inside(rootDir, candidate)) throw new Error(`extension import escapes the Pi package: ${specifier} from ${fromFile}`);
214
+ if (await isFile(candidate)) return candidate;
215
+ }
216
+ throw new Error(`cannot resolve local extension import ${JSON.stringify(specifier)} from ${fromFile}`);
217
+ }
218
+ async function expandAsset(path, rootDir) {
219
+ if (!inside(rootDir, path)) throw new Error(`extension asset escapes the Pi package: ${path}`);
220
+ let info;
221
+ try {
222
+ info = await lstat(path);
223
+ } catch (error) {
224
+ if (error.code !== "ENOENT") throw error;
225
+ for (const alternate of sourceAlternates(path)) if (await isFile(alternate)) return [alternate];
226
+ throw error;
227
+ }
228
+ if (info.isSymbolicLink()) throw new Error(`refusing to copy symbolic link from Pi package: ${path}`);
229
+ if (info.isFile()) return [path];
230
+ if (!info.isDirectory()) return [];
231
+ const output = [];
232
+ for (const entry of await readdir(path)) output.push(...await expandAsset(join(path, entry), rootDir));
233
+ return output;
234
+ }
235
+ async function collectLocalClosure(rootDir, entries) {
236
+ const importsMap = await packageImportsMap(rootDir);
237
+ const graph = /* @__PURE__ */ new Map();
238
+ const issues = [];
239
+ const queue = entries.map((path) => resolve(path));
240
+ while (queue.length > 0) {
241
+ const source = queue.shift();
242
+ if (graph.has(source)) continue;
243
+ if (!inside(rootDir, source)) throw new Error(`extension source escapes the Pi package: ${source}`);
244
+ const info = await lstat(source);
245
+ if (info.isSymbolicLink()) throw new Error(`refusing to copy symbolic link from Pi package: ${source}`);
246
+ if (!info.isFile()) throw new Error(`extension closure contains a non-file path: ${source}`);
247
+ const edges = [];
248
+ graph.set(source, edges);
249
+ if (!SCRIPT_EXTENSIONS.has(extname(source))) continue;
250
+ const text = await readFile(source, "utf8");
251
+ for (const reference of localReferences(source, text)) {
252
+ const lazy = reference.lazy || reference.kind === "asset";
253
+ try {
254
+ const targets = reference.kind === "module" ? [await resolveModule(source, reference.specifier, rootDir, importsMap)] : await expandAsset(resolve(dirname(source), reference.specifier), rootDir);
255
+ edges.push({
256
+ lazy,
257
+ targets
258
+ });
259
+ queue.push(...targets);
260
+ } catch (error) {
261
+ issues.push({
262
+ file: source,
263
+ kind: reference.kind,
264
+ specifier: reference.specifier,
265
+ detail: error instanceof Error ? error.message : String(error),
266
+ lazy
267
+ });
268
+ }
269
+ }
270
+ }
271
+ const loadTimeFiles = /* @__PURE__ */ new Set();
272
+ const loadQueue = entries.map((path) => resolve(path)).filter((path) => graph.has(path));
273
+ while (loadQueue.length > 0) {
274
+ const source = loadQueue.shift();
275
+ if (loadTimeFiles.has(source)) continue;
276
+ loadTimeFiles.add(source);
277
+ for (const edge of graph.get(source) ?? []) {
278
+ if (edge.lazy) continue;
279
+ for (const target of edge.targets) if (!loadTimeFiles.has(target)) loadQueue.push(target);
280
+ }
281
+ }
282
+ for (const issue of issues) if (!loadTimeFiles.has(issue.file)) issue.lazy = true;
283
+ return {
284
+ files: [...graph.keys()].sort(),
285
+ loadTimeFiles,
286
+ issues
287
+ };
288
+ }
289
+ //#endregion
290
+ //#region src/analyzer.ts
291
+ var analyzer_exports = /* @__PURE__ */ __exportAll({ analyzePackage: () => analyzePackage });
292
+ function literalText(node) {
293
+ return node !== void 0 && (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) ? node.text : void 0;
294
+ }
295
+ function hasModifier(node, kind) {
296
+ return ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === kind) === true;
297
+ }
298
+ function parameterIdentifier(node) {
299
+ const parameter = node.parameters[0];
300
+ return parameter !== void 0 && ts.isIdentifier(parameter.name) ? parameter.name.text : void 0;
301
+ }
302
+ function extensionApiReceivers(source) {
303
+ const receivers = /* @__PURE__ */ new Set();
304
+ const functions = /* @__PURE__ */ new Map();
305
+ function index(node) {
306
+ if (ts.isFunctionDeclaration(node) && node.name !== void 0) functions.set(node.name.text, node);
307
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer !== void 0 && (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) functions.set(node.name.text, node.initializer);
308
+ if (ts.isParameter(node) && node.type !== void 0 && /(?:^|\.)ExtensionAPI\b/u.test(node.type.getText(source)) && ts.isIdentifier(node.name)) receivers.add(node.name.text);
309
+ if (ts.isParameter(node) && ts.isIdentifier(node.name) && /^(?:pi|extensionApi)$/iu.test(node.name.text)) receivers.add(node.name.text);
310
+ ts.forEachChild(node, index);
311
+ }
312
+ index(source);
313
+ for (const statement of source.statements) {
314
+ if (ts.isFunctionDeclaration(statement) && hasModifier(statement, ts.SyntaxKind.ExportKeyword) && hasModifier(statement, ts.SyntaxKind.DefaultKeyword)) {
315
+ const name = parameterIdentifier(statement);
316
+ if (name !== void 0) receivers.add(name);
317
+ }
318
+ if (ts.isExportAssignment(statement)) {
319
+ const expression = statement.expression;
320
+ if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
321
+ const name = parameterIdentifier(expression);
322
+ if (name !== void 0) receivers.add(name);
323
+ } else if (ts.isIdentifier(expression)) {
324
+ const candidate = functions.get(expression.text);
325
+ if (candidate !== void 0) {
326
+ const name = parameterIdentifier(candidate);
327
+ if (name !== void 0) receivers.add(name);
328
+ }
329
+ }
330
+ }
331
+ if (ts.isExportDeclaration(statement) && statement.moduleSpecifier === void 0 && statement.exportClause !== void 0 && ts.isNamedExports(statement.exportClause)) for (const element of statement.exportClause.elements) {
332
+ if (element.name.text !== "default" || element.propertyName === void 0 || !ts.isIdentifier(element.propertyName)) continue;
333
+ const candidate = functions.get(element.propertyName.text);
334
+ if (candidate !== void 0) {
335
+ const name = parameterIdentifier(candidate);
336
+ if (name !== void 0) receivers.add(name);
337
+ }
338
+ }
339
+ }
340
+ return receivers;
341
+ }
342
+ function extensionApiProperties(source, receivers) {
343
+ const properties = /* @__PURE__ */ new Set();
344
+ function visit(node) {
345
+ if ((ts.isPropertyDeclaration(node) || ts.isParameter(node)) && ts.isIdentifier(node.name)) {
346
+ if (node.type !== void 0 && /(?:^|\.)(?:Pi)?ExtensionAPI\b/u.test(node.type.getText(source)) || /^(?:pi|extensionApi)$/iu.test(node.name.text)) properties.add(node.name.text);
347
+ } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && node.left.expression.kind === ts.SyntaxKind.ThisKeyword && ts.isIdentifier(node.right) && receivers.has(node.right.text)) properties.add(node.left.name.text);
348
+ ts.forEachChild(node, visit);
349
+ }
350
+ visit(source);
351
+ return properties;
352
+ }
353
+ function enclosingFunctionName(node) {
354
+ const parent = node.parent;
355
+ if (ts.isMethodDeclaration(parent) && parent.name !== void 0) return parent.name.getText();
356
+ if ((ts.isArrowFunction(parent) || ts.isFunctionExpression(parent)) && ts.isPropertyAssignment(parent.parent)) return parent.parent.name.getText();
357
+ }
358
+ function extensionContextReceivers(source) {
359
+ const receivers = /* @__PURE__ */ new Set();
360
+ function visit(node) {
361
+ if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
362
+ const typedContext = node.type !== void 0 && /(?:^|\.)(?:Extension|ExtensionCommand|ToolExecution)Context\b/u.test(node.type.getText(source));
363
+ const conventionalHandlerContext = /^(?:ctx|context)$/iu.test(node.name.text) && /^(?:execute|handler)$/u.test(enclosingFunctionName(node) ?? "");
364
+ if (typedContext || conventionalHandlerContext) receivers.add(node.name.text);
365
+ }
366
+ ts.forEachChild(node, visit);
367
+ }
368
+ visit(source);
369
+ return receivers;
370
+ }
371
+ const PI_SHIMMED_PACKAGES = /* @__PURE__ */ new Set([
372
+ ...PI_CODING_AGENT_PACKAGES,
373
+ ...PI_TUI_PACKAGES,
374
+ ...PI_AI_PACKAGES
375
+ ]);
376
+ const PI_HOST_PACKAGES = /* @__PURE__ */ new Set([
377
+ ...PI_SHIMMED_PACKAGES,
378
+ "typebox",
379
+ "@sinclair/typebox"
380
+ ]);
381
+ function dependencyNames(packageJson) {
382
+ const names = /* @__PURE__ */ new Set();
383
+ for (const field of [
384
+ "dependencies",
385
+ "optionalDependencies",
386
+ "peerDependencies"
387
+ ]) {
388
+ const value = packageJson[field];
389
+ if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
390
+ for (const [name, specifier] of Object.entries(value)) if (typeof specifier === "string") names.add(name);
391
+ }
392
+ return names;
393
+ }
394
+ function pushFinding(findings, rootDir, file, source, node, capability, level, detail) {
395
+ const position = source.getLineAndCharacterOfPosition(node.getStart(source));
396
+ findings.push({
397
+ capability,
398
+ level,
399
+ file: relative(rootDir, file).replaceAll("\\", "/"),
400
+ line: position.line + 1,
401
+ detail
402
+ });
403
+ }
404
+ async function analyzeExtension(rootDir, file) {
405
+ const text = await readFile(file, "utf8");
406
+ const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, sourceKind(file));
407
+ const findings = [];
408
+ const receivers = extensionApiReceivers(source);
409
+ const apiProperties = extensionApiProperties(source, receivers);
410
+ const contextReceivers = extensionContextReceivers(source);
411
+ const methodAliases = /* @__PURE__ */ new Map();
412
+ const eventBusAliases = /* @__PURE__ */ new Set();
413
+ const uiAliases = /* @__PURE__ */ new Set();
414
+ function reportHostImport(packageName, importedName, node) {
415
+ const matched = ruleForHostImport(packageName, importedName);
416
+ if (matched === void 0) {
417
+ pushFinding(findings, rootDir, file, source, node, `host-import(${packageName}:${importedName})`, "unsupported", `The pi2dsh host shim does not export ${JSON.stringify(importedName)} from ${JSON.stringify(packageName)}.`);
418
+ return;
419
+ }
420
+ pushFinding(findings, rootDir, file, source, node, `host-import(${packageName}:${importedName})`, matched.level, matched.detail);
421
+ }
422
+ for (const statement of source.statements) if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier) && PI_SHIMMED_PACKAGES.has(statement.moduleSpecifier.text)) {
423
+ const packageName = statement.moduleSpecifier.text;
424
+ const clause = statement.importClause;
425
+ if (clause === void 0) {
426
+ reportHostImport(packageName, "<side-effect>", statement);
427
+ continue;
428
+ }
429
+ if (clause.isTypeOnly) continue;
430
+ if (clause.name !== void 0) reportHostImport(packageName, "default", clause.name);
431
+ if (clause.namedBindings !== void 0 && ts.isNamespaceImport(clause.namedBindings)) reportHostImport(packageName, "*", clause.namedBindings);
432
+ else if (clause.namedBindings !== void 0) {
433
+ for (const element of clause.namedBindings.elements) if (!element.isTypeOnly) reportHostImport(packageName, element.propertyName?.text ?? element.name.text, element);
434
+ }
435
+ } else if (ts.isExportDeclaration(statement) && !statement.isTypeOnly && statement.moduleSpecifier !== void 0 && ts.isStringLiteral(statement.moduleSpecifier) && PI_HOST_PACKAGES.has(statement.moduleSpecifier.text)) {
436
+ const packageName = statement.moduleSpecifier.text;
437
+ if (statement.exportClause === void 0 || ts.isNamespaceExport(statement.exportClause)) reportHostImport(packageName, "*", statement);
438
+ else for (const element of statement.exportClause.elements) if (!element.isTypeOnly) reportHostImport(packageName, element.propertyName?.text ?? element.name.text, element);
439
+ } else if (ts.isImportEqualsDeclaration(statement) && !statement.isTypeOnly && ts.isExternalModuleReference(statement.moduleReference) && ts.isStringLiteral(statement.moduleReference.expression) && PI_HOST_PACKAGES.has(statement.moduleReference.expression.text)) reportHostImport(statement.moduleReference.expression.text, "*", statement);
440
+ const declarations = [];
441
+ const isApiReceiver = (node) => ts.isIdentifier(node) && receivers.has(node.text) || ts.isPropertyAccessExpression(node) && node.expression.kind === ts.SyntaxKind.ThisKeyword && apiProperties.has(node.name.text);
442
+ function collectDeclarations(node) {
443
+ if (ts.isVariableDeclaration(node)) declarations.push(node);
444
+ ts.forEachChild(node, collectDeclarations);
445
+ }
446
+ collectDeclarations(source);
447
+ for (let pass = 0; pass < declarations.length + 1; pass += 1) {
448
+ let changed = false;
449
+ for (const declaration of declarations) {
450
+ const initializer = declaration.initializer;
451
+ if (initializer === void 0) continue;
452
+ if (ts.isIdentifier(declaration.name) && isApiReceiver(initializer)) {
453
+ if (!receivers.has(declaration.name.text)) {
454
+ receivers.add(declaration.name.text);
455
+ changed = true;
456
+ }
457
+ }
458
+ if (ts.isIdentifier(declaration.name) && ts.isIdentifier(initializer) && contextReceivers.has(initializer.text)) {
459
+ if (!contextReceivers.has(declaration.name.text)) {
460
+ contextReceivers.add(declaration.name.text);
461
+ changed = true;
462
+ }
463
+ }
464
+ if (ts.isIdentifier(declaration.name) && ts.isPropertyAccessExpression(initializer) && initializer.name.text === "ui" && ts.isIdentifier(initializer.expression) && contextReceivers.has(initializer.expression.text) && !uiAliases.has(declaration.name.text)) {
465
+ uiAliases.add(declaration.name.text);
466
+ changed = true;
467
+ }
468
+ if (ts.isIdentifier(declaration.name) && ts.isPropertyAccessExpression(initializer) && isApiReceiver(initializer.expression)) {
469
+ if (initializer.name.text === "events") {
470
+ if (!eventBusAliases.has(declaration.name.text)) {
471
+ eventBusAliases.add(declaration.name.text);
472
+ changed = true;
473
+ }
474
+ } else if (!methodAliases.has(declaration.name.text)) {
475
+ methodAliases.set(declaration.name.text, initializer.name.text);
476
+ changed = true;
477
+ }
478
+ }
479
+ if (ts.isObjectBindingPattern(declaration.name) && isApiReceiver(initializer)) for (const element of declaration.name.elements) {
480
+ if (!ts.isIdentifier(element.name)) continue;
481
+ const method = element.propertyName !== void 0 && ts.isIdentifier(element.propertyName) ? element.propertyName.text : element.name.text;
482
+ if (method === "events") {
483
+ if (!eventBusAliases.has(element.name.text)) {
484
+ eventBusAliases.add(element.name.text);
485
+ changed = true;
486
+ }
487
+ } else if (!methodAliases.has(element.name.text)) {
488
+ methodAliases.set(element.name.text, method);
489
+ changed = true;
490
+ }
491
+ }
492
+ }
493
+ if (!changed) break;
494
+ }
495
+ function reportMethod(method, args, node) {
496
+ if (method === "on") {
497
+ const event = literalText(args[0]);
498
+ if (event === void 0) pushFinding(findings, rootDir, file, source, node, "on(<dynamic>)", "unsupported", "Dynamic event names cannot be audited or mapped safely.");
499
+ else {
500
+ const rule = ruleForEvent(event);
501
+ pushFinding(findings, rootDir, file, source, node, `on(${event})`, rule.level, rule.detail);
502
+ }
503
+ return;
504
+ }
505
+ const rule = ruleForApi(method);
506
+ if (rule === void 0) {
507
+ pushFinding(findings, rootDir, file, source, node, method, "unsupported", `Unknown ExtensionAPI method ${JSON.stringify(method)} cannot be audited or mapped safely.`);
508
+ return;
509
+ }
510
+ pushFinding(findings, rootDir, file, source, node, method, rule.level, rule.detail);
511
+ }
512
+ function reportEventBus(method, node) {
513
+ const rule = ruleForApi("events");
514
+ if ((method === "on" || method === "emit") && rule !== void 0) pushFinding(findings, rootDir, file, source, node, `events.${method}`, rule.level, rule.detail);
515
+ else pushFinding(findings, rootDir, file, source, node, `events.${method}`, "unsupported", `Unknown Pi event-bus method ${JSON.stringify(method)} cannot be mapped safely.`);
516
+ }
517
+ function reportContext(property, node) {
518
+ const matched = ruleForContextProperty(property);
519
+ if (matched === void 0) pushFinding(findings, rootDir, file, source, node, `ctx.${property}`, "unsupported", `Unknown Pi extension-context property ${JSON.stringify(property)} cannot be audited or mapped safely.`);
520
+ else pushFinding(findings, rootDir, file, source, node, `ctx.${property}`, matched.level, matched.detail);
521
+ }
522
+ function reportUiContext(property, node) {
523
+ const matched = ruleForUiContextProperty(property);
524
+ if (matched === void 0) pushFinding(findings, rootDir, file, source, node, `ctx.ui.${property}`, "unsupported", `Unknown Pi UI-context property ${JSON.stringify(property)} cannot be audited or mapped safely.`);
525
+ else pushFinding(findings, rootDir, file, source, node, `ctx.ui.${property}`, matched.level, matched.detail);
526
+ }
527
+ function visit(node) {
528
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
529
+ const method = methodAliases.get(node.expression.text);
530
+ if (method !== void 0) reportMethod(method, node.arguments, node);
531
+ } else if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
532
+ const target = node.expression.expression;
533
+ if (isApiReceiver(target)) reportMethod(node.expression.name.text, node.arguments, node);
534
+ else if (ts.isIdentifier(target) && eventBusAliases.has(target.text)) reportEventBus(node.expression.name.text, node);
535
+ else if (ts.isPropertyAccessExpression(target) && target.name.text === "events" && isApiReceiver(target.expression)) reportEventBus(node.expression.name.text, node);
536
+ } else if (ts.isCallExpression(node) && ts.isElementAccessExpression(node.expression) && isApiReceiver(node.expression.expression)) {
537
+ const method = literalText(node.expression.argumentExpression);
538
+ if (method === void 0) pushFinding(findings, rootDir, file, source, node, "<dynamic-api-method>", "unsupported", "Dynamic ExtensionAPI method access cannot be audited or mapped safely.");
539
+ else reportMethod(method, node.arguments, node);
540
+ }
541
+ if (ts.isPropertyAccessExpression(node)) {
542
+ const target = node.expression;
543
+ if (ts.isPropertyAccessExpression(target) && target.name.text === "ui" && ts.isIdentifier(target.expression) && contextReceivers.has(target.expression.text)) reportUiContext(node.name.text, node);
544
+ else if (ts.isIdentifier(target) && uiAliases.has(target.text)) reportUiContext(node.name.text, node);
545
+ else if (ts.isIdentifier(target) && contextReceivers.has(target.text) && node.name.text !== "ui") reportContext(node.name.text, node);
546
+ } else if (ts.isElementAccessExpression(node) && ts.isIdentifier(node.expression) && contextReceivers.has(node.expression.text)) {
547
+ const property = literalText(node.argumentExpression);
548
+ if (property === void 0) pushFinding(findings, rootDir, file, source, node, "ctx.<dynamic>", "unsupported", "Dynamic Pi extension-context access cannot be audited or mapped safely.");
549
+ else if (property !== "ui") reportContext(property, node);
550
+ }
551
+ ts.forEachChild(node, visit);
552
+ }
553
+ visit(source);
554
+ return findings;
555
+ }
556
+ async function analyzePackage(pkg) {
557
+ const extensionClosure = await collectLocalClosure(pkg.rootDir, pkg.resources.extensions);
558
+ const findings = (await Promise.all(extensionClosure.files.filter((file) => SCRIPT_EXTENSIONS.has(extname(file))).map((file) => analyzeExtension(pkg.rootDir, file)))).flat();
559
+ if (pkg.resources.extensions.length > 0 && findings.length === 0) findings.push({
560
+ capability: "static-audit",
561
+ level: "unsupported",
562
+ file: pkg.resources.extensions.map((file) => relative(pkg.rootDir, file).replaceAll("\\", "/")).join(", "),
563
+ line: 1,
564
+ detail: "No ExtensionAPI use was statically proven across the local module closure; conversion fails closed instead of claiming compatibility."
565
+ });
566
+ for (const issue of extensionClosure.issues) {
567
+ const lazyIssue = issue.lazy || issue.kind === "asset";
568
+ findings.push({
569
+ capability: `${issue.kind}(${issue.specifier})`,
570
+ level: lazyIssue ? "partial" : "fatal",
571
+ file: relative(pkg.rootDir, issue.file).replaceAll("\\", "/"),
572
+ line: 1,
573
+ detail: lazyIssue ? `Unresolved reference on a lazy path: ${issue.detail}. Extension load is unaffected; if the feature that evaluates it runs, it fails the same way under Pi (published file layout is preserved).` : `The local extension closure is incomplete: ${issue.detail}`
574
+ });
575
+ }
576
+ const declaredDependencies = dependencyNames(pkg.packageJson);
577
+ for (const file of extensionClosure.files.filter((candidate) => SCRIPT_EXTENSIONS.has(extname(candidate)))) {
578
+ const text = await readFile(file, "utf8");
579
+ const lazyFile = !extensionClosure.loadTimeFiles.has(file);
580
+ for (const use of runtimeExternalPackages(file, text)) {
581
+ if (PI_HOST_PACKAGES.has(use.name) || declaredDependencies.has(use.name)) continue;
582
+ const lazyUse = use.lazy || lazyFile;
583
+ findings.push({
584
+ capability: lazyUse ? `optional-lazy-dependency(${use.name})` : `undeclared-runtime-dependency(${use.name})`,
585
+ level: lazyUse ? "partial" : "fatal",
586
+ file: relative(pkg.rootDir, file).replaceAll("\\", "/"),
587
+ line: 1,
588
+ detail: lazyUse ? `The extension imports ${JSON.stringify(use.name)} only on a lazily-evaluated path without declaring it; the feature that needs it asks for the module at call time, exactly as under Pi (install ${use.name} to use that feature).` : `The extension imports ${JSON.stringify(use.name)} at load time, but the Pi package does not declare it as a dependency.`
589
+ });
590
+ }
591
+ }
592
+ const resourceFinding = (file, capability, level, detail) => ({
593
+ capability,
594
+ level,
595
+ file: relative(pkg.rootDir, file).replaceAll("\\", "/"),
596
+ line: 1,
597
+ detail
598
+ });
599
+ for (const file of pkg.resources.skills.filter((path) => basename(path) === "SKILL.md" || path.endsWith(".md"))) findings.push(resourceFinding(file, "skill", "full", "Copied as a DSH filesystem skill with its resource directory intact."));
600
+ for (const file of pkg.resources.prompts) findings.push(resourceFinding(file, "prompt", "full", "Registered as a DSH slash command with Pi-compatible argument expansion."));
601
+ for (const file of pkg.resources.themes) findings.push(resourceFinding(file, "theme", "unsupported", "Pi terminal themes have no effect in DSH Web or headless surfaces."));
602
+ findings.sort((left, right) => left.file.localeCompare(right.file) || left.line - right.line || left.capability.localeCompare(right.capability));
603
+ const summary = {
604
+ full: 0,
605
+ partial: 0,
606
+ unsupported: 0,
607
+ fatal: 0
608
+ };
609
+ for (const finding of findings) summary[finding.level] += 1;
610
+ const verdict = summary.fatal > 0 ? "blocked" : summary.partial > 0 || summary.unsupported > 0 ? "review" : "ready";
611
+ return {
612
+ schemaVersion: 1,
613
+ package: pkg.identity,
614
+ verdict,
615
+ summary,
616
+ resources: {
617
+ extensions: pkg.resources.extensions.map((file) => relative(pkg.rootDir, file).replaceAll("\\", "/")),
618
+ skills: pkg.resources.skills.map((file) => relative(pkg.rootDir, file).replaceAll("\\", "/")),
619
+ prompts: pkg.resources.prompts.map((file) => relative(pkg.rootDir, file).replaceAll("\\", "/")),
620
+ themes: pkg.resources.themes.map((file) => relative(pkg.rootDir, file).replaceAll("\\", "/"))
621
+ },
622
+ findings
623
+ };
624
+ }
625
+ //#endregion
626
+ export { runtimeExternalPackages as a, collectLocalClosure as i, analyzer_exports as n, SCRIPT_EXTENSIONS as r, analyzePackage as t };
627
+
628
+ //# sourceMappingURL=analyzer-CKTsWVzn.mjs.map