@agimon-ai/po-core 0.0.0-alpha.65 → 0.0.0-alpha.67

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.
@@ -1 +1 @@
1
- {"version":3,"file":"headless.cjs","names":[],"sources":["../../../src/schemas/headless.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { CallToolResult, Tool } from '@modelcontextprotocol/server';\nimport type { Static, TSchema } from 'typebox';\n\nimport type { SessionToolSurface } from '../types/server/sessionToolSurface';\nimport type { PoApprovalPolicy, PoApprovalPrompt } from './approval';\nimport type { PoSessionContext } from './hubChannel';\nimport type { PoNotificationRequest } from './notification';\nimport type { PoServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const PO_HEADLESS_HOST_SERVICE = 'po/headless-host';\nexport const PO_HEADLESS_OWNER = Symbol.for('po/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'PoHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory package-hook failure. */\nexport class PoHeadlessPromptAdmissionError extends Error {\n constructor(cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n this.name = PROMPT_ADMISSION_ERROR;\n }\n}\n\nconst SESSION_SETUP_ERROR = 'PoSessionSetupError';\n\n/**\n * A session cannot start until the user fixes their setup, such as configuring a model.\n *\n * Its message is written for the user and says what to do, so a server returns it as is\n * rather than hiding it behind a generic internal error.\n */\nexport class PoSessionSetupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = SESSION_SETUP_ERROR;\n }\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoSessionSetupError(error: unknown): error is Error {\n return error instanceof Error && error.name === SESSION_SETUP_ERROR;\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nconst TOOL_BUSY_ERROR = 'PoHeadlessToolBusyError';\n\n/** The tool and its hooks have not started. */\nexport class PoHeadlessToolBusyError extends Error {\n constructor() {\n super('An operation is already running');\n this.name = TOOL_BUSY_ERROR;\n }\n}\n\nexport function isPoHeadlessToolBusyError(error: unknown): boolean {\n return error instanceof Error && error.name === TOOL_BUSY_ERROR;\n}\n\nexport interface PoHeadlessSelection {\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n readonly domains: readonly string[];\n readonly profile?: string;\n /** Feature-owned activation sets, keyed by the contributing capability. */\n readonly state?: Readonly<Record<string, readonly string[]>>;\n}\n\n/** One package-owned selection transition. Server packages change exactly one axis per operation. */\nexport type PoHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | {\n readonly axis: 'state';\n readonly key: string;\n readonly values: readonly string[];\n };\n\n/** A selection axis a listener re-applies from its config even when its value did not change. */\nexport type PoHeadlessRefreshAxis = 'majorMode' | 'domains' | 'profile';\n\n/** How a selection was applied. `refresh` names axes whose config changed on disk. */\nexport interface PoHeadlessSelectionApplied {\n readonly refresh?: readonly PoHeadlessRefreshAxis[];\n}\n\nexport function readPoHeadlessOwner(context: Context): PoServerBundleEntry | undefined {\n return (context as Context & { [PO_HEADLESS_OWNER]?: PoServerBundleEntry })[PO_HEADLESS_OWNER];\n}\n\nexport interface PoHeadlessRegistration {\n dispose(): void;\n}\n\nexport type PoHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface PoHeadlessToolResult {\n content: PoHeadlessContent[];\n /** Public MCP result data. Internal renderer details are not a remote result contract. */\n structuredContent?: Record<string, unknown>;\n /** Component-only MCP metadata, never inferred from internal renderer details. */\n _meta?: CallToolResult['_meta'];\n details?: unknown;\n isError?: boolean;\n}\n\nlet crcTable: Uint32Array | undefined;\n\nfunction crc32(bytes: Uint8Array, start: number, end: number): number {\n if (crcTable === undefined) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (let i = start; i < end; i++) crc = crcTable[(crc ^ bytes[i]!) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nfunction startsWith(bytes: Uint8Array, prefix: readonly number[], offset = 0): boolean {\n return prefix.every((byte, index) => bytes[offset + index] === byte);\n}\n\n/** Why the model API would reject this image, or undefined when it looks decodable. Only png, jpeg, gif and webp are checked. */\nexport function invalidImageReason(data: string, mimeType: string): string | undefined {\n let bytes: Uint8Array;\n try {\n bytes = Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n } catch {\n return 'the data is not valid base64';\n }\n if (mimeType === 'image/png') {\n if (!startsWith(bytes, PNG_SIGNATURE)) return 'the data is not a PNG';\n const view = new DataView(bytes.buffer);\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = view.getUint32(offset);\n const end = offset + 8 + length;\n if (end + 4 > bytes.length) break;\n if (crc32(bytes, offset + 4, end) !== view.getUint32(end)) return 'a PNG chunk failed its checksum';\n if (startsWith(bytes, [0x49, 0x45, 0x4e, 0x44], offset + 4)) return undefined;\n offset = end + 4;\n }\n return 'the PNG is truncated';\n }\n if (mimeType === 'image/jpeg') return startsWith(bytes, [0xff, 0xd8]) ? undefined : 'the data is not a JPEG';\n if (mimeType === 'image/gif')\n return startsWith(bytes, [0x47, 0x49, 0x46, 0x38]) ? undefined : 'the data is not a GIF';\n if (mimeType === 'image/webp')\n return startsWith(bytes, [0x52, 0x49, 0x46, 0x46]) && startsWith(bytes, [0x57, 0x45, 0x42, 0x50], 8)\n ? undefined\n : 'the data is not a WebP';\n return undefined;\n}\n\n/** Keeps valid images and swaps an undecodable one for a text note, since one bad image fails the whole turn and every later one. */\nexport function dropInvalidImages(content: readonly PoHeadlessContent[]): PoHeadlessContent[] {\n return content.map((part) => {\n if (part.type !== 'image') return part;\n const reason = invalidImageReason(part.data, part.mimeType);\n return reason === undefined ? part : { type: 'text', text: `[image omitted: ${reason}]` };\n });\n}\n\n/**\n * Narrows a Pi tool result to the headless contract. Pi types `structuredContent` as any JSON\n * value, while MCP only accepts an object, so anything else is dropped rather than forwarded.\n */\nexport function toPoHeadlessToolResult(result: {\n readonly content: PoHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly _meta?: CallToolResult['_meta'];\n readonly isError?: boolean;\n}): PoHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n ...(typeof structuredContent === 'object' && structuredContent !== null && !Array.isArray(structuredContent)\n ? { structuredContent: structuredContent as Record<string, unknown> }\n : {}),\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\nexport interface PoHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n purpose?: 'feedback';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n /** Set only by po-approval: a `select` of Approve/Deny the app draws as an approval card. */\n approval?: PoApprovalPrompt;\n}\n\nexport interface PoHeadlessClient {\n /**\n * Operator-facing surface only: the body is flattened to one line and capped at 4096 characters\n * by schemas/notification.ts:73-83, and the model never sees it. Use session.admitPrompt to\n * reach the model.\n */\n notify(request: PoNotificationRequest): void | Promise<void>;\n request(request: PoHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n /** Only the currently visible feedback question, never an approval or queued request. */\n pendingFeedback?():\n | {\n id: string;\n kind: 'select' | 'input';\n title: string;\n message?: string;\n labels?: string[];\n }\n | undefined;\n /** Returns false for stale ids, queued requests and approvals. */\n answerFeedback?(id: string, value: string): boolean;\n /** Only the visible approval at the head of the dialog queue. */\n pendingApproval?(): PoApprovalPrompt | undefined;\n /** Refuses stale, queued, expired and duplicate answers. Voice cannot answer a human approval. */\n answerApproval?(id: string, decision: 'approved' | 'denied', channel: 'voice' | 'app'): boolean;\n /** Ignored once the session has closed, so a package can clear its status while it unwinds. */\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface PoHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface PoHeadlessSession {\n /** Live host close intent, set synchronously before interruption. Absent for a person's stop or remove. */\n readonly closeReason?: 'released' | 'host_shutdown';\n readModelSettings?(): Promise<PoHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<PoHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n /** Stream matching history newest first. Stop iteration to stop storage reads. */\n entriesNewestFirst(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): AsyncIterable<Record<string, unknown>>;\n appendCustomEntry(type: string, data: unknown): Promise<void>;\n /** Append a displayable informational message to history and model context, without admitting input or starting a turn. */\n appendMessage?(message: { type: string; text: string; display?: boolean; details?: unknown }): Promise<string | void>;\n /**\n * Admit one custom message without awaiting its turn, using environmental input policy.\n * Defaults to followUp. Reusing requestId deduplicates normal Durable admission retries;\n * locked-agent appends and deferred operator admission do not provide that guarantee.\n * The receipt's settled resolves when the run that consumed the message ends; a locked agent\n * resolves it at once. Hosts without tracking return nothing.\n */\n admitMessage?(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n delivery?: 'steer' | 'followUp',\n requestId?: string,\n ): Promise<{ requestId: string; settled: Promise<void> } | void>;\n /**\n * Register a checkpoint flush before the next tool-turn request. Idle writes return undefined instead of queueing when busy.\n * `resetContext` starts native context at the message, which stands for itself followed by `retainedMessages`.\n */\n registerCheckpointBoundary?(\n callback: (boundary: {\n signal?: AbortSignal;\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n }) => Promise<void>,\n ): {\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n dispose(): void;\n };\n /** Detached canonical model context before package transformations, with context edits applied and no system message. */\n contextMessages?(): Promise<readonly Record<string, unknown>[]>;\n /** The latest measured assistant usage and the selected model's context window. */\n contextUsage?(): Promise<{ tokens: number | null; contextWindow: number } | undefined>;\n /** Label a durable entry without admitting input or starting a turn. */\n setLabel?(entryId: string, label: string | undefined): Promise<void>;\n /**\n * Delivers operator input through prompt preflight and awaits its turn.\n * Environmental input uses admitPrompt with origin omitted instead.\n * An idle agent is woken; busy delivery uses Durable steering or follow-up.\n */\n prompt(text: string, delivery?: 'prompt' | 'steer' | 'followUp'): Promise<void>;\n /**\n * Admits input without awaiting its turn. Environmental input omits origin and never\n * changes the operator queue. Operator origin uses prompt preflight, including voice\n * capture; 'interrupt' cancels the active run and admits operator input while preserving\n * retained queued work. Environmental callers may reuse requestId when retrying the same input.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n requestId?: string,\n ): Promise<void>;\n /** Stops the current run. With expectedOperationId, a different or finished operation is left alone. */\n abort(expectedOperationId?: string): Promise<void>;\n compact(instructions?: string): Promise<void>;\n /** operationId names the current run, absent while idle or settling. */\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean; operationId?: string }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** The current branch's newest entry, for a child that starts from this session's history. */\n forkSource?(): Promise<{\n kind: 'fork';\n entryId?: string;\n }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface PoMcpSkillAccess {\n list(): Promise<readonly { name: string; description: string }[]>;\n read(name: string): Promise<string>;\n}\n\n/** A stateless auxiliary request. These tools are private to this request, never registered on the agent. */\nexport interface PoHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary token usage in this session, including rejected results. */\n recordUsage?: boolean;\n tools: readonly Pick<PoHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface PoHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\n/** Credential-free catalog metadata. Packages cannot obtain auth, headers, or a mutable registry. */\nexport interface PoHeadlessModelMetadata {\n readonly provider: string;\n readonly id: string;\n readonly api?: string;\n readonly baseUrl?: string;\n readonly name?: string;\n readonly compat?: Readonly<Record<string, boolean | string>>;\n}\n\n/** Host policy retained by a supervised tool sequence after its original call returns. */\nexport interface PoHeadlessToolContinuation {\n admit(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n signal?: AbortSignal;\n }): Promise<Record<string, unknown>>;\n finalize(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n result: PoHeadlessToolResult;\n signal?: AbortSignal;\n }): Promise<PoHeadlessToolResult>;\n}\n\nexport interface PoHeadlessExecutionContext {\n /** Present only on an admitted tool invocation. Retained callbacks recheck current host policy. */\n readonly toolContinuation?: PoHeadlessToolContinuation;\n readonly cwd: string;\n /** The checkout the session runs in, distinct from the tool execution directory. */\n readonly repoRoot: string;\n readonly sessionId: string;\n /** Who invoked the tool: the session's own agent, or a subagent borrowing it. Absent when the host cannot tell. */\n readonly caller?: 'main' | 'child';\n /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: PoSessionContext;\n /** Host-owned presence, also supplied when the session has no workspace context. */\n readonly interaction?: 'interactive' | 'unattended';\n /** Immutable session configuration. Packages must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: PoHeadlessClient;\n readonly session: PoHeadlessSession;\n readonly model?: PoHeadlessModelMetadata;\n /** Lookup in this session's catalog, including physical models named by finalized messages. */\n readonly getModel?: (provider: string, id: string) => PoHeadlessModelMetadata | undefined;\n /** Detached credential-free authenticated chat catalog, read after refreshing provider availability. */\n readonly getAvailableModels?: () => Promise<\n readonly {\n readonly provider: string;\n readonly id: string;\n }[]\n >;\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\n /** Tool-less conversation summary through the host's guarded session provider. */\n summarize?(\n reference: string,\n request: {\n messages: readonly Record<string, unknown>[];\n instructions: string;\n previousSummary?: string;\n thinkingLevel?: ThinkingLevel;\n signal?: AbortSignal;\n },\n ): Promise<string>;\n complete(\n reference: string,\n request: {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary usage and reject truncated text rather than returning partial output. */\n recordUsage?: boolean;\n },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: PoHeadlessToolCompletionRequest): Promise<PoHeadlessToolCompletionResult>;\n };\n /** Guarded image operation. Credentials and transport configuration remain host-owned. */\n readonly imageGeneration?: {\n available(): boolean;\n generate(request: {\n prompt: string;\n transparentBackground?: boolean;\n images?: readonly { data: string; mimeType: string }[];\n correlationId: string;\n signal?: AbortSignal;\n }): Promise<{ data: string; mimeType: 'image/png'; requestId?: string; generationId?: string }>;\n };\n /**\n * Guarded web search. Credentials, endpoint, model choice, session identity and transport remain host-owned.\n * `commands` follows a schema owned by the calling package; the host only bounds it.\n */\n readonly webSearch?: {\n available(): boolean;\n search(request: {\n commands: Readonly<Record<string, unknown>>;\n /** Optional plain-text excerpt, oldest first. Omit to send no conversation content. */\n conversation?: readonly { role: 'user' | 'assistant'; text: string }[];\n access: 'cached' | 'indexed' | 'live';\n signal?: AbortSignal;\n }): Promise<{ output: string; results?: readonly Record<string, unknown>[] }>;\n };\n readonly selection: PoHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: PoMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface PoHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain' | 'shared'; mode: string; label?: string };\n domain?: string;\n /** Any selected domain must match. Absent is unrestricted; empty never matches. */\n domains?: readonly string[];\n}\n\nexport interface PoHeadlessToolRestriction {\n when?: PoHeadlessCondition;\n /** Optional capability ceiling. An empty list disables every tool. */\n allowedTools?: readonly string[];\n /**\n * Narrow exclusions without disabling unrelated tools. Exclude a tool your package owns, or a\n * specific foreign tool the mode exists to withdraw. Never enumerate an allowlist here.\n */\n excludedTools?: readonly string[];\n}\n\nexport interface PoHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: PoHeadlessCondition;\n name: string;\n label?: string;\n description: string;\n parameters: TParameters;\n annotations?: Tool['annotations'];\n outputSchema?: Tool['outputSchema'];\n /** Remote presentation only. Component tool access must be explicitly opted into. */\n _meta?: Tool['_meta'] & {\n ui?: { resourceUri?: string; visibility?: ('model' | 'app')[] };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n /**\n * Keeps the tool from subagents, which otherwise borrow the parent's tools. Set it when the tool needs\n * the person to answer, since nobody can answer a subagent, or when it acts for the main agent itself.\n */\n mainAgentOnly?: boolean;\n /** Asks the person before each call; see PoApprovalPolicy for who can answer. */\n approval?: PoApprovalPolicy;\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ): Promise<PoHeadlessToolResult>;\n}\n\n/**\n * One package contribution to the session's resource surface.\n *\n * `kind` decides what the model is billed for, and the difference is large:\n * - `context` is EAGER. `read()` runs on every prompt build and the text is pasted\n * into the system prompt verbatim. Reserve it for small live session state that\n * exists nowhere on disk. Never use it for a file the package ships: a README\n * registered this way costs its full length on every single turn.\n * - `skill` is LAZY. Only `name`, `description` and `path` reach the prompt; the\n * agent reads the file itself when the description matches the task.\n * - `prompt` is inert until the user invokes it by name.\n *\n * The rule in one line: if it is a file the package ships, it is a `skill`.\n */\nexport interface PoHeadlessResource {\n when?: PoHeadlessCondition;\n name: string;\n /** Model-visible selection signal. A `skill` without one tells the agent nothing. */\n description?: string;\n /** Absolute path of the file `read()` returns, so an advertised skill is one the agent can open. */\n path?: string;\n /**\n * A `skill` listed in the system prompt itself, kept out of the `load_skill` catalog and\n * `search_skills`. For a few always-relevant guides (the code-mode how-tos) that search would miss.\n */\n pinned?: boolean;\n kind: 'prompt' | 'skill' | 'context';\n read(context: PoHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface PoHeadlessCommand {\n when?: PoHeadlessCondition;\n name: string;\n description: string;\n /** Selection-only control allowed after a coherent selection fails admission. */\n selectionRecovery?: boolean;\n execute(args: string, context: PoHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type PoHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\n | 'agent_end'\n | 'agent_settled'\n | 'turn_start'\n | 'turn_end'\n | 'context'\n | 'before_provider_request'\n | 'message_start'\n | 'message_update'\n | 'message_end'\n | 'tool_call'\n | 'tool_execution_start'\n | 'tool_execution_update'\n | 'tool_execution_end'\n | 'tool_result'\n | 'model_select'\n | 'session_before_compact'\n | 'session_compact';\n\nexport type PoHeadlessHookEvent<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? {\n lane: string;\n runId: string;\n model: { provider: string; id: string; api?: string };\n payload: unknown;\n }\n : E extends 'session_before_compact'\n ? {\n reason: string;\n preparation: unknown;\n instructions?: string;\n customInstructions?: string;\n }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface PoHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type PoHeadlessHookResult<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? {\n cancel?: boolean;\n decline?: boolean;\n compaction?: PoHeadlessCompactionResult;\n } | void\n : E extends 'context'\n ? { messages?: unknown[]; systemPrompt?: string } | void\n : E extends 'before_agent_start'\n ? { systemPrompt?: string } | void\n : E extends 'tool_call'\n ? {\n args?: Record<string, unknown>;\n block?: { reason: string; terminate?: boolean };\n } | void\n : E extends 'tool_result'\n ? {\n content?: PoHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type PoHeadlessHook<E extends PoHeadlessEventName = PoHeadlessEventName> = E extends PoHeadlessEventName\n ? {\n when?: PoHeadlessCondition;\n event: E;\n handle(\n event: Readonly<PoHeadlessHookEvent<E>>,\n context: PoHeadlessExecutionContext,\n ): PoHeadlessHookResult<E> | Promise<PoHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained package can register activity without starting disabled watchers or services. */\nexport interface PoHeadlessActivity {\n when?: PoHeadlessCondition;\n name: string;\n start(context: PoHeadlessExecutionContext): (() => void | Promise<void>) | Promise<() => void | Promise<void>>;\n}\n\n/** Read-only metadata for the currently applied session, never executable declarations or resource bodies. */\nexport interface PoHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: PoHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\n/** Visibility controls model discovery only, never admission for external execution. */\nexport function isPoHeadlessToolModelVisible(tool: Pick<PoHeadlessTool, '_meta'>): boolean {\n const visibility = tool._meta?.ui?.visibility;\n return visibility === undefined || visibility.includes('model');\n}\n\nexport interface PoHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly PoHeadlessCapability[];\n}\n\n/** Session skill discovery tools, adapted to the size of the active catalog. */\nexport const PO_LOAD_SKILL_TOOL = 'load_skill';\nexport const PO_SEARCH_SKILLS_TOOL = 'search_skills';\nexport interface PoHeadlessHostService {\n readonly context: PoHeadlessExecutionContext;\n /** Admitted external execution, sharing native hooks, restrictions and session lifetime. */\n readonly toolSurface?: Pick<SessionToolSurface, 'readSurface' | 'invokeTool'>;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n /** Names and descriptions of searchable applied skills, excluding pinned guides and instruction bodies. */\n listSkills(): readonly { readonly name: string; readonly description: string }[];\n /** atToolBoundary defers the change to the next tool boundary, as slash commands do; idle sessions apply at once. */\n changeSelection(change: PoHeadlessSelectionChange, options?: { atToolBoundary?: boolean }): Promise<void>;\n assertActive(source?: string): void;\n /** Whether a package owns contributions in the currently applied selection. */\n isSourceActive(source: string): boolean;\n subscribeSelection(\n listener: (selection: PoHeadlessSelection, applied: PoHeadlessSelectionApplied) => void | Promise<void>,\n ): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): PoHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: PoHeadlessToolRestriction): PoHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: PoHeadlessTool<TParameters>): PoHeadlessRegistration;\n registerResource(resource: PoHeadlessResource): PoHeadlessRegistration;\n registerCommand(command: PoHeadlessCommand): PoHeadlessRegistration;\n registerHook(hook: PoHeadlessHook): PoHeadlessRegistration;\n registerActivity(activity: PoHeadlessActivity): PoHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/headless-host': PoHeadlessHostService;\n }\n}\n\nexport function readPoHeadlessHost(context: Context): PoHeadlessHostService | undefined {\n return context.get(PO_HEADLESS_HOST_SERVICE) as PoHeadlessHostService | undefined;\n}\n\nexport function requirePoHeadlessHost(context: Context): PoHeadlessHostService {\n const host = readPoHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Po headless session host.');\n return host;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"headless.cjs","names":[],"sources":["../../../src/schemas/headless.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { CallToolResult, Tool } from '@modelcontextprotocol/server';\nimport type { Static, TSchema } from 'typebox';\n\nimport type { SessionToolSurface } from '../types/server/sessionToolSurface';\nimport type { PoApprovalPolicy, PoApprovalPrompt } from './approval';\nimport type { PoSessionContext } from './hubChannel';\nimport type { PoNotificationRequest } from './notification';\nimport type { PoServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const PO_HEADLESS_HOST_SERVICE = 'po/headless-host';\nexport const PO_HEADLESS_OWNER = Symbol.for('po/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'PoHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory package-hook failure. */\nexport class PoHeadlessPromptAdmissionError extends Error {\n constructor(cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n this.name = PROMPT_ADMISSION_ERROR;\n }\n}\n\nconst SESSION_SETUP_ERROR = 'PoSessionSetupError';\n\n/**\n * A session cannot start until the user fixes their setup, such as configuring a model.\n *\n * Its message is written for the user and says what to do, so a server returns it as is\n * rather than hiding it behind a generic internal error.\n */\nexport class PoSessionSetupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = SESSION_SETUP_ERROR;\n }\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoSessionSetupError(error: unknown): error is Error {\n return error instanceof Error && error.name === SESSION_SETUP_ERROR;\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nconst TOOL_BUSY_ERROR = 'PoHeadlessToolBusyError';\n\n/** The tool and its hooks have not started. */\nexport class PoHeadlessToolBusyError extends Error {\n constructor() {\n super('An operation is already running');\n this.name = TOOL_BUSY_ERROR;\n }\n}\n\nexport function isPoHeadlessToolBusyError(error: unknown): boolean {\n return error instanceof Error && error.name === TOOL_BUSY_ERROR;\n}\n\nexport interface PoHeadlessSelection {\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n readonly domains: readonly string[];\n readonly profile?: string;\n /** Feature-owned activation sets, keyed by the contributing capability. */\n readonly state?: Readonly<Record<string, readonly string[]>>;\n}\n\n/** One package-owned selection transition. Server packages change exactly one axis per operation. */\nexport type PoHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | {\n readonly axis: 'state';\n readonly key: string;\n readonly values: readonly string[];\n };\n\n/** A selection axis a listener re-applies from its config even when its value did not change. */\nexport type PoHeadlessRefreshAxis = 'majorMode' | 'domains' | 'profile';\n\n/** How a selection was applied. `refresh` names axes whose config changed on disk. */\nexport interface PoHeadlessSelectionApplied {\n readonly refresh?: readonly PoHeadlessRefreshAxis[];\n}\n\nexport function readPoHeadlessOwner(context: Context): PoServerBundleEntry | undefined {\n return (context as Context & { [PO_HEADLESS_OWNER]?: PoServerBundleEntry })[PO_HEADLESS_OWNER];\n}\n\nexport interface PoHeadlessRegistration {\n dispose(): void;\n}\n\nexport type PoHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface PoHeadlessToolResult {\n content: PoHeadlessContent[];\n /** Public MCP result data. Internal renderer details are not a remote result contract. */\n structuredContent?: Record<string, unknown>;\n /** Component-only MCP metadata, never inferred from internal renderer details. */\n _meta?: CallToolResult['_meta'];\n details?: unknown;\n isError?: boolean;\n}\n\nlet crcTable: Uint32Array | undefined;\n\nfunction crc32(bytes: Uint8Array, start: number, end: number): number {\n if (crcTable === undefined) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (let i = start; i < end; i++) crc = crcTable[(crc ^ bytes[i]!) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nfunction startsWith(bytes: Uint8Array, prefix: readonly number[], offset = 0): boolean {\n return prefix.every((byte, index) => bytes[offset + index] === byte);\n}\n\n/** Why the model API would reject this image, or undefined when it looks decodable. Only png, jpeg, gif and webp are checked. */\nexport function invalidImageReason(data: string, mimeType: string): string | undefined {\n let bytes: Uint8Array;\n try {\n bytes = Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n } catch {\n return 'the data is not valid base64';\n }\n if (mimeType === 'image/png') {\n if (!startsWith(bytes, PNG_SIGNATURE)) return 'the data is not a PNG';\n const view = new DataView(bytes.buffer);\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = view.getUint32(offset);\n const end = offset + 8 + length;\n if (end + 4 > bytes.length) break;\n if (crc32(bytes, offset + 4, end) !== view.getUint32(end)) return 'a PNG chunk failed its checksum';\n if (startsWith(bytes, [0x49, 0x45, 0x4e, 0x44], offset + 4)) return undefined;\n offset = end + 4;\n }\n return 'the PNG is truncated';\n }\n if (mimeType === 'image/jpeg') return startsWith(bytes, [0xff, 0xd8]) ? undefined : 'the data is not a JPEG';\n if (mimeType === 'image/gif')\n return startsWith(bytes, [0x47, 0x49, 0x46, 0x38]) ? undefined : 'the data is not a GIF';\n if (mimeType === 'image/webp')\n return startsWith(bytes, [0x52, 0x49, 0x46, 0x46]) && startsWith(bytes, [0x57, 0x45, 0x42, 0x50], 8)\n ? undefined\n : 'the data is not a WebP';\n return undefined;\n}\n\n/** Keeps valid images and swaps an undecodable one for a text note, since one bad image fails the whole turn and every later one. */\nexport function dropInvalidImages(content: readonly PoHeadlessContent[]): PoHeadlessContent[] {\n return content.map((part) => {\n if (part.type !== 'image') return part;\n const reason = invalidImageReason(part.data, part.mimeType);\n return reason === undefined ? part : { type: 'text', text: `[image omitted: ${reason}]` };\n });\n}\n\n/**\n * Narrows a Pi tool result to the headless contract. Pi types `structuredContent` as any JSON\n * value, while MCP only accepts an object, so anything else is dropped rather than forwarded.\n */\nexport function toPoHeadlessToolResult(result: {\n readonly content: PoHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly _meta?: CallToolResult['_meta'];\n readonly isError?: boolean;\n}): PoHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n ...(typeof structuredContent === 'object' && structuredContent !== null && !Array.isArray(structuredContent)\n ? { structuredContent: structuredContent as Record<string, unknown> }\n : {}),\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\nexport interface PoHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n purpose?: 'feedback';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n /** Set only by po-approval: a `select` of Approve/Deny the app draws as an approval card. */\n approval?: PoApprovalPrompt;\n}\n\nexport interface PoHeadlessClient {\n /**\n * Operator-facing surface only: the body is flattened to one line and capped at 4096 characters\n * by schemas/notification.ts:73-83, and the model never sees it. Use session.admitPrompt to\n * reach the model.\n */\n notify(request: PoNotificationRequest): void | Promise<void>;\n request(request: PoHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n /** Only the currently visible feedback question, never an approval or queued request. */\n pendingFeedback?():\n | {\n id: string;\n kind: 'select' | 'input';\n title: string;\n message?: string;\n labels?: string[];\n }\n | undefined;\n /** Returns false for stale ids, queued requests and approvals. */\n answerFeedback?(id: string, value: string): boolean;\n /** Only the visible approval at the head of the dialog queue. */\n pendingApproval?(): PoApprovalPrompt | undefined;\n /** Refuses stale, queued, expired and duplicate answers. Voice cannot answer a human approval. */\n answerApproval?(id: string, decision: 'approved' | 'denied', channel: 'voice' | 'app'): boolean;\n /** Ignored once the session has closed, so a package can clear its status while it unwinds. */\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface PoHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface PoHeadlessSession {\n /** Live host close intent, set synchronously before interruption. Absent for a person's stop or remove. */\n readonly closeReason?: 'released' | 'host_shutdown';\n readModelSettings?(): Promise<PoHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<PoHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n /** Stream matching history newest first. Stop iteration to stop storage reads. */\n entriesNewestFirst(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): AsyncIterable<Record<string, unknown>>;\n appendCustomEntry(type: string, data: unknown): Promise<void>;\n /** Append a displayable informational message to history and model context, without admitting input or starting a turn. */\n appendMessage?(message: { type: string; text: string; display?: boolean; details?: unknown }): Promise<string | void>;\n /**\n * Admit one custom message without awaiting its turn, using environmental input policy.\n * Defaults to followUp. Reusing requestId deduplicates normal Durable admission retries;\n * locked-agent appends and deferred operator admission do not provide that guarantee.\n * The receipt's settled resolves when the run that consumed the message ends; a locked agent\n * resolves it at once. Hosts without tracking return nothing.\n */\n admitMessage?(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n delivery?: 'steer' | 'followUp',\n requestId?: string,\n ): Promise<{ requestId: string; settled: Promise<void> } | void>;\n /**\n * Register a checkpoint flush before the next tool-turn request. Idle writes return undefined instead of queueing when busy.\n * `resetContext` starts native context at the message, which stands for itself followed by `retainedMessages`.\n */\n registerCheckpointBoundary?(\n callback: (boundary: {\n signal?: AbortSignal;\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n }) => Promise<void>,\n ): {\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n dispose(): void;\n };\n /** Detached canonical model context before package transformations, with context edits applied and no system message. */\n contextMessages?(): Promise<readonly Record<string, unknown>[]>;\n /** The latest measured assistant usage and the selected model's context window. */\n contextUsage?(): Promise<{ tokens: number | null; contextWindow: number } | undefined>;\n /** Label a durable entry without admitting input or starting a turn. */\n setLabel?(entryId: string, label: string | undefined): Promise<void>;\n /**\n * Delivers operator input through prompt preflight and awaits its turn.\n * Environmental input uses admitPrompt with origin omitted instead.\n * An idle agent is woken; busy delivery uses Durable steering or follow-up.\n */\n prompt(text: string, delivery?: 'prompt' | 'steer' | 'followUp'): Promise<void>;\n /**\n * Admits input without awaiting its turn. Environmental input omits origin and never\n * changes the operator queue. Operator origin uses prompt preflight, including voice\n * capture; 'interrupt' cancels the active run and admits operator input while preserving\n * retained queued work. Environmental callers may reuse requestId when retrying the same input.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n requestId?: string,\n ): Promise<void>;\n /** Stops the current run. With expectedOperationId, a different or finished operation is left alone. */\n abort(expectedOperationId?: string): Promise<void>;\n compact(instructions?: string): Promise<void>;\n /** operationId names the current run, absent while idle or settling. */\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean; operationId?: string }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** The current branch's newest entry, for a child that starts from this session's history. */\n forkSource?(): Promise<{\n kind: 'fork';\n entryId?: string;\n }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface PoMcpSkillAccess {\n list(): Promise<readonly { name: string; description: string }[]>;\n read(name: string): Promise<string>;\n}\n\n/** A stateless auxiliary request. These tools are private to this request, never registered on the agent. */\nexport interface PoHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary token usage in this session, including rejected results. */\n recordUsage?: boolean;\n tools: readonly Pick<PoHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface PoHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\n/** Credential-free catalog metadata. Packages cannot obtain auth, headers, or a mutable registry. */\nexport interface PoHeadlessModelMetadata {\n readonly provider: string;\n readonly id: string;\n readonly api?: string;\n readonly baseUrl?: string;\n readonly name?: string;\n readonly compat?: Readonly<Record<string, boolean | string>>;\n}\n\n/** Host policy retained by a supervised tool sequence after its original call returns. */\nexport interface PoHeadlessToolContinuation {\n admit(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n signal?: AbortSignal;\n }): Promise<Record<string, unknown>>;\n finalize(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n result: PoHeadlessToolResult;\n signal?: AbortSignal;\n }): Promise<PoHeadlessToolResult>;\n}\n\nexport interface PoHeadlessExecutionContext {\n /** Present only on an admitted tool invocation. Retained callbacks recheck current host policy. */\n readonly toolContinuation?: PoHeadlessToolContinuation;\n readonly cwd: string;\n /** The checkout the session runs in, distinct from the tool execution directory. */\n readonly repoRoot: string;\n readonly sessionId: string;\n /** Who invoked the tool: the session's own agent, or a subagent borrowing it. Absent when the host cannot tell. */\n readonly caller?: 'main' | 'child';\n /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: PoSessionContext;\n /** Host-owned presence, also supplied when the session has no workspace context. */\n readonly interaction?: 'interactive' | 'unattended';\n /** Immutable session configuration. Packages must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: PoHeadlessClient;\n readonly session: PoHeadlessSession;\n readonly model?: PoHeadlessModelMetadata;\n /** Lookup in this session's catalog, including physical models named by finalized messages. */\n readonly getModel?: (provider: string, id: string) => PoHeadlessModelMetadata | undefined;\n /** Detached credential-free authenticated chat catalog, read after refreshing provider availability. */\n readonly getAvailableModels?: () => Promise<\n readonly {\n readonly provider: string;\n readonly id: string;\n }[]\n >;\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\n /** Tool-less conversation summary through the host's guarded session provider. */\n summarize?(\n reference: string,\n request: {\n messages: readonly Record<string, unknown>[];\n instructions: string;\n previousSummary?: string;\n thinkingLevel?: ThinkingLevel;\n signal?: AbortSignal;\n },\n ): Promise<string>;\n complete(\n reference: string,\n request: {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary usage and reject truncated text rather than returning partial output. */\n recordUsage?: boolean;\n },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: PoHeadlessToolCompletionRequest): Promise<PoHeadlessToolCompletionResult>;\n };\n /** Guarded image operation. Credentials and transport configuration remain host-owned. */\n readonly imageGeneration?: {\n available(): boolean;\n generate(request: {\n prompt: string;\n transparentBackground?: boolean;\n images?: readonly { data: string; mimeType: string }[];\n correlationId: string;\n signal?: AbortSignal;\n }): Promise<{ data: string; mimeType: 'image/png'; requestId?: string; generationId?: string }>;\n };\n /**\n * Guarded web search. Credentials, endpoint, model choice, session identity and transport remain host-owned.\n * `commands` follows a schema owned by the calling package; the host only bounds it.\n */\n readonly webSearch?: {\n available(): boolean;\n search(request: {\n commands: Readonly<Record<string, unknown>>;\n /** Optional plain-text excerpt, oldest first. Omit to send no conversation content. */\n conversation?: readonly { role: 'user' | 'assistant'; text: string }[];\n access: 'cached' | 'indexed' | 'live';\n signal?: AbortSignal;\n }): Promise<{ output: string; results?: readonly Record<string, unknown>[] }>;\n };\n readonly selection: PoHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: PoMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface PoHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain' | 'shared'; mode: string; label?: string };\n domain?: string;\n /** Any selected domain must match. Absent is unrestricted; empty never matches. */\n domains?: readonly string[];\n}\n\nexport interface PoHeadlessToolRestriction {\n when?: PoHeadlessCondition;\n /** Optional capability ceiling. An empty list disables every tool. */\n allowedTools?: readonly string[];\n /**\n * Narrow exclusions without disabling unrelated tools. Exclude a tool your package owns, or a\n * specific foreign tool the mode exists to withdraw. Never enumerate an allowlist here.\n */\n excludedTools?: readonly string[];\n}\n\nexport interface PoHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: PoHeadlessCondition;\n name: string;\n label?: string;\n description: string;\n parameters: TParameters;\n annotations?: Tool['annotations'];\n outputSchema?: Tool['outputSchema'];\n /** Remote presentation only. Component tool access must be explicitly opted into. */\n _meta?: Tool['_meta'] & {\n ui?: { resourceUri?: string; visibility?: ('model' | 'app')[] };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n /**\n * Keeps the tool from subagents, which otherwise borrow the parent's tools. Set it when the tool needs\n * the person to answer, since nobody can answer a subagent, or when it acts for the main agent itself.\n */\n mainAgentOnly?: boolean;\n /** Asks the person before each call; see PoApprovalPolicy for who can answer. */\n approval?: PoApprovalPolicy;\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ): Promise<PoHeadlessToolResult>;\n}\n\n/**\n * One package contribution to the session's resource surface.\n *\n * `kind` decides what the model is billed for, and the difference is large:\n * - `context` is EAGER. `read()` runs on every prompt build and the text is pasted\n * into the system prompt verbatim. Reserve it for small live session state that\n * exists nowhere on disk. Never use it for a file the package ships: a README\n * registered this way costs its full length on every single turn.\n * - `skill` is LAZY. Only `name`, `description` and `path` reach the prompt; the\n * agent reads the file itself when the description matches the task.\n * - `prompt` is inert until the user invokes it by name.\n *\n * The rule in one line: if it is a file the package ships, it is a `skill`.\n */\nexport interface PoHeadlessResource {\n when?: PoHeadlessCondition;\n name: string;\n /** Model-visible selection signal. A `skill` without one tells the agent nothing. */\n description?: string;\n /** Absolute path of the file `read()` returns, so an advertised skill is one the agent can open. */\n path?: string;\n /**\n * A `skill` listed in the system prompt itself, kept out of the `load_skill` catalog and\n * `search_skills`. For a few always-relevant guides (the code-mode how-tos) that search would miss.\n */\n pinned?: boolean;\n kind: 'prompt' | 'skill' | 'context';\n read(context: PoHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface PoHeadlessCommand {\n when?: PoHeadlessCondition;\n name: string;\n description: string;\n /** Selection-only control allowed after a coherent selection fails admission. */\n selectionRecovery?: boolean;\n execute(args: string, context: PoHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type PoHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\n | 'agent_end'\n | 'agent_settled'\n | 'turn_start'\n | 'turn_end'\n | 'context'\n | 'before_provider_request'\n | 'message_start'\n | 'message_update'\n | 'message_end'\n | 'tool_call'\n | 'tool_execution_start'\n | 'tool_execution_update'\n | 'tool_execution_end'\n | 'tool_result'\n | 'model_select'\n | 'session_before_compact'\n | 'session_compact';\n\nexport type PoHeadlessHookEvent<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? {\n lane: string;\n runId: string;\n model: { provider: string; id: string; api?: string };\n payload: unknown;\n }\n : E extends 'session_before_compact'\n ? {\n reason: string;\n preparation: unknown;\n instructions?: string;\n customInstructions?: string;\n }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface PoHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type PoHeadlessHookResult<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? {\n cancel?: boolean;\n decline?: boolean;\n compaction?: PoHeadlessCompactionResult;\n } | void\n : E extends 'context'\n ? { messages?: unknown[]; systemPrompt?: string } | void\n : E extends 'before_agent_start'\n ? { systemPrompt?: string } | void\n : E extends 'tool_call'\n ? {\n args?: Record<string, unknown>;\n block?: { reason: string; terminate?: boolean };\n } | void\n : E extends 'tool_result'\n ? {\n content?: PoHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type PoHeadlessHook<E extends PoHeadlessEventName = PoHeadlessEventName> = E extends PoHeadlessEventName\n ? {\n when?: PoHeadlessCondition;\n event: E;\n handle(\n event: Readonly<PoHeadlessHookEvent<E>>,\n context: PoHeadlessExecutionContext,\n ): PoHeadlessHookResult<E> | Promise<PoHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained package can register activity without starting disabled watchers or services. */\nexport interface PoHeadlessActivity {\n when?: PoHeadlessCondition;\n name: string;\n start(context: PoHeadlessExecutionContext): (() => void | Promise<void>) | Promise<() => void | Promise<void>>;\n}\n\n/** Read-only metadata for the currently applied session, never executable declarations or resource bodies. */\nexport interface PoHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: PoHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\n/** Visibility controls model discovery only, never admission for external execution. */\nexport function isPoHeadlessToolModelVisible(tool: Pick<PoHeadlessTool, '_meta'>): boolean {\n const visibility = tool._meta?.ui?.visibility;\n return visibility === undefined || visibility.includes('model');\n}\n\nexport interface PoHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly PoHeadlessCapability[];\n}\n\n/** Session skill discovery tools, adapted to the size of the active catalog. */\nexport const PO_LOAD_SKILL_TOOL = 'load_skill';\nexport const PO_SEARCH_SKILLS_TOOL = 'search_skills';\nexport interface PoHeadlessHostService {\n readonly context: PoHeadlessExecutionContext;\n /** Admitted external execution, sharing native hooks, restrictions and session lifetime. */\n readonly toolSurface?: Pick<SessionToolSurface, 'readSurface' | 'invokeTool'>;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n /** Names and descriptions of searchable applied skills, excluding pinned guides and instruction bodies. */\n listSkills(): readonly { readonly name: string; readonly description: string }[];\n /** atToolBoundary defers the change to the next tool boundary, as slash commands do; idle sessions apply at once. */\n changeSelection(change: PoHeadlessSelectionChange, options?: { atToolBoundary?: boolean }): Promise<void>;\n assertActive(source?: string): void;\n /** Whether a package owns contributions in the currently applied selection. */\n isSourceActive(source: string): boolean;\n /** Normalize selection before the first successful application only. Disposed with the registering context. */\n registerInitialSelectionResolver(resolve: (selection: PoHeadlessSelection) => PoHeadlessSelection): () => void;\n subscribeSelection(\n listener: (selection: PoHeadlessSelection, applied: PoHeadlessSelectionApplied) => void | Promise<void>,\n ): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): PoHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: PoHeadlessToolRestriction): PoHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: PoHeadlessTool<TParameters>): PoHeadlessRegistration;\n registerResource(resource: PoHeadlessResource): PoHeadlessRegistration;\n registerCommand(command: PoHeadlessCommand): PoHeadlessRegistration;\n registerHook(hook: PoHeadlessHook): PoHeadlessRegistration;\n registerActivity(activity: PoHeadlessActivity): PoHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/headless-host': PoHeadlessHostService;\n }\n}\n\nexport function readPoHeadlessHost(context: Context): PoHeadlessHostService | undefined {\n return context.get(PO_HEADLESS_HOST_SERVICE) as PoHeadlessHostService | undefined;\n}\n\nexport function requirePoHeadlessHost(context: Context): PoHeadlessHostService {\n const host = readPoHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Po headless session host.');\n return host;\n}\n"],"mappings":"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"}
@@ -592,6 +592,8 @@ export interface PoHeadlessHostService {
592
592
  assertActive(source?: string): void;
593
593
  /** Whether a package owns contributions in the currently applied selection. */
594
594
  isSourceActive(source: string): boolean;
595
+ /** Normalize selection before the first successful application only. Disposed with the registering context. */
596
+ registerInitialSelectionResolver(resolve: (selection: PoHeadlessSelection) => PoHeadlessSelection): () => void;
595
597
  subscribeSelection(listener: (selection: PoHeadlessSelection, applied: PoHeadlessSelectionApplied) => void | Promise<void>): () => void;
596
598
  /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */
597
599
  inspectCapabilities(): PoHeadlessCapabilitySnapshot;
@@ -1 +1 @@
1
- {"version":3,"file":"headless.d.mts","names":[],"sources":["../../../src/schemas/headless.ts"],"mappings":"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"}
1
+ {"version":3,"file":"headless.d.mts","names":[],"sources":["../../../src/schemas/headless.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"headless.mjs","names":[],"sources":["../../../src/schemas/headless.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { CallToolResult, Tool } from '@modelcontextprotocol/server';\nimport type { Static, TSchema } from 'typebox';\n\nimport type { SessionToolSurface } from '../types/server/sessionToolSurface';\nimport type { PoApprovalPolicy, PoApprovalPrompt } from './approval';\nimport type { PoSessionContext } from './hubChannel';\nimport type { PoNotificationRequest } from './notification';\nimport type { PoServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const PO_HEADLESS_HOST_SERVICE = 'po/headless-host';\nexport const PO_HEADLESS_OWNER = Symbol.for('po/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'PoHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory package-hook failure. */\nexport class PoHeadlessPromptAdmissionError extends Error {\n constructor(cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n this.name = PROMPT_ADMISSION_ERROR;\n }\n}\n\nconst SESSION_SETUP_ERROR = 'PoSessionSetupError';\n\n/**\n * A session cannot start until the user fixes their setup, such as configuring a model.\n *\n * Its message is written for the user and says what to do, so a server returns it as is\n * rather than hiding it behind a generic internal error.\n */\nexport class PoSessionSetupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = SESSION_SETUP_ERROR;\n }\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoSessionSetupError(error: unknown): error is Error {\n return error instanceof Error && error.name === SESSION_SETUP_ERROR;\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nconst TOOL_BUSY_ERROR = 'PoHeadlessToolBusyError';\n\n/** The tool and its hooks have not started. */\nexport class PoHeadlessToolBusyError extends Error {\n constructor() {\n super('An operation is already running');\n this.name = TOOL_BUSY_ERROR;\n }\n}\n\nexport function isPoHeadlessToolBusyError(error: unknown): boolean {\n return error instanceof Error && error.name === TOOL_BUSY_ERROR;\n}\n\nexport interface PoHeadlessSelection {\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n readonly domains: readonly string[];\n readonly profile?: string;\n /** Feature-owned activation sets, keyed by the contributing capability. */\n readonly state?: Readonly<Record<string, readonly string[]>>;\n}\n\n/** One package-owned selection transition. Server packages change exactly one axis per operation. */\nexport type PoHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | {\n readonly axis: 'state';\n readonly key: string;\n readonly values: readonly string[];\n };\n\n/** A selection axis a listener re-applies from its config even when its value did not change. */\nexport type PoHeadlessRefreshAxis = 'majorMode' | 'domains' | 'profile';\n\n/** How a selection was applied. `refresh` names axes whose config changed on disk. */\nexport interface PoHeadlessSelectionApplied {\n readonly refresh?: readonly PoHeadlessRefreshAxis[];\n}\n\nexport function readPoHeadlessOwner(context: Context): PoServerBundleEntry | undefined {\n return (context as Context & { [PO_HEADLESS_OWNER]?: PoServerBundleEntry })[PO_HEADLESS_OWNER];\n}\n\nexport interface PoHeadlessRegistration {\n dispose(): void;\n}\n\nexport type PoHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface PoHeadlessToolResult {\n content: PoHeadlessContent[];\n /** Public MCP result data. Internal renderer details are not a remote result contract. */\n structuredContent?: Record<string, unknown>;\n /** Component-only MCP metadata, never inferred from internal renderer details. */\n _meta?: CallToolResult['_meta'];\n details?: unknown;\n isError?: boolean;\n}\n\nlet crcTable: Uint32Array | undefined;\n\nfunction crc32(bytes: Uint8Array, start: number, end: number): number {\n if (crcTable === undefined) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (let i = start; i < end; i++) crc = crcTable[(crc ^ bytes[i]!) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nfunction startsWith(bytes: Uint8Array, prefix: readonly number[], offset = 0): boolean {\n return prefix.every((byte, index) => bytes[offset + index] === byte);\n}\n\n/** Why the model API would reject this image, or undefined when it looks decodable. Only png, jpeg, gif and webp are checked. */\nexport function invalidImageReason(data: string, mimeType: string): string | undefined {\n let bytes: Uint8Array;\n try {\n bytes = Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n } catch {\n return 'the data is not valid base64';\n }\n if (mimeType === 'image/png') {\n if (!startsWith(bytes, PNG_SIGNATURE)) return 'the data is not a PNG';\n const view = new DataView(bytes.buffer);\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = view.getUint32(offset);\n const end = offset + 8 + length;\n if (end + 4 > bytes.length) break;\n if (crc32(bytes, offset + 4, end) !== view.getUint32(end)) return 'a PNG chunk failed its checksum';\n if (startsWith(bytes, [0x49, 0x45, 0x4e, 0x44], offset + 4)) return undefined;\n offset = end + 4;\n }\n return 'the PNG is truncated';\n }\n if (mimeType === 'image/jpeg') return startsWith(bytes, [0xff, 0xd8]) ? undefined : 'the data is not a JPEG';\n if (mimeType === 'image/gif')\n return startsWith(bytes, [0x47, 0x49, 0x46, 0x38]) ? undefined : 'the data is not a GIF';\n if (mimeType === 'image/webp')\n return startsWith(bytes, [0x52, 0x49, 0x46, 0x46]) && startsWith(bytes, [0x57, 0x45, 0x42, 0x50], 8)\n ? undefined\n : 'the data is not a WebP';\n return undefined;\n}\n\n/** Keeps valid images and swaps an undecodable one for a text note, since one bad image fails the whole turn and every later one. */\nexport function dropInvalidImages(content: readonly PoHeadlessContent[]): PoHeadlessContent[] {\n return content.map((part) => {\n if (part.type !== 'image') return part;\n const reason = invalidImageReason(part.data, part.mimeType);\n return reason === undefined ? part : { type: 'text', text: `[image omitted: ${reason}]` };\n });\n}\n\n/**\n * Narrows a Pi tool result to the headless contract. Pi types `structuredContent` as any JSON\n * value, while MCP only accepts an object, so anything else is dropped rather than forwarded.\n */\nexport function toPoHeadlessToolResult(result: {\n readonly content: PoHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly _meta?: CallToolResult['_meta'];\n readonly isError?: boolean;\n}): PoHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n ...(typeof structuredContent === 'object' && structuredContent !== null && !Array.isArray(structuredContent)\n ? { structuredContent: structuredContent as Record<string, unknown> }\n : {}),\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\nexport interface PoHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n purpose?: 'feedback';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n /** Set only by po-approval: a `select` of Approve/Deny the app draws as an approval card. */\n approval?: PoApprovalPrompt;\n}\n\nexport interface PoHeadlessClient {\n /**\n * Operator-facing surface only: the body is flattened to one line and capped at 4096 characters\n * by schemas/notification.ts:73-83, and the model never sees it. Use session.admitPrompt to\n * reach the model.\n */\n notify(request: PoNotificationRequest): void | Promise<void>;\n request(request: PoHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n /** Only the currently visible feedback question, never an approval or queued request. */\n pendingFeedback?():\n | {\n id: string;\n kind: 'select' | 'input';\n title: string;\n message?: string;\n labels?: string[];\n }\n | undefined;\n /** Returns false for stale ids, queued requests and approvals. */\n answerFeedback?(id: string, value: string): boolean;\n /** Only the visible approval at the head of the dialog queue. */\n pendingApproval?(): PoApprovalPrompt | undefined;\n /** Refuses stale, queued, expired and duplicate answers. Voice cannot answer a human approval. */\n answerApproval?(id: string, decision: 'approved' | 'denied', channel: 'voice' | 'app'): boolean;\n /** Ignored once the session has closed, so a package can clear its status while it unwinds. */\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface PoHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface PoHeadlessSession {\n /** Live host close intent, set synchronously before interruption. Absent for a person's stop or remove. */\n readonly closeReason?: 'released' | 'host_shutdown';\n readModelSettings?(): Promise<PoHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<PoHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n /** Stream matching history newest first. Stop iteration to stop storage reads. */\n entriesNewestFirst(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): AsyncIterable<Record<string, unknown>>;\n appendCustomEntry(type: string, data: unknown): Promise<void>;\n /** Append a displayable informational message to history and model context, without admitting input or starting a turn. */\n appendMessage?(message: { type: string; text: string; display?: boolean; details?: unknown }): Promise<string | void>;\n /**\n * Admit one custom message without awaiting its turn, using environmental input policy.\n * Defaults to followUp. Reusing requestId deduplicates normal Durable admission retries;\n * locked-agent appends and deferred operator admission do not provide that guarantee.\n * The receipt's settled resolves when the run that consumed the message ends; a locked agent\n * resolves it at once. Hosts without tracking return nothing.\n */\n admitMessage?(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n delivery?: 'steer' | 'followUp',\n requestId?: string,\n ): Promise<{ requestId: string; settled: Promise<void> } | void>;\n /**\n * Register a checkpoint flush before the next tool-turn request. Idle writes return undefined instead of queueing when busy.\n * `resetContext` starts native context at the message, which stands for itself followed by `retainedMessages`.\n */\n registerCheckpointBoundary?(\n callback: (boundary: {\n signal?: AbortSignal;\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n }) => Promise<void>,\n ): {\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n dispose(): void;\n };\n /** Detached canonical model context before package transformations, with context edits applied and no system message. */\n contextMessages?(): Promise<readonly Record<string, unknown>[]>;\n /** The latest measured assistant usage and the selected model's context window. */\n contextUsage?(): Promise<{ tokens: number | null; contextWindow: number } | undefined>;\n /** Label a durable entry without admitting input or starting a turn. */\n setLabel?(entryId: string, label: string | undefined): Promise<void>;\n /**\n * Delivers operator input through prompt preflight and awaits its turn.\n * Environmental input uses admitPrompt with origin omitted instead.\n * An idle agent is woken; busy delivery uses Durable steering or follow-up.\n */\n prompt(text: string, delivery?: 'prompt' | 'steer' | 'followUp'): Promise<void>;\n /**\n * Admits input without awaiting its turn. Environmental input omits origin and never\n * changes the operator queue. Operator origin uses prompt preflight, including voice\n * capture; 'interrupt' cancels the active run and admits operator input while preserving\n * retained queued work. Environmental callers may reuse requestId when retrying the same input.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n requestId?: string,\n ): Promise<void>;\n /** Stops the current run. With expectedOperationId, a different or finished operation is left alone. */\n abort(expectedOperationId?: string): Promise<void>;\n compact(instructions?: string): Promise<void>;\n /** operationId names the current run, absent while idle or settling. */\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean; operationId?: string }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** The current branch's newest entry, for a child that starts from this session's history. */\n forkSource?(): Promise<{\n kind: 'fork';\n entryId?: string;\n }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface PoMcpSkillAccess {\n list(): Promise<readonly { name: string; description: string }[]>;\n read(name: string): Promise<string>;\n}\n\n/** A stateless auxiliary request. These tools are private to this request, never registered on the agent. */\nexport interface PoHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary token usage in this session, including rejected results. */\n recordUsage?: boolean;\n tools: readonly Pick<PoHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface PoHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\n/** Credential-free catalog metadata. Packages cannot obtain auth, headers, or a mutable registry. */\nexport interface PoHeadlessModelMetadata {\n readonly provider: string;\n readonly id: string;\n readonly api?: string;\n readonly baseUrl?: string;\n readonly name?: string;\n readonly compat?: Readonly<Record<string, boolean | string>>;\n}\n\n/** Host policy retained by a supervised tool sequence after its original call returns. */\nexport interface PoHeadlessToolContinuation {\n admit(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n signal?: AbortSignal;\n }): Promise<Record<string, unknown>>;\n finalize(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n result: PoHeadlessToolResult;\n signal?: AbortSignal;\n }): Promise<PoHeadlessToolResult>;\n}\n\nexport interface PoHeadlessExecutionContext {\n /** Present only on an admitted tool invocation. Retained callbacks recheck current host policy. */\n readonly toolContinuation?: PoHeadlessToolContinuation;\n readonly cwd: string;\n /** The checkout the session runs in, distinct from the tool execution directory. */\n readonly repoRoot: string;\n readonly sessionId: string;\n /** Who invoked the tool: the session's own agent, or a subagent borrowing it. Absent when the host cannot tell. */\n readonly caller?: 'main' | 'child';\n /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: PoSessionContext;\n /** Host-owned presence, also supplied when the session has no workspace context. */\n readonly interaction?: 'interactive' | 'unattended';\n /** Immutable session configuration. Packages must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: PoHeadlessClient;\n readonly session: PoHeadlessSession;\n readonly model?: PoHeadlessModelMetadata;\n /** Lookup in this session's catalog, including physical models named by finalized messages. */\n readonly getModel?: (provider: string, id: string) => PoHeadlessModelMetadata | undefined;\n /** Detached credential-free authenticated chat catalog, read after refreshing provider availability. */\n readonly getAvailableModels?: () => Promise<\n readonly {\n readonly provider: string;\n readonly id: string;\n }[]\n >;\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\n /** Tool-less conversation summary through the host's guarded session provider. */\n summarize?(\n reference: string,\n request: {\n messages: readonly Record<string, unknown>[];\n instructions: string;\n previousSummary?: string;\n thinkingLevel?: ThinkingLevel;\n signal?: AbortSignal;\n },\n ): Promise<string>;\n complete(\n reference: string,\n request: {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary usage and reject truncated text rather than returning partial output. */\n recordUsage?: boolean;\n },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: PoHeadlessToolCompletionRequest): Promise<PoHeadlessToolCompletionResult>;\n };\n /** Guarded image operation. Credentials and transport configuration remain host-owned. */\n readonly imageGeneration?: {\n available(): boolean;\n generate(request: {\n prompt: string;\n transparentBackground?: boolean;\n images?: readonly { data: string; mimeType: string }[];\n correlationId: string;\n signal?: AbortSignal;\n }): Promise<{ data: string; mimeType: 'image/png'; requestId?: string; generationId?: string }>;\n };\n /**\n * Guarded web search. Credentials, endpoint, model choice, session identity and transport remain host-owned.\n * `commands` follows a schema owned by the calling package; the host only bounds it.\n */\n readonly webSearch?: {\n available(): boolean;\n search(request: {\n commands: Readonly<Record<string, unknown>>;\n /** Optional plain-text excerpt, oldest first. Omit to send no conversation content. */\n conversation?: readonly { role: 'user' | 'assistant'; text: string }[];\n access: 'cached' | 'indexed' | 'live';\n signal?: AbortSignal;\n }): Promise<{ output: string; results?: readonly Record<string, unknown>[] }>;\n };\n readonly selection: PoHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: PoMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface PoHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain' | 'shared'; mode: string; label?: string };\n domain?: string;\n /** Any selected domain must match. Absent is unrestricted; empty never matches. */\n domains?: readonly string[];\n}\n\nexport interface PoHeadlessToolRestriction {\n when?: PoHeadlessCondition;\n /** Optional capability ceiling. An empty list disables every tool. */\n allowedTools?: readonly string[];\n /**\n * Narrow exclusions without disabling unrelated tools. Exclude a tool your package owns, or a\n * specific foreign tool the mode exists to withdraw. Never enumerate an allowlist here.\n */\n excludedTools?: readonly string[];\n}\n\nexport interface PoHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: PoHeadlessCondition;\n name: string;\n label?: string;\n description: string;\n parameters: TParameters;\n annotations?: Tool['annotations'];\n outputSchema?: Tool['outputSchema'];\n /** Remote presentation only. Component tool access must be explicitly opted into. */\n _meta?: Tool['_meta'] & {\n ui?: { resourceUri?: string; visibility?: ('model' | 'app')[] };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n /**\n * Keeps the tool from subagents, which otherwise borrow the parent's tools. Set it when the tool needs\n * the person to answer, since nobody can answer a subagent, or when it acts for the main agent itself.\n */\n mainAgentOnly?: boolean;\n /** Asks the person before each call; see PoApprovalPolicy for who can answer. */\n approval?: PoApprovalPolicy;\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ): Promise<PoHeadlessToolResult>;\n}\n\n/**\n * One package contribution to the session's resource surface.\n *\n * `kind` decides what the model is billed for, and the difference is large:\n * - `context` is EAGER. `read()` runs on every prompt build and the text is pasted\n * into the system prompt verbatim. Reserve it for small live session state that\n * exists nowhere on disk. Never use it for a file the package ships: a README\n * registered this way costs its full length on every single turn.\n * - `skill` is LAZY. Only `name`, `description` and `path` reach the prompt; the\n * agent reads the file itself when the description matches the task.\n * - `prompt` is inert until the user invokes it by name.\n *\n * The rule in one line: if it is a file the package ships, it is a `skill`.\n */\nexport interface PoHeadlessResource {\n when?: PoHeadlessCondition;\n name: string;\n /** Model-visible selection signal. A `skill` without one tells the agent nothing. */\n description?: string;\n /** Absolute path of the file `read()` returns, so an advertised skill is one the agent can open. */\n path?: string;\n /**\n * A `skill` listed in the system prompt itself, kept out of the `load_skill` catalog and\n * `search_skills`. For a few always-relevant guides (the code-mode how-tos) that search would miss.\n */\n pinned?: boolean;\n kind: 'prompt' | 'skill' | 'context';\n read(context: PoHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface PoHeadlessCommand {\n when?: PoHeadlessCondition;\n name: string;\n description: string;\n /** Selection-only control allowed after a coherent selection fails admission. */\n selectionRecovery?: boolean;\n execute(args: string, context: PoHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type PoHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\n | 'agent_end'\n | 'agent_settled'\n | 'turn_start'\n | 'turn_end'\n | 'context'\n | 'before_provider_request'\n | 'message_start'\n | 'message_update'\n | 'message_end'\n | 'tool_call'\n | 'tool_execution_start'\n | 'tool_execution_update'\n | 'tool_execution_end'\n | 'tool_result'\n | 'model_select'\n | 'session_before_compact'\n | 'session_compact';\n\nexport type PoHeadlessHookEvent<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? {\n lane: string;\n runId: string;\n model: { provider: string; id: string; api?: string };\n payload: unknown;\n }\n : E extends 'session_before_compact'\n ? {\n reason: string;\n preparation: unknown;\n instructions?: string;\n customInstructions?: string;\n }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface PoHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type PoHeadlessHookResult<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? {\n cancel?: boolean;\n decline?: boolean;\n compaction?: PoHeadlessCompactionResult;\n } | void\n : E extends 'context'\n ? { messages?: unknown[]; systemPrompt?: string } | void\n : E extends 'before_agent_start'\n ? { systemPrompt?: string } | void\n : E extends 'tool_call'\n ? {\n args?: Record<string, unknown>;\n block?: { reason: string; terminate?: boolean };\n } | void\n : E extends 'tool_result'\n ? {\n content?: PoHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type PoHeadlessHook<E extends PoHeadlessEventName = PoHeadlessEventName> = E extends PoHeadlessEventName\n ? {\n when?: PoHeadlessCondition;\n event: E;\n handle(\n event: Readonly<PoHeadlessHookEvent<E>>,\n context: PoHeadlessExecutionContext,\n ): PoHeadlessHookResult<E> | Promise<PoHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained package can register activity without starting disabled watchers or services. */\nexport interface PoHeadlessActivity {\n when?: PoHeadlessCondition;\n name: string;\n start(context: PoHeadlessExecutionContext): (() => void | Promise<void>) | Promise<() => void | Promise<void>>;\n}\n\n/** Read-only metadata for the currently applied session, never executable declarations or resource bodies. */\nexport interface PoHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: PoHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\n/** Visibility controls model discovery only, never admission for external execution. */\nexport function isPoHeadlessToolModelVisible(tool: Pick<PoHeadlessTool, '_meta'>): boolean {\n const visibility = tool._meta?.ui?.visibility;\n return visibility === undefined || visibility.includes('model');\n}\n\nexport interface PoHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly PoHeadlessCapability[];\n}\n\n/** Session skill discovery tools, adapted to the size of the active catalog. */\nexport const PO_LOAD_SKILL_TOOL = 'load_skill';\nexport const PO_SEARCH_SKILLS_TOOL = 'search_skills';\nexport interface PoHeadlessHostService {\n readonly context: PoHeadlessExecutionContext;\n /** Admitted external execution, sharing native hooks, restrictions and session lifetime. */\n readonly toolSurface?: Pick<SessionToolSurface, 'readSurface' | 'invokeTool'>;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n /** Names and descriptions of searchable applied skills, excluding pinned guides and instruction bodies. */\n listSkills(): readonly { readonly name: string; readonly description: string }[];\n /** atToolBoundary defers the change to the next tool boundary, as slash commands do; idle sessions apply at once. */\n changeSelection(change: PoHeadlessSelectionChange, options?: { atToolBoundary?: boolean }): Promise<void>;\n assertActive(source?: string): void;\n /** Whether a package owns contributions in the currently applied selection. */\n isSourceActive(source: string): boolean;\n subscribeSelection(\n listener: (selection: PoHeadlessSelection, applied: PoHeadlessSelectionApplied) => void | Promise<void>,\n ): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): PoHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: PoHeadlessToolRestriction): PoHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: PoHeadlessTool<TParameters>): PoHeadlessRegistration;\n registerResource(resource: PoHeadlessResource): PoHeadlessRegistration;\n registerCommand(command: PoHeadlessCommand): PoHeadlessRegistration;\n registerHook(hook: PoHeadlessHook): PoHeadlessRegistration;\n registerActivity(activity: PoHeadlessActivity): PoHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/headless-host': PoHeadlessHostService;\n }\n}\n\nexport function readPoHeadlessHost(context: Context): PoHeadlessHostService | undefined {\n return context.get(PO_HEADLESS_HOST_SERVICE) as PoHeadlessHostService | undefined;\n}\n\nexport function requirePoHeadlessHost(context: Context): PoHeadlessHostService {\n const host = readPoHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Po headless session host.');\n return host;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"headless.mjs","names":[],"sources":["../../../src/schemas/headless.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { CallToolResult, Tool } from '@modelcontextprotocol/server';\nimport type { Static, TSchema } from 'typebox';\n\nimport type { SessionToolSurface } from '../types/server/sessionToolSurface';\nimport type { PoApprovalPolicy, PoApprovalPrompt } from './approval';\nimport type { PoSessionContext } from './hubChannel';\nimport type { PoNotificationRequest } from './notification';\nimport type { PoServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const PO_HEADLESS_HOST_SERVICE = 'po/headless-host';\nexport const PO_HEADLESS_OWNER = Symbol.for('po/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'PoHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory package-hook failure. */\nexport class PoHeadlessPromptAdmissionError extends Error {\n constructor(cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n this.name = PROMPT_ADMISSION_ERROR;\n }\n}\n\nconst SESSION_SETUP_ERROR = 'PoSessionSetupError';\n\n/**\n * A session cannot start until the user fixes their setup, such as configuring a model.\n *\n * Its message is written for the user and says what to do, so a server returns it as is\n * rather than hiding it behind a generic internal error.\n */\nexport class PoSessionSetupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = SESSION_SETUP_ERROR;\n }\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoSessionSetupError(error: unknown): error is Error {\n return error instanceof Error && error.name === SESSION_SETUP_ERROR;\n}\n\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isPoHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nconst TOOL_BUSY_ERROR = 'PoHeadlessToolBusyError';\n\n/** The tool and its hooks have not started. */\nexport class PoHeadlessToolBusyError extends Error {\n constructor() {\n super('An operation is already running');\n this.name = TOOL_BUSY_ERROR;\n }\n}\n\nexport function isPoHeadlessToolBusyError(error: unknown): boolean {\n return error instanceof Error && error.name === TOOL_BUSY_ERROR;\n}\n\nexport interface PoHeadlessSelection {\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n readonly domains: readonly string[];\n readonly profile?: string;\n /** Feature-owned activation sets, keyed by the contributing capability. */\n readonly state?: Readonly<Record<string, readonly string[]>>;\n}\n\n/** One package-owned selection transition. Server packages change exactly one axis per operation. */\nexport type PoHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | {\n readonly axis: 'state';\n readonly key: string;\n readonly values: readonly string[];\n };\n\n/** A selection axis a listener re-applies from its config even when its value did not change. */\nexport type PoHeadlessRefreshAxis = 'majorMode' | 'domains' | 'profile';\n\n/** How a selection was applied. `refresh` names axes whose config changed on disk. */\nexport interface PoHeadlessSelectionApplied {\n readonly refresh?: readonly PoHeadlessRefreshAxis[];\n}\n\nexport function readPoHeadlessOwner(context: Context): PoServerBundleEntry | undefined {\n return (context as Context & { [PO_HEADLESS_OWNER]?: PoServerBundleEntry })[PO_HEADLESS_OWNER];\n}\n\nexport interface PoHeadlessRegistration {\n dispose(): void;\n}\n\nexport type PoHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface PoHeadlessToolResult {\n content: PoHeadlessContent[];\n /** Public MCP result data. Internal renderer details are not a remote result contract. */\n structuredContent?: Record<string, unknown>;\n /** Component-only MCP metadata, never inferred from internal renderer details. */\n _meta?: CallToolResult['_meta'];\n details?: unknown;\n isError?: boolean;\n}\n\nlet crcTable: Uint32Array | undefined;\n\nfunction crc32(bytes: Uint8Array, start: number, end: number): number {\n if (crcTable === undefined) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (let i = start; i < end; i++) crc = crcTable[(crc ^ bytes[i]!) & 0xff]! ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nconst PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];\n\nfunction startsWith(bytes: Uint8Array, prefix: readonly number[], offset = 0): boolean {\n return prefix.every((byte, index) => bytes[offset + index] === byte);\n}\n\n/** Why the model API would reject this image, or undefined when it looks decodable. Only png, jpeg, gif and webp are checked. */\nexport function invalidImageReason(data: string, mimeType: string): string | undefined {\n let bytes: Uint8Array;\n try {\n bytes = Uint8Array.from(atob(data), (char) => char.charCodeAt(0));\n } catch {\n return 'the data is not valid base64';\n }\n if (mimeType === 'image/png') {\n if (!startsWith(bytes, PNG_SIGNATURE)) return 'the data is not a PNG';\n const view = new DataView(bytes.buffer);\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = view.getUint32(offset);\n const end = offset + 8 + length;\n if (end + 4 > bytes.length) break;\n if (crc32(bytes, offset + 4, end) !== view.getUint32(end)) return 'a PNG chunk failed its checksum';\n if (startsWith(bytes, [0x49, 0x45, 0x4e, 0x44], offset + 4)) return undefined;\n offset = end + 4;\n }\n return 'the PNG is truncated';\n }\n if (mimeType === 'image/jpeg') return startsWith(bytes, [0xff, 0xd8]) ? undefined : 'the data is not a JPEG';\n if (mimeType === 'image/gif')\n return startsWith(bytes, [0x47, 0x49, 0x46, 0x38]) ? undefined : 'the data is not a GIF';\n if (mimeType === 'image/webp')\n return startsWith(bytes, [0x52, 0x49, 0x46, 0x46]) && startsWith(bytes, [0x57, 0x45, 0x42, 0x50], 8)\n ? undefined\n : 'the data is not a WebP';\n return undefined;\n}\n\n/** Keeps valid images and swaps an undecodable one for a text note, since one bad image fails the whole turn and every later one. */\nexport function dropInvalidImages(content: readonly PoHeadlessContent[]): PoHeadlessContent[] {\n return content.map((part) => {\n if (part.type !== 'image') return part;\n const reason = invalidImageReason(part.data, part.mimeType);\n return reason === undefined ? part : { type: 'text', text: `[image omitted: ${reason}]` };\n });\n}\n\n/**\n * Narrows a Pi tool result to the headless contract. Pi types `structuredContent` as any JSON\n * value, while MCP only accepts an object, so anything else is dropped rather than forwarded.\n */\nexport function toPoHeadlessToolResult(result: {\n readonly content: PoHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly _meta?: CallToolResult['_meta'];\n readonly isError?: boolean;\n}): PoHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\n ...(result._meta === undefined ? {} : { _meta: result._meta }),\n ...(typeof structuredContent === 'object' && structuredContent !== null && !Array.isArray(structuredContent)\n ? { structuredContent: structuredContent as Record<string, unknown> }\n : {}),\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\nexport interface PoHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n purpose?: 'feedback';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n /** Set only by po-approval: a `select` of Approve/Deny the app draws as an approval card. */\n approval?: PoApprovalPrompt;\n}\n\nexport interface PoHeadlessClient {\n /**\n * Operator-facing surface only: the body is flattened to one line and capped at 4096 characters\n * by schemas/notification.ts:73-83, and the model never sees it. Use session.admitPrompt to\n * reach the model.\n */\n notify(request: PoNotificationRequest): void | Promise<void>;\n request(request: PoHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n /** Only the currently visible feedback question, never an approval or queued request. */\n pendingFeedback?():\n | {\n id: string;\n kind: 'select' | 'input';\n title: string;\n message?: string;\n labels?: string[];\n }\n | undefined;\n /** Returns false for stale ids, queued requests and approvals. */\n answerFeedback?(id: string, value: string): boolean;\n /** Only the visible approval at the head of the dialog queue. */\n pendingApproval?(): PoApprovalPrompt | undefined;\n /** Refuses stale, queued, expired and duplicate answers. Voice cannot answer a human approval. */\n answerApproval?(id: string, decision: 'approved' | 'denied', channel: 'voice' | 'app'): boolean;\n /** Ignored once the session has closed, so a package can clear its status while it unwinds. */\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface PoHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface PoHeadlessSession {\n /** Live host close intent, set synchronously before interruption. Absent for a person's stop or remove. */\n readonly closeReason?: 'released' | 'host_shutdown';\n readModelSettings?(): Promise<PoHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<PoHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n /** Stream matching history newest first. Stop iteration to stop storage reads. */\n entriesNewestFirst(query?: {\n type?: 'custom' | 'message' | 'compaction';\n customType?: string;\n limit?: number;\n }): AsyncIterable<Record<string, unknown>>;\n appendCustomEntry(type: string, data: unknown): Promise<void>;\n /** Append a displayable informational message to history and model context, without admitting input or starting a turn. */\n appendMessage?(message: { type: string; text: string; display?: boolean; details?: unknown }): Promise<string | void>;\n /**\n * Admit one custom message without awaiting its turn, using environmental input policy.\n * Defaults to followUp. Reusing requestId deduplicates normal Durable admission retries;\n * locked-agent appends and deferred operator admission do not provide that guarantee.\n * The receipt's settled resolves when the run that consumed the message ends; a locked agent\n * resolves it at once. Hosts without tracking return nothing.\n */\n admitMessage?(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n delivery?: 'steer' | 'followUp',\n requestId?: string,\n ): Promise<{ requestId: string; settled: Promise<void> } | void>;\n /**\n * Register a checkpoint flush before the next tool-turn request. Idle writes return undefined instead of queueing when busy.\n * `resetContext` starts native context at the message, which stands for itself followed by `retainedMessages`.\n */\n registerCheckpointBoundary?(\n callback: (boundary: {\n signal?: AbortSignal;\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n }) => Promise<void>,\n ): {\n appendMessage(\n message: {\n type: string;\n text: string;\n display?: boolean;\n details?: unknown;\n },\n options?: { resetContext?: { retainedMessages: readonly Record<string, unknown>[] } },\n ): Promise<string | undefined>;\n dispose(): void;\n };\n /** Detached canonical model context before package transformations, with context edits applied and no system message. */\n contextMessages?(): Promise<readonly Record<string, unknown>[]>;\n /** The latest measured assistant usage and the selected model's context window. */\n contextUsage?(): Promise<{ tokens: number | null; contextWindow: number } | undefined>;\n /** Label a durable entry without admitting input or starting a turn. */\n setLabel?(entryId: string, label: string | undefined): Promise<void>;\n /**\n * Delivers operator input through prompt preflight and awaits its turn.\n * Environmental input uses admitPrompt with origin omitted instead.\n * An idle agent is woken; busy delivery uses Durable steering or follow-up.\n */\n prompt(text: string, delivery?: 'prompt' | 'steer' | 'followUp'): Promise<void>;\n /**\n * Admits input without awaiting its turn. Environmental input omits origin and never\n * changes the operator queue. Operator origin uses prompt preflight, including voice\n * capture; 'interrupt' cancels the active run and admits operator input while preserving\n * retained queued work. Environmental callers may reuse requestId when retrying the same input.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n requestId?: string,\n ): Promise<void>;\n /** Stops the current run. With expectedOperationId, a different or finished operation is left alone. */\n abort(expectedOperationId?: string): Promise<void>;\n compact(instructions?: string): Promise<void>;\n /** operationId names the current run, absent while idle or settling. */\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean; operationId?: string }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** The current branch's newest entry, for a child that starts from this session's history. */\n forkSource?(): Promise<{\n kind: 'fork';\n entryId?: string;\n }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface PoMcpSkillAccess {\n list(): Promise<readonly { name: string; description: string }[]>;\n read(name: string): Promise<string>;\n}\n\n/** A stateless auxiliary request. These tools are private to this request, never registered on the agent. */\nexport interface PoHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary token usage in this session, including rejected results. */\n recordUsage?: boolean;\n tools: readonly Pick<PoHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface PoHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\n/** Credential-free catalog metadata. Packages cannot obtain auth, headers, or a mutable registry. */\nexport interface PoHeadlessModelMetadata {\n readonly provider: string;\n readonly id: string;\n readonly api?: string;\n readonly baseUrl?: string;\n readonly name?: string;\n readonly compat?: Readonly<Record<string, boolean | string>>;\n}\n\n/** Host policy retained by a supervised tool sequence after its original call returns. */\nexport interface PoHeadlessToolContinuation {\n admit(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n signal?: AbortSignal;\n }): Promise<Record<string, unknown>>;\n finalize(request: {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n result: PoHeadlessToolResult;\n signal?: AbortSignal;\n }): Promise<PoHeadlessToolResult>;\n}\n\nexport interface PoHeadlessExecutionContext {\n /** Present only on an admitted tool invocation. Retained callbacks recheck current host policy. */\n readonly toolContinuation?: PoHeadlessToolContinuation;\n readonly cwd: string;\n /** The checkout the session runs in, distinct from the tool execution directory. */\n readonly repoRoot: string;\n readonly sessionId: string;\n /** Who invoked the tool: the session's own agent, or a subagent borrowing it. Absent when the host cannot tell. */\n readonly caller?: 'main' | 'child';\n /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: PoSessionContext;\n /** Host-owned presence, also supplied when the session has no workspace context. */\n readonly interaction?: 'interactive' | 'unattended';\n /** Immutable session configuration. Packages must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: PoHeadlessClient;\n readonly session: PoHeadlessSession;\n readonly model?: PoHeadlessModelMetadata;\n /** Lookup in this session's catalog, including physical models named by finalized messages. */\n readonly getModel?: (provider: string, id: string) => PoHeadlessModelMetadata | undefined;\n /** Detached credential-free authenticated chat catalog, read after refreshing provider availability. */\n readonly getAvailableModels?: () => Promise<\n readonly {\n readonly provider: string;\n readonly id: string;\n }[]\n >;\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\n /** Tool-less conversation summary through the host's guarded session provider. */\n summarize?(\n reference: string,\n request: {\n messages: readonly Record<string, unknown>[];\n instructions: string;\n previousSummary?: string;\n thinkingLevel?: ThinkingLevel;\n signal?: AbortSignal;\n },\n ): Promise<string>;\n complete(\n reference: string,\n request: {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n /** Record auxiliary usage and reject truncated text rather than returning partial output. */\n recordUsage?: boolean;\n },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: PoHeadlessToolCompletionRequest): Promise<PoHeadlessToolCompletionResult>;\n };\n /** Guarded image operation. Credentials and transport configuration remain host-owned. */\n readonly imageGeneration?: {\n available(): boolean;\n generate(request: {\n prompt: string;\n transparentBackground?: boolean;\n images?: readonly { data: string; mimeType: string }[];\n correlationId: string;\n signal?: AbortSignal;\n }): Promise<{ data: string; mimeType: 'image/png'; requestId?: string; generationId?: string }>;\n };\n /**\n * Guarded web search. Credentials, endpoint, model choice, session identity and transport remain host-owned.\n * `commands` follows a schema owned by the calling package; the host only bounds it.\n */\n readonly webSearch?: {\n available(): boolean;\n search(request: {\n commands: Readonly<Record<string, unknown>>;\n /** Optional plain-text excerpt, oldest first. Omit to send no conversation content. */\n conversation?: readonly { role: 'user' | 'assistant'; text: string }[];\n access: 'cached' | 'indexed' | 'live';\n signal?: AbortSignal;\n }): Promise<{ output: string; results?: readonly Record<string, unknown>[] }>;\n };\n readonly selection: PoHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: PoMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface PoHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain' | 'shared'; mode: string; label?: string };\n domain?: string;\n /** Any selected domain must match. Absent is unrestricted; empty never matches. */\n domains?: readonly string[];\n}\n\nexport interface PoHeadlessToolRestriction {\n when?: PoHeadlessCondition;\n /** Optional capability ceiling. An empty list disables every tool. */\n allowedTools?: readonly string[];\n /**\n * Narrow exclusions without disabling unrelated tools. Exclude a tool your package owns, or a\n * specific foreign tool the mode exists to withdraw. Never enumerate an allowlist here.\n */\n excludedTools?: readonly string[];\n}\n\nexport interface PoHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: PoHeadlessCondition;\n name: string;\n label?: string;\n description: string;\n parameters: TParameters;\n annotations?: Tool['annotations'];\n outputSchema?: Tool['outputSchema'];\n /** Remote presentation only. Component tool access must be explicitly opted into. */\n _meta?: Tool['_meta'] & {\n ui?: { resourceUri?: string; visibility?: ('model' | 'app')[] };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n /**\n * Keeps the tool from subagents, which otherwise borrow the parent's tools. Set it when the tool needs\n * the person to answer, since nobody can answer a subagent, or when it acts for the main agent itself.\n */\n mainAgentOnly?: boolean;\n /** Asks the person before each call; see PoApprovalPolicy for who can answer. */\n approval?: PoApprovalPolicy;\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ): Promise<PoHeadlessToolResult>;\n}\n\n/**\n * One package contribution to the session's resource surface.\n *\n * `kind` decides what the model is billed for, and the difference is large:\n * - `context` is EAGER. `read()` runs on every prompt build and the text is pasted\n * into the system prompt verbatim. Reserve it for small live session state that\n * exists nowhere on disk. Never use it for a file the package ships: a README\n * registered this way costs its full length on every single turn.\n * - `skill` is LAZY. Only `name`, `description` and `path` reach the prompt; the\n * agent reads the file itself when the description matches the task.\n * - `prompt` is inert until the user invokes it by name.\n *\n * The rule in one line: if it is a file the package ships, it is a `skill`.\n */\nexport interface PoHeadlessResource {\n when?: PoHeadlessCondition;\n name: string;\n /** Model-visible selection signal. A `skill` without one tells the agent nothing. */\n description?: string;\n /** Absolute path of the file `read()` returns, so an advertised skill is one the agent can open. */\n path?: string;\n /**\n * A `skill` listed in the system prompt itself, kept out of the `load_skill` catalog and\n * `search_skills`. For a few always-relevant guides (the code-mode how-tos) that search would miss.\n */\n pinned?: boolean;\n kind: 'prompt' | 'skill' | 'context';\n read(context: PoHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface PoHeadlessCommand {\n when?: PoHeadlessCondition;\n name: string;\n description: string;\n /** Selection-only control allowed after a coherent selection fails admission. */\n selectionRecovery?: boolean;\n execute(args: string, context: PoHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type PoHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\n | 'agent_end'\n | 'agent_settled'\n | 'turn_start'\n | 'turn_end'\n | 'context'\n | 'before_provider_request'\n | 'message_start'\n | 'message_update'\n | 'message_end'\n | 'tool_call'\n | 'tool_execution_start'\n | 'tool_execution_update'\n | 'tool_execution_end'\n | 'tool_result'\n | 'model_select'\n | 'session_before_compact'\n | 'session_compact';\n\nexport type PoHeadlessHookEvent<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? {\n lane: string;\n runId: string;\n model: { provider: string; id: string; api?: string };\n payload: unknown;\n }\n : E extends 'session_before_compact'\n ? {\n reason: string;\n preparation: unknown;\n instructions?: string;\n customInstructions?: string;\n }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface PoHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type PoHeadlessHookResult<E extends PoHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? {\n cancel?: boolean;\n decline?: boolean;\n compaction?: PoHeadlessCompactionResult;\n } | void\n : E extends 'context'\n ? { messages?: unknown[]; systemPrompt?: string } | void\n : E extends 'before_agent_start'\n ? { systemPrompt?: string } | void\n : E extends 'tool_call'\n ? {\n args?: Record<string, unknown>;\n block?: { reason: string; terminate?: boolean };\n } | void\n : E extends 'tool_result'\n ? {\n content?: PoHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type PoHeadlessHook<E extends PoHeadlessEventName = PoHeadlessEventName> = E extends PoHeadlessEventName\n ? {\n when?: PoHeadlessCondition;\n event: E;\n handle(\n event: Readonly<PoHeadlessHookEvent<E>>,\n context: PoHeadlessExecutionContext,\n ): PoHeadlessHookResult<E> | Promise<PoHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained package can register activity without starting disabled watchers or services. */\nexport interface PoHeadlessActivity {\n when?: PoHeadlessCondition;\n name: string;\n start(context: PoHeadlessExecutionContext): (() => void | Promise<void>) | Promise<() => void | Promise<void>>;\n}\n\n/** Read-only metadata for the currently applied session, never executable declarations or resource bodies. */\nexport interface PoHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: PoHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\n/** Visibility controls model discovery only, never admission for external execution. */\nexport function isPoHeadlessToolModelVisible(tool: Pick<PoHeadlessTool, '_meta'>): boolean {\n const visibility = tool._meta?.ui?.visibility;\n return visibility === undefined || visibility.includes('model');\n}\n\nexport interface PoHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly PoHeadlessCapability[];\n}\n\n/** Session skill discovery tools, adapted to the size of the active catalog. */\nexport const PO_LOAD_SKILL_TOOL = 'load_skill';\nexport const PO_SEARCH_SKILLS_TOOL = 'search_skills';\nexport interface PoHeadlessHostService {\n readonly context: PoHeadlessExecutionContext;\n /** Admitted external execution, sharing native hooks, restrictions and session lifetime. */\n readonly toolSurface?: Pick<SessionToolSurface, 'readSurface' | 'invokeTool'>;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n /** Names and descriptions of searchable applied skills, excluding pinned guides and instruction bodies. */\n listSkills(): readonly { readonly name: string; readonly description: string }[];\n /** atToolBoundary defers the change to the next tool boundary, as slash commands do; idle sessions apply at once. */\n changeSelection(change: PoHeadlessSelectionChange, options?: { atToolBoundary?: boolean }): Promise<void>;\n assertActive(source?: string): void;\n /** Whether a package owns contributions in the currently applied selection. */\n isSourceActive(source: string): boolean;\n /** Normalize selection before the first successful application only. Disposed with the registering context. */\n registerInitialSelectionResolver(resolve: (selection: PoHeadlessSelection) => PoHeadlessSelection): () => void;\n subscribeSelection(\n listener: (selection: PoHeadlessSelection, applied: PoHeadlessSelectionApplied) => void | Promise<void>,\n ): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): PoHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: PoHeadlessToolRestriction): PoHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: PoHeadlessTool<TParameters>): PoHeadlessRegistration;\n registerResource(resource: PoHeadlessResource): PoHeadlessRegistration;\n registerCommand(command: PoHeadlessCommand): PoHeadlessRegistration;\n registerHook(hook: PoHeadlessHook): PoHeadlessRegistration;\n registerActivity(activity: PoHeadlessActivity): PoHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/headless-host': PoHeadlessHostService;\n }\n}\n\nexport function readPoHeadlessHost(context: Context): PoHeadlessHostService | undefined {\n return context.get(PO_HEADLESS_HOST_SERVICE) as PoHeadlessHostService | undefined;\n}\n\nexport function requirePoHeadlessHost(context: Context): PoHeadlessHostService {\n const host = readPoHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Po headless session host.');\n return host;\n}\n"],"mappings":"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"}
@@ -45,10 +45,10 @@ const PROFILE_ICON_MIME_TYPES = [
45
45
  "image/webp"
46
46
  ];
47
47
  const ProfileIdentityProjectionSchema = typebox.Type.Object({
48
- profile: typebox.Type.String({
48
+ profile: typebox.Type.Union([typebox.Type.String({
49
49
  minLength: 1,
50
50
  maxLength: MAX_PROFILE_NAME_LENGTH
51
- }),
51
+ }), typebox.Type.Null()]),
52
52
  name: typebox.Type.Optional(typebox.Type.String({
53
53
  minLength: 1,
54
54
  maxLength: MAX_PROFILE_NAME_LENGTH
@@ -1 +1 @@
1
- {"version":3,"file":"profileIdentity.cjs","names":["Type"],"sources":["../../../src/schemas/profileIdentity.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\n/**\n * The custom session entry the runtime journals when the active profile's\n * persona identity changes.\n *\n * A profile has always been prompt text only, so a cockpit had nothing to show\n * for it beyond the profile name already published as footer status. This entry\n * carries the persona's display name and avatar so the transcript can attribute\n * each assistant message to the persona that produced it.\n *\n * It rides Pi's `entry_appended` frames on the road the agent-model projection\n * already uses, so any RPC client sees the change live and on replay without a\n * new protocol.\n *\n * Unlike the minor-mode, context, and agent-model projections, this entry is\n * NOT a projection: it is transcript, positioned in journal order. A cockpit\n * folding it must keep every occurrence rather than collapsing to the latest\n * one, because a message written before a switch keeps the identity it was\n * written under. Collapsing would rewrite history.\n */\nexport const PO_PROFILE_IDENTITY_ENTRY_TYPE = 'po-profile-identity';\n\n/**\n * Ceiling on the encoded icon, counted on the finished `data:` URL rather than\n * the file, so one number bounds both the journal entry and the transport.\n *\n * An avatar renders at 32 CSS pixels. This much room is already generous, and\n * the cap exists because the entry is replayed with the transcript: an oversize\n * icon is dropped and the persona keeps its name, never failing a profile load.\n */\nexport const PROFILE_ICON_MAX_DATA_URL_LENGTH = 262_144;\n\nconst MAX_PROFILE_NAME_LENGTH = 128;\n\n/**\n * Image types allowed for a persona icon.\n *\n * Deliberately narrower than the cockpit's general media catalog: `image/svg+xml`\n * is excluded because an SVG rendered same-origin executes script, and the icon\n * path comes from user-authored persona front-matter. Do not reconcile this list\n * with the broader media type map.\n */\nexport const PROFILE_ICON_MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'] as const;\nexport type ProfileIconMimeType = (typeof PROFILE_ICON_MIME_TYPES)[number];\n\nexport const ProfileIdentityProjectionSchema = Type.Object(\n {\n profile: Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH }),\n name: Type.Optional(Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH })),\n icon: Type.Optional(Type.String({ minLength: 1, maxLength: PROFILE_ICON_MAX_DATA_URL_LENGTH })),\n },\n { additionalProperties: false },\n);\n\n/** The persona a message was produced under: the profile name, plus optional display name and icon. */\nexport type ProfileIdentityProjection = Static<typeof ProfileIdentityProjectionSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,iCAAiC;;;;;;;;;AAU9C,MAAa,mCAAmC;AAEhD,MAAM,0BAA0B;;;;;;;;;AAUhC,MAAa,0BAA0B;CAAC;CAAa;CAAc;CAAa;AAAY;AAG5F,MAAa,kCAAkCA,QAAAA,KAAK,OAClD;CACE,SAASA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC;CACzE,MAAMA,QAAAA,KAAK,SAASA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,CAAC;CACrF,MAAMA,QAAAA,KAAK,SAASA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAiC,CAAC,CAAC;AAChG,GACA,EAAE,sBAAsB,MAAM,CAChC"}
1
+ {"version":3,"file":"profileIdentity.cjs","names":["Type"],"sources":["../../../src/schemas/profileIdentity.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\n/**\n * The custom session entry the runtime journals when the active profile's\n * persona identity changes.\n *\n * A profile has always been prompt text only, so a cockpit had nothing to show\n * for it beyond the profile name already published as footer status. This entry\n * carries the persona's display name and avatar so the transcript can attribute\n * each assistant message to the persona that produced it.\n *\n * It rides Pi's `entry_appended` frames on the road the agent-model projection\n * already uses, so any RPC client sees the change live and on replay without a\n * new protocol.\n *\n * Unlike the minor-mode, context, and agent-model projections, this entry is\n * NOT a projection: it is transcript, positioned in journal order. A cockpit\n * folding it must keep every occurrence rather than collapsing to the latest\n * one, because a message written before a switch keeps the identity it was\n * written under. Collapsing would rewrite history.\n */\nexport const PO_PROFILE_IDENTITY_ENTRY_TYPE = 'po-profile-identity';\n\n/**\n * Ceiling on the encoded icon, counted on the finished `data:` URL rather than\n * the file, so one number bounds both the journal entry and the transport.\n *\n * An avatar renders at 32 CSS pixels. This much room is already generous, and\n * the cap exists because the entry is replayed with the transcript: an oversize\n * icon is dropped and the persona keeps its name, never failing a profile load.\n */\nexport const PROFILE_ICON_MAX_DATA_URL_LENGTH = 262_144;\n\nconst MAX_PROFILE_NAME_LENGTH = 128;\n\n/**\n * Image types allowed for a persona icon.\n *\n * Deliberately narrower than the cockpit's general media catalog: `image/svg+xml`\n * is excluded because an SVG rendered same-origin executes script, and the icon\n * path comes from user-authored persona front-matter. Do not reconcile this list\n * with the broader media type map.\n */\nexport const PROFILE_ICON_MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'] as const;\nexport type ProfileIconMimeType = (typeof PROFILE_ICON_MIME_TYPES)[number];\n\nexport const ProfileIdentityProjectionSchema = Type.Object(\n {\n profile: Type.Union([Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH }), Type.Null()]),\n name: Type.Optional(Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH })),\n icon: Type.Optional(Type.String({ minLength: 1, maxLength: PROFILE_ICON_MAX_DATA_URL_LENGTH })),\n },\n { additionalProperties: false },\n);\n\n/** The persona a message was produced under: the profile name, plus optional display name and icon. */\nexport type ProfileIdentityProjection = Static<typeof ProfileIdentityProjectionSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,iCAAiC;;;;;;;;;AAU9C,MAAa,mCAAmC;AAEhD,MAAM,0BAA0B;;;;;;;;;AAUhC,MAAa,0BAA0B;CAAC;CAAa;CAAc;CAAa;AAAY;AAG5F,MAAa,kCAAkCA,QAAAA,KAAK,OAClD;CACE,SAASA,QAAAA,KAAK,MAAM,CAACA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,GAAGA,QAAAA,KAAK,KAAK,CAAC,CAAC;CACpG,MAAMA,QAAAA,KAAK,SAASA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,CAAC;CACrF,MAAMA,QAAAA,KAAK,SAASA,QAAAA,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAiC,CAAC,CAAC;AAChG,GACA,EAAE,sBAAsB,MAAM,CAChC"}
@@ -40,7 +40,7 @@ export declare const PROFILE_ICON_MAX_DATA_URL_LENGTH = 262144;
40
40
  export declare const PROFILE_ICON_MIME_TYPES: readonly ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
41
41
  export type ProfileIconMimeType = (typeof PROFILE_ICON_MIME_TYPES)[number];
42
42
  export declare const ProfileIdentityProjectionSchema: Type.TObject<{
43
- profile: Type.TString;
43
+ profile: Type.TUnion<[Type.TString, Type.TNull]>;
44
44
  name: Type.TOptional<Type.TString>;
45
45
  icon: Type.TOptional<Type.TString>;
46
46
  }>;
@@ -45,10 +45,10 @@ const PROFILE_ICON_MIME_TYPES = [
45
45
  "image/webp"
46
46
  ];
47
47
  const ProfileIdentityProjectionSchema = Type.Object({
48
- profile: Type.String({
48
+ profile: Type.Union([Type.String({
49
49
  minLength: 1,
50
50
  maxLength: MAX_PROFILE_NAME_LENGTH
51
- }),
51
+ }), Type.Null()]),
52
52
  name: Type.Optional(Type.String({
53
53
  minLength: 1,
54
54
  maxLength: MAX_PROFILE_NAME_LENGTH
@@ -1 +1 @@
1
- {"version":3,"file":"profileIdentity.mjs","names":[],"sources":["../../../src/schemas/profileIdentity.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\n/**\n * The custom session entry the runtime journals when the active profile's\n * persona identity changes.\n *\n * A profile has always been prompt text only, so a cockpit had nothing to show\n * for it beyond the profile name already published as footer status. This entry\n * carries the persona's display name and avatar so the transcript can attribute\n * each assistant message to the persona that produced it.\n *\n * It rides Pi's `entry_appended` frames on the road the agent-model projection\n * already uses, so any RPC client sees the change live and on replay without a\n * new protocol.\n *\n * Unlike the minor-mode, context, and agent-model projections, this entry is\n * NOT a projection: it is transcript, positioned in journal order. A cockpit\n * folding it must keep every occurrence rather than collapsing to the latest\n * one, because a message written before a switch keeps the identity it was\n * written under. Collapsing would rewrite history.\n */\nexport const PO_PROFILE_IDENTITY_ENTRY_TYPE = 'po-profile-identity';\n\n/**\n * Ceiling on the encoded icon, counted on the finished `data:` URL rather than\n * the file, so one number bounds both the journal entry and the transport.\n *\n * An avatar renders at 32 CSS pixels. This much room is already generous, and\n * the cap exists because the entry is replayed with the transcript: an oversize\n * icon is dropped and the persona keeps its name, never failing a profile load.\n */\nexport const PROFILE_ICON_MAX_DATA_URL_LENGTH = 262_144;\n\nconst MAX_PROFILE_NAME_LENGTH = 128;\n\n/**\n * Image types allowed for a persona icon.\n *\n * Deliberately narrower than the cockpit's general media catalog: `image/svg+xml`\n * is excluded because an SVG rendered same-origin executes script, and the icon\n * path comes from user-authored persona front-matter. Do not reconcile this list\n * with the broader media type map.\n */\nexport const PROFILE_ICON_MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'] as const;\nexport type ProfileIconMimeType = (typeof PROFILE_ICON_MIME_TYPES)[number];\n\nexport const ProfileIdentityProjectionSchema = Type.Object(\n {\n profile: Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH }),\n name: Type.Optional(Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH })),\n icon: Type.Optional(Type.String({ minLength: 1, maxLength: PROFILE_ICON_MAX_DATA_URL_LENGTH })),\n },\n { additionalProperties: false },\n);\n\n/** The persona a message was produced under: the profile name, plus optional display name and icon. */\nexport type ProfileIdentityProjection = Static<typeof ProfileIdentityProjectionSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,iCAAiC;;;;;;;;;AAU9C,MAAa,mCAAmC;AAEhD,MAAM,0BAA0B;;;;;;;;;AAUhC,MAAa,0BAA0B;CAAC;CAAa;CAAc;CAAa;AAAY;AAG5F,MAAa,kCAAkC,KAAK,OAClD;CACE,SAAS,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC;CACzE,MAAM,KAAK,SAAS,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,CAAC;CACrF,MAAM,KAAK,SAAS,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAiC,CAAC,CAAC;AAChG,GACA,EAAE,sBAAsB,MAAM,CAChC"}
1
+ {"version":3,"file":"profileIdentity.mjs","names":[],"sources":["../../../src/schemas/profileIdentity.ts"],"sourcesContent":["import { type Static, Type } from 'typebox';\n\n/**\n * The custom session entry the runtime journals when the active profile's\n * persona identity changes.\n *\n * A profile has always been prompt text only, so a cockpit had nothing to show\n * for it beyond the profile name already published as footer status. This entry\n * carries the persona's display name and avatar so the transcript can attribute\n * each assistant message to the persona that produced it.\n *\n * It rides Pi's `entry_appended` frames on the road the agent-model projection\n * already uses, so any RPC client sees the change live and on replay without a\n * new protocol.\n *\n * Unlike the minor-mode, context, and agent-model projections, this entry is\n * NOT a projection: it is transcript, positioned in journal order. A cockpit\n * folding it must keep every occurrence rather than collapsing to the latest\n * one, because a message written before a switch keeps the identity it was\n * written under. Collapsing would rewrite history.\n */\nexport const PO_PROFILE_IDENTITY_ENTRY_TYPE = 'po-profile-identity';\n\n/**\n * Ceiling on the encoded icon, counted on the finished `data:` URL rather than\n * the file, so one number bounds both the journal entry and the transport.\n *\n * An avatar renders at 32 CSS pixels. This much room is already generous, and\n * the cap exists because the entry is replayed with the transcript: an oversize\n * icon is dropped and the persona keeps its name, never failing a profile load.\n */\nexport const PROFILE_ICON_MAX_DATA_URL_LENGTH = 262_144;\n\nconst MAX_PROFILE_NAME_LENGTH = 128;\n\n/**\n * Image types allowed for a persona icon.\n *\n * Deliberately narrower than the cockpit's general media catalog: `image/svg+xml`\n * is excluded because an SVG rendered same-origin executes script, and the icon\n * path comes from user-authored persona front-matter. Do not reconcile this list\n * with the broader media type map.\n */\nexport const PROFILE_ICON_MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'] as const;\nexport type ProfileIconMimeType = (typeof PROFILE_ICON_MIME_TYPES)[number];\n\nexport const ProfileIdentityProjectionSchema = Type.Object(\n {\n profile: Type.Union([Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH }), Type.Null()]),\n name: Type.Optional(Type.String({ minLength: 1, maxLength: MAX_PROFILE_NAME_LENGTH })),\n icon: Type.Optional(Type.String({ minLength: 1, maxLength: PROFILE_ICON_MAX_DATA_URL_LENGTH })),\n },\n { additionalProperties: false },\n);\n\n/** The persona a message was produced under: the profile name, plus optional display name and icon. */\nexport type ProfileIdentityProjection = Static<typeof ProfileIdentityProjectionSchema>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,iCAAiC;;;;;;;;;AAU9C,MAAa,mCAAmC;AAEhD,MAAM,0BAA0B;;;;;;;;;AAUhC,MAAa,0BAA0B;CAAC;CAAa;CAAc;CAAa;AAAY;AAG5F,MAAa,kCAAkC,KAAK,OAClD;CACE,SAAS,KAAK,MAAM,CAAC,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;CACpG,MAAM,KAAK,SAAS,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAwB,CAAC,CAAC;CACrF,MAAM,KAAK,SAAS,KAAK,OAAO;EAAE,WAAW;EAAG,WAAW;CAAiC,CAAC,CAAC;AAChG,GACA,EAAE,sBAAsB,MAAM,CAChC"}
@@ -14,9 +14,9 @@ const MAX_WARNING_DETAIL_DEPTH = 3;
14
14
  const MAX_ATTRIBUTE_STRING_LENGTH = 128;
15
15
  const MAX_REPORTED_FAILURES = 500;
16
16
  const MAX_EVENT_NAME_LENGTH = 128;
17
- const SESSION_ID_HEADERS = ["AGENT_SESSION_ID", "PI_SESSION_ID"];
17
+ const SESSION_ID_HEADERS = ["AGENT_SESSION_ID", "PO_SESSION_ID"];
18
18
  const PARENT_SESSION_ID_HEADERS = ["AGENT_PARENT_SESSION_ID", "PARENT_AGENT_SESSION_ID"];
19
- const TRANSPORT_SESSION_HEADERS = ["PI_SESSION_ID", "AGENT_PARENT_SESSION_ID"];
19
+ const TRANSPORT_SESSION_HEADERS = ["PO_SESSION_ID", "AGENT_PARENT_SESSION_ID"];
20
20
  const TRUE_VALUES = /* @__PURE__ */ new Set([
21
21
  "1",
22
22
  "true",