pi2dsh 0.13.2 → 0.13.3
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.
- package/README.md +22 -19
- package/README.zh.md +18 -15
- package/dist/{analyzer-CJFwQlSG.mjs → analyzer-DBtUYKI1.mjs} +2 -2
- package/dist/{analyzer-CJFwQlSG.mjs.map → analyzer-DBtUYKI1.mjs.map} +1 -1
- package/dist/anthropic-messages-CaYTgvLF.mjs +6436 -0
- package/dist/anthropic-messages-CaYTgvLF.mjs.map +1 -0
- package/dist/azure-openai-responses-HKWkzl2m.mjs +208 -0
- package/dist/azure-openai-responses-HKWkzl2m.mjs.map +1 -0
- package/dist/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/compat/pi-ai.d.mts +3 -2636
- package/dist/compat/pi-ai.mjs +3 -2
- package/dist/compat/pi-coding-agent.d.mts +2 -2
- package/dist/compat/pi-coding-agent.mjs +2 -2
- package/dist/{mcp-config-_idn-pzI.mjs → compatibility-Bz6ZXA7F.mjs} +8 -185
- package/dist/compatibility-Bz6ZXA7F.mjs.map +1 -0
- package/dist/completionchunk-Dhk56lZl.mjs +5212 -0
- package/dist/completionchunk-Dhk56lZl.mjs.map +1 -0
- package/dist/{credentials-oauth-Txs6oew8.mjs → credentials-oauth-CAohSLcB.mjs} +3 -3
- package/dist/{credentials-oauth-Txs6oew8.mjs.map → credentials-oauth-CAohSLcB.mjs.map} +1 -1
- package/dist/credentials-oauth.mjs +1 -1
- package/dist/deferred-tools-BD4g5QUx.mjs +32 -0
- package/dist/deferred-tools-BD4g5QUx.mjs.map +1 -0
- package/dist/diagnostics-BqYkodgB.mjs +35 -0
- package/dist/diagnostics-BqYkodgB.mjs.map +1 -0
- package/dist/dist-QBBA-dL_.mjs +1246 -0
- package/dist/dist-QBBA-dL_.mjs.map +1 -0
- package/dist/error-body-DKA3lknR.mjs +104 -0
- package/dist/error-body-DKA3lknR.mjs.map +1 -0
- package/dist/event-stream-QxN1yvIF.mjs +64 -0
- package/dist/event-stream-QxN1yvIF.mjs.map +1 -0
- package/dist/from-BCscBQ9P.mjs +3856 -0
- package/dist/from-BCscBQ9P.mjs.map +1 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs +25 -0
- package/dist/github-copilot-headers-CZo2QHrt.mjs.map +1 -0
- package/dist/google-generative-ai-2gCFYp-t.mjs +356 -0
- package/dist/google-generative-ai-2gCFYp-t.mjs.map +1 -0
- package/dist/google-shared-75IdVyrx.mjs +29041 -0
- package/dist/google-shared-75IdVyrx.mjs.map +1 -0
- package/dist/google-vertex-Bhyo4z2i.mjs +400 -0
- package/dist/google-vertex-Bhyo4z2i.mjs.map +1 -0
- package/dist/hash-Dbggamac.mjs +19 -0
- package/dist/hash-Dbggamac.mjs.map +1 -0
- package/dist/headers-CPzZhJQn.mjs +17 -0
- package/dist/headers-CPzZhJQn.mjs.map +1 -0
- package/dist/host.d.mts +12 -2
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +43 -5
- package/dist/host.mjs.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +40 -16
- package/dist/index.mjs.map +1 -1
- package/dist/json-parse-CZ0U0sj_.mjs +384 -0
- package/dist/json-parse-CZ0U0sj_.mjs.map +1 -0
- package/dist/mcp-config-jmzbgdHa.mjs +181 -0
- package/dist/mcp-config-jmzbgdHa.mjs.map +1 -0
- package/dist/mistral-conversations-DJyeTo8C.mjs +36921 -0
- package/dist/mistral-conversations-DJyeTo8C.mjs.map +1 -0
- package/dist/multipart-parser-SRcGkVuX.mjs +301 -0
- package/dist/multipart-parser-SRcGkVuX.mjs.map +1 -0
- package/dist/{pi-ai-D7PqVeWs.mjs → openai-DkzRh5_G.mjs} +78 -5063
- package/dist/openai-DkzRh5_G.mjs.map +1 -0
- package/dist/openai-codex-responses-DedxQjNG.mjs +1220 -0
- package/dist/openai-codex-responses-DedxQjNG.mjs.map +1 -0
- package/dist/openai-completions-DrjrWRdX.mjs +945 -0
- package/dist/openai-completions-DrjrWRdX.mjs.map +1 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs +11 -0
- package/dist/openai-prompt-cache-BDWtZRKh.mjs.map +1 -0
- package/dist/openai-responses-BRdGpBX6.mjs +251 -0
- package/dist/openai-responses-BRdGpBX6.mjs.map +1 -0
- package/dist/openai-responses-shared-BmnSvdKL.mjs +570 -0
- package/dist/openai-responses-shared-BmnSvdKL.mjs.map +1 -0
- package/dist/otel-CBhmS-NR.mjs +24935 -0
- package/dist/otel-CBhmS-NR.mjs.map +1 -0
- package/dist/pi-ai-CfokFhIL.d.mts +2673 -0
- package/dist/pi-ai-CfokFhIL.d.mts.map +1 -0
- package/dist/pi-ai-Dh7HUxbt.mjs +3239 -0
- package/dist/pi-ai-Dh7HUxbt.mjs.map +1 -0
- package/dist/{pi-coding-agent-B0PT23gE.d.mts → pi-coding-agent-69yY0ke-.d.mts} +4 -2
- package/dist/{pi-coding-agent-B0PT23gE.d.mts.map → pi-coding-agent-69yY0ke-.d.mts.map} +1 -1
- package/dist/{pi-coding-agent-BVZu0dHG.mjs → pi-coding-agent-Cvez0jkF.mjs} +0 -0
- package/dist/{pi-coding-agent-BVZu0dHG.mjs.map → pi-coding-agent-Cvez0jkF.mjs.map} +1 -1
- package/dist/pi-messages-D61G2tgs.mjs +307 -0
- package/dist/pi-messages-D61G2tgs.mjs.map +1 -0
- package/dist/provider-env-C72pF4vP.mjs +40 -0
- package/dist/provider-env-C72pF4vP.mjs.map +1 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs +80 -0
- package/dist/provider-retry-Cw6YJ4cr.mjs.map +1 -0
- package/dist/rolldown-runtime-CTfmNlz1.mjs +44 -0
- package/dist/{runtime-DEjs_Qlf.mjs → runtime-Dd2KhoX-.mjs} +659 -125
- package/dist/runtime-Dd2KhoX-.mjs.map +1 -0
- package/dist/runtime.d.mts +135 -26
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/simple-options-B_GO8FDE.mjs +456 -0
- package/dist/simple-options-B_GO8FDE.mjs.map +1 -0
- package/dist/src-DlTagfW5.mjs +1186 -0
- package/dist/src-DlTagfW5.mjs.map +1 -0
- package/dist/{types-7IWJPPvS.d.mts → types-B9VBF8le.d.mts} +2 -9
- package/dist/{types-7IWJPPvS.d.mts.map → types-B9VBF8le.d.mts.map} +1 -1
- package/package.json +2 -2
- package/dist/compat/pi-ai.d.mts.map +0 -1
- package/dist/mcp-config-_idn-pzI.mjs.map +0 -1
- package/dist/pi-ai-D7PqVeWs.mjs.map +0 -1
- package/dist/runtime-DEjs_Qlf.mjs.map +0 -1
package/dist/host.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.mjs","names":[],"sources":["../src/host.ts"],"sourcesContent":["// PiHostOnDSH: one DSH plugin that hosts unmodified Pi packages.\n//\n// Instead of converting each package into a vendored bundle, the host bundle\n// declares Pi packages as ordinary npm dependencies; DSH's plugin manager\n// (pnpm) installs them, and at load time this module resolves each installed\n// package, discovers its Pi entry points, and mounts it through the same\n// package-agnostic runtime as converted bundles. One host, any package —\n// there is deliberately no per-package branching here.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { readdir, readFile, stat, writeFile, mkdir, cp } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join, relative } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { applyPiPackage, registerVisionCompanions } from './runtime.js'\nimport { resolvePiPackage } from './source.js'\nimport type { GeneratedRuntimeManifest, ResolvedPiPackage } from './types.js'\n\ntype UnknownRecord = Record<string, unknown>\n\nexport interface PiHostPackageSpec {\n /** npm package name as installed in the host bundle's node_modules. */\n name: string\n /** Optional per-package config forwarded to the runtime. */\n config?: UnknownRecord\n}\n\nexport interface PiHostConfig {\n packages: Array<string | PiHostPackageSpec>\n /** Image-admission companions: default automatic; `false` off; explicit map narrows. */\n visionCompanions?: false | Record<string, readonly string[]>\n}\n\nfunction parseFrontmatter(text: string): { attributes: Record<string, string>; body: string } {\n const normalized = text.replace(/\\r\\n?/gu, '\\n')\n if (!normalized.startsWith('---')) return { attributes: {}, body: normalized }\n const endIndex = normalized.indexOf('\\n---', 3)\n if (endIndex === -1) return { attributes: {}, body: normalized }\n const attributes: Record<string, string> = {}\n for (const line of normalized.slice(4, endIndex).split('\\n')) {\n const separator = line.indexOf(':')\n if (separator === -1) continue\n const key = line.slice(0, separator).trim()\n let value = line.slice(separator + 1).trim()\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1)\n }\n if (key.length > 0) attributes[key] = value\n }\n return { attributes, body: normalized.slice(endIndex + 4).trim() }\n}\n\n/** Build a runtime manifest in place over an installed Pi package directory. */\nexport async function manifestForInstalled(pkg: ResolvedPiPackage): Promise<GeneratedRuntimeManifest> {\n const relativeTo = (file: string): string => relative(pkg.rootDir, file).replaceAll('\\\\', '/')\n\n const skillDirs = new Set<string>()\n for (const file of pkg.resources.skills) {\n // <dir>/<name>/SKILL.md contributes <dir>; a flat <dir>/<name>.md contributes <dir>.\n skillDirs.add(relativeTo(basename(file) === 'SKILL.md' ? dirname(dirname(file)) : dirname(file)))\n }\n\n const prompts: GeneratedRuntimeManifest['prompts'] = []\n const promptNames = new Set<string>()\n for (const source of pkg.resources.prompts) {\n const name = basename(source, '.md').toLowerCase().replace(/[^a-z0-9_-]+/gu, '-')\n if (promptNames.has(name)) throw new Error(`prompt command name collision in ${pkg.identity.name}: ${name}`)\n promptNames.add(name)\n const { attributes, body } = parseFrontmatter(await readFile(source, 'utf8'))\n const firstLine = body.split(/\\r?\\n/u).map(line => line.trim()).find(Boolean)\n prompts.push({\n name,\n description: attributes.description ?? firstLine ?? `Run migrated Pi prompt ${name}`,\n ...(attributes['argument-hint'] !== undefined ? { argumentHint: attributes['argument-hint'] } : {}),\n path: relativeTo(source),\n })\n }\n\n return {\n schemaVersion: 1,\n package: pkg.identity,\n extensions: pkg.resources.extensions.map(relativeTo),\n skillDirs: [...skillDirs].sort(),\n prompts,\n }\n}\n\nfunction normalizeSpecs(config: PiHostConfig): PiHostPackageSpec[] {\n const packages = Array.isArray(config?.packages) ? config.packages : []\n return packages.map(spec => (typeof spec === 'string' ? { name: spec } : spec))\n .filter(spec => typeof spec?.name === 'string' && spec.name.length > 0)\n}\n\nfunction resolveInstalledDir(anchor: string, packageName: string): string {\n const require = createRequire(anchor)\n try {\n return dirname(require.resolve(`${packageName}/package.json`))\n } catch {\n // Modern strict `exports` maps refuse the package.json subpath, and pure\n // ESM packages (no \"require\" condition) refuse CJS entry resolution too.\n // Locate the installed directory on the filesystem instead: probe every\n // node_modules candidate on the resolution path — no exports involved.\n for (const candidate of require.resolve.paths(packageName) ?? []) {\n const dir = join(candidate, packageName)\n if (existsSync(join(dir, 'package.json'))) return dir\n }\n throw new Error(`cannot locate the installed package directory for ${JSON.stringify(packageName)} near ${JSON.stringify(anchor)}`)\n }\n}\n\n/**\n * Mount every configured Pi package from the host bundle's own node_modules.\n * Packages that fail to mount report their error and do not take down the\n * host or their siblings — matching Pi's own per-extension error isolation.\n */\nexport async function applyPiHost(ctx: Context, config: PiHostConfig, anchor?: string): Promise<void> {\n const anchorPath = anchor ?? fileURLToPath(import.meta.url)\n registerVisionCompanions(ctx, config.visionCompanions)\n const errors: Array<{ name: string; error: string }> = []\n for (const spec of normalizeSpecs(config)) {\n try {\n const dir = resolveInstalledDir(anchorPath, spec.name)\n const pkg = await resolvePiPackage(dir)\n try {\n const manifest = await manifestForInstalled(pkg)\n await applyPiPackage(ctx, {\n rootUrl: pathToFileURL(`${pkg.rootDir}/`),\n manifest,\n ...(spec.config === undefined ? {} : { config: spec.config }),\n })\n } finally {\n await pkg.dispose()\n }\n } catch (error) {\n errors.push({ name: spec.name, error: error instanceof Error ? error.message : String(error) })\n }\n }\n for (const failure of errors) {\n // Console AND logger, the same rule the engine states for its own mount\n // line: a profile's logger level must never be able to hide which packages\n // did not mount. It could, and it did — a package failed to mount and the\n // only symptom was its absence from a list nobody was diffing.\n const log = (ctx as unknown as { logger?: { warn?(message: string): void } }).logger\n const message = `[pi2dsh host] failed to mount ${failure.name}: ${failure.error}`\n log?.warn?.(message)\n console.warn(message)\n }\n if (errors.length > 0 && errors.length === normalizeSpecs(config).length) {\n throw new Error(`pi2dsh host mounted no packages; first failure: ${errors[0]!.name}: ${errors[0]!.error}`)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"host.mjs","names":[],"sources":["../src/host.ts"],"sourcesContent":["// PiHostOnDSH: one DSH plugin that hosts unmodified Pi packages.\n//\n// Pi packages are ordinary npm dependencies of the profile; DSH's plugin\n// manager (pnpm) installs them, and at load time this module resolves each\n// installed package, discovers its Pi entry points, and mounts it through\n// the same package-agnostic runtime. One host, any package — there is\n// deliberately no per-package branching here.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { readFile, stat, writeFile, mkdir, cp } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join, relative } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { applyPiPackage, registerVisionCompanions } from './runtime.js'\nimport { resolvePiPackage } from './source.js'\nimport type { GeneratedRuntimeManifest, ResolvedPiPackage } from './types.js'\n\ntype UnknownRecord = Record<string, unknown>\n\nexport interface PiHostPackageSpec {\n /** npm package name as installed in the host bundle's node_modules. */\n name: string\n /** Optional per-package config forwarded to the runtime. */\n config?: UnknownRecord\n}\n\nexport interface PiHostConfig {\n packages: Array<string | PiHostPackageSpec>\n /** Image-admission companions: default automatic; `false` off; explicit map narrows. */\n visionCompanions?: false | Record<string, readonly string[]>\n}\n\nexport interface PreparedPiHostPackage {\n readonly name: string\n readonly rootUrl: URL\n readonly manifest: GeneratedRuntimeManifest\n readonly config?: UnknownRecord\n}\n\nfunction parseFrontmatter(text: string): { attributes: Record<string, string>; body: string } {\n const normalized = text.replace(/\\r\\n?/gu, '\\n')\n if (!normalized.startsWith('---')) return { attributes: {}, body: normalized }\n const endIndex = normalized.indexOf('\\n---', 3)\n if (endIndex === -1) return { attributes: {}, body: normalized }\n const attributes: Record<string, string> = {}\n for (const line of normalized.slice(4, endIndex).split('\\n')) {\n const separator = line.indexOf(':')\n if (separator === -1) continue\n const key = line.slice(0, separator).trim()\n let value = line.slice(separator + 1).trim()\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1)\n }\n if (key.length > 0) attributes[key] = value\n }\n return { attributes, body: normalized.slice(endIndex + 4).trim() }\n}\n\n/** Build a runtime manifest in place over an installed Pi package directory. */\nexport async function manifestForInstalled(pkg: ResolvedPiPackage): Promise<GeneratedRuntimeManifest> {\n const relativeTo = (file: string): string => relative(pkg.rootDir, file).replaceAll('\\\\', '/')\n\n const skillDirs = new Set<string>()\n for (const file of pkg.resources.skills) {\n // <dir>/<name>/SKILL.md contributes <dir>; a flat <dir>/<name>.md contributes <dir>.\n skillDirs.add(relativeTo(basename(file) === 'SKILL.md' ? dirname(dirname(file)) : dirname(file)))\n }\n\n const prompts: GeneratedRuntimeManifest['prompts'] = []\n const promptNames = new Set<string>()\n for (const source of pkg.resources.prompts) {\n const name = basename(source, '.md').toLowerCase().replace(/[^a-z0-9_-]+/gu, '-')\n if (promptNames.has(name)) throw new Error(`prompt command name collision in ${pkg.identity.name}: ${name}`)\n promptNames.add(name)\n const { attributes, body } = parseFrontmatter(await readFile(source, 'utf8'))\n const firstLine = body.split(/\\r?\\n/u).map(line => line.trim()).find(Boolean)\n prompts.push({\n name,\n description: attributes.description ?? firstLine ?? `Run migrated Pi prompt ${name}`,\n ...(attributes['argument-hint'] !== undefined ? { argumentHint: attributes['argument-hint'] } : {}),\n path: relativeTo(source),\n })\n }\n\n return {\n schemaVersion: 1,\n package: pkg.identity,\n extensions: pkg.resources.extensions.map(relativeTo),\n skillDirs: [...skillDirs].sort(),\n prompts,\n }\n}\n\nfunction normalizeSpecs(config: PiHostConfig): PiHostPackageSpec[] {\n const packages = Array.isArray(config?.packages) ? config.packages : []\n return packages.map(spec => (typeof spec === 'string' ? { name: spec } : spec))\n .filter(spec => typeof spec?.name === 'string' && spec.name.length > 0)\n}\n\nfunction resolveInstalledDir(anchor: string, packageName: string): string {\n const require = createRequire(anchor)\n try {\n return dirname(require.resolve(`${packageName}/package.json`))\n } catch {\n // Modern strict `exports` maps refuse the package.json subpath, and pure\n // ESM packages (no \"require\" condition) refuse CJS entry resolution too.\n // Locate the installed directory on the filesystem instead: probe every\n // node_modules candidate on the resolution path — no exports involved.\n for (const candidate of require.resolve.paths(packageName) ?? []) {\n const dir = join(candidate, packageName)\n if (existsSync(join(dir, 'package.json'))) return dir\n }\n throw new Error(`cannot locate the installed package directory for ${JSON.stringify(packageName)} near ${JSON.stringify(anchor)}`)\n }\n}\n\n/**\n * Mount every configured Pi package from the host bundle's own node_modules.\n * Packages that fail to mount report their error and do not take down the\n * host or their siblings — matching Pi's own per-extension error isolation.\n */\nexport async function applyPiHost(ctx: Context, config: PiHostConfig, anchor?: string): Promise<void> {\n registerVisionCompanions(ctx, config.visionCompanions)\n const prepared = await preparePiHost(config, anchor)\n await applyPreparedPiHost(ctx, prepared)\n}\n\n/** Resolve installed Pi packages and build immutable manifests without mounting their runtimes. */\nexport async function preparePiHost(config: PiHostConfig, anchor?: string): Promise<PreparedPiHostPackage[]> {\n const anchorPath = anchor ?? fileURLToPath(import.meta.url)\n const errors: Array<{ name: string; error: string }> = []\n const prepared: PreparedPiHostPackage[] = []\n for (const spec of normalizeSpecs(config)) {\n try {\n const dir = resolveInstalledDir(anchorPath, spec.name)\n const pkg = await resolvePiPackage(dir)\n try {\n const manifest = await manifestForInstalled(pkg)\n prepared.push({\n name: spec.name,\n rootUrl: pathToFileURL(`${pkg.rootDir}/`),\n manifest,\n ...(spec.config === undefined ? {} : { config: spec.config }),\n })\n } finally {\n await pkg.dispose()\n }\n } catch (error) {\n errors.push({ name: spec.name, error: error instanceof Error ? error.message : String(error) })\n }\n }\n for (const failure of errors) {\n // Console AND logger, the same rule the engine states for its own mount\n // line: a profile's logger level must never be able to hide which packages\n // did not mount. It could, and it did — a package failed to mount and the\n // only symptom was its absence from a list nobody was diffing.\n const message = `[pi2dsh host] failed to mount ${failure.name}: ${failure.error}`\n console.warn(message)\n }\n if (errors.length > 0 && errors.length === normalizeSpecs(config).length) {\n throw new Error(`pi2dsh host mounted no packages; first failure: ${errors[0]!.name}: ${errors[0]!.error}`)\n }\n return prepared\n}\n\n/** Mount prepared Pi package runtimes into one exact DSH context. */\nexport async function applyPreparedPiHost(\n ctx: Context,\n prepared: readonly PreparedPiHostPackage[],\n ownerAgent?: UnknownRecord,\n): Promise<void> {\n const errors: Array<{ name: string; error: string }> = []\n for (const pkg of prepared) {\n try {\n // One real Cordis activation per Pi package, owned by this Agent scope.\n // Besides giving teardown the correct owner, dsh-TUI's contribution\n // services bind registration and later use to this activation identity;\n // calling applyPiPackage() naked from the setup event has no live plugin\n // caller and cannot register or open a scene correctly.\n await ctx.plugin(Object.assign(\n async (packageCtx: Context) => {\n await applyPiPackage(packageCtx, {\n rootUrl: pkg.rootUrl,\n manifest: pkg.manifest,\n // The engine/host registers companion routes once on the host\n // before mounting prepared packages. Suppress applyPiPackage's\n // standalone default here so one package cannot undo an explicit\n // host-level `visionCompanions: false` or duplicate the catalog.\n config: { ...(pkg.config ?? {}), visionCompanions: false },\n ...(ownerAgent === undefined ? {} : { ownerAgent }),\n })\n },\n { inject: ['tools', 'systemPrompt', 'commands'] },\n ))\n } catch (error) {\n errors.push({ name: pkg.name, error: error instanceof Error ? error.message : String(error) })\n }\n }\n for (const failure of errors) {\n const log = (ctx as unknown as { logger?: { warn?(message: string): void } }).logger\n const message = `[pi2dsh host] failed to mount ${failure.name}: ${failure.error}`\n log?.warn?.(message)\n console.warn(message)\n }\n if (errors.length > 0 && errors.length === prepared.length) {\n throw new Error(`pi2dsh host mounted no packages; first failure: ${errors[0]!.name}: ${errors[0]!.error}`)\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { a as
|
|
3
|
-
import { applyPiHost, manifestForInstalled } from "./host.mjs";
|
|
2
|
+
import { a as PackageIdentity, i as GeneratedRuntimeManifest, n as CompatibilityLevel, o as ResolvedPiPackage, r as CompatibilityReport, s as ResourceInventory, t as CompatibilityFinding } from "./types-B9VBF8le.mjs";
|
|
3
|
+
import { applyPiHost, applyPreparedPiHost, manifestForInstalled, preparePiHost } from "./host.mjs";
|
|
4
4
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
//#region src/engine.d.ts
|
|
6
6
|
interface EngineConfig {
|
|
@@ -33,6 +33,8 @@ declare function discoverProfilePiPackages(profileRoot: string, options?: {
|
|
|
33
33
|
exclude?: string[];
|
|
34
34
|
warn?: (message: string) => void;
|
|
35
35
|
}): Promise<DiscoveredPackage[]>;
|
|
36
|
+
/** Discover a surface-owned, pre-publication Agent setup event from direct dependencies. */
|
|
37
|
+
declare function discoverAgentSetupEvent(profileRoot: string): Promise<string | undefined>;
|
|
36
38
|
/** Cordis plugin surface: `dsh plugin add pi2dsh` mounts this. */
|
|
37
39
|
declare const name = "pi2dsh";
|
|
38
40
|
declare const inject: string[];
|
|
@@ -112,5 +114,5 @@ declare function resolvePiPackage(source: string, cwd?: string): Promise<Resolve
|
|
|
112
114
|
*/
|
|
113
115
|
declare function analyzePackage(pkg: ResolvedPiPackage): Promise<CompatibilityReport>;
|
|
114
116
|
//#endregion
|
|
115
|
-
export { API_RULES, CONTEXT_RULES, type CompatibilityFinding, type CompatibilityLevel, type CompatibilityReport, EVENT_RULES, type EngineConfig, type
|
|
117
|
+
export { API_RULES, CONTEXT_RULES, type CompatibilityFinding, type CompatibilityLevel, type CompatibilityReport, EVENT_RULES, type EngineConfig, 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, applyPreparedPiHost, collectPiMcpServers, convertPiMcpConfig, discoverAgentSetupEvent, discoverProfilePiPackages, findProfileRoot, inject, manifestForInstalled, name, preparePiHost, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
|
|
116
118
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/engine.ts","../src/compatibility.ts","../src/mcp-config.ts","../src/source.ts","../src/index.ts"],"mappings":";;;;;UA6BiB;;EAEf;;EAEA;;;;;;;;EAQA,2BAA2B;;;iBAIb,gBAAgB;UAUtB;EACR;EACA;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/engine.ts","../src/compatibility.ts","../src/mcp-config.ts","../src/source.ts","../src/index.ts"],"mappings":";;;;;UA6BiB;;EAEf;;EAEA;;;;;;;;EAQA,2BAA2B;;;iBAIb,gBAAgB;UAUtB;EACR;EACA;;;;;;;;iBAyBoB,0BACpB,qBACA;EAAW;EAAoB,QAAQ;IACtC,QAAQ;;iBA2CW,wBAAwB,sBAAsB;;cAsBvD;cACA;iBAES,MAAM,KAAK,SAAS,SAAQ,eAAoB;;;UCvJ5D;EACR,OAAO;EACP;;EAEA;;;;;;;;;UAUQ,oBAAoB;EAC5B;;cAQW;cAKA;cAKA;cAWA,mBAAmB,SAAS,eAAe,SAAS,eAAe;cAoNnE,eAAe,SAAS,eAAe;cA4BvC,kBAAkB,SAAS,eAAe;cA+B1C,WAAW,SAAS,eAAe;cA6InC,aAAa,SAAS,eAAe;iBAgHlC,WAAW,iBAAiB;iBAI5B,aAAa,gBAAgB;iBAO7B,kBAAkB,qBAAqB,uBAAuB;iBAS9D,uBAAuB,mBAAmB;iBAI1C,yBAAyB,mBAAmB;;;KCrkBvD,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;;;;;;;;iBChH/D,eAAe,KAAK,oBAAoB,QAAQ"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import { r as registerVisionCompanions } from "./runtime-Dd2KhoX-.mjs";
|
|
3
3
|
import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
|
|
4
|
-
import { applyPiHost, manifestForInstalled } from "./host.mjs";
|
|
5
|
-
import { a as
|
|
4
|
+
import { applyPiHost, applyPreparedPiHost, manifestForInstalled, preparePiHost } from "./host.mjs";
|
|
5
|
+
import { a as PI_AI_PACKAGES, c as UI_CONTEXT_RULES, d as ruleForEvent, f as ruleForHostImport, i as HOST_IMPORT_RULES, l as ruleForApi, n as CONTEXT_RULES, o as PI_CODING_AGENT_PACKAGES, p as ruleForUiContextProperty, r as EVENT_RULES, s as PI_TUI_PACKAGES, t as API_RULES, u as ruleForContextProperty } from "./compatibility-Bz6ZXA7F.mjs";
|
|
6
|
+
import { n as convertPiMcpConfig, r as renderMcpPatch, t as collectPiMcpServers } from "./mcp-config-jmzbgdHa.mjs";
|
|
6
7
|
import { readFile } from "node:fs/promises";
|
|
7
8
|
import { existsSync } from "node:fs";
|
|
8
9
|
import { dirname, join } from "node:path";
|
|
@@ -18,6 +19,9 @@ function findProfileRoot(start) {
|
|
|
18
19
|
dir = parent;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
async function readProfileManifest(profileRoot) {
|
|
23
|
+
return JSON.parse(await readFile(join(profileRoot, "package.json"), "utf8"));
|
|
24
|
+
}
|
|
21
25
|
function resolveDependencyDir(profileRoot, name) {
|
|
22
26
|
const dir = join(profileRoot, "node_modules", name);
|
|
23
27
|
return existsSync(join(dir, "package.json")) ? dir : void 0;
|
|
@@ -31,8 +35,7 @@ function resolveDependencyDir(profileRoot, name) {
|
|
|
31
35
|
async function discoverProfilePiPackages(profileRoot, options = {}) {
|
|
32
36
|
const warn = options.warn ?? (() => {});
|
|
33
37
|
const excluded = new Set(options.exclude ?? []);
|
|
34
|
-
const
|
|
35
|
-
const manifest = JSON.parse(manifestText);
|
|
38
|
+
const manifest = await readProfileManifest(profileRoot);
|
|
36
39
|
const discovered = [];
|
|
37
40
|
for (const name of Object.keys(manifest.dependencies ?? {})) {
|
|
38
41
|
if (name === "pi2dsh" || excluded.has(name)) continue;
|
|
@@ -70,6 +73,20 @@ async function discoverProfilePiPackages(profileRoot, options = {}) {
|
|
|
70
73
|
}
|
|
71
74
|
return discovered;
|
|
72
75
|
}
|
|
76
|
+
/** Discover a surface-owned, pre-publication Agent setup event from direct dependencies. */
|
|
77
|
+
async function discoverAgentSetupEvent(profileRoot) {
|
|
78
|
+
const manifest = await readProfileManifest(profileRoot);
|
|
79
|
+
const bundles = new Set(manifest.dsh?.profile?.bundles ?? []);
|
|
80
|
+
for (const name of Object.keys(manifest.dependencies ?? {})) {
|
|
81
|
+
if (!bundles.has(name)) continue;
|
|
82
|
+
const dir = resolveDependencyDir(profileRoot, name);
|
|
83
|
+
if (dir === void 0) continue;
|
|
84
|
+
try {
|
|
85
|
+
const event = JSON.parse(await readFile(join(dir, "package.json"), "utf8")).dshTui?.agentSetupEvent;
|
|
86
|
+
if (typeof event === "string" && event.length > 0) return event;
|
|
87
|
+
} catch {}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
73
90
|
/** Cordis plugin surface: `dsh plugin add pi2dsh` mounts this. */
|
|
74
91
|
const name = "pi2dsh";
|
|
75
92
|
const inject = [
|
|
@@ -95,8 +112,11 @@ async function apply(ctx, config = {}) {
|
|
|
95
112
|
...Array.isArray(config.exclude) ? { exclude: config.exclude } : {},
|
|
96
113
|
warn
|
|
97
114
|
});
|
|
115
|
+
registerVisionCompanions(ctx, config.visionCompanions);
|
|
116
|
+
let prepared;
|
|
98
117
|
if (packages.length === 0) {
|
|
99
|
-
|
|
118
|
+
prepared = [{
|
|
119
|
+
name: "pi2dsh-builtins",
|
|
100
120
|
rootUrl: new URL(".", import.meta.url),
|
|
101
121
|
manifest: {
|
|
102
122
|
schemaVersion: 1,
|
|
@@ -108,17 +128,21 @@ async function apply(ctx, config = {}) {
|
|
|
108
128
|
extensions: [],
|
|
109
129
|
skillDirs: [],
|
|
110
130
|
prompts: []
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
});
|
|
131
|
+
}
|
|
132
|
+
}];
|
|
114
133
|
info("[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>");
|
|
134
|
+
} else {
|
|
135
|
+
info(`[pi2dsh engine] preparing ${packages.length} Pi package(s): ${packages.map((pkg) => pkg.name).join(", ")}`);
|
|
136
|
+
prepared = await preparePiHost({ packages: packages.map((pkg) => ({ name: pkg.name })) }, join(profileRoot, "package.json"));
|
|
137
|
+
}
|
|
138
|
+
const agentSetupEvent = await discoverAgentSetupEvent(profileRoot);
|
|
139
|
+
if (agentSetupEvent === void 0) {
|
|
140
|
+
await applyPreparedPiHost(ctx, prepared);
|
|
115
141
|
return;
|
|
116
142
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
...config.visionCompanions === void 0 ? {} : { visionCompanions: config.visionCompanions }
|
|
121
|
-
}, join(profileRoot, "package.json"));
|
|
143
|
+
ctx.on(agentSetupEvent, async ({ agent, agentCtx }) => {
|
|
144
|
+
await applyPreparedPiHost(agentCtx, prepared, agent);
|
|
145
|
+
});
|
|
122
146
|
}
|
|
123
147
|
//#endregion
|
|
124
148
|
//#region src/index.ts
|
|
@@ -128,10 +152,10 @@ async function apply(ctx, config = {}) {
|
|
|
128
152
|
* @returns the compatibility report.
|
|
129
153
|
*/
|
|
130
154
|
async function analyzePackage(pkg) {
|
|
131
|
-
const { analyzePackage: run } = await import("./analyzer-
|
|
155
|
+
const { analyzePackage: run } = await import("./analyzer-DBtUYKI1.mjs");
|
|
132
156
|
return run(pkg);
|
|
133
157
|
}
|
|
134
158
|
//#endregion
|
|
135
|
-
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, inject, manifestForInstalled, name, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
|
|
159
|
+
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, applyPreparedPiHost, collectPiMcpServers, convertPiMcpConfig, discoverAgentSetupEvent, discoverProfilePiPackages, findProfileRoot, inject, manifestForInstalled, name, preparePiHost, renderMcpPatch, resolvePiPackage, ruleForApi, ruleForContextProperty, ruleForEvent, ruleForHostImport, ruleForUiContextProperty };
|
|
136
160
|
|
|
137
161
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/engine.ts","../src/index.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 { applyPiPackage } from './runtime.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 * Image-admission companion routes. Default: AUTOMATIC — every text-only\n * llm route gets a \\`<route>-vision\\` companion that admits pasted images\n * (a mounted vision extension analyzes them; without one the image is\n * materialized to a file any image-capable tool can read). \\`false\\`\n * turns companions off; an explicit \\`{ <route>: [modelIds] }\\` narrows.\n */\n visionCompanions?: false | Record<string, readonly 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 // Same emission as the runtime's logger helper: the cordis logger AND the\n // console — profile logger levels must never hide what the engine mounted.\n const log = (ctx as unknown as { logger?: { info?(m: string): void, warn?(m: string): void } }).logger\n const warn = (message: string): void => { log?.warn?.(message); console.warn(message) }\n const info = (message: string): void => { log?.info?.(message); console.log(message) }\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 // The host itself owns Pi's built-in provider directory and `/login`.\n // Mount an empty internal package so those host-level capabilities exist\n // even before the user installs their first community Pi package. Calling\n // registerVisionCompanions alone here left a fresh engine unable to run\n // `/login openai-codex`: DSH treated the unknown slash line as a model\n // prompt and failed on the unrelated default provider credential.\n await applyPiPackage(ctx, {\n rootUrl: new URL('.', import.meta.url),\n manifest: {\n schemaVersion: 1,\n package: { name: 'pi2dsh-builtins', version: '0.0.0', source: 'engine' },\n extensions: [],\n skillDirs: [],\n prompts: [],\n },\n config: {\n ...(config.visionCompanions === undefined ? {} : { visionCompanions: config.visionCompanions }),\n },\n })\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 {\n packages: packages.map(pkg => ({ name: pkg.name })),\n ...(config.visionCompanions === undefined ? {} : { visionCompanions: config.visionCompanions }),\n },\n join(profileRoot, 'package.json'),\n )\n}\n","// Engine surface: `dsh plugin add pi2dsh` resolves this entry as a cordis\n// plugin (named exports, no default — a default export would make the\n// loader discard the function-plugin namespace).\nexport { apply, inject, name, discoverProfilePiPackages, findProfileRoot, type EngineConfig } from './engine.js'\n\n// The CLI-only analysis surface loads lazily: its static-analysis dependency\n// (the 23 MB typescript compiler, an optional peer) must never be pulled\n// into a profile that installs the ENGINE. The dynamic import below keeps\n// the analyzer in its own chunk, off the engine's load path.\nimport type { CompatibilityReport, ResolvedPiPackage } from './types.js'\n\n/**\n * Static compatibility analysis of one resolved Pi package (CLI `inspect`).\n * @param pkg - the resolved package.\n * @returns the compatibility report.\n */\nexport async function analyzePackage(pkg: ResolvedPiPackage): Promise<CompatibilityReport> {\n const { analyzePackage: run } = await import('./analyzer.js')\n return run(pkg)\n}\n\nexport {\n API_RULES,\n CONTEXT_RULES,\n EVENT_RULES,\n HOST_IMPORT_RULES,\n PI_AI_PACKAGES,\n PI_CODING_AGENT_PACKAGES,\n PI_TUI_PACKAGES,\n UI_CONTEXT_RULES,\n ruleForApi,\n ruleForContextProperty,\n ruleForEvent,\n ruleForHostImport,\n ruleForUiContextProperty,\n} from './compatibility.js'\nexport { applyPiHost, manifestForInstalled } from './host.js'\nexport { collectPiMcpServers, convertPiMcpConfig, renderMcpPatch } from './mcp-config.js'\nexport { resolvePiPackage } from './source.js'\nexport type * from './types.js'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/engine.ts","../src/index.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 { applyPreparedPiHost, preparePiHost, type PreparedPiHostPackage } from './host.js'\nimport { registerVisionCompanions } from './runtime.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 * Image-admission companion routes. Default: AUTOMATIC — every text-only\n * llm route gets a \\`<route>-vision\\` companion that admits pasted images\n * (a mounted vision extension analyzes them; without one the image is\n * materialized to a file any image-capable tool can read). \\`false\\`\n * turns companions off; an explicit \\`{ <route>: [modelIds] }\\` narrows.\n */\n visionCompanions?: false | Record<string, readonly 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\ninterface ProfileManifest {\n dependencies?: Record<string, string>\n dsh?: { profile?: { bundles?: string[] } }\n}\n\nasync function readProfileManifest(profileRoot: string): Promise<ProfileManifest> {\n return JSON.parse(await readFile(join(profileRoot, 'package.json'), 'utf8')) as ProfileManifest\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 manifest = await readProfileManifest(profileRoot)\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/** Discover a surface-owned, pre-publication Agent setup event from direct dependencies. */\nexport async function discoverAgentSetupEvent(profileRoot: string): Promise<string | undefined> {\n const manifest = await readProfileManifest(profileRoot)\n const bundles = new Set(manifest.dsh?.profile?.bundles ?? [])\n for (const name of Object.keys(manifest.dependencies ?? {})) {\n if (!bundles.has(name)) continue\n const dir = resolveDependencyDir(profileRoot, name)\n if (dir === undefined) continue\n try {\n const dependency = JSON.parse(await readFile(join(dir, 'package.json'), 'utf8')) as {\n dshTui?: { agentSetupEvent?: unknown }\n }\n const event = dependency.dshTui?.agentSetupEvent\n if (typeof event === 'string' && event.length > 0) return event\n } catch {\n // Package discovery already reports unreadable direct dependencies. A\n // surface capability probe only decides between scoped and legacy mount.\n }\n }\n return undefined\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 // Same emission as the runtime's logger helper: the cordis logger AND the\n // console — profile logger levels must never hide what the engine mounted.\n const log = (ctx as unknown as { logger?: { info?(m: string): void, warn?(m: string): void } }).logger\n const warn = (message: string): void => { log?.warn?.(message); console.warn(message) }\n const info = (message: string): void => { log?.info?.(message); console.log(message) }\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 registerVisionCompanions(ctx, config.visionCompanions)\n let prepared: PreparedPiHostPackage[]\n if (packages.length === 0) {\n // The host itself owns Pi's built-in provider directory and `/login`.\n // Mount an empty internal package so those host-level capabilities exist\n // even before the user installs their first community Pi package. Calling\n // registerVisionCompanions alone here left a fresh engine unable to run\n // `/login openai-codex`: DSH treated the unknown slash line as a model\n // prompt and failed on the unrelated default provider credential.\n prepared = [{\n name: 'pi2dsh-builtins',\n rootUrl: new URL('.', import.meta.url),\n manifest: {\n schemaVersion: 1,\n package: { name: 'pi2dsh-builtins', version: '0.0.0', source: 'engine' },\n extensions: [],\n skillDirs: [],\n prompts: [],\n },\n }]\n info('[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>')\n } else {\n info(`[pi2dsh engine] preparing ${packages.length} Pi package(s): ${packages.map(pkg => pkg.name).join(', ')}`)\n prepared = await preparePiHost(\n { packages: packages.map(pkg => ({ name: pkg.name })) },\n join(profileRoot, 'package.json'),\n )\n }\n\n const agentSetupEvent = await discoverAgentSetupEvent(profileRoot)\n if (agentSetupEvent === undefined) {\n // Web, headless and older TUI surfaces do not expose a pre-publication\n // contributor seam. Preserve pi2dsh's established host-scoped behavior on\n // those products; the per-Agent path below is an additive surface\n // capability, never a regression for existing profiles.\n await applyPreparedPiHost(ctx, prepared)\n return\n }\n\n // dsh-TUI runs this serial event from its existing agents.create/resume\n // setup callback, after preset composition and before DSH publishes the\n // Agent. Every Agent therefore receives fresh Pi extension instances and\n // owns their effects through its agentCtx; stock DSH Core needs no patch.\n ;(ctx as unknown as {\n on(name: string, listener: (payload: { agent: Record<string, unknown>, agentCtx: Context }) => Promise<void>): () => void\n }).on(agentSetupEvent, async ({ agent, agentCtx }) => {\n await applyPreparedPiHost(agentCtx, prepared, agent)\n })\n}\n","// Engine surface: `dsh plugin add pi2dsh` resolves this entry as a cordis\n// plugin (named exports, no default — a default export would make the\n// loader discard the function-plugin namespace).\nexport { apply, inject, name, discoverAgentSetupEvent, discoverProfilePiPackages, findProfileRoot, type EngineConfig } from './engine.js'\n\n// The CLI-only analysis surface loads lazily: its static-analysis dependency\n// (the 23 MB typescript compiler, an optional peer) must never be pulled\n// into a profile that installs the ENGINE. The dynamic import below keeps\n// the analyzer in its own chunk, off the engine's load path.\nimport type { CompatibilityReport, ResolvedPiPackage } from './types.js'\n\n/**\n * Static compatibility analysis of one resolved Pi package (CLI `inspect`).\n * @param pkg - the resolved package.\n * @returns the compatibility report.\n */\nexport async function analyzePackage(pkg: ResolvedPiPackage): Promise<CompatibilityReport> {\n const { analyzePackage: run } = await import('./analyzer.js')\n return run(pkg)\n}\n\nexport {\n API_RULES,\n CONTEXT_RULES,\n EVENT_RULES,\n HOST_IMPORT_RULES,\n PI_AI_PACKAGES,\n PI_CODING_AGENT_PACKAGES,\n PI_TUI_PACKAGES,\n UI_CONTEXT_RULES,\n ruleForApi,\n ruleForContextProperty,\n ruleForEvent,\n ruleForHostImport,\n ruleForUiContextProperty,\n} from './compatibility.js'\nexport { applyPiHost, applyPreparedPiHost, manifestForInstalled, preparePiHost } from './host.js'\nexport { collectPiMcpServers, convertPiMcpConfig, renderMcpPatch } from './mcp-config.js'\nexport { resolvePiPackage } from './source.js'\nexport type * from './types.js'\n"],"mappings":"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"}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
|
|
2
|
+
import { t as __commonJSMin } from "./rolldown-runtime-CTfmNlz1.mjs";
|
|
3
|
+
//#region node_modules/.pnpm/partial-json@0.1.7/node_modules/partial-json/dist/options.js
|
|
4
|
+
var require_options = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
5
|
+
/**
|
|
6
|
+
* Sometimes you don't allow every type to be partially parsed.
|
|
7
|
+
* For example, you may not want a partial number because it may increase its size gradually before it's complete.
|
|
8
|
+
* In this case, you can use the `Allow` object to control what types you allow to be partially parsed.
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Allow = exports.ALL = exports.COLLECTION = exports.ATOM = exports.SPECIAL = exports.INF = exports._INFINITY = exports.INFINITY = exports.NAN = exports.BOOL = exports.NULL = exports.OBJ = exports.ARR = exports.NUM = exports.STR = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* allow partial strings like `"hello \u12` to be parsed as `"hello "`
|
|
15
|
+
*/
|
|
16
|
+
exports.STR = 1;
|
|
17
|
+
/**
|
|
18
|
+
* allow partial numbers like `123.` to be parsed as `123`
|
|
19
|
+
*/
|
|
20
|
+
exports.NUM = 2;
|
|
21
|
+
/**
|
|
22
|
+
* allow partial arrays like `[1, 2,` to be parsed as `[1, 2]`
|
|
23
|
+
*/
|
|
24
|
+
exports.ARR = 4;
|
|
25
|
+
/**
|
|
26
|
+
* allow partial objects like `{"a": 1, "b":` to be parsed as `{"a": 1}`
|
|
27
|
+
*/
|
|
28
|
+
exports.OBJ = 8;
|
|
29
|
+
/**
|
|
30
|
+
* allow `nu` to be parsed as `null`
|
|
31
|
+
*/
|
|
32
|
+
exports.NULL = 16;
|
|
33
|
+
/**
|
|
34
|
+
* allow `tr` to be parsed as `true`, and `fa` to be parsed as `false`
|
|
35
|
+
*/
|
|
36
|
+
exports.BOOL = 32;
|
|
37
|
+
/**
|
|
38
|
+
* allow `Na` to be parsed as `NaN`
|
|
39
|
+
*/
|
|
40
|
+
exports.NAN = 64;
|
|
41
|
+
/**
|
|
42
|
+
* allow `Inf` to be parsed as `Infinity`
|
|
43
|
+
*/
|
|
44
|
+
exports.INFINITY = 128;
|
|
45
|
+
/**
|
|
46
|
+
* allow `-Inf` to be parsed as `-Infinity`
|
|
47
|
+
*/
|
|
48
|
+
exports._INFINITY = 256;
|
|
49
|
+
exports.INF = exports.INFINITY | exports._INFINITY;
|
|
50
|
+
exports.SPECIAL = exports.NULL | exports.BOOL | exports.INF | exports.NAN;
|
|
51
|
+
exports.ATOM = exports.STR | exports.NUM | exports.SPECIAL;
|
|
52
|
+
exports.COLLECTION = exports.ARR | exports.OBJ;
|
|
53
|
+
exports.ALL = exports.ATOM | exports.COLLECTION;
|
|
54
|
+
/**
|
|
55
|
+
* Control what types you allow to be partially parsed.
|
|
56
|
+
* The default is to allow all types to be partially parsed, which in most casees is the best option.
|
|
57
|
+
* @example
|
|
58
|
+
* If you don't want to allow partial objects, you can use the following code:
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { Allow, parse } from "partial-json";
|
|
61
|
+
* parse(`[{"a": 1, "b": 2}, {"a": 3,`, Allow.ARR); // [ { a: 1, b: 2 } ]
|
|
62
|
+
* ```
|
|
63
|
+
* Or you can use `~` to disallow a type:
|
|
64
|
+
* ```ts
|
|
65
|
+
* parse(`[{"a": 1, "b": 2}, {"a": 3,`, ~Allow.OBJ); // [ { a: 1, b: 2 } ]
|
|
66
|
+
* ```
|
|
67
|
+
* @example
|
|
68
|
+
* If you don't want to allow partial strings, you can use the following code:
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { Allow, parse } from "partial-json";
|
|
71
|
+
* parse(`["complete string", "incompl`, ~Allow.STR); // [ 'complete string' ]
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
exports.Allow = {
|
|
75
|
+
STR: exports.STR,
|
|
76
|
+
NUM: exports.NUM,
|
|
77
|
+
ARR: exports.ARR,
|
|
78
|
+
OBJ: exports.OBJ,
|
|
79
|
+
NULL: exports.NULL,
|
|
80
|
+
BOOL: exports.BOOL,
|
|
81
|
+
NAN: exports.NAN,
|
|
82
|
+
INFINITY: exports.INFINITY,
|
|
83
|
+
_INFINITY: exports._INFINITY,
|
|
84
|
+
INF: exports.INF,
|
|
85
|
+
SPECIAL: exports.SPECIAL,
|
|
86
|
+
ATOM: exports.ATOM,
|
|
87
|
+
COLLECTION: exports.COLLECTION,
|
|
88
|
+
ALL: exports.ALL
|
|
89
|
+
};
|
|
90
|
+
exports.default = exports.Allow;
|
|
91
|
+
}));
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/json-parse.js
|
|
94
|
+
var import_dist = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
95
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
96
|
+
if (k2 === void 0) k2 = k;
|
|
97
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
98
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
get: function() {
|
|
101
|
+
return m[k];
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
Object.defineProperty(o, k2, desc);
|
|
105
|
+
}) : (function(o, m, k, k2) {
|
|
106
|
+
if (k2 === void 0) k2 = k;
|
|
107
|
+
o[k2] = m[k];
|
|
108
|
+
}));
|
|
109
|
+
var __exportStar = exports && exports.__exportStar || function(m, exports$1) {
|
|
110
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
|
|
111
|
+
};
|
|
112
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
113
|
+
exports.Allow = exports.MalformedJSON = exports.PartialJSON = exports.parseJSON = exports.parse = void 0;
|
|
114
|
+
const options_1 = require_options();
|
|
115
|
+
Object.defineProperty(exports, "Allow", {
|
|
116
|
+
enumerable: true,
|
|
117
|
+
get: function() {
|
|
118
|
+
return options_1.Allow;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
__exportStar(require_options(), exports);
|
|
122
|
+
var PartialJSON = class extends Error {};
|
|
123
|
+
exports.PartialJSON = PartialJSON;
|
|
124
|
+
var MalformedJSON = class extends Error {};
|
|
125
|
+
exports.MalformedJSON = MalformedJSON;
|
|
126
|
+
/**
|
|
127
|
+
* Parse incomplete JSON
|
|
128
|
+
* @param {string} jsonString Partial JSON to be parsed
|
|
129
|
+
* @param {number} allowPartial Specify what types are allowed to be partial, see {@link Allow} for details
|
|
130
|
+
* @returns The parsed JSON
|
|
131
|
+
* @throws {PartialJSON} If the JSON is incomplete (related to the `allow` parameter)
|
|
132
|
+
* @throws {MalformedJSON} If the JSON is malformed
|
|
133
|
+
*/
|
|
134
|
+
function parseJSON(jsonString, allowPartial = options_1.Allow.ALL) {
|
|
135
|
+
if (typeof jsonString !== "string") throw new TypeError(`expecting str, got ${typeof jsonString}`);
|
|
136
|
+
if (!jsonString.trim()) throw new Error(`${jsonString} is empty`);
|
|
137
|
+
return _parseJSON(jsonString.trim(), allowPartial);
|
|
138
|
+
}
|
|
139
|
+
exports.parseJSON = parseJSON;
|
|
140
|
+
const _parseJSON = (jsonString, allow) => {
|
|
141
|
+
const length = jsonString.length;
|
|
142
|
+
let index = 0;
|
|
143
|
+
const markPartialJSON = (msg) => {
|
|
144
|
+
throw new PartialJSON(`${msg} at position ${index}`);
|
|
145
|
+
};
|
|
146
|
+
const throwMalformedError = (msg) => {
|
|
147
|
+
throw new MalformedJSON(`${msg} at position ${index}`);
|
|
148
|
+
};
|
|
149
|
+
const parseAny = () => {
|
|
150
|
+
skipBlank();
|
|
151
|
+
if (index >= length) markPartialJSON("Unexpected end of input");
|
|
152
|
+
if (jsonString[index] === "\"") return parseStr();
|
|
153
|
+
if (jsonString[index] === "{") return parseObj();
|
|
154
|
+
if (jsonString[index] === "[") return parseArr();
|
|
155
|
+
if (jsonString.substring(index, index + 4) === "null" || options_1.Allow.NULL & allow && length - index < 4 && "null".startsWith(jsonString.substring(index))) {
|
|
156
|
+
index += 4;
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
if (jsonString.substring(index, index + 4) === "true" || options_1.Allow.BOOL & allow && length - index < 4 && "true".startsWith(jsonString.substring(index))) {
|
|
160
|
+
index += 4;
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (jsonString.substring(index, index + 5) === "false" || options_1.Allow.BOOL & allow && length - index < 5 && "false".startsWith(jsonString.substring(index))) {
|
|
164
|
+
index += 5;
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
if (jsonString.substring(index, index + 8) === "Infinity" || options_1.Allow.INFINITY & allow && length - index < 8 && "Infinity".startsWith(jsonString.substring(index))) {
|
|
168
|
+
index += 8;
|
|
169
|
+
return Infinity;
|
|
170
|
+
}
|
|
171
|
+
if (jsonString.substring(index, index + 9) === "-Infinity" || options_1.Allow._INFINITY & allow && 1 < length - index && length - index < 9 && "-Infinity".startsWith(jsonString.substring(index))) {
|
|
172
|
+
index += 9;
|
|
173
|
+
return -Infinity;
|
|
174
|
+
}
|
|
175
|
+
if (jsonString.substring(index, index + 3) === "NaN" || options_1.Allow.NAN & allow && length - index < 3 && "NaN".startsWith(jsonString.substring(index))) {
|
|
176
|
+
index += 3;
|
|
177
|
+
return NaN;
|
|
178
|
+
}
|
|
179
|
+
return parseNum();
|
|
180
|
+
};
|
|
181
|
+
const parseStr = () => {
|
|
182
|
+
const start = index;
|
|
183
|
+
let escape = false;
|
|
184
|
+
index++;
|
|
185
|
+
while (index < length && (jsonString[index] !== "\"" || escape && jsonString[index - 1] === "\\")) {
|
|
186
|
+
escape = jsonString[index] === "\\" ? !escape : false;
|
|
187
|
+
index++;
|
|
188
|
+
}
|
|
189
|
+
if (jsonString.charAt(index) == "\"") try {
|
|
190
|
+
return JSON.parse(jsonString.substring(start, ++index - Number(escape)));
|
|
191
|
+
} catch (e) {
|
|
192
|
+
throwMalformedError(String(e));
|
|
193
|
+
}
|
|
194
|
+
else if (options_1.Allow.STR & allow) try {
|
|
195
|
+
return JSON.parse(jsonString.substring(start, index - Number(escape)) + "\"");
|
|
196
|
+
} catch (e) {
|
|
197
|
+
return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("\\")) + "\"");
|
|
198
|
+
}
|
|
199
|
+
markPartialJSON("Unterminated string literal");
|
|
200
|
+
};
|
|
201
|
+
const parseObj = () => {
|
|
202
|
+
index++;
|
|
203
|
+
skipBlank();
|
|
204
|
+
const obj = {};
|
|
205
|
+
try {
|
|
206
|
+
while (jsonString[index] !== "}") {
|
|
207
|
+
skipBlank();
|
|
208
|
+
if (index >= length && options_1.Allow.OBJ & allow) return obj;
|
|
209
|
+
const key = parseStr();
|
|
210
|
+
skipBlank();
|
|
211
|
+
index++;
|
|
212
|
+
try {
|
|
213
|
+
obj[key] = parseAny();
|
|
214
|
+
} catch (e) {
|
|
215
|
+
if (options_1.Allow.OBJ & allow) return obj;
|
|
216
|
+
else throw e;
|
|
217
|
+
}
|
|
218
|
+
skipBlank();
|
|
219
|
+
if (jsonString[index] === ",") index++;
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
if (options_1.Allow.OBJ & allow) return obj;
|
|
223
|
+
else markPartialJSON("Expected '}' at end of object");
|
|
224
|
+
}
|
|
225
|
+
index++;
|
|
226
|
+
return obj;
|
|
227
|
+
};
|
|
228
|
+
const parseArr = () => {
|
|
229
|
+
index++;
|
|
230
|
+
const arr = [];
|
|
231
|
+
try {
|
|
232
|
+
while (jsonString[index] !== "]") {
|
|
233
|
+
arr.push(parseAny());
|
|
234
|
+
skipBlank();
|
|
235
|
+
if (jsonString[index] === ",") index++;
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
if (options_1.Allow.ARR & allow) return arr;
|
|
239
|
+
markPartialJSON("Expected ']' at end of array");
|
|
240
|
+
}
|
|
241
|
+
index++;
|
|
242
|
+
return arr;
|
|
243
|
+
};
|
|
244
|
+
const parseNum = () => {
|
|
245
|
+
if (index === 0) {
|
|
246
|
+
if (jsonString === "-") throwMalformedError("Not sure what '-' is");
|
|
247
|
+
try {
|
|
248
|
+
return JSON.parse(jsonString);
|
|
249
|
+
} catch (e) {
|
|
250
|
+
if (options_1.Allow.NUM & allow) try {
|
|
251
|
+
return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf("e")));
|
|
252
|
+
} catch (e) {}
|
|
253
|
+
throwMalformedError(String(e));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const start = index;
|
|
257
|
+
if (jsonString[index] === "-") index++;
|
|
258
|
+
while (jsonString[index] && ",]}".indexOf(jsonString[index]) === -1) index++;
|
|
259
|
+
if (index == length && !(options_1.Allow.NUM & allow)) markPartialJSON("Unterminated number literal");
|
|
260
|
+
try {
|
|
261
|
+
return JSON.parse(jsonString.substring(start, index));
|
|
262
|
+
} catch (e) {
|
|
263
|
+
if (jsonString.substring(start, index) === "-") markPartialJSON("Not sure what '-' is");
|
|
264
|
+
try {
|
|
265
|
+
return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("e")));
|
|
266
|
+
} catch (e) {
|
|
267
|
+
throwMalformedError(String(e));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const skipBlank = () => {
|
|
272
|
+
while (index < length && " \n\r ".includes(jsonString[index])) index++;
|
|
273
|
+
};
|
|
274
|
+
return parseAny();
|
|
275
|
+
};
|
|
276
|
+
exports.parse = parseJSON;
|
|
277
|
+
})))();
|
|
278
|
+
const VALID_JSON_ESCAPES = /* @__PURE__ */ new Set([
|
|
279
|
+
"\"",
|
|
280
|
+
"\\",
|
|
281
|
+
"/",
|
|
282
|
+
"b",
|
|
283
|
+
"f",
|
|
284
|
+
"n",
|
|
285
|
+
"r",
|
|
286
|
+
"t",
|
|
287
|
+
"u"
|
|
288
|
+
]);
|
|
289
|
+
function isControlCharacter(char) {
|
|
290
|
+
const codePoint = char.codePointAt(0);
|
|
291
|
+
return codePoint !== void 0 && codePoint >= 0 && codePoint <= 31;
|
|
292
|
+
}
|
|
293
|
+
function escapeControlCharacter(char) {
|
|
294
|
+
switch (char) {
|
|
295
|
+
case "\b": return "\\b";
|
|
296
|
+
case "\f": return "\\f";
|
|
297
|
+
case "\n": return "\\n";
|
|
298
|
+
case "\r": return "\\r";
|
|
299
|
+
case " ": return "\\t";
|
|
300
|
+
default: return `\\u${char.codePointAt(0)?.toString(16).padStart(4, "0") ?? "0000"}`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Repairs malformed JSON string literals by:
|
|
305
|
+
* - escaping raw control characters inside strings
|
|
306
|
+
* - doubling backslashes before invalid escape characters
|
|
307
|
+
*/
|
|
308
|
+
function repairJson(json) {
|
|
309
|
+
let repaired = "";
|
|
310
|
+
let inString = false;
|
|
311
|
+
for (let index = 0; index < json.length; index++) {
|
|
312
|
+
const char = json[index];
|
|
313
|
+
if (!inString) {
|
|
314
|
+
repaired += char;
|
|
315
|
+
if (char === "\"") inString = true;
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (char === "\"") {
|
|
319
|
+
repaired += char;
|
|
320
|
+
inString = false;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (char === "\\") {
|
|
324
|
+
const nextChar = json[index + 1];
|
|
325
|
+
if (nextChar === void 0) {
|
|
326
|
+
repaired += "\\\\";
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (nextChar === "u") {
|
|
330
|
+
const unicodeDigits = json.slice(index + 2, index + 6);
|
|
331
|
+
if (/^[0-9a-fA-F]{4}$/.test(unicodeDigits)) {
|
|
332
|
+
repaired += `\\u${unicodeDigits}`;
|
|
333
|
+
index += 5;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (VALID_JSON_ESCAPES.has(nextChar)) {
|
|
338
|
+
repaired += `\\${nextChar}`;
|
|
339
|
+
index += 1;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
repaired += "\\\\";
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
repaired += isControlCharacter(char) ? escapeControlCharacter(char) : char;
|
|
346
|
+
}
|
|
347
|
+
return repaired;
|
|
348
|
+
}
|
|
349
|
+
function parseJsonWithRepair(json) {
|
|
350
|
+
try {
|
|
351
|
+
return JSON.parse(json);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
const repairedJson = repairJson(json);
|
|
354
|
+
if (repairedJson !== json) return JSON.parse(repairedJson);
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Attempts to parse potentially incomplete JSON during streaming.
|
|
360
|
+
* Always returns a valid object, even if the JSON is incomplete.
|
|
361
|
+
*
|
|
362
|
+
* @param partialJson The partial JSON string from streaming
|
|
363
|
+
* @returns Parsed object or empty object if parsing fails
|
|
364
|
+
*/
|
|
365
|
+
function parseStreamingJson(partialJson) {
|
|
366
|
+
if (!partialJson || partialJson.trim() === "") return {};
|
|
367
|
+
try {
|
|
368
|
+
return parseJsonWithRepair(partialJson);
|
|
369
|
+
} catch {
|
|
370
|
+
try {
|
|
371
|
+
return (0, import_dist.parse)(partialJson) ?? {};
|
|
372
|
+
} catch {
|
|
373
|
+
try {
|
|
374
|
+
return (0, import_dist.parse)(repairJson(partialJson)) ?? {};
|
|
375
|
+
} catch {
|
|
376
|
+
return {};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
export { parseStreamingJson as n, parseJsonWithRepair as t };
|
|
383
|
+
|
|
384
|
+
//# sourceMappingURL=json-parse-CZ0U0sj_.mjs.map
|