pi2dsh 0.22.0 → 0.24.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.
- package/README.md +8 -5
- package/README.zh.md +6 -3
- package/dist/{analyzer-LD53mBKa.mjs → analyzer-DqsrD1FG.mjs} +2 -2
- package/dist/{analyzer-LD53mBKa.mjs.map → analyzer-DqsrD1FG.mjs.map} +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/{compatibility-PfLsrQPc.mjs → compatibility-CZ0QpE76.mjs} +4 -4
- package/dist/compatibility-CZ0QpE76.mjs.map +1 -0
- package/dist/host.mjs +1 -1
- package/dist/index.mjs +5 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{runtime-BVrvJuiO.mjs → runtime-BiHMcD_8.mjs} +235 -127
- package/dist/runtime-BiHMcD_8.mjs.map +1 -0
- package/dist/runtime.d.mts +75 -47
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +12 -12
- package/dist/compatibility-PfLsrQPc.mjs.map +0 -1
- package/dist/runtime-BVrvJuiO.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compatibility-CZ0QpE76.mjs","names":[],"sources":["../src/compatibility.ts"],"sourcesContent":["import type { CompatibilityLevel } from './types.js'\n\ninterface Rule {\n level: CompatibilityLevel\n detail: string\n /** How the mapping is built — the DSH seam or service that carries it. */\n design?: string\n}\n\n/**\n * A Pi extension surface. `design` is REQUIRED here and optional on Rule: an\n * imported symbol is served by a shim family the docs describe once, but every\n * surface a package can call has to name the DSH mechanism behind it, or the\n * documentation degrades into a list of verdicts nobody can act on. Adding a\n * surface without one is a type error, which is the point.\n */\ninterface SurfaceRule extends Rule {\n design: string\n}\n\nconst rule = (level: CompatibilityLevel, detail: string): Rule => ({ level, detail })\n\nconst surface = (level: CompatibilityLevel, detail: string, design: string): SurfaceRule =>\n ({ level, detail, design })\n\nexport const PI_CODING_AGENT_PACKAGES = Object.freeze([\n '@earendil-works/pi-coding-agent',\n '@mariozechner/pi-coding-agent',\n] as const)\n\nexport const PI_TUI_PACKAGES = Object.freeze([\n '@earendil-works/pi-tui',\n '@mariozechner/pi-tui',\n] as const)\n\nexport const PI_AI_PACKAGES = Object.freeze([\n '@earendil-works/pi-ai',\n '@mariozechner/pi-ai',\n] as const)\n\nconst VENDORED = 'Vendored byte-identical from Pi, so semantics match Pi exactly.'\nconst HEADLESS_COMPONENT = 'Constructible headless component with Pi-exact signatures; renders plain text, never a terminal.'\nconst VENDORED_TOOL = 'Pi\\'s built-in tool constructor, vendored byte-identical with its pure-logic closure.'\nconst EVENT_GUARD = 'Pi\\'s exact one-line tool-event guard, reimplemented verbatim.'\nconst VENDORED_SUMMARIZER = 'Vendored Pi logic; the model call fills Pi\\'s own streamFn injection point with the DSH llm bridge when the caller passes none, so summarization runs on the ONE model path. Without a mounted llm service it fails explicitly.'\nconst PI_PROVIDER_TRANSPORT_FACTORY = 'Pi\\'s real lazy protocol transport factory, exposed to transport-owning provider packages and then wrapped as one native DSH llm adapter.'\n\nexport const HOST_IMPORT_RULES: Readonly<Record<string, Readonly<Record<string, Rule>>>> = Object.freeze({\n 'pi-coding-agent': Object.freeze({\n defineTool: rule('full', 'Identity helper, preserved.'),\n CONFIG_DIR_NAME: rule('partial', 'The conventional config directory name is preserved, while DSH owns the actual profile layout.'),\n DEFAULT_MAX_LINES: rule('full', VENDORED),\n DEFAULT_MAX_BYTES: rule('full', VENDORED),\n VERSION: rule('partial', 'Reports a pi2dsh compatibility marker instead of a Pi release version.'),\n CURRENT_SESSION_VERSION: rule('full', VENDORED),\n getAgentDir: rule('partial', 'Redirected to an isolated DSH-owned pi2dsh directory instead of Pi global state.'),\n getPackageDir: rule('partial', 'Resolves inside the DSH-owned pi2dsh agent directory.'),\n formatSize: rule('full', VENDORED),\n truncateHead: rule('full', VENDORED),\n truncateTail: rule('full', VENDORED),\n truncateLine: rule('full', VENDORED),\n withFileMutationQueue: rule('full', VENDORED),\n SessionManager: rule('full', `${VENDORED} Sessions live under the DSH-owned pi2dsh agent directory.`),\n parseSessionEntries: rule('full', VENDORED),\n migrateSessionEntries: rule('full', VENDORED),\n getLatestCompactionEntry: rule('full', VENDORED),\n sessionEntryToContextMessages: rule('full', VENDORED),\n buildContextEntries: rule('full', VENDORED),\n buildSessionContext: rule('full', VENDORED),\n loadEntriesFromFile: rule('full', VENDORED),\n findMostRecentSession: rule('full', VENDORED),\n getDefaultSessionDir: rule('full', VENDORED),\n assertValidSessionId: rule('full', VENDORED),\n convertToLlm: rule('full', VENDORED),\n createCustomMessage: rule('full', VENDORED),\n createBranchSummaryMessage: rule('full', VENDORED),\n createCompactionSummaryMessage: rule('full', VENDORED),\n bashExecutionToText: rule('full', VENDORED),\n estimateTokens: rule('full', VENDORED),\n calculateContextTokens: rule('full', `${VENDORED} Pi\\'s Usage-based total (an earlier reimplementation summed message estimates — same name, different meaning — and was replaced).`),\n DEFAULT_COMPACTION_SETTINGS: rule('full', VENDORED),\n serializeConversation: rule('full', VENDORED),\n shouldCompact: rule('full', `${VENDORED} The pure threshold check; DSH still owns automatic compaction scheduling.`),\n compact: rule('partial', VENDORED_SUMMARIZER),\n findCutPoint: rule('full', VENDORED),\n generateSummary: rule('partial', VENDORED_SUMMARIZER),\n generateSummaryWithUsage: rule('partial', VENDORED_SUMMARIZER),\n generateBranchSummary: rule('partial', VENDORED_SUMMARIZER),\n parseFrontmatter: rule('full', `${VENDORED} Returns Pi\\'s public { frontmatter, body } shape with YAML-parsed values (an earlier reimplementation returned { attributes } with string values and was replaced).`),\n stripFrontmatter: rule('full', VENDORED),\n copyToClipboard: rule('partial', 'Attempts the platform clipboard command (pbcopy/clip/wl-copy/xclip); resolves false when none succeeds.'),\n resizeImage: rule('partial', 'Passes images through un-resized; Pi resizes only to save tokens, so content is preserved.'),\n convertToPng: rule('partial', 'PNG input passes through; other formats fail explicitly without Pi\\'s wasm codec.'),\n getShellConfig: rule('partial', 'Standard shell detection without Pi\\'s managed-bin PATH handling.'),\n getBinDir: rule('partial', 'Reports the first PATH segment instead of Pi\\'s managed bin directory.'),\n Theme: rule('partial', 'Headless theme: styling calls return their input text unstyled.'),\n theme: rule('partial', 'A headless theme singleton; jiti-loaded Pi extensions must not rely on Pi global theme state anyway.'),\n initTheme: rule('partial', 'Accepted as a no-op; DSH surfaces own presentation.'),\n getSettingsListTheme: rule('partial', 'Returns an unstyled theme with Pi\\'s exact field shape.'),\n getSelectListTheme: rule('partial', 'Returns an unstyled theme with Pi\\'s exact field shape.'),\n getMarkdownTheme: rule('partial', 'Returns a plain-text headless theme; Pi terminal styling is intentionally discarded.'),\n getLanguageFromPath: rule('partial', 'Extension-based language detection covering common languages.'),\n highlightCode: rule('partial', 'Splits lines without terminal syntax colors.'),\n DynamicBorder: rule('full', 'Headless implementation of Pi\\'s one-line border component; pass an explicit color function as Pi itself recommends.'),\n SettingsManager: rule('partial', 'In-memory settings with Pi\\'s getter/setter surface; DSH owns real persisted configuration.'),\n InMemorySettingsStorage: rule('partial', 'In-memory storage stub honoring the withLock contract.'),\n FileSettingsStorage: rule('partial', 'Alias of the in-memory storage; DSH owns persisted settings.'),\n ModelRegistry: rule('partial', 'A local registry container; DSH llm adapters own real model routing.'),\n createEventBus: rule('full', 'Pi event-bus semantics: async handler isolation and unsubscribe functions.'),\n readStoredCredential: rule('partial', 'Reads Pi-style auth.json from the pi2dsh-owned agent directory; DSH credentials stay authoritative for DSH model calls.'),\n parseSkillBlock: rule('full', 'Pi\\'s skill_content block parser, reimplemented over the same wire shape.'),\n wrapRegisteredTool: rule('full', `${VENDORED} The runner argument is used exactly as Pi uses it (createContext + getActiveTools), which the pi2dsh projection provides.`),\n ProjectTrustStore: rule('partial', `${VENDORED} The store operates on trust.json under the caller\\'s agentDir — with the redirected getAgentDir convention that is package-visible state inside the DSH-owned pi2dsh directory. The DSH host never consults it; host trust stays a DSH decision (ctx.isProjectTrusted reports it: true for an agent session's directory, fail-closed without an agent).`),\n DefaultResourceLoader: rule('partial', 'A headless resource loader honoring overrides. Extension discovery is REAL: the default-discovered set is the host\\'s installed Pi packages (each package\\'s declared pi extension entry, as an absolute installed path), so a creator\\'s own filtering code — pi-subagents\\' extensions/exclude_extensions/ext: machinery canonicalizes by entry basename and owning-manifest npm short name — runs unchanged and selects exactly what it selects on Pi. noExtensions empties the set; additionalExtensionPaths cannot be loaded fresh on this host and surface as per-entry errors (Pi\\'s diagnostics shape). Skills/prompts/themes/agents-files discovery stays empty.'),\n DefaultPackageManager: rule('unsupported', 'Installing packages is owned by the DSH host and its security gates (dsh plugin add/remove behind pnpm\\'s build-script approval). Importing it is flagged at mount time (startup check); constructing it throws a structured PiCapabilityError, and doing so during entry setup marks the package unusable.'),\n ModelRuntime: rule('unsupported', 'Standalone model stacks are owned by the DSH host llm configuration; packages read the ONE directory through ctx.modelRegistry. Importing it is flagged at mount time (startup check); constructing it throws a structured PiCapabilityError, and doing so during entry setup marks the package unusable.'),\n createAgentSession: rule('partial', 'Bridged to a genuine DSH child agent through ctx.agents with the creator-exclusive setup contribution. Child tools join a preset composition in the roster\\'s official preference order — inherit the parent\\'s standing composition (composeFrom), else mount the roster default — which is what keeps children tooled on roster-owned surfaces (dsh-tui disables host-layer tool rows); rosterless deployments compose from the host rows as before. The Pi tools allowlist/excludeTools become official scoped restrictions, customTools register in the child scope, delegation policy travels the official way, and the child\\'s model resolves in three tiers — the explicit Pi model on the options, else the caller\\'s LIVE route read from its durable session log\\'s last request/header (so a mid-session /model switch in the DSH UI is inherited, proven live on the stock TUI), else the creation-time snapshot; a truly modelless child fails its first {{model}}-keyed prompt assembly. A per-child thinkingLevel becomes the child\\'s own reasoningEffort through the official agent/request waterfall (never leaking to siblings or the parent). session.subscribe projects tool_execution_start/end from the durable log (tool-use accounting works), The child is served its EXTENSION SET exactly as real Pi loads one: the host\\'s installed Pi packages, filtered by the creator\\'s resource loader (its own getExtensions applies noExtensions/extensionsOverride — the creator\\'s code decides; no loader means Pi\\'s default, everything discovered), mounted as per-child package instances on the child agent\\'s own ctx before createAgentSession returns — their tools register in the child scope, their handlers see the child session, and everything unwinds with the agent (leak-free by scope, not by bookkeeping). bindExtensions() reports per-extension mount failures to the binding\\'s onError in Pi\\'s {extensionPath, error} shape; one timing nuance: session_start reaches child-bound packages at creation rather than at the bindExtensions call. steer() and followUp() are async per Pi\\'s AgentSession face (consumers chain .catch on the returned promise; steer interrupts, followUp queues behind the running turn), and abort() follows Pi\\'s contract: the child turn is cancelled AND post-abort wakes (a late tool result reaching quiescence) are re-cancelled on every opening event until the next explicit prompt(). The child exposes session.sessionManager (readonly projection) whose getSessionFile() names a durable archive (`<id>.jsonl`) in genuine Pi session-file format — a Pi header line plus any Pi-only entries, parseable by Pi\\'s own SessionManager; conversation content is NOT copied there, it projects live from the native DSH log. Handing a SessionManager opened FROM such an archive back to createAgentSession reopens the SAME persisted DSH session through the registry\\'s official resume seam, across process restarts (pi-subagents\\' tombstone resurrect shape). If a reopen fails, DSH\\'s own persistence list() delivers the verdict (the check agent-loop itself uses): a POSITIVE \"gone\" retires the archive file so existsSync answers honestly from then on, while a composition merely lacking persistence keeps the token and fails loudly — absence of evidence never destroys a valid identity. Compositions without a loop factory fail explicitly.'),\n createCodingTools: rule('full', 'Pi\\'s exact tool set composed from the vendored built-in constructors.'),\n createReadOnlyTools: rule('full', 'Pi\\'s exact read-only tool set composed from the vendored built-in constructors.'),\n createBashTool: rule('full', VENDORED_TOOL),\n createReadTool: rule('full', VENDORED_TOOL),\n createEditTool: rule('full', VENDORED_TOOL),\n createWriteTool: rule('full', VENDORED_TOOL),\n createGrepTool: rule('full', VENDORED_TOOL),\n createFindTool: rule('full', VENDORED_TOOL),\n createLsTool: rule('full', VENDORED_TOOL),\n createBashToolDefinition: rule('full', VENDORED_TOOL),\n createReadToolDefinition: rule('full', VENDORED_TOOL),\n createEditToolDefinition: rule('full', VENDORED_TOOL),\n createWriteToolDefinition: rule('full', VENDORED_TOOL),\n createGrepToolDefinition: rule('full', VENDORED_TOOL),\n createFindToolDefinition: rule('full', VENDORED_TOOL),\n createLsToolDefinition: rule('full', VENDORED_TOOL),\n isToolCallEventType: rule('full', EVENT_GUARD),\n isBashToolResult: rule('full', EVENT_GUARD),\n isReadToolResult: rule('full', EVENT_GUARD),\n isEditToolResult: rule('full', EVENT_GUARD),\n isWriteToolResult: rule('full', EVENT_GUARD),\n isGrepToolResult: rule('full', EVENT_GUARD),\n isFindToolResult: rule('full', EVENT_GUARD),\n isLsToolResult: rule('full', EVENT_GUARD),\n loadSkills: rule('partial', `${VENDORED} Real directory discovery with Pi\\'s exact rules; default locations resolve through the redirected getAgentDir, i.e. inside the DSH-owned pi2dsh directory.`),\n loadSkillsFromDir: rule('full', `${VENDORED} Real directory discovery: SKILL.md roots, direct .md children, ignore files, symlink dedup, and Pi\\'s name/description validation.`),\n formatSkillsForPrompt: rule('full', 'Pi\\'s skill prompt formatter, vendored with logic unchanged.'),\n CustomEditor: rule('partial', HEADLESS_COMPONENT),\n ToolExecutionComponent: rule('partial', HEADLESS_COMPONENT),\n FooterComponent: rule('partial', HEADLESS_COMPONENT),\n BorderedLoader: rule('partial', HEADLESS_COMPONENT),\n CustomMessageComponent: rule('partial', HEADLESS_COMPONENT),\n AssistantMessageComponent: rule('partial', HEADLESS_COMPONENT),\n UserMessageComponent: rule('partial', HEADLESS_COMPONENT),\n ExtensionSelectorComponent: rule('partial', HEADLESS_COMPONENT),\n ExtensionInputComponent: rule('partial', HEADLESS_COMPONENT),\n ExtensionEditorComponent: rule('partial', HEADLESS_COMPONENT),\n SettingsSelectorComponent: rule('partial', HEADLESS_COMPONENT),\n renderDiff: rule('partial', 'Plain unified-style diff lines without terminal colors.'),\n truncateToVisualLines: rule('partial', 'Visual-line truncation backed by Pi\\'s vendored width math.'),\n keyHint: rule('partial', 'Plain-text key hint without theme styling.'),\n keyText: rule('partial', 'Plain-text key name without theme styling.'),\n rawKeyHint: rule('partial', 'Plain-text key hint without theme styling.'),\n }),\n 'pi-tui': Object.freeze({\n visibleWidth: rule('full', VENDORED),\n truncateToWidth: rule('full', VENDORED),\n wrapTextWithAnsi: rule('full', VENDORED),\n sliceByColumn: rule('full', VENDORED),\n sliceWithWidth: rule('full', VENDORED),\n stripTerminalSequences: rule('full', VENDORED),\n getOsc8LinkAtColumn: rule('full', VENDORED),\n normalizeTerminalOutput: rule('full', VENDORED),\n extractAnsiCode: rule('full', VENDORED),\n getGraphemeCellRange: rule('full', VENDORED),\n getGraphemeSegmenter: rule('full', VENDORED),\n getWordSegmenter: rule('full', VENDORED),\n applyBackgroundToLine: rule('full', VENDORED),\n isWhitespaceChar: rule('full', VENDORED),\n isPunctuationChar: rule('full', VENDORED),\n cjkBreakRegex: rule('full', VENDORED),\n PUNCTUATION_REGEX: rule('full', VENDORED),\n fuzzyMatch: rule('full', VENDORED),\n fuzzyFilter: rule('full', VENDORED),\n parseKey: rule('full', VENDORED),\n matchesKey: rule('full', VENDORED),\n isKeyRelease: rule('full', VENDORED),\n isKeyRepeat: rule('full', VENDORED),\n decodeKittyPrintable: rule('full', VENDORED),\n isKittyProtocolActive: rule('full', VENDORED),\n setKittyProtocolActive: rule('full', VENDORED),\n Key: rule('full', VENDORED),\n getKeybindings: rule('full', `${VENDORED} Bindings only match when a surface feeds terminal input, which DSH does not.`),\n setKeybindings: rule('full', VENDORED),\n KeybindingsManager: rule('full', VENDORED),\n TUI_KEYBINDINGS: rule('full', VENDORED),\n parseOsc11BackgroundColor: rule('full', VENDORED),\n parseTerminalColorSchemeReport: rule('full', VENDORED),\n renderLatex: rule('full', VENDORED),\n getPngDimensions: rule('full', VENDORED),\n getJpegDimensions: rule('full', VENDORED),\n getGifDimensions: rule('full', VENDORED),\n getWebpDimensions: rule('full', VENDORED),\n getImageDimensions: rule('full', VENDORED),\n calculateImageRows: rule('full', VENDORED),\n allocateImageId: rule('full', VENDORED),\n encodeKitty: rule('partial', `${VENDORED} No DSH surface consumes the escape sequences.`),\n encodeITerm2: rule('partial', `${VENDORED} No DSH surface consumes the escape sequences.`),\n deleteKittyImage: rule('partial', `${VENDORED} No DSH surface consumes the escape sequences.`),\n deleteAllKittyImages: rule('partial', `${VENDORED} No DSH surface consumes the escape sequences.`),\n detectCapabilities: rule('partial', `${VENDORED} Headless environments report no image protocol.`),\n getCapabilities: rule('partial', VENDORED),\n setCapabilities: rule('partial', VENDORED),\n resetCapabilitiesCache: rule('partial', VENDORED),\n getCellDimensions: rule('partial', VENDORED),\n setCellDimensions: rule('partial', VENDORED),\n hyperlink: rule('full', VENDORED),\n imageFallback: rule('full', VENDORED),\n CombinedAutocompleteProvider: rule('partial', `${VENDORED} Suggestions surface only if a DSH UI asks for them.`),\n Marked: rule('full', 'Re-exported from the same marked dependency Pi uses.'),\n CURSOR_MARKER: rule('full', 'Pi\\'s exact APC marker; vendored width math treats it as zero-width.'),\n Text: rule('partial', HEADLESS_COMPONENT),\n Spacer: rule('partial', HEADLESS_COMPONENT),\n Container: rule('partial', HEADLESS_COMPONENT),\n Box: rule('partial', HEADLESS_COMPONENT),\n Markdown: rule('partial', HEADLESS_COMPONENT),\n TruncatedText: rule('partial', HEADLESS_COMPONENT),\n Editor: rule('partial', `${HEADLESS_COMPONENT} Text editing state works; interactive keyboard flows do not.`),\n Input: rule('partial', `${HEADLESS_COMPONENT} Value state and submit/escape callbacks work; kill-ring editing does not.`),\n SelectList: rule('partial', `${HEADLESS_COMPONENT} Filtering and selection state work; keyboard interaction does not.`),\n SettingsList: rule('partial', `${HEADLESS_COMPONENT} Value updates work; keyboard interaction does not.`),\n ScrollView: rule('partial', HEADLESS_COMPONENT),\n VStack: rule('partial', HEADLESS_COMPONENT),\n HStack: rule('partial', HEADLESS_COMPONENT),\n Loader: rule('partial', HEADLESS_COMPONENT),\n CancellableLoader: rule('partial', HEADLESS_COMPONENT),\n Image: rule('partial', `${HEADLESS_COMPONENT} Renders a text placeholder; image bytes flow through DSH attachments instead.`),\n isFocusable: rule('full', 'Structural check preserved.'),\n isViewportTUI: rule('partial', 'Always false: no viewport TUI exists in DSH surfaces.'),\n }),\n 'pi-ai': Object.freeze({\n StringEnum: rule('full', 'Preserves Pi flat string-enum JSON Schema generation without loading provider SDKs.'),\n envApiKeyAuth: rule('full', 'Pi 0.84.1 stored-key-first auth helper with ordered environment fallback and the original secret-prompt login contract.'),\n anthropicMessagesApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n openAICompletionsApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n openAIResponsesApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n openAICodexResponsesApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n azureOpenAIResponsesApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n googleGenerativeAIApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n googleVertexApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n mistralConversationsApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n bedrockConverseStreamApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n piMessagesApi: rule('full', PI_PROVIDER_TRANSPORT_FACTORY),\n streamSimpleOpenAIResponses: rule('full', 'Pi\\'s real OpenAI Responses simple transport, exported under the legacy symbol used by transport-owning provider packages.'),\n registerProvider: rule('partial', 'Recorded in the Pi-facing registry, then exposed as a DSH route: a transport-owning provider uses llm.registerAdapter; a catalog-only provider is translated into the official llm-pi-ai profile schema.'),\n getProviders: rule('partial', 'Returns the bridge-local registry contents.'),\n getProvider: rule('partial', 'Reads the bridge-local registry.'),\n getModel: rule('partial', 'Resolves no Pi model objects; DSH owns model routing.'),\n getModels: rule('partial', 'Returns an empty list; DSH owns model routing.'),\n complete: rule('partial', 'Real model calls through the DSH llm bridge (the host installs it at mount); without a mounted llm service the call fails explicitly. Provider SDKs are never loaded.'),\n stream: rule('partial', 'Real streaming model calls through the DSH llm bridge (the host installs it at mount); without a mounted llm service the call fails explicitly. Provider SDKs are never loaded.'),\n Type: rule('full', 'Re-exported from the same typebox dependency Pi resolves for extensions.'),\n uuidv7: rule('full', VENDORED),\n isContextOverflow: rule('full', VENDORED),\n isRecoverableLength: rule('full', VENDORED),\n isRetryableAssistantError: rule('full', VENDORED),\n contentText: rule('full', 'Pi\\'s text-block joiner, reimplemented with identical semantics.'),\n clampThinkingLevel: rule('full', 'Pi\\'s clamping walk over the extended thinking-level ladder.'),\n getSupportedThinkingLevels: rule('full', 'Pi\\'s thinkingLevelMap filter, preserved.'),\n modelsAreEqual: rule('full', 'Id+provider equality, preserved.'),\n }),\n})\n\nexport const CONTEXT_RULES: Readonly<Record<string, SurfaceRule>> = Object.freeze({\n cwd: surface('full', 'Mapped to the active DSH agent session working directory.', 'Read off the live DSH agent\\'s session; the bridge keeps no working directory of its own.'),\n signal: surface('full', 'Mapped to the active DSH cancellation signal when one is available.', 'The DSH cancellation signal belonging to the moment the context was built — a tool context carries its execution signal, a lifecycle context the agent\\'s.'),\n hasUI: surface('full', 'Reports whether a real interactive surface exists: true for a mounted public terminal surface (dsh-TUI tuiScenes or dsh-pi-tui piTuiExtensions) or for a live DSH question answerer; false for a genuinely headless composition and for child-agent questions that DSH refuses.', 'The terminal answer comes from the capability-selected TerminalSurfaceAdapter. The question answer is generation-selected by capability: rc lines expose a provider slot, so the bridge registers a throwaway provider and reads the documented DUPLICATE_PROVIDER rejection as \"a real provider is already there\"; the 0.1.2 line replaced the slot with agent-scoped user-questions/request waterfall answerers, so the bridge lists would-be listeners through cordis Lifecycle.dispatch (a typed public member) and falls back to a recent browser contact on the presentation route. Inside a child agent only the terminal seat can make this true, because DSH refuses child-agent questions.'),\n mode: surface('full', 'Reports tui only where a real full-screen terminal seat exists — dsh-TUI scenes or dsh-pi-tui raw mounts. Every web composition is rpc on purpose (2026-08-29 product decision): the browser renders product UI (side-chat window, MCP tab, pills), never a projected TUI, so packages asked \"can I show interactive full-screen UI here?\" get the honest no and take their own official degradation.', 'Derived from the live optional TerminalSurfaceAdapter only. Surface selection is by public service/capability (`tuiScenes` or `piTuiExtensions` + unstable.surface.handle), never by Pi consumer package.'),\n isIdle: surface('partial', 'Command contexts report idle; tool/lifecycle contexts conservatively report non-idle.', 'Derived from which context the call arrived through: a command context is outside a step, a tool or lifecycle context is inside one.'),\n isProjectTrusted: surface('full', 'Reports the DSH host\\'s own trust decision: true for an agent session\\'s working directory, false for the host anchor and detached contexts.', 'Host-semantic translation, not a constant. On DSH the trust act is opening a workspace — the host already runs its own bash/edit/write in the session\\'s directory without a further prompt — so an agent-scoped context answers true for exactly that directory. Contexts with no agent (the host anchor, detached projections) stay fail-closed. The earlier hardcoded false claimed the host actively distrusts every project — a stronger statement than DSH makes anywhere — and packages honor it literally: pi-lens disables every language-server spawn on an explicit false while treating a missing accessor as unknown-and-allowed. Pi\\'s own ProjectTrustStore stays vendored for packages that manage their own per-path trust.'),\n hasPendingMessages: surface('full', 'Reads the DSH agent inbox — next-step plus next-turn input — which is exactly Pi\\'s steering plus follow-up queue.', 'Reads the DSH agent inbox — next-step plus next-turn queues — which is the same queue sendMessage/sendUserMessage write into.'),\n getContextUsage: surface('partial', 'Returns no Pi token-usage projection.', 'Not synthesized. DSH accounts tokens in its own token-meter service, and a guessed Pi projection would be read as measurement.'),\n getSystemPrompt: surface('full', 'Returns the system prompt currently assembled by the bridge.', 'Returns the string the bridge recorded during system-prompt/assemble for the current turn. It is recorded on every assembly, before any gate, so a package that only reads the prompt still sees it.'),\n getSystemPromptOptions: surface('partial', 'Returns an empty Pi option projection in command contexts.', 'Pi\\'s option object describes Pi\\'s own prompt builder, which never runs here; the projection stays empty rather than reconstructed from DSH\\'s sections.'),\n waitForIdle: surface('partial', 'Mapped to the DSH agent idle boundary when available.', 'Awaits the DSH agent\\'s own idle boundary when the agent exposes one.'),\n sessionManager: surface('partial', 'A real read-only projection: DSH durable messages plus the session\\'s Pi-only entries (customs, labels, branch summaries — stored as genuine Pi entry lines in the per-session archive file), exposed through Pi\\'s exact 14-method surface as a single-branch tree. Conversation content is never duplicated: it projects live from the native DSH log at call time. buildContextEntries is compaction-aware — entries a compaction summarized away are gone, exactly as they are for the model — while getEntries stays the append-only log, which is the same split Pi makes.', 'A read-only projection folded from two ordered sources — DSH\\'s durable session log (single authority for conversation, projected live) and the per-session Pi-format archive holding only Pi-only entries — into the single chain Pi\\'s 14-method surface walks. Compaction awareness comes from the same fold: entries a compaction summarized away are dropped from the context view and kept in the log view.'),\n modelRegistry: surface('partial', 'A live registry over the ONE model directory — the DSH llm directory — projected exactly into Pi vocabulary; package-registered Pi-native routes keep api/baseUrl and the full Model shape through the round trip. DSH describes one model across two seams (a listing for directory membership, an exact per-route resolve for capacity) while Pi puts everything on one Model object read synchronously, so the projection joins them when the directory is read: entries carry contextWindow, maxTokens and reasoning, and a settings change re-reads them rather than serving the retired numbers. Custom gateways are HOST configuration (the official llm-pi-ai adapter\\'s settings), never a Pi-side file: Pi\\'s ~/.pi/agent/models.json is deliberately NOT read — user-facing configuration is DSH-shaped only. getProviderAuth/getApiKeyAndHeaders run Pi\\'s full credential chain for package-registered providers and the host\\'s configurable-provider + credentials seams for DSH routes. Host configuration may declare \"<route>-vision\" image-admission companions: real DSH routes that admit images, replace image blocks with explicit path-carrying notices (materialized attachment files any path-taking tool can read), and forward text-only to the original route; Pi\\'s ctx.model reports the original route for a companion selection.', 'A ModelCatalog over llm.listProviders() x listModels(), joined per route with llm.resolveModelInfo() for capacity, refreshed on the llm/adapters-updated notification and cached so reads stay synchronous — Pi\\'s getAll() is not async. Package-registered routes have their exact Pi Model restored from the registration on the way out.'),\n model: surface('partial', 'The agent\\'s real provider/model route (a setModel() override wins), enriched from the projected catalog. When the selected route is an image-admission companion, ctx.model reports the ORIGINAL route with its true modalities — the generating model is the original text-only one, which is the truth extensions branching on input modalities (a vision bridge\\'s activation check) need.', 'Reads the live agent\\'s own options.provider/model (a setModel override wins) and enriches it through the same catalog projection, so a package reads one Model shape everywhere.'),\n scopedModels: surface('full', 'Empty, carrying Pi\\'s own meaning for empty: no model scope is configured, so every available model is usable. DSH has no model-scope concept to narrow it.', 'Nothing to compute. DSH has no model-scope concept, and Pi\\'s empty array already carries exactly that meaning.'),\n hasConfiguredAuth: surface('partial', 'Configuration check on the projected registry: true when the model\\'s provider has a live route or package registration (not a key-liveness probe).', 'Answered from configuration alone — the package-provider map plus the live catalog — and never opens a connection, which is also what Pi\\'s own check does.'),\n thinkingLevel: surface('partial', 'Reflects the level recorded by setThinkingLevel(); applied as reasoningEffort on the next request.', 'Bridge state written by setThinkingLevel, applied to the request on the agent/request waterfall.'),\n abort: surface('partial', 'Mapped to agent.cancel({ kind: \"hook\" }) on the live DSH agent.', 'Calls agent.cancel({ kind: \\'hook\\' }) on the live DSH agent.'),\n shutdown: surface('partial', 'Pi defines shutdown behavior as host-provided (runner.ts bindExtensions); this host absorbs the request — the user owns DSH process exit — and informs the user once. The package keeps running.', 'Pi defines shutdown as host-provided, so this host absorbs it: the request is recorded in the capability ledger and surfaced to the user once. Nothing calls process.exit — the DSH process belongs to the user.'),\n compact: surface('partial', 'Pi\\'s fire-and-forget trigger, translated to DSH\\'s official manual compaction (ctx.compaction.compactNow on the live agent). onComplete receives the real summary text and the shadowed-content token estimate as tokensBefore; firstKeptEntryId is empty because the DSH log has no Pi entry ids. Without a compaction service the gap flows through Pi\\'s onError callback and the capability ledger.', 'Calls DSH\\'s official compaction.compactNow on the live agent and adapts the outcome onto Pi\\'s onComplete/onError callbacks. With no compaction service mounted the gap flows through onError rather than an exception.'),\n newSession: surface('partial', 'Really creates a DSH session (ctx.sessions.create) with parent lineage; withSession runs against a projection context bound to it, whose sendMessage/sendUserMessage/appendEntry write into THAT session rather than the one the call came from. DSH has no host-level \"current session pointer\" a plugin could move — which session the surface shows stays a host choice, announced once.', 'ctx.sessions.create with parent lineage, then a projection context bound to the new session so everything inside withSession (sendMessage, appendEntry, ...) writes into THAT session.'),\n fork: surface('partial', 'Really forks on DSH\\'s official prefix-fork surface (ctx.sessions.fork with lineage metadata). Anchors are durable-log entries (projected ids \"dsh-<seq>\"); Pi\\'s default position \"before\" is honored, and the boundary shrinks to the nearest completed-turn edge because DSH seeds must not split an open turn. Sidecar entries cannot anchor a fork.', 'ctx.sessions.fork at a durable sequence number decoded from the projected entry id (dsh-<seq>), snapped to the nearest completed-turn edge because a DSH seed must not split an open turn.'),\n navigateTree: surface('partial', 'Expressed through DSH\\'s session model: the DSH tree lives BETWEEN sessions (fork lineage), not inside one log, so navigation forks at the target boundary. summarize runs Pi\\'s vendored branch summarizer over the abandoned durable slice (model call on the DSH llm bridge) and lands the summary as a branch_summary entry in the new session\\'s projection; label lands as a label entry.', 'A fork at the target boundary, plus — when the caller asks for one — Pi\\'s vendored branch summarizer run over the abandoned slice with the DSH llm bridge filling Pi\\'s own streamFn injection point.'),\n switchSession: surface('partial', 'Targets a LIVE DSH session by id (or a Pi-style path whose basename is \"<id>.jsonl\"); withSession runs against its projection. Switching to persisted sessions is host-owned — resume them from the DSH surface first. Which session the surface shows stays a host choice.', 'Resolves the id (or the basename of a Pi-style <id>.jsonl path) against live DSH sessions and binds a projection context to it.'),\n reload: surface('partial', 'Really remounts every mounted package\\'s extension entries through a fresh loader (registrations replaced via the same-name path, event handlers reset), so edited plugin code takes effect. Skills, prompts, and themes are host-managed and reload with dsh itself.', 'Remounts every mounted package\\'s extension entries through a fresh jiti loader: registrations are replaced through the same-name path and handler lists reset, so edited plugin code takes effect without restarting DSH.'),\n})\n\nexport const UI_CONTEXT_RULES: Readonly<Record<string, SurfaceRule>> = Object.freeze({\n notify: surface('full', 'Captured as a command result when applicable and emitted through DSH logging at the severity the caller passed (warning and error log as warnings).', 'Written to the DSH logger at the severity the caller passed, and returned as the command result when the call happens inside one.'),\n setStatus: surface('full', 'Pi\\'s keyed status entries render in the active DSH front door: dsh-TUI\\'s native status line, dsh-pi-tui\\'s public footer-status slot, or package-keyed pills in the bridge\\'s browser half. setStatus(key, undefined) removes exactly one entry.', 'The selected terminal backend owns a package/key-scoped handle: tuiStatus on dsh-TUI, or a replaceable chrome.footer.status contribution on dsh-pi-tui. Browser mode writes BrowserSurfaces by (session, package, key); the client half draws the entries from the bridge route.'),\n setWidget: surface('partial', 'Widgets float in DSH web\\'s lower-right overlay stack, session-scoped: a single-line widget renders as an ambient status pill, taller content opens as a floating card on arrival and collapses to a labelled pill (diagnostics-shaped content gets product rows — file chips, severity dots, locations). setWidget(key, undefined) removes one widget. A component factory runs with a LIVE tui handle: requestRender re-renders the retained component into the same slot, and replacing or clearing the widget disposes it.', 'BrowserSurfaces.setWidget keeps the rendered text per widget key; the client half presents it from the shell overlay (pill or floating card by shape), never as an in-column strip — the strip form could not be dismissed and wore the previous session\\'s content on the new-session screen. Factories get a real driver because packages RETAIN the handle: pi-lens closes over tui and calls requestRender from later tool executions — with an undefined handle that call crashed the tool, far outside any factory-time catch.'),\n select: surface('full', 'Mapped to one native DSH userQuestions single-select request. A terminal-oriented multi-line title becomes DSH\\'s plain heading plus native detail; links render as Markdown on Web and OSC 8 in dsh-TUI without visible escape bytes.', 'One native DSH UserQuestionService request carrying Pi\\'s options as the choices. The turn really blocks until a human answers; the shared dialog projection separates title/body and selects the link encoding the active public renderer consumes.'),\n confirm: surface('full', 'Mapped to one native DSH userQuestions Yes/No request. A terminal-oriented multi-line title becomes DSH\\'s plain heading plus native detail; links render as Markdown on Web and OSC 8 in dsh-TUI without visible escape bytes.', 'One native DSH UserQuestionService request with two choices, using the shared dialog projection for title/body and surface-native links.'),\n input: surface('full', 'Mapped to one native DSH userQuestions free-text request. A terminal-oriented multi-line title becomes DSH\\'s plain heading plus native detail; links render as Markdown on Web and OSC 8 in dsh-TUI without visible escape bytes.', 'One native DSH UserQuestionService free-text request. The shared dialog projection preserves visible copy and link destinations, selects the active renderer\\'s link encoding, and removes duplicate raw-link lines.'),\n editor: surface('partial', 'Mapped to one DSH userQuestions free-text request. The prefill is shown as context but is NOT editable text: the caller receives what the user typed fresh, not an edit of the prefill. Terminal-oriented title formatting uses the same surface-native DSH heading/detail projection.', 'One native DSH UserQuestionService free-text request. DSH has no editable-prefill question type, so the prefill is shown in the question body and the answer comes back as fresh text; link encoding uses the active public renderer.'),\n custom: surface('partial', 'Runs the real Pi component on the terminal front doors: a dsh-TUI full-screen scene or dsh-pi-tui\\'s raw component mount, with width, ANSI frames, raw input, render invalidation, result completion and disposal preserved. Web and headless compositions resolve undefined — Pi\\'s own rpc-mode behavior. The web deliberately projects no TUI (2026-08-29 product decision): the content a scene would carry is served by product surfaces instead (a package\\'s side conversation by the side-chat window, MCP management by the MCP tab), and product-UI command invocations take the same degradation so a component never doubles the window presenting it.', 'The Pi component stays Host-owned behind a transport-neutral relay whose messages are width/lines/input/close. The current local dsh-pi-tui transport wraps that relay with the public UNSTABLE_API_LEVEL=1 mountComponent facade; dsh-TUI keeps its public scene seat. No callback or component object is part of the relay contract, so a future DSH Server/Client split changes only the transport. One scene at a time, opening a new one finishes the previous run.'),\n onTerminalInput: surface('partial', 'Raw terminal input is absent; feature-detected listeners remain disabled.', 'Recorded; no DSH surface produces raw terminal input, and feature-detecting packages keep the listener disabled.'),\n setWorkingMessage: surface('partial', 'A live working message, drawn in DSH\\'s conversation.composer.dock band (under the composer card — the host\\'s ambient-readout seat, where its own stats line sits). Calling with no argument restores the default, i.e. clears it.', 'Recorded per session per package and drawn by the client half\\'s composer-dock seat. Pi\\'s rpc mode is a no-op here (it has no TUI loader); a browser host genuinely can show the text, so the bridge supersedes it.'),\n setWorkingVisible: surface('partial', 'Hides or shows the working chrome (message, indicator, hidden-thinking label) without clearing it — Pi\\'s exact semantics.', 'A flag on the per-package surface view; the client half skips working keys while it is false. Supersedes Pi\\'s rpc-mode no-op with a real visibility switch.'),\n setWorkingIndicator: surface('partial', 'WorkingIndicatorOptions ({frames?: string[]}) project to the frames\\' text in the same composer-dock working chrome. An empty array hides the indicator and frames: undefined restores the default (clears it); animated frames render as their static concatenation — the honest still of the package\\'s own frames.', 'surfaceText projects the frames object to text, recorded like the other working surfaces. Pi\\'s rpc mode ignores the call; the browser host draws the static projection instead.'),\n setHiddenThinkingLabel: surface('partial', 'The label shows in the same working chrome; calling with no argument restores the default, i.e. clears it. DSH owns the thinking block\\'s own presentation, so the label is informational chrome, not a re-render of the block.', 'Recorded per session per package like the other working surfaces. Pi\\'s rpc mode is a no-op here; the browser host shows the text.'),\n setFooter: surface('partial', 'A custom footer factory renders when it can build its component without Pi\\'s TUI, into the conversation.composer.dock band; otherwise the surface stays empty — the same shape as Pi\\'s rpc mode, where no footer factory runs at all. The factory receives the bridge\\'s headless theme.', 'surfaceText calls the factory with the headless theme (and no TUI) and renders the returned component\\'s render(80) output; a factory that needs the TUI throws and degrades to an empty surface.'),\n setHeader: surface('partial', 'A custom header factory renders when it can build its component without Pi\\'s TUI, into DSH\\'s conversation.session.header.utilities seat; otherwise the surface stays empty — the same shape as Pi\\'s rpc mode.', 'surfaceText calls the factory with the headless theme (and no TUI) and renders the component; failures degrade to empty. Drawn by the client half\\'s header-utilities seat.'),\n setTitle: surface('partial', 'Pi\\'s transient window title shows as a frame-wide pill in the bridge\\'s browser half. It deliberately does NOT rename the DSH session: a session title is durable, user-owned and shown in the session list, and quietly rewriting it would outlive the turn that asked.', 'Recorded per session per package and drawn as a pill in the shell.overlay seat, next to the status pills.'),\n pasteToEditor: surface('partial', 'Appends to a per-agent editor buffer readable through getEditorText().', 'Appends to the live composer text and writes it back through the same path as setEditorText — the append is against what the user actually has, not against the package\\'s last write.'),\n setEditorText: surface('partial', 'Stored in a per-agent editor buffer readable through getEditorText().', 'Writes the DSH composer for real. `inputActions.setDraft` is part of the session standard kit every session-scoped slot component receives, so the bridge\\'s own browser half performs the write; the request carries a revision so a repeated call is a new write rather than a no-op. Without a browser (the CLI profile) it falls back to the per-agent buffer, which is what Pi\\'s own non-interactive modes do.'),\n getEditorText: surface('partial', 'Reads the per-agent editor buffer maintained by the bridge.', 'Reads what the composer actually holds: the browser half reports the live draft back to the bridge, so a package sees the user\\'s typing and not only its own writes. With no browser watching, it answers with the last text this package wrote.'),\n addAutocompleteProvider: surface('partial', 'The provider really runs: its completions appear as rows in DSH\\'s own `@` trigger menu, and picking one inserts the value it chose. Providers anchored on a trigger character map exactly; one that completes bare words mid-sentence has no moment to fire in.', 'Pi asks a provider at the cursor on every edit; DSH asks a source after `/` or `@`. The two agree exactly for a provider ANCHORED on a trigger character — an @-mention provider, which is what the ecosystem\\'s provider is — so the bridge builds Pi\\'s provider chain, asks it with the token being typed, and offers the result as rows in DSH\\'s own trigger menu; picking one inserts the value the provider chose. A provider that completes bare words mid-sentence has no DSH moment to fire in and contributes nothing, rather than being given an interaction its author never designed.'),\n setEditorComponent: surface('partial', 'Registration is recorded; no DSH surface mounts a Pi editor component.', 'Kept in bridge state and readable back; no DSH surface consumes it.'),\n getEditorComponent: surface('partial', 'Returns the recorded factory.', 'Returns the factory setEditorComponent recorded.'),\n theme: surface('partial', 'A headless theme whose styling calls return unstyled text.', 'A single headless Theme object whose styling functions return their input unchanged; DSH does the rendering.'),\n getAllThemes: surface('partial', 'Lists the single headless theme.', 'Lists the one headless theme the bridge owns.'),\n getTheme: surface('partial', 'Resolves only the headless theme.', 'Resolves the one headless theme by name.'),\n setTheme: surface('partial', 'Accepts the headless theme; other names report an explicit error result.', 'Accepts the headless theme and returns Pi\\'s explicit error result for any other name, rather than pretending a switch happened.'),\n getToolsExpanded: surface('partial', 'A bridge-local presentation flag.', 'A bridge-local flag; nothing renders from it.'),\n setToolsExpanded: surface('partial', 'A bridge-local presentation flag.', 'A bridge-local flag; nothing renders from it.'),\n})\n\nexport const API_RULES: Readonly<Record<string, SurfaceRule>> = Object.freeze({\n registerTool: {\n level: 'partial',\n detail: 'Registered as a native DSH tool. Text and image results use native DSH content/attachments; unsupported JSON Schema constraints and Pi-only error details are explicitly degraded.',\n design: 'Registered on DSH\\'s own tool registry, so the model sees it in the same catalog and the loop runs it through the same permission and sandbox path. Arguments go through Pi\\'s vendored validateToolArguments inside DSH\\'s prepareArguments hook, which is what gives a Pi tool the coercions (\"7\" to 7) Pi\\'s own gate would have made before its handler ran.',\n },\n unregisterTool: {\n level: 'full',\n detail: 'Disposes the exact native DSH tool registration and removes it from the migrated package registry.',\n design: 'Disposes the exact registration handle kept when the tool was registered, and drops it from the package\\'s own registry.',\n },\n registerCommand: {\n level: 'partial',\n detail: 'Registered in ctx.commands with Pi\\'s never-throw collision semantics: a package re-registering its own name replaces it, and cross-source collisions mount under Pi\\'s numbered scheme (/name-2 — the earlier registration keeps the bare name, where Pi renumbers both). Active terminal-native commands keep their original names; a colliding Pi package command remains reachable with a pi- source prefix. A bridge fallback such as /login is omitted when the Host already owns the command and consumes the same projected authorization service.',\n design: 'Registered on ctx.commands with an input descriptor. Before projection, the selected terminal backend supplies its public native-command ownership set (dsh-pi-tui exports LOCAL_COMMANDS; the legacy dsh-TUI generation remains pinned until its public registry lands). Command policy is capability/surface based, not consumer-package based, and is resolved before registrations so plugin load order cannot create a duplicate.',\n },\n registerShortcut: {\n level: 'partial',\n detail: 'Registration is recorded and introspectable; DSH surfaces feed no terminal key input, so handlers never fire — the same as Pi\\'s non-TUI modes.',\n design: 'Recorded in bridge state; no DSH surface feeds terminal key events, exactly as in Pi\\'s own non-TUI modes.',\n },\n registerFlag: {\n level: 'partial',\n detail: 'The declared default is available through getFlag; Pi process flags cannot be added to the DSH launcher.',\n design: 'The declared default goes into a bridge map. DSH\\'s launcher exposes no seam for adding process flags, so the flag exists for the package\\'s own reads only.',\n },\n getFlag: {\n level: 'partial',\n detail: 'Returns the migrated flag default because DSH cannot register the original Pi CLI flag.',\n design: 'Reads the bridge map registerFlag wrote.',\n },\n registerProvider: {\n level: 'partial',\n detail: 'Two outcomes, by whether the provider carries its own transport. '\n + 'WITH a transport (pi-ai createProvider and friends): it becomes a real DSH llm route through llm.registerAdapter, and from then on the package\\'s own HTTP client carries the turn — its API key or OAuth token is resolved by Pi\\'s credential chain and persisted in the bridge\\'s auth.json, not by DSH credentials. '\n + 'WITHOUT one (catalog-only): protocol, endpoint, credential reference, model capabilities, reasoning levels and the compat fields offered by DSH are translated into the official llm-pi-ai profile; no bridge transport is synthesized. '\n + 'An OAuth-capable provider additionally gets /login <id>, and on hosts that compose the official authorization service (0.1.1 line) it also joins DSH\\'s native sign-in registry as a `pi2dsh/<id>` flow: the flow runs the package\\'s own login, the official sign-out (deleteRecord) removes the bridge\\'s stored login, and the official llm-pi-ai catalog flows coexist in the same listing under their own scope.',\n design: 'Two mechanisms behind one call. A provider carrying its own transport becomes a real DSH route through llm.registerAdapter, and the package\\'s own HTTP client then carries the turn with its key resolved by Pi\\'s credential chain into the bridge\\'s auth.json. A catalog-only declaration becomes configuration for DSH\\'s official llm-pi-ai adapter, which owns credentials and the real HTTP request. Both enter the one DSH model directory. The shared ledger follows Pi\\'s layered composition (model-runtime registerProvider/recomposeProvider at the pinned upstream): the engine\\'s built-in OAuth entries are the base layer, package registrations overlay it field-wise (defined fields win, undefined fields expose the base — a package overriding only the endpoint keeps the builtin OAuth flow), later packages override earlier ones in load order, re-registration merges defined fields over the package\\'s previous registration, and a changed composition rebuilds the route. One adaptation for the long-lived host: overlays are slotted per package so another agent instance\\'s idempotent re-registration cannot perturb cross-package order.',\n },\n unregisterProvider: {\n level: 'partial',\n detail: 'Removes this package\\'s registration; the composed provider recomposes so the builtin base (or the remaining packages\\' overlays) is restored, matching Pi\\'s unregister-restores-builtin contract.',\n design: 'Deletes the package\\'s ledger slot and recomposes the canonical config; a changed composition retires the route built on the old shape. Deviation from Pi noted: Pi\\'s unregister deletes the WHOLE extension layer (safe inside one short-lived session runtime); on the long-lived host ledger only the calling package\\'s slot is removed so one package cannot erase another\\'s registration.',\n },\n registerMessageRenderer: {\n level: 'partial',\n detail: 'The renderer really runs: a custom message the package sent is drawn by the package\\'s own code and shown in the DSH web conversation. What reaches the browser is the component\\'s rendered text, not a mounted Pi component.',\n design: 'A custom message is a durable DSH log entry carrying Pi\\'s role:\"custom\" marker (source.piCustomType), so the projection reads it back from the session through ctx.sessions.get(id) rather than from a cache — the renderer keeps working after a restart. The returned component is projected through its own render(width), and the text takes a seat in the conversation flow.',\n },\n registerEntryRenderer: {\n level: 'partial',\n detail: 'The renderer really runs: entries the package appended are drawn by the package\\'s own code and shown in the DSH web conversation. What reaches the browser is the component\\'s rendered text, not a mounted Pi component.',\n design: 'Custom entries live as Pi entry lines in the per-session Pi-format archive (DSH\\'s durable log has no channel for event types declared outside the harness, so the host\\'s own conversation view can never show them). The registered EntryRenderer runs per entry, its component is projected through render(width), and the text is seated in the conversation flow. A renderer that throws contributes nothing and leaves every other package\\'s entries — and the request — intact.',\n },\n registerMarkdownTransformer: {\n level: 'partial',\n detail: 'Registration is accepted; DSH owns presentation, so the transformer is never invoked — matching Pi\\'s non-TUI surfaces.',\n design: 'Kept in bridge state and readable back; no DSH surface consumes it.',\n },\n sendMessage: {\n level: 'partial',\n detail: 'Durable by the time it returns, as in Pi: the no-turn call appends to the session log and announces its message events immediately, so the message IS in the conversation when the call resolves. Steering and follow-up drive a turn through the agent. Pi display/details metadata awaits the custom session-entry seam.',\n design: 'Two paths under one name. The no-turn call appends through Session.append(type, data, { surfaceOp: \\'append\\' }) — the public marker DSH requires for surface-eligible types — so the message is durable and visible by the time the call resolves, then announces its own message_start/message_end. Steering and follow-up go through the DSH agent inbox instead, which is what actually drives a turn.',\n },\n sendUserMessage: {\n level: 'full',\n detail: 'Mapped to native DSH steer/followup delivery with text and attachment-backed image content.',\n design: 'The DSH agent inbox (steer or follow-up by option), with image content materialized as DSH attachments first.',\n },\n appendEntry: {\n level: 'partial',\n detail: 'Persisted as a genuine Pi custom entry line in the per-session Pi-format archive (the same file getSessionFile() names, parseable by Pi\\'s own SessionManager) and replayed on session start; DSH\\'s main log stays untouched because its persistence read path refuses out-of-vocabulary event types and Session.append cannot set the ignorable escape hatch.',\n design: 'A Pi entry line appended to the session\\'s Pi-format archive file, replayed at session start. These entries are sole originals, not copies of anything native. DSH\\'s own log has no channel for event types declared outside the harness — its read path refuses unknown types without the envelope\\'s ignorable marker, which Session.append cannot set — so writing them there corrupts the session for every other reader. The native registration surface is explicitly deferred upstream \"until such a consumer exists\"; migrating these entries there is the endgame.',\n },\n setSessionName: {\n level: 'full',\n detail: 'Renames the DSH session through ctx.sessionTitle, so every DSH surface shows it and the title is pinned against automatic regeneration, and announces it through session_info_changed. A composition that mounts no title service falls back to a session_info entry in the Pi-format archive, as does a blank name (DSH requires visible characters in a title; Pi does not).',\n design: 'ctx.sessionTitle.rename, which is also what pins the title against DSH\\'s automatic regeneration, followed by a session_info_changed dispatch. A composition with no title service — or a blank name, which DSH refuses and Pi allows — falls back to a session_info entry in the Pi-format archive.',\n },\n getSessionName: {\n level: 'full',\n detail: 'Reads DSH\\'s own session title, so it agrees with what DSH displays and sees titles DSH generated itself; falls back to the archive\\'s session_info entry when no title service is mounted.',\n design: 'ctx.sessionTitle.get, so the answer agrees with what DSH displays and includes titles DSH generated itself; archive session_info fallback when no title service is mounted.',\n },\n setLabel: {\n level: 'partial',\n detail: 'Persisted as a Pi label entry line in the per-session Pi-format archive and reflected by the sessionManager projection.',\n design: 'A Pi label entry line in the session\\'s Pi-format archive, read back through the sessionManager projection.',\n },\n exec: {\n level: 'partial',\n detail: 'Mapped to ctx.subprocess, so the selected local/E2B provider owns execution, isolation, cancellation, and tree cleanup; output is bounded to 64 MiB per stream.',\n design: 'Handed to ctx.subprocess, so the selected local or E2B provider owns execution, isolation, cancellation and process-tree cleanup — the bridge never spawns a child itself.',\n },\n getActiveTools: {\n level: 'partial',\n detail: 'Returns every tool visible in the current DSH agent scope, including native and migrated tools; scope-local tools follow DSH composition rules.',\n design: 'Lists the DSH tool scope the current context belongs to, native and migrated tools alike.',\n },\n getAllTools: {\n level: 'partial',\n detail: 'Returns metadata for all tools visible in the current DSH scope, without Pi-specific prompt guidelines unavailable from DSH schemas.',\n design: 'Reads schemas from the same DSH tool scope; Pi\\'s prompt-guideline fields have no DSH source and are left out rather than invented.',\n },\n setActiveTools: {\n level: 'partial',\n detail: 'Mapped to the active DSH agent scope through tools.restrict, per-agent and without mutating other agents. Names DSH does not know are skipped exactly as Pi skips them. A tool DSH does not permit restricting (a scope\\'s own registration, or a reserved transport name) cannot be deactivated at all and is reported once rather than silently left running.',\n design: 'DSH\\'s scoped tools.restrict, narrowed first. Pi silently skips names its registry does not know, while DSH fails the whole restrict call on a name it cannot restrict — so the list is filtered against what the scope reports as restrictable before it is applied, and a visible-but-unrestrictable tool is reported once instead of being silently left running. Called before an agent exists, the intent is remembered and applied when one starts.',\n },\n getCommands: {\n level: 'partial',\n detail: 'Returns commands registered by this migrated Pi package, not every command visible in the DSH scope.',\n design: 'Reads the bridge\\'s own command map, which holds this package\\'s registrations rather than the whole DSH scope.',\n },\n setModel: {\n level: 'partial',\n detail: 'Recorded as a per-agent override applied through the agent/request waterfall on the next model call; DSH remains authoritative for provider routing.',\n design: 'Recorded as a per-agent override and applied on the agent/request waterfall, so the next model call carries it while DSH stays authoritative for routing.',\n },\n getThinkingLevel: {\n level: 'partial',\n detail: 'Returns the level recorded by setThinkingLevel (default off).',\n design: 'Reads the per-agent level the bridge recorded.',\n },\n setThinkingLevel: {\n level: 'partial',\n detail: 'Recorded per agent and applied as reasoningEffort through the agent/request waterfall; DSH validates the effort id at the request boundary.',\n design: 'Recorded per agent and applied as reasoningEffort on the agent/request waterfall; DSH validates the effort id at the request boundary.',\n },\n events: {\n level: 'full',\n detail: 'Pi\\'s cross-extension event bus: one shared bus per agent, so every Pi package mounted for the same agent hears every other package\\'s emits — matching Pi\\'s one-bus-per-session loader contract. Different agents have different buses.',\n design: 'The bus is keyed on the owning agent in shared host state (host/anchor instances share the host bus). Each instance unwinds only its own subscriptions on dispose/reload, never the other packages\\'.',\n },\n})\n\nconst OBSERVED_NEVER_FIRES = (moment: string): SurfaceRule => ({\n level: 'partial',\n detail: `Registration is accepted; ${moment} never occurs on DSH surfaces, so the handler never fires. Loading is unaffected.`,\n design: `The handler goes into the bridge's handler map like any other, and nothing dispatches it: no DSH seam produces ${moment}. Registration is kept rather than refused so a package that subscribes at load time still loads.`,\n})\n\nexport const EVENT_RULES: Readonly<Record<string, SurfaceRule>> = Object.freeze({\n session_start: { level: 'full', detail: 'Mapped to agent/session-start.', design: 'Dispatched from the cordis agent/session-start notification.' },\n session_shutdown: { level: 'full', detail: 'Mapped to agent disposal and plugin teardown with duplicate suppression.', design: 'Dispatched from agent/disposed and from plugin teardown, with duplicate suppression so a package that sees both gets one event.' },\n session_info_changed: { level: 'partial', detail: 'Fired by setSessionName() and projected from DSH session/title events.', design: 'Two sources, one event: the bridge\\'s own setSessionName, and DSH\\'s durable session title event projected into Pi\\'s shape.' },\n agent_start: { level: 'full', detail: 'Mapped to the DSH turn/start boundary.', design: 'The DSH turn/start boundary from the durable session/event stream. DSH\\'s turn is the whole prompt, which is what Pi calls an agent run.' },\n agent_settled: { level: 'full', detail: 'Mapped to the DSH turn/end boundary.', design: 'The DSH turn/end boundary.' },\n turn_start: { level: 'full', detail: 'Fires once per MODEL CALL, as in Pi — DSH calls that a step — with turnIndex counting from zero and resetting at each new prompt.', design: 'The DSH step/start boundary — one step is one model call, which is what Pi calls a turn. The index resets when a new prompt is claimed off the inbox, matching Pi\\'s reset at agent_start.' },\n tool_execution_start: { level: 'full', detail: 'Mapped from durable tool/call events.', design: 'Projected from the durable tool/call event, so a handler sees exactly what was written to the session log.' },\n tool_execution_end: { level: 'full', detail: 'Mapped from finalized tools/result events.', design: 'Dispatched on DSH\\'s tools/post-execute waterfall and awaited there. Riding the durable result emit instead let the handler land after turn_end, which is the opposite of Pi\\'s order; the waterfall is the moment that is guaranteed to run before the caller sees the result.' },\n tool_execution_update: {\n level: 'partial',\n detail: 'Fired from migrated Pi tools\\' own onUpdate callbacks; DSH-native tools expose no partial-result stream.',\n design: 'Fed by migrated Pi tools\\' own onUpdate callbacks. DSH-native tools expose no partial-result stream, so nothing is synthesized for them.',\n },\n tool_call: {\n level: 'partial',\n detail: 'Blocking is supported, in-place argument mutation reaches migrated Pi tools, and `terminate` follows Pi\\'s batch rule — the loop stops after a tool batch only when every call in it was blocked asking to stop. Mutating a DSH-native tool\\'s arguments is rejected because DSH logs arguments before policy.',\n design: 'DSH\\'s tools/pre-execute waterfall, whose decision type carries exactly the two outcomes Pi needs (proceed, deny with a reason). Pi\\'s in-place argument mutation is applied to migrated Pi tools; for a DSH-native tool it is refused, because DSH logs arguments before policy runs and the log would then disagree with what executed. Pi\\'s batch rule for terminate is reimplemented verbatim: the loop stops only when every finalized call in the batch asked to stop.',\n },\n tool_result: {\n level: 'partial',\n detail: 'Text replacement and success-to-error blocking are supported; arbitrary details and error recovery are not.',\n design: 'The same tools/post-execute waterfall, which is where a result can still be rewritten before the caller reads it.',\n },\n before_agent_start: {\n level: 'full',\n detail: 'Fires once per user prompt, inside the assembly of the turn it belongs to, with the real prompt text and image attachments; returned custom messages enter that same turn beside the user message, and a returned systemPrompt overrides that turn\\'s own assembly and resets at the next turn.',\n design: 'DSH\\'s system-prompt/assemble waterfall — an async waterfall that runs while the prompt is being assembled and whose return value is authoritative. That is why a returned systemPrompt reaches the very turn the handler fired for; the later agent/pre-step waterfall would have been one turn too late. Firing is gated on the inbox claim so it happens once per user prompt, and returned custom messages are held and injected into that same step.',\n },\n agent_end: {\n level: 'partial',\n detail: 'The lifecycle boundary is mapped, but the reconstructed Pi message history is intentionally minimal.',\n design: 'The DSH turn/end boundary. Pi\\'s message history on this event is reconstructed minimally rather than replayed, because the durable log is the honest source and packages that need it read the projection.',\n },\n turn_end: {\n level: 'full',\n detail: 'Fires once per MODEL CALL, as in Pi — DSH calls that a step — carrying that call\\'s own assistant message and its own tool results, with turnIndex counting model calls from zero and resetting each prompt.',\n design: 'The DSH step/end boundary, carrying that model call\\'s own assistant message and the tool results belonging to it.',\n },\n message_start: {\n level: 'partial',\n detail: 'Durable user, assistant, and tool-result messages are mapped without Pi-specific provider metadata.',\n design: 'Projected from durable message events in the session/event stream.',\n },\n message_end: {\n level: 'partial',\n detail: 'Durable messages are observed, but message replacement is not supported.',\n design: 'Projected from the same durable message events; DSH\\'s log is append-only, so Pi\\'s message replacement has nowhere to land.',\n },\n message_update: {\n level: 'partial',\n detail: 'Projected from DSH assistant/chunk events with accumulated text; Pi\\'s full AgentMessage accumulation state is approximated.',\n design: 'Projected from DSH assistant/chunk events with text accumulated by the bridge. Pi\\'s full AgentMessage accumulation state is approximated, not reconstructed.',\n },\n session_before_compact: {\n level: 'partial',\n detail: 'Projected from DSH compaction/start as a notification; cancel/replace cannot reach DSH\\'s compactor.',\n design: 'Projected from DSH\\'s compaction/start as a notification. It is an emit, not a waterfall, so a cancel or a replacement has no channel to reach DSH\\'s compactor and is not pretended.',\n },\n session_compact: {\n level: 'partial',\n detail: 'Fires once per SUCCESSFUL compaction, from DSH\\'s summary event, with the summary rendered to the string Pi\\'s CompactionEntry declares. A manual compaction is identified as manual; DSH does not record which automatic trigger fired, so automatic ones report \"threshold\" and willRetry is always false.',\n design: 'Projected from DSH\\'s compaction summary event, rendered to the exact string Pi\\'s CompactionEntry declares. Manual compactions are identifiable; DSH does not record which automatic trigger fired, so automatic ones report Pi\\'s threshold reason.',\n },\n model_select: {\n level: 'partial',\n detail: 'Fired by setModel() and projected from request/header model changes in the durable log.',\n design: 'Fired by the bridge\\'s own setModel, and projected from model changes in the durable request/header record — which is the call configuration DSH logs, not the HTTP body.',\n },\n thinking_level_select: {\n level: 'partial',\n detail: 'Fired by setThinkingLevel(); DSH-side reasoning changes surface through request/header projection.',\n design: 'Fired by the bridge\\'s own setThinkingLevel; host-side reasoning changes arrive through the same request/header projection.',\n },\n context: {\n level: 'partial',\n detail: 'Fires before each step with the full message projection; the transform applies to the step\\'s not-yet-entered messages (the slice packages rewrite), while already-entered history stays read-only under DSH\\'s append-only log.',\n design: 'DSH\\'s agent/pre-step waterfall, whose decision type distinguishes entering a step from rejecting it. The transform applies to the messages that have not entered the step yet — the slice Pi packages actually rewrite — while entered history stays read-only under DSH\\'s append-only log.',\n },\n before_provider_request: {\n level: 'partial',\n detail: 'Fires with the exact outgoing payload for Pi package-owned transports; native DSH adapters expose no body-builder hook and remain unavailable.',\n design: 'A transport-owning Pi provider is wrapped by pi2dsh as a DSH llm adapter and Pi\\'s standard stream helpers expose the exact pre-fetch body through onPayload, so the waterfall is real there. Native DSH adapters build their body behind their own boundary; without an upstream seam this event cannot honestly fire for them.',\n },\n before_provider_headers: {\n level: 'unsupported',\n detail: 'Provider header mutation belongs in a native DSH LLM adapter; the handler is accepted but never fires.',\n design: 'Deliberately not wired, for the same reason as before_provider_request: headers belong to the adapter that owns the transport.',\n },\n after_provider_response: {\n level: 'unsupported',\n detail: 'Provider response interception belongs in a native DSH LLM adapter; the handler is accepted but never fires.',\n design: 'Deliberately not wired: the response is consumed inside the adapter, and interception there is an adapter concern.',\n },\n user_bash: OBSERVED_NEVER_FIRES('Pi\\'s ! command surface'),\n input: OBSERVED_NEVER_FIRES('raw Pi terminal input'),\n project_trust: {\n level: 'unsupported',\n detail: 'Project trust must remain owned by the DSH host; the handler is accepted but never consulted.',\n design: 'Accepted and never consulted. Trust is a host decision in DSH, and letting a package answer it would move the decision to the code being trusted.',\n },\n resources_discover: {\n level: 'unsupported',\n detail: 'Dynamic resource discovery must be converted into DSH providers; the handler is accepted but never fires.',\n design: 'Accepted and never fired. Dynamic resource discovery in DSH is a provider registration, which is a different (and official) seam.',\n },\n session_before_switch: OBSERVED_NEVER_FIRES('Pi session switching'),\n session_before_fork: OBSERVED_NEVER_FIRES('Pi tree forking'),\n session_before_tree: OBSERVED_NEVER_FIRES('Pi session-tree navigation'),\n session_tree: OBSERVED_NEVER_FIRES('Pi session-tree navigation'),\n})\n\nexport function ruleForApi(method: string): Rule | undefined {\n return API_RULES[method]\n}\n\nexport function ruleForEvent(event: string): Rule {\n return EVENT_RULES[event] ?? {\n level: 'unsupported',\n detail: `Unknown Pi event ${JSON.stringify(event)} has no verified DSH mapping.`,\n }\n}\n\nexport function ruleForHostImport(packageName: string, importedName: string): Rule | undefined {\n const family = (PI_CODING_AGENT_PACKAGES as readonly string[]).includes(packageName)\n ? 'pi-coding-agent'\n : (PI_TUI_PACKAGES as readonly string[]).includes(packageName)\n ? 'pi-tui'\n : (PI_AI_PACKAGES as readonly string[]).includes(packageName) ? 'pi-ai' : undefined\n return family === undefined ? undefined : HOST_IMPORT_RULES[family]?.[importedName]\n}\n\nexport function ruleForContextProperty(property: string): Rule | undefined {\n return CONTEXT_RULES[property]\n}\n\nexport function ruleForUiContextProperty(property: string): Rule | undefined {\n return UI_CONTEXT_RULES[property]\n}\n"],"mappings":"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"}
|
package/dist/host.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { s as registerVisionCompanions, t as applyPiPackage } from "./runtime-
|
|
2
|
+
import { s as registerVisionCompanions, t as applyPiPackage } from "./runtime-BiHMcD_8.mjs";
|
|
3
3
|
import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
import { ot as providePiExtensionDiscovery } from "./pi-coding-agent-CPXFo0UO.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
4
|
+
import { c as runtimeInternals, n as getSharedChildExtensionCatalog, o as registerChildExtensionCatalog, s as registerVisionCompanions } from "./runtime-BiHMcD_8.mjs";
|
|
4
5
|
import { i as renderMcpPatch, n as convertPiMcpConfig, t as collectPiMcpServers } from "./mcp-config-C1K-IzzB.mjs";
|
|
5
6
|
import { t as resolvePiPackage } from "./source-0sA5z08z.mjs";
|
|
6
7
|
import { applyPiHost, applyPreparedPiHost, manifestForInstalled, preparePiHost } from "./host.mjs";
|
|
7
|
-
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-
|
|
8
|
+
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-CZ0QpE76.mjs";
|
|
8
9
|
import { readFile } from "node:fs/promises";
|
|
9
10
|
import { existsSync, realpathSync } from "node:fs";
|
|
10
11
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -317,6 +318,7 @@ const inject = [
|
|
|
317
318
|
"skills"
|
|
318
319
|
];
|
|
319
320
|
async function apply(ctx, config = {}) {
|
|
321
|
+
if (process.env.PI_CODING_AGENT_DIR === void 0 || process.env.PI_CODING_AGENT_DIR === "") process.env.PI_CODING_AGENT_DIR = getAgentDir();
|
|
320
322
|
const log = ctx.logger;
|
|
321
323
|
const warn = (message) => {
|
|
322
324
|
log?.warn?.(message);
|
|
@@ -407,7 +409,7 @@ async function apply(ctx, config = {}) {
|
|
|
407
409
|
* @returns the compatibility report.
|
|
408
410
|
*/
|
|
409
411
|
async function analyzePackage(pkg) {
|
|
410
|
-
const { analyzePackage: run } = await import("./analyzer-
|
|
412
|
+
const { analyzePackage: run } = await import("./analyzer-DqsrD1FG.mjs");
|
|
411
413
|
return run(pkg);
|
|
412
414
|
}
|
|
413
415
|
//#endregion
|
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, realpathSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { applyPreparedPiHost, preparePiHost, type PreparedPiHostPackage } from './host.js'\nimport { getSharedChildExtensionCatalog, registerChildExtensionCatalog, registerVisionCompanions, runtimeInternals } from './runtime.js'\nimport { providePiExtensionDiscovery } from './compat/pi-coding-agent.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 * Serve the browser presentation surfaces (the `/pi2dsh` state route the\n * web renderer polls, and with it the `mode: 'tui'` claim on the web\n * composition). Default: OFF — the engine alone projects nothing into the\n * browser, so a web session behaves exactly like the headless CLI (Pi's\n * own rpc mode; packages degrade gracefully on their own). The dsh-work-x\n * suite turns this on and carries the actual renderer in its client\n * bundle; any other product layer that ships a renderer can do the same.\n */\n browserPresentation?: boolean\n /**\n * Serve DSH-native subagents with the profile's Pi packages (default: OFF —\n * such children run as plain DSH agents, today's behavior). Children the Pi\n * subagent bridge mints are NEVER covered: they already receive the creator's\n * own per-spawn loader mount and are recognized by the `pi2dsh-sub-` session-id\n * prefix.\n */\n serveNativeSubagents?: boolean\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 /** Resolution anchor when the package is carried by a suite (its members\n * are the suite's dependencies, unreachable from the profile root under\n * pnpm's isolated layout). */\n anchor?: 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 suite: `pi2dsh: { suite: [names...] }` mounts the listed Pi packages\n // as if the user had added each one. The list is an explicit manifest —\n // the same discovery covenant as the profile dependency list, one hop\n // deeper — and the members are the suite's own dependencies, so each\n // resolves anchored at the suite package (pnpm keeps transitive\n // dependencies out of the profile root). One level only, no recursion.\n const suite = (packageJson.pi2dsh as { suite?: unknown } | undefined)?.suite\n if (Array.isArray(suite)) {\n // The anchor must be the suite's REAL directory: the profile's\n // node_modules entry is a pnpm symlink into .pnpm, and Node resolution\n // walks up from the anchor's literal path — only the realpath has the\n // suite's own dependencies as .pnpm neighbours.\n let anchorDir = dir\n try {\n anchorDir = realpathSync(dir)\n } catch { /* an unreadable dir keeps the literal path and fails loud in prepare */ }\n for (const member of suite) {\n if (typeof member !== 'string' || member.length === 0) continue\n if (member === 'pi2dsh' || excluded.has(member)) continue\n discovered.push({ name: member, dir, anchor: join(anchorDir, 'package.json') })\n }\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 // One mount per name. A package that is both a direct dependency and a\n // suite member mounts as the DIRECT dependency (the user's own explicit\n // add, resolved from the profile root) — the suite copy yields.\n const byName = new Map<string, DiscoveredPackage>()\n for (const pkg of discovered) {\n const existing = byName.get(pkg.name)\n if (existing === undefined || (existing.anchor !== undefined && pkg.anchor === undefined)) {\n byName.set(pkg.name, pkg)\n }\n }\n return [...byName.values()]\n}\n\ninterface AgentScopedMount {\n ready: Promise<void>\n /** Set when the mount failed; the agent then runs as a plain DSH agent. */\n failure?: string\n}\n\n/** The loose shapes of the official DSH seams this file consumes. */\ninterface AgentLike {\n ctx: Context\n}\ninterface EngineHostContext {\n /** Un-injected reflection access (the ctx.get('loader') idiom): the engine\n * must not hard-depend on the agent registry — compositions without one\n * (bare test hosts) simply have no agents to mount for. */\n get?(name: string): unknown\n tools?: { schemas?(scope: unknown): Array<{ name: string }> }\n on(name: string, listener: (...args: never[]) => unknown): () => void\n}\ninterface AgentRegistryLike {\n roots?(): AgentLike[]\n}\n\n/**\n * The single mount path on every DSH surface: one Pi runtime per root Agent.\n *\n * Pi instantiates its extensions once per session; DSH's twin of that scope is\n * the Agent with its public `agent.ctx` (\"contributions are agent-local,\n * unwind on disposal\"). Mounting is driven purely by official core seams, so\n * the same semantics hold on the TUI, web, headless, ACP and config-declared\n * agents alike:\n *\n * - `agent/created` fires on every publication path before the loop can run\n * a first turn; it eagerly starts that agent's mount.\n * - `system-prompt/assemble` (awaited waterfall, runs in every step's\n * preStep) gates the assembly on the mount and patches the pre-waterfall\n * tools snapshot from the official scoped projection `tools.schemas()` —\n * stock DSH collects `assembly.tools` before dispatching the waterfall,\n * so a mount that lands during the wait would otherwise miss turn one.\n * - `tools/pre-execute` (awaited waterfall) closes the same window for\n * direct executions that bypass assembly.\n *\n * `agent/session-start` deliberately is NOT the trigger: DSH documents it as a\n * veto-less notification that cannot gate startup. The waterfalls above are\n * the officially awaited seams, and the exact pattern of registering onto a\n * foreign agent's ctx from a lifecycle event is what DSH's own schedule\n * plugin ships.\n *\n * A mount failure never takes the Agent down: the agent keeps running as a\n * plain DSH agent, the failure is reported loudly once, and only the Pi\n * packages are missing — the capability-gap discipline, not a rollback.\n */\nexport function installAgentScopedMounts(\n ctx: Context,\n preparedPackages: Promise<readonly PreparedPiHostPackage[]>,\n report: { warn(message: string): void },\n): void {\n const host = ctx as unknown as EngineHostContext\n const mounts = new WeakMap<object, AgentScopedMount>()\n\n const registry = (): AgentRegistryLike | undefined => {\n try {\n return host.get?.('agents') as AgentRegistryLike | undefined\n } catch {\n return undefined\n }\n }\n\n const isRootAgent = (agent: object): boolean => {\n // Subagents keep Pi's own sub-session semantics through the session\n // bridge; only runtime roots receive a Pi runtime (the same distinction\n // DSH's schedule plugin draws via agents.roots()).\n const agents = registry()\n const roots = agents?.roots\n if (typeof roots !== 'function') return true\n try {\n return (roots.call(agents) as unknown[]).includes(agent)\n } catch {\n return true\n }\n }\n\n const ensureMount = (agent: AgentLike): AgentScopedMount => {\n let mount = mounts.get(agent)\n if (mount === undefined) {\n const started: AgentScopedMount = { ready: Promise.resolve() }\n started.ready = preparedPackages.then(async prepared => {\n if (prepared.length === 0) return\n try {\n await applyPreparedPiHost(agent.ctx, prepared, agent as unknown as Record<string, unknown>)\n } catch (error) {\n // Loud, once per agent; the gates resolve so the plain DSH agent\n // keeps working. Faking success is forbidden — the message names\n // what is missing.\n started.failure = error instanceof Error ? error.message : String(error)\n report.warn(`[pi2dsh engine] Pi packages failed to mount for this agent; it continues without them: ${started.failure}`)\n }\n })\n mounts.set(agent, started)\n mount = started\n }\n return mount\n }\n\n // Eager start on publication. `agent/created` reaches host-level listeners\n // on every create/resume/config path, before the loop can open a turn.\n host.on('agent/created', ((payload: { agent: AgentLike }) => {\n if (isRootAgent(payload.agent)) ensureMount(payload.agent)\n }) as never)\n\n // Correctness boundary #1: no prompt assembly for a root agent proceeds\n // before its Pi runtime is mounted, and the tools snapshot taken before\n // this waterfall is reconciled against the official scoped projection.\n host.on('system-prompt/assemble', (async (\n assembly: { tools: Array<{ name: string }> },\n context: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = context.agent\n if (agent !== undefined && isRootAgent(agent)) {\n await ensureMount(agent).ready\n const schemas = host.tools?.schemas\n if (typeof schemas === 'function') {\n const present = new Set(assembly.tools.map(tool => tool.name))\n for (const schema of schemas.call(host.tools, agent)) {\n if (!present.has(schema.name)) assembly.tools.push(schema)\n }\n }\n }\n return next()\n }) as never)\n\n // Correctness boundary #2: tool execution for a root agent waits for the\n // same mount (serially awaited by the tool runtime before dispatch).\n host.on('tools/pre-execute', (async (\n exec: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n if (exec.agent !== undefined && isRootAgent(exec.agent)) await ensureMount(exec.agent).ready\n return next()\n }) as never)\n\n // Backfill: agents published before this plugin finished loading (a surface\n // that skips the official await-the-loader pattern DSH's headless runner\n // uses). Their next assembly still passes the gates above.\n void preparedPackages.then(() => {\n const agents = registry()\n const roots = agents?.roots\n if (typeof roots !== 'function') return\n for (const agent of roots.call(agents)) ensureMount(agent)\n })\n}\n\n/** Session-id prefix minted by the Pi subagent bridge (src/subagent-bridge.ts). */\nexport const BRIDGE_CHILD_SESSION_ID_PREFIX = 'pi2dsh-sub-'\n\n/**\n * Optional coverage for DSH-native subagents, enabled by the\n * `serveNativeSubagents` engine config.\n *\n * The Pi subagent bridge already serves the children IT mints: the creator's\n * per-spawn loader mount (a8b7a0a) runs at creation and again on a persisted\n * resume. This covers the OTHER lineage — children a DSH surface mints\n * directly (DSH-native delegation, headless subagents, a second agent in the\n * web UI) — which carry no Pi lineage and would otherwise run as plain DSH\n * agents with none of the profile's Pi extensions.\n *\n * One lineage check per created Agent (maintainer point 2): subagent origin\n * AND a session id that does not carry the bridge prefix. The bridge mints\n * `pi2dsh-sub-` ids at creation and a persisted resume keeps the original id,\n * so the skip holds on both bridge paths and a bridge child is never mounted\n * twice.\n *\n * The mount reuses the engine's own child-extension catalog (maintainer\n * point 3) — the same object the bridge's hook consumes — so a native child's\n * tool set is exactly Pi's default-discovered set (the catalog's no-loader\n * path), the mount lands on the child's OWN ctx and unwinds with the child,\n * and there is no second registration path to drift out of sync.\n *\n * Partition with the root-mount path: agents the registry reports as runtime\n * roots are installAgentScopedMounts' territory (it gates them the same way\n * this path does). Live delegation shows a DSH-native child of a top-level\n * session CAN be a runtime root — serving it here as well raced two mount\n * passes onto the same scope (each package survived via the prompt-section\n * guard, but the double attempt is exactly what this flag must not do). This\n * listener therefore serves exactly the remainder: subagent-origin,\n * non-bridge, non-root agents. The predicate is the root path's own, applied\n * at the same event; its fail-open (roots() unavailable ⇒ every agent is a\n * root) mirrors here as fail-closed (this listener serves nothing).\n *\n * The readiness promise is memoized on the child's SCOPE (agent.ctx), not the\n * agent object: a re-announced agent for the same session reuses the scope,\n * and the dedupe must key on what the mount actually lands in.\n *\n * First-turn gates mirror the root path's exactly: the child's first prompt\n * assembly and its direct tool executions await the mount, and the\n * pre-waterfall tools snapshot is reconciled against the official scoped\n * projection. Without the gate a mount that lands after the first turn's\n * snapshot leaves the child's first (and sometimes only) turn tool-less —\n * proven live at depth 2, where the child's grandchild saw zero extension\n * tools because its mount raced its first model call.\n *\n * A mount failure never takes the child down: the same capability-gap\n * discipline as root mounting — the child keeps running as a plain DSH agent\n * and the failure is reported loudly once.\n */\nexport function installNativeSubagentMounts(\n ctx: Context,\n preparedPackages: Promise<readonly PreparedPiHostPackage[]>,\n enabled: boolean,\n report: { warn(message: string): void },\n): void {\n if (!enabled) return\n const host = ctx as unknown as EngineHostContext\n\n // The root path's own predicate, applied at the same event it applies its\n // (see installAgentScopedMounts): a runtime root is served — and gated —\n // there. Failing closed keeps the partition exact when roots() is absent.\n const isRootAgent = (agent: object): boolean => {\n let agents: AgentRegistryLike | undefined\n try {\n agents = host.get?.('agents') as AgentRegistryLike | undefined\n } catch {\n return true\n }\n const roots = agents?.roots\n if (typeof roots !== 'function') return true\n try {\n return (roots.call(agents) as unknown[]).includes(agent)\n } catch {\n return true\n }\n }\n\n // child scope (agent.ctx) -> its mount's readiness. Reading the catalog\n // after preparation (never before) covers children published while the\n // engine was still preparing; no catalog = plain child, exactly the bridge\n // hook's no-catalog behavior.\n const mounts = new WeakMap<object, Promise<void>>()\n\n const ensureMount = (agent: AgentLike): Promise<void> => {\n const scope = agent.ctx\n let ready = mounts.get(scope)\n if (ready === undefined) {\n ready = preparedPackages.then(async () => {\n const catalog = getSharedChildExtensionCatalog(ctx)\n if (catalog === undefined) return\n // Native children have no creator loader: the full discovered set is\n // Pi's default discovery (the no-loader path of\n // resolveChildExtensionPackages).\n const names = [...new Set(catalog.packageByEntryPath.values())]\n if (names.length === 0) return\n try {\n const failures = await catalog.mount(agent as unknown as Record<string, unknown>, names)\n for (const failure of failures) {\n // Same message shape the bridge's own mount path uses.\n report.warn(`[pi2dsh] child extension ${failure.name} did not mount: ${failure.error}`)\n }\n } catch (error) {\n report.warn(`[pi2dsh] child extension mount failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n })\n mounts.set(scope, ready)\n }\n return ready\n }\n\n const handle = (agent: AgentLike): void => {\n // The single lineage check: DSH-native subagents only. Pi-origin\n // (bridge) children are already served by the creator's per-spawn loader\n // mount; the `pi2dsh-sub-` prefix identifies them on creation AND on a\n // persisted resume, where the original session id survives.\n if (!runtimeInternals.isSubagentOrigin(agent as unknown as Record<string, unknown>)) return\n const session = (agent as { session?: { id?: unknown } }).session ?? agent\n if (String((session as { id?: unknown }).id ?? '').startsWith(BRIDGE_CHILD_SESSION_ID_PREFIX)) return\n // Runtime roots are the root-mount path's territory; serving them here\n // would race a second mount onto the same scope.\n if (isRootAgent(agent)) return\n void ensureMount(agent)\n }\n\n host.on('agent/created', ((payload: { agent: AgentLike }) => {\n if (payload.agent !== undefined) handle(payload.agent)\n }) as never)\n\n // Correctness boundary #1 (mirror of the root path's): no prompt assembly\n // for a served child proceeds before its mount lands, and the pre-waterfall\n // tools snapshot is reconciled against the official scoped projection.\n host.on('system-prompt/assemble', (async (\n assembly: { tools: Array<{ name: string }> },\n context: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = context.agent\n const ready = agent === undefined ? undefined : mounts.get(agent.ctx)\n if (ready !== undefined) {\n await ready\n const schemas = host.tools?.schemas\n if (typeof schemas === 'function') {\n const present = new Set(assembly.tools.map(tool => tool.name))\n for (const schema of schemas.call(host.tools, agent)) {\n if (!present.has(schema.name)) assembly.tools.push(schema)\n }\n }\n }\n return next()\n }) as never)\n\n // Correctness boundary #2 (mirror of the root path's): direct tool\n // executions for a served child wait for the same mount.\n host.on('tools/pre-execute', (async (\n exec: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = exec.agent\n const ready = agent === undefined ? undefined : mounts.get(agent.ctx)\n if (ready !== undefined) await ready\n return next()\n }) as never)\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 // The single mount path, before any await: gates and lifecycle listeners\n // must exist the moment a surface can publish its first Agent. Package\n // preparation resolves behind this promise; the gates hold each agent's\n // first assembly until its own mount lands.\n let resolvePrepared!: (prepared: readonly PreparedPiHostPackage[]) => void\n const preparedPackages = new Promise<readonly PreparedPiHostPackage[]>(resolve => {\n resolvePrepared = resolve\n })\n installAgentScopedMounts(ctx, preparedPackages, { warn })\n installNativeSubagentMounts(ctx, preparedPackages, config.serveNativeSubagents === true, { warn })\n\n registerVisionCompanions(ctx, config.visionCompanions)\n\n try {\n // The host half, mounted exactly once regardless of packages or agents:\n // Pi's built-in provider directory, `/login`, and credential recovery.\n // Without it a fresh engine cannot run `/login openai-codex`: DSH treats\n // the unknown slash line as a model prompt and fails on the unrelated\n // default provider credential. Community packages join the same\n // SharedHostState (keyed on ctx.root), so host-level resources stay\n // single-instance no matter which agent scope mounts them.\n await applyPreparedPiHost(ctx, [{\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\n const packages: Array<{ name: string, anchor?: string }> = Array.isArray(config.packages) && config.packages.length > 0\n ? config.packages.map(name => ({ name }))\n : await discoverProfilePiPackages(profileRoot, {\n ...(Array.isArray(config.exclude) ? { exclude: config.exclude } : {}),\n warn,\n })\n if (packages.length === 0) {\n info('[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>')\n resolvePrepared([])\n return\n }\n info(`[pi2dsh engine] preparing ${packages.length} Pi package(s): ${packages.map(pkg => pkg.name).join(', ')}`)\n const prepared = await preparePiHost(\n {\n packages: packages.map(pkg =>\n pkg.anchor === undefined ? { name: pkg.name } : { name: pkg.name, anchor: pkg.anchor }),\n },\n join(profileRoot, 'package.json'),\n )\n // Child-extension catalog: what real Pi's createAgentSession \"default-\n // discovered extensions\" means on this host. Entries are each package's\n // DECLARED pi extension files (absolute, inside the installed dir), so a\n // creator's own filter code (pi-subagents' extensions/exclude/ext:\n // machinery) canonicalizes them exactly as it does on Pi. Mounting lands\n // on the child agent's OWN ctx — contributions unwind with the agent,\n // which is what makes per-child instances leak-free by construction.\n const entryCatalog = new Map<string, string>()\n for (const pkg of prepared) {\n const rootDir = fileURLToPath(pkg.rootUrl)\n // Resolved keys, because the consumer looks entries up by resolved path.\n for (const rel of pkg.manifest.extensions) entryCatalog.set(resolve(rootDir, rel), pkg.name)\n }\n providePiExtensionDiscovery([...entryCatalog.keys()].map(path => ({ path })))\n registerChildExtensionCatalog(ctx, {\n packageByEntryPath: entryCatalog,\n mount: async (childAgent, packageNames) => {\n const wanted = new Set(packageNames)\n const subset = prepared.filter(pkg => wanted.has(pkg.name))\n const scope = (childAgent as { ctx?: Context }).ctx\n if (scope === undefined) {\n return subset.map(pkg => ({ name: pkg.name, error: 'the child agent exposes no ctx scope to mount into' }))\n }\n return applyPreparedPiHost(scope, subset, childAgent)\n },\n })\n\n // Host anchors, before the per-Agent gates open: every package's\n // HOST-level contributions (provider routes, OAuth accounts, /login,\n // credential recovery, companions, skills) exist from engine apply — a\n // surface with zero live Agents (web at boot) still advertises them, the\n // first Agent's model resolution finds its routes, and routes survive\n // Agent churn. Anchors serve no Agent; sessions belong to the per-Agent\n // instances the gates mount.\n // The engine-level browserPresentation flag rides into every package\n // mount's config: the /pi2dsh route (and the web `mode: 'tui'` claim)\n // exists only when a product layer configured a renderer. Stamped here\n // rather than defaulted in the runtime so per-Agent remounts and the\n // host anchor agree on one answer.\n const presented = config.browserPresentation === true\n ? prepared.map(pkg => ({ ...pkg, config: { ...(pkg.config ?? {}), browserPresentation: true } }))\n : prepared\n await applyPreparedPiHost(ctx, presented, undefined, { hostAnchor: true })\n resolvePrepared(presented)\n } catch (error) {\n // The gates must never hang on a failed preparation; agents keep running\n // as plain DSH agents while the engine failure propagates loudly.\n resolvePrepared([])\n throw error\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, installAgentScopedMounts, 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":";;;;;;;;;;;;;AAgEA,SAAgB,gBAAgB,OAAmC;CACjE,IAAI,MAAM;CACV,SAAS;EACP,IAAI,WAAW,KAAK,KAAK,YAAY,CAAC,KAAK,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG,OAAO;EACzF,MAAM,SAAS,QAAQ,GAAG;EAC1B,IAAI,WAAW,KAAK,OAAO,KAAA;EAC3B,MAAM;CACR;AACF;AAgBA,eAAe,oBAAoB,aAA+C;CAChF,OAAO,KAAK,MAAM,MAAM,SAAS,KAAK,aAAa,cAAc,GAAG,MAAM,CAAC;AAC7E;AAEA,SAAS,qBAAqB,aAAqB,MAAkC;CAGnF,MAAM,MAAM,KAAK,aAAa,gBAAgB,IAAI;CAClD,OAAO,WAAW,KAAK,KAAK,cAAc,CAAC,IAAI,MAAM,KAAA;AACvD;;;;;;;AAQA,eAAsB,0BACpB,aACA,UAAoE,CAAC,GACvC;CAC9B,MAAM,OAAO,QAAQ,eAAe,CAAC;CACrC,MAAM,WAAW,IAAI,IAAI,QAAQ,WAAW,CAAC,CAAC;CAC9C,MAAM,WAAW,MAAM,oBAAoB,WAAW;CACtD,MAAM,aAAkC,CAAC;CACzC,KAAK,MAAM,QAAQ,OAAO,KAAK,SAAS,gBAAgB,CAAC,CAAC,GAAG;EAC3D,IAAI,SAAS,YAAY,SAAS,IAAI,IAAI,GAAG;EAC7C,MAAM,MAAM,qBAAqB,aAAa,IAAI;EAClD,IAAI,QAAQ,KAAA,GAAW;GACrB,KAAK,8BAA8B,KAAK,UAAU,IAAI,EAAE,8CAA8C;GACtG;EACF;EACA,IAAI;EACJ,IAAI;GACF,cAAc,KAAK,MAAM,MAAM,SAAS,KAAK,KAAK,cAAc,GAAG,MAAM,CAAC;EAC5E,SAAS,OAAO;GACd,KAAK,+BAA+B,KAAK,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,YAAY;GAC7H;EACF;EAOA,MAAM,QAAS,YAAY,QAA4C;EACvE,IAAI,MAAM,QAAQ,KAAK,GAAG;GAKxB,IAAI,YAAY;GAChB,IAAI;IACF,YAAY,aAAa,GAAG;GAC9B,QAAQ,CAA2E;GACnF,KAAK,MAAM,UAAU,OAAO;IAC1B,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAAG;IACvD,IAAI,WAAW,YAAY,SAAS,IAAI,MAAM,GAAG;IACjD,WAAW,KAAK;KAAE,MAAM;KAAQ;KAAK,QAAQ,KAAK,WAAW,cAAc;IAAE,CAAC;GAChF;GACA;EACF;EAEA,IAAK,YAAY,KAA0C,WAAW,KAAA,GAAW;EACjF,IAAI,YAAY,OAAO,KAAA,KAAa,OAAO,YAAY,OAAO,UAAU;GACtE,WAAW,KAAK;IAAE;IAAM;GAAI,CAAC;GAC7B;EACF;EAIA,IAAI;GACF,MAAM,MAAM,MAAM,iBAAiB,GAAG;GACtC,IAAI;IACF,IAAI,IAAI,UAAU,WAAW,SAAS,GAAG,WAAW,KAAK;KAAE;KAAM;IAAI,CAAC;GACxE,UAAU;IACR,MAAM,IAAI,QAAQ;GACpB;EACF,QAAQ,CAER;CACF;CAIA,MAAM,yBAAS,IAAI,IAA+B;CAClD,KAAK,MAAM,OAAO,YAAY;EAC5B,MAAM,WAAW,OAAO,IAAI,IAAI,IAAI;EACpC,IAAI,aAAa,KAAA,KAAc,SAAS,WAAW,KAAA,KAAa,IAAI,WAAW,KAAA,GAC7E,OAAO,IAAI,IAAI,MAAM,GAAG;CAE5B;CACA,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,yBACd,KACA,kBACA,QACM;CACN,MAAM,OAAO;CACb,MAAM,yBAAS,IAAI,QAAkC;CAErD,MAAM,iBAAgD;EACpD,IAAI;GACF,OAAO,KAAK,MAAM,QAAQ;EAC5B,QAAQ;GACN;EACF;CACF;CAEA,MAAM,eAAe,UAA2B;EAI9C,MAAM,SAAS,SAAS;EACxB,MAAM,QAAQ,QAAQ;EACtB,IAAI,OAAO,UAAU,YAAY,OAAO;EACxC,IAAI;GACF,OAAQ,MAAM,KAAK,MAAM,CAAC,CAAe,SAAS,KAAK;EACzD,QAAQ;GACN,OAAO;EACT;CACF;CAEA,MAAM,eAAe,UAAuC;EAC1D,IAAI,QAAQ,OAAO,IAAI,KAAK;EAC5B,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,UAA4B,EAAE,OAAO,QAAQ,QAAQ,EAAE;GAC7D,QAAQ,QAAQ,iBAAiB,KAAK,OAAM,aAAY;IACtD,IAAI,SAAS,WAAW,GAAG;IAC3B,IAAI;KACF,MAAM,oBAAoB,MAAM,KAAK,UAAU,KAA2C;IAC5F,SAAS,OAAO;KAId,QAAQ,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KACvE,OAAO,KAAK,0FAA0F,QAAQ,SAAS;IACzH;GACF,CAAC;GACD,OAAO,IAAI,OAAO,OAAO;GACzB,QAAQ;EACV;EACA,OAAO;CACT;CAIA,KAAK,GAAG,mBAAmB,YAAkC;EAC3D,IAAI,YAAY,QAAQ,KAAK,GAAG,YAAY,QAAQ,KAAK;CAC3D,EAAW;CAKX,KAAK,GAAG,2BAA2B,OACjC,UACA,SACA,SACG;EACH,MAAM,QAAQ,QAAQ;EACtB,IAAI,UAAU,KAAA,KAAa,YAAY,KAAK,GAAG;GAC7C,MAAM,YAAY,KAAK,CAAC,CAAC;GACzB,MAAM,UAAU,KAAK,OAAO;GAC5B,IAAI,OAAO,YAAY,YAAY;IACjC,MAAM,UAAU,IAAI,IAAI,SAAS,MAAM,KAAI,SAAQ,KAAK,IAAI,CAAC;IAC7D,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,OAAO,KAAK,GACjD,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,GAAG,SAAS,MAAM,KAAK,MAAM;GAE7D;EACF;EACA,OAAO,KAAK;CACd,EAAW;CAIX,KAAK,GAAG,sBAAsB,OAC5B,MACA,SACG;EACH,IAAI,KAAK,UAAU,KAAA,KAAa,YAAY,KAAK,KAAK,GAAG,MAAM,YAAY,KAAK,KAAK,CAAC,CAAC;EACvF,OAAO,KAAK;CACd,EAAW;CAKX,iBAAsB,WAAW;EAC/B,MAAM,SAAS,SAAS;EACxB,MAAM,QAAQ,QAAQ;EACtB,IAAI,OAAO,UAAU,YAAY;EACjC,KAAK,MAAM,SAAS,MAAM,KAAK,MAAM,GAAG,YAAY,KAAK;CAC3D,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,4BACd,KACA,kBACA,SACA,QACM;CACN,IAAI,CAAC,SAAS;CACd,MAAM,OAAO;CAKb,MAAM,eAAe,UAA2B;EAC9C,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,QAAQ;EAC9B,QAAQ;GACN,OAAO;EACT;EACA,MAAM,QAAQ,QAAQ;EACtB,IAAI,OAAO,UAAU,YAAY,OAAO;EACxC,IAAI;GACF,OAAQ,MAAM,KAAK,MAAM,CAAC,CAAe,SAAS,KAAK;EACzD,QAAQ;GACN,OAAO;EACT;CACF;CAMA,MAAM,yBAAS,IAAI,QAA+B;CAElD,MAAM,eAAe,UAAoC;EACvD,MAAM,QAAQ,MAAM;EACpB,IAAI,QAAQ,OAAO,IAAI,KAAK;EAC5B,IAAI,UAAU,KAAA,GAAW;GACvB,QAAQ,iBAAiB,KAAK,YAAY;IACxC,MAAM,UAAU,+BAA+B,GAAG;IAClD,IAAI,YAAY,KAAA,GAAW;IAI3B,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,QAAQ,mBAAmB,OAAO,CAAC,CAAC;IAC9D,IAAI,MAAM,WAAW,GAAG;IACxB,IAAI;KACF,MAAM,WAAW,MAAM,QAAQ,MAAM,OAA6C,KAAK;KACvF,KAAK,MAAM,WAAW,UAEpB,OAAO,KAAK,4BAA4B,QAAQ,KAAK,kBAAkB,QAAQ,OAAO;IAE1F,SAAS,OAAO;KACd,OAAO,KAAK,0CAA0C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;IAChH;GACF,CAAC;GACD,OAAO,IAAI,OAAO,KAAK;EACzB;EACA,OAAO;CACT;CAEA,MAAM,UAAU,UAA2B;EAKzC,IAAI,CAAC,iBAAiB,iBAAiB,KAA2C,GAAG;EACrF,MAAM,UAAW,MAAyC,WAAW;EACrE,IAAI,OAAQ,QAA6B,MAAM,EAAE,CAAC,CAAC,WAAA,aAAyC,GAAG;EAG/F,IAAI,YAAY,KAAK,GAAG;EACxB,YAAiB,KAAK;CACxB;CAEA,KAAK,GAAG,mBAAmB,YAAkC;EAC3D,IAAI,QAAQ,UAAU,KAAA,GAAW,OAAO,QAAQ,KAAK;CACvD,EAAW;CAKX,KAAK,GAAG,2BAA2B,OACjC,UACA,SACA,SACG;EACH,MAAM,QAAQ,QAAQ;EACtB,MAAM,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO,IAAI,MAAM,GAAG;EACpE,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM;GACN,MAAM,UAAU,KAAK,OAAO;GAC5B,IAAI,OAAO,YAAY,YAAY;IACjC,MAAM,UAAU,IAAI,IAAI,SAAS,MAAM,KAAI,SAAQ,KAAK,IAAI,CAAC;IAC7D,KAAK,MAAM,UAAU,QAAQ,KAAK,KAAK,OAAO,KAAK,GACjD,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,GAAG,SAAS,MAAM,KAAK,MAAM;GAE7D;EACF;EACA,OAAO,KAAK;CACd,EAAW;CAIX,KAAK,GAAG,sBAAsB,OAC5B,MACA,SACG;EACH,MAAM,QAAQ,KAAK;EACnB,MAAM,QAAQ,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO,IAAI,MAAM,GAAG;EACpE,IAAI,UAAU,KAAA,GAAW,MAAM;EAC/B,OAAO,KAAK;CACd,EAAW;AACb;;AAGA,MAAa,OAAO;AACpB,MAAa,SAAS;CAAC;CAAS;CAAgB;CAAY;AAAQ;AAEpE,eAAsB,MAAM,KAAc,SAAuB,CAAC,GAAkB;CAGlF,MAAM,MAAO,IAAmF;CAChG,MAAM,QAAQ,YAA0B;EAAE,KAAK,OAAO,OAAO;EAAG,QAAQ,KAAK,OAAO;CAAE;CACtF,MAAM,QAAQ,YAA0B;EAAE,KAAK,OAAO,OAAO;EAAG,QAAQ,IAAI,OAAO;CAAE;CAKrF,MAAM,UAAW,IAAwC;CACzD,MAAM,eAAe,YAAY,KAAA,IAAY,gBAAgB,cAAc,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC,IAAI,KAAA,MAChG,gBAAgB,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC;CAC5D,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,8IAA8I;CAOhK,IAAI;CACJ,MAAM,mBAAmB,IAAI,SAA0C,YAAW;EAChF,kBAAkB;CACpB,CAAC;CACD,yBAAyB,KAAK,kBAAkB,EAAE,KAAK,CAAC;CACxD,4BAA4B,KAAK,kBAAkB,OAAO,yBAAyB,MAAM,EAAE,KAAK,CAAC;CAEjG,yBAAyB,KAAK,OAAO,gBAAgB;CAErD,IAAI;EAQF,MAAM,oBAAoB,KAAK,CAAC;GAC9B,MAAM;GACN,SAAS,IAAI,IAAI,KAAK,YAAY,GAAG;GACrC,UAAU;IACR,eAAe;IACf,SAAS;KAAE,MAAM;KAAmB,SAAS;KAAS,QAAQ;IAAS;IACvE,YAAY,CAAC;IACb,WAAW,CAAC;IACZ,SAAS,CAAC;GACZ;EACF,CAAC,CAAC;EAEF,MAAM,WAAqD,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,IAClH,OAAO,SAAS,KAAI,UAAS,EAAE,KAAK,EAAE,IACtC,MAAM,0BAA0B,aAAa;GAC3C,GAAI,MAAM,QAAQ,OAAO,OAAO,IAAI,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;GACnE;EACF,CAAC;EACL,IAAI,SAAS,WAAW,GAAG;GACzB,KAAK,wHAAwH;GAC7H,gBAAgB,CAAC,CAAC;GAClB;EACF;EACA,KAAK,6BAA6B,SAAS,OAAO,kBAAkB,SAAS,KAAI,QAAO,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG;EAC9G,MAAM,WAAW,MAAM,cACrB,EACE,UAAU,SAAS,KAAI,QACrB,IAAI,WAAW,KAAA,IAAY,EAAE,MAAM,IAAI,KAAK,IAAI;GAAE,MAAM,IAAI;GAAM,QAAQ,IAAI;EAAO,CAAC,EAC1F,GACA,KAAK,aAAa,cAAc,CAClC;EAQA,MAAM,+BAAe,IAAI,IAAoB;EAC7C,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,UAAU,cAAc,IAAI,OAAO;GAEzC,KAAK,MAAM,OAAO,IAAI,SAAS,YAAY,aAAa,IAAI,QAAQ,SAAS,GAAG,GAAG,IAAI,IAAI;EAC7F;EACA,4BAA4B,CAAC,GAAG,aAAa,KAAK,CAAC,CAAC,CAAC,KAAI,UAAS,EAAE,KAAK,EAAE,CAAC;EAC5E,8BAA8B,KAAK;GACjC,oBAAoB;GACpB,OAAO,OAAO,YAAY,iBAAiB;IACzC,MAAM,SAAS,IAAI,IAAI,YAAY;IACnC,MAAM,SAAS,SAAS,QAAO,QAAO,OAAO,IAAI,IAAI,IAAI,CAAC;IAC1D,MAAM,QAAS,WAAiC;IAChD,IAAI,UAAU,KAAA,GACZ,OAAO,OAAO,KAAI,SAAQ;KAAE,MAAM,IAAI;KAAM,OAAO;IAAqD,EAAE;IAE5G,OAAO,oBAAoB,OAAO,QAAQ,UAAU;GACtD;EACF,CAAC;EAcD,MAAM,YAAY,OAAO,wBAAwB,OAC7C,SAAS,KAAI,SAAQ;GAAE,GAAG;GAAK,QAAQ;IAAE,GAAI,IAAI,UAAU,CAAC;IAAI,qBAAqB;GAAK;EAAE,EAAE,IAC9F;EACJ,MAAM,oBAAoB,KAAK,WAAW,KAAA,GAAW,EAAE,YAAY,KAAK,CAAC;EACzE,gBAAgB,SAAS;CAC3B,SAAS,OAAO;EAGd,gBAAgB,CAAC,CAAC;EAClB,MAAM;CACR;AACF;;;;;;;;AClmBA,eAAsB,eAAe,KAAsD;CACzF,MAAM,EAAE,gBAAgB,QAAQ,MAAM,OAAO;CAC7C,OAAO,IAAI,GAAG;AAChB"}
|
|
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, realpathSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { applyPreparedPiHost, preparePiHost, type PreparedPiHostPackage } from './host.js'\nimport { getSharedChildExtensionCatalog, registerChildExtensionCatalog, registerVisionCompanions, runtimeInternals } from './runtime.js'\nimport { getAgentDir, providePiExtensionDiscovery } from './compat/pi-coding-agent.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 * Serve the browser presentation surfaces (the `/pi2dsh` state route the\n * web renderer polls, and with it the `mode: 'tui'` claim on the web\n * composition). Default: OFF — the engine alone projects nothing into the\n * browser, so a web session behaves exactly like the headless CLI (Pi's\n * own rpc mode; packages degrade gracefully on their own). The dsh-work-x\n * suite turns this on and carries the actual renderer in its client\n * bundle; any other product layer that ships a renderer can do the same.\n */\n browserPresentation?: boolean\n /**\n * Serve DSH-native subagents with the profile's Pi packages (default: OFF —\n * such children run as plain DSH agents, today's behavior). Children the Pi\n * subagent bridge mints are NEVER covered: they already receive the creator's\n * own per-spawn loader mount and are recognized by the `pi2dsh-sub-` session-id\n * prefix.\n */\n serveNativeSubagents?: boolean\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 /** Resolution anchor when the package is carried by a suite (its members\n * are the suite's dependencies, unreachable from the profile root under\n * pnpm's isolated layout). */\n anchor?: 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 suite: `pi2dsh: { suite: [names...] }` mounts the listed Pi packages\n // as if the user had added each one. The list is an explicit manifest —\n // the same discovery covenant as the profile dependency list, one hop\n // deeper — and the members are the suite's own dependencies, so each\n // resolves anchored at the suite package (pnpm keeps transitive\n // dependencies out of the profile root). One level only, no recursion.\n const suite = (packageJson.pi2dsh as { suite?: unknown } | undefined)?.suite\n if (Array.isArray(suite)) {\n // The anchor must be the suite's REAL directory: the profile's\n // node_modules entry is a pnpm symlink into .pnpm, and Node resolution\n // walks up from the anchor's literal path — only the realpath has the\n // suite's own dependencies as .pnpm neighbours.\n let anchorDir = dir\n try {\n anchorDir = realpathSync(dir)\n } catch { /* an unreadable dir keeps the literal path and fails loud in prepare */ }\n for (const member of suite) {\n if (typeof member !== 'string' || member.length === 0) continue\n if (member === 'pi2dsh' || excluded.has(member)) continue\n discovered.push({ name: member, dir, anchor: join(anchorDir, 'package.json') })\n }\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 // One mount per name. A package that is both a direct dependency and a\n // suite member mounts as the DIRECT dependency (the user's own explicit\n // add, resolved from the profile root) — the suite copy yields.\n const byName = new Map<string, DiscoveredPackage>()\n for (const pkg of discovered) {\n const existing = byName.get(pkg.name)\n if (existing === undefined || (existing.anchor !== undefined && pkg.anchor === undefined)) {\n byName.set(pkg.name, pkg)\n }\n }\n return [...byName.values()]\n}\n\ninterface AgentScopedMount {\n ready: Promise<void>\n /** Set when the mount failed; the agent then runs as a plain DSH agent. */\n failure?: string\n}\n\n/** The loose shapes of the official DSH seams this file consumes. */\ninterface AgentLike {\n ctx: Context\n}\ninterface EngineHostContext {\n /** Un-injected reflection access (the ctx.get('loader') idiom): the engine\n * must not hard-depend on the agent registry — compositions without one\n * (bare test hosts) simply have no agents to mount for. */\n get?(name: string): unknown\n tools?: { schemas?(scope: unknown): Array<{ name: string }> }\n on(name: string, listener: (...args: never[]) => unknown): () => void\n}\ninterface AgentRegistryLike {\n roots?(): AgentLike[]\n}\n\n/**\n * The single mount path on every DSH surface: one Pi runtime per root Agent.\n *\n * Pi instantiates its extensions once per session; DSH's twin of that scope is\n * the Agent with its public `agent.ctx` (\"contributions are agent-local,\n * unwind on disposal\"). Mounting is driven purely by official core seams, so\n * the same semantics hold on the TUI, web, headless, ACP and config-declared\n * agents alike:\n *\n * - `agent/created` fires on every publication path before the loop can run\n * a first turn; it eagerly starts that agent's mount.\n * - `system-prompt/assemble` (awaited waterfall, runs in every step's\n * preStep) gates the assembly on the mount and patches the pre-waterfall\n * tools snapshot from the official scoped projection `tools.schemas()` —\n * stock DSH collects `assembly.tools` before dispatching the waterfall,\n * so a mount that lands during the wait would otherwise miss turn one.\n * - `tools/pre-execute` (awaited waterfall) closes the same window for\n * direct executions that bypass assembly.\n *\n * `agent/session-start` deliberately is NOT the trigger: DSH documents it as a\n * veto-less notification that cannot gate startup. The waterfalls above are\n * the officially awaited seams, and the exact pattern of registering onto a\n * foreign agent's ctx from a lifecycle event is what DSH's own schedule\n * plugin ships.\n *\n * A mount failure never takes the Agent down: the agent keeps running as a\n * plain DSH agent, the failure is reported loudly once, and only the Pi\n * packages are missing — the capability-gap discipline, not a rollback.\n */\nexport function installAgentScopedMounts(\n ctx: Context,\n preparedPackages: Promise<readonly PreparedPiHostPackage[]>,\n report: { warn(message: string): void },\n): void {\n const host = ctx as unknown as EngineHostContext\n const mounts = new WeakMap<object, AgentScopedMount>()\n\n const registry = (): AgentRegistryLike | undefined => {\n try {\n return host.get?.('agents') as AgentRegistryLike | undefined\n } catch {\n return undefined\n }\n }\n\n const isRootAgent = (agent: object): boolean => {\n // Subagents keep Pi's own sub-session semantics through the session\n // bridge; only runtime roots receive a Pi runtime (the same distinction\n // DSH's schedule plugin draws via agents.roots()).\n const agents = registry()\n const roots = agents?.roots\n if (typeof roots !== 'function') return true\n try {\n return (roots.call(agents) as unknown[]).includes(agent)\n } catch {\n return true\n }\n }\n\n const ensureMount = (agent: AgentLike): AgentScopedMount => {\n let mount = mounts.get(agent)\n if (mount === undefined) {\n const started: AgentScopedMount = { ready: Promise.resolve() }\n started.ready = preparedPackages.then(async prepared => {\n if (prepared.length === 0) return\n try {\n await applyPreparedPiHost(agent.ctx, prepared, agent as unknown as Record<string, unknown>)\n } catch (error) {\n // Loud, once per agent; the gates resolve so the plain DSH agent\n // keeps working. Faking success is forbidden — the message names\n // what is missing.\n started.failure = error instanceof Error ? error.message : String(error)\n report.warn(`[pi2dsh engine] Pi packages failed to mount for this agent; it continues without them: ${started.failure}`)\n }\n })\n mounts.set(agent, started)\n mount = started\n }\n return mount\n }\n\n // Eager start on publication. `agent/created` reaches host-level listeners\n // on every create/resume/config path, before the loop can open a turn.\n host.on('agent/created', ((payload: { agent: AgentLike }) => {\n if (isRootAgent(payload.agent)) ensureMount(payload.agent)\n }) as never)\n\n // Correctness boundary #1: no prompt assembly for a root agent proceeds\n // before its Pi runtime is mounted, and the tools snapshot taken before\n // this waterfall is reconciled against the official scoped projection.\n host.on('system-prompt/assemble', (async (\n assembly: { tools: Array<{ name: string }> },\n context: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = context.agent\n if (agent !== undefined && isRootAgent(agent)) {\n await ensureMount(agent).ready\n const schemas = host.tools?.schemas\n if (typeof schemas === 'function') {\n const present = new Set(assembly.tools.map(tool => tool.name))\n for (const schema of schemas.call(host.tools, agent)) {\n if (!present.has(schema.name)) assembly.tools.push(schema)\n }\n }\n }\n return next()\n }) as never)\n\n // Correctness boundary #2: tool execution for a root agent waits for the\n // same mount (serially awaited by the tool runtime before dispatch).\n host.on('tools/pre-execute', (async (\n exec: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n if (exec.agent !== undefined && isRootAgent(exec.agent)) await ensureMount(exec.agent).ready\n return next()\n }) as never)\n\n // Backfill: agents published before this plugin finished loading (a surface\n // that skips the official await-the-loader pattern DSH's headless runner\n // uses). Their next assembly still passes the gates above.\n void preparedPackages.then(() => {\n const agents = registry()\n const roots = agents?.roots\n if (typeof roots !== 'function') return\n for (const agent of roots.call(agents)) ensureMount(agent)\n })\n}\n\n/** Session-id prefix minted by the Pi subagent bridge (src/subagent-bridge.ts). */\nexport const BRIDGE_CHILD_SESSION_ID_PREFIX = 'pi2dsh-sub-'\n\n/**\n * Optional coverage for DSH-native subagents, enabled by the\n * `serveNativeSubagents` engine config.\n *\n * The Pi subagent bridge already serves the children IT mints: the creator's\n * per-spawn loader mount (a8b7a0a) runs at creation and again on a persisted\n * resume. This covers the OTHER lineage — children a DSH surface mints\n * directly (DSH-native delegation, headless subagents, a second agent in the\n * web UI) — which carry no Pi lineage and would otherwise run as plain DSH\n * agents with none of the profile's Pi extensions.\n *\n * One lineage check per created Agent (maintainer point 2): subagent origin\n * AND a session id that does not carry the bridge prefix. The bridge mints\n * `pi2dsh-sub-` ids at creation and a persisted resume keeps the original id,\n * so the skip holds on both bridge paths and a bridge child is never mounted\n * twice.\n *\n * The mount reuses the engine's own child-extension catalog (maintainer\n * point 3) — the same object the bridge's hook consumes — so a native child's\n * tool set is exactly Pi's default-discovered set (the catalog's no-loader\n * path), the mount lands on the child's OWN ctx and unwinds with the child,\n * and there is no second registration path to drift out of sync.\n *\n * Partition with the root-mount path: agents the registry reports as runtime\n * roots are installAgentScopedMounts' territory (it gates them the same way\n * this path does). Live delegation shows a DSH-native child of a top-level\n * session CAN be a runtime root — serving it here as well raced two mount\n * passes onto the same scope (each package survived via the prompt-section\n * guard, but the double attempt is exactly what this flag must not do). This\n * listener therefore serves exactly the remainder: subagent-origin,\n * non-bridge, non-root agents. The predicate is the root path's own, applied\n * at the same event; its fail-open (roots() unavailable ⇒ every agent is a\n * root) mirrors here as fail-closed (this listener serves nothing).\n *\n * The readiness promise is memoized on the child's SCOPE (agent.ctx), not the\n * agent object: a re-announced agent for the same session reuses the scope,\n * and the dedupe must key on what the mount actually lands in.\n *\n * First-turn gates mirror the root path's exactly: the child's first prompt\n * assembly and its direct tool executions await the mount, and the\n * pre-waterfall tools snapshot is reconciled against the official scoped\n * projection. Without the gate a mount that lands after the first turn's\n * snapshot leaves the child's first (and sometimes only) turn tool-less —\n * proven live at depth 2, where the child's grandchild saw zero extension\n * tools because its mount raced its first model call.\n *\n * A mount failure never takes the child down: the same capability-gap\n * discipline as root mounting — the child keeps running as a plain DSH agent\n * and the failure is reported loudly once.\n */\nexport function installNativeSubagentMounts(\n ctx: Context,\n preparedPackages: Promise<readonly PreparedPiHostPackage[]>,\n enabled: boolean,\n report: { warn(message: string): void },\n): void {\n if (!enabled) return\n const host = ctx as unknown as EngineHostContext\n\n // The root path's own predicate, applied at the same event it applies its\n // (see installAgentScopedMounts): a runtime root is served — and gated —\n // there. Failing closed keeps the partition exact when roots() is absent.\n const isRootAgent = (agent: object): boolean => {\n let agents: AgentRegistryLike | undefined\n try {\n agents = host.get?.('agents') as AgentRegistryLike | undefined\n } catch {\n return true\n }\n const roots = agents?.roots\n if (typeof roots !== 'function') return true\n try {\n return (roots.call(agents) as unknown[]).includes(agent)\n } catch {\n return true\n }\n }\n\n // child scope (agent.ctx) -> its mount's readiness. Reading the catalog\n // after preparation (never before) covers children published while the\n // engine was still preparing; no catalog = plain child, exactly the bridge\n // hook's no-catalog behavior.\n const mounts = new WeakMap<object, Promise<void>>()\n\n const ensureMount = (agent: AgentLike): Promise<void> => {\n const scope = agent.ctx\n let ready = mounts.get(scope)\n if (ready === undefined) {\n ready = preparedPackages.then(async () => {\n const catalog = getSharedChildExtensionCatalog(ctx)\n if (catalog === undefined) return\n // Native children have no creator loader: the full discovered set is\n // Pi's default discovery (the no-loader path of\n // resolveChildExtensionPackages).\n const names = [...new Set(catalog.packageByEntryPath.values())]\n if (names.length === 0) return\n try {\n const failures = await catalog.mount(agent as unknown as Record<string, unknown>, names)\n for (const failure of failures) {\n // Same message shape the bridge's own mount path uses.\n report.warn(`[pi2dsh] child extension ${failure.name} did not mount: ${failure.error}`)\n }\n } catch (error) {\n report.warn(`[pi2dsh] child extension mount failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n })\n mounts.set(scope, ready)\n }\n return ready\n }\n\n const handle = (agent: AgentLike): void => {\n // The single lineage check: DSH-native subagents only. Pi-origin\n // (bridge) children are already served by the creator's per-spawn loader\n // mount; the `pi2dsh-sub-` prefix identifies them on creation AND on a\n // persisted resume, where the original session id survives.\n if (!runtimeInternals.isSubagentOrigin(agent as unknown as Record<string, unknown>)) return\n const session = (agent as { session?: { id?: unknown } }).session ?? agent\n if (String((session as { id?: unknown }).id ?? '').startsWith(BRIDGE_CHILD_SESSION_ID_PREFIX)) return\n // Runtime roots are the root-mount path's territory; serving them here\n // would race a second mount onto the same scope.\n if (isRootAgent(agent)) return\n void ensureMount(agent)\n }\n\n host.on('agent/created', ((payload: { agent: AgentLike }) => {\n if (payload.agent !== undefined) handle(payload.agent)\n }) as never)\n\n // Correctness boundary #1 (mirror of the root path's): no prompt assembly\n // for a served child proceeds before its mount lands, and the pre-waterfall\n // tools snapshot is reconciled against the official scoped projection.\n host.on('system-prompt/assemble', (async (\n assembly: { tools: Array<{ name: string }> },\n context: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = context.agent\n const ready = agent === undefined ? undefined : mounts.get(agent.ctx)\n if (ready !== undefined) {\n await ready\n const schemas = host.tools?.schemas\n if (typeof schemas === 'function') {\n const present = new Set(assembly.tools.map(tool => tool.name))\n for (const schema of schemas.call(host.tools, agent)) {\n if (!present.has(schema.name)) assembly.tools.push(schema)\n }\n }\n }\n return next()\n }) as never)\n\n // Correctness boundary #2 (mirror of the root path's): direct tool\n // executions for a served child wait for the same mount.\n host.on('tools/pre-execute', (async (\n exec: { agent?: AgentLike },\n next: () => Promise<unknown>,\n ) => {\n const agent = exec.agent\n const ready = agent === undefined ? undefined : mounts.get(agent.ctx)\n if (ready !== undefined) await ready\n return next()\n }) as never)\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 // The redirected Pi agent directory must be visible to PLUGIN code, not\n // just to the bridge's own vendored components. Packages that import\n // `getAgentDir` from the aliased pi-coding-agent are redirected already,\n // but real packages also read `process.env.PI_CODING_AGENT_DIR` (or fall\n // back to ~/.pi/agent) at module load — pi-hermes-memory's paths.ts does\n // exactly that, and without this line its store landed in the REAL\n // ~/.pi/agent, colliding with any actual Pi installation. Publishing the\n // same path the shim computes keeps both classes on one directory; a\n // user-set value is honored (the shim reads the env first, so the two can\n // never disagree). Set before any package module is imported.\n if (process.env.PI_CODING_AGENT_DIR === undefined || process.env.PI_CODING_AGENT_DIR === '') {\n process.env.PI_CODING_AGENT_DIR = getAgentDir()\n }\n\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 // The single mount path, before any await: gates and lifecycle listeners\n // must exist the moment a surface can publish its first Agent. Package\n // preparation resolves behind this promise; the gates hold each agent's\n // first assembly until its own mount lands.\n let resolvePrepared!: (prepared: readonly PreparedPiHostPackage[]) => void\n const preparedPackages = new Promise<readonly PreparedPiHostPackage[]>(resolve => {\n resolvePrepared = resolve\n })\n installAgentScopedMounts(ctx, preparedPackages, { warn })\n installNativeSubagentMounts(ctx, preparedPackages, config.serveNativeSubagents === true, { warn })\n\n registerVisionCompanions(ctx, config.visionCompanions)\n\n try {\n // The host half, mounted exactly once regardless of packages or agents:\n // Pi's built-in provider directory, `/login`, and credential recovery.\n // Without it a fresh engine cannot run `/login openai-codex`: DSH treats\n // the unknown slash line as a model prompt and fails on the unrelated\n // default provider credential. Community packages join the same\n // SharedHostState (keyed on ctx.root), so host-level resources stay\n // single-instance no matter which agent scope mounts them.\n await applyPreparedPiHost(ctx, [{\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\n const packages: Array<{ name: string, anchor?: string }> = Array.isArray(config.packages) && config.packages.length > 0\n ? config.packages.map(name => ({ name }))\n : await discoverProfilePiPackages(profileRoot, {\n ...(Array.isArray(config.exclude) ? { exclude: config.exclude } : {}),\n warn,\n })\n if (packages.length === 0) {\n info('[pi2dsh engine] no Pi packages installed in this profile yet — add one with: dsh plugin --profile <p> add <pi-package>')\n resolvePrepared([])\n return\n }\n info(`[pi2dsh engine] preparing ${packages.length} Pi package(s): ${packages.map(pkg => pkg.name).join(', ')}`)\n const prepared = await preparePiHost(\n {\n packages: packages.map(pkg =>\n pkg.anchor === undefined ? { name: pkg.name } : { name: pkg.name, anchor: pkg.anchor }),\n },\n join(profileRoot, 'package.json'),\n )\n // Child-extension catalog: what real Pi's createAgentSession \"default-\n // discovered extensions\" means on this host. Entries are each package's\n // DECLARED pi extension files (absolute, inside the installed dir), so a\n // creator's own filter code (pi-subagents' extensions/exclude/ext:\n // machinery) canonicalizes them exactly as it does on Pi. Mounting lands\n // on the child agent's OWN ctx — contributions unwind with the agent,\n // which is what makes per-child instances leak-free by construction.\n const entryCatalog = new Map<string, string>()\n for (const pkg of prepared) {\n const rootDir = fileURLToPath(pkg.rootUrl)\n // Resolved keys, because the consumer looks entries up by resolved path.\n for (const rel of pkg.manifest.extensions) entryCatalog.set(resolve(rootDir, rel), pkg.name)\n }\n providePiExtensionDiscovery([...entryCatalog.keys()].map(path => ({ path })))\n registerChildExtensionCatalog(ctx, {\n packageByEntryPath: entryCatalog,\n mount: async (childAgent, packageNames) => {\n const wanted = new Set(packageNames)\n const subset = prepared.filter(pkg => wanted.has(pkg.name))\n const scope = (childAgent as { ctx?: Context }).ctx\n if (scope === undefined) {\n return subset.map(pkg => ({ name: pkg.name, error: 'the child agent exposes no ctx scope to mount into' }))\n }\n return applyPreparedPiHost(scope, subset, childAgent)\n },\n })\n\n // Host anchors, before the per-Agent gates open: every package's\n // HOST-level contributions (provider routes, OAuth accounts, /login,\n // credential recovery, companions, skills) exist from engine apply — a\n // surface with zero live Agents (web at boot) still advertises them, the\n // first Agent's model resolution finds its routes, and routes survive\n // Agent churn. Anchors serve no Agent; sessions belong to the per-Agent\n // instances the gates mount.\n // The engine-level browserPresentation flag rides into every package\n // mount's config: the /pi2dsh route (and the web `mode: 'tui'` claim)\n // exists only when a product layer configured a renderer. Stamped here\n // rather than defaulted in the runtime so per-Agent remounts and the\n // host anchor agree on one answer.\n const presented = config.browserPresentation === true\n ? prepared.map(pkg => ({ ...pkg, config: { ...(pkg.config ?? {}), browserPresentation: true } }))\n : prepared\n await applyPreparedPiHost(ctx, presented, undefined, { hostAnchor: true })\n resolvePrepared(presented)\n } catch (error) {\n // The gates must never hang on a failed preparation; agents keep running\n // as plain DSH agents while the engine failure propagates loudly.\n resolvePrepared([])\n throw error\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, installAgentScopedMounts, 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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"}
|