pi2dsh 0.12.2 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config-Cjae0vot.mjs","names":[],"sources":["../src/compatibility.ts","../src/mcp-config.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.'\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 fails closed).`),\n DefaultResourceLoader: rule('partial', 'A headless resource loader honoring overrides, with empty discovery sets.'),\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 (a Pi model on the options routes the child); 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 registerProvider: rule('partial', 'Recorded in a bridge-local registry; DSH llm adapters own real routing.'),\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 human can actually answer: false when no questions service is mounted, false when the service is mounted with no provider registered (the headless posture), and false inside a child agent, which DSH refuses to let ask.', 'Probed rather than guessed. The bridge registers a throwaway provider on DSH\\'s UserQuestionService and reads the documented DUPLICATE_PROVIDER rejection as \"a real provider is already there\", then disposes it. Inside a child agent the answer is false without probing, because DSH refuses to let child agents ask.'),\n mode: surface('partial', 'Reports rpc mode so Pi extensions can choose their documented headless fallback.', 'A constant. The bridge is an rpc host, and this is the value Pi packages branch on to take their own documented headless path.'),\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('partial', 'Fails closed as untrusted because DSH does not expose Pi project-trust state.', 'No DSH seam carries Pi\\'s project-trust state, so the bridge returns the safe constant instead of inventing one. Pi\\'s own ProjectTrustStore is vendored and available to packages that manage their own.'),\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 pi2dsh sidecar entries, exposed through Pi\\'s exact 14-method surface as a single-branch tree. 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 and the pi2dsh sidecar — 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('partial', 'Accepted as a no-op because DSH owns status presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setWidget: surface('partial', 'Accepted as a no-op because Pi terminal widgets cannot render in DSH.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n select: surface('full', 'Mapped to one native DSH userQuestions single-select request.', 'One native DSH UserQuestionService request carrying Pi\\'s options as the choices. The turn really blocks until a human answers.'),\n confirm: surface('full', 'Mapped to one native DSH userQuestions Yes/No request.', 'One native DSH UserQuestionService request with two choices.'),\n input: surface('full', 'Mapped to one native DSH userQuestions free-text request.', 'One native DSH UserQuestionService free-text request.'),\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.', '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.'),\n custom: surface('partial', 'Resolves undefined, exactly like Pi\\'s own rpc mode; guarded fallbacks keep working. A Pi component cannot be forwarded to a browser — but the SHAPE packages use this for (a focused side panel over the conversation) is drawn natively by the bridge\\'s own browser half.', 'Two halves. The call itself resolves undefined, matching Pi\\'s rpc mode, because a Pi TUI component has no meaning in a browser. Separately, pi2dsh ships a client half (`dsh.client` + `exports[\"./client\"]`) that takes DSH\\'s frame-wide `shell.overlay` seat and renders a side conversation as a floating panel, fed by this package\\'s own route (`/pi2dsh/side-panel`). So the capability lands as a native DSH surface rather than as a relayed Pi component.'),\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', 'Accepted as a no-op; DSH owns progress presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setWorkingVisible: surface('partial', 'Accepted as a no-op; DSH owns progress presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setWorkingIndicator: surface('partial', 'Accepted as a no-op; DSH owns progress presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setHiddenThinkingLabel: surface('partial', 'Accepted as a no-op; DSH owns thinking presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setFooter: surface('partial', 'Accepted as a no-op; DSH owns footer presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setHeader: surface('partial', 'Accepted as a no-op; DSH owns header presentation.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n setTitle: surface('partial', 'Accepted as a no-op; DSH owns window titles.', 'Not wired yet, and not because there is nowhere to put it: DSH\\'s browser half has slot seats for frame-wide and in-conversation surfaces, and pi2dsh already ships a client half that takes one (the side-conversation panel). The call is accepted and returns so a package that decorates a terminal keeps running; when a real consumer appears, this lands on the same client half rather than staying a no-op.'),\n pasteToEditor: surface('partial', 'Appends to a per-agent editor buffer readable through getEditorText().', 'A per-agent text buffer inside the bridge; the three editor calls only talk to each other.'),\n setEditorText: surface('partial', 'Stored in a per-agent editor buffer readable through getEditorText().', 'A per-agent text buffer inside the bridge; the three editor calls only talk to each other.'),\n getEditorText: surface('partial', 'Reads the per-agent editor buffer maintained by the bridge.', 'Reads the per-agent buffer the other two editor calls write.'),\n addAutocompleteProvider: surface('partial', 'Registration is recorded; no DSH surface requests suggestions.', 'Kept in bridge state and readable back; no DSH surface consumes it.'),\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). ui.notify becomes the result, while interactive Pi TUI methods fail explicitly in headless DSH.',\n design: 'Registered on ctx.commands with an input descriptor. The descriptor is what makes /name <arguments> parse as a command in the web app instead of being sent as chat, so it is not optional detail.',\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): the declaration is recorded and introspectable, no bridge transport is synthesized, and model calls stay on native DSH llm adapters and credentials.',\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 registers no transport at all: those models are served by the host\\'s adapters and DSH credentials, and the declaration only contributes directory entries.',\n },\n unregisterProvider: {\n level: 'partial',\n detail: 'Removes the recorded provider declaration.',\n design: 'Disposes the route registration when one was made and drops the recorded declaration.',\n },\n registerMessageRenderer: {\n level: 'partial',\n detail: 'Registration is accepted; DSH owns presentation, so the renderer 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 registerEntryRenderer: {\n level: 'partial',\n detail: 'Registration is accepted; DSH owns presentation, so the renderer 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 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 in a pi2dsh sidecar next to the DSH session and replayed on session start; DSH\\'s main log stays untouched because it has no out-of-repo plugin-event channel yet.',\n design: 'A pi2dsh sidecar file beside the DSH session, replayed at session start. DSH\\'s own log has no channel for event types declared outside the harness, and writing unknown types into it corrupts the session for every other reader.',\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 the pi2dsh sidecar, 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 the sidecar.',\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 sidecar 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; sidecar fallback when no title service is mounted.',\n },\n setLabel: {\n level: 'partial',\n detail: 'Persisted in the pi2dsh sidecar and reflected by the sessionManager projection.',\n design: 'Stored in the pi2dsh sidecar and 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: 'Package-local Pi extension event-bus emit/on semantics are preserved for migrated extensions in the same bundle.',\n design: 'A package-local emitter inside the bridge, so extensions bundled together talk to each other exactly as they do under Pi.',\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: 'unsupported',\n detail: 'Provider payload mutation belongs in a native DSH LLM adapter; the handler is accepted but never fires.',\n design: 'Deliberately not wired. The request body is built inside a DSH llm adapter, and a package that needs to shape it should be one (or register its own provider, which this bridge does support). Faking the moment on the bridge side would let a handler edit a body that is not the one sent.',\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","// Pi MCP configuration -> DSH mcp-client patch entries.\n//\n// Pi (via pi-mcp-adapter) reads the standard `mcpServers` files. DSH ships an\n// official MCP client (`@deepseek-ai/dsh-mcp-client`) configured through\n// cordis patch layers — so migration is config translation, not running Pi's\n// adapter code. This module reads Pi's documented six-layer precedence,\n// resolves `disabled` flags, and emits one patch entry per enabled server.\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { getAgentDir } from './compat/vendor/pi-config-shim.js'\n\ntype UnknownRecord = Record<string, unknown>\n\nexport interface PiMcpServer {\n name: string\n sourcePath: string\n transport: 'stdio' | 'streamable-http'\n command?: string\n args?: string[]\n env?: Record<string, string>\n cwd?: string\n url?: string\n headers?: Record<string, string>\n disabled: boolean\n}\n\nexport interface McpConversionWarning {\n server: string\n message: string\n}\n\nexport interface McpConversionResult {\n servers: PiMcpServer[]\n entries: UnknownRecord[]\n warnings: McpConversionWarning[]\n sources: string[]\n}\n\n/** Pi's documented config precedence, lowest to highest. */\nexport function piMcpConfigPaths(cwd: string): string[] {\n const home = homedir()\n return [\n join(home, '.config', 'mcp', 'mcp.json'),\n join(home, '.agents', 'mcp.json'),\n join(home, '.agents', 'mcp', 'mcp.json'),\n join(getAgentDir(), 'mcp.json'),\n join(cwd, '.mcp.json'),\n join(cwd, '.pi', 'mcp.json'),\n ]\n}\n\nfunction stringRecord(value: unknown): Record<string, string> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const entries = Object.entries(value).filter((entry): entry is [string, string] => typeof entry[1] === 'string')\n return entries.length === 0 ? undefined : Object.fromEntries(entries)\n}\n\nfunction parseServer(name: string, raw: unknown, sourcePath: string): PiMcpServer | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined\n const record = raw as UnknownRecord\n const disabled = record.disabled === true\n if (typeof record.url === 'string') {\n return {\n name, sourcePath, transport: 'streamable-http', url: record.url,\n ...(stringRecord(record.headers) === undefined ? {} : { headers: stringRecord(record.headers)! }),\n disabled,\n }\n }\n if (typeof record.command === 'string') {\n return {\n name, sourcePath, transport: 'stdio', command: record.command,\n ...(Array.isArray(record.args) ? { args: record.args.map(String) } : {}),\n ...(stringRecord(record.env) === undefined ? {} : { env: stringRecord(record.env)! }),\n ...(typeof record.cwd === 'string' ? { cwd: record.cwd } : {}),\n disabled,\n }\n }\n return undefined\n}\n\nexport function collectPiMcpServers(cwd: string, extraPaths: string[] = []): { servers: Map<string, PiMcpServer>; sources: string[] } {\n const servers = new Map<string, PiMcpServer>()\n const sources: string[] = []\n for (const path of [...piMcpConfigPaths(cwd), ...extraPaths]) {\n if (!existsSync(path)) continue\n let parsed: unknown\n try {\n parsed = JSON.parse(readFileSync(path, 'utf8'))\n } catch {\n continue\n }\n const mcpServers = (parsed as UnknownRecord | undefined)?.mcpServers\n if (typeof mcpServers !== 'object' || mcpServers === null) continue\n sources.push(path)\n for (const [name, raw] of Object.entries(mcpServers)) {\n const record = raw as UnknownRecord | null\n const existing = servers.get(name)\n // Later (higher-precedence) layers override whole entries; a bare\n // `disabled` toggle updates the effective server from a lower layer.\n if (existing !== undefined && typeof record === 'object' && record !== null\n && record.command === undefined && record.url === undefined && typeof record.disabled === 'boolean') {\n servers.set(name, { ...existing, disabled: record.disabled, sourcePath: path })\n continue\n }\n const server = parseServer(name, raw, path)\n if (server !== undefined) servers.set(name, server)\n }\n }\n return { servers, sources }\n}\n\nconst SERVER_NAME_PATTERN = /^[A-Za-z0-9_-]{1,32}$/u\nconst ENV_REFERENCE_PATTERN = /^\\$\\{?([A-Za-z_][A-Za-z0-9_]*)\\}?$/u\nconst SECRETISH_KEY_PATTERN = /token|secret|key|password|credential/iu\n\ninterface JsExpression {\n __pi2dshJs: string\n}\n\nfunction js(expression: string): JsExpression {\n return { __pi2dshJs: expression }\n}\n\nfunction convertValueMap(\n server: string,\n kind: 'env' | 'headers',\n values: Record<string, string> | undefined,\n warnings: McpConversionWarning[],\n): Record<string, string | JsExpression> | undefined {\n if (values === undefined) return undefined\n const output: Record<string, string | JsExpression> = {}\n for (const [key, value] of Object.entries(values)) {\n const reference = ENV_REFERENCE_PATTERN.exec(value)\n if (reference !== null) {\n output[key] = js(`process.env.${reference[1]}`)\n continue\n }\n if (SECRETISH_KEY_PATTERN.test(key)) {\n warnings.push({\n server,\n message: `${kind}.${key} carries a literal value; move the secret to an environment variable and reference it as $NAME so the patch stays credential-free`,\n })\n }\n output[key] = value\n }\n return output\n}\n\nexport function convertPiMcpConfig(cwd: string, extraPaths: string[] = []): McpConversionResult {\n const { servers, sources } = collectPiMcpServers(cwd, extraPaths)\n const warnings: McpConversionWarning[] = []\n const entries: UnknownRecord[] = []\n for (const server of servers.values()) {\n if (server.disabled) {\n warnings.push({ server: server.name, message: 'skipped: disabled in Pi configuration' })\n continue\n }\n if (!SERVER_NAME_PATTERN.test(server.name)) {\n warnings.push({\n server: server.name,\n message: 'skipped: DSH serverName must match [A-Za-z0-9_-]{1,32}; rename the server in the Pi config',\n })\n continue\n }\n const config: UnknownRecord = { serverName: server.name, transport: server.transport }\n if (server.transport === 'stdio') {\n config.command = server.command\n if (server.args !== undefined) config.args = server.args\n const env = convertValueMap(server.name, 'env', server.env, warnings)\n if (env !== undefined) config.env = env\n if (server.cwd !== undefined) config.cwd = server.cwd\n } else {\n config.url = server.url\n const headers = convertValueMap(server.name, 'headers', server.headers, warnings)\n if (headers !== undefined) config.headers = headers\n }\n entries.push({ id: `mcp-${server.name}`, name: '@deepseek-ai/dsh-mcp-client', config })\n }\n return { servers: [...servers.values()], entries, warnings, sources }\n}\n\nfunction yamlScalar(value: unknown, indent: string): string {\n if (typeof value === 'object' && value !== null && '__pi2dshJs' in (value as JsExpression)) {\n return `!!js ${(value as JsExpression).__pi2dshJs}`\n }\n if (typeof value === 'string') {\n return /^[A-Za-z0-9@._\\/:-]+$/u.test(value) ? value : JSON.stringify(value)\n }\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]'\n return `\\n${value.map(item => `${indent} - ${yamlScalar(item, `${indent} `)}`).join('\\n')}`\n }\n if (typeof value === 'object' && value !== null) {\n const record = value as UnknownRecord\n const keys = Object.keys(record)\n if (keys.length === 0) return '{}'\n return `\\n${keys.map(key => `${indent} ${key}: ${yamlScalar(record[key], `${indent} `)}`).join('\\n')}`\n }\n return String(value)\n}\n\n/** Render the converted entries as a cordis.patch.yml `insert` block. */\nexport function renderMcpPatch(result: McpConversionResult): string {\n if (result.entries.length === 0) return '# no enabled MCP servers found in Pi configuration\\n'\n const lines: string[] = ['- insert:']\n for (const entry of result.entries) {\n lines.push(` - id: ${String(entry.id)}`)\n lines.push(` name: '@deepseek-ai/dsh-mcp-client'`)\n lines.push(` inject: [tools]`)\n lines.push(` config:${yamlScalar(entry.config, ' ')}`)\n }\n return `${lines.join('\\n')}\\n`\n}\n"],"mappings":";;;;;;AAoBA,MAAM,QAAQ,OAA2B,YAA0B;CAAE;CAAO;AAAO;AAEnF,MAAM,WAAW,OAA2B,QAAgB,YACzD;CAAE;CAAO;CAAQ;AAAO;AAE3B,MAAa,2BAA2B,OAAO,OAAO,CACpD,mCACA,+BACF,CAAU;AAEV,MAAa,kBAAkB,OAAO,OAAO,CAC3C,0BACA,sBACF,CAAU;AAEV,MAAa,iBAAiB,OAAO,OAAO,CAC1C,yBACA,qBACF,CAAU;AAEV,MAAM,WAAW;AACjB,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AACtB,MAAM,cAAc;AACpB,MAAM,sBAAsB;AAE5B,MAAa,oBAA8E,OAAO,OAAO;CACvG,mBAAmB,OAAO,OAAO;EAC/B,YAAY,KAAK,QAAQ,6BAA6B;EACtD,iBAAiB,KAAK,WAAW,gGAAgG;EACjI,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,SAAS,KAAK,WAAW,wEAAwE;EACjG,yBAAyB,KAAK,QAAQ,QAAQ;EAC9C,aAAa,KAAK,WAAW,kFAAkF;EAC/G,eAAe,KAAK,WAAW,uDAAuD;EACtF,YAAY,KAAK,QAAQ,QAAQ;EACjC,cAAc,KAAK,QAAQ,QAAQ;EACnC,cAAc,KAAK,QAAQ,QAAQ;EACnC,cAAc,KAAK,QAAQ,QAAQ;EACnC,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,gBAAgB,KAAK,QAAQ,GAAG,SAAS,2DAA2D;EACpG,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,0BAA0B,KAAK,QAAQ,QAAQ;EAC/C,+BAA+B,KAAK,QAAQ,QAAQ;EACpD,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,cAAc,KAAK,QAAQ,QAAQ;EACnC,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,4BAA4B,KAAK,QAAQ,QAAQ;EACjD,gCAAgC,KAAK,QAAQ,QAAQ;EACrD,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,gBAAgB,KAAK,QAAQ,QAAQ;EACrC,wBAAwB,KAAK,QAAQ,GAAG,SAAS,mIAAmI;EACpL,6BAA6B,KAAK,QAAQ,QAAQ;EAClD,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,eAAe,KAAK,QAAQ,GAAG,SAAS,2EAA2E;EACnH,SAAS,KAAK,WAAW,mBAAmB;EAC5C,cAAc,KAAK,QAAQ,QAAQ;EACnC,iBAAiB,KAAK,WAAW,mBAAmB;EACpD,0BAA0B,KAAK,WAAW,mBAAmB;EAC7D,uBAAuB,KAAK,WAAW,mBAAmB;EAC1D,kBAAkB,KAAK,QAAQ,GAAG,SAAS,qKAAqK;EAChN,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,iBAAiB,KAAK,WAAW,yGAAyG;EAC1I,aAAa,KAAK,WAAW,4FAA4F;EACzH,cAAc,KAAK,WAAW,kFAAmF;EACjH,gBAAgB,KAAK,WAAW,kEAAmE;EACnG,WAAW,KAAK,WAAW,uEAAwE;EACnG,OAAO,KAAK,WAAW,iEAAiE;EACxF,OAAO,KAAK,WAAW,sGAAsG;EAC7H,WAAW,KAAK,WAAW,qDAAqD;EAChF,sBAAsB,KAAK,WAAW,wDAAyD;EAC/F,oBAAoB,KAAK,WAAW,wDAAyD;EAC7F,kBAAkB,KAAK,WAAW,sFAAsF;EACxH,qBAAqB,KAAK,WAAW,+DAA+D;EACpG,eAAe,KAAK,WAAW,8CAA8C;EAC7E,eAAe,KAAK,QAAQ,qHAAsH;EAClJ,iBAAiB,KAAK,WAAW,4FAA6F;EAC9H,yBAAyB,KAAK,WAAW,wDAAwD;EACjG,qBAAqB,KAAK,WAAW,8DAA8D;EACnG,eAAe,KAAK,WAAW,sEAAsE;EACrG,gBAAgB,KAAK,QAAQ,4EAA4E;EACzG,sBAAsB,KAAK,WAAW,yHAAyH;EAC/J,iBAAiB,KAAK,QAAQ,0EAA2E;EACzG,oBAAoB,KAAK,QAAQ,GAAG,SAAS,2HAA2H;EACxK,mBAAmB,KAAK,WAAW,GAAG,SAAS,sRAAsR;EACrU,uBAAuB,KAAK,WAAW,2EAA2E;EAClH,uBAAuB,KAAK,eAAe,4SAA6S;EACxV,cAAc,KAAK,eAAe,2SAA2S;EAC7U,oBAAoB,KAAK,WAAW,4JAA4J;EAChM,mBAAmB,KAAK,QAAQ,uEAAwE;EACxG,qBAAqB,KAAK,QAAQ,iFAAkF;EACpH,gBAAgB,KAAK,QAAQ,aAAa;EAC1C,gBAAgB,KAAK,QAAQ,aAAa;EAC1C,gBAAgB,KAAK,QAAQ,aAAa;EAC1C,iBAAiB,KAAK,QAAQ,aAAa;EAC3C,gBAAgB,KAAK,QAAQ,aAAa;EAC1C,gBAAgB,KAAK,QAAQ,aAAa;EAC1C,cAAc,KAAK,QAAQ,aAAa;EACxC,0BAA0B,KAAK,QAAQ,aAAa;EACpD,0BAA0B,KAAK,QAAQ,aAAa;EACpD,0BAA0B,KAAK,QAAQ,aAAa;EACpD,2BAA2B,KAAK,QAAQ,aAAa;EACrD,0BAA0B,KAAK,QAAQ,aAAa;EACpD,0BAA0B,KAAK,QAAQ,aAAa;EACpD,wBAAwB,KAAK,QAAQ,aAAa;EAClD,qBAAqB,KAAK,QAAQ,WAAW;EAC7C,kBAAkB,KAAK,QAAQ,WAAW;EAC1C,kBAAkB,KAAK,QAAQ,WAAW;EAC1C,kBAAkB,KAAK,QAAQ,WAAW;EAC1C,mBAAmB,KAAK,QAAQ,WAAW;EAC3C,kBAAkB,KAAK,QAAQ,WAAW;EAC1C,kBAAkB,KAAK,QAAQ,WAAW;EAC1C,gBAAgB,KAAK,QAAQ,WAAW;EACxC,YAAY,KAAK,WAAW,GAAG,SAAS,4JAA4J;EACpM,mBAAmB,KAAK,QAAQ,GAAG,SAAS,oIAAoI;EAChL,uBAAuB,KAAK,QAAQ,6DAA8D;EAClG,cAAc,KAAK,WAAW,kBAAkB;EAChD,wBAAwB,KAAK,WAAW,kBAAkB;EAC1D,iBAAiB,KAAK,WAAW,kBAAkB;EACnD,gBAAgB,KAAK,WAAW,kBAAkB;EAClD,wBAAwB,KAAK,WAAW,kBAAkB;EAC1D,2BAA2B,KAAK,WAAW,kBAAkB;EAC7D,sBAAsB,KAAK,WAAW,kBAAkB;EACxD,4BAA4B,KAAK,WAAW,kBAAkB;EAC9D,yBAAyB,KAAK,WAAW,kBAAkB;EAC3D,0BAA0B,KAAK,WAAW,kBAAkB;EAC5D,2BAA2B,KAAK,WAAW,kBAAkB;EAC7D,YAAY,KAAK,WAAW,yDAAyD;EACrF,uBAAuB,KAAK,WAAW,4DAA6D;EACpG,SAAS,KAAK,WAAW,4CAA4C;EACrE,SAAS,KAAK,WAAW,4CAA4C;EACrE,YAAY,KAAK,WAAW,4CAA4C;CAC1E,CAAC;CACD,UAAU,OAAO,OAAO;EACtB,cAAc,KAAK,QAAQ,QAAQ;EACnC,iBAAiB,KAAK,QAAQ,QAAQ;EACtC,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,eAAe,KAAK,QAAQ,QAAQ;EACpC,gBAAgB,KAAK,QAAQ,QAAQ;EACrC,wBAAwB,KAAK,QAAQ,QAAQ;EAC7C,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,yBAAyB,KAAK,QAAQ,QAAQ;EAC9C,iBAAiB,KAAK,QAAQ,QAAQ;EACtC,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,eAAe,KAAK,QAAQ,QAAQ;EACpC,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,YAAY,KAAK,QAAQ,QAAQ;EACjC,aAAa,KAAK,QAAQ,QAAQ;EAClC,UAAU,KAAK,QAAQ,QAAQ;EAC/B,YAAY,KAAK,QAAQ,QAAQ;EACjC,cAAc,KAAK,QAAQ,QAAQ;EACnC,aAAa,KAAK,QAAQ,QAAQ;EAClC,sBAAsB,KAAK,QAAQ,QAAQ;EAC3C,uBAAuB,KAAK,QAAQ,QAAQ;EAC5C,wBAAwB,KAAK,QAAQ,QAAQ;EAC7C,KAAK,KAAK,QAAQ,QAAQ;EAC1B,gBAAgB,KAAK,QAAQ,GAAG,SAAS,8EAA8E;EACvH,gBAAgB,KAAK,QAAQ,QAAQ;EACrC,oBAAoB,KAAK,QAAQ,QAAQ;EACzC,iBAAiB,KAAK,QAAQ,QAAQ;EACtC,2BAA2B,KAAK,QAAQ,QAAQ;EAChD,gCAAgC,KAAK,QAAQ,QAAQ;EACrD,aAAa,KAAK,QAAQ,QAAQ;EAClC,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,kBAAkB,KAAK,QAAQ,QAAQ;EACvC,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,oBAAoB,KAAK,QAAQ,QAAQ;EACzC,oBAAoB,KAAK,QAAQ,QAAQ;EACzC,iBAAiB,KAAK,QAAQ,QAAQ;EACtC,aAAa,KAAK,WAAW,GAAG,SAAS,+CAA+C;EACxF,cAAc,KAAK,WAAW,GAAG,SAAS,+CAA+C;EACzF,kBAAkB,KAAK,WAAW,GAAG,SAAS,+CAA+C;EAC7F,sBAAsB,KAAK,WAAW,GAAG,SAAS,+CAA+C;EACjG,oBAAoB,KAAK,WAAW,GAAG,SAAS,iDAAiD;EACjG,iBAAiB,KAAK,WAAW,QAAQ;EACzC,iBAAiB,KAAK,WAAW,QAAQ;EACzC,wBAAwB,KAAK,WAAW,QAAQ;EAChD,mBAAmB,KAAK,WAAW,QAAQ;EAC3C,mBAAmB,KAAK,WAAW,QAAQ;EAC3C,WAAW,KAAK,QAAQ,QAAQ;EAChC,eAAe,KAAK,QAAQ,QAAQ;EACpC,8BAA8B,KAAK,WAAW,GAAG,SAAS,qDAAqD;EAC/G,QAAQ,KAAK,QAAQ,sDAAsD;EAC3E,eAAe,KAAK,QAAQ,qEAAsE;EAClG,MAAM,KAAK,WAAW,kBAAkB;EACxC,QAAQ,KAAK,WAAW,kBAAkB;EAC1C,WAAW,KAAK,WAAW,kBAAkB;EAC7C,KAAK,KAAK,WAAW,kBAAkB;EACvC,UAAU,KAAK,WAAW,kBAAkB;EAC5C,eAAe,KAAK,WAAW,kBAAkB;EACjD,QAAQ,KAAK,WAAW,GAAG,mBAAmB,8DAA8D;EAC5G,OAAO,KAAK,WAAW,GAAG,mBAAmB,2EAA2E;EACxH,YAAY,KAAK,WAAW,GAAG,mBAAmB,oEAAoE;EACtH,cAAc,KAAK,WAAW,GAAG,mBAAmB,oDAAoD;EACxG,YAAY,KAAK,WAAW,kBAAkB;EAC9C,QAAQ,KAAK,WAAW,kBAAkB;EAC1C,QAAQ,KAAK,WAAW,kBAAkB;EAC1C,QAAQ,KAAK,WAAW,kBAAkB;EAC1C,mBAAmB,KAAK,WAAW,kBAAkB;EACrD,OAAO,KAAK,WAAW,GAAG,mBAAmB,+EAA+E;EAC5H,aAAa,KAAK,QAAQ,6BAA6B;EACvD,eAAe,KAAK,WAAW,uDAAuD;CACxF,CAAC;CACD,SAAS,OAAO,OAAO;EACrB,YAAY,KAAK,QAAQ,qFAAqF;EAC9G,kBAAkB,KAAK,WAAW,yEAAyE;EAC3G,cAAc,KAAK,WAAW,6CAA6C;EAC3E,aAAa,KAAK,WAAW,kCAAkC;EAC/D,UAAU,KAAK,WAAW,uDAAuD;EACjF,WAAW,KAAK,WAAW,gDAAgD;EAC3E,UAAU,KAAK,WAAW,uKAAuK;EACjM,QAAQ,KAAK,WAAW,iLAAiL;EACzM,MAAM,KAAK,QAAQ,0EAA0E;EAC7F,QAAQ,KAAK,QAAQ,QAAQ;EAC7B,mBAAmB,KAAK,QAAQ,QAAQ;EACxC,qBAAqB,KAAK,QAAQ,QAAQ;EAC1C,2BAA2B,KAAK,QAAQ,QAAQ;EAChD,aAAa,KAAK,QAAQ,iEAAkE;EAC5F,oBAAoB,KAAK,QAAQ,6DAA8D;EAC/F,4BAA4B,KAAK,QAAQ,0CAA2C;EACpF,gBAAgB,KAAK,QAAQ,kCAAkC;CACjE,CAAC;AACH,CAAC;AAED,MAAa,gBAAuD,OAAO,OAAO;CAChF,KAAK,QAAQ,QAAQ,6DAA6D,0FAA2F;CAC7K,QAAQ,QAAQ,QAAQ,uEAAuE,2JAA4J;CAC3P,OAAO,QAAQ,QAAQ,gPAAgP,4TAA2T;CAClkB,MAAM,QAAQ,WAAW,oFAAoF,gIAAgI;CAC7O,QAAQ,QAAQ,WAAW,yFAAyF,sIAAsI;CAC1P,kBAAkB,QAAQ,WAAW,iFAAiF,yMAA2M;CACjU,oBAAoB,QAAQ,QAAQ,qHAAsH,+HAA+H;CACzR,iBAAiB,QAAQ,WAAW,yCAAyC,gIAAgI;CAC7M,iBAAiB,QAAQ,QAAQ,gEAAgE,sMAAsM;CACvS,wBAAwB,QAAQ,WAAW,8DAA8D,wJAA2J;CACpQ,aAAa,QAAQ,WAAW,yDAAyD,sEAAuE;CAChK,gBAAgB,QAAQ,WAAW,mWAAoW,iTAAmT;CAC1rB,eAAe,QAAQ,WAAW,kyCAAqyC,6UAA8U;CACrpD,OAAO,QAAQ,WAAW,gYAAkY,kLAAmL;CAC/kB,cAAc,QAAQ,QAAQ,8JAA+J,gHAAiH;CAC9S,mBAAmB,QAAQ,WAAW,sJAAuJ,4JAA6J;CAC1V,eAAe,QAAQ,WAAW,sGAAsG,kGAAkG;CAC1O,OAAO,QAAQ,WAAW,qEAAmE,6DAA+D;CAC5J,UAAU,QAAQ,WAAW,oMAAoM,kNAAkN;CACnb,SAAS,QAAQ,WAAW,yYAA4Y,wNAA0N;CACloB,YAAY,QAAQ,WAAW,iYAA+X,wLAAwL;CACtlB,MAAM,QAAQ,WAAW,8VAA4V,4LAA4L;CACjjB,cAAc,QAAQ,WAAW,gYAAmY,sMAAwM;CAC5mB,eAAe,QAAQ,WAAW,iRAA+Q,iIAAiI;CAClb,QAAQ,QAAQ,WAAW,wQAAyQ,2NAA4N;AAClgB,CAAC;AAED,MAAa,mBAA0D,OAAO,OAAO;CACnF,QAAQ,QAAQ,QAAQ,uJAAuJ,mIAAmI;CAClT,WAAW,QAAQ,WAAW,6DAA6D,qZAAsZ;CACjf,WAAW,QAAQ,WAAW,yEAAyE,qZAAsZ;CAC7f,QAAQ,QAAQ,QAAQ,iEAAiE,gIAAiI;CAC1N,SAAS,QAAQ,QAAQ,0DAA0D,8DAA8D;CACjJ,OAAO,QAAQ,QAAQ,6DAA6D,uDAAuD;CAC3I,QAAQ,QAAQ,WAAW,2LAA2L,wLAAwL;CAC9Y,QAAQ,QAAQ,WAAW,8QAAgR,scAAuc;CAClvB,iBAAiB,QAAQ,WAAW,6EAA6E,kHAAkH;CACnO,mBAAmB,QAAQ,WAAW,wDAAwD,qZAAsZ;CACpf,mBAAmB,QAAQ,WAAW,wDAAwD,qZAAsZ;CACpf,qBAAqB,QAAQ,WAAW,wDAAwD,qZAAsZ;CACtf,wBAAwB,QAAQ,WAAW,wDAAwD,qZAAsZ;CACzf,WAAW,QAAQ,WAAW,sDAAsD,qZAAsZ;CAC1e,WAAW,QAAQ,WAAW,sDAAsD,qZAAsZ;CAC1e,UAAU,QAAQ,WAAW,gDAAgD,qZAAsZ;CACne,eAAe,QAAQ,WAAW,0EAA0E,4FAA4F;CACxM,eAAe,QAAQ,WAAW,yEAAyE,4FAA4F;CACvM,eAAe,QAAQ,WAAW,+DAA+D,8DAA8D;CAC/J,yBAAyB,QAAQ,WAAW,kEAAkE,qEAAqE;CACnL,oBAAoB,QAAQ,WAAW,0EAA0E,qEAAqE;CACtL,oBAAoB,QAAQ,WAAW,iCAAiC,kDAAkD;CAC1H,OAAO,QAAQ,WAAW,8DAA8D,8GAA8G;CACtM,cAAc,QAAQ,WAAW,oCAAoC,+CAA+C;CACpH,UAAU,QAAQ,WAAW,qCAAqC,0CAA0C;CAC5G,UAAU,QAAQ,WAAW,4EAA4E,iIAAkI;CAC3O,kBAAkB,QAAQ,WAAW,qCAAqC,+CAA+C;CACzH,kBAAkB,QAAQ,WAAW,qCAAqC,+CAA+C;AAC3H,CAAC;AAED,MAAa,YAAmD,OAAO,OAAO;CAC5E,cAAc;EACZ,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,kBAAkB;EAChB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,cAAc;EACZ,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,SAAS;EACP,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,kBAAkB;EAChB,OAAO;EACP,QAAQ;EAGR,QAAQ;CACV;CACA,oBAAoB;EAClB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,yBAAyB;EACvB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,uBAAuB;EACrB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,6BAA6B;EAC3B,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,UAAU;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,MAAM;EACJ,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,UAAU;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,kBAAkB;EAChB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,kBAAkB;EAChB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,QAAQ;EACN,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;AACF,CAAC;AAED,MAAM,wBAAwB,YAAiC;CAC7D,OAAO;CACP,QAAQ,6BAA6B,OAAO;CAC5C,QAAQ,kHAAkH,OAAO;AACnI;AAEA,MAAa,cAAqD,OAAO,OAAO;CAC9E,eAAe;EAAE,OAAO;EAAQ,QAAQ;EAAkC,QAAQ;CAA+D;CACjJ,kBAAkB;EAAE,OAAO;EAAQ,QAAQ;EAA4E,QAAQ;CAAkI;CACjQ,sBAAsB;EAAE,OAAO;EAAW,QAAQ;EAA0E,QAAQ;CAA+H;CACnQ,aAAa;EAAE,OAAO;EAAQ,QAAQ;EAA0C,QAAQ;CAA2I;CACnO,eAAe;EAAE,OAAO;EAAQ,QAAQ;EAAwC,QAAQ;CAA6B;CACrH,YAAY;EAAE,OAAO;EAAQ,QAAQ;EAAqI,QAAQ;CAA6L;CAC/W,sBAAsB;EAAE,OAAO;EAAQ,QAAQ;EAAyC,QAAQ;CAA6G;CAC7M,oBAAoB;EAAE,OAAO;EAAQ,QAAQ;EAA8C,QAAQ;CAAkR;CACrX,uBAAuB;EACrB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,WAAW;EACT,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,oBAAoB;EAClB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,WAAW;EACT,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,UAAU;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,eAAe;EACb,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;EACX,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,gBAAgB;EACd,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,wBAAwB;EACtB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,iBAAiB;EACf,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,cAAc;EACZ,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,uBAAuB;EACrB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,SAAS;EACP,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,yBAAyB;EACvB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,yBAAyB;EACvB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,yBAAyB;EACvB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,WAAW,qBAAqB,wBAAyB;CACzD,OAAO,qBAAqB,uBAAuB;CACnD,eAAe;EACb,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,oBAAoB;EAClB,OAAO;EACP,QAAQ;EACR,QAAQ;CACV;CACA,uBAAuB,qBAAqB,sBAAsB;CAClE,qBAAqB,qBAAqB,iBAAiB;CAC3D,qBAAqB,qBAAqB,4BAA4B;CACtE,cAAc,qBAAqB,4BAA4B;AACjE,CAAC;AAED,SAAgB,WAAW,QAAkC;CAC3D,OAAO,UAAU;AACnB;AAEA,SAAgB,aAAa,OAAqB;CAChD,OAAO,YAAY,UAAU;EAC3B,OAAO;EACP,QAAQ,oBAAoB,KAAK,UAAU,KAAK,EAAE;CACpD;AACF;AAEA,SAAgB,kBAAkB,aAAqB,cAAwC;CAC7F,MAAM,SAAU,yBAA+C,SAAS,WAAW,IAC/E,oBACC,gBAAsC,SAAS,WAAW,IACzD,WACC,eAAqC,SAAS,WAAW,IAAI,UAAU,KAAA;CAC9E,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,kBAAkB,OAAO,GAAG;AACxE;AAEA,SAAgB,uBAAuB,UAAoC;CACzE,OAAO,cAAc;AACvB;AAEA,SAAgB,yBAAyB,UAAoC;CAC3E,OAAO,iBAAiB;AAC1B;;;;AC1iBA,SAAgB,iBAAiB,KAAuB;CACtD,MAAM,OAAO,QAAQ;CACrB,OAAO;EACL,KAAK,MAAM,WAAW,OAAO,UAAU;EACvC,KAAK,MAAM,WAAW,UAAU;EAChC,KAAK,MAAM,WAAW,OAAO,UAAU;EACvC,KAAK,YAAY,GAAG,UAAU;EAC9B,KAAK,KAAK,WAAW;EACrB,KAAK,KAAK,OAAO,UAAU;CAC7B;AACF;AAEA,SAAS,aAAa,OAAoD;CACxE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;CAChF,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,UAAqC,OAAO,MAAM,OAAO,QAAQ;CAC/G,OAAO,QAAQ,WAAW,IAAI,KAAA,IAAY,OAAO,YAAY,OAAO;AACtE;AAEA,SAAS,YAAY,MAAc,KAAc,YAA6C;CAC5F,IAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM,OAAO,KAAA;CACpD,MAAM,SAAS;CACf,MAAM,WAAW,OAAO,aAAa;CACrC,IAAI,OAAO,OAAO,QAAQ,UACxB,OAAO;EACL;EAAM;EAAY,WAAW;EAAmB,KAAK,OAAO;EAC5D,GAAI,aAAa,OAAO,OAAO,MAAM,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,aAAa,OAAO,OAAO,EAAG;EAC/F;CACF;CAEF,IAAI,OAAO,OAAO,YAAY,UAC5B,OAAO;EACL;EAAM;EAAY,WAAW;EAAS,SAAS,OAAO;EACtD,GAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,EAAE,MAAM,OAAO,KAAK,IAAI,MAAM,EAAE,IAAI,CAAC;EACtE,GAAI,aAAa,OAAO,GAAG,MAAM,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK,aAAa,OAAO,GAAG,EAAG;EACnF,GAAI,OAAO,OAAO,QAAQ,WAAW,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;EAC5D;CACF;AAGJ;AAEA,SAAgB,oBAAoB,KAAa,aAAuB,CAAC,GAA6D;CACpI,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,QAAQ,CAAC,GAAG,iBAAiB,GAAG,GAAG,GAAG,UAAU,GAAG;EAC5D,IAAI,CAAC,WAAW,IAAI,GAAG;EACvB,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;EAChD,QAAQ;GACN;EACF;EACA,MAAM,aAAc,QAAsC;EAC1D,IAAI,OAAO,eAAe,YAAY,eAAe,MAAM;EAC3D,QAAQ,KAAK,IAAI;EACjB,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,UAAU,GAAG;GACpD,MAAM,SAAS;GACf,MAAM,WAAW,QAAQ,IAAI,IAAI;GAGjC,IAAI,aAAa,KAAA,KAAa,OAAO,WAAW,YAAY,WAAW,QAClE,OAAO,YAAY,KAAA,KAAa,OAAO,QAAQ,KAAA,KAAa,OAAO,OAAO,aAAa,WAAW;IACrG,QAAQ,IAAI,MAAM;KAAE,GAAG;KAAU,UAAU,OAAO;KAAU,YAAY;IAAK,CAAC;IAC9E;GACF;GACA,MAAM,SAAS,YAAY,MAAM,KAAK,IAAI;GAC1C,IAAI,WAAW,KAAA,GAAW,QAAQ,IAAI,MAAM,MAAM;EACpD;CACF;CACA,OAAO;EAAE;EAAS;CAAQ;AAC5B;AAEA,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;AAC9B,MAAM,wBAAwB;AAM9B,SAAS,GAAG,YAAkC;CAC5C,OAAO,EAAE,YAAY,WAAW;AAClC;AAEA,SAAS,gBACP,QACA,MACA,QACA,UACmD;CACnD,IAAI,WAAW,KAAA,GAAW,OAAO,KAAA;CACjC,MAAM,SAAgD,CAAC;CACvD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;EACjD,MAAM,YAAY,sBAAsB,KAAK,KAAK;EAClD,IAAI,cAAc,MAAM;GACtB,OAAO,OAAO,GAAG,eAAe,UAAU,IAAI;GAC9C;EACF;EACA,IAAI,sBAAsB,KAAK,GAAG,GAChC,SAAS,KAAK;GACZ;GACA,SAAS,GAAG,KAAK,GAAG,IAAI;EAC1B,CAAC;EAEH,OAAO,OAAO;CAChB;CACA,OAAO;AACT;AAEA,SAAgB,mBAAmB,KAAa,aAAuB,CAAC,GAAwB;CAC9F,MAAM,EAAE,SAAS,YAAY,oBAAoB,KAAK,UAAU;CAChE,MAAM,WAAmC,CAAC;CAC1C,MAAM,UAA2B,CAAC;CAClC,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG;EACrC,IAAI,OAAO,UAAU;GACnB,SAAS,KAAK;IAAE,QAAQ,OAAO;IAAM,SAAS;GAAwC,CAAC;GACvF;EACF;EACA,IAAI,CAAC,oBAAoB,KAAK,OAAO,IAAI,GAAG;GAC1C,SAAS,KAAK;IACZ,QAAQ,OAAO;IACf,SAAS;GACX,CAAC;GACD;EACF;EACA,MAAM,SAAwB;GAAE,YAAY,OAAO;GAAM,WAAW,OAAO;EAAU;EACrF,IAAI,OAAO,cAAc,SAAS;GAChC,OAAO,UAAU,OAAO;GACxB,IAAI,OAAO,SAAS,KAAA,GAAW,OAAO,OAAO,OAAO;GACpD,MAAM,MAAM,gBAAgB,OAAO,MAAM,OAAO,OAAO,KAAK,QAAQ;GACpE,IAAI,QAAQ,KAAA,GAAW,OAAO,MAAM;GACpC,IAAI,OAAO,QAAQ,KAAA,GAAW,OAAO,MAAM,OAAO;EACpD,OAAO;GACL,OAAO,MAAM,OAAO;GACpB,MAAM,UAAU,gBAAgB,OAAO,MAAM,WAAW,OAAO,SAAS,QAAQ;GAChF,IAAI,YAAY,KAAA,GAAW,OAAO,UAAU;EAC9C;EACA,QAAQ,KAAK;GAAE,IAAI,OAAO,OAAO;GAAQ,MAAM;GAA+B;EAAO,CAAC;CACxF;CACA,OAAO;EAAE,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC;EAAG;EAAS;EAAU;CAAQ;AACtE;AAEA,SAAS,WAAW,OAAgB,QAAwB;CAC1D,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,gBAAiB,OAClE,OAAO,QAAS,MAAuB;CAEzC,IAAI,OAAO,UAAU,UACnB,OAAO,yBAAyB,KAAK,KAAK,IAAI,QAAQ,KAAK,UAAU,KAAK;CAE5E,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,IAAI,MAAM,WAAW,GAAG,OAAO;EAC/B,OAAO,KAAK,MAAM,KAAI,SAAQ,GAAG,OAAO,MAAM,WAAW,MAAM,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI;CAC5F;CACA,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAC/C,MAAM,SAAS;EACf,MAAM,OAAO,OAAO,KAAK,MAAM;EAC/B,IAAI,KAAK,WAAW,GAAG,OAAO;EAC9B,OAAO,KAAK,KAAK,KAAI,QAAO,GAAG,OAAO,IAAI,IAAI,IAAI,WAAW,OAAO,MAAM,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI;CACvG;CACA,OAAO,OAAO,KAAK;AACrB;;AAGA,SAAgB,eAAe,QAAqC;CAClE,IAAI,OAAO,QAAQ,WAAW,GAAG,OAAO;CACxC,MAAM,QAAkB,CAAC,WAAW;CACpC,KAAK,MAAM,SAAS,OAAO,SAAS;EAClC,MAAM,KAAK,aAAa,OAAO,MAAM,EAAE,GAAG;EAC1C,MAAM,KAAK,2CAA2C;EACtD,MAAM,KAAK,uBAAuB;EAClC,MAAM,KAAK,gBAAgB,WAAW,MAAM,QAAQ,QAAQ,GAAG;CACjE;CACA,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;AAC7B"}
@@ -348,6 +348,7 @@ var PiBridgedAgentSession = class {
348
348
  agent = {};
349
349
  messages = [];
350
350
  #seed = [];
351
+ #carried = /* @__PURE__ */ new WeakSet();
351
352
  #host;
352
353
  #handle;
353
354
  #session;
@@ -433,7 +434,19 @@ var PiBridgedAgentSession = class {
433
434
  const identity = (message) => JSON.stringify([message.role, message.content]);
434
435
  const known = new Set(this.messages.map(identity));
435
436
  this.#seed = next.filter((message) => !known.has(identity(message)));
436
- for (const message of this.#seed) this.messages.push(message);
437
+ for (const message of this.#seed) {
438
+ this.#carried.add(message);
439
+ this.messages.push(message);
440
+ }
441
+ }
442
+ /**
443
+ * Whether one transcript entry is carried context rather than part of the
444
+ * exchange in this child session.
445
+ * @param message - an entry of {@link messages}.
446
+ * @returns true for a seeded transcript entry or a host runtime snapshot.
447
+ */
448
+ isCarriedContext(message) {
449
+ return this.#carried.has(message);
437
450
  }
438
451
  #project(event) {
439
452
  const type = event.type;
@@ -498,6 +511,7 @@ var PiBridgedAgentSession = class {
498
511
  this.#messageProjection = this.#messageProjection.then(async () => {
499
512
  const message = await this.#host.messageFromSessionEvent(event);
500
513
  if (message === void 0) return;
514
+ if ((event.data?.source)?.form === "snapshot") this.#carried.add(message);
501
515
  this.messages.push(message);
502
516
  emit({
503
517
  type: "message_start",
@@ -541,7 +555,7 @@ var PiBridgedAgentSession = class {
541
555
  if (rendered.length > 0) {
542
556
  const seedBlocks = await this.#host.piContentToDsh([{
543
557
  type: "text",
544
- text: `<prior-conversation>\n${rendered.join("\n\n")}\n</prior-conversation>`
558
+ text: `<${SEED_CARRIER_TAG}>\n${rendered.join("\n\n")}\n</${SEED_CARRIER_TAG}>`
545
559
  }]);
546
560
  this.#host.deliver(this.#handle.agent, createUserMessage({
547
561
  content: seedBlocks,
@@ -639,6 +653,15 @@ var PiBridgedAgentSession = class {
639
653
  * @param requested - a label the calling package supplied, if any.
640
654
  * @param packageName - the Pi package the call came from.
641
655
  */
656
+ /**
657
+ * Envelope the bridge wraps a seeded transcript in before handing it to the
658
+ * child as one durable message.
659
+ *
660
+ * Exported because it is a CONTRACT, not a formatting detail: a reader of the
661
+ * child session (the side panel) has to recognise the carrier to tell carried
662
+ * context apart from the exchange, and matching on a copied string would drift.
663
+ */
664
+ const SEED_CARRIER_TAG = "prior-conversation";
642
665
  function childLabel(requested, packageName) {
643
666
  if (typeof requested === "string" && requested.trim().length > 0) return requested.trim().slice(0, 80);
644
667
  const owner = packageName?.trim();
@@ -698,6 +721,105 @@ async function createBridgedAgentSession(host, options) {
698
721
  return { session: new PiBridgedAgentSession(host, handle, tools) };
699
722
  }
700
723
  //#endregion
724
+ //#region src/side-panel.ts
725
+ /** Flatten one Pi message's content to the text a panel row shows. */
726
+ function messageText(message) {
727
+ const content = message.content;
728
+ if (typeof content === "string") return content;
729
+ if (!Array.isArray(content)) return "";
730
+ const parts = [];
731
+ for (const block of content) if (block.type === "text" && typeof block.text === "string") parts.push(block.text);
732
+ else if (block.type === "toolCall" && typeof block.name === "string") parts.push(`[tool: ${block.name}]`);
733
+ return parts.join("\n");
734
+ }
735
+ /**
736
+ * Live side threads, keyed by the parent session they belong to.
737
+ *
738
+ * Host-level (one per engine instance, like the provider directory): the panel
739
+ * is one surface, however many Pi packages contribute threads to it.
740
+ */
741
+ var SidePanelRegistry = class {
742
+ #byParent = /* @__PURE__ */ new Map();
743
+ /**
744
+ * Track one child session under its parent.
745
+ * @param parentSessionId - the session the panel floats over.
746
+ * @param thread - the child's identity and live session object.
747
+ * @returns a disposer that removes the thread from the panel.
748
+ */
749
+ track(parentSessionId, thread) {
750
+ const threads = this.#byParent.get(parentSessionId) ?? /* @__PURE__ */ new Map();
751
+ threads.set(thread.id, thread);
752
+ this.#byParent.set(parentSessionId, threads);
753
+ return () => {
754
+ const live = this.#byParent.get(parentSessionId);
755
+ if (live === void 0) return;
756
+ live.delete(thread.id);
757
+ if (live.size === 0) this.#byParent.delete(parentSessionId);
758
+ };
759
+ }
760
+ /**
761
+ * The panel's view of one parent session.
762
+ * @param parentSessionId - session the browser is currently showing.
763
+ * @returns every side thread opened under it, oldest first.
764
+ */
765
+ snapshot(parentSessionId) {
766
+ const threads = this.#byParent.get(parentSessionId);
767
+ if (threads === void 0) return [];
768
+ return [...threads.values()].map((thread) => ({
769
+ id: thread.id,
770
+ label: thread.label,
771
+ ...thread.package === void 0 ? {} : { package: thread.package },
772
+ running: thread.session.isStreaming === true,
773
+ messages: thread.session.messages.filter((message) => !thread.session.isCarriedContext(message)).map((message) => ({
774
+ role: String(message.role ?? ""),
775
+ text: messageText(message)
776
+ })).filter((entry) => !entry.text.startsWith(`<${SEED_CARRIER_TAG}>`)).filter((entry) => entry.text.length > 0)
777
+ }));
778
+ }
779
+ };
780
+ /**
781
+ * Serve the panel's own read route on the host's web server.
782
+ *
783
+ * One prefix, one GET: the client half polls it for the session it is showing.
784
+ * A composition with no web server (the CLI profile) simply has no panel, which
785
+ * is the correct outcome rather than an error — the side conversation itself
786
+ * still runs, and the host's subagent catalog still lists it.
787
+ * @param ctx - the mounting context.
788
+ * @param registry - live thread registry to read from.
789
+ * @returns whether the route was registered.
790
+ */
791
+ function registerSidePanelRoute(ctx, registry) {
792
+ const web = ctx.get("webServer");
793
+ if (web === void 0 || typeof web.register !== "function") return false;
794
+ ctx.effect(() => web.register({
795
+ kind: "prefix",
796
+ path: "/pi2dsh",
797
+ handler: async (req, res) => {
798
+ const response = res;
799
+ const method = String(req.method ?? "GET");
800
+ if (method !== "GET" && method !== "HEAD") {
801
+ response.writeHead(405);
802
+ response.end();
803
+ return;
804
+ }
805
+ const url = new URL(String(req.url ?? "/"), "http://pi2dsh.invalid");
806
+ if (url.pathname !== "/pi2dsh/side-panel") {
807
+ response.writeHead(404);
808
+ response.end();
809
+ return;
810
+ }
811
+ const session = url.searchParams.get("session") ?? "";
812
+ const body = JSON.stringify({ threads: session === "" ? [] : registry.snapshot(session) });
813
+ response.writeHead(200, {
814
+ "content-type": "application/json; charset=utf-8",
815
+ "cache-control": "no-store"
816
+ });
817
+ response.end(method === "HEAD" ? void 0 : body);
818
+ }
819
+ }), "pi2dsh: side-panel route");
820
+ return true;
821
+ }
822
+ //#endregion
701
823
  //#region src/compat/vendor/pi-tool-validation.ts
702
824
  const validatorCache = /* @__PURE__ */ new WeakMap();
703
825
  const TYPEBOX_KIND = Symbol.for("TypeBox.Kind");
@@ -1888,6 +2010,8 @@ function registerPiProviderRoute(options) {
1888
2010
  }
1889
2011
  //#endregion
1890
2012
  //#region src/runtime.ts
2013
+ /** Fallback thread ids when a child session reports none. */
2014
+ let sidePanelSerial = 0;
1891
2015
  function logger(ctx) {
1892
2016
  const candidate = ctx.logger;
1893
2017
  return {
@@ -4273,7 +4397,24 @@ async function applyPiPackage(ctx, options) {
4273
4397
  }));
4274
4398
  ctx.effect(() => () => __setPiAiLlmBridge(void 0));
4275
4399
  }
4276
- __setSubagentSessionFactory((subagentOptions) => createBridgedAgentSession({
4400
+ const sidePanel = state.shared.sidePanel ??= new SidePanelRegistry();
4401
+ if (state.shared.sidePanelRouted !== true) state.shared.sidePanelRouted = registerSidePanelRoute(ctx, sidePanel);
4402
+ __setSubagentSessionFactory(async (subagentOptions) => {
4403
+ const created = await createBridgedAgentSession(subagentHost(), subagentOptions);
4404
+ const parent = agentSession(currentAgent(state));
4405
+ const parentId = parent === void 0 ? "" : String(parent.id ?? "");
4406
+ if (parentId.length > 0) {
4407
+ const dispose = sidePanel.track(parentId, {
4408
+ id: String(created.session.sessionId ?? "") || `pi2dsh-thread-${parentId}-${sidePanelSerial++}`,
4409
+ label: childLabel(subagentOptions.label, state.packageName),
4410
+ package: state.packageName,
4411
+ session: created.session
4412
+ });
4413
+ ctx.effect(() => dispose);
4414
+ }
4415
+ return created;
4416
+ });
4417
+ const subagentHost = () => ({
4277
4418
  cordis: ctx,
4278
4419
  cwd: () => cwdOf(currentAgent(state)),
4279
4420
  parentSessionId: () => {
@@ -4292,7 +4433,7 @@ async function applyPiPackage(ctx, options) {
4292
4433
  messageFromSessionEvent: (event) => messageFromSessionEvent(ctx, event),
4293
4434
  messageSource: state.messageSource,
4294
4435
  packageName: state.packageName
4295
- }, subagentOptions));
4436
+ });
4296
4437
  ctx.effect(() => () => __setSubagentSessionFactory(void 0));
4297
4438
  await registerPromptCommands(ctx, state, rootDir, options.manifest);
4298
4439
  const onExtensionError = (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`);
@@ -4336,4 +4477,4 @@ const runtimeInternals = {
4336
4477
  //#endregion
4337
4478
  export { runtimeInternals as i, normalizeToolSchema as n, registerVisionCompanions as r, applyPiPackage as t };
4338
4479
 
4339
- //# sourceMappingURL=runtime-DsPaznXJ.mjs.map
4480
+ //# sourceMappingURL=runtime-B_Ig28og.mjs.map