@agimon-ai/doompi-core 0.0.1-alpha.111 → 0.0.1-alpha.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/schemas/headless.cjs.map +1 -1
- package/dist/src/schemas/headless.d.mts +2 -2
- package/dist/src/schemas/headless.d.mts.map +1 -1
- package/dist/src/schemas/headless.mjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.cjs +52 -52
- package/dist/src/server/directHarnessRuntime.cjs.map +1 -1
- package/dist/src/server/directHarnessRuntime.mjs +52 -52
- package/dist/src/server/directHarnessRuntime.mjs.map +1 -1
- package/dist/src/services/piExtensionHost/index.cjs +14 -6
- package/dist/src/services/piExtensionHost/index.cjs.map +1 -1
- package/dist/src/services/piExtensionHost/index.mjs +14 -6
- package/dist/src/services/piExtensionHost/index.mjs.map +1 -1
- package/dist/src/systems/main/adapters/headlessSessionHost.cjs +2 -2
- package/dist/src/systems/main/adapters/headlessSessionHost.cjs.map +1 -1
- package/dist/src/systems/main/adapters/headlessSessionHost.mjs +2 -2
- package/dist/src/systems/main/adapters/headlessSessionHost.mjs.map +1 -1
- package/dist/src/types/server/directHarnessRuntime.d.mts +2 -1
- package/dist/src/types/server/directHarnessRuntime.d.mts.map +1 -1
- package/package.json +1 -1
|
@@ -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 { DoomSessionContext } from './hubChannel';\nimport type { DoomNotificationRequest } from './notification';\nimport type { DoomServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const DOOM_HEADLESS_HOST_SERVICE = 'doom/headless-host';\nexport const DOOM_HEADLESS_OWNER = Symbol.for('doom/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'DoomHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory facet-hook failure. */\nexport class DoomHeadlessPromptAdmissionError 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\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isDoomHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nexport interface DoomHeadlessSelection {\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 facets change exactly one axis per operation. */\nexport type DoomHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | { readonly axis: 'state'; readonly key: string; readonly values: readonly string[] };\n\nexport function readDoomHeadlessOwner(context: Context): DoomServerBundleEntry | undefined {\n return (context as Context & { [DOOM_HEADLESS_OWNER]?: DoomServerBundleEntry })[DOOM_HEADLESS_OWNER];\n}\n\nexport interface DoomHeadlessRegistration {\n dispose(): void;\n}\n\nexport type DoomHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface DoomHeadlessToolResult {\n content: DoomHeadlessContent[];\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\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 toDoomHeadlessToolResult(result: {\n readonly content: DoomHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly isError?: boolean;\n}): DoomHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\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 DoomHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n}\n\nexport interface DoomHeadlessClient {\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: DoomNotificationRequest): void | Promise<void>;\n request(request: DoomHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface DoomHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface DoomHeadlessSession {\n readModelSettings?(): Promise<DoomHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<DoomHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n appendCustomEntry(type: string, data: unknown): 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.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n ): Promise<void>;\n abort(): Promise<void>;\n compact(instructions?: string): Promise<void>;\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** Capture the current persisted branch for an in-process child fork. */\n forkSource?(): Promise<{ kind: 'v4-fork'; sessionFile: string; branch: string; entryId?: string }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface DoomMcpSkillAccess {\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 DoomHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n tools: readonly Pick<DoomHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface DoomHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\nexport interface DoomHeadlessExecutionContext {\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 /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: DoomSessionContext;\n /** Immutable session configuration. Facets must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: DoomHeadlessClient;\n readonly session: DoomHeadlessSession;\n readonly model?: { provider: string; id: string };\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\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 },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: DoomHeadlessToolCompletionRequest): Promise<DoomHeadlessToolCompletionResult>;\n };\n readonly selection: DoomHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: DoomMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface DoomHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain'; mode: string; label?: string };\n domain?: string;\n}\n\nexport interface DoomHeadlessToolRestriction {\n when?: DoomHeadlessCondition;\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 DoomHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: DoomHeadlessCondition;\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?: {\n resourceUri?: string;\n visibility?: ('model' | 'app')[];\n };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ): Promise<DoomHeadlessToolResult>;\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 DoomHeadlessResource {\n when?: DoomHeadlessCondition;\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 kind: 'prompt' | 'skill' | 'context';\n read(context: DoomHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface DoomHeadlessCommand {\n when?: DoomHeadlessCondition;\n name: string;\n description: string;\n execute(args: string, context: DoomHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type DoomHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\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 DoomHeadlessHookEvent<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { lane: string; runId: string; model: { provider: string; id: string }; payload: unknown }\n : E extends 'session_before_compact'\n ? { reason: string; preparation: unknown; instructions?: string; customInstructions?: string }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface DoomHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type DoomHeadlessHookResult<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? { cancel?: boolean; decline?: boolean; compaction?: DoomHeadlessCompactionResult } | 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 ? { args?: Record<string, unknown>; block?: { reason: string; terminate?: boolean } } | void\n : E extends 'tool_result'\n ? {\n content?: DoomHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type DoomHeadlessHook<E extends DoomHeadlessEventName = DoomHeadlessEventName> = E extends DoomHeadlessEventName\n ? {\n when?: DoomHeadlessCondition;\n event: E;\n handle(\n event: Readonly<DoomHeadlessHookEvent<E>>,\n context: DoomHeadlessExecutionContext,\n ): DoomHeadlessHookResult<E> | Promise<DoomHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained facet can register activity without starting disabled watchers or services. */\nexport interface DoomHeadlessActivity {\n when?: DoomHeadlessCondition;\n name: string;\n start(context: DoomHeadlessExecutionContext): (() => 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 DoomHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: DoomHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\nexport interface DoomHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly DoomHeadlessCapability[];\n}\n\n/** Registrations inherit package ownership from the caller's Cordis facet. */\n/**\n * The tool a server session loads skills through. When a session carries it, the prompt lists\n * every skill by name and points here, so a skill needs no file the agent could read.\n */\nexport const DOOM_LOAD_SKILL_TOOL = 'load_skill';\n\nexport interface DoomHeadlessHostService {\n readonly context: DoomHeadlessExecutionContext;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n changeSelection(change: DoomHeadlessSelectionChange): Promise<void>;\n assertActive(source?: string): void;\n subscribeSelection(listener: (selection: DoomHeadlessSelection) => void | Promise<void>): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): DoomHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: DoomHeadlessToolRestriction): DoomHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: DoomHeadlessTool<TParameters>): DoomHeadlessRegistration;\n registerResource(resource: DoomHeadlessResource): DoomHeadlessRegistration;\n registerCommand(command: DoomHeadlessCommand): DoomHeadlessRegistration;\n registerHook(hook: DoomHeadlessHook): DoomHeadlessRegistration;\n registerActivity(activity: DoomHeadlessActivity): DoomHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/headless-host': DoomHeadlessHostService;\n }\n}\n\nexport function readDoomHeadlessHost(context: Context): DoomHeadlessHostService | undefined {\n return context.get(DOOM_HEADLESS_HOST_SERVICE) as DoomHeadlessHostService | undefined;\n}\n\nexport function requireDoomHeadlessHost(context: Context): DoomHeadlessHostService {\n const host = readDoomHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Doom headless session host.');\n return host;\n}\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAC1C,MAAa,sBAAsB,OAAO,IAAI,qBAAqB;AAEnE,MAAM,yBAAyB;;AAG/B,IAAa,mCAAb,cAAsD,MAAM;CAC1D,YAAY,OAAgB;EAC1B,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC;EACvE,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAiBA,SAAgB,sBAAsB,SAAqD;CACzF,OAAQ,QAAwE;AAClF;;;;;AAsBA,SAAgB,yBAAyB,QAKd;CACzB,MAAM,EAAE,sBAAsB;CAC9B,OAAO;EACL,SAAS,OAAO;EAChB,SAAS,OAAO;EAChB,GAAI,OAAO,sBAAsB,YAAY,sBAAsB,QAAQ,CAAC,MAAM,QAAQ,iBAAiB,IACvG,EAAqB,kBAA6C,IAClE,CAAC;EACL,GAAI,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO,QAAQ;CACpE;AACF;;;;;;AA0SA,MAAa,uBAAuB;AAyBpC,SAAgB,qBAAqB,SAAuD;CAC1F,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,wBAAwB,SAA2C;CACjF,MAAM,OAAO,qBAAqB,OAAO;CACzC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,4DAA4D;CACvF,OAAO;AACT"}
|
|
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 { DoomSessionContext } from './hubChannel';\nimport type { DoomNotificationRequest } from './notification';\nimport type { DoomServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const DOOM_HEADLESS_HOST_SERVICE = 'doom/headless-host';\nexport const DOOM_HEADLESS_OWNER = Symbol.for('doom/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'DoomHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory facet-hook failure. */\nexport class DoomHeadlessPromptAdmissionError 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\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isDoomHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nexport interface DoomHeadlessSelection {\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 facets change exactly one axis per operation. */\nexport type DoomHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | { readonly axis: 'state'; readonly key: string; readonly values: readonly string[] };\n\nexport function readDoomHeadlessOwner(context: Context): DoomServerBundleEntry | undefined {\n return (context as Context & { [DOOM_HEADLESS_OWNER]?: DoomServerBundleEntry })[DOOM_HEADLESS_OWNER];\n}\n\nexport interface DoomHeadlessRegistration {\n dispose(): void;\n}\n\nexport type DoomHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface DoomHeadlessToolResult {\n content: DoomHeadlessContent[];\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\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 toDoomHeadlessToolResult(result: {\n readonly content: DoomHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly isError?: boolean;\n}): DoomHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\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 DoomHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n}\n\nexport interface DoomHeadlessClient {\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: DoomNotificationRequest): void | Promise<void>;\n request(request: DoomHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface DoomHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface DoomHeadlessSession {\n readModelSettings?(): Promise<DoomHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<DoomHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n appendCustomEntry(type: string, data: unknown): 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 abort(): Promise<void>;\n compact(instructions?: string): Promise<void>;\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** Capture the current persisted branch for an in-process child fork. */\n forkSource?(): Promise<{ kind: 'v4-fork'; sessionFile: string; branch: string; entryId?: string }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface DoomMcpSkillAccess {\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 DoomHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n tools: readonly Pick<DoomHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface DoomHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\nexport interface DoomHeadlessExecutionContext {\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 /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: DoomSessionContext;\n /** Immutable session configuration. Facets must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: DoomHeadlessClient;\n readonly session: DoomHeadlessSession;\n readonly model?: { provider: string; id: string };\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\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 },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: DoomHeadlessToolCompletionRequest): Promise<DoomHeadlessToolCompletionResult>;\n };\n readonly selection: DoomHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: DoomMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface DoomHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain'; mode: string; label?: string };\n domain?: string;\n}\n\nexport interface DoomHeadlessToolRestriction {\n when?: DoomHeadlessCondition;\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 DoomHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: DoomHeadlessCondition;\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?: {\n resourceUri?: string;\n visibility?: ('model' | 'app')[];\n };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ): Promise<DoomHeadlessToolResult>;\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 DoomHeadlessResource {\n when?: DoomHeadlessCondition;\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 kind: 'prompt' | 'skill' | 'context';\n read(context: DoomHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface DoomHeadlessCommand {\n when?: DoomHeadlessCondition;\n name: string;\n description: string;\n execute(args: string, context: DoomHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type DoomHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\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 DoomHeadlessHookEvent<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { lane: string; runId: string; model: { provider: string; id: string }; payload: unknown }\n : E extends 'session_before_compact'\n ? { reason: string; preparation: unknown; instructions?: string; customInstructions?: string }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface DoomHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type DoomHeadlessHookResult<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? { cancel?: boolean; decline?: boolean; compaction?: DoomHeadlessCompactionResult } | 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 ? { args?: Record<string, unknown>; block?: { reason: string; terminate?: boolean } } | void\n : E extends 'tool_result'\n ? {\n content?: DoomHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type DoomHeadlessHook<E extends DoomHeadlessEventName = DoomHeadlessEventName> = E extends DoomHeadlessEventName\n ? {\n when?: DoomHeadlessCondition;\n event: E;\n handle(\n event: Readonly<DoomHeadlessHookEvent<E>>,\n context: DoomHeadlessExecutionContext,\n ): DoomHeadlessHookResult<E> | Promise<DoomHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained facet can register activity without starting disabled watchers or services. */\nexport interface DoomHeadlessActivity {\n when?: DoomHeadlessCondition;\n name: string;\n start(context: DoomHeadlessExecutionContext): (() => 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 DoomHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: DoomHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\nexport interface DoomHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly DoomHeadlessCapability[];\n}\n\n/** Registrations inherit package ownership from the caller's Cordis facet. */\n/**\n * The tool a server session loads skills through. When a session carries it, the prompt lists\n * every skill by name and points here, so a skill needs no file the agent could read.\n */\nexport const DOOM_LOAD_SKILL_TOOL = 'load_skill';\n\nexport interface DoomHeadlessHostService {\n readonly context: DoomHeadlessExecutionContext;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n changeSelection(change: DoomHeadlessSelectionChange): Promise<void>;\n assertActive(source?: string): void;\n subscribeSelection(listener: (selection: DoomHeadlessSelection) => void | Promise<void>): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): DoomHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: DoomHeadlessToolRestriction): DoomHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: DoomHeadlessTool<TParameters>): DoomHeadlessRegistration;\n registerResource(resource: DoomHeadlessResource): DoomHeadlessRegistration;\n registerCommand(command: DoomHeadlessCommand): DoomHeadlessRegistration;\n registerHook(hook: DoomHeadlessHook): DoomHeadlessRegistration;\n registerActivity(activity: DoomHeadlessActivity): DoomHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/headless-host': DoomHeadlessHostService;\n }\n}\n\nexport function readDoomHeadlessHost(context: Context): DoomHeadlessHostService | undefined {\n return context.get(DOOM_HEADLESS_HOST_SERVICE) as DoomHeadlessHostService | undefined;\n}\n\nexport function requireDoomHeadlessHost(context: Context): DoomHeadlessHostService {\n const host = readDoomHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Doom headless session host.');\n return host;\n}\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAC1C,MAAa,sBAAsB,OAAO,IAAI,qBAAqB;AAEnE,MAAM,yBAAyB;;AAG/B,IAAa,mCAAb,cAAsD,MAAM;CAC1D,YAAY,OAAgB;EAC1B,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC;EACvE,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAiBA,SAAgB,sBAAsB,SAAqD;CACzF,OAAQ,QAAwE;AAClF;;;;;AAsBA,SAAgB,yBAAyB,QAKd;CACzB,MAAM,EAAE,sBAAsB;CAC9B,OAAO;EACL,SAAS,OAAO;EAChB,SAAS,OAAO;EAChB,GAAI,OAAO,sBAAsB,YAAY,sBAAsB,QAAQ,CAAC,MAAM,QAAQ,iBAAiB,IACvG,EAAqB,kBAA6C,IAClE,CAAC;EACL,GAAI,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO,QAAQ;CACpE;AACF;;;;;;AA2SA,MAAa,uBAAuB;AAyBpC,SAAgB,qBAAqB,SAAuD;CAC1F,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,wBAAwB,SAA2C;CACjF,MAAM,OAAO,qBAAqB,OAAO;CACzC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,4DAA4D;CACvF,OAAO;AACT"}
|
|
@@ -120,9 +120,9 @@ export interface DoomHeadlessSession {
|
|
|
120
120
|
* Admits input without awaiting its turn. Environmental input omits origin and never
|
|
121
121
|
* changes the operator queue. Operator origin uses prompt preflight, including voice
|
|
122
122
|
* capture; 'interrupt' cancels the active run and admits operator input while preserving
|
|
123
|
-
* retained queued work.
|
|
123
|
+
* retained queued work. Environmental callers may reuse requestId when retrying the same input.
|
|
124
124
|
*/
|
|
125
|
-
admitPrompt?(text: string, delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt', origin?: 'operator'): Promise<void>;
|
|
125
|
+
admitPrompt?(text: string, delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt', origin?: 'operator', requestId?: string): Promise<void>;
|
|
126
126
|
abort(): Promise<void>;
|
|
127
127
|
compact(instructions?: string): Promise<void>;
|
|
128
128
|
activity(): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless.d.mts","names":[],"sources":["../../../src/schemas/headless.ts"],"mappings":";;;;;;;;;qBAUa;qBACA;;qBAKA,yCAAyC;EACpD,YAAY;;;wBAOE,mCAAmC;iBAGlC;WACN;WACA;WACA;WACA;;WAEA,QAAQ,SAAS;;;YAIhB;WACG;WAA4B;;WAC5B;WAA0B;;WAC1B;WAA0B;;WAC1B;WAAwB;WAAsB;;wBAE7C,sBAAsB,SAAS,UAAU;iBAIxC;EACf;;YAGU;EAAwB;EAAc;;EAAmB;EAAe;EAAc;;iBAEjF;EACf,SAAS;;EAET,oBAAoB;;EAEpB,QAAQ;EACR;EACA;;;;;;wBAOc,yBAAyB;WAC9B,SAAS;WACT;WACA;WACA;IACP;iBAYa;EACf;EACA;EACA;EACA;IAAqB;IAAe;IAAsB;;EAC1D;EACA;;iBAGe;;;;;;EAMf,OAAO,SAAS,iCAAiC;EACjD,QAAQ,SAAS,2BAA2B,SAAS,cAAc;EACnE,UAAU,gBAAgB;EAC1B,oBAAoB;;iBAGL;EACf;IAAU;IAAkB;;EAC5B,eAAe;;iBAGA;EACf,sBAAsB,QAAQ;EAC9B,aAAa,mBAAmB;EAChC,kBAAkB,UAAU,QAAQ,6BAA6B;;EAEjE,QAAQ;IACN;IACA;IACA;eACW,4BAA4B,iBAAiB;EAC1D,kBAAkB,cAAc,gBAAgB;;;;;;EAMhD,OAAO,cAAc,6CAA6C;;;;;;;EAOlE,aACE,cACA,0DACA,
|
|
1
|
+
{"version":3,"file":"headless.d.mts","names":[],"sources":["../../../src/schemas/headless.ts"],"mappings":";;;;;;;;;qBAUa;qBACA;;qBAKA,yCAAyC;EACpD,YAAY;;;wBAOE,mCAAmC;iBAGlC;WACN;WACA;WACA;WACA;;WAEA,QAAQ,SAAS;;;YAIhB;WACG;WAA4B;;WAC5B;WAA0B;;WAC1B;WAA0B;;WAC1B;WAAwB;WAAsB;;wBAE7C,sBAAsB,SAAS,UAAU;iBAIxC;EACf;;YAGU;EAAwB;EAAc;;EAAmB;EAAe;EAAc;;iBAEjF;EACf,SAAS;;EAET,oBAAoB;;EAEpB,QAAQ;EACR;EACA;;;;;;wBAOc,yBAAyB;WAC9B,SAAS;WACT;WACA;WACA;IACP;iBAYa;EACf;EACA;EACA;EACA;IAAqB;IAAe;IAAsB;;EAC1D;EACA;;iBAGe;;;;;;EAMf,OAAO,SAAS,iCAAiC;EACjD,QAAQ,SAAS,2BAA2B,SAAS,cAAc;EACnE,UAAU,gBAAgB;EAC1B,oBAAoB;;iBAGL;EACf;IAAU;IAAkB;;EAC5B,eAAe;;iBAGA;EACf,sBAAsB,QAAQ;EAC9B,aAAa,mBAAmB;EAChC,kBAAkB,UAAU,QAAQ,6BAA6B;;EAEjE,QAAQ;IACN;IACA;IACA;eACW,4BAA4B,iBAAiB;EAC1D,kBAAkB,cAAc,gBAAgB;;;;;;EAMhD,OAAO,cAAc,6CAA6C;;;;;;;EAOlE,aACE,cACA,0DACA,qBACA,qBACC;EACH,SAAS;EACT,QAAQ,wBAAwB;EAChC,YAAY;IAAU;IAA6B;;;EAEnD,SAAS,eAAe;;EAExB,eAAe;IAAU;IAAiB;IAAqB;IAAgB;;;;iBAIhE;EACf,QAAQ;IAAmB;IAAc;;EACzC,KAAK,eAAe;;;iBAIL;EACf;EACA;EACA;EACA;EACA,SAAS;EACT,gBAAgB,KAAK;;iBAGN;EACf;IAAsB;IAAY;IAAc;;EAChD;IAAS;;;iBAGM;WACN;;WAEA;WACA;;WAEA,iBAAiB;;WAEjB,aAAa,SAAS;WACtB,QAAQ;WACR,SAAS;WACT;IAAU;IAAkB;;;WAE5B,SAAS;WACT;IACP,UAAU;IACV,SACE,mBACA;MACE;MACA;MACA;MACA;MACA,SAAS;QAEV;;WAEI;IACP,SAAS,mBAAmB,SAAS,oCAAoC,QAAQ;;WAE1E,WAAW;;WAEX,YAAY;EACrB;;;iBAIe;EACf,QAAQ,SAAS;EACjB;IAAgB;IAA0B;IAAc;;EACxD;;iBAGe;EACf,OAAO;;EAEP;;;;;EAKA;;iBAGe,iBAAiB,oBAAoB,UAAU;EAC9D,OAAO;EACP;EACA;EACA;EACA,YAAY;EACZ,cAAc;EACd,eAAe;;EAEf,QAAQ;IACN;MACE;MACA;;;EAGJ;EACA;EACA;EACA,QACE,oBACA,YAAY,OAAO,cACnB,QAAQ,yBACR,YAAY,QAAQ,8CACpB,SAAS,+BACR,QAAQ;;;;;;;;;;;;;;;;iBAiBI;EACf,OAAO;EACP;;EAEA;;EAEA;EACA;EACA,KAAK,SAAS,wCAAwC;;iBAGvC;EACf,OAAO;EACP;EACA;EACA,QAAQ,cAAc,SAAS,sCAAsC;;YAG3D;YAuBA,sBAAsB,UAAU,yBAAyB;EAC/D;EAAc;EAAe;IAAS;IAAkB;;EAAc;IACxE;EACI;EAAgB;EAAsB;EAAuB;IAC/D;EACI;IAAS;IAAkB;;IAC7B,SAAS;iBAEA;EACf;EACA;EACA,cAAc;EACd,QAAQ;EACR;;YAGU,uBAAuB,UAAU,yBAAyB;EAChE;WACF;EACI;EAAkB;EAAmB,aAAa;WACpD;EACI;EAAsB;WACxB;EACI;WACF;EACI,OAAO;EAAyB;IAAU;IAAgB;;WAC5D;EAEI,UAAU;EACV;EACA;EACA,QAAQ;EACR;;YAIJ,iBAAiB,UAAU,wBAAwB,yBAAyB,UAAU;EAE5F,OAAO;EACP,OAAO;EACP,OACE,OAAO,SAAS,sBAAsB,KACtC,SAAS,+BACR,uBAAuB,KAAK,QAAQ,uBAAuB;;;iBAKnD;EACf,OAAO;EACP;EACA,MAAM,SAAS,6CAA6C,iBAAiB,qBAAqB;;;iBAInF;WACN;WACA;WACA;WACA,OAAO;WACP;WACA;WACA;;iBAGM;WACN;WACA;WACA,uBAAuB;;;;;;;qBAQrB;iBAEI;WACN,SAAS;;EAElB,UAAU;EACV,gBAAgB,QAAQ,8BAA8B;EACtD,aAAa;EACb,mBAAmB,WAAW,WAAW,iCAAiC;;EAE1E,uBAAuB;EACvB,wBAAwB,aAAa,8BAA8B;EACnE,aAAa,oBAAoB,SAAS,MAAM,iBAAiB,eAAe;EAChF,iBAAiB,UAAU,uBAAuB;EAClD,gBAAgB,SAAS,sBAAsB;EAC/C,aAAa,MAAM,mBAAmB;EACtC,iBAAiB,UAAU,uBAAuB;;;YAIxC;IACR,sBAAsB;;;wBAIV,qBAAqB,SAAS,UAAU;wBAIxC,wBAAwB,SAAS,UAAU"}
|
|
@@ -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 { DoomSessionContext } from './hubChannel';\nimport type { DoomNotificationRequest } from './notification';\nimport type { DoomServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const DOOM_HEADLESS_HOST_SERVICE = 'doom/headless-host';\nexport const DOOM_HEADLESS_OWNER = Symbol.for('doom/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'DoomHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory facet-hook failure. */\nexport class DoomHeadlessPromptAdmissionError 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\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isDoomHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nexport interface DoomHeadlessSelection {\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 facets change exactly one axis per operation. */\nexport type DoomHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | { readonly axis: 'state'; readonly key: string; readonly values: readonly string[] };\n\nexport function readDoomHeadlessOwner(context: Context): DoomServerBundleEntry | undefined {\n return (context as Context & { [DOOM_HEADLESS_OWNER]?: DoomServerBundleEntry })[DOOM_HEADLESS_OWNER];\n}\n\nexport interface DoomHeadlessRegistration {\n dispose(): void;\n}\n\nexport type DoomHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface DoomHeadlessToolResult {\n content: DoomHeadlessContent[];\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\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 toDoomHeadlessToolResult(result: {\n readonly content: DoomHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly isError?: boolean;\n}): DoomHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\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 DoomHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n}\n\nexport interface DoomHeadlessClient {\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: DoomNotificationRequest): void | Promise<void>;\n request(request: DoomHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface DoomHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface DoomHeadlessSession {\n readModelSettings?(): Promise<DoomHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<DoomHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n appendCustomEntry(type: string, data: unknown): 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.\n */\n admitPrompt?(\n text: string,\n delivery?: 'prompt' | 'steer' | 'followUp' | 'interrupt',\n origin?: 'operator',\n ): Promise<void>;\n abort(): Promise<void>;\n compact(instructions?: string): Promise<void>;\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** Capture the current persisted branch for an in-process child fork. */\n forkSource?(): Promise<{ kind: 'v4-fork'; sessionFile: string; branch: string; entryId?: string }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface DoomMcpSkillAccess {\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 DoomHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n tools: readonly Pick<DoomHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface DoomHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\nexport interface DoomHeadlessExecutionContext {\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 /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: DoomSessionContext;\n /** Immutable session configuration. Facets must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: DoomHeadlessClient;\n readonly session: DoomHeadlessSession;\n readonly model?: { provider: string; id: string };\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\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 },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: DoomHeadlessToolCompletionRequest): Promise<DoomHeadlessToolCompletionResult>;\n };\n readonly selection: DoomHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: DoomMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface DoomHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain'; mode: string; label?: string };\n domain?: string;\n}\n\nexport interface DoomHeadlessToolRestriction {\n when?: DoomHeadlessCondition;\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 DoomHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: DoomHeadlessCondition;\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?: {\n resourceUri?: string;\n visibility?: ('model' | 'app')[];\n };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ): Promise<DoomHeadlessToolResult>;\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 DoomHeadlessResource {\n when?: DoomHeadlessCondition;\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 kind: 'prompt' | 'skill' | 'context';\n read(context: DoomHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface DoomHeadlessCommand {\n when?: DoomHeadlessCondition;\n name: string;\n description: string;\n execute(args: string, context: DoomHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type DoomHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\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 DoomHeadlessHookEvent<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { lane: string; runId: string; model: { provider: string; id: string }; payload: unknown }\n : E extends 'session_before_compact'\n ? { reason: string; preparation: unknown; instructions?: string; customInstructions?: string }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface DoomHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type DoomHeadlessHookResult<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? { cancel?: boolean; decline?: boolean; compaction?: DoomHeadlessCompactionResult } | 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 ? { args?: Record<string, unknown>; block?: { reason: string; terminate?: boolean } } | void\n : E extends 'tool_result'\n ? {\n content?: DoomHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type DoomHeadlessHook<E extends DoomHeadlessEventName = DoomHeadlessEventName> = E extends DoomHeadlessEventName\n ? {\n when?: DoomHeadlessCondition;\n event: E;\n handle(\n event: Readonly<DoomHeadlessHookEvent<E>>,\n context: DoomHeadlessExecutionContext,\n ): DoomHeadlessHookResult<E> | Promise<DoomHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained facet can register activity without starting disabled watchers or services. */\nexport interface DoomHeadlessActivity {\n when?: DoomHeadlessCondition;\n name: string;\n start(context: DoomHeadlessExecutionContext): (() => 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 DoomHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: DoomHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\nexport interface DoomHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly DoomHeadlessCapability[];\n}\n\n/** Registrations inherit package ownership from the caller's Cordis facet. */\n/**\n * The tool a server session loads skills through. When a session carries it, the prompt lists\n * every skill by name and points here, so a skill needs no file the agent could read.\n */\nexport const DOOM_LOAD_SKILL_TOOL = 'load_skill';\n\nexport interface DoomHeadlessHostService {\n readonly context: DoomHeadlessExecutionContext;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n changeSelection(change: DoomHeadlessSelectionChange): Promise<void>;\n assertActive(source?: string): void;\n subscribeSelection(listener: (selection: DoomHeadlessSelection) => void | Promise<void>): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): DoomHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: DoomHeadlessToolRestriction): DoomHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: DoomHeadlessTool<TParameters>): DoomHeadlessRegistration;\n registerResource(resource: DoomHeadlessResource): DoomHeadlessRegistration;\n registerCommand(command: DoomHeadlessCommand): DoomHeadlessRegistration;\n registerHook(hook: DoomHeadlessHook): DoomHeadlessRegistration;\n registerActivity(activity: DoomHeadlessActivity): DoomHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/headless-host': DoomHeadlessHostService;\n }\n}\n\nexport function readDoomHeadlessHost(context: Context): DoomHeadlessHostService | undefined {\n return context.get(DOOM_HEADLESS_HOST_SERVICE) as DoomHeadlessHostService | undefined;\n}\n\nexport function requireDoomHeadlessHost(context: Context): DoomHeadlessHostService {\n const host = readDoomHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Doom headless session host.');\n return host;\n}\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAC1C,MAAa,sBAAsB,OAAO,IAAI,qBAAqB;AAEnE,MAAM,yBAAyB;;AAG/B,IAAa,mCAAb,cAAsD,MAAM;CAC1D,YAAY,OAAgB;EAC1B,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC;EACvE,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAiBA,SAAgB,sBAAsB,SAAqD;CACzF,OAAQ,QAAwE;AAClF;;;;;AAsBA,SAAgB,yBAAyB,QAKd;CACzB,MAAM,EAAE,sBAAsB;CAC9B,OAAO;EACL,SAAS,OAAO;EAChB,SAAS,OAAO;EAChB,GAAI,OAAO,sBAAsB,YAAY,sBAAsB,QAAQ,CAAC,MAAM,QAAQ,iBAAiB,IACvG,EAAqB,kBAA6C,IAClE,CAAC;EACL,GAAI,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO,QAAQ;CACpE;AACF;;;;;;AA0SA,MAAa,uBAAuB;AAyBpC,SAAgB,qBAAqB,SAAuD;CAC1F,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,wBAAwB,SAA2C;CACjF,MAAM,OAAO,qBAAqB,OAAO;CACzC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,4DAA4D;CACvF,OAAO;AACT"}
|
|
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 { DoomSessionContext } from './hubChannel';\nimport type { DoomNotificationRequest } from './notification';\nimport type { DoomServerBundleEntry } from './serverBundle';\n\n/** Session-only contributions. This is not a Pi ExtensionAPI or a TUI adapter. */\nexport const DOOM_HEADLESS_HOST_SERVICE = 'doom/headless-host';\nexport const DOOM_HEADLESS_OWNER = Symbol.for('doom/headless-owner');\n\nconst PROMPT_ADMISSION_ERROR = 'DoomHeadlessPromptAdmissionError';\n\n/** Admission is a host boundary, not an advisory facet-hook failure. */\nexport class DoomHeadlessPromptAdmissionError 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\n/** Error identity must survive independently bundled server and extension graphs. */\nexport function isDoomHeadlessPromptAdmissionError(error: unknown): boolean {\n return error instanceof Error && error.name === PROMPT_ADMISSION_ERROR;\n}\nexport interface DoomHeadlessSelection {\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 facets change exactly one axis per operation. */\nexport type DoomHeadlessSelectionChange =\n | { readonly axis: 'majorMode'; readonly majorMode: string }\n | { readonly axis: 'domains'; readonly domains: readonly string[] }\n | { readonly axis: 'profile'; readonly profile?: string }\n | { readonly axis: 'state'; readonly key: string; readonly values: readonly string[] };\n\nexport function readDoomHeadlessOwner(context: Context): DoomServerBundleEntry | undefined {\n return (context as Context & { [DOOM_HEADLESS_OWNER]?: DoomServerBundleEntry })[DOOM_HEADLESS_OWNER];\n}\n\nexport interface DoomHeadlessRegistration {\n dispose(): void;\n}\n\nexport type DoomHeadlessContent = { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };\n\nexport interface DoomHeadlessToolResult {\n content: DoomHeadlessContent[];\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\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 toDoomHeadlessToolResult(result: {\n readonly content: DoomHeadlessContent[];\n readonly details?: unknown;\n readonly structuredContent?: unknown;\n readonly isError?: boolean;\n}): DoomHeadlessToolResult {\n const { structuredContent } = result;\n return {\n content: result.content,\n details: result.details,\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 DoomHeadlessClientRequest {\n kind: 'confirm' | 'select' | 'input';\n title: string;\n message?: string;\n options?: readonly { label: string; description?: string; value: string }[];\n initialValue?: string;\n multiline?: boolean;\n}\n\nexport interface DoomHeadlessClient {\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: DoomNotificationRequest): void | Promise<void>;\n request(request: DoomHeadlessClientRequest, signal?: AbortSignal): Promise<unknown>;\n setStatus(source: string, text: string | undefined): void;\n appendComposerText?(text: string): void;\n}\n\nexport interface DoomHeadlessModelSettings {\n model?: { provider: string; id: string };\n thinkingLevel: ThinkingLevel;\n}\n\nexport interface DoomHeadlessSession {\n readModelSettings?(): Promise<DoomHeadlessModelSettings>;\n setFastMode?(enabled: boolean): Promise<void>;\n setModelSettings?(settings: Partial<DoomHeadlessModelSettings>): Promise<void>;\n /** Query durable history on demand; hosts do not retain the entire transcript. */\n entries(query?: {\n type?: 'custom' | 'message';\n customType?: string;\n limit?: number;\n }): readonly Record<string, unknown>[] | Promise<readonly Record<string, unknown>[]>;\n appendCustomEntry(type: string, data: unknown): 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 abort(): Promise<void>;\n compact(instructions?: string): Promise<void>;\n activity(): Promise<{ hasPendingMessages: boolean; isIdle: boolean }>;\n /** Renames the durable session and publishes the updated title to presentation clients. */\n setName?(name: string): Promise<void>;\n /** Capture the current persisted branch for an in-process child fork. */\n forkSource?(): Promise<{ kind: 'v4-fork'; sessionFile: string; branch: string; entryId?: string }>;\n}\n\n/** A grant-filtered skill view available only during one remote MCP tool invocation. */\nexport interface DoomMcpSkillAccess {\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 DoomHeadlessToolCompletionRequest {\n systemPrompt: string;\n input: string;\n maxTokens: number;\n cacheRetention?: 'none' | 'short' | 'long';\n signal?: AbortSignal;\n tools: readonly Pick<DoomHeadlessTool, 'name' | 'description' | 'parameters'>[];\n}\n\nexport interface DoomHeadlessToolCompletionResult {\n toolCalls: readonly { id: string; name: string; arguments: unknown }[];\n usage: { totalTokens: number };\n}\n\nexport interface DoomHeadlessExecutionContext {\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 /** The session's baseline context, when its host knows its workspace. */\n readonly sessionContext?: DoomSessionContext;\n /** Immutable session configuration. Facets must not read or mutate process.env. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n readonly client: DoomHeadlessClient;\n readonly session: DoomHeadlessSession;\n readonly model?: { provider: string; id: string };\n /** Operation cancellation, supplied only for an active invocation. */\n readonly signal?: AbortSignal;\n readonly textCompletion?: {\n available(reference: string): boolean;\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 },\n ): Promise<string>;\n };\n readonly toolCompletion?: {\n complete(reference: string, request: DoomHeadlessToolCompletionRequest): Promise<DoomHeadlessToolCompletionResult>;\n };\n readonly selection: DoomHeadlessSelection;\n /** Present only while an authenticated remote MCP tool is running. */\n readonly mcpSkills?: DoomMcpSkillAccess;\n shutdown(): void;\n}\n\n/** Conditions narrow an eligible owner's contributions; they can never restore a disabled owner. */\nexport interface DoomHeadlessCondition {\n state?: Readonly<Record<string, string>>;\n attribution?: { kind: 'minor' | 'domain'; mode: string; label?: string };\n domain?: string;\n}\n\nexport interface DoomHeadlessToolRestriction {\n when?: DoomHeadlessCondition;\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 DoomHeadlessTool<TParameters extends TSchema = TSchema> {\n when?: DoomHeadlessCondition;\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?: {\n resourceUri?: string;\n visibility?: ('model' | 'app')[];\n };\n };\n promptSnippet?: string;\n promptGuidelines?: readonly string[];\n executionMode?: 'parallel' | 'serial';\n execute(\n toolCallId: string,\n parameters: Static<TParameters>,\n signal: AbortSignal | undefined,\n onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ): Promise<DoomHeadlessToolResult>;\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 DoomHeadlessResource {\n when?: DoomHeadlessCondition;\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 kind: 'prompt' | 'skill' | 'context';\n read(context: DoomHeadlessExecutionContext): string | Promise<string>;\n}\n\nexport interface DoomHeadlessCommand {\n when?: DoomHeadlessCondition;\n name: string;\n description: string;\n execute(args: string, context: DoomHeadlessExecutionContext): void | Promise<void>;\n}\n\nexport type DoomHeadlessEventName =\n | 'session_start'\n | 'session_shutdown'\n | 'session_tree'\n | 'before_agent_start'\n | 'agent_start'\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 DoomHeadlessHookEvent<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { lane: string; runId: string; model: { provider: string; id: string }; payload: unknown }\n : E extends 'session_before_compact'\n ? { reason: string; preparation: unknown; instructions?: string; customInstructions?: string }\n : E extends 'model_select'\n ? { model: { provider: string; id: string } }\n : Readonly<Record<string, unknown>>;\n\nexport interface DoomHeadlessCompactionResult {\n summary: string;\n tokensBefore: number;\n retainedTail: Record<string, unknown>[];\n usage?: Record<string, unknown>;\n details?: unknown;\n}\n\nexport type DoomHeadlessHookResult<E extends DoomHeadlessEventName> = E extends 'before_provider_request'\n ? { payload: unknown } | void\n : E extends 'session_before_compact'\n ? { cancel?: boolean; decline?: boolean; compaction?: DoomHeadlessCompactionResult } | 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 ? { args?: Record<string, unknown>; block?: { reason: string; terminate?: boolean } } | void\n : E extends 'tool_result'\n ? {\n content?: DoomHeadlessContent[];\n details?: unknown;\n isError?: boolean;\n usage?: Record<string, unknown>;\n terminate?: boolean;\n } | void\n : unknown;\n\nexport type DoomHeadlessHook<E extends DoomHeadlessEventName = DoomHeadlessEventName> = E extends DoomHeadlessEventName\n ? {\n when?: DoomHeadlessCondition;\n event: E;\n handle(\n event: Readonly<DoomHeadlessHookEvent<E>>,\n context: DoomHeadlessExecutionContext,\n ): DoomHeadlessHookResult<E> | Promise<DoomHeadlessHookResult<E>>;\n }\n : never;\n\n/** A retained facet can register activity without starting disabled watchers or services. */\nexport interface DoomHeadlessActivity {\n when?: DoomHeadlessCondition;\n name: string;\n start(context: DoomHeadlessExecutionContext): (() => 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 DoomHeadlessCapability {\n readonly source: string;\n readonly name: string;\n readonly kind: 'tool' | 'skill';\n readonly when?: DoomHeadlessCondition;\n readonly active: boolean;\n readonly discoverable: boolean;\n readonly reason?: 'inactive' | 'restricted' | 'shadowed' | 'unavailable' | 'not-discoverable';\n}\n\nexport interface DoomHeadlessCapabilitySnapshot {\n readonly revision: number;\n readonly ready: boolean;\n readonly capabilities: readonly DoomHeadlessCapability[];\n}\n\n/** Registrations inherit package ownership from the caller's Cordis facet. */\n/**\n * The tool a server session loads skills through. When a session carries it, the prompt lists\n * every skill by name and points here, so a skill needs no file the agent could read.\n */\nexport const DOOM_LOAD_SKILL_TOOL = 'load_skill';\n\nexport interface DoomHeadlessHostService {\n readonly context: DoomHeadlessExecutionContext;\n /** The instructions of an applied skill by exact name, or undefined when none is applied. */\n readSkill(name: string): string | undefined;\n changeSelection(change: DoomHeadlessSelectionChange): Promise<void>;\n assertActive(source?: string): void;\n subscribeSelection(listener: (selection: DoomHeadlessSelection) => void | Promise<void>): () => void;\n /** Inspect only a coherently applied generation. A transition returns ready=false and no partial inventory. */\n inspectCapabilities(): DoomHeadlessCapabilitySnapshot;\n registerToolRestriction(restriction: DoomHeadlessToolRestriction): DoomHeadlessRegistration;\n registerTool<TParameters extends TSchema>(tool: DoomHeadlessTool<TParameters>): DoomHeadlessRegistration;\n registerResource(resource: DoomHeadlessResource): DoomHeadlessRegistration;\n registerCommand(command: DoomHeadlessCommand): DoomHeadlessRegistration;\n registerHook(hook: DoomHeadlessHook): DoomHeadlessRegistration;\n registerActivity(activity: DoomHeadlessActivity): DoomHeadlessRegistration;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/headless-host': DoomHeadlessHostService;\n }\n}\n\nexport function readDoomHeadlessHost(context: Context): DoomHeadlessHostService | undefined {\n return context.get(DOOM_HEADLESS_HOST_SERVICE) as DoomHeadlessHostService | undefined;\n}\n\nexport function requireDoomHeadlessHost(context: Context): DoomHeadlessHostService {\n const host = readDoomHeadlessHost(context);\n if (!host) throw new Error('This contribution requires the Doom headless session host.');\n return host;\n}\n"],"mappings":";;AAUA,MAAa,6BAA6B;AAC1C,MAAa,sBAAsB,OAAO,IAAI,qBAAqB;AAEnE,MAAM,yBAAyB;;AAG/B,IAAa,mCAAb,cAAsD,MAAM;CAC1D,YAAY,OAAgB;EAC1B,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC;EACvE,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,mCAAmC,OAAyB;CAC1E,OAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAiBA,SAAgB,sBAAsB,SAAqD;CACzF,OAAQ,QAAwE;AAClF;;;;;AAsBA,SAAgB,yBAAyB,QAKd;CACzB,MAAM,EAAE,sBAAsB;CAC9B,OAAO;EACL,SAAS,OAAO;EAChB,SAAS,OAAO;EAChB,GAAI,OAAO,sBAAsB,YAAY,sBAAsB,QAAQ,CAAC,MAAM,QAAQ,iBAAiB,IACvG,EAAqB,kBAA6C,IAClE,CAAC;EACL,GAAI,OAAO,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,OAAO,QAAQ;CACpE;AACF;;;;;;AA2SA,MAAa,uBAAuB;AAyBpC,SAAgB,qBAAqB,SAAuD;CAC1F,OAAO,QAAQ,IAAI,0BAA0B;AAC/C;AAEA,SAAgB,wBAAwB,SAA2C;CACjF,MAAM,OAAO,qBAAqB,OAAO;CACzC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,4DAA4D;CACvF,OAAO;AACT"}
|
|
@@ -493,7 +493,8 @@ async function createDirectHarnessRuntime(options) {
|
|
|
493
493
|
}, context);
|
|
494
494
|
const storedFastMode = await harness.snapshot(FastModeDoc, context);
|
|
495
495
|
fastMode = storedFastMode?.enabled ?? options.initialFastMode ?? false;
|
|
496
|
-
const
|
|
496
|
+
const storedIdentity = await harness.snapshot(require_sqliteSessionStorage.SessionIdentityDoc, context);
|
|
497
|
+
const sessionId = storedIdentity?.id || options.sessionId || (0, node_crypto.randomUUID)();
|
|
497
498
|
await writable(() => harness.commit(async (tx) => {
|
|
498
499
|
const identity = await tx.doc(require_sqliteSessionStorage.SessionIdentityDoc);
|
|
499
500
|
if (!identity.id) {
|
|
@@ -515,7 +516,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
515
516
|
const metadata = await tx.doc(require_sqliteSessionStorage.SessionMetadataDoc);
|
|
516
517
|
metadata.workspaceRoot ||= options.cwd;
|
|
517
518
|
if (options.lane !== void 0) metadata.laneName = options.lane;
|
|
518
|
-
if (options.sessionName !== void 0) metadata.name = options.sessionName;
|
|
519
|
+
if (!storedIdentity?.id && options.sessionName !== void 0) metadata.name = options.sessionName;
|
|
519
520
|
}, context));
|
|
520
521
|
const laneName = options.lane ?? "main";
|
|
521
522
|
let resolveExited;
|
|
@@ -565,7 +566,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
565
566
|
return {
|
|
566
567
|
revision: record.revision,
|
|
567
568
|
paused: record.paused,
|
|
568
|
-
queue: record.queue.filter((item) => item.disposition !== "consumed" && item.disposition !== "removed").map(({ submissionId: _s, conversationId: _c, message: _m, operationId: _o, attempt: _a, ...item }) => item),
|
|
569
|
+
queue: record.queue.filter((item) => item.explicitQueue === true && item.disposition !== "consumed" && item.disposition !== "removed").map(({ explicitQueue: _q, submissionId: _s, conversationId: _c, message: _m, operationId: _o, attempt: _a, ...item }) => item),
|
|
569
570
|
operation: await execution()
|
|
570
571
|
};
|
|
571
572
|
};
|
|
@@ -1051,13 +1052,13 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1051
1052
|
}
|
|
1052
1053
|
});
|
|
1053
1054
|
};
|
|
1054
|
-
const handoff = async (item, mode, recovering = false) => {
|
|
1055
|
+
const handoff = async (item, mode, recovering = false, allowPaused = false) => {
|
|
1055
1056
|
if (handingOff.has(item.id)) return void 0;
|
|
1056
1057
|
handingOff.add(item.id);
|
|
1057
1058
|
try {
|
|
1058
1059
|
const claimed = await changeRecord((r) => {
|
|
1059
1060
|
const q = r.queue.find((q) => q.id === item.id);
|
|
1060
|
-
if (!q || r.paused && !recovering) return void 0;
|
|
1061
|
+
if (!q || r.paused && !recovering && !allowPaused) return void 0;
|
|
1061
1062
|
if (recovering ? q.disposition !== "handoff" || q.submissionId !== void 0 : q.disposition !== "pending") return void 0;
|
|
1062
1063
|
q.disposition = "handoff";
|
|
1063
1064
|
q.conversationId = conversation.id;
|
|
@@ -1118,7 +1119,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1118
1119
|
text: message
|
|
1119
1120
|
}, ...images] : message;
|
|
1120
1121
|
};
|
|
1121
|
-
const enqueue = async (message, images, delivery, scheduling) => {
|
|
1122
|
+
const enqueue = async (message, images, delivery, scheduling, explicitQueue = false) => {
|
|
1122
1123
|
const id = (0, node_crypto.randomUUID)();
|
|
1123
1124
|
await changeRecord((r) => {
|
|
1124
1125
|
r.queue.push({
|
|
@@ -1128,6 +1129,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1128
1129
|
...typeof message === "string" ? {} : { message },
|
|
1129
1130
|
delivery,
|
|
1130
1131
|
scheduling,
|
|
1132
|
+
explicitQueue,
|
|
1131
1133
|
disposition: "pending"
|
|
1132
1134
|
});
|
|
1133
1135
|
});
|
|
@@ -1151,17 +1153,9 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1151
1153
|
handledCommand: true
|
|
1152
1154
|
};
|
|
1153
1155
|
const record = await readRecord();
|
|
1154
|
-
if (record.paused) {
|
|
1155
|
-
if (record.queue.some((q) => q.disposition !== "consumed" && q.disposition !== "removed")) throw new Error("The queue is paused");
|
|
1156
|
-
await changeRecord((r) => {
|
|
1157
|
-
r.paused = false;
|
|
1158
|
-
delete r.abortOperationId;
|
|
1159
|
-
delete r.abortTaskId;
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
1156
|
await flushNextTurn();
|
|
1163
1157
|
const { id } = await enqueue(message, images, mode ?? "nextRun", "automatic");
|
|
1164
|
-
const submission = await handoff((await readRecord()).queue.find((q) => q.id === id), mode ?? "reject");
|
|
1158
|
+
const submission = await handoff((await readRecord()).queue.find((q) => q.id === id), mode ?? "reject", false, record.paused);
|
|
1165
1159
|
if (!submission) return { settled: Promise.resolve() };
|
|
1166
1160
|
let resolveDelivery;
|
|
1167
1161
|
const delivered = new Promise((resolve) => {
|
|
@@ -1220,7 +1214,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1220
1214
|
const doc = await tx.doc(LifecycleDoc);
|
|
1221
1215
|
const record = JSON.parse(doc.json);
|
|
1222
1216
|
const q = record.queue.find((q) => q.id === selection.id);
|
|
1223
|
-
if (!q) return "not_found";
|
|
1217
|
+
if (!q || q.explicitQueue !== true) return "not_found";
|
|
1224
1218
|
const requestId = `${q.id}:${q.attempt ?? 0}`;
|
|
1225
1219
|
const accepted = await tx.submissionByRequest(conversation.id, requestId);
|
|
1226
1220
|
if (accepted && accepted.type !== "input") throw new Error(`Request ${requestId} already identifies a submission of type ${accepted.type}`);
|
|
@@ -1385,7 +1379,7 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1385
1379
|
if (selection) {
|
|
1386
1380
|
const outcome = await changeRecord((r) => {
|
|
1387
1381
|
const q = r.queue.find((q) => q.id === selection.id);
|
|
1388
|
-
if (!q || q.disposition === "removed" || q.disposition === "consumed") return "not_found";
|
|
1382
|
+
if (!q || q.explicitQueue !== true || q.disposition === "removed" || q.disposition === "consumed") return "not_found";
|
|
1389
1383
|
if (q.disposition !== "pending") return "in_flight";
|
|
1390
1384
|
if (current?.id !== selection.operationId || current?.status === "aborting") return "target_changed";
|
|
1391
1385
|
if (q.message && q.message.role !== "user") throw new Error("Only user input can interrupt and respond");
|
|
@@ -1602,6 +1596,31 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1602
1596
|
}, context));
|
|
1603
1597
|
return entryId;
|
|
1604
1598
|
};
|
|
1599
|
+
const removeQueued = async (id) => {
|
|
1600
|
+
const item = (await readRecord()).queue.find((q) => q.id === id);
|
|
1601
|
+
if (!item || item.explicitQueue !== true) return "not_found";
|
|
1602
|
+
if (item.disposition === "consumed") return "already_consumed";
|
|
1603
|
+
if (item.disposition === "removed") return "removed";
|
|
1604
|
+
if (item.submissionId) {
|
|
1605
|
+
const result = await harness.abortSubmission(item.submissionId, context, conversation.id);
|
|
1606
|
+
if (result === "already_placed") return "in_flight";
|
|
1607
|
+
if (result === "settled") return "already_consumed";
|
|
1608
|
+
} else if (item.disposition !== "pending") return "in_flight";
|
|
1609
|
+
const result = await changeRecord((r) => {
|
|
1610
|
+
const q = r.queue.find((q) => q.id === id);
|
|
1611
|
+
if (!q || q.explicitQueue !== true) return "not_found";
|
|
1612
|
+
if (q.disposition === "consumed") return "already_consumed";
|
|
1613
|
+
if (q.disposition === "removed") return "removed";
|
|
1614
|
+
if (q.submissionId !== item.submissionId || item.submissionId === void 0 && q.disposition !== "pending") return "in_flight";
|
|
1615
|
+
q.disposition = "removed";
|
|
1616
|
+
q.text = "";
|
|
1617
|
+
delete q.message;
|
|
1618
|
+
delete q.images;
|
|
1619
|
+
return "removed";
|
|
1620
|
+
});
|
|
1621
|
+
await publish();
|
|
1622
|
+
return result;
|
|
1623
|
+
};
|
|
1605
1624
|
return {
|
|
1606
1625
|
sessionId,
|
|
1607
1626
|
sessionFile: storage.sessionFile,
|
|
@@ -1641,7 +1660,8 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1641
1660
|
const metadata = await harness.snapshot(require_sqliteSessionStorage.SessionMetadataDoc, context);
|
|
1642
1661
|
const stats = await getSessionStats();
|
|
1643
1662
|
const inbox = await harness.snapshot(_earendil_works_pi_durable.InboxDoc, conversation.id, context);
|
|
1644
|
-
const
|
|
1663
|
+
const retained = (await readRecord()).queue;
|
|
1664
|
+
const retainedSubmissions = new Set(retained.map((item) => item.submissionId));
|
|
1645
1665
|
const nativePending = inbox?.items.filter((item) => item.mode !== "write" && !retainedSubmissions.has(item.id)).length ?? 0;
|
|
1646
1666
|
return json({
|
|
1647
1667
|
sessionId,
|
|
@@ -1663,42 +1683,18 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1663
1683
|
followUpMode: settings.followUpMode ?? "one-at-a-time",
|
|
1664
1684
|
autoCompactionEnabled: settings.compaction?.enabled ?? true,
|
|
1665
1685
|
messageCount: stats.messageCount,
|
|
1666
|
-
pendingMessageCount:
|
|
1686
|
+
pendingMessageCount: retained.filter((item) => item.disposition !== "consumed" && item.disposition !== "removed").length + nativePending + nextTurnMessages.length + deferredInternalCount
|
|
1667
1687
|
});
|
|
1668
1688
|
},
|
|
1669
1689
|
enqueueAutomatic: async (value, images) => {
|
|
1670
|
-
const result = await enqueue(value, images, "nextRun", "automatic");
|
|
1690
|
+
const result = await enqueue(value, images, "nextRun", "automatic", true);
|
|
1671
1691
|
drain().catch((error) => emit({
|
|
1672
1692
|
type: "error",
|
|
1673
1693
|
error: String(error)
|
|
1674
1694
|
}));
|
|
1675
1695
|
return result;
|
|
1676
1696
|
},
|
|
1677
|
-
|
|
1678
|
-
const item = (await readRecord()).queue.find((q) => q.id === id);
|
|
1679
|
-
if (!item) return "not_found";
|
|
1680
|
-
if (item.disposition === "consumed") return "already_consumed";
|
|
1681
|
-
if (item.disposition === "removed") return "removed";
|
|
1682
|
-
if (item.submissionId) {
|
|
1683
|
-
const result = await harness.abortSubmission(item.submissionId, context, conversation.id);
|
|
1684
|
-
if (result === "already_placed") return "in_flight";
|
|
1685
|
-
if (result === "settled") return "already_consumed";
|
|
1686
|
-
} else if (item.disposition !== "pending") return "in_flight";
|
|
1687
|
-
const result = await changeRecord((r) => {
|
|
1688
|
-
const q = r.queue.find((q) => q.id === id);
|
|
1689
|
-
if (!q) return "not_found";
|
|
1690
|
-
if (q.disposition === "consumed") return "already_consumed";
|
|
1691
|
-
if (q.disposition === "removed") return "removed";
|
|
1692
|
-
if (q.submissionId !== item.submissionId || item.submissionId === void 0 && q.disposition !== "pending") return "in_flight";
|
|
1693
|
-
q.disposition = "removed";
|
|
1694
|
-
q.text = "";
|
|
1695
|
-
delete q.message;
|
|
1696
|
-
delete q.images;
|
|
1697
|
-
return "removed";
|
|
1698
|
-
});
|
|
1699
|
-
await publish();
|
|
1700
|
-
return result;
|
|
1701
|
-
},
|
|
1697
|
+
removeQueued,
|
|
1702
1698
|
async promoteQueued(id, operationId) {
|
|
1703
1699
|
return (await submitUserPrompt("", void 0, {
|
|
1704
1700
|
id,
|
|
@@ -1921,19 +1917,23 @@ async function createDirectHarnessRuntime(options) {
|
|
|
1921
1917
|
}
|
|
1922
1918
|
}),
|
|
1923
1919
|
async clearQueue() {
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
r.queue = [];
|
|
1927
|
-
});
|
|
1920
|
+
const selected = (await readRecord()).queue.filter((item) => item.explicitQueue === true && item.disposition !== "consumed" && item.disposition !== "removed");
|
|
1921
|
+
for (const item of selected) await removeQueued(item.id);
|
|
1928
1922
|
await publish();
|
|
1929
1923
|
return {
|
|
1930
1924
|
steering: [],
|
|
1931
1925
|
followUp: []
|
|
1932
1926
|
};
|
|
1933
1927
|
},
|
|
1934
|
-
setName
|
|
1935
|
-
|
|
1936
|
-
|
|
1928
|
+
async setName(name) {
|
|
1929
|
+
await writable(() => harness.commit(async (tx) => {
|
|
1930
|
+
(await tx.doc(require_sqliteSessionStorage.SessionMetadataDoc)).name = name;
|
|
1931
|
+
}, context));
|
|
1932
|
+
emit({
|
|
1933
|
+
type: "session_info_changed",
|
|
1934
|
+
name
|
|
1935
|
+
});
|
|
1936
|
+
},
|
|
1937
1937
|
getSessionStats,
|
|
1938
1938
|
async replaceTools(replacement) {
|
|
1939
1939
|
tools = replacement;
|