@agimon-ai/doompi-workflow 0.0.1-alpha.93 → 0.0.1-alpha.94
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":"pi.cjs","names":["WORKFLOW_RUN_TOOL_NAME","resolveRootSessionId","readChildProcessContext","SUBAGENT_PARENT_SESSION_ENV","AsyncLocalStorage","z","resolveRootSessionId","createEmbeddedWorkflowFeature","z","resolve","WORKFLOW_RUN_TOOL_NAME","resolveRootSessionId","asRecord","detailLines","DoomToolResult","DoomToolCall","renderToolHeading","resolve","COMPLETED_STAGE","ERROR_STAGE","truncateToWidth","visibleWidth","ELLIPSIS","DOOM_FULLSCREEN_UI_OPTIONS","visibleWidth","truncateToWidth","ELLIPSIS","HARD_RESET","fit","truncateToWidth","visibleWidth","rightAligned","DOOM_FULLSCREEN_UI_OPTIONS","TITLE","BREADCRUMB","DEFAULT_PAGE_SIZE","META_INDENT","EMPTY_NAME","KEY_CLEAR","FILTER_LABEL","FOOTER","FOOTER_HINTS","visibleWidth","wrapTextWithAnsi","truncateToWidth","matchesKey","Key","fit","rightAligned","WORKFLOW_FINISHED_MESSAGE","COMPLETED_STAGE","HELD_STAGES","statusIcon","runLine","renderWorkflowFinished","isWorkflowFinishedRuns","createWorkflowFinishedRenderer","Text","DOOM_FULLSCREEN_UI_OPTIONS","TITLE","OUTPUT_HEADING","truncateToWidth","visibleWidth","currentWorkflowPosition","matchesKey","isKeyRelease","matchesKey","DOOM_FULLSCREEN_UI_OPTIONS","KEY_CLEAR","DIM","ACCENT","SELECTED_BG","ROW_BG","matchesKey","fit","truncateToWidth","DOOM_FULLSCREEN_UI_OPTIONS","matchesKey","fit","rightAligned","matchesKey","fit","DOOM_FULLSCREEN_UI_OPTIONS","isWorkflowStepMessageDetails","WorkflowStepMessageLines","truncateToWidth","renderWorkflowStepMessage","Box","Text","LEGACY_WORKFLOW_STEP_MESSAGE","truncateToWidth","visibleWidth","SUBAGENT_ROOT_SESSION_ENV","basename","extname","createRequire","spawn","createEmbeddedWorkflowFeature","randomUUID","readDoomReadinessCoordinator","createDoomReadinessCoordinator","registerRunProvider","defineMinorMode","createDoomTelemetry","createNarrationRequest","DOOM_NARRATION_SERVICE","requireDoomNarrationService","resolveRootSessionId","readWorkflowProgress","summarizeWorkflowProgress","WORKFLOW_FINISHED_MESSAGE","WorkflowTerminalService","createWorkflowTerminalService","resolve","readFile","parseWorkflowLaunchCommand","isLaunchParseFailure","resolveWorkflowEntry","validateWorkflowLaunch","workflowSkillDirectory","existsSync","createWorkflowFinishedRenderer","isWorkflowStepMessageDetails","renderWorkflowStepMessage","DOOM_UI_HUB_SERVICE","requireDoomUiHub","piMinorModes","DOOM_SKILL_SOURCES_SERVICE","workflowSkillDirectory","requireDoomSkillSourcesService","DOOM_UI_HUB_SERVICE","requireDoomUiHub","definePiTool","defineRoot","runtime","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","Text","defineMessageRenderer","truncateToWidth","Box","Text","defineMessageRenderer","definePiExtension","rootSession","composeRootHooks","commandWorkflowLaunch","hookResourcesDiscover","hookSessionStart","messageWorkflowFinished","messageWorkflowStep","resourceWorkflowSkills","shortcutWorkflowPanel","shortcutWorkflowViewClose","toolRestrictionWorkflow","piToolContributions","toolWorkflow"],"sources":["../../src/constants/workflow.ts","../../src/services/workflowFence/index.ts","../../src/schemas/workflowPi.ts","../../src/services/piToolBridge/index.ts","../../src/services/workflowExecution/index.ts","../../src/services/workflowTools/index.ts","../../src/tui/leader.ts","../../src/tui/workflow/workflowToolRender.ts","../../src/services/workflowLauncher/index.ts","../../src/services/workflowNarration/index.ts","../../src/tui/workflow/rendering.ts","../../src/tui/workflow/doomOverlay.ts","../../src/tui/workflow/overlayText.ts","../../src/tui/workflow/workflowCatalog.ts","../../src/tui/workflow/workflowFinishedMessage.ts","../../src/tui/workflow/workflowStatusRow.ts","../../src/tui/workflow/workflowInspector.ts","../../src/tui/workflow/workflowOverlay.ts","../../src/tui/workflow/workflowPicker.ts","../../src/tui/workflow/workflowProgressOverlay.ts","../../src/tui/workflow/workflowPrompt.ts","../../src/tui/workflow/workflowRunPanel.ts","../../src/tui/workflow/workflowStepMessage.ts","../../src/tui/workflowRuntime.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/index.cli.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.ts","../../src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.ts","../../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.ts","../../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.ts","../../src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.ts","../../src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.ts","../../generated/pi.ts"],"sourcesContent":["export const COMMAND_DESCRIPTION = 'Doom Pi workflow execution and monitoring integration';\nexport const PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\n\nexport const LEADER_KEY = 'w';\nexport const LEADER_LABEL = 'workflows';\nexport const LEADER_ORDER = 50;\nexport const LEADER_ENABLE_ACTION = 'workflow.enable';\nexport const LEADER_DISABLE_ACTION = 'workflow.disable';\nexport const LEADER_MANAGE_ACTION = 'workflow.manage';\nexport const LEADER_RECOVER_ACTION = 'workflow.recover';\nexport const LEADER_CATALOG_ACTION = 'workflow.catalog';\nexport const LEADER_DETAIL = 'multi-step agent runs';\n\nexport const LIST_WORKFLOWS_TOOL_NAME = 'list_workflows';\nexport const LAUNCH_WORKFLOW_TOOL_NAME = 'launch_workflow';\nexport const WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\nexport const WORKFLOW_PI_TOOL_NAMES = [\n LIST_WORKFLOWS_TOOL_NAME,\n LAUNCH_WORKFLOW_TOOL_NAME,\n WORKFLOW_RUN_TOOL_NAME,\n] as const;\n","import { AsyncLocalStorage } from 'node:async_hooks';\n\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-core/childProcess';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\nimport type { ExtensionAPI, ExtensionContext, ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\nconst WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\n\ntype ToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\nexport interface WorkflowFence {\n tool<TSchema extends ToolSchema, TDetails>(\n tool: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails>;\n command(name: string, options: CommandOptions): readonly [string, CommandOptions];\n shortcut(\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): readonly [Parameters<ExtensionAPI['registerShortcut']>[0], ShortcutOptions];\n events(handlers: PiEventHandlers): PiEventHandlers;\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/**\n * A dispatcher child launches workflows for its root session and never runs one\n * itself, so `workflow_run` stays off its surface even if something registers it.\n */\nexport function dispatcherToolRestriction(): DoomToolRestriction {\n return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function dispatcherTools<TSchema extends ToolSchema, TDetails>(\n tools: readonly ToolDefinition<TSchema, TDetails>[],\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>>,\n): ToolDefinition<TSchema, TDetails>[] {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return tools\n .filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name))\n .map((tool) => {\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;\n return {\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n };\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nexport function createWorkflowFence(host: ExtensionAPI, signal?: AbortSignal): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const tool = <TSchema extends ToolSchema, TDetails>(\n definition: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails> => {\n return {\n ...definition,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n return result;\n },\n };\n };\n\n const command: WorkflowFence['command'] = (name, options) => {\n return [\n name,\n {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const shortcut: WorkflowFence['shortcut'] = (key, options) => {\n return [\n key,\n {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const events = (handlers: PiEventHandlers): PiEventHandlers =>\n Object.fromEntries(\n Object.entries(handlers).map(([eventName, handler]) => [\n eventName,\n (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () =>\n (handler as LifecycleHandler)(event, guardContext(context, eventGeneration)),\n );\n },\n ]),\n ) as PiEventHandlers;\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n tool,\n command,\n shortcut,\n events,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n","import { z } from 'zod';\n\nconst RUN_SELECTOR_FIELDS = {\n runKey: z.string().min(1).describe('Run key of the workflow run.'),\n workspace: z.string().optional().describe('Workspace the run belongs to.'),\n} as const;\n\nexport const workflowRunInputSchema = z.discriminatedUnion('action', [\n z.object({ action: z.literal('status'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('tail'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('recovery-evidence'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('follow'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('open'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('pause'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z.object({ action: z.literal('resume'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z.object({ action: z.literal('stop'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z\n .object({\n action: z.literal('recover'),\n ...RUN_SELECTOR_FIELDS,\n dryRun: z.boolean().optional(),\n job: z.string().optional(),\n runner: z.string().optional(),\n })\n .strict(),\n]);\n\nexport type WorkflowRunInput = z.infer<typeof workflowRunInputSchema>;\n\nexport const dispatchInputSchema = z\n .object({\n description: z.string().optional().describe('Description shown for the workflow input.'),\n required: z.boolean().optional().describe('Whether the workflow input must be provided.'),\n default: z.string().optional().describe('Default value for the workflow input.'),\n type: z.string().optional().describe('Declared workflow input type.'),\n options: z.array(z.string()).optional().describe('Allowed values for the workflow input.'),\n })\n .passthrough();\n\nexport type DispatchInput = z.infer<typeof dispatchInputSchema>;\n\nexport const workflowDispatchInputsSchema = z\n .object({\n inputs: z.record(z.string(), dispatchInputSchema).optional().describe('Workflow dispatch input definitions.'),\n })\n .passthrough();\n\nexport const workflowCatalogPageSchema = z\n .object({\n directory: z.string().min(1).describe('Directory searched for workflow definitions.'),\n hasNextPage: z.boolean().describe('Whether another catalog page exists.'),\n page: z.number().int().positive().describe('One-based catalog page number.'),\n pageSize: z.number().int().positive().describe('Catalog page size.'),\n workflows: z\n .array(\n z\n .object({\n path: z.string().min(1).describe('Workflow path relative to the catalog directory.'),\n name: z.string().describe('Workflow display name.'),\n description: z.string().describe('Workflow description.'),\n tags: z.array(z.string()).describe('Workflow tags.'),\n })\n .passthrough(),\n )\n .describe('Workflow definitions on this page.'),\n })\n .passthrough();\n","/**\n * Pure bridging logic between MCP tool results and the Pi tool surface.\n *\n * DESIGN PATTERNS:\n * - Adapter pattern: MCP `CallToolResult` is converted to Pi's result shape\n * - Pure module: no service or tool-class imports, so this is unit-testable\n * without constructing the workflow execution stack\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported functions\n *\n * AVOID:\n * - Importing tool classes or services here (that belongs in `piTools.ts`)\n * - Returning an error flag Pi does not read; Pi tools signal failure by throwing\n */\n\nimport type { WorkflowProgressJob, WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { AgentToolResult } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Environment variable stamped onto every run launched from a Pi session.\n *\n * `RunWorkflowService` forwards `env` to the inner CLI invocation across the\n * `launch-command` delegation boundary and persists it on the run record, so\n * this survives backgrounding and identifies the launching session afterwards.\n */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\n/** Operator override for the per-session launch ceiling. */\nconst MAX_CONCURRENT_ENV = 'WORKFLOW_MCP_MAX_CONCURRENT';\nconst DEFAULT_MAX_CONCURRENT = 5;\n\nexport interface WorkflowToolDetails {\n tool: string;\n}\n\n/** Resolve the per-session launch ceiling from the environment. */\nexport function resolveMaxConcurrent(env: NodeJS.ProcessEnv = process.env): number {\n const parsed = Number(env[MAX_CONCURRENT_ENV]);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT;\n}\n\n/**\n * True when this session launched the run.\n *\n * Fails closed on a missing session id: an unstamped record (a CLI launch) and\n * a call arriving before the session id is known both match nothing, so no run\n * ever leaks across sessions through an undefined-equals-undefined comparison.\n */\nexport function isSessionRun(record: WorkflowRunRecord, sessionId: string | undefined): boolean {\n return sessionId !== undefined && record.env?.[PI_SESSION_ENV] === sessionId;\n}\n\n/** Runs launched by one Pi session that are still running. */\nexport function runsForSession(records: WorkflowRunRecord[], sessionId: string): WorkflowRunRecord[] {\n return records.filter((record) => isSessionRun(record, sessionId) && record.stage === 'running');\n}\n\n/**\n * What the caller is told when the registry, not the launcher, acknowledged a\n * launch.\n *\n * Leads with the run key because it is the handle every other workflow action\n * takes, and it is no longer available any other way: the launcher's own output\n * is not waited for, so nothing else in this result carries it.\n */\nexport function launchedRunSummary(record: WorkflowRunRecord): string {\n return [\n `Started ${record.displayName} in workspace ${record.workspace}.`,\n `Run key: ${record.runKey}`,\n 'The run is registered and going. This call returned at that point rather than waiting for the launcher process to exit.',\n ].join('\\n');\n}\n\n/**\n * What the caller is told when the launch was handed off but no run has\n * registered inside the acknowledgement budget.\n *\n * Deliberately not an error: the launcher is slow rather than broken often\n * enough that failing here would strand runs that go on to start normally.\n * There is no run key to offer yet, so it points at the surfaces that do not\n * need one.\n */\nexport function launchHandoffSummary(workflowPath: string): string {\n return [\n `Launch handed off for ${workflowPath}, but no run has registered yet.`,\n 'Nothing was cancelled: the launcher is still starting, and a run that registers later still reports back here when it finishes.',\n 'Do not launch it again. Ask the user to check the active workflow list if they need to see it sooner.',\n ].join('\\n');\n}\n\n/**\n * Escape sequences a terminal consumes rather than prints.\n *\n * Built from a string with the rule silenced, the way `doom-runner`'s own\n * scrubber does it, because matching the escape byte is the entire job. Not\n * imported from there: that package's published build is a stale artifact\n * missing the export, and a launch notice should not need another package's\n * build to be current.\n */\n// oxlint-disable-next-line no-control-regex -- matching terminal control bytes is the point\nconst ESCAPE_SEQUENCE = new RegExp(\n ['\\\\u001B\\\\[[0-9;?]*[ -/]*[@-~]', '\\\\u001B\\\\][^\\\\u0007\\\\u001B]*(?:\\\\u0007|\\\\u001B\\\\\\\\)', '\\\\u001B[@-Z\\\\\\\\-_]'].join(\n '|',\n ),\n 'g',\n);\n\n/** Rows made only of box-drawing: separators that carry nothing once trimmed. */\nconst RULE_ROW = /^[\\s─-╿]*$/u;\nconst NOTICE_LINE_LIMIT = 3;\n/**\n * Widest a notice row may be before it is clipped.\n *\n * A three-line cap does not bound a toast on its own: the engine announces its\n * delegation by echoing the whole shell command, temp script path included, and\n * one line of that wraps across three rows of a narrow terminal and shoves the\n * transcript around. Clipped at a width every terminal can hold instead.\n */\nconst NOTICE_WIDTH_LIMIT = 100;\n\n/**\n * Cut a tool result down to something a toast can hold.\n *\n * The launch result used to reach `ui.notify` whole, and for a workflow that\n * executes in this process that result is the engine's entire console log:\n * banner, run directory, job tree, rules, colour. Pi rendered every line of it\n * over the transcript, which reads as a broken screen rather than as output.\n * Escape sequences go first: the log carries colour the notification would\n * render as literal text, and a stray clear or cursor-move would do to the\n * screen exactly what this function exists to prevent.\n */\nexport function launchNotice(text: string, limit: number = NOTICE_LINE_LIMIT): string {\n const lines = text\n .replace(ESCAPE_SEQUENCE, '')\n .split('\\n')\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0 && !RULE_ROW.test(line))\n .map((line) => (line.length > NOTICE_WIDTH_LIMIT ? `${line.slice(0, NOTICE_WIDTH_LIMIT - 1)}…` : line));\n if (lines.length === 0) return 'Workflow started.';\n if (lines.length <= limit) return lines.join('\\n');\n return [...lines.slice(0, limit), `… ${lines.length - limit} more lines, in the run's own output.`].join('\\n');\n}\n\n/** Flatten MCP tool content to text for Pi. */\nexport function toolResultText(result: CallToolResult): string {\n return result.content\n .map((part) => (part.type === 'text' ? part.text : ''))\n .filter(Boolean)\n .join('\\n')\n .trim();\n}\n\n/**\n * Convert an MCP tool result into a Pi tool result.\n *\n * Pi signals tool failure by throwing: the agent loop catches it and builds the\n * error result. So an `isError` MCP result becomes a thrown error rather than a\n * successful result carrying a flag Pi would ignore.\n */\nexport function toAgentToolResult(\n tool: string,\n result: CallToolResult,\n errorOptions: string[] = [],\n): AgentToolResult<WorkflowToolDetails> {\n const text = toolResultText(result) || 'No output.';\n if (result.isError) throw new Error(withOptions(text, errorOptions));\n return { content: [{ type: 'text', text }], details: { tool } };\n}\n\n/**\n * Attach a short menu of next steps to a problem.\n *\n * An error with no route forward is where an agent invents one: retrying a\n * capacity limit, relaunching a run that should be recovered, or silently\n * giving up on work the user is waiting for. Naming two or three real options\n * turns an error into a decision, and the decision belongs to the user.\n */\nexport function withOptions(problem: string, options: string[]): string {\n if (options.length === 0) return problem;\n return [problem, '', 'Options, put these to the user rather than picking one yourself:', ...options.map(bullet)].join(\n '\\n',\n );\n}\n\nfunction bullet(option: string): string {\n return `- ${option}`;\n}\n\n/** The job and step a run died on, preferring the progress log to the record. */\nfunction failurePosition(\n record: WorkflowRunRecord,\n jobs: WorkflowProgressJob[],\n): { job?: string; step?: string; reason?: string } {\n // The progress log knows which step was in flight; the record only names the\n // job. Falling back keeps this working for runs that predate the log.\n const failedJob = jobs.find((job) => job.status === 'failed');\n const failedStep = failedJob?.steps.find((step) => step.status === 'failed');\n return {\n job: failedJob?.name ?? record.failedJob,\n step: failedStep?.name,\n reason: failedStep?.reason ?? failedJob?.reason,\n };\n}\n\n/**\n * Describe a finished run for the agent that launched it.\n *\n * Carries the job identifiers back so a dispatching agent can match the run to\n * the work item it launched it for without another lookup. When the run failed,\n * carries the failing step and a set of options too: the agent is being told\n * about this out of band, with no user question in flight, so without them it\n * has to guess whether to recover, relaunch, or report.\n */\nexport function finishedRunSummary(record: WorkflowRunRecord, jobs: WorkflowProgressJob[] = []): string {\n const outcome = record.stage === 'completed' ? 'completed' : `ended in ${record.stage}`;\n const failure = failurePosition(record, jobs);\n const lines: Array<string | undefined> = [\n `Workflow run ${record.runKey} in workspace ${record.workspace} ${outcome}.`,\n record.workflowId ? `Workflow: ${record.workflowId}` : undefined,\n failure.job ? `Failed job: ${failure.job}${failure.step ? ` (step: ${failure.step})` : ''}` : undefined,\n record.errorMessage ? `Error: ${record.errorMessage}` : undefined,\n failure.reason && failure.reason !== record.errorMessage ? `Step reported: ${failure.reason}` : undefined,\n ];\n const jobId = record.env?.AGIFLOW_JOB_ID;\n if (jobId) lines.push(`Agiflow job: ${record.env?.AGIFLOW_JOB_KIND ?? 'unknown'} ${jobId}`);\n\n const summary = lines.filter((line): line is string => Boolean(line)).join('\\n');\n if (record.stage === 'completed') return summary;\n\n // A run the user stopped is not a defect, so it gets no diagnosis step: the\n // question is only whether to pick it back up.\n const stopped = record.outcome === 'interrupted';\n if (stopped) {\n return withOptions(summary, [\n `workflow_run {\"action\":\"recover\",\"runKey\":${JSON.stringify(record.runKey)}}: pick it up where it stopped.`,\n 'Leave it stopped and move on.',\n ]);\n }\n\n const diagnosticText = [record.errorMessage, failure.reason].filter(Boolean).join('\\n');\n if (diagnosticText.includes('JOB_ALREADY_CLAIMED')) {\n return withOptions(summary, [\n 'Report contention: another worker owns this job. Do not unlock, release, or retry the claim automatically.',\n ]);\n }\n if (diagnosticText.includes('WORKFLOW_NOT_OWNED') || /release failed/i.test(diagnosticText)) {\n return withOptions(summary, [\n 'Inspect the current workflow ownership and ask the user before any release or unlock. Never force another worker’s lock.',\n ]);\n }\n if (/running workflow not found/i.test(diagnosticText)) {\n return withOptions(summary, [\n `workflow_run {\"action\":\"status\",\"runKey\":${JSON.stringify(record.runKey)}}: re-check current state before retrying.`,\n 'Report the recorded terminal state when no running owner remains.',\n ]);\n }\n\n return withOptions(summary, [\n `workflow_run {\"action\":\"tail\",\"runKey\":${JSON.stringify(record.runKey)}}: read the run's own output first, when the error above does not explain the failure.`,\n `workflow_run {\"action\":\"recover\",\"runKey\":${JSON.stringify(record.runKey)}}: resume from the failed job, keeping the work already done. Fits a transient or external cause.`,\n 'Report the failure and stop, when it needs a code change or a decision you cannot make.',\n ]);\n}\n","import { resolveRootSessionId } from '@agimon-ai/doompi-core/childProcess';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\nimport { type EmbeddedWorkflowFeature, type WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\n\nimport { type WorkflowRunInput } from '../../schemas/workflowPi';\nimport {\n launchedRunSummary,\n launchHandoffSummary,\n PI_SESSION_ENV,\n resolveMaxConcurrent,\n toolResultText,\n withOptions,\n} from '../piToolBridge';\n\nconst AGIFLOW_JOB_ID_ENV = 'AGIFLOW_JOB_ID';\nconst AGIFLOW_JOB_KIND_ENV = 'AGIFLOW_JOB_KIND';\nconst AGIFLOW_PROJECT_ID_ENV = 'AGIFLOW_PROJECT_ID';\n\nimport { WORKFLOW_PI_TOOL_NAMES, LAUNCH_WORKFLOW_TOOL_NAME } from '../../constants/workflow';\n\n/**\n * What workflow mode does to the tool surface: nothing but hide its own tools.\n *\n * The tools are registered for the whole session because Pi has no other way to\n * add one later, so the mode is expressed as a restriction rather than as a\n * registration.\n */\nexport function workflowToolRestriction(enabled: boolean): DoomToolRestriction {\n const hidden = new Set<string>(WORKFLOW_PI_TOOL_NAMES);\n return (incoming) => (enabled ? incoming : incoming.filter((name) => !hidden.has(name)));\n}\n\nexport type WorkflowRunSelector = Pick<WorkflowRunInput, 'runKey' | 'workspace'>;\n\nexport type WorkflowLaunchInput = z.infer<ReturnType<EmbeddedWorkflowFeature['runTool']['getInputSchema']>>;\n\n/**\n * Where a launch was answered from, which decides what the caller is told.\n *\n * Tagged rather than inferred from an absent field: the failure carries an\n * `unknown`, and `unknown` includes `undefined`, so only a tag can tell a\n * rejection apart from a result.\n */\ntype LaunchOutcome = { kind: 'value'; result: CallToolResult } | { kind: 'error'; error: unknown };\ntype LaunchAck =\n | { kind: 'settled'; outcome: LaunchOutcome }\n | { kind: 'record'; record: WorkflowRunRecord }\n | { kind: 'handoff' };\n\n/** How often the registry is asked whether the launch has produced a run. */\nconst LAUNCH_ACK_POLL_MS = 500;\n/**\n * How long to wait for that before answering without a run key.\n *\n * Long enough to cover a launcher that is merely slow, short enough that a\n * caller is never left holding a turn open for a launcher that will not answer.\n */\nconst LAUNCH_ACK_TIMEOUT_MS = 15_000;\n\nexport interface LaunchedRunQuery {\n sessionId: string | undefined;\n /** Epoch milliseconds the launch began, so an earlier run cannot match. */\n since: number;\n workflowPath: string;\n}\n\nexport interface WorkflowLaunchExecutorDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n activeRunCount?: () => Promise<number>;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n observeSession?: (sessionId: string | undefined) => void;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n runTool: EmbeddedWorkflowFeature['runTool'];\n trackPendingRun: <T>(run: Promise<T>) => Promise<T>;\n /**\n * The run this launch registered, or undefined while none has appeared.\n *\n * Its presence is what lets a launch answer on the registry instead of on the\n * launcher process exiting. Left out, the launch waits for the process, which\n * is the behaviour every caller had before.\n */\n findLaunchedRun?: (query: LaunchedRunQuery) => Promise<WorkflowRunRecord | undefined>;\n /** Report a launch that fails after this call already answered \"started\". */\n onLateFailure?: (error: unknown, ctx: ExtensionContext) => void;\n launchAckPollMs?: number;\n launchAckTimeoutMs?: number;\n}\n\nexport interface WorkflowLaunchExecutor {\n execute(\n input: WorkflowLaunchInput,\n ctx: ExtensionContext,\n onUpdate?: AgentToolUpdateCallback<{ tool: string }>,\n ): Promise<CallToolResult>;\n}\n\nexport interface WorkflowPiToolDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n launchExecutor?: WorkflowLaunchExecutor;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n activeRunCount?: () => Promise<number>;\n followRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n tailRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n openRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n requireSessionRun?: (input: WorkflowRunSelector, sessionId: string | undefined) => Promise<WorkflowRunRecord>;\n /**\n * Resolve a failed recovery target globally.\n *\n * Recovery is the one ownership-transferring action: a replacement Pi\n * session must be able to adopt a terminal run whose launching session is\n * gone. Every non-recovery action remains session-scoped.\n */\n requireRecoverableRun?: (input: WorkflowRunSelector) => Promise<WorkflowRunRecord>;\n readRecoveryEvidence?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n /**\n * Hand a recovery to a terminal launcher, returning what to tell the caller.\n *\n * Undefined means this recovery cannot be delegated, and the in-process\n * replay below is used instead.\n */\n delegateRecovery?: (\n input: { runKey: string; workspace?: string; runner?: string },\n ctx: ExtensionContext,\n ) => Promise<string | undefined>;\n observeSession?: (sessionId: string | undefined) => void;\n trackPendingRun?: <T>(run: Promise<T>) => Promise<T>;\n feature?: EmbeddedWorkflowFeature;\n recoverTool?: {\n execute(input: {\n dryRun?: boolean;\n job?: string;\n runKey: string;\n runner?: string;\n workspace?: string;\n }): Promise<CallToolResult>;\n };\n controlTool?: ReturnType<EmbeddedWorkflowFeature['createControlTool']>;\n runTool?: EmbeddedWorkflowFeature['runTool'];\n listWorkflowsTool?: EmbeddedWorkflowFeature['listWorkflowsTool'];\n}\n\nexport function reportProgress(\n onUpdate: AgentToolUpdateCallback<{ tool: string }> | undefined,\n tool: string,\n message: string,\n): void {\n onUpdate?.({ content: [{ type: 'text', text: message }], details: { tool } });\n}\n\nexport function appendGuidance(\n result: AgentToolResult<{ tool: string }>,\n guidance: string,\n): AgentToolResult<{ tool: string }> {\n return { ...result, content: [...result.content, { type: 'text', text: guidance }] };\n}\n\nfunction statusAction(runKey: string): string {\n return `workflow_run {\"action\":\"status\",\"runKey\":${JSON.stringify(runKey)}}`;\n}\n\nexport function actionGuidance(action: WorkflowRunInput['action'], runKey: string): string[] {\n const status = statusAction(runKey);\n if (action === 'stop') return [`Next: call ${status} to confirm the run reached a terminal stage.`];\n if (action === 'recover') {\n return [\n `Report the recovery failure and do not retry it blindly: call ${status} first.`,\n 'Ask the user before launching fresh work when the recorded recovery is no longer valid.',\n ];\n }\n return [`Next: call ${status} to verify the recorded execution state.`];\n}\n\nexport const launchFailureOptions = [\n 'Report the failure to the user with the error above. A launch failure is usually a bad workflow path, a missing launcher, or a workflow whose own pre-conditions refused.',\n 'list_workflows: confirm the workflow path exists and its description matches the work, if the path may be wrong.',\n 'workflow_run with action status: check whether an earlier attempt is already running before launching again.',\n];\n\n/**\n * An Error, whatever the launch rejected with.\n *\n * A rejection reaches here as `unknown` because it crossed a promise boundary,\n * and rethrowing that as-is hands Pi's tool layer something it cannot read a\n * message or a stack off. The original is kept as the cause rather than\n * flattened into a string.\n */\nfunction asError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value), { cause: value });\n}\n\n/** Resolves to undefined, so a race against it reads as \"nothing settled yet\". */\nfunction sleep(ms: number): Promise<undefined> {\n return new Promise((settle) => {\n const timer = setTimeout(() => settle(undefined), ms);\n timer.unref?.();\n });\n}\n\n/**\n * Wait for whichever answer arrives first: the launch settling, the run\n * appearing in the registry, or the budget running out.\n *\n * A launch that delegates to a terminal launcher settles when that launcher's\n * whole process chain closes, which on a loaded machine has been measured\n * minutes after the run itself was registered and working. The registry is the\n * earlier and more truthful signal: a run recorded there is a run that started.\n */\nasync function awaitLaunchAck(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n query: LaunchedRunQuery,\n): Promise<LaunchAck> {\n const findLaunchedRun = dependencies.findLaunchedRun;\n if (!findLaunchedRun) return { kind: 'settled', outcome: await settled };\n\n const pollMs = dependencies.launchAckPollMs ?? LAUNCH_ACK_POLL_MS;\n const deadline = Date.now() + (dependencies.launchAckTimeoutMs ?? LAUNCH_ACK_TIMEOUT_MS);\n for (;;) {\n const outcome = await Promise.race([settled, sleep(pollMs)]);\n if (outcome) return { kind: 'settled', outcome };\n // A registry read that throws must not fail the launch: the run may be\n // perfectly healthy, and the settled promise is still the fallback.\n const record = await findLaunchedRun(query).catch(() => undefined);\n if (record) return { kind: 'record', record };\n if (Date.now() >= deadline) return { kind: 'handoff' };\n }\n}\n\n/**\n * Carry a failure that lands after the caller was told the run started.\n *\n * Answering early trades the launcher's exit code for timeliness. Dropping that\n * code entirely is not part of the trade: a launch that fails a minute later\n * would otherwise leave a user waiting on a run that never existed.\n */\nfunction reportLateFailure(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n ctx: ExtensionContext,\n): void {\n void settled.then((outcome) => {\n if (outcome.kind === 'error') {\n dependencies.onLateFailure?.(asError(outcome.error), ctx);\n return;\n }\n if (outcome.result.isError) {\n dependencies.onLateFailure?.(new Error(toolResultText(outcome.result) || 'Workflow launch failed.'), ctx);\n }\n });\n}\n\nexport function createWorkflowLaunchExecutor(dependencies: WorkflowLaunchExecutorDependencies): WorkflowLaunchExecutor {\n return {\n async execute(input, ctx, onUpdate) {\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), dependencies.environment);\n dependencies.observeSession?.(sessionId);\n const agiflowJobKind = input.env?.[AGIFLOW_JOB_KIND_ENV]?.trim();\n const agiflowJobId = input.env?.[AGIFLOW_JOB_ID_ENV]?.trim();\n const explicitProjectId = input.env?.[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (Boolean(agiflowJobKind) !== Boolean(agiflowJobId)) {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND and AGIFLOW_JOB_ID together.');\n }\n if (agiflowJobKind && agiflowJobKind !== 'task' && agiflowJobKind !== 'work-unit') {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND to be task or work-unit.');\n }\n if (agiflowJobKind && !explicitProjectId) {\n throw new Error('Agiflow workflow launches require AGIFLOW_PROJECT_ID with the job identity.');\n }\n if (agiflowJobKind && !input.prompt?.trim()) {\n throw new Error(\n 'Agiflow workflow launches require a non-empty prompt so user_prompt runs do not wait for terminal input.',\n );\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, 'Checking workflow capacity...');\n const maxConcurrent = resolveMaxConcurrent(dependencies.environment);\n const active = (await dependencies.activeRunCount?.()) ?? 0;\n if (active >= maxConcurrent) {\n throw new Error(\n withOptions(`This session is at capacity: ${active}/${maxConcurrent} workflows running.`, [\n 'Wait for a running workflow to finish, then launch again. The extension reports each one as it ends.',\n 'workflow_run with action status: show what is running, so the user can judge whether something is stuck.',\n 'workflow_run with action stop: free a slot by stopping a run the user no longer wants.',\n ]),\n );\n }\n\n if (input.runner) {\n const rejection = dependencies.rejectRunner?.(input.workflowPath, input.runner);\n if (rejection) throw new Error(rejection);\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, `Launching workflow ${input.workflowPath}...`);\n const workflowEnv = { ...input.env };\n const dispatcherContextFile = dependencies.environment.AGIFLOW_DISPATCH_CONTEXT_FILE;\n const dispatcherProjectId = dependencies.environment[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (\n dispatcherContextFile &&\n agiflowJobKind &&\n dispatcherProjectId &&\n explicitProjectId &&\n dispatcherProjectId !== explicitProjectId\n ) {\n throw new Error(\n `Agiflow workflow project identity conflicts with the dispatcher context (${explicitProjectId} versus ${dispatcherProjectId}).`,\n );\n }\n if (dispatcherContextFile) {\n for (const key of [\n 'AGIFLOW_ORGANIZATION_ID',\n 'AGIFLOW_PROJECT_ID',\n 'AGIFLOW_DEVICE_ID',\n 'BACKEND_AGIFLOW_API_ENDPOINT',\n 'AGIFLOW_DISPATCH_SECRET_FILE',\n ] as const) {\n const hostValue = dependencies.environment[key];\n if (hostValue) workflowEnv[key] = hostValue;\n }\n }\n const since = Date.now();\n const launch = dependencies.trackPendingRun(\n dependencies.runTool.execute({\n ...input,\n env: { ...workflowEnv, [PI_SESSION_ENV]: sessionId },\n }),\n );\n // Folded into a value before anything races it. A promise this function\n // may stop awaiting must never be able to reject unobserved, which in\n // Node ends the whole process, Pi's TUI included.\n const settled: Promise<LaunchOutcome> = launch.then(\n (value): LaunchOutcome => ({ kind: 'value', result: value }),\n (error: unknown): LaunchOutcome => ({ kind: 'error', error }),\n );\n\n const ack = await awaitLaunchAck(settled, dependencies, {\n sessionId,\n since,\n workflowPath: input.workflowPath,\n });\n\n if (ack.kind === 'settled') {\n const outcome = ack.outcome;\n if (outcome.kind === 'error') throw asError(outcome.error);\n const result = outcome.result;\n if (result.isError)\n throw new Error(withOptions(toolResultText(result) || 'Workflow launch failed.', launchFailureOptions));\n await dependencies.onLaunch?.(ctx);\n return result;\n }\n\n reportLateFailure(settled, dependencies, ctx);\n await dependencies.onLaunch?.(ctx);\n return {\n content: [\n {\n type: 'text',\n text: ack.kind === 'record' ? launchedRunSummary(ack.record) : launchHandoffSummary(input.workflowPath),\n },\n ],\n };\n },\n };\n}\n","import { resolve } from 'node:path';\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-core/childProcess';\nimport {\n createEmbeddedWorkflowFeature,\n type WorkflowRunRecord,\n type EmbeddedWorkflowFeature,\n} from '@agimon-ai/workflow-mcp';\nimport type { ExtensionAPI, ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { z } from 'zod';\n\nimport { workflowRunInputSchema } from '../../schemas/workflowPi';\nimport { toAgentToolResult, type WorkflowToolDetails } from '../../services/piToolBridge';\nimport {\n type WorkflowLaunchInput,\n type WorkflowRunSelector,\n launchFailureOptions,\n} from '../../services/workflowExecution';\nimport {\n createWorkflowLaunchExecutor,\n reportProgress,\n appendGuidance,\n actionGuidance,\n type WorkflowPiToolDependencies,\n} from '../../services/workflowExecution';\ntype WorkflowToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\nimport {\n WORKFLOW_PI_TOOL_NAMES,\n LIST_WORKFLOWS_TOOL_NAME,\n LAUNCH_WORKFLOW_TOOL_NAME,\n WORKFLOW_RUN_TOOL_NAME,\n} from '../../constants/workflow';\nconst PI_LAUNCH_FIELDS = {\n workflowPath: true,\n workspace: true,\n runner: true,\n name: true,\n env: true,\n prompt: true,\n job: true,\n inputs: true,\n} as const;\nexport type WorkflowNativeTool = ToolDefinition<WorkflowToolSchema, WorkflowToolDetails>;\nexport type WorkflowToolRenderers = Pick<WorkflowNativeTool, 'renderCall' | 'renderResult'>;\nexport function createWorkflowTools(\n dependencies: WorkflowPiToolDependencies,\n renderers: (name: (typeof WORKFLOW_PI_TOOL_NAMES)[number]) => WorkflowToolRenderers = () => ({}),\n): WorkflowNativeTool[] {\n const feature = dependencies.feature ?? createEmbeddedWorkflowFeature();\n const runTool = dependencies.runTool ?? feature.runTool;\n const listWorkflowsTool = dependencies.listWorkflowsTool ?? feature.listWorkflowsTool;\n const recoverTool = dependencies.recoverTool ?? feature.createRecoverTool();\n const controlTool = dependencies.controlTool ?? feature.createControlTool();\n const trackPendingRun = dependencies.trackPendingRun ?? (<T>(run: Promise<T>): Promise<T> => run);\n const launchExecutor =\n dependencies.launchExecutor ??\n createWorkflowLaunchExecutor({\n environment: dependencies.environment,\n activeRunCount: dependencies.activeRunCount,\n onLaunch: dependencies.onLaunch,\n observeSession: dependencies.observeSession,\n rejectRunner: dependencies.rejectRunner,\n runTool,\n trackPendingRun,\n });\n\n return [\n {\n name: LIST_WORKFLOWS_TOOL_NAME,\n label: 'List Workflows',\n description: 'List the workflow definitions available in this repository.',\n promptSnippet: 'List available workflow definitions',\n parameters: z.toJSONSchema(listWorkflowsTool.getInputSchema()),\n renderShell: 'self',\n ...renderers(LIST_WORKFLOWS_TOOL_NAME),\n async execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n const input = params as Parameters<EmbeddedWorkflowFeature['listWorkflowsTool']['execute']>[0];\n return toAgentToolResult(\n LIST_WORKFLOWS_TOOL_NAME,\n await listWorkflowsTool.execute({\n ...input,\n directory:\n input?.directory === undefined\n ? ctx.cwd\n : typeof input.directory === 'string'\n ? resolve(ctx.cwd, input.directory)\n : input.directory,\n }),\n );\n },\n },\n\n {\n name: LAUNCH_WORKFLOW_TOOL_NAME,\n label: 'Launch Workflow',\n description:\n 'Start a workflow run. Returns once the run has started, not once it finishes; use workflow_run with action status or wait for the completion notice.',\n promptSnippet: 'Start a workflow run and return its identifier',\n promptGuidelines: [\n 'Before launching, call list_workflows and pick the workflow whose own description matches the work. A workflow description is the source of truth; never infer one from its filename. If nothing matches, say so and stop rather than launching an approximate fit.',\n 'launch_workflow returns when the run has STARTED, not when it has finished. Never report success from its result. Poll workflow_run with action status, or wait for the completion notice the extension delivers on its own.',\n 'When dispatching Agiflow work, pass AGIFLOW_PROJECT_ID, AGIFLOW_JOB_KIND, and AGIFLOW_JOB_ID through env plus a non-empty prompt. Kind must be task or work-unit. The id alone is not a key, and omitting prompt leaves user_prompt workflows waiting for terminal input.',\n 'A workflow claims its own job in its pre step. Never claim a job yourself. JOB_ALREADY_CLAIMED or HTTP 409 means another worker won the race, so report contention and do not unlock, release, or retry automatically.',\n 'If a result says WORKFLOW_NOT_OWNED or a release failed, inspect current ownership and ask the user before any release or unlock. Never force another worker’s lock.',\n 'If a running workflow is not found, call workflow_run with action status to re-check current state before retrying.',\n 'The per-session concurrency ceiling is a real limit. If launch_workflow refuses, wait for a run to finish; do not launch through the shell to get around it.',\n ],\n parameters: z.toJSONSchema(runTool.getInputSchema().pick(PI_LAUNCH_FIELDS)),\n renderShell: 'self',\n ...renderers(LAUNCH_WORKFLOW_TOOL_NAME),\n async execute(_toolCallId, params, _signal, onUpdate, ctx) {\n const input = params as WorkflowLaunchInput;\n const result = await launchExecutor.execute(input, ctx, onUpdate);\n const adapted = toAgentToolResult(LAUNCH_WORKFLOW_TOOL_NAME, result, launchFailureOptions);\n return appendGuidance(\n adapted,\n 'Next: call workflow_run with action status and verify the recorded stage before reporting the workflow outcome.',\n );\n },\n },\n\n {\n name: WORKFLOW_RUN_TOOL_NAME,\n label: 'Workflow Run',\n description:\n 'Inspect or control one workflow run. Use action status, tail, recovery-evidence, follow, open, pause, resume, stop, or recover. Every action requires an exact run key.',\n promptSnippet: 'Inspect or control a workflow run',\n promptGuidelines: [\n 'Use action status as the authority for stage, outcome, execution state, and pause cursor. A run that started is not a run that succeeded.',\n 'Use action pause or resume for cooperative lifecycle control. Pause is not stop: the run keeps its stage running, capacity, services, and heartbeat while paused.',\n 'Use action stop only when the user requests stopping a run. A user-requested stop is not a failure and needs no failure diagnosis.',\n 'Do not use follow or tail merely to wait for a healthy run; use status or the completion notice. Tail returns chat-safe status without raw PTY frames. Use follow only when the user asks to pin live progress, and open only when a human wants the recorded launcher foregrounded.',\n 'Use action recovery-evidence for terminal-only, durable status and artifacts before recovery. It is the only inspection path that may read a failed run from an earlier session and it never reads a live launcher.',\n 'Use action recover only after loading the `workflow-recovery` skill and gathering its required evidence. Recovery may adopt a terminal failed run from an earlier Pi session; it never grants cross-session control of running work. Never edit issue.md or repair.json, and verify real process and registry progress before recovery.',\n 'Never unlock or force-release an Agiflow claim from this tool.',\n ],\n parameters: z.toJSONSchema(workflowRunInputSchema),\n renderShell: 'self',\n ...renderers(WORKFLOW_RUN_TOOL_NAME),\n async execute(_toolCallId, rawParams, _signal, onUpdate, ctx) {\n const input = workflowRunInputSchema.parse(rawParams);\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), dependencies.environment);\n dependencies.observeSession?.(sessionId);\n const selector: WorkflowRunSelector = { runKey: input.runKey, workspace: input.workspace };\n const requireOwnedRun = async (): Promise<WorkflowRunRecord> => {\n if (!dependencies.requireSessionRun) {\n throw new Error('Workflow run ownership is not available in this session.');\n }\n return dependencies.requireSessionRun(selector, sessionId);\n };\n\n if (input.action === 'status') {\n const record = await requireOwnedRun();\n return {\n content: [{ type: 'text', text: JSON.stringify(record, null, 2) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'tail') {\n if (!dependencies.tailRun) throw new Error('Reading workflow output is not available in this session.');\n const record = await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Reading output for workflow ${input.runKey}...`);\n await dependencies.tailRun(selector, ctx);\n return {\n content: [\n {\n type: 'text',\n text: [\n `Workflow: ${record.displayName} (${record.runKey})`,\n `Stage: ${record.effectiveStage ?? record.stage}`,\n 'Raw launcher output is hidden from chat. Use action follow or open to view it.',\n ].join('\\n'),\n },\n ],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'recovery-evidence') {\n if (!dependencies.readRecoveryEvidence) {\n throw new Error('Reading workflow recovery evidence is not available in this session.');\n }\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Reading recovery evidence for workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.readRecoveryEvidence(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'follow') {\n if (!dependencies.followRun) throw new Error('Following workflow output is not available in this session.');\n await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Following workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.followRun(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'open') {\n if (!dependencies.openRun) throw new Error('Opening a workflow launcher is not available in this session.');\n await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Opening workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.openRun(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n\n if (input.action === 'recover') {\n if (!dependencies.requireRecoverableRun) {\n throw new Error('Workflow recovery ownership transfer is not available in this session.');\n }\n const recoverable = await dependencies.requireRecoverableRun(selector);\n const recoverySelector = { runKey: recoverable.runKey, workspace: recoverable.workspace };\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Recovering workflow ${input.runKey}...`);\n // A recovery replays the workflow, and the replay skips the launch\n // step, so every job runs in THIS process. For a workflow whose steps\n // are interactive that means an agent TUI spawned onto this process's\n // own terminal. Hand it to a launcher instead, where the workflow says\n // how. A dry run prints rather than executes, so it stays here.\n if (!input.dryRun) {\n const delegated = await dependencies.delegateRecovery?.({ ...recoverySelector, runner: input.runner }, ctx);\n if (delegated) {\n const guidance = actionGuidance(input.action, input.runKey);\n await dependencies.onLaunch?.(ctx);\n return {\n content: [{ type: 'text', text: [delegated, guidance[0]].join('\\n\\n') }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n }\n const recoverInput = {\n dryRun: input.dryRun,\n job: input.job,\n runKey: recoverySelector.runKey,\n runner: input.runner,\n workspace: recoverySelector.workspace,\n };\n const result = await trackPendingRun(recoverTool.execute(recoverInput));\n const guidance = actionGuidance(input.action, input.runKey);\n const adapted = toAgentToolResult(WORKFLOW_RUN_TOOL_NAME, result, guidance);\n await dependencies.onLaunch?.(ctx);\n return appendGuidance(adapted, guidance[0]!);\n }\n\n const ownedRun = await requireOwnedRun();\n if (!ownedRun.runId) throw new Error(`Workflow ${input.runKey} has no controllable run generation.`);\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Requesting ${input.action} for workflow ${input.runKey}...`);\n const result = await controlTool.execute({\n action: input.action,\n expectedRunId: ownedRun.runId,\n reason: input.reason,\n runKey: input.runKey,\n workspace: input.workspace,\n });\n const guidance = actionGuidance(input.action, input.runKey);\n const adapted = toAgentToolResult(WORKFLOW_RUN_TOOL_NAME, result, guidance);\n return appendGuidance(adapted, guidance[0]!);\n },\n },\n ];\n}\n","import type { LeaderBinding } from '@agimon-ai/doompi-core/leader';\nimport type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport {\n LEADER_CATALOG_ACTION,\n LEADER_DETAIL,\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../constants/workflow';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = {\n key: LEADER_KEY,\n label: LEADER_LABEL,\n detail: LEADER_DETAIL,\n order: LEADER_ORDER,\n} as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.catalog`,\n // Launching lives on this board's own `r` key rather than a second menu\n // entry: picking which workflow to run is the same act as reading what\n // one does.\n path: [GROUP_SEGMENT, { key: 'l', label: 'list', detail: 'browse and launch workflows' }],\n action: { name: LEADER_CATALOG_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'runs', detail: 'runs in this session' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools', tone: 'exit' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n // `r` is runs everywhere, so recovery moves off it rather than reading as a\n // third flavour of list in the one space that has both.\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'c', label: 'recover', detail: 'adopt a failed run' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(hub: DoomUiHubService, enabled = false): WorkflowLeaderHandle {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(enabled),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n","import { DoomToolCall, DoomToolResult, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme, ThemeColor } from '@earendil-works/pi-coding-agent';\nimport type { Component } from '@earendil-works/pi-tui';\n\nexport type WorkflowToolName = 'launch_workflow' | 'list_workflows' | 'workflow_run';\nexport type WorkflowPiToolName = WorkflowToolName;\n\ninterface WorkflowToolResultLike {\n content?: unknown;\n isError?: boolean;\n}\n\ninterface WorkflowToolRenderOptions {\n expanded: boolean;\n isError?: boolean;\n isPartial?: boolean;\n}\n\ntype JsonRecord = Record<string, unknown>;\n\ntype WorkflowState = {\n color: ThemeColor;\n glyph: string;\n label: string;\n};\n\ninterface WorkflowCatalogItem {\n description: string;\n name: string;\n path: string;\n tags: string[];\n}\n\ninterface WorkflowCatalog {\n directory?: string;\n page: number;\n pageSize: number;\n tags: Array<{ count: number; tag: string }>;\n total: number;\n totalPages: number;\n workflows: WorkflowCatalogItem[];\n}\n\ninterface EvidenceSection {\n body: string[];\n name: string;\n}\n\nconst COLLAPSED_CATALOG_ROWS = 6;\nconst COLLAPSED_DETAIL_LINES = 8;\nconst PARTIAL_DETAIL_LINES = 4;\n\nfunction asRecord(value: unknown): JsonRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n return value as JsonRecord;\n}\n\nfunction inlineText(value: string): string {\n let normalized = '';\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n normalized += code <= 31 || code === 127 ? ' ' : character;\n }\n return normalized.replace(/\\s+/gu, ' ').trim();\n}\n\nfunction readString(record: JsonRecord | undefined, key: string): string | undefined {\n const value = record?.[key];\n if (typeof value !== 'string') return undefined;\n return inlineText(value) || undefined;\n}\n\nfunction readNumber(record: JsonRecord | undefined, key: string): number | undefined {\n const value = record?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction readBoolean(record: JsonRecord | undefined, key: string): boolean | undefined {\n const value = record?.[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction readStringArray(record: JsonRecord | undefined, key: string): string[] {\n const value = record?.[key];\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction parseJsonRecord(text: string | undefined): JsonRecord | undefined {\n if (!text) return undefined;\n try {\n return asRecord(JSON.parse(text));\n } catch {\n return undefined;\n }\n}\n\nfunction textBlocks(result: WorkflowToolResultLike): string[] {\n if (!Array.isArray(result.content)) return [];\n return result.content.flatMap((item) => {\n const record = asRecord(item);\n return record?.type === 'text' && typeof record.text === 'string' ? [record.text] : [];\n });\n}\n\nfunction detailLines(result: WorkflowToolResultLike): string[] {\n return textBlocks(result)\n .flatMap((block) => block.split('\\n'))\n .map((line) => line.trimEnd())\n .filter((line) => line.length > 0);\n}\n\nfunction firstPayload(result: WorkflowToolResultLike): JsonRecord | undefined {\n return parseJsonRecord(textBlocks(result)[0]);\n}\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`): string {\n return count === 1 ? singular : pluralForm;\n}\n\nfunction labelValue(label: string, value: string, theme: Theme): string {\n return `${theme.fg('dim', `${label} `)}${theme.fg('text', value)}`;\n}\n\nfunction targetScope(args: Record<string, unknown>): string | undefined {\n const runKey = readString(args, 'runKey');\n if (!runKey) return undefined;\n const workspace = readString(args, 'workspace');\n return workspace ? `${workspace}/${runKey}` : runKey;\n}\n\nfunction toolAction(toolName: WorkflowPiToolName, args: Record<string, unknown>): string {\n if (toolName === 'list_workflows') return 'list';\n if (toolName === 'launch_workflow') return 'launch';\n return readString(args, 'action') ?? 'run';\n}\n\nfunction toolTarget(toolName: WorkflowPiToolName, args: Record<string, unknown>): string | undefined {\n if (toolName === 'list_workflows') return readString(args, 'directory');\n if (toolName === 'launch_workflow') return readString(args, 'workflowPath');\n return targetScope(args);\n}\n\nfunction renderResult(lines: readonly string[], theme: Theme, expanded: boolean): Component {\n return new DoomToolResult(lines, theme, { wrap: expanded });\n}\n\nfunction hiddenDetailLine(hidden: number, theme: Theme): string {\n return theme.fg('dim', `… ${hidden} more · ctrl+o`);\n}\n\nfunction statusTimestamp(value: string): string {\n return value.replace('T', ' ').replace(/\\.\\d{3}Z$/, 'Z');\n}\n\nfunction workflowNameFromPath(path: string | undefined): string {\n if (!path) return 'workflow';\n const filename = path.split('/').at(-1) ?? path;\n return filename.replace(/\\.workflow\\.ya?ml$/u, '') || filename;\n}\n\nfunction callMetadata(toolName: WorkflowPiToolName, args: Record<string, unknown>, theme: Theme): string[] {\n const values: string[] = [];\n\n if (toolName === 'list_workflows') {\n const page = readNumber(args, 'page');\n const pageSize = readNumber(args, 'pageSize');\n if (page !== undefined) values.push(`page ${page}`);\n if (pageSize !== undefined) values.push(`${pageSize}/page`);\n if (readString(args, 'filter')) values.push('filtered');\n const tags = readStringArray(args, 'tags');\n if (tags.length > 0) values.push(`${tags.length} ${plural(tags.length, 'tag')}`);\n } else if (toolName === 'launch_workflow') {\n const job = readString(args, 'job');\n const runner = readString(args, 'runner');\n const workspace = readString(args, 'workspace');\n const inputCount = Object.keys(asRecord(args.inputs) ?? {}).length;\n const environmentCount = Object.keys(asRecord(args.env) ?? {}).length;\n if (workspace) values.push(`workspace ${workspace}`);\n if (job) values.push(`job ${job}`);\n if (runner) values.push(`runner ${runner}`);\n if (readBoolean(args, 'dryRun')) values.push('dry run');\n if (readString(args, 'prompt')) values.push('with prompt');\n if (inputCount > 0) values.push(`${inputCount} ${plural(inputCount, 'input')}`);\n if (environmentCount > 0) values.push(`${environmentCount} env`);\n } else {\n const expectedRunId = readString(args, 'expectedRunId');\n if (expectedRunId) values.push('generation checked');\n if (readString(args, 'reason')) values.push('with reason');\n if (readBoolean(args, 'dryRun')) values.push('dry run');\n if (readString(args, 'job')) values.push('job override');\n if (readString(args, 'runner')) values.push('runner override');\n }\n\n return values.map((value) => theme.fg('dim', value));\n}\n\nexport function renderWorkflowToolCall(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n theme: Theme,\n): Component {\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const metadata = callMetadata(toolName, args, theme);\n const purpose = [theme.bold(action), target ? theme.fg('muted', target) : undefined, ...metadata]\n .filter((part): part is string => !!part)\n .join(theme.fg('dim', ' · '));\n return new DoomToolCall(renderToolHeading('workflow', purpose, theme));\n}\n\nfunction parseCatalog(payload: JsonRecord | undefined): WorkflowCatalog | undefined {\n if (!Array.isArray(payload?.workflows)) return undefined;\n\n const workflows = payload.workflows.flatMap((value) => {\n const record = asRecord(value);\n const path = readString(record, 'path');\n if (!record || !path) return [];\n return [\n {\n description: readString(record, 'description') ?? '',\n name: readString(record, 'name') ?? '',\n path,\n tags: readStringArray(record, 'tags'),\n },\n ];\n });\n const tags = Array.isArray(payload.tags)\n ? payload.tags.flatMap((value) => {\n const record = asRecord(value);\n const tag = readString(record, 'tag');\n const count = readNumber(record, 'count');\n return tag && count !== undefined ? [{ count, tag }] : [];\n })\n : [];\n\n return {\n directory: readString(payload, 'directory'),\n page: readNumber(payload, 'page') ?? 1,\n pageSize: readNumber(payload, 'pageSize') ?? workflows.length,\n tags,\n total: readNumber(payload, 'total') ?? workflows.length,\n totalPages: readNumber(payload, 'totalPages') ?? (workflows.length > 0 ? 1 : 0),\n workflows,\n };\n}\n\nfunction catalogItemLines(item: WorkflowCatalogItem, expanded: boolean, theme: Theme): string[] {\n const name = item.name || workflowNameFromPath(item.path);\n const lines = [`${theme.fg('accent', '›')} ${theme.bold(name)} ${theme.fg('muted', `· ${item.path}`)}`];\n if (!expanded) return lines;\n if (item.description) lines.push(` ${theme.fg('text', item.description)}`);\n if (item.tags.length > 0) lines.push(` ${labelValue('tags', item.tags.join(', '), theme)}`);\n return lines;\n}\n\nfunction renderCatalogResult(\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component | undefined {\n const catalog = parseCatalog(firstPayload(result));\n if (!catalog) return undefined;\n\n const pageLabel = `page ${catalog.page}/${catalog.totalPages}`;\n const summary = `${theme.fg(catalog.total > 0 ? 'success' : 'muted', catalog.total > 0 ? '✓' : '○')} ${theme.bold(\n `${catalog.total} ${plural(catalog.total, 'workflow')}`,\n )} ${theme.fg('dim', `· ${pageLabel}`)}`;\n const shown = options.expanded ? catalog.workflows : catalog.workflows.slice(0, COLLAPSED_CATALOG_ROWS);\n const lines = [summary, ...shown.flatMap((item) => catalogItemLines(item, options.expanded, theme))];\n const hidden = catalog.workflows.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n\n if (options.expanded) {\n if (catalog.tags.length > 0) {\n const tags = catalog.tags.map(({ count, tag }) => `${tag} (${count})`).join(', ');\n lines.push(labelValue('available tags', tags, theme));\n }\n if (catalog.directory) lines.push(labelValue('directory', catalog.directory, theme));\n lines.push(labelValue('page size', String(catalog.pageSize), theme));\n }\n\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction readWorkflowState(record: JsonRecord): WorkflowState {\n const stage = readString(record, 'effectiveStage') ?? readString(record, 'stage') ?? 'unknown';\n const outcome = readString(record, 'effectiveOutcome') ?? readString(record, 'outcome');\n const executionState = readString(record, 'executionState');\n\n if (outcome === 'interrupted') return { color: 'warning', glyph: '!', label: 'interrupted' };\n if (stage === 'error' || outcome === 'failed') return { color: 'error', glyph: '✗', label: 'failed' };\n if (stage === 'completed' && outcome === 'skipped') return { color: 'muted', glyph: '○', label: 'skipped' };\n if (stage === 'completed') return { color: 'success', glyph: '✓', label: 'completed' };\n if (executionState === 'paused') return { color: 'warning', glyph: 'Ⅱ', label: 'paused' };\n if (executionState === 'pause_requested') return { color: 'warning', glyph: '◐', label: 'pause requested' };\n if (executionState === 'resume_requested') return { color: 'warning', glyph: '◐', label: 'resume requested' };\n if (stage === 'running') return { color: 'accent', glyph: '◐', label: 'running' };\n return { color: 'muted', glyph: '○', label: stage };\n}\n\nfunction recordScope(record: JsonRecord): string {\n const runKey = readString(record, 'runKey') ?? 'unknown run';\n const workspace = readString(record, 'workspace');\n return workspace ? `${workspace}/${runKey}` : runKey;\n}\n\nfunction currentActivity(record: JsonRecord, theme: Theme): string | undefined {\n const cursor = asRecord(record.executionCursor);\n const job = readString(cursor, 'job') ?? readString(record, 'job');\n const step = readString(cursor, 'stepName');\n const phase = readString(cursor, 'phase');\n if (!job && !step && !phase) return undefined;\n const context = job ?? phase ?? 'workflow';\n return ` ${theme.fg('muted', `[${context}]`)} ${theme.fg('text', step ?? phase ?? 'running')}`;\n}\n\nfunction launcherLabel(record: JsonRecord): string | undefined {\n const launcher = asRecord(record.launcher);\n const type = readString(launcher, 'type');\n if (!type) return undefined;\n const identity = readString(launcher, 'sessionName') ?? readString(launcher, 'workspaceId');\n return identity ? `${type} ${identity}` : type;\n}\n\nfunction workflowRecordLines(record: JsonRecord, expanded: boolean, theme: Theme): string[] | undefined {\n const runKey = readString(record, 'runKey');\n const stage = readString(record, 'stage');\n if (!runKey || !stage) return undefined;\n\n const state = readWorkflowState(record);\n const displayName = readString(record, 'displayName') ?? runKey;\n const heading = `${theme.fg(state.color, state.glyph)} ${theme.bold(displayName)} ${theme.fg(\n 'dim',\n `· ${recordScope(record)} ·`,\n )} ${theme.fg(state.color, state.label)}`;\n const lines = [heading];\n const activity = currentActivity(record, theme);\n if (activity) lines.push(activity);\n\n const failure = readString(record, 'errorMessage') ?? readString(record, 'failureReason');\n if (failure) lines.push(`${theme.fg('error', 'error')} ${theme.fg('text', failure)}`);\n const staleReason = readString(record, 'staleReason');\n if (staleReason) lines.push(`${theme.fg('warning', 'stale')} ${theme.fg('text', staleReason)}`);\n\n const conciseMetadata = [\n readString(record, 'runner') ? `runner ${readString(record, 'runner')}` : undefined,\n readBoolean(record, 'dryRun') ? 'dry run' : undefined,\n readNumber(record, 'exitCode') !== undefined ? `exit ${readNumber(record, 'exitCode')}` : undefined,\n readString(record, 'startedAt') ? `started ${statusTimestamp(readString(record, 'startedAt') ?? '')}` : undefined,\n ].filter((value): value is string => !!value);\n if (conciseMetadata.length > 0) lines.push(theme.fg('dim', conciseMetadata.join(' · ')));\n\n if (!expanded) return lines;\n\n const detailedValues: Array<[string, string | undefined]> = [\n ['workflow', readString(record, 'workflowPath')],\n ['workflow id', readString(record, 'workflowId')],\n ['run id', readString(record, 'runId')],\n ['launcher', launcherLabel(record)],\n ['job', readString(record, 'job')],\n ['outcome', readString(record, 'effectiveOutcome') ?? readString(record, 'outcome')],\n [\n 'finished',\n readString(record, 'finishedAt') ? statusTimestamp(readString(record, 'finishedAt') ?? '') : undefined,\n ],\n ['pid', readNumber(record, 'pid')?.toString()],\n ['repair', readString(record, 'activeRepairId') ? `#${readString(record, 'activeRepairId')}` : undefined],\n ['worktree', readString(record, 'worktreeBranch') ?? readString(record, 'worktreePath')],\n ];\n for (const [label, value] of detailedValues) {\n if (value) lines.push(labelValue(label, value, theme));\n }\n return lines;\n}\n\nfunction renderStatusResult(\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component | undefined {\n const payload = firstPayload(result);\n if (!payload) return undefined;\n const lines = workflowRecordLines(payload, options.expanded, theme);\n return lines ? renderResult(lines, theme, options.expanded) : undefined;\n}\n\nfunction nestedRequestedAt(payload: JsonRecord | undefined): string | undefined {\n return readString(asRecord(payload?.request), 'requestedAt') ?? readString(payload, 'requestedAt');\n}\n\nfunction renderControlResult(\n action: string,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const payload = firstPayload(result);\n const scope = targetScope(args) ?? readString(payload, 'runKey') ?? 'workflow';\n const payloadWorkspace = readString(payload, 'workspace');\n const resolvedScope = payloadWorkspace && !scope.includes('/') ? `${payloadWorkspace}/${scope}` : scope;\n const lines = [\n `${theme.fg('warning', '◐')} ${theme.bold(`${action} requested`)} ${theme.fg('dim', `· ${resolvedScope}`)}`,\n ];\n const requestedAt = nestedRequestedAt(payload);\n if (requestedAt) lines.push(labelValue('requested', statusTimestamp(requestedAt), theme));\n if (options.expanded) lines.push(theme.fg('dim', 'verify the transition with workflow_run status'));\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction matchLine(text: string, pattern: RegExp): string | undefined {\n return text.match(pattern)?.[1]?.trim();\n}\n\nfunction launchSummary(\n text: string,\n args: Record<string, unknown>,\n): { name: string; scope: string; state: WorkflowState } {\n const startedName = matchLine(text, /^Started (.+) in workspace .+\\.$/mu);\n const workspace = matchLine(text, /^Started .+ in workspace (.+)\\.$/mu) ?? readString(args, 'workspace');\n const runKey = matchLine(text, /^Run key:\\s*(.+)$/mu);\n const path = readString(args, 'workflowPath');\n const name = startedName ?? workflowNameFromPath(path);\n const scope = runKey ? (workspace ? `${workspace}/${runKey}` : runKey) : (workspace ?? path ?? 'workflow');\n\n if (/Workflow completed successfully/iu.test(text)) {\n return { name, scope, state: { color: 'success', glyph: '✓', label: 'completed' } };\n }\n if (/Workflow skipped/iu.test(text)) {\n return { name, scope, state: { color: 'muted', glyph: '○', label: 'skipped' } };\n }\n if (/no run was registered/iu.test(text)) {\n return { name, scope, state: { color: 'warning', glyph: '◐', label: 'starting · run key pending' } };\n }\n return { name, scope, state: { color: 'accent', glyph: '◐', label: runKey ? 'started' : 'launch accepted' } };\n}\n\nfunction renderLaunchResult(\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const blocks = textBlocks(result);\n const text = blocks.join('\\n');\n const summary = launchSummary(text, args);\n const lines = [\n `${theme.fg(summary.state.color, summary.state.glyph)} ${theme.bold(summary.name)} ${theme.fg(\n 'dim',\n `· ${summary.scope} ·`,\n )} ${theme.fg(summary.state.color, summary.state.label)}`,\n ];\n const metadata = [\n readString(args, 'job') ? `job ${readString(args, 'job')}` : undefined,\n readString(args, 'runner') ? `runner ${readString(args, 'runner')}` : undefined,\n readBoolean(args, 'dryRun') ? 'dry run' : undefined,\n ].filter((value): value is string => !!value);\n if (metadata.length > 0) lines.push(theme.fg('dim', metadata.join(' · ')));\n if (options.expanded) {\n const details = detailLines(result).filter((line) => !line.startsWith('Next steps for the agent:'));\n if (details.length > 0) lines.push(...details);\n }\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction splitEvidence(text: string): EvidenceSection[] {\n const sections: EvidenceSection[] = [];\n let current: EvidenceSection | undefined;\n for (const line of text.split('\\n')) {\n const match = line.match(/^--- (.+) ---$/u);\n if (match?.[1]) {\n current = { body: [], name: match[1] };\n sections.push(current);\n continue;\n }\n current?.body.push(line);\n }\n return sections;\n}\n\nfunction recoveryRecord(sections: EvidenceSection[]): JsonRecord | undefined {\n const runSection = sections.find((section) => section.name === 'run.json');\n return parseJsonRecord(runSection?.body.join('\\n'));\n}\n\nfunction renderRecoveryEvidenceResult(\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const text = textBlocks(result).join('\\n');\n const sections = splitEvidence(text);\n const record = recoveryRecord(sections);\n const recordLines = record ? workflowRecordLines(record, options.expanded, theme) : undefined;\n const evidenceSections = sections.filter((section) => section.name !== 'run.json');\n const scope = targetScope(args) ?? 'workflow';\n const lines = recordLines ?? [\n `${theme.fg('success', '✓')} ${theme.bold('recovery evidence')} ${theme.fg('dim', `· ${scope}`)}`,\n ];\n const names = evidenceSections.map((section) => section.name);\n lines.push(\n names.length > 0\n ? labelValue('evidence', names.join(', '), theme)\n : theme.fg('muted', 'no durable evidence files recorded'),\n );\n\n if (options.expanded) {\n for (const section of evidenceSections) {\n lines.push(theme.bold(section.name), ...section.body.filter((line) => line.length > 0));\n }\n }\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderSimpleActionResult(\n action: string,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const scope = targetScope(args) ?? 'workflow';\n const actionLabel: Record<string, string> = {\n follow: 'following output',\n open: 'launcher opened',\n recover: readBoolean(args, 'dryRun') ? 'recovery dry run finished' : 'recovery accepted',\n tail: 'launcher output checked',\n };\n const state: WorkflowState =\n action === 'recover'\n ? { color: 'accent', glyph: '◐', label: actionLabel[action] ?? action }\n : { color: 'success', glyph: '✓', label: actionLabel[action] ?? action };\n const lines = [`${theme.fg(state.color, state.glyph)} ${theme.bold(state.label)} ${theme.fg('dim', `· ${scope}`)}`];\n const details = detailLines(result);\n if (action === 'tail') {\n const stageLine = details.find((line) => line.startsWith('Stage:'));\n const workflowLine = details.find((line) => line.startsWith('Workflow:'));\n if (workflowLine) lines.push(workflowLine);\n if (stageLine) lines.push(stageLine);\n }\n if (options.expanded && details.length > 0) lines.push(...details);\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderFailure(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const summary = `${theme.fg('error', '✗')} ${theme.bold(`${action} failed`)}${\n target ? theme.fg('dim', ` · ${target}`) : ''\n }`;\n const details = detailLines(result);\n const shown = options.expanded ? details : details.slice(0, COLLAPSED_DETAIL_LINES);\n const lines = [summary, ...(shown.length > 0 ? shown : [theme.fg('error', 'Unknown workflow error')])];\n const hidden = details.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderPartial(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const details = detailLines(result);\n const shown = details.slice(-PARTIAL_DETAIL_LINES);\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const summary = `${theme.fg('accent', '◐')} ${theme.bold(action)}${target ? theme.fg('dim', ` · ${target}`) : ''}`;\n const hidden = details.length - shown.length;\n const lines = [summary];\n if (hidden > 0) lines.push(theme.fg('dim', `… ${hidden} earlier`));\n lines.push(...shown);\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderFallback(result: WorkflowToolResultLike, options: WorkflowToolRenderOptions, theme: Theme): Component {\n const details = detailLines(result);\n if (details.length === 0) return renderResult([theme.fg('muted', 'No workflow output.')], theme, options.expanded);\n const shown = options.expanded ? details : details.slice(0, COLLAPSED_DETAIL_LINES);\n const lines = [...shown];\n const hidden = details.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n return renderResult(lines, theme, options.expanded);\n}\n\nexport function renderWorkflowToolResult(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n if (options.isPartial) return renderPartial(toolName, args, result, options, theme);\n if (options.isError === true || result.isError === true) {\n return renderFailure(toolName, args, result, options, theme);\n }\n\n if (toolName === 'list_workflows') {\n return renderCatalogResult(result, options, theme) ?? renderFallback(result, options, theme);\n }\n if (toolName === 'launch_workflow') return renderLaunchResult(args, result, options, theme);\n\n const action = readString(args, 'action');\n if (action === 'status') {\n return renderStatusResult(result, options, theme) ?? renderFallback(result, options, theme);\n }\n if (action === 'pause' || action === 'resume' || action === 'stop') {\n return renderControlResult(action, args, result, options, theme);\n }\n if (action === 'recovery-evidence') {\n return renderRecoveryEvidenceResult(args, result, options, theme);\n }\n if (action === 'follow' || action === 'open' || action === 'recover' || action === 'tail') {\n return renderSimpleActionResult(action, args, result, options, theme);\n }\n return renderFallback(result, options, theme);\n}\n","import { resolve } from 'node:path';\n\nimport { type EmbeddedWorkflowFeature, type Workflow } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { type DispatchInput, workflowCatalogPageSchema, workflowDispatchInputsSchema } from '../../schemas/workflowPi';\nimport type {\n WorkflowCatalogDetail,\n WorkflowInputSummary,\n WorkflowJobSummary,\n} from '../../tui/workflow/workflowCatalog';\nimport { toolResultText } from '../piToolBridge';\nimport { type WorkflowLaunchExecutor, type WorkflowLaunchInput } from '../workflowExecution';\n\nconst CATALOG_PAGE_SIZE = 100;\nconst USER_PROMPT_TRIGGER = 'user_prompt';\nconst WORKFLOW_DISPATCH_TRIGGER = 'workflow_dispatch';\nconst BOOLEAN_INPUT_TYPE = 'boolean';\n\ntype WorkflowListTool = EmbeddedWorkflowFeature['listWorkflowsTool'];\ntype WorkflowListInput = Parameters<WorkflowListTool['execute']>[0];\n\nexport interface WorkflowCatalogEntry {\n description: string;\n name: string;\n path: string;\n relativePath: string;\n tags: string[];\n}\n\nexport interface WorkflowCatalogPage {\n directory: string;\n hasNextPage: boolean;\n page: number;\n pageSize: number;\n workflows: WorkflowCatalogEntry[];\n}\n\nexport interface WorkflowLauncherUi {\n editor(title: string, prefill?: string): Promise<string | undefined>;\n input(title: string, placeholder?: string): Promise<string | undefined>;\n notify(message: string, type?: 'info' | 'warning' | 'error'): void;\n select(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface WorkflowEntryLaunchOptions {\n compatibleRunners(workflow: Workflow): string[] | undefined;\n launch: WorkflowLaunchExecutor['execute'];\n parseWorkflow(workflowPath: string): Workflow;\n ui: WorkflowLauncherUi;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};\n}\n\nfunction workflowTriggerBlock(workflow: Workflow): Record<string, unknown> {\n return asRecord(workflow.on);\n}\n\nfunction dispatchInputs(workflow: Workflow): Record<string, DispatchInput> {\n const dispatch = workflowTriggerBlock(workflow)[WORKFLOW_DISPATCH_TRIGGER];\n if (dispatch === null || dispatch === undefined) return {};\n const parsed = workflowDispatchInputsSchema.safeParse(dispatch);\n if (!parsed.success) throw new Error(`Invalid workflow_dispatch input definitions: ${parsed.error.message}`);\n return parsed.data.inputs ?? {};\n}\n\nfunction launchResultError(result: CallToolResult): Error {\n return new Error(toolResultText(result) || 'Workflow launch failed.');\n}\n\nexport function parseWorkflowCatalogPage(result: CallToolResult): WorkflowCatalogPage {\n if (result.isError) throw launchResultError(result);\n let value: unknown;\n try {\n value = JSON.parse(toolResultText(result));\n } catch (cause) {\n throw new Error('Workflow catalog returned invalid JSON.', { cause });\n }\n const parsed = workflowCatalogPageSchema.safeParse(value);\n if (!parsed.success) throw new Error(`Workflow catalog response was invalid: ${parsed.error.message}`);\n return {\n directory: parsed.data.directory,\n hasNextPage: parsed.data.hasNextPage,\n page: parsed.data.page,\n pageSize: parsed.data.pageSize,\n workflows: parsed.data.workflows.map((entry) => ({\n description: entry.description,\n name: entry.name,\n path: resolve(parsed.data.directory, entry.path),\n relativePath: entry.path,\n tags: entry.tags,\n })),\n };\n}\n\nexport async function loadWorkflowCatalog(\n listWorkflowsTool: WorkflowListTool,\n directory: string,\n): Promise<WorkflowCatalogEntry[]> {\n const entries: WorkflowCatalogEntry[] = [];\n let page = 1;\n let hasNextPage = true;\n while (hasNextPage) {\n const input: WorkflowListInput = { directory, page, pageSize: CATALOG_PAGE_SIZE };\n const result = await listWorkflowsTool.execute(input);\n const catalogPage = parseWorkflowCatalogPage(result);\n entries.push(...catalogPage.workflows);\n hasNextPage = catalogPage.hasNextPage;\n page += 1;\n }\n return entries;\n}\n\nasync function requestPrompt(ui: WorkflowLauncherUi): Promise<string | undefined> {\n while (true) {\n const value = await ui.editor('Workflow prompt');\n if (value === undefined) return undefined;\n const prompt = value.trim();\n if (prompt) return prompt;\n ui.notify('A workflow prompt is required.', 'warning');\n }\n}\n\nasync function requestDispatchInput(\n ui: WorkflowLauncherUi,\n name: string,\n input: DispatchInput,\n): Promise<string | undefined> {\n const title = input.description ? `${name}: ${input.description}` : `Workflow input: ${name}`;\n if (input.options && input.options.length > 0) return ui.select(title, input.options);\n if (input.type === BOOLEAN_INPUT_TYPE) return ui.select(title, ['true', 'false']);\n\n while (true) {\n const value = await ui.input(title, input.default);\n if (value === undefined) return undefined;\n const normalized = value.trim() || input.default;\n if (normalized || !input.required) return normalized || undefined;\n ui.notify(`A value is required for workflow input ${name}.`, 'warning');\n }\n}\n\nexport async function collectWorkflowInputs(\n workflow: Workflow,\n ui: WorkflowLauncherUi,\n): Promise<{ inputs?: Record<string, string>; prompt?: string } | undefined> {\n const triggers = workflowTriggerBlock(workflow);\n const requiresPrompt = Object.hasOwn(triggers, USER_PROMPT_TRIGGER);\n const prompt = requiresPrompt ? await requestPrompt(ui) : undefined;\n if (requiresPrompt && prompt === undefined) return undefined;\n\n const definitions = dispatchInputs(workflow);\n const inputs: Record<string, string> = {};\n for (const [name, definition] of Object.entries(definitions)) {\n const value = await requestDispatchInput(ui, name, definition);\n if (value === undefined && definition.required) return undefined;\n if (value !== undefined) inputs[name] = value;\n }\n return {\n ...(prompt === undefined ? {} : { prompt }),\n ...(Object.keys(inputs).length === 0 ? {} : { inputs }),\n };\n}\n\n/**\n * Everything a launch needs once the workflow is chosen: the runner, the\n * prompt, and any `workflow_dispatch` inputs, each asked for through the\n * host's own dialogs. Selection is the caller's business - `SPC w l` launches\n * the row under its cursor, so this takes an entry rather than picking one.\n */\nfunction stepLabel(step: { name?: string; uses?: string; run?: unknown; id?: string }, index: number): string {\n if (step.name) return step.name;\n if (step.uses) return step.uses;\n if (step.id) return step.id;\n // A `run:` step without a name is identified by its position; printing the\n // command would put a shell line into a summary pane.\n return `step ${index + 1}`;\n}\n\nfunction catalogInputs(workflow: Workflow): WorkflowInputSummary[] {\n return Object.entries(dispatchInputs(workflow)).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n ...(definition.required === undefined ? {} : { required: definition.required }),\n ...(definition.default === undefined ? {} : { default: definition.default }),\n ...(definition.options ? { options: definition.options } : {}),\n }));\n}\n\nfunction catalogJobs(workflow: Workflow): WorkflowJobSummary[] {\n return Object.entries(workflow.jobs ?? {}).map(([name, job]) => ({\n name,\n steps: (job.steps ?? []).map((step, index) => stepLabel(step, index)),\n }));\n}\n\n/**\n * The parsed shape `SPC w l`'s detail pane shows. A parse failure is returned\n * as `error` rather than thrown: one unparseable file in a repository must not\n * take the whole board down.\n */\nexport function summarizeWorkflowFile(\n workflowPath: string,\n options: Pick<WorkflowEntryLaunchOptions, 'compatibleRunners' | 'parseWorkflow'>,\n): WorkflowCatalogDetail {\n try {\n const workflow = options.parseWorkflow(workflowPath);\n const runners = options.compatibleRunners(workflow);\n return {\n triggers: Object.keys(workflowTriggerBlock(workflow)),\n inputs: catalogInputs(workflow),\n jobs: catalogJobs(workflow),\n ...(runners ? { runners } : {}),\n };\n } catch (cause) {\n return {\n triggers: [],\n inputs: [],\n jobs: [],\n error: cause instanceof Error ? cause.message : String(cause),\n };\n }\n}\n\nexport async function launchWorkflowEntry(\n options: WorkflowEntryLaunchOptions,\n selected: Pick<WorkflowCatalogEntry, 'path'>,\n ctx: ExtensionContext,\n): Promise<CallToolResult | undefined> {\n const workflow = options.parseWorkflow(selected.path);\n const runners = options.compatibleRunners(workflow);\n if (runners && runners.length === 0) throw new Error('No compatible runner is available for this workflow.');\n let runner: string | undefined;\n if (runners) {\n runner = await options.ui.select('Select a workflow runner', runners);\n if (runner === undefined) return undefined;\n }\n\n const triggerInputs = await collectWorkflowInputs(workflow, options.ui);\n if (triggerInputs === undefined) return undefined;\n const launchInput: WorkflowLaunchInput = {\n workflowPath: selected.path,\n ...(runner === undefined ? {} : { runner }),\n ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n ...triggerInputs,\n };\n return options.launch(launchInput, ctx);\n}\n","import type { WorkflowRunRecord, WorkflowStage } from '@agimon-ai/workflow-mcp';\n\n/** Package-local narration sink; the Pi adapter binds it to the injected Cordis service. */\nexport interface WorkflowNarrationSink {\n narrate(text: string): void;\n}\n\nconst RUNNING_STAGE: WorkflowStage = 'running';\nconst COMPLETED_STAGE: WorkflowStage = 'completed';\nconst ERROR_STAGE: WorkflowStage = 'error';\n\ntype NarratedWorkflow = Pick<WorkflowRunRecord, 'displayName' | 'stage'>;\n\n/**\n * Translate an observed workflow lifecycle transition into generic speech.\n * Voice owns delivery and ignores requests while its minor mode is inactive.\n */\nexport function narrateWorkflowTransition(\n requester: WorkflowNarrationSink,\n record: NarratedWorkflow,\n previousStage: WorkflowStage | undefined,\n startedDuringSession: boolean,\n): void {\n const newlyLaunched = previousStage === undefined && startedDuringSession;\n if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);\n\n if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;\n if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);\n if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);\n}\n","import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nconst THOUSAND = 1000;\nconst MILLION = 1_000_000;\n/** Below this many tokens the \"k\" form keeps a decimal, above it rounds. */\nconst K_DECIMAL_LIMIT = 10_000;\n\n/** Compact token count, e.g. `812`, `4.2k`, `186k`, `1.3M`. */\nexport function formatTokens(value: number): string {\n if (value < THOUSAND) return String(value);\n if (value < MILLION) return `${(value / THOUSAND).toFixed(value < K_DECIMAL_LIMIT ? 1 : 0)}k`;\n return `${(value / MILLION).toFixed(1)}M`;\n}\n\nexport function fitLine(text: string, width: number): string {\n return truncateToWidth(text, Math.max(0, width), '');\n}\n\nexport function padLine(text: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const fitted = fitLine(text, safeWidth);\n return `${fitted}${' '.repeat(Math.max(0, safeWidth - visibleWidth(fitted)))}`;\n}\n\nexport function alignLine(left: string, right: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const rightWidth = visibleWidth(right);\n if (!right || rightWidth >= safeWidth) return fitLine(right || left, safeWidth);\n\n const maxLeftWidth = Math.max(0, safeWidth - rightWidth - 1);\n const fittedLeft = fitLine(left, maxLeftWidth);\n const gap = ' '.repeat(Math.max(1, safeWidth - visibleWidth(fittedLeft) - rightWidth));\n return fitLine(`${fittedLeft}${gap}${right}`, safeWidth);\n}\n\nexport function frameLine(content: string, width: number, left = '│', right = '│'): string {\n const safeWidth = Math.max(0, width);\n const frameWidth = visibleWidth(left) + visibleWidth(right);\n if (safeWidth <= frameWidth) return fitLine(`${left}${right}`, safeWidth);\n return `${left}${padLine(content, safeWidth - frameWidth)}${right}`;\n}\n\nexport function packSegments(segments: string[], width: number, separator = ' '): string[] {\n const safeWidth = Math.max(0, width);\n if (safeWidth === 0) return [];\n\n const lines: string[] = [];\n let current = '';\n for (const segment of segments) {\n const candidate = current ? `${current}${separator}${segment}` : segment;\n if (visibleWidth(candidate) <= safeWidth) {\n current = candidate;\n continue;\n }\n if (current) lines.push(fitLine(current, safeWidth));\n current = fitLine(segment, safeWidth);\n }\n if (current) lines.push(current);\n return lines;\n}\n","import type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport { fitLine, frameLine, padLine } from './rendering';\n\nconst DEFAULT_TERMINAL_ROWS = 24;\nconst FULL_CHROME_ROWS = 6;\n/** Two frame columns and two gutter columns, leaving content worth framing. */\nconst MIN_FRAMED_WIDTH = 8;\nconst GUTTER = ' ';\nconst GUTTER_COLUMNS = 2;\n/** Blank columns kept between a row's left cluster and its right-aligned status. */\nconst ROW_GAP = 2;\n/** A secondary segment thinner than this is dropped rather than shredded into a stub. */\nconst MIN_SEGMENT_WIDTH = 8;\nconst ELLIPSIS = '…';\nconst BORDER_COLOR = 'borderMuted';\nconst TEXT_COLOR = 'text';\n/** Filled key caps read as pressable, matching the doom mockups' footers. */\nconst HINT_CAP_BACKGROUND = 'selectedBg';\nconst HINT_SEPARATOR = ' ';\n/** A cap's two pad columns plus the space before its label. */\nconst HINT_CHROME_COLUMNS = 6;\nconst TITLE_COLOR = 'accent';\nconst SECONDARY_COLOR = 'dim';\nconst HORIZONTAL_BORDER = '─';\nconst VERTICAL_BORDER = '│';\nconst TOP_CORNERS = ['╭', '╮'] as const;\nconst DIVIDER_JOINTS = ['├', '┤'] as const;\nconst BOTTOM_CORNERS = ['╰', '╯'] as const;\n\nexport interface DoomOverlayTui {\n terminal?: {\n rows: number;\n columns?: number;\n };\n requestRender(force?: boolean): void;\n}\n\nexport interface DoomOverlayChrome {\n title: string;\n breadcrumb?: string;\n headerRight?: string;\n footer: string;\n footerRight?: string;\n /**\n * Key/label pairs rendered as filled caps, e.g. `[ enter ] edit subject`.\n * Takes precedence over `footer`, which stays for surfaces that want a plain\n * sentence rather than a key legend.\n */\n footerHints?: readonly (readonly [string, string])[];\n /**\n * Signature colour for the surface. When set, the frame takes it and the\n * title renders as a filled badge rather than plain accent text, matching the\n * doom mockups. Left unset, the frame stays muted and the title plain.\n */\n accent?: Parameters<Theme['fg']>[0];\n}\n\n/**\n * One signature colour for every doom overlay: the frame and the title badge.\n * Per-surface colours were tried and read as arbitrary, and they also borrowed\n * tokens that mean something else (`warning`, `syntaxNumber`), so a theme edit\n * elsewhere would have repainted a frame. Change it here to change them all.\n */\nexport const DOOM_OVERLAY_ACCENT = 'mdHeading' satisfies DoomOverlayChrome['accent'];\n\nexport const DOOM_FULLSCREEN_UI_OPTIONS = {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n} as const;\n\n/**\n * Fits a secondary segment into `budget`, or drops it entirely when too few\n * columns remain for it to stay readable. Truncating everything to fit is what\n * makes a tight header read as one run-on string.\n */\nfunction fitSegment(text: string | undefined, budget: number): string {\n if (!text || budget <= 0) return '';\n return budget < Math.min(visibleWidth(text), MIN_SEGMENT_WIDTH) ? '' : truncateToWidth(text, budget, ELLIPSIS);\n}\n\nexport abstract class DoomOverlay implements Component {\n protected constructor(\n protected readonly tui: DoomOverlayTui,\n protected readonly theme: Theme,\n ) {}\n\n invalidate(): void {\n this.tui.requestRender();\n }\n\n render(width: number): string[] {\n const safeWidth = Math.max(0, Math.floor(width));\n const height = Math.max(0, Math.floor(this.tui.terminal?.rows ?? DEFAULT_TERMINAL_ROWS));\n if (safeWidth === 0 || height === 0) return [];\n\n const chrome = this.getChrome();\n if (height < FULL_CHROME_ROWS || safeWidth < MIN_FRAMED_WIDTH) {\n return this.renderCompact(chrome, safeWidth, height);\n }\n\n const innerWidth = safeWidth - GUTTER_COLUMNS;\n const contentWidth = innerWidth - GUTTER_COLUMNS;\n const bodyHeight = height - FULL_CHROME_ROWS;\n const body = this.renderBody(contentWidth, bodyHeight).slice(0, bodyHeight);\n while (body.length < bodyHeight) body.push('');\n\n const frame = chrome.accent ?? BORDER_COLOR;\n return [\n this.borderRow(TOP_CORNERS, innerWidth, frame),\n this.contentRow(this.headerRow(chrome, contentWidth), contentWidth, safeWidth, frame),\n this.borderRow(DIVIDER_JOINTS, innerWidth, frame, BORDER_COLOR),\n ...body.map((line) => this.contentRow(line, contentWidth, safeWidth, frame)),\n this.borderRow(DIVIDER_JOINTS, innerWidth, frame, BORDER_COLOR),\n this.contentRow(this.footerRow(chrome, contentWidth), contentWidth, safeWidth, frame),\n this.borderRow(BOTTOM_CORNERS, innerWidth, frame),\n ].map((line) => padLine(line, safeWidth));\n }\n\n protected abstract getChrome(): DoomOverlayChrome;\n\n protected abstract renderBody(width: number, height: number): string[];\n\n /**\n * Edge glyphs and the rule between them are coloured separately: the outer\n * rectangle carries the signature colour while an internal separator stays\n * muted, meeting the frame at accent-coloured junctions.\n */\n private borderRow(\n [left, right]: readonly [string, string],\n innerWidth: number,\n edge: DoomOverlayChrome['accent'] = BORDER_COLOR,\n fill: DoomOverlayChrome['accent'] = edge,\n ): string {\n const edgeColour = edge ?? BORDER_COLOR;\n return [\n this.theme.fg(edgeColour, left),\n this.theme.fg(fill ?? edgeColour, HORIZONTAL_BORDER.repeat(innerWidth)),\n this.theme.fg(edgeColour, right),\n ].join('');\n }\n\n private contentRow(\n content: string,\n contentWidth: number,\n width: number,\n colour: DoomOverlayChrome['accent'] = BORDER_COLOR,\n ): string {\n const edge = this.theme.fg(colour ?? BORDER_COLOR, VERTICAL_BORDER);\n return frameLine(`${GUTTER}${padLine(content, contentWidth)}${GUTTER}`, width, edge, edge);\n }\n\n private headerRow(chrome: DoomOverlayChrome, width: number): string {\n // A signature colour turns the title into a filled badge, as the mockups\n // show; without one it stays plain accent text.\n const accent = chrome.accent;\n const titleBudget = accent ? width - GUTTER_COLUMNS : width;\n const title = truncateToWidth(chrome.title, Math.max(0, titleBudget), ELLIPSIS);\n let left = accent\n ? this.theme.inverse(this.theme.bold(this.theme.fg(accent, ` ${title} `)))\n : this.theme.bold(this.theme.fg(TITLE_COLOR, title));\n let leftWidth = visibleWidth(title) + (accent ? GUTTER_COLUMNS : 0);\n\n // The breadcrumb claims room before the right status: it says where you are,\n // which outranks ambient context when the terminal is narrow.\n const breadcrumb = fitSegment(chrome.breadcrumb, width - leftWidth - ROW_GAP);\n if (breadcrumb) {\n left += `${' '.repeat(ROW_GAP)}${this.theme.fg(SECONDARY_COLOR, breadcrumb)}`;\n leftWidth += ROW_GAP + visibleWidth(breadcrumb);\n }\n return this.withRightStatus(left, leftWidth, chrome.headerRight, width);\n }\n\n private footerRow(chrome: DoomOverlayChrome, width: number): string {\n const footer = chrome.footerHints?.length\n ? this.hintLegend(chrome.footerHints, width)\n : this.theme.fg(SECONDARY_COLOR, truncateToWidth(chrome.footer, width, ELLIPSIS));\n return this.withRightStatus(footer, visibleWidth(footer), chrome.footerRight, width);\n }\n\n /**\n * Key legend with each key in a filled cap. Every segment sets its own colour\n * so the caps survive: a cap's reset would otherwise strip the surrounding\n * dim from the labels that follow it.\n */\n private hintLegend(hints: readonly (readonly [string, string])[], width: number): string {\n let legend = '';\n let used = 0;\n for (const [key, label] of hints) {\n const segmentWidth = visibleWidth(key) + visibleWidth(label) + HINT_CHROME_COLUMNS;\n if (used + segmentWidth > width) break;\n const cap = this.theme.bg(HINT_CAP_BACKGROUND, this.theme.fg(TEXT_COLOR, ` ${key} `));\n legend += `${legend ? HINT_SEPARATOR : ''}${cap}${this.theme.fg(SECONDARY_COLOR, ` ${label}`)}`;\n used += segmentWidth;\n }\n return legend;\n }\n\n /**\n * Right-aligns a status cluster, dropping it whole when the row cannot spare\n * the columns. A clipped status reads as a stub (`doom-log…`) that carries\n * less than the blank space it costs.\n */\n private withRightStatus(left: string, leftWidth: number, right: string | undefined, width: number): string {\n const statusWidth = right ? visibleWidth(right) : 0;\n if (!right || statusWidth === 0 || leftWidth + ROW_GAP + statusWidth > width) return left;\n return `${left}${' '.repeat(width - leftWidth - statusWidth)}${this.theme.fg(SECONDARY_COLOR, right)}`;\n }\n\n private renderCompact(chrome: DoomOverlayChrome, width: number, height: number): string[] {\n const lines = Array.from({ length: height }, () => '');\n lines[0] = this.theme.bold(this.theme.fg(TITLE_COLOR, chrome.title));\n if (height > 1) lines[height - 1] = this.theme.fg(SECONDARY_COLOR, chrome.footer);\n return lines.map((line) => padLine(fitLine(line, width), width));\n }\n}\n","/**\n * Text primitives shared by every doom overlay in this extension.\n *\n * Kept in one place because each of them encodes a decision that has to hold on\n * every surface: how a cell is clipped, which end of a path survives, and what\n * counts as a keystroke that carries text.\n */\n\nimport { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nexport const ELLIPSIS = '…';\nexport const CURSOR_BLOCK = '█';\nexport const SELECTION_MARKER = '›';\n/** pi-tui brackets a truncation ellipsis with this; see `fit`. */\nconst HARD_RESET = '\\x1b[0m';\nconst ESCAPE = '\\x1b';\nconst FIRST_PRINTABLE_CODE_POINT = 0x20;\nconst DELETE_CODE_POINT = 0x7f;\n\n/**\n * Truncates and pads to an exact column count.\n *\n * `truncateToWidth` wraps its ellipsis in a hard `\\x1b[0m`, which would strip a\n * row's background for everything after a clipped cell. Nothing here sets a\n * colour that a full reset is the correct end for -- the theme closes its own\n * with `\\x1b[39m` and `\\x1b[49m` -- so the injected resets are dropped.\n */\nexport function fit(text: string, width: number): string {\n const clipped = truncateToWidth(text, Math.max(0, width), ELLIPSIS).replaceAll(HARD_RESET, '');\n return clipped + ' '.repeat(Math.max(0, width - visibleWidth(clipped)));\n}\n\n/**\n * Fits a line that carries its own colour, keeping every escape it contains.\n *\n * `fit` above drops hard resets, which is right for a themed row whose\n * background must survive a clipped cell and wrong for captured terminal\n * output: those resets are what END the child's colour runs, and deleting them\n * bleeds a colour through the rest of the panel. This closes the line with a\n * reset instead, before the padding, so no attribute escapes the row.\n */\nexport function fitTerminalLine(text: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const clipped = truncateToWidth(text, safeWidth, ELLIPSIS);\n const padding = ' '.repeat(Math.max(0, safeWidth - visibleWidth(clipped)));\n return clipped.includes(ESCAPE) ? `${clipped}${HARD_RESET}${padding}` : `${clipped}${padding}`;\n}\n\n/** Right-aligns a trailing cluster against a left one, both clipped to fit. */\nexport function rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fit(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fit(right, rightWidth);\n}\n\n/**\n * Trims from the front rather than the tail.\n *\n * For a path the file name identifies the thing, while the\n * `automations/marketing-workflows/` prefix every entry shares does not.\n */\nexport function pathTail(text: string, width: number): string {\n if (width <= 0) return '';\n if (visibleWidth(text) <= width) return text;\n return `${ELLIPSIS}${text.slice(text.length - Math.max(0, width - 1))}`;\n}\n\n/**\n * Keystrokes that carry no text: escape sequences, control keys, delete.\n *\n * Indexed rather than iterated so surrogate pairs stay intact; both halves sit\n * far above the control range, so no emoji is ever mistaken for one.\n */\nexport function isControlInput(data: string): boolean {\n for (let index = 0; index < data.length; index++) {\n const code = data.charCodeAt(index);\n if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;\n }\n return false;\n}\n\n/**\n * Whitespace-separated terms, each of which must appear somewhere in the row's\n * searchable text. Splitting on whitespace is what lets `short video` match a\n * row whose words are divided between its title and its file name.\n */\nexport function matchesQuery(haystack: string, query: string): boolean {\n const terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (terms.length === 0) return true;\n const lowered = haystack.toLowerCase();\n return terms.every((term) => lowered.includes(term));\n}\n","/**\n * The `SPC w l` board: every workflow this repository defines, with the cursor\n * workflow's parsed detail beside it and `r` to launch it.\n *\n * WHY NOT `workflowPicker.ts`:\n * That surface answers \"which one\", hands a value back, and closes - which is\n * what `SPC w c` recovery still needs. This one answers \"what is this workflow,\n * and do I want to run it\", so the detail has to be on screen next to the list\n * rather than behind a selection. The picker stays for the pick-and-return case\n * rather than growing a second mode.\n *\n * DESIGN PATTERNS:\n * - Detail is loaded through an injected loader, so parsing a workflow file\n * stays out of the TUI and the surface is assertable as text. Loaded on\n * demand for the cursor row and cached by row key: a repository with fifty\n * workflows must not parse fifty files to draw one pane\n * - A row is two lines, name over path. One line made the name - the field a\n * reader picks a row by - share a third of the overlay with a path that\n * repeats its directory on every row\n * - `/` opens the filter rather than plain letters filtering as they are typed:\n * the letter keys carry commands here (`r` launch, `t`/`i`/`s` tabs)\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport {\n CURSOR_BLOCK,\n ELLIPSIS,\n fit,\n isControlInput,\n matchesQuery,\n pathTail,\n rightAligned,\n SELECTION_MARKER,\n} from './overlayText';\n\nexport const WORKFLOW_CATALOG_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\n/** One workflow file, as the catalog tool reports it. */\nexport interface WorkflowCatalogRow {\n /** Stable identity and the loader's cache key: the absolute path. */\n key: string;\n name: string;\n relativePath: string;\n description: string;\n tags: readonly string[];\n}\n\nexport interface WorkflowInputSummary {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n options?: readonly string[];\n}\n\nexport interface WorkflowJobSummary {\n name: string;\n steps: readonly string[];\n}\n\n/**\n * What the detail pane shows for one workflow. `runners` is undefined when the\n * workflow names no runner map at all, which is not the same as naming an empty\n * one - see `compatibleRunners`.\n */\nexport interface WorkflowCatalogDetail {\n triggers: readonly string[];\n inputs: readonly WorkflowInputSummary[];\n jobs: readonly WorkflowJobSummary[];\n runners?: readonly string[];\n /** Set when the file could not be parsed; the pane shows this instead of guessing. */\n error?: string;\n}\n\nexport type WorkflowDetailLoader = (row: WorkflowCatalogRow) => WorkflowCatalogDetail;\n\n/** Starts one workflow and returns immediately; the overlay closes on launch. */\nexport type WorkflowLaunchDispatcher = (row: WorkflowCatalogRow) => void;\n\nexport interface WorkflowCatalogOptions {\n loadDetail: WorkflowDetailLoader;\n /** Absent until a composition root wires the launch key to a real launcher. */\n launchWorkflow?: WorkflowLaunchDispatcher;\n}\n\nexport type WorkflowDetailTab = 'triggers' | 'inputs' | 'steps';\n\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst TITLE = 'WORKFLOWS';\nconst BREADCRUMB = 'SPC › w / workflows › l / list';\nconst DIVIDER = '│';\nconst DEFAULT_PAGE_SIZE = 1;\nconst ROWS_PER_ENTRY = 2;\n/** Indent under `${SELECTION_MARKER} `, so the path line hangs under the name. */\nconst META_INDENT = ' ';\nconst EMPTY_NAME = '(unnamed)';\nconst LAUNCH_KEY = 'r';\nconst FILTER_KEY = '/';\nconst KEY_CLEAR = '\\x15';\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_MESSAGE = 'No workflow definitions were found in this repository.';\nconst TAB_ORDER: readonly WorkflowDetailTab[] = ['triggers', 'inputs', 'steps'];\nconst TAB_KEYS: Record<string, WorkflowDetailTab> = { t: 'triggers', i: 'inputs', s: 'steps' };\nconst FOOTER = '↑↓ cursor · JK scroll · tab detail · / filter · r launch · esc close';\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'move'],\n ['JK', 'scroll'],\n ['tab', 'cycle'],\n ['/', 'filter'],\n ['r', 'launch'],\n];\nconst FILTER_FOOTER = 'enter keep · esc clear · ctrl+u wipe';\nconst FILTER_FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['enter', 'keep'],\n ['esc', 'clear'],\n ['ctrl+u', 'wipe'],\n];\n\ninterface SplitLayout {\n leftContentWidth: number;\n rightContentWidth: number;\n gutterWidth: number;\n}\n\nfunction splitLayout(width: number): SplitLayout {\n const paneBudget = Math.max(2, width - visibleWidth(DIVIDER));\n const leftPaneWidth = Math.max(1, Math.floor(paneBudget / 3));\n const rightPaneWidth = Math.max(1, paneBudget - leftPaneWidth);\n const gutterWidth = leftPaneWidth >= 3 && rightPaneWidth >= 3 ? 1 : 0;\n return {\n leftContentWidth: Math.max(1, leftPaneWidth - gutterWidth),\n rightContentWidth: Math.max(1, rightPaneWidth - gutterWidth),\n gutterWidth,\n };\n}\n\nfunction appendWrapped(lines: string[], text: string, width: number, colour: ThemeColor, theme: Theme): void {\n for (const line of wrapTextWithAnsi(text, Math.max(1, width))) lines.push(theme.fg(colour, line));\n}\n\nfunction appendSection(lines: string[], heading: string, items: readonly string[], width: number, theme: Theme): void {\n lines.push(theme.bold(theme.fg('accent', heading)));\n if (items.length === 0) lines.push(theme.fg('dim', ' none'));\n else for (const item of items) appendWrapped(lines, ` • ${item}`, width, 'text', theme);\n lines.push('');\n}\n\nfunction inputLabel(input: WorkflowInputSummary): string {\n const qualifiers = [\n input.required ? 'required' : 'optional',\n input.default === undefined ? undefined : `default ${input.default}`,\n input.options && input.options.length > 0 ? `one of ${input.options.join(', ')}` : undefined,\n ].filter((part): part is string => Boolean(part));\n const description = input.description ? `${input.description} · ` : '';\n return `${input.name} — ${description}${qualifiers.join(' · ')}`;\n}\n\nexport function workflowDetailLines(\n detail: WorkflowCatalogDetail,\n tab: WorkflowDetailTab,\n width: number,\n theme: Theme,\n): string[] {\n const lines: string[] = [];\n if (detail.error) {\n lines.push(theme.bold(theme.fg('error', 'WORKFLOW ERROR')));\n appendWrapped(lines, detail.error, width, 'error', theme);\n lines.push('');\n return lines;\n }\n if (tab === 'triggers') {\n appendSection(lines, 'TRIGGERS', detail.triggers, width, theme);\n // No runner map means every runner qualifies, which a bare \"none\" would\n // report as the opposite.\n appendSection(lines, 'RUNNERS', detail.runners ?? ['any available runner'], width, theme);\n return lines;\n }\n if (tab === 'inputs') {\n appendSection(lines, 'DISPATCH INPUTS', detail.inputs.map(inputLabel), width, theme);\n return lines;\n }\n for (const job of detail.jobs) {\n lines.push(theme.bold(theme.fg('accent', job.name)));\n if (job.steps.length === 0) lines.push(theme.fg('dim', ' no steps'));\n else for (const step of job.steps) appendWrapped(lines, ` • ${step}`, width, 'text', theme);\n lines.push('');\n }\n if (detail.jobs.length === 0) appendSection(lines, 'JOBS', [], width, theme);\n return lines;\n}\n\nfunction tabStrip(tab: WorkflowDetailTab, width: number, theme: Theme): string {\n const labels = TAB_ORDER.map((candidate) => {\n const label = candidate.toUpperCase();\n return candidate === tab ? theme.inverse(theme.bold(` ${label} `)) : theme.fg('dim', ` ${label} `);\n }).join(' ');\n return truncateToWidth(labels, Math.max(0, width), ELLIPSIS);\n}\n\nexport function filterWorkflowRows(rows: readonly WorkflowCatalogRow[], query: string): readonly WorkflowCatalogRow[] {\n if (!query.trim()) return rows;\n return rows.filter((row) =>\n matchesQuery([row.name, row.relativePath, row.description, row.tags.join(' ')].join(' '), query),\n );\n}\n\nexport class WorkflowCatalogComponent extends DoomOverlay {\n private readonly rows: readonly WorkflowCatalogRow[];\n private readonly detailCache = new Map<string, WorkflowCatalogDetail>();\n private cursorIndex = 0;\n private tab: WorkflowDetailTab = 'triggers';\n private query = '';\n private filtering = false;\n private notice: string | undefined;\n private listPageSize = DEFAULT_PAGE_SIZE;\n private detailPageSize = DEFAULT_PAGE_SIZE;\n private detailOffset = 0;\n private detailTotal = 0;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n rows: readonly WorkflowCatalogRow[],\n private readonly done: (result: undefined) => void,\n private readonly options: WorkflowCatalogOptions,\n ) {\n super(tui, theme);\n this.rows = [...rows].sort((left, right) => left.name.localeCompare(right.name));\n }\n\n private matches(): readonly WorkflowCatalogRow[] {\n return filterWorkflowRows(this.rows, this.query);\n }\n\n private cursorRow(): WorkflowCatalogRow | undefined {\n const matches = this.matches();\n return matches[Math.min(this.cursorIndex, Math.max(0, matches.length - 1))];\n }\n\n /** Parsed once per workflow, then reused for every repaint of that row. */\n private detailFor(row: WorkflowCatalogRow): WorkflowCatalogDetail {\n const cached = this.detailCache.get(row.key);\n if (cached) return cached;\n const detail = this.options.loadDetail(row);\n this.detailCache.set(row.key, detail);\n return detail;\n }\n\n private moveCursor(delta: number): void {\n const count = this.matches().length;\n if (count === 0) return;\n const next = Math.max(0, Math.min(count - 1, this.cursorIndex + delta));\n if (next === this.cursorIndex) return;\n this.cursorIndex = next;\n // The detail pane follows the cursor, so its scroll belonged to the row\n // that was showing, not the one replacing it.\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private switchTab(tab: WorkflowDetailTab): void {\n if (this.tab === tab) return;\n this.tab = tab;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private cycleTab(): void {\n const current = TAB_ORDER.indexOf(this.tab);\n this.switchTab(TAB_ORDER[(current + 1) % TAB_ORDER.length] ?? 'triggers');\n }\n\n private scrollDetail(delta: number): void {\n if (!this.cursorRow()) return;\n const maximum = Math.max(0, this.detailTotal - this.detailPageSize);\n const next = Math.max(0, Math.min(maximum, this.detailOffset + delta));\n if (next === this.detailOffset) return;\n this.detailOffset = next;\n this.invalidate();\n }\n\n private setNotice(notice: string): void {\n this.notice = notice;\n this.invalidate();\n }\n\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n // The previous index named a row this filter may no longer list.\n this.cursorIndex = 0;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private launchCursor(): void {\n const row = this.cursorRow();\n if (!row) {\n this.setNotice('launch unavailable · no workflow is selected');\n return;\n }\n const launchWorkflow = this.options.launchWorkflow;\n if (!launchWorkflow) {\n this.setNotice('launch unavailable · no workflow launcher is attached');\n return;\n }\n const detail = this.detailFor(row);\n if (detail.error) {\n this.setNotice(`launch unavailable · ${detail.error}`);\n return;\n }\n // Closing first is what makes the launcher's own prompts reachable: they\n // are host dialogs, and a fullscreen overlay sits over them.\n this.done(undefined);\n launchWorkflow(row);\n }\n\n private handleFilterInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.filtering = false;\n this.setQuery('');\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'enter')) {\n this.filtering = false;\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'backspace')) {\n this.setQuery(this.query.slice(0, -1));\n return;\n }\n if (data === KEY_CLEAR) {\n this.setQuery('');\n return;\n }\n if (!isControlInput(data)) this.setQuery(this.query + data);\n }\n\n handleInput(data: string): void {\n if (this.filtering) {\n this.handleFilterInput(data);\n return;\n }\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, Key.shift('k'))) return this.scrollDetail(-1);\n if (matchesKey(data, Key.shift('j'))) return this.scrollDetail(1);\n if (matchesKey(data, 'up') || data === 'k') return this.moveCursor(-1);\n if (matchesKey(data, 'down') || data === 'j') return this.moveCursor(1);\n if (matchesKey(data, 'pageUp')) return this.moveCursor(-this.listPageSize);\n if (matchesKey(data, 'pageDown')) return this.moveCursor(this.listPageSize);\n if (matchesKey(data, 'tab')) return this.cycleTab();\n if (data === FILTER_KEY) {\n this.filtering = true;\n this.notice = undefined;\n this.invalidate();\n return;\n }\n if (data === LAUNCH_KEY) return this.launchCursor();\n const tab = TAB_KEYS[data];\n if (tab) this.switchTab(tab);\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${scope} workflows · ${this.tab}`,\n footer: this.filtering ? FILTER_FOOTER : FOOTER,\n footerHints: this.filtering ? FILTER_FOOTER_HINTS : FOOTER_HINTS,\n footerRight: matches.length\n ? `${Math.min(this.cursorIndex, matches.length - 1) + 1}/${matches.length}`\n : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const filterRows = this.filtering || this.query ? 1 : 0;\n const transientRows = filterRows + (this.notice === undefined ? 0 : 1);\n const mainHeight = Math.max(0, height - transientRows);\n const layout = splitLayout(width);\n const left = this.renderList(layout.leftContentWidth, mainHeight);\n const right = this.renderDetail(layout.rightContentWidth, mainHeight);\n const gutter = ' '.repeat(layout.gutterWidth);\n const divider = this.theme.fg('borderMuted', DIVIDER);\n const lines: string[] = [];\n for (let index = 0; index < mainHeight; index++) {\n lines.push(\n `${fit(left[index] ?? '', layout.leftContentWidth)}${gutter}${divider}${gutter}${fit(\n right[index] ?? '',\n layout.rightContentWidth,\n )}`,\n );\n }\n if (filterRows) {\n const value = this.filtering ? `${this.query}${CURSOR_BLOCK}` : this.query;\n lines.push(` ${this.theme.bold(this.theme.fg('accent', FILTER_LABEL))} ${value}`);\n }\n if (this.notice !== undefined) lines.push(` ${this.theme.fg('muted', this.notice)}`);\n return lines.slice(0, height).map((line) => fit(line, width));\n }\n\n private renderList(width: number, height: number): string[] {\n const matches = this.matches();\n const lines = [this.theme.bold(this.theme.fg('accent', `WORKFLOWS ${matches.length}`))];\n if (matches.length === 0) {\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'dim',\n this.theme,\n );\n this.listPageSize = DEFAULT_PAGE_SIZE;\n return lines.slice(0, height);\n }\n\n this.listPageSize = Math.max(DEFAULT_PAGE_SIZE, Math.floor((height - 1) / ROWS_PER_ENTRY));\n const active = Math.min(this.cursorIndex, matches.length - 1);\n const start = Math.max(\n 0,\n Math.min(active - this.listPageSize + 1, Math.max(0, matches.length - this.listPageSize)),\n );\n for (const [offset, row] of matches.slice(start, start + this.listPageSize).entries()) {\n const current = start + offset === active;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const label = row.name || EMPTY_NAME;\n const name = current ? this.theme.bold(this.theme.fg('accent', label)) : this.theme.fg('text', label);\n const meta = this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, width - META_INDENT.length)));\n lines.push(fit(`${marker} ${name}`, width));\n lines.push(fit(`${META_INDENT}${meta}`, width));\n }\n return lines.slice(0, height);\n }\n\n private renderDetail(width: number, height: number): string[] {\n const row = this.cursorRow();\n if (!row) {\n this.detailTotal = 0;\n this.detailPageSize = Math.max(DEFAULT_PAGE_SIZE, height);\n this.detailOffset = 0;\n const lines = [this.theme.bold(this.theme.fg('accent', 'WORKFLOW DETAIL')), ''];\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'text',\n this.theme,\n );\n return lines.slice(0, height);\n }\n\n const header = [\n rightAligned(\n this.theme.bold(this.theme.fg('accent', `INSPECTING ${row.name || EMPTY_NAME}`)),\n this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, Math.floor(width / 2)))),\n width,\n ),\n ];\n if (row.description) appendWrapped(header, row.description, width, 'text', this.theme);\n if (row.tags.length > 0) appendWrapped(header, row.tags.join(' · '), width, 'dim', this.theme);\n header.push(tabStrip(this.tab, width, this.theme), '');\n\n const body = workflowDetailLines(this.detailFor(row), this.tab, width, this.theme);\n this.detailPageSize = Math.max(0, height - header.length);\n this.detailTotal = body.length;\n this.detailOffset = Math.min(this.detailOffset, Math.max(0, body.length - this.detailPageSize));\n return [...header, ...body.slice(this.detailOffset, this.detailOffset + this.detailPageSize)].slice(0, height);\n }\n}\n\nexport async function openWorkflowCatalogOverlay(\n ctx: ExtensionContext,\n rows: readonly WorkflowCatalogRow[],\n options: WorkflowCatalogOptions,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new WorkflowCatalogComponent(tui, theme, rows, done, options),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Renders the `workflow-run-finished` custom message: one line per run that\n * reached a terminal state, rather than the host's default block of the\n * `[workflow-run-finished]` label above raw markdown.\n *\n * The same shape `@agimon-ai/doompi-team` gives a slash launch: a status glyph,\n * the run's identity, its outcome, and anything that went wrong indented under\n * it. A finished run is read at a glance in a transcript that is mostly about\n * something else, so it earns a line, not a card.\n *\n * DESIGN PATTERNS:\n * - A message with no `details` renders its content verbatim. That is a\n * transcript entry written before the field existed, and re-deriving it by\n * parsing the summary back out of markdown is exactly the liability\n * `completionNotice.ts` in the team package refused to port\n * - The full summary is still the message's `content`, which is what the model\n * reads and what `deliverAs: 'steer'` carries. This changes what a person\n * sees, never what the agent is told\n */\n\nimport type { ExtensionAPI, Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, Text } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_FINISHED_MESSAGE = 'workflow-run-finished';\n\n/** One finished run, as the extension records it on the message. */\nexport interface WorkflowFinishedRun {\n runKey: string;\n workspace: string;\n stage: string;\n workflowId?: string;\n failedJob?: string;\n error?: string;\n}\n\nexport interface WorkflowFinishedDetails {\n /** Kept for readers that already index runs by id; the lines come from `runs`. */\n runIds?: string[];\n runs?: WorkflowFinishedRun[];\n}\n\nconst COMPLETED_STAGE = 'completed';\nconst HELD_STAGES = new Set(['stopped', 'paused', 'cancelled']);\n\nfunction statusIcon(stage: string, theme: Theme): string {\n if (stage === COMPLETED_STAGE) return theme.fg('success', '✔');\n // Held is not failed: the run went nowhere wrong, it just stopped short.\n if (HELD_STAGES.has(stage)) return theme.fg('warning', '■');\n return theme.fg('error', '✖');\n}\n\nfunction runLine(run: WorkflowFinishedRun, theme: Theme): string {\n const separator = ` ${theme.fg('dim', '·')} `;\n const identity = [run.runKey, run.workspace].filter(Boolean).join('/');\n const parts = [theme.fg('dim', identity), theme.fg('dim', run.stage)];\n if (run.workflowId) parts.unshift(theme.bold(run.workflowId));\n let text = `${statusIcon(run.stage, theme)} ${parts.join(separator)}`;\n if (run.failedJob) text += `\\n ${theme.fg('dim', `⎿ failed job: ${run.failedJob}`)}`;\n if (run.error) text += `\\n ${theme.fg('dim', `⎿ ${run.error}`)}`;\n return text;\n}\n\n/**\n * Exported for tests: the rendered string before it is wrapped in a `Text`\n * component, so the formatting is assertable without a terminal.\n */\nexport function renderWorkflowFinished(runs: readonly WorkflowFinishedRun[], theme: Theme): string {\n return runs.map((run) => runLine(run, theme)).join('\\n');\n}\n\nexport function isWorkflowFinishedRuns(value: unknown): value is WorkflowFinishedRun[] {\n if (!Array.isArray(value) || value.length === 0) return false;\n return value.every(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as WorkflowFinishedRun).runKey === 'string' &&\n typeof (entry as WorkflowFinishedRun).stage === 'string',\n );\n}\n\nexport function createWorkflowFinishedRenderer(): readonly [...Parameters<ExtensionAPI['registerMessageRenderer']>] {\n return [\n WORKFLOW_FINISHED_MESSAGE,\n (message, _options, theme: Theme): Component => {\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n const runs = (message.details as WorkflowFinishedDetails | undefined)?.runs;\n if (!isWorkflowFinishedRuns(runs)) return new Text(content, 0, 0);\n return new Text(renderWorkflowFinished(runs, theme), 0, 0);\n },\n ];\n}\n","/**\n * Session reporting for a run's progress log.\n *\n * DESIGN PATTERNS:\n * - Pure derivation. Takes a run's raw progress events and returns report lines,\n * so the behaviour is unit-testable without a registry or a live run.\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported members\n *\n * Live progress now renders through `workflowProgressOverlay.ts`. This module\n * remains the compatibility derivation used by terminal summaries and legacy\n * workflow-step cards already persisted in older sessions.\n */\n\nimport type { WorkflowProgressEvent } from '@agimon-ai/workflow-mcp';\n\n/** Step names come from workflow YAML and can be sentences. */\nconst MAX_STEP_LABEL = 48;\n\n/** One session line, plus the key that stops it being reported twice. */\nexport interface StepReport {\n duration?: string;\n job: string;\n key: string;\n status: 'FAILED' | 'FINISHED' | 'STARTED';\n step: string;\n}\n\nfunction truncateStep(step: string): string {\n return step.length <= MAX_STEP_LABEL ? step : `${step.slice(0, MAX_STEP_LABEL - 1)}…`;\n}\n\n/**\n * Human-scale duration.\n *\n * Rounded hard on purpose: this is read at a glance next to a step name, where\n * milliseconds are noise and \"4m12s\" answers the only question being asked.\n */\nexport function humanizeDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '?';\n if (ms < 1000) return `${ms}ms`;\n const seconds = Math.round(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m${String(seconds % 60).padStart(2, '0')}s`;\n return `${Math.floor(minutes / 60)}h${String(minutes % 60).padStart(2, '0')}m`;\n}\n\n/**\n * Turn a run's raw progress log into session report lines.\n *\n * Derives durations by pairing each step's start with its end rather than\n * recording a duration in the log, so nothing about the log format has to\n * change and old runs read back the same way.\n *\n * Keyed by the event's own timestamp so a caller polling the same append-only\n * file repeatedly reports each transition exactly once, however often it polls.\n */\nexport function stepReportLines(runKey: string, events: WorkflowProgressEvent[]): StepReport[] {\n const startedAt = new Map<string, string>();\n const reports: StepReport[] = [];\n\n for (const event of events) {\n if (event.type !== 'step' || !event.step) continue;\n const id = `${runKey}/${event.job}`;\n const stepKey = `${id}/${event.step}`;\n const label = truncateStep(event.step);\n\n if (event.status === 'running') {\n startedAt.set(stepKey, event.at);\n reports.push({ job: event.job, key: `started:${stepKey}:${event.at}`, status: 'STARTED', step: label });\n continue;\n }\n\n const began = startedAt.get(stepKey);\n const duration = began ? humanizeDuration(Date.parse(event.at) - Date.parse(began)) : '?';\n // A failed step did finish, but calling it FINISHED buries the one outcome\n // the reader needs to see. Same shape, honest verb.\n const status = event.status === 'failed' ? 'FAILED' : 'FINISHED';\n reports.push({ duration, job: event.job, key: `${status}:${stepKey}:${event.at}`, status, step: label });\n }\n\n return reports;\n}\n","/**\n * Workflow Space: the `SPC w l` overlay.\n *\n * A doom overlay rather than a hand-rolled frame: the roster owns the left\n * third, the run under the cursor owns the right two thirds, and the chrome is\n * the same frame, breadcrumb and key legend every other doom surface draws.\n *\n * Rendering is pure -- `renderBody(width, height)` reads the last polled\n * snapshot and returns lines with no side effects -- so the surface can be\n * asserted as text without a live terminal.\n */\n\nimport { currentWorkflowPosition, type WorkflowProgressJob } from '@agimon-ai/workflow-mcp';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fitTerminalLine } from './overlayText';\nimport { humanizeDuration } from './workflowStatusRow';\n\nexport const WORKFLOW_INSPECTOR_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nexport interface WorkflowInspectorSelection {\n runId?: string;\n runKey: string;\n startedAt: string;\n workspace: string;\n}\n\nexport interface WorkflowInspectorItem extends WorkflowInspectorSelection {\n displayName: string;\n executionState?: string;\n jobs: WorkflowProgressJob[];\n key: string;\n output: string[];\n}\n\nexport interface WorkflowInspectorSource {\n list(): Promise<WorkflowInspectorItem[]>;\n output(item: WorkflowInspectorItem): Promise<string[]>;\n}\n\nexport interface WorkflowInspectorOptions {\n initialKey?: string;\n refreshMs?: number;\n}\n\nconst TITLE = 'WORKFLOW SPACE';\nconst BREADCRUMB = 'SPC › w / workflows › l / manage';\nconst ROSTER_HEADING = 'RUNNING · this session';\nconst EMPTY_ROSTER = 'No active workflows';\nconst PROGRESS_HEADING = 'PROGRESS';\nconst OUTPUT_HEADING = 'OUTPUT · newest last';\nconst NO_SELECTION = 'Select a workflow to inspect its jobs and output.';\nconst RUNNING_STATE = 'running';\nconst PAUSED_STATE = 'paused';\n/** Mirrors DoomPi's list-navigation legend without adding a runtime doompi-ui dependency. */\nconst LIST_NAVIGATION_KEYS = '↑↓';\nconst FOOTER = `${LIST_NAVIGATION_KEYS} select · PgUp/PgDn page · enter open · esc close`;\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n [LIST_NAVIGATION_KEYS, 'select'],\n ['PgUp/PgDn', 'page'],\n ['enter', 'open'],\n ['esc', 'close'],\n];\n\nconst DEFAULT_REFRESH_MS = 750;\nconst SELECTION_MARKER = '›';\nconst ELLIPSIS = '…';\n/** pi-tui brackets a truncation ellipsis with this; see `fit`. */\nconst HARD_RESET = '\\x1b[0m';\n/** A third for the roster, two thirds for the run being read. */\nconst LIST_PANE_RATIO = 1 / 3;\n/** One blank column each side of the divider so neither pane touches it. */\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\n/** Below this the roster cannot hold a readable name, so the detail takes the body. */\nconst MIN_TWO_PANE_WIDTH = 48;\n/** Each run occupies a name row and a state row beneath it. */\nconst ROWS_PER_ITEM = 2;\n/** Hanging indent for the state row: clears the marker and the glyph. */\nconst META_INDENT = 4;\n/** Rows the roster heading and its spacer take. */\nconst ROSTER_CHROME_ROWS = 2;\n/** The output tail keeps at least this many rows, or it is not worth a divider. */\nconst MIN_OUTPUT_ROWS = 2;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\n/**\n * Truncates and pads to an exact column count.\n *\n * `truncateToWidth` wraps its ellipsis in a hard `\\x1b[0m`, which would strip a\n * row's background for everything after a clipped name. The theme closes its own\n * colours with `\\x1b[39m` and `\\x1b[49m`, so the injected resets are dropped.\n */\nfunction fit(text: string, width: number): string {\n const clipped = truncateToWidth(text, Math.max(0, width), ELLIPSIS).replaceAll(HARD_RESET, '');\n return clipped + ' '.repeat(Math.max(0, width - visibleWidth(clipped)));\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fit(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fit(right, rightWidth);\n}\n\nfunction jobGlyph(status: string): string {\n return status === 'completed' ? '✓' : status === 'failed' ? '✗' : '●';\n}\n\nfunction jobColour(status: string): ThemeColor {\n return status === 'completed' ? 'success' : status === 'failed' ? 'error' : 'accent';\n}\n\nfunction progressLines(item: WorkflowInspectorItem, width: number, theme: Theme): string[] {\n const lines: string[] = [];\n for (const job of item.jobs) {\n const position = job.total ? ` · ${(job.index ?? 0) + 1}/${job.total}` : '';\n lines.push(\n truncateToWidth(\n theme.fg(jobColour(job.status), `${jobGlyph(job.status)} ${job.name}`) + theme.fg('dim', position),\n width,\n ELLIPSIS,\n ),\n );\n // Only the running job's steps: every finished job's steps would push the\n // live one off the pane, which is the one thing worth watching.\n if (job.status !== RUNNING_STATE) continue;\n for (const step of job.steps) {\n const stepColour: ThemeColor =\n step.status === 'failed' ? 'error' : step.status === RUNNING_STATE ? 'muted' : 'dim';\n lines.push(truncateToWidth(theme.fg(stepColour, ` ${jobGlyph(step.status)} ${step.name}`), width, ELLIPSIS));\n }\n }\n return lines;\n}\n\nfunction detailLines(item: WorkflowInspectorItem | undefined, width: number, height: number, theme: Theme): string[] {\n if (!item) return [theme.fg('dim', NO_SELECTION)];\n\n const position = currentWorkflowPosition(item.jobs);\n const elapsed = humanizeDuration(Math.max(0, Date.now() - Date.parse(item.startedAt)));\n const executionState = item.executionState ?? RUNNING_STATE;\n const stateColour: ThemeColor = executionState === PAUSED_STATE ? 'warning' : 'dim';\n const lines = [\n rightAligned(\n `${theme.fg('accent', '●')} ${theme.bold(item.displayName)}`,\n theme.fg(stateColour, executionState),\n width,\n ),\n truncateToWidth(theme.fg('dim', `${item.runKey} · ${item.workspace} · ${elapsed}`), width, ELLIPSIS),\n position\n ? truncateToWidth(\n `${theme.fg('accent', position.job)}${position.step ? theme.fg('muted', ` · ${position.step}`) : ''}`,\n width,\n ELLIPSIS,\n )\n : theme.fg('dim', 'starting'),\n '',\n theme.fg('dim', PROGRESS_HEADING),\n ];\n\n // The output tail claims its rows first: progress is a list that can be paged\n // to by opening the run, while the tail is the only live signal on screen.\n const reservedOutput = item.output.length > 0 ? MIN_OUTPUT_ROWS + 1 : 0;\n const progressRoom = Math.max(0, height - lines.length - reservedOutput);\n lines.push(...progressLines(item, width, theme).slice(0, progressRoom));\n\n if (item.output.length > 0 && height - lines.length >= MIN_OUTPUT_ROWS) {\n lines.push('', theme.fg('dim', OUTPUT_HEADING));\n const outputRoom = Math.max(0, height - lines.length);\n // Captured output carries the run's own colour, so it is fitted by the\n // escape-preserving path: `fit` below drops hard resets, and a capture that\n // lost its reset bleeds its colour through the divider and down the pane.\n lines.push(...item.output.slice(-outputRoom).map((line) => fitTerminalLine(line, width)));\n }\n\n return lines.slice(0, height);\n}\n\nexport class WorkflowInspectorComponent extends DoomOverlay {\n private bodyHeight = 8;\n private completed = false;\n private error: string | undefined;\n private items: WorkflowInspectorItem[] = [];\n private refreshActive = false;\n private selected = 0;\n private selectedKey: string | undefined;\n private readonly timer: ReturnType<typeof setInterval>;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly source: WorkflowInspectorSource,\n private readonly done: (selection: WorkflowInspectorSelection | undefined) => void,\n options: WorkflowInspectorOptions = {},\n ) {\n super(tui, theme);\n this.selectedKey = options.initialKey;\n void this.refresh();\n this.timer = setInterval(() => void this.refresh(), options.refreshMs ?? DEFAULT_REFRESH_MS);\n this.timer.unref?.();\n }\n\n private async refresh(): Promise<void> {\n if (this.refreshActive || this.completed) return;\n this.refreshActive = true;\n try {\n const previousKey = this.items[this.selected]?.key ?? this.selectedKey;\n const items = await this.source.list();\n if (this.completed) return;\n const preserved = previousKey ? items.findIndex((item) => item.key === previousKey) : -1;\n this.items = items;\n this.selected = preserved >= 0 ? preserved : Math.min(this.selected, Math.max(0, items.length - 1));\n this.selectedKey = items[this.selected]?.key;\n const selected = items[this.selected];\n if (selected) selected.output = await this.source.output(selected);\n this.error = undefined;\n if (!this.completed) this.tui.requestRender();\n } catch (cause) {\n this.error = cause instanceof Error ? cause.message : String(cause);\n if (!this.completed) this.tui.requestRender();\n } finally {\n this.refreshActive = false;\n }\n }\n\n private move(delta: number): void {\n if (this.items.length === 0) return;\n this.selected = Math.max(0, Math.min(this.items.length - 1, this.selected + delta));\n this.selectedKey = this.items[this.selected]?.key;\n void this.refreshSelectedOutput();\n this.tui.requestRender();\n }\n\n private async refreshSelectedOutput(): Promise<void> {\n const selected = this.items[this.selected];\n if (!selected || this.completed) return;\n try {\n selected.output = await this.source.output(selected);\n this.error = undefined;\n } catch (cause) {\n this.error = cause instanceof Error ? cause.message : String(cause);\n }\n if (!this.completed && selected.key === this.selectedKey) this.tui.requestRender();\n }\n\n private finish(selection: WorkflowInspectorSelection | undefined): void {\n if (this.completed) return;\n this.completed = true;\n clearInterval(this.timer);\n this.done(selection);\n }\n\n close(): void {\n this.finish(undefined);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.finish(undefined);\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n this.move(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n this.move(1);\n return;\n }\n if (matchesKey(data, 'pageUp')) {\n this.move(-this.rosterCapacity());\n return;\n }\n if (matchesKey(data, 'pageDown')) {\n this.move(this.rosterCapacity());\n return;\n }\n if (matchesKey(data, 'enter')) {\n const selected = this.items[this.selected];\n if (selected) {\n this.finish({\n ...(selected.runId ? { runId: selected.runId } : {}),\n runKey: selected.runKey,\n startedAt: selected.startedAt,\n workspace: selected.workspace,\n });\n }\n }\n }\n\n /** Runs the roster can draw, which is also what a page key moves by. */\n private rosterCapacity(): number {\n return Math.max(1, Math.floor((this.bodyHeight - ROSTER_CHROME_ROWS) / ROWS_PER_ITEM));\n }\n\n private current(): WorkflowInspectorItem | undefined {\n if (this.items.length === 0) return undefined;\n return this.items[Math.min(this.selected, this.items.length - 1)];\n }\n\n protected getChrome(): DoomOverlayChrome {\n const selected = this.current();\n const summary = selected\n ? `${selected.displayName} · ${selected.executionState ?? RUNNING_STATE}`\n : 'no active workflows';\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${this.items.length} running · ${summary}`,\n footer: FOOTER,\n footerHints: FOOTER_HINTS,\n footerRight:\n this.items.length > 0 ? `${Math.min(this.selected, this.items.length - 1) + 1}/${this.items.length}` : 'empty',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n this.bodyHeight = height;\n const detailFor = (paneWidth: number): string[] =>\n this.error\n ? [this.theme.fg('warning', `Unable to refresh workflows: ${this.error}`)]\n : detailLines(this.current(), paneWidth, height, this.theme);\n\n // Too narrow for two useful columns: the detail takes the whole body rather\n // than shredding both panes into stubs.\n if (width < MIN_TWO_PANE_WIDTH) return detailFor(width).slice(0, height);\n\n const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * LIST_PANE_RATIO));\n const rightWidth = Math.max(1, width - leftWidth - 1);\n const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n\n const left = this.rosterLines(leftContent);\n const right = detailFor(rightContent);\n const divider = this.theme.fg('borderMuted', '│');\n return Array.from({ length: height }, (_, index) => {\n // The roster keeps `fit`, whose reset stripping protects its row\n // backgrounds; the detail pane has none and may carry captured colour.\n const row = `${fit(left[index] ?? '', leftContent)} ${divider} ${fitTerminalLine(\n right[index] ?? '',\n rightContent,\n )}`;\n return truncateToWidth(row, width, ELLIPSIS);\n });\n }\n\n private rosterLines(width: number): string[] {\n const lines = [this.theme.bold(ROSTER_HEADING), ''];\n if (this.items.length === 0) {\n lines.push(this.theme.fg('dim', EMPTY_ROSTER));\n return lines;\n }\n\n // Two rows per run: at a third of the width a single row left the name with\n // a handful of columns once the stage took its share.\n const budget = this.rosterCapacity();\n const active = Math.min(this.selected, this.items.length - 1);\n const start = Math.max(0, Math.min(active - budget + 1, Math.max(0, this.items.length - budget)));\n for (const [offset, item] of this.items.slice(start, start + budget).entries()) {\n const current = start + offset === active;\n const paused = item.executionState === PAUSED_STATE;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const glyph = this.theme.fg(paused ? 'warning' : 'accent', '●');\n const name = current ? this.theme.bold(item.displayName) : item.displayName;\n const stage = paused ? PAUSED_STATE : (currentWorkflowPosition(item.jobs)?.job ?? 'starting');\n const heading = `${marker} ${glyph} ${name}`;\n const meta = `${' '.repeat(META_INDENT)}${this.theme.fg(paused ? 'warning' : 'dim', stage)}`;\n const background: ThemeBg = current ? 'selectedBg' : 'userMessageBg';\n for (const row of [heading, meta]) lines.push(this.theme.bg(background, fit(row, width)));\n }\n return lines;\n }\n\n /** Overridden: a repaint request is also the cue to re-read the registry. */\n invalidate(): void {\n void this.refresh();\n }\n\n dispose(): void {\n if (this.completed) return;\n this.completed = true;\n clearInterval(this.timer);\n }\n}\n","/**\n * Input plumbing for the run panel: keystroke batching and the escape hatch.\n *\n * The panel's rendering lives in `workflowRunPanel.ts`, which is a doom overlay;\n * what stays here is the behaviour that has nothing to do with drawing.\n *\n * DESIGN PATTERNS:\n * - Input batching. Every keystroke sent individually costs one subprocess\n * round trip, measured at ~18ms, which caps sustained typing near 56 c/s and\n * makes held keys queue visibly. Coalescing a frame's bytes into one send\n * keeps latency at roughly one frame no matter how fast the user types.\n * - Stateless render. The component recomputes from the latest snapshot on\n * every frame, so a theme change needs no cache invalidation.\n * - Terminal-independent escape hatch. The focused panel forwards every key to\n * the run, so the way out cannot itself depend on a modifier the terminal\n * may not transmit.\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported members\n *\n * AVOID:\n * - Sending per keystroke: it is the difference between usable and unusable\n * - Holding the flush timer open after dispose, which would keep writing into\n * a run the user has stopped watching\n */\n\nimport { isKeyRelease, matchesKey } from '@earendil-works/pi-tui';\n\n/** One frame at 60Hz. Long enough to coalesce a burst, short enough to feel direct. */\nconst FLUSH_INTERVAL_MS = 16;\n\n/**\n * How close two Escapes must be to read as \"get me out\".\n *\n * Long enough to be reachable without hurrying, short enough that two\n * deliberate, separate interrupts sent to the run are not mistaken for it.\n */\nexport const DOUBLE_ESCAPE_WINDOW_MS = 350;\n\n/** What the overlay should do with a keystroke. */\nexport type EscapeAction = 'forward' | 'close';\n\n/**\n * The panel's guaranteed way out: press Escape twice, quickly.\n *\n * A focused panel hands every key to the run so its agent stays interruptible,\n * which leaves the two `ctrl+alt` chords as the only exits. Those are exactly\n * the keys a terminal may not deliver: macOS without Option-as-Meta sends plain\n * `ctrl+w` instead, and the byte is forwarded into the run rather than matching.\n * The user is then inside a view they cannot leave. Escape is the one key every\n * terminal transmits identically, which is what makes it the failsafe.\n *\n * The first Escape is still forwarded, so interrupting the step stays as fast as\n * it ever was. Only the second one is consumed, and only when it lands inside\n * the window. The cost is one keystroke: sending the run two literal Escapes in\n * quick succession is no longer possible, which is worth an escapable panel.\n */\nexport class DoubleEscapeDetector {\n private lastEscapeAt: number | undefined;\n\n constructor(private readonly windowMs: number = DOUBLE_ESCAPE_WINDOW_MS) {}\n\n /**\n * Classify one chunk of terminal input.\n *\n * `now` is injected so the decision is a pure function of its inputs, which\n * is what makes the window testable without timers.\n */\n observe(data: string, now: number = Date.now()): EscapeAction {\n // Two Escapes coalesced into one read. A terminal in legacy mode delivers\n // this when they arrive inside the same poll, so it is the same gesture and\n // has to reach the same answer. `matchesKey` never sees it as an escape:\n // it parses as ctrl+alt+[, which has no meaning to a run either way.\n if (data === '\\x1b\\x1b') {\n this.lastEscapeAt = undefined;\n return 'close';\n }\n\n // A Kitty release event repeats the press's own bytes. Counting it would\n // turn one deliberate press into a pair and close the panel under the user.\n if (isKeyRelease(data)) return 'forward';\n\n if (!matchesKey(data, 'escape')) {\n // Anything typed in between makes these two separate interrupts rather\n // than one gesture, so the pair has to start over.\n this.lastEscapeAt = undefined;\n return 'forward';\n }\n\n if (this.lastEscapeAt !== undefined && now - this.lastEscapeAt <= this.windowMs) {\n this.lastEscapeAt = undefined;\n return 'close';\n }\n\n this.lastEscapeAt = now;\n return 'forward';\n }\n}\n\n/**\n * Collects keystrokes and forwards them in frame-sized batches.\n *\n * Failures are swallowed on purpose: a dropped keystroke is a nuisance, but an\n * exception raised from a terminal input handler would tear down the overlay.\n */\nexport class TerminalInputBatcher {\n private pending = '';\n private timer: NodeJS.Timeout | undefined;\n private disposed = false;\n\n constructor(\n private readonly send: (text: string) => Promise<void>,\n private readonly flushIntervalMs: number = FLUSH_INTERVAL_MS,\n ) {}\n\n write(data: string): void {\n if (this.disposed || data.length === 0) return;\n this.pending += data;\n if (this.timer) return;\n this.timer = setTimeout(() => void this.flush(), this.flushIntervalMs);\n this.timer.unref?.();\n }\n\n /** Send whatever has accumulated. Safe to call with nothing pending. */\n async flush(): Promise<void> {\n if (this.timer) clearTimeout(this.timer);\n this.timer = undefined;\n const text = this.pending;\n this.pending = '';\n if (!text || this.disposed) return;\n try {\n await this.send(text);\n } catch {\n // A dropped keystroke must not take the overlay down with it.\n }\n }\n\n /** Stop accepting and forwarding input. Pending bytes are discarded. */\n dispose(): void {\n this.disposed = true;\n if (this.timer) clearTimeout(this.timer);\n this.timer = undefined;\n this.pending = '';\n }\n\n /** Exposed for tests: whether a flush is scheduled. */\n hasPending(): boolean {\n return this.pending.length > 0;\n }\n}\n","/**\n * Scrollable, filterable list picker for every long list this extension shows.\n *\n * Replaces a bare `ui.select`, which wrapped each `name · detail` pair across\n * two or three terminal rows and left no way to reach a row other than scrolling\n * past all of them. This is a doom overlay instead: one row per item, a windowed\n * list that scrolls with the selection, and a filter field that narrows as you\n * type.\n *\n * Generic over the value it hands back. `SPC w c` picks a failed run to recover\n * through it; browsing and launching workflows moved to `workflowCatalog.ts`,\n * which needs the detail on screen beside the list rather than behind a pick.\n *\n * Rendering is pure, so the surface can be asserted as text without a terminal.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { CURSOR_BLOCK, fit, isControlInput, matchesQuery, pathTail, SELECTION_MARKER } from './overlayText';\n\nexport const WORKFLOW_PICKER_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_NAME = '(unnamed)';\nconst KEY_CLEAR = '\\x15';\n/** Rows the filter field and its trailing spacer take from the body. */\nconst FILTER_ROWS = 3;\n/** Columns the marker and its trailing space take from a row. */\nconst MARKER_COLUMNS = 2;\n/** Blank columns between the name column and the detail column. */\nconst COLUMN_GAP = 2;\nconst MIN_NAME_WIDTH = 16;\nconst NAME_RATIO = 0.45;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst DIM: ThemeColor = 'dim';\nconst ACCENT: ThemeColor = 'accent';\nconst SELECTED_BG: ThemeBg = 'selectedBg';\nconst ROW_BG: ThemeBg = 'userMessageBg';\n\nexport interface PickerRow<T> {\n /** Stable identity, used only to keep rows distinct. */\n key: string;\n /** Left column. */\n name: string;\n /** Right column, trimmed from the front so its tail survives. */\n detail: string;\n /** Extra text the filter should match but the row does not show. */\n search?: string;\n value: T;\n}\n\nexport interface WorkflowPickerConfig {\n title: string;\n breadcrumb: string;\n /** Plural noun for the header count, e.g. `workflows`. */\n unit: string;\n /** Verb on the enter key cap, e.g. `launch`. */\n action: string;\n filterPlaceholder: string;\n /** Shown when the source list itself is empty, as opposed to over-filtered. */\n emptyMessage: string;\n}\n\nexport function filterPickerRows<T>(rows: readonly PickerRow<T>[], query: string): PickerRow<T>[] {\n if (!query.trim()) return [...rows];\n return rows.filter((row) => matchesQuery([row.name, row.detail, row.search ?? ''].join(' '), query));\n}\n\nexport class WorkflowPickerComponent<T> extends DoomOverlay {\n private query = '';\n private selected = 0;\n private bodyHeight = 1;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly config: WorkflowPickerConfig,\n private readonly rows: readonly PickerRow<T>[],\n private readonly done: (value: T | undefined) => void,\n ) {\n super(tui, theme);\n }\n\n private matches(): PickerRow<T>[] {\n return filterPickerRows(this.rows, this.query);\n }\n\n /** Rows the list can draw, once the filter field has taken its share. */\n private capacity(): number {\n return Math.max(1, this.bodyHeight - FILTER_ROWS);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n const matches = this.matches();\n if (matchesKey(data, 'enter')) {\n const row = matches[Math.min(this.selected, matches.length - 1)];\n if (row) this.done(row.value);\n return;\n }\n\n if (matchesKey(data, 'up') || matchesKey(data, 'ctrl+p')) this.move(-1, matches.length);\n else if (matchesKey(data, 'down') || matchesKey(data, 'ctrl+n')) this.move(1, matches.length);\n else if (matchesKey(data, 'pageUp')) this.move(-this.capacity(), matches.length);\n else if (matchesKey(data, 'pageDown')) this.move(this.capacity(), matches.length);\n else if (matchesKey(data, 'backspace')) this.setQuery(this.query.slice(0, -1));\n else if (data === KEY_CLEAR) this.setQuery('');\n else if (!isControlInput(data)) this.setQuery(this.query + data);\n else return;\n\n this.tui.requestRender();\n }\n\n /** Editing the filter resets the cursor: the previous index named another row. */\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n this.selected = 0;\n }\n\n private move(delta: number, count: number): void {\n if (count === 0) return;\n this.selected = Math.max(0, Math.min(count - 1, this.selected + delta));\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: this.config.title,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.config.breadcrumb,\n headerRight: `${scope} ${this.config.unit}`,\n footer: `↑↓ select · enter ${this.config.action} · type to filter · ctrl+u clear · esc cancel`,\n footerHints: [\n ['↑↓', 'select'],\n ['enter', this.config.action],\n ['type', 'filter'],\n ['ctrl+u', 'clear'],\n ['esc', 'cancel'],\n ],\n footerRight:\n matches.length > 0 ? `${Math.min(this.selected, matches.length - 1) + 1}/${matches.length}` : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n this.bodyHeight = height;\n return [...this.filterField(width), ...this.listLines(width)].slice(0, height);\n }\n\n private filterField(width: number): string[] {\n const value = this.query\n ? `${this.query}${CURSOR_BLOCK}`\n : `${CURSOR_BLOCK}${this.theme.fg(DIM, this.config.filterPlaceholder)}`;\n return [this.theme.fg(DIM, FILTER_LABEL), this.theme.bg(SELECTED_BG, fit(` ${value}`, width)), ''];\n }\n\n private listLines(width: number): string[] {\n if (this.rows.length === 0) return [this.theme.fg(DIM, this.config.emptyMessage)];\n const matches = this.matches();\n if (matches.length === 0) return [this.theme.fg(DIM, `No ${this.config.unit} match \"${this.query}\".`)];\n\n const capacity = this.capacity();\n const active = Math.min(this.selected, matches.length - 1);\n // The window follows the cursor rather than the other way round, so a filter\n // that shrinks the list can never strand the selection off-screen.\n const start = Math.max(0, Math.min(active - capacity + 1, Math.max(0, matches.length - capacity)));\n\n const nameWidth = Math.max(MIN_NAME_WIDTH, Math.floor((width - MARKER_COLUMNS - COLUMN_GAP) * NAME_RATIO));\n const detailWidth = Math.max(0, width - MARKER_COLUMNS - COLUMN_GAP - nameWidth);\n return matches.slice(start, start + capacity).map((row, offset) => {\n const current = start + offset === active;\n const marker = current ? this.theme.fg(ACCENT, SELECTION_MARKER) : ' ';\n const name = row.name || EMPTY_NAME;\n const label = current ? this.theme.bold(fit(name, nameWidth)) : fit(name, nameWidth);\n const detail = this.theme.fg(DIM, fit(pathTail(row.detail, detailWidth), detailWidth));\n const background: ThemeBg = current ? SELECTED_BG : ROW_BG;\n return this.theme.bg(background, fit(`${marker} ${label}${' '.repeat(COLUMN_GAP)}${detail}`, width));\n });\n }\n}\n\nexport async function openWorkflowPickerOverlay<T>(\n ctx: ExtensionContext,\n config: WorkflowPickerConfig,\n rows: readonly PickerRow<T>[],\n): Promise<T | undefined> {\n return ctx.ui.custom<T | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowPickerComponent(tui, theme, config, rows, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Task-like live workflow list shown above Pi's editor.\n *\n * DESIGN PATTERNS:\n * - The extension owns run/event state; this component only projects and renders it.\n * - Register the widget once, then request redraws as progress, elapsed time, or the spinner changes.\n * - Terminal runs are absent from `rows`, so the widget disappears when the last run ends.\n *\n * CODING STANDARDS:\n * - Every rendered line is ANSI-aware and truncated to the available terminal width.\n * - Theme colors come from Pi's live UI context so theme changes repaint correctly.\n * - Named exports only and explicit return types on exported members.\n *\n * AVOID:\n * - Persisting progress in the chat transcript.\n * - Starting timers while no workflow is visible.\n */\n\nimport type { WorkflowProgressEvent, WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionUIContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type TUI, truncateToWidth } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_PROGRESS_WIDGET_KEY = 'workflow-mcp-progress';\n\nconst OVERLAY_HEADING = 'Workflows';\nconst PROGRESS_TICK_MS = 200;\nconst RUNNING_SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] as const;\nconst STATIC_PROGRESS_MARKER = '*';\nconst MILLISECONDS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst STARTING_JOB_STEP = 'Starting job';\nconst STARTING_WORKFLOW_STEP = 'Starting workflow';\nconst PREPARING_WORKFLOW_STEP = 'Preparing workflow';\nconst FINALIZING_WORKFLOW_STEP = 'Finalizing workflow';\n\ntype WorkflowProgressColor = Parameters<Theme['fg']>[0];\n\nexport type WorkflowProgressState = 'completed' | 'failed' | 'paused' | 'running' | 'skipped' | 'starting';\n\n/** One explicit palette makes every workflow state visually stable across the list. */\nexport const WORKFLOW_PROGRESS_COLORS: Readonly<Record<WorkflowProgressState, WorkflowProgressColor>> = {\n starting: 'dim',\n running: 'accent',\n completed: 'success',\n paused: 'warning',\n failed: 'error',\n skipped: 'muted',\n};\n\nexport interface WorkflowProgressRow {\n job: string;\n key: string;\n name: string;\n startedAt: string;\n state: WorkflowProgressState;\n step: string;\n}\n\nfunction latestStep(events: readonly WorkflowProgressEvent[]): WorkflowProgressEvent | undefined {\n return events.findLast((event) => event.type === 'step' && !!event.step);\n}\n\nfunction latestEvent(events: readonly WorkflowProgressEvent[]): WorkflowProgressEvent | undefined {\n return events.at(-1);\n}\n\nfunction progressState(record: WorkflowRunRecord, event: WorkflowProgressEvent | undefined): WorkflowProgressState {\n if (record.stage === 'error') return 'failed';\n if (record.stage === 'completed') return 'completed';\n if (record.executionState === 'paused' || record.executionState === 'pause_requested') return 'paused';\n\n switch (event?.status) {\n case 'failed':\n return 'failed';\n case 'paused':\n case 'pause_requested':\n return 'paused';\n case 'completed':\n return 'completed';\n case 'skipped':\n return 'skipped';\n case 'resumed':\n case 'running':\n return 'running';\n default:\n return record.executionCursor?.stepName ? 'running' : 'starting';\n }\n}\n\nfunction fallbackStep(record: WorkflowRunRecord): string {\n switch (record.executionCursor?.phase) {\n case 'pre':\n return PREPARING_WORKFLOW_STEP;\n case 'post':\n return FINALIZING_WORKFLOW_STEP;\n case 'job':\n case 'step':\n return STARTING_JOB_STEP;\n default:\n return STARTING_WORKFLOW_STEP;\n }\n}\n\n/** Derive the single current line for one run from its record and pushed progress events. */\nexport function workflowProgressRow(\n record: WorkflowRunRecord,\n events: readonly WorkflowProgressEvent[],\n): WorkflowProgressRow {\n const stepEvent = latestStep(events);\n const event = latestEvent(events);\n const cursor = record.executionCursor;\n const job = cursor?.job ?? stepEvent?.job ?? event?.job ?? record.job ?? cursor?.phase ?? 'workflow';\n const step = cursor?.stepName ?? (stepEvent?.job === job ? stepEvent.step : undefined) ?? fallbackStep(record);\n\n return {\n job,\n key: record.runId ?? `${record.workspace}/${record.runKey}`,\n name: record.displayName,\n startedAt: record.startedAt,\n state: progressState(record, event),\n step,\n };\n}\n\n/** Task-style elapsed time: whole seconds stay stable and compact between animation ticks. */\nexport function formatWorkflowDuration(durationMs: number): string {\n if (!Number.isFinite(durationMs) || durationMs < 0) return '?';\n const totalSeconds = Math.floor(durationMs / MILLISECONDS_PER_SECOND);\n const seconds = totalSeconds % SECONDS_PER_MINUTE;\n const totalMinutes = Math.floor(totalSeconds / SECONDS_PER_MINUTE);\n if (totalMinutes < MINUTES_PER_HOUR) {\n return totalMinutes === 0 ? `${seconds}s` : `${totalMinutes}m${String(seconds).padStart(2, '0')}s`;\n }\n const minutes = totalMinutes % MINUTES_PER_HOUR;\n const hours = Math.floor(totalMinutes / MINUTES_PER_HOUR);\n return `${hours}h${String(minutes).padStart(2, '0')}m${String(seconds).padStart(2, '0')}s`;\n}\n\nfunction progressMarker(state: WorkflowProgressState, nowMs: number): string {\n if (state !== 'running' && state !== 'starting') return STATIC_PROGRESS_MARKER;\n const tick = Number.isFinite(nowMs) ? Math.floor(Math.max(0, nowMs) / PROGRESS_TICK_MS) : 0;\n return RUNNING_SPINNER_FRAMES[tick % RUNNING_SPINNER_FRAMES.length] ?? RUNNING_SPINNER_FRAMES[0];\n}\n\n/** Render exactly: `<workflow name>[<duration>][<job>] <activity> <step>`. */\nexport function formatWorkflowProgressRow(row: WorkflowProgressRow, theme: Theme, nowMs = Date.now()): string {\n const startedAt = Date.parse(row.startedAt);\n const duration = formatWorkflowDuration(Number.isFinite(startedAt) ? nowMs - startedAt : Number.NaN);\n const color = WORKFLOW_PROGRESS_COLORS[row.state];\n return [\n theme.fg(color, row.name),\n theme.fg('muted', `[${duration}][${row.job}]`),\n theme.fg(color, ` ${progressMarker(row.state, nowMs)} `),\n theme.fg('text', row.step),\n ].join('');\n}\n\n/** Persistent workflow widget with the same heading/tree shape as Doom's task list. */\nexport class WorkflowProgressOverlay {\n private rows: readonly WorkflowProgressRow[] = [];\n private uiCtx: ExtensionUIContext | undefined;\n private widgetRegistered = false;\n private tui: TUI | undefined;\n private progressTimer: NodeJS.Timeout | undefined;\n\n /** Identity-compare so repeated session starts do not register duplicate widgets. */\n setUICtx(ctx: ExtensionUIContext): void {\n if (ctx === this.uiCtx) return;\n if (this.uiCtx && this.widgetRegistered) this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.stopProgressTimer();\n this.uiCtx = ctx;\n this.widgetRegistered = false;\n this.tui = undefined;\n }\n\n update(rows: readonly WorkflowProgressRow[]): void {\n this.rows = rows;\n if (!this.uiCtx) {\n this.stopProgressTimer();\n return;\n }\n\n if (rows.length === 0) {\n if (this.widgetRegistered) {\n this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.widgetRegistered = false;\n this.tui = undefined;\n }\n this.stopProgressTimer();\n return;\n }\n\n if (this.widgetRegistered) {\n this.syncProgressTimer();\n this.tui?.requestRender();\n return;\n }\n\n this.uiCtx.setWidget(\n WORKFLOW_PROGRESS_WIDGET_KEY,\n (tui, factoryTheme) => {\n this.tui = tui;\n return {\n render: (width: number) => this.renderWidget(this.uiCtx?.theme ?? factoryTheme, width),\n invalidate: () => {\n // Nothing cached: the next render reads the current rows, clock, and theme.\n },\n };\n },\n { placement: 'aboveEditor' },\n );\n this.widgetRegistered = true;\n this.syncProgressTimer();\n }\n\n private syncProgressTimer(): void {\n if (!this.widgetRegistered || this.rows.length === 0) {\n this.stopProgressTimer();\n return;\n }\n if (this.progressTimer) return;\n this.progressTimer = setInterval(() => this.tui?.requestRender(), PROGRESS_TICK_MS);\n this.progressTimer.unref?.();\n }\n\n private stopProgressTimer(): void {\n if (this.progressTimer) clearInterval(this.progressTimer);\n this.progressTimer = undefined;\n }\n\n private renderWidget(theme: Theme, width: number): string[] {\n if (this.rows.length === 0) return [];\n const truncate = (line: string): string => truncateToWidth(line, width, '…');\n const heading = truncate(\n `${theme.fg('accent', '●')} ${theme.fg('accent', `${OVERLAY_HEADING} (${this.rows.length})`)}`,\n );\n const nowMs = Date.now();\n const lines = [heading];\n\n for (const [index, row] of this.rows.entries()) {\n const branch = index === this.rows.length - 1 ? '└─' : '├─';\n lines.push(truncate(`${theme.fg('dim', branch)} ${formatWorkflowProgressRow(row, theme, nowMs)}`));\n }\n\n // Pi adds space above widgets but not below; keep the list off the editor border.\n lines.push('');\n return lines;\n }\n\n dispose(): void {\n this.stopProgressTimer();\n if (this.uiCtx) this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.rows = [];\n this.widgetRegistered = false;\n this.tui = undefined;\n this.uiCtx = undefined;\n }\n}\n","/**\n * The short prompts: pick one of a few options, or type one value.\n *\n * These were `ui.select` and `ui.input`, which meant the run manager, the runner\n * picker and every `workflow_dispatch` input rendered as native Pi widgets in the\n * middle of a flow whose other steps are framed doom overlays. Same surface for\n * all of them now, so a launch reads as one sequence rather than three styles.\n *\n * Rendering is pure, so both modes can be asserted as text without a terminal.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { CURSOR_BLOCK, fit, isControlInput, rightAligned, SELECTION_MARKER } from './overlayText';\n\nexport const WORKFLOW_PROMPT_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nconst CHOICE_TITLE = 'WORKFLOW PROMPT';\nconst CHOOSE_LABEL = 'CHOOSE';\nconst VALUE_LABEL = 'VALUE';\nconst DEFAULT_MARKER = 'default';\nconst EMPTY_CHOICES = 'No options are available.';\nconst CHOICE_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'select'],\n ['enter', 'confirm'],\n ['esc', 'cancel'],\n];\nconst INPUT_HINTS: readonly (readonly [string, string])[] = [\n ['type', 'edit'],\n ['enter', 'confirm'],\n ['ctrl+u', 'clear'],\n ['esc', 'cancel'],\n];\nconst KEY_CLEAR = '\\x15';\n/** Rows the heading and its spacer take before the first option. */\nconst HEADING_ROWS = 2;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst DIM: ThemeColor = 'dim';\nconst ACCENT: ThemeColor = 'accent';\nconst SELECTED_BG: ThemeBg = 'selectedBg';\nconst ROW_BG: ThemeBg = 'userMessageBg';\n\nexport interface WorkflowChoiceOptions {\n title: string;\n breadcrumb: string;\n choices: readonly string[];\n /** Marked `default` in the list and pre-selected. */\n preselect?: string;\n}\n\nexport interface WorkflowInputOptions {\n title: string;\n breadcrumb: string;\n /** Committed when the field is left empty, and shown beside the label. */\n fallback?: string;\n}\n\nexport class WorkflowChoiceComponent extends DoomOverlay {\n private selected: number;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowChoiceOptions,\n private readonly done: (choice: string | undefined) => void,\n ) {\n super(tui, theme);\n this.selected = Math.max(0, options.preselect ? options.choices.indexOf(options.preselect) : 0);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, 'enter')) {\n const choice = this.options.choices[this.selected];\n if (choice !== undefined) this.done(choice);\n return;\n }\n const count = this.options.choices.length;\n if (count === 0) return;\n if (matchesKey(data, 'up') || matchesKey(data, 'ctrl+p')) this.selected = Math.max(0, this.selected - 1);\n else if (matchesKey(data, 'down') || matchesKey(data, 'ctrl+n'))\n this.selected = Math.min(count - 1, this.selected + 1);\n else return;\n this.tui.requestRender();\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: CHOICE_TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: `${this.options.choices.length} options`,\n footer: '↑↓ select · enter confirm · esc cancel',\n footerHints: CHOICE_HINTS,\n footerRight:\n this.options.choices.length > 0 ? `${this.selected + 1}/${this.options.choices.length}` : 'no options',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const lines = [this.theme.bold(fit(this.options.title, width)), ''];\n if (this.options.choices.length === 0) {\n lines.push(this.theme.fg(DIM, EMPTY_CHOICES));\n return lines.slice(0, height);\n }\n\n lines.push(this.theme.fg(DIM, CHOOSE_LABEL));\n // The window follows the cursor, so a list longer than the body still scrolls.\n const capacity = Math.max(1, height - HEADING_ROWS - 1);\n const start = Math.max(\n 0,\n Math.min(this.selected - capacity + 1, Math.max(0, this.options.choices.length - capacity)),\n );\n for (const [offset, choice] of this.options.choices.slice(start, start + capacity).entries()) {\n const current = start + offset === this.selected;\n const marker = current ? this.theme.fg(ACCENT, SELECTION_MARKER) : ' ';\n const label = current ? this.theme.bold(choice) : choice;\n const note = choice === this.options.preselect ? this.theme.fg(DIM, DEFAULT_MARKER) : '';\n const background: ThemeBg = current ? SELECTED_BG : ROW_BG;\n lines.push(this.theme.bg(background, rightAligned(`${marker} ${label}`, note, width)));\n }\n return lines.slice(0, height);\n }\n}\n\nexport class WorkflowInputComponent extends DoomOverlay {\n private draft = '';\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowInputOptions,\n private readonly done: (value: string | undefined) => void,\n ) {\n super(tui, theme);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, 'enter')) {\n // An empty field commits the fallback rather than an empty string: the\n // caller offered a default, and pressing enter is how you accept it.\n this.done(this.draft.trim() || this.options.fallback || '');\n return;\n }\n if (matchesKey(data, 'backspace')) this.draft = this.draft.slice(0, -1);\n else if (data === KEY_CLEAR) this.draft = '';\n else if (!isControlInput(data)) this.draft += data;\n else return;\n this.tui.requestRender();\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: CHOICE_TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: this.options.fallback ? `default ${this.options.fallback}` : 'no default',\n footer: 'type to edit · enter confirm · ctrl+u clear · esc cancel',\n footerHints: INPUT_HINTS,\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const label = this.options.fallback\n ? rightAligned(\n this.theme.fg(DIM, VALUE_LABEL),\n this.theme.fg(DIM, `${DEFAULT_MARKER} ${this.options.fallback}`),\n width,\n )\n : this.theme.fg(DIM, VALUE_LABEL);\n return [\n this.theme.bold(fit(this.options.title, width)),\n '',\n label,\n this.theme.bg(SELECTED_BG, fit(` ${this.draft}${CURSOR_BLOCK}`, width)),\n ].slice(0, height);\n }\n}\n\nexport async function openWorkflowChoice(\n ctx: ExtensionContext,\n options: WorkflowChoiceOptions,\n): Promise<string | undefined> {\n return ctx.ui.custom<string | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowChoiceComponent(tui, theme, options, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n\nexport async function openWorkflowInput(\n ctx: ExtensionContext,\n options: WorkflowInputOptions,\n): Promise<string | undefined> {\n return ctx.ui.custom<string | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowInputComponent(tui, theme, options, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Run panel: the live view of one run's job tree and its terminal.\n *\n * A doom overlay rather than the bare header/body/footer it used to draw, so the\n * one surface a user sits inside for minutes at a time carries the same frame,\n * breadcrumb and key legend as every other. The base class owns the chrome and\n * hands the body an exact height, which also retires the hand-rolled row\n * arithmetic that existed only to stop Pi clipping the footer.\n *\n * Key routing is the reason this is a component rather than a renderer: a\n * focused panel receives input before Pi's global dispatcher, so the view\n * controls have to be handled here or the run's TTY swallows them.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type KeyId, matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fit, fitTerminalLine } from './overlayText';\nimport { DoubleEscapeDetector } from './workflowOverlay';\n\nconst TITLE = 'WORKFLOW RUN';\nconst VIEW_ONLY = 'view only · this run is hosted natively';\nconst OUTPUT_HEADING = 'OUTPUT · newest last';\nconst WAITING = 'Waiting for output…';\n/** A divider and its heading earn their rows only when output sits beneath them. */\nconst OUTPUT_CHROME_ROWS = 2;\n\nexport interface WorkflowRunPanelSnapshot {\n /** Job tree lines, already themed by the caller. */\n progress: string[];\n /** Recent terminal output for the running step. */\n output: string[];\n}\n\nexport interface WorkflowRunPanelOptions {\n runKey: string;\n /** Full run label for the header, e.g. `name · workspace/runKey`. */\n label: string;\n breadcrumb: string;\n /** False for a natively hosted run, which has no terminal to type into. */\n interactive: boolean;\n /** Plain-sentence footer, used when the terminal cannot fit the key caps. */\n footer: string;\n /** Key legend, which differs between a typeable panel and a view. */\n hints: readonly (readonly [string, string])[];\n /** Given the body width, because the job tree is fitted as it is built. */\n snapshot: (width: number) => WorkflowRunPanelSnapshot;\n /**\n * The columns and rows the output pane can actually show, reported on each\n * paint so a launcher that supports resizing can match the run to them.\n * Called from render, so an implementation must not do the work inline: the\n * run's geometry changes out of band and the next poll picks up the reflow.\n */\n onViewport?: (columns: number, rows: number) => void;\n /** Hand typing back to the session, leaving the panel open. */\n onUnfollow: () => void;\n onClose: () => void;\n /** Forward a keystroke to the run. */\n sendInput: (data: string) => void;\n /**\n * Send whatever is buffered before the panel goes away, or the Escape that\n * closed it dies with the batcher.\n */\n flushInput: () => void;\n unfollowShortcut: KeyId;\n closeShortcut: KeyId;\n onDispose: () => void;\n}\n\nexport class WorkflowRunPanelComponent extends DoomOverlay {\n private readonly escapes = new DoubleEscapeDetector();\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowRunPanelOptions,\n ) {\n super(tui, theme);\n }\n\n /**\n * The chords are matched against the whole chunk, as Pi delivers one per key\n * event. A chord buried in a coalesced burst therefore misses, which is\n * acceptable now that double-Escape guarantees an exit: scanning for the bytes\n * anywhere in a chunk would instead eat legitimate input, since `\\x1b\\x17` is\n * also a valid Escape-then-ctrl+w for the run's own editor.\n */\n handleInput(data: string): void {\n if (matchesKey(data, this.options.unfollowShortcut)) {\n this.options.onUnfollow();\n return;\n }\n if (matchesKey(data, this.options.closeShortcut)) {\n this.options.onClose();\n return;\n }\n // The failsafe. The first Escape falls through to the run, so interrupting\n // the step is as fast as it ever was; only the second one inside the window\n // is consumed.\n if (this.escapes.observe(data) === 'close') {\n this.options.flushInput();\n this.options.onClose();\n return;\n }\n this.options.sendInput(data);\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: this.options.interactive ? this.options.label : `${this.options.label} · ${VIEW_ONLY}`,\n footer: this.options.footer,\n footerHints: this.options.hints,\n footerRight: this.options.interactive ? 'typing goes to the run' : 'typing stays here',\n };\n }\n\n /**\n * The tree is never truncated: knowing which job is running matters more than\n * seeing another line of output, so the terminal pane absorbs whatever the\n * tree does not use.\n */\n protected renderBody(width: number, height: number): string[] {\n const { progress, output } = this.options.snapshot(width);\n const tree = progress.slice(0, height).map((line) => fit(line, width));\n\n const spare = height - tree.length;\n if (spare <= OUTPUT_CHROME_ROWS) return tree.slice(0, height);\n\n const rows = spare - OUTPUT_CHROME_ROWS;\n this.options.onViewport?.(width, rows);\n // Output keeps its own colour, so it is fitted by the escape-preserving\n // path rather than the themed-row one; see `fitTerminalLine`.\n const tail = output.slice(-rows).map((line) => fitTerminalLine(line, width));\n return [\n ...tree,\n '',\n this.theme.fg('dim', OUTPUT_HEADING),\n ...(tail.length > 0 ? tail : [this.theme.fg('dim', WAITING)]),\n ].slice(0, height);\n }\n\n dispose(): void {\n this.options.onDispose();\n }\n}\n\n/**\n * A panel whose keys cannot reach anything must never take them. Pi focuses an\n * overlay on show unless told otherwise, which for a native run would swallow\n * the user's typing into a run with no terminal to receive it.\n */\nexport function runPanelUiOptions(interactive: boolean): Record<string, unknown> {\n return {\n ...DOOM_FULLSCREEN_UI_OPTIONS,\n overlayOptions: {\n ...DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions,\n ...(interactive ? {} : { nonCapturing: true }),\n },\n };\n}\n\nexport type WorkflowRunPanelHost = Pick<ExtensionContext['ui'], 'custom'>;\n","import type { Theme } from '@earendil-works/pi-coding-agent';\nimport { Box, type Component, Text, truncateToWidth } from '@earendil-works/pi-tui';\n\nimport type { StepReport } from './workflowStatusRow';\n\nexport interface WorkflowStepMessageDetails {\n displayName: string;\n duration?: string;\n job: string;\n status: StepReport['status'];\n step: string;\n}\n\nexport function workflowStepMessageDetails(displayName: string, report: StepReport): WorkflowStepMessageDetails {\n return {\n displayName,\n job: report.job,\n status: report.status,\n step: report.step,\n ...(report.duration ? { duration: report.duration } : {}),\n };\n}\n\nexport function formatWorkflowStepMessage(details: WorkflowStepMessageDetails): string {\n const transition = details.duration\n ? `${details.status}::${details.duration}::${details.step}`\n : `${details.status}::${details.step}`;\n return `[${details.displayName}]: ${details.job}\\n${transition}`;\n}\n\nexport function isWorkflowStepMessageDetails(value: unknown): value is WorkflowStepMessageDetails {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Partial<WorkflowStepMessageDetails>;\n return (\n typeof candidate.displayName === 'string' &&\n typeof candidate.job === 'string' &&\n typeof candidate.step === 'string' &&\n (candidate.status === 'STARTED' || candidate.status === 'FINISHED' || candidate.status === 'FAILED') &&\n (candidate.duration === undefined || typeof candidate.duration === 'string')\n );\n}\n\nclass WorkflowStepMessageLines implements Component {\n constructor(\n private readonly details: WorkflowStepMessageDetails,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n const header = `${this.theme.fg('accent', `[${this.details.displayName}]:`)} ${this.details.job}`;\n const transition = this.details.duration\n ? `${this.details.status}::${this.details.duration}::${this.details.step}`\n : `${this.details.status}::${this.details.step}`;\n const colour =\n this.details.status === 'FAILED' ? 'error' : this.details.status === 'FINISHED' ? 'success' : 'accent';\n return [truncateToWidth(header, width), truncateToWidth(this.theme.fg(colour, transition), width)];\n }\n\n invalidate(): void {}\n}\n\nexport function renderWorkflowStepMessage(\n details: WorkflowStepMessageDetails | undefined,\n fallback: string,\n outputPad: number,\n theme: Theme,\n): Component {\n const box = new Box(outputPad, 1, (text) => theme.bg('customMessageBg', text));\n box.addChild(details ? new WorkflowStepMessageLines(details, theme) : new Text(fallback, 0, 0));\n return box;\n}\n","import { spawn } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { basename, extname, resolve } from 'node:path';\n\nimport { resolveRootSessionId, SUBAGENT_ROOT_SESSION_ENV } from '@agimon-ai/doompi-core/childProcess';\nimport {\n createNarrationRequest,\n DOOM_NARRATION_SERVICE,\n type DoomNarrationService,\n requireDoomNarrationService,\n} from '@agimon-ai/doompi-core/narration';\nimport type { PiPluginContributions, PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-core/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport { piMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport {\n defineMinorMode,\n type MinorModeOwner,\n type MinorModeOwnerActionContext,\n type MinorModeState,\n} from '@agimon-ai/doompi-minor-mode';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createEmbeddedWorkflowFeature,\n type EmbeddedWorkflowFeature,\n readWorkflowProgress,\n summarizeWorkflowProgress,\n type Workflow,\n type WorkflowProgressEvent,\n type WorkflowProgressJob,\n type WorkflowRunControl,\n type WorkflowRunRecord,\n type WorkflowStage,\n WorkflowTerminalService,\n} from '@agimon-ai/workflow-mcp';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type OverlayHandle, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_CATALOG_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../constants/workflow';\nimport { type RunProviderHandle, registerRunProvider } from '../services/backgroundWork';\nimport {\n finishedRunSummary,\n isSessionRun,\n launchNotice,\n runsForSession,\n toolResultText,\n withOptions,\n} from '../services/piToolBridge';\nimport {\n createWorkflowLaunchExecutor,\n type WorkflowPiToolDependencies,\n workflowToolRestriction,\n type WorkflowLaunchExecutor,\n type WorkflowLaunchInput,\n} from '../services/workflowExecution';\nimport {\n isLaunchParseFailure,\n parseWorkflowLaunchCommand,\n resolveWorkflowEntry,\n validateWorkflowLaunch,\n} from '../services/workflowLaunchCommand';\nimport {\n launchWorkflowEntry,\n loadWorkflowCatalog,\n summarizeWorkflowFile,\n type WorkflowLauncherUi,\n} from '../services/workflowLauncher';\nimport { narrateWorkflowTransition, type WorkflowNarrationSink } from '../services/workflowNarration';\nimport { workflowSkillDirectory } from '../services/workflowResource';\nimport { createWorkflowTerminalService } from '../services/workflowTerminal';\nimport { openWorkflowCatalogOverlay } from './workflow/workflowCatalog';\nimport {\n createWorkflowFinishedRenderer,\n type WorkflowFinishedRun,\n WORKFLOW_FINISHED_MESSAGE,\n} from './workflow/workflowFinishedMessage';\nimport { WorkflowInspectorComponent, type WorkflowInspectorSelection } from './workflow/workflowInspector';\nimport { TerminalInputBatcher } from './workflow/workflowOverlay';\nimport { openWorkflowPickerOverlay } from './workflow/workflowPicker';\nimport { WorkflowProgressOverlay, workflowProgressRow } from './workflow/workflowProgressOverlay';\nimport { openWorkflowChoice, openWorkflowInput } from './workflow/workflowPrompt';\nimport { runPanelUiOptions, WorkflowRunPanelComponent } from './workflow/workflowRunPanel';\nimport { isWorkflowStepMessageDetails, renderWorkflowStepMessage } from './workflow/workflowStepMessage';\n\nconst DOOM_FULLSCREEN_UI_OPTIONS = {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n} as const;\n\n/** A run panel currently on screen, and how to take it down. */\ninterface ActiveOverlay {\n handle?: OverlayHandle;\n /**\n * Whether keys typed at this panel can reach the run.\n *\n * False for a natively hosted run, which has no multiplexer to address. Such\n * a panel is opened without focus and must never be given it: typing into it\n * would go nowhere at all.\n */\n interactive: boolean;\n runKey: string;\n teardown: () => void;\n}\n\n/** Renderer retained for step cards already persisted by older package versions. */\nconst LEGACY_WORKFLOW_STEP_MESSAGE = 'workflow-step';\nconst FOLLOW_WIDGET_KEY = 'workflow-mcp-follow';\nconst MODE_ID = 'workflow';\nconst MODE_LABEL = 'Workflow';\nconst MODE_LABEL_STYLE = 'accent';\nconst MODE_ORDER = 20;\nconst MODE_ACTION_ACTIVATE = 'activate';\nconst MODE_ACTION_DEACTIVATE = 'deactivate';\n\nfunction workflowModeState(active: boolean, runCount: number): MinorModeState {\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: runCount > 0 ? `${runCount} active runs` : 'tools enabled', color: MODE_LABEL_STYLE } : {}),\n actions: [\n ...(active\n ? [{ id: MODE_ACTION_ACTIVATE, enabled: false, disabledReason: 'Workflow mode is active.' } as const]\n : [{ id: MODE_ACTION_ACTIVATE, enabled: true } as const]),\n ...(active\n ? [{ id: MODE_ACTION_DEACTIVATE, enabled: true } as const]\n : [{ id: MODE_ACTION_DEACTIVATE, enabled: false, disabledReason: 'Workflow mode is inactive.' } as const]),\n ],\n };\n}\n\nconst LEADER_MODE_BREADCRUMB = 'SPC w e';\nconst CATALOG_BREADCRUMB = 'SPC › w / workflows › l / list';\nconst MANAGE_BREADCRUMB = 'SPC › w / workflows › r / runs';\nconst RECOVER_BREADCRUMB = 'SPC › w / workflows › c / recover';\nconst RUN_PANEL_BREADCRUMB = 'SPC › w / workflows › run';\nconst PAUSED_EXECUTION_STATE = 'paused';\n\nconst UNFOLLOW_SHORTCUT = 'ctrl+alt+w';\n/**\n * Dismisses the run panel.\n *\n * Separate from the focus toggle because a focused panel hands every key to the\n * run, Escape included, so a plain \"Escape closes an overlay\" is unavailable:\n * interrupting the agent inside a step is worth more than a close key. Folding\n * closing into the focus toggle instead would leave an unfocused panel with no\n * way back to typing into the run.\n *\n * Not the only way out. This chord relies on a modifier some terminals do not\n * transmit, so `DoubleEscapeDetector` backs it with a plain double-Escape that\n * every terminal can send.\n */\nconst CLOSE_OVERLAY_SHORTCUT = 'ctrl+alt+q';\n\n/** Modifier glyphs macOS users read on their own keyboards and in every menu. */\nconst MAC_MODIFIER_GLYPHS: Record<string, string> = {\n alt: '⌥',\n cmd: '⌘',\n ctrl: '⌃',\n meta: '⌘',\n shift: '⇧',\n};\n\n/**\n * Render a binding the way the user's own platform writes it.\n *\n * The binding string Pi registers stays canonical (`ctrl+alt+w`) on every\n * platform; only the label changes. A macOS user reading \"alt\" has to translate\n * it to the Option key they actually press, and the modifier is not even\n * labelled \"alt\" on most Apple keyboards.\n *\n * Pi branches on `process.platform` for its own keybindings, so this follows a\n * convention already in the host rather than inventing one.\n */\nexport function shortcutLabel(binding: string, platform: NodeJS.Platform = process.platform): string {\n const parts = binding.split('+');\n if (platform === 'darwin') {\n // Glyphs join without separators, as they do in a macOS menu: ⌃⌥W.\n return parts.map((part) => MAC_MODIFIER_GLYPHS[part] ?? part.toUpperCase()).join('');\n }\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('+');\n}\nconst DEFAULT_PAGE_SIZE = 100;\n/**\n * The reconcile sweep, which is a fallback rather than the mechanism.\n *\n * The observer reports a change as it happens, so this only bounds how long a\n * change nothing notified us about stays invisible. It was 5s when it was the\n * only way anything was noticed.\n */\nconst MONITOR_INTERVAL_MS = 30_000;\n/**\n * Coalescing window for event-driven status refreshes.\n *\n * A run emits several transitions at once, and each one would otherwise page\n * the registry for the authoritative lifecycle snapshot. One page per burst.\n */\nconst STATUS_REFRESH_DEBOUNCE_MS = 120;\nconst PI_EXEC_TIMEOUT_MS = 10_000;\nconst RECOVERY_EVIDENCE_MAX_BYTES = 64 * 1024;\nconst RUNNING_STATUS = 'running';\nconst COMPLETED_STATUS = 'completed';\nconst FAILED_STATUS = 'failed';\nconst ERROR_STAGE = 'error';\nconst ERROR_COLOUR = 'error';\n/**\n * How long shutdown waits for an interrupted inline run to finalize its record.\n *\n * Long enough for a step that honours SIGTERM to unwind and for the registry\n * write that follows, short enough that a step ignoring it does not strand the\n * user in a session that will not close.\n */\nconst SHUTDOWN_FINALIZE_TIMEOUT_MS = 10_000;\nconst FOLLOW_INTERVAL_MS = 2_000;\nconst TAIL_LINES = 24;\n/** Below these a resized run has no room left to draw, so it keeps its own size and the panel clips. */\n/**\n * Overlay refresh cadence and size.\n *\n * Faster than the background widget's 2s: a foregrounded terminal that lags\n * behind your own typing reads as broken, and only the one run being watched\n * pays for it.\n */\nconst OVERLAY_REFRESH_MS = 200;\n/**\n * Slowest part of a refresh, given its own cadence.\n *\n * Reading a run's screen means forking `tmux capture-pane` or `cmux read-screen`,\n * measured at ~75ms. Repainting at 200ms is right for a panel; forking at 200ms\n * is not, so the two are decoupled and only the render keeps the fast tick. A\n * terminal tail is a rolling window of the last few seconds either way, so the\n * slower read costs the reader nothing they can perceive.\n */\nconst SCREEN_REFRESH_MS = 750;\n/**\n * How many recent run announcements the launch handshake can look back through.\n *\n * Only ever searched for a run that registered within the acknowledgement\n * window, so this needs to cover concurrent launches, not session history. The\n * per-session concurrency ceiling is five.\n */\nconst ANNOUNCED_RUN_HISTORY = 32;\n/**\n * Telemetry name for a launch being asked for.\n *\n * Named once because both launch paths, the wizard and the tool, report it and\n * a query that spans them only works while the two agree.\n */\nconst LAUNCH_REQUESTED_EVENT = 'doom_workflow.launch_requested';\n/**\n * Recovery skill shipped by this package, offered to Pi at resource discovery.\n *\n * Recovery is the one path here complex enough to deserve a real skill rather\n * than a few tool guidelines, and this package owns that domain: it cannot\n * assume the host repository provides one. Discovery is cheap, since Pi puts\n * only the name, description, and location in the system prompt and reads the\n * body on demand.\n *\n * Resolved from the module directory, not the module file: `resolve` treats a\n * trailing filename as a path segment. Both `src/extensions` and\n * `dist/extensions` sit two levels below the package root.\n */\n\n/**\n * Glyphs for widgets, panels, and notices.\n *\n * Deliberately restricted to characters that render in a default terminal font.\n * A box-drawing or emoji glyph that falls back to tofu is worse than no glyph.\n */\nconst GLYPH = {\n running: '▸',\n repair: '⚠',\n completed: '✔',\n failed: '✖',\n separator: '·',\n} as const;\n\n/**\n * The panel's footer: how to leave, in the order a stuck user needs it.\n *\n * Escape leads on an interactive panel because it is the key every terminal\n * transmits, and the one someone reaches for first when a view will not let go.\n * A view-only panel says so instead: a user who does not know the run is\n * unreachable reads the silence as the panel being broken.\n */\nexport function panelHint(interactive: boolean, platform: NodeJS.Platform = process.platform): string {\n const close = shortcutLabel(CLOSE_OVERLAY_SHORTCUT, platform);\n if (!interactive) return `view only ${GLYPH.separator} ${close} closes this view`;\n return [\n 'Esc Esc closes this view',\n `${shortcutLabel(UNFOLLOW_SHORTCUT, platform)} switches typing`,\n `${close} closes`,\n ].join(` ${GLYPH.separator} `);\n}\n\n/** The same hints as key caps, for the doom footer legend. */\nexport function panelHints(\n interactive: boolean,\n platform: NodeJS.Platform = process.platform,\n): readonly (readonly [string, string])[] {\n const close: readonly [string, string] = [shortcutLabel(CLOSE_OVERLAY_SHORTCUT, platform), 'close'];\n if (!interactive) return [close];\n // Leads the legend, and spelled as the copy says it: this cap is the escape\n // hatch, and the chords beside it ride on a modifier some terminals never send.\n return [['Esc Esc', 'close'], [shortcutLabel(UNFOLLOW_SHORTCUT, platform), 'switch typing'], close];\n}\n\n/**\n * Header and output lines for the follow widget, fitted to the terminal.\n *\n * Every line a component renders must fit the given width, so the header sheds\n * detail right to left as the terminal narrows: the dismissal hint goes first,\n * then the workspace/stage context, and the run key survives longest because it\n * is the identifier the user needs to name the run.\n *\n * Colour is applied after fitting. Measuring plain text and styling afterwards\n * keeps the arithmetic honest, since escape codes occupy no visible columns.\n */\nfunction renderFollowLines(record: WorkflowRunRecord, output: string[], theme: Theme, width: number): string[] {\n const key = `${GLYPH.running} ${record.runKey}`;\n const meta = [record.workspace, stageLabel(record), record.runner].filter(Boolean).join(` ${GLYPH.separator} `);\n const hint = `${shortcutLabel(UNFOLLOW_SHORTCUT)} to background`;\n const gap = ' ';\n\n let header = theme.fg('accent', truncateToWidth(key, width));\n if (visibleWidth(key) + gap.length + visibleWidth(meta) <= width) {\n header += gap + theme.fg('muted', meta);\n const used = visibleWidth(key) + gap.length + visibleWidth(meta);\n if (used + gap.length + visibleWidth(hint) <= width) header += gap + theme.fg('dim', hint);\n }\n\n return [header, ...output.map((line) => truncateToWidth(line, width))];\n}\n\n/**\n * Job tree for the follow widget, in the shape a CI run reads best.\n *\n * Finished jobs collapse to a single line so the eye lands on the one still\n * running, whose steps are listed. That is the whole reason this exists: a\n * scraped terminal shows whatever the runner last printed, which is not the\n * same as knowing which job of how many is in flight.\n */\nfunction renderProgressLines(jobs: WorkflowProgressJob[], theme: Theme, width: number): string[] {\n const lines: string[] = [];\n for (const job of jobs) {\n const glyph =\n job.status === COMPLETED_STATUS ? GLYPH.completed : job.status === FAILED_STATUS ? GLYPH.failed : GLYPH.running;\n const colour = job.status === COMPLETED_STATUS ? 'success' : job.status === FAILED_STATUS ? ERROR_COLOUR : 'accent';\n const position = job.total ? ` ${GLYPH.separator} ${(job.index ?? 0) + 1}/${job.total}` : '';\n lines.push(truncateToWidth(theme.fg(colour, `${glyph} ${job.name}`) + theme.fg('dim', position), width));\n\n // Only the job in flight expands. A finished job's steps are noise.\n if (job.status !== RUNNING_STATUS) continue;\n for (const step of job.steps) {\n const stepGlyph =\n step.status === COMPLETED_STATUS\n ? GLYPH.completed\n : step.status === FAILED_STATUS\n ? GLYPH.failed\n : GLYPH.running;\n const stepColour =\n step.status === RUNNING_STATUS ? 'muted' : step.status === FAILED_STATUS ? ERROR_COLOUR : 'dim';\n lines.push(truncateToWidth(theme.fg(stepColour, ` ${stepGlyph} ${step.name}`), width));\n }\n }\n return lines;\n}\n\nfunction progressEventsForRun(record: WorkflowRunRecord, events: WorkflowProgressEvent[]): WorkflowProgressEvent[] {\n const startedAt = Date.parse(record.startedAt);\n if (!Number.isFinite(startedAt)) return events;\n return events.filter((event) => {\n const eventAt = Date.parse(event.at);\n return !Number.isFinite(eventAt) || eventAt >= startedAt;\n });\n}\n\n/** Human-readable stage, rather than leaking the raw registry enum. */\nfunction stageLabel(record: WorkflowRunRecord): string {\n if (record.stale) return 'stale';\n if (record.stage === ERROR_STAGE) return FAILED_STATUS;\n return record.stage;\n}\n\ninterface ParsedArguments {\n invalidLauncher?: string;\n launcher?: MultiplexerLauncher;\n name?: string;\n positionals: string[];\n runner?: string;\n workspace?: string;\n}\n\n/** Spawn a launcher and forget it, which is all a delegated run needs from us. */\nexport type DetachedSpawn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; env: NodeJS.ProcessEnv },\n) => Promise<void>;\n\nexport interface WorkflowPiExtensionOptions {\n /** Captured environment used for session lineage and external child processes. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Package plugin context used to resolve session-scoped Cordis services. */\n cordis?: Context;\n followIntervalMs?: number;\n monitorIntervalMs?: number;\n /** Initial session mode, used by the non-interactive dispatcher composition. */\n initialMode?: boolean;\n /** Told about every mode change, so the leader menu can offer the way out rather than the way in. */\n onModeChange?: (enabled: boolean) => void;\n featureFactory?: () => EmbeddedWorkflowFeature;\n /** Reject work inherited from a stale session or disposed package root. */\n isActive?: () => boolean;\n runCleanup?: <T>(operation: () => T) => T;\n /** Injected so a test can read the delegated command without running it. */\n spawnDetached?: DetachedSpawn;\n launchAckPollMs?: number;\n launchAckTimeoutMs?: number;\n}\n\nexport interface WorkflowPiRuntime extends Pick<\n PiPluginContributions,\n 'events' | 'shortcuts' | 'messageRenderers' | 'services' | 'toolRestrictions'\n> {\n readonly commands: readonly (readonly [...Parameters<ExtensionAPI['registerCommand']>])[];\n readonly toolDependencies: WorkflowPiToolDependencies;\n waitForReadiness(signal?: AbortSignal): Promise<void>;\n dispose(context?: ExtensionContext): Promise<void>;\n}\n\n/**\n * Multiplexer identity of THIS process, which a launcher spawn must not carry.\n *\n * A child that inherits it records Pi's own workspace as the run's launcher, so\n * every later `open` or `tail` would foreground or scrape this session's screen\n * instead of the run's. The status file is per-step and equally non-inheritable.\n */\nconst CMUX_WORKSPACE_ID_ENV = 'CMUX_WORKSPACE_ID';\nconst TMUX_PANE_ENV = 'TMUX_PANE';\nconst WORKFLOW_TMUX_SESSION_NAME_ENV = 'WORKFLOW_TMUX_SESSION_NAME';\nconst LAUNCHER_ENVIRONMENT_STRIPPED = [\n 'CMUX_SURFACE_ID',\n SUBAGENT_ROOT_SESSION_ENV,\n CMUX_WORKSPACE_ID_ENV,\n TMUX_PANE_ENV,\n 'WORKFLOW_LAUNCHER_TYPE',\n WORKFLOW_TMUX_SESSION_NAME_ENV,\n 'WORKFLOW_STATUS_FILE',\n] as const;\n\n/**\n * Slack between this process's clock and the run record's timestamp.\n *\n * The record is written by another process, and a launch acknowledged a\n * fraction of a second \"before\" it began is a clock difference, not somebody\n * else's run.\n */\nconst LAUNCH_ACK_CLOCK_SKEW_MS = 2_000;\n\nconst LAUNCHER_ENV = 'WORKFLOW_LAUNCHER';\nconst RECOVER_COMMAND = 'recover-workflow';\nconst LAUNCH_PROCESS_COMMAND = 'launch-process';\n\n/**\n * How a run is hosted, which is also the name of the binary that addresses it.\n *\n * One token per launcher rather than two, because they are the same token: a\n * record's `launcher.type` is `tmux` precisely because tmux is what hosts it and\n * `tmux` is what reads it back. `native` has no binary, which is exactly why\n * every surface has to branch on it.\n */\nconst LAUNCHER_TMUX = 'tmux';\nconst LAUNCHER_CMUX = 'cmux';\nconst LAUNCHER_NATIVE = 'native';\n/** The cmux socket method that answers with a styled render grid rather than plain text. */\n/** The verb the cockpit's launch dialog sends; the leader board does the same work. */\nconst WORKFLOW_LAUNCH_COMMAND = 'workflow-launch';\ntype MultiplexerLauncher = typeof LAUNCHER_TMUX | typeof LAUNCHER_CMUX;\n\nconst HOST_TERMINAL_OUTPUT_BLOCKED =\n \"This run points at Pi's own terminal, so its launcher screen is hidden. Use workflow status instead.\";\n\n/**\n * Whether stale or inherited launcher metadata addresses this Pi process.\n *\n * Reading such a target recursively captures the chat into its own widget;\n * opening or sending to it can foreground or type into Pi itself. New embedded\n * runs record `native`, but this guard also makes older records safe.\n */\n/**\n * A run with no recorded launcher, which reading and foregrounding both hit.\n *\n * Older records predate launcher identity being persisted, so this is a real\n * state rather than a corrupt one, and both surfaces owe the user the same\n * explanation for it.\n */\nconst NO_LAUNCHER_RECORDED = 'No durable launcher identity is recorded for this run.';\n\n/**\n * The identifier a run record carries for its definition.\n *\n * Derived the same way `RunWorkflowService` derives it, so the two agree: the\n * file name without its final extension, which keeps the `.workflow` part.\n */\nfunction workflowIdFor(workflowPath: string): string {\n return basename(workflowPath, extname(workflowPath));\n}\n\nfunction launcherEnvironment(environment: Readonly<Record<string, string | undefined>>): NodeJS.ProcessEnv {\n const env = { ...environment };\n for (const key of LAUNCHER_ENVIRONMENT_STRIPPED) delete env[key];\n return env;\n}\n\n/** The launcher the workflow templates default to, when it is a known one. */\nfunction preferredLauncher(environment: Readonly<Record<string, string | undefined>>): MultiplexerLauncher | undefined {\n const value = environment[LAUNCHER_ENV];\n return value === LAUNCHER_TMUX || value === LAUNCHER_CMUX ? value : undefined;\n}\n\n/**\n * One shell word per argument.\n *\n * `launch-process` hands `--command` to the launcher as a shell string, so a\n * run key or a path with a space in it has to survive one more round of shell\n * parsing than the argv we spawn with.\n */\nfunction shellCommand(argv: readonly string[]): string {\n return argv.map((word) => `'${word.replaceAll(\"'\", `'\\\\''`)}'`).join(' ');\n}\n\n/**\n * The workflow-mcp CLI this extension is built against.\n *\n * Resolved from the dependency rather than PATH: `pnpm exec workflow-mcp` finds\n * whatever the workspace root happens to install, which is not necessarily this\n * version, and it pays for a package-manager resolution on the launch path.\n */\nfunction resolveWorkflowCli(): string | undefined {\n try {\n return createRequire(import.meta.url).resolve('@agimon-ai/workflow-mcp/cli');\n } catch {\n return undefined;\n }\n}\n\nconst detachedSpawn: DetachedSpawn = async (command, args, options) => {\n // Detached with no stdio: the run owns a launcher terminal of its own, and\n // anything inherited from here would be written onto Pi's screen. Wait only\n // for spawn/error so an immediate exec failure releases the recovery claim.\n await new Promise<void>((resolveSpawn, rejectSpawn) => {\n const child = spawn(command, [...args], { ...options, detached: true, stdio: 'ignore' });\n child.once('error', rejectSpawn);\n child.once('spawn', () => {\n child.off('error', rejectSpawn);\n child.unref();\n resolveSpawn();\n });\n });\n};\n\nfunction tokenize(value: string): string[] {\n return (\n value.match(/\"[^\"]*\"|'[^']*'|\\S+/g)?.map((token) => {\n if ((token.startsWith('\"') && token.endsWith('\"')) || (token.startsWith(\"'\") && token.endsWith(\"'\"))) {\n return token.slice(1, -1);\n }\n return token;\n }) ?? []\n );\n}\n\nexport function parseWorkflowCommandArguments(value: string): ParsedArguments {\n const tokens = tokenize(value);\n const parsed: ParsedArguments = { positionals: [] };\n for (let index = 0; index < tokens.length; index += 1) {\n const token = tokens[index];\n const next = tokens[index + 1];\n if (token === '--launcher' && next) {\n if (next === LAUNCHER_CMUX || next === LAUNCHER_TMUX) parsed.launcher = next;\n else parsed.invalidLauncher = next;\n index += 1;\n } else if (token === '--runner' && next) {\n parsed.runner = next;\n index += 1;\n } else if (token === '--workspace' && next) {\n parsed.workspace = next;\n index += 1;\n } else if (token === '--name' && next) {\n parsed.name = next;\n index += 1;\n } else {\n parsed.positionals.push(token);\n }\n }\n return parsed;\n}\n\nfunction collectRunnerMaps(value: unknown, maps: string[][]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectRunnerMaps(item, maps);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, nested] of Object.entries(value)) {\n if ((key === 'interactiveRun' || key === 'run') && nested && typeof nested === 'object' && !Array.isArray(nested)) {\n maps.push(Object.keys(nested));\n } else {\n collectRunnerMaps(nested, maps);\n }\n }\n}\n\nexport function compatibleRunners(workflow: Workflow): string[] | undefined {\n const maps: string[][] = [];\n collectRunnerMaps(workflow, maps);\n if (maps.length === 0) return undefined;\n return maps[0].filter((runner) => maps.every((available) => available.includes(runner))).sort();\n}\n\nasync function listAllRuns(\n registry: EmbeddedWorkflowFeature['registry'],\n workspace?: string,\n): Promise<WorkflowRunRecord[]> {\n const records: WorkflowRunRecord[] = [];\n let page = 1;\n let hasNextPage = true;\n while (hasNextPage) {\n const result = await registry.listRunsPage({ page, pageSize: DEFAULT_PAGE_SIZE, workspace });\n records.push(...result.items);\n hasNextPage = result.hasNextPage;\n page += 1;\n }\n return records;\n}\n\n/**\n * One run, as a person reads it.\n *\n * Middle dots rather than pipes: pipes read as table borders in a terminal and\n * collide visually with the launcher output the widget sits above.\n */\nfunction runLabel(record: WorkflowRunRecord): string {\n return [record.runKey, record.workspace, stageLabel(record), record.runner]\n .filter(Boolean)\n .join(` ${GLYPH.separator} `);\n}\n\nexport function createWorkflowPiRuntime(pi: ExtensionAPI, options: WorkflowPiExtensionOptions): WorkflowPiRuntime {\n const services: NonNullable<PiPluginContributions['services']>[number][] = [];\n const feature = options.featureFactory?.() ?? createEmbeddedWorkflowFeature();\n const runtimeGeneration = randomUUID();\n let runtimeActive = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n const invocationActive = options.isActive ?? (() => true);\n const isRuntimeActive = (): boolean => runtimeActive && invocationActive();\n const notifyStandaloneReadiness = (notification: DoomReadinessNotification): void => {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n const message = `${notification.packageId} initialization ${notification.state}: ${detail}`;\n if (sessionCtx?.hasUI) sessionCtx.ui.notify(message, 'warning');\n else process.emitWarning(message);\n };\n const readinessCoordinator = (_ctx: ExtensionContext): DoomReadinessCoordinator => {\n const shared = options.cordis ? readDoomReadinessCoordinator(options.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({ notify: notifyStandaloneReadiness });\n return standaloneReadiness;\n };\n const waitForReadiness = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Workflow session initialization has not started.');\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!isRuntimeActive() || pending !== readinessHandle) {\n throw new Error('Workflow readiness belongs to a stale extension generation.');\n }\n };\n const { parser, recoverService, registry, runService, runTool } = feature;\n const spawnDetached = options.spawnDetached ?? detachedSpawn;\n const monitorIntervalMs = options.monitorIntervalMs ?? MONITOR_INTERVAL_MS;\n const followIntervalMs = options.followIntervalMs ?? FOLLOW_INTERVAL_MS;\n let monitorTimer: NodeJS.Timeout | undefined;\n let monitorRefreshGeneration: number | undefined;\n let followTimer: NodeJS.Timeout | undefined;\n let followRefreshActive = false;\n let followedRun: WorkflowRunRecord | undefined;\n let previousStages = new Map<string, WorkflowStage>();\n const pendingTerminalRuns = new Map<string, WorkflowRunRecord>();\n const deliveredTerminalRuns = new Set<string>();\n let sessionStartedAt = 0;\n let runProvider: RunProviderHandle | undefined;\n services.push((context: Context) => {\n runProvider = registerRunProvider(context);\n });\n let lifecycleNarrationReady = false;\n let sessionRunCount = 0;\n let workflowMode = false;\n let publishedWorkflowState: string | undefined;\n const restrictionListeners = new Set<() => void>();\n const modeContribution: MinorModeOwner<MinorModeOwnerActionContext<ExtensionContext>> = defineMinorMode<\n undefined,\n MinorModeOwnerActionContext<ExtensionContext>\n >({\n descriptor: {\n source: PACKAGE_SOURCE,\n id: MODE_ID,\n label: MODE_LABEL,\n description: 'Workflow discovery, launch, inspection, control, and recovery tools.',\n order: MODE_ORDER,\n actions: [\n {\n id: MODE_ACTION_ACTIVATE,\n label: 'Activate',\n description: 'Enable workflow tools for this session.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: MODE_ACTION_DEACTIVATE,\n label: 'Deactivate',\n description: 'Disable workflow tools without stopping active runs.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n ],\n },\n state: () => workflowModeState(workflowMode, sessionRunCount),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n await waitForReadiness();\n if (actionId === MODE_ACTION_ACTIVATE) {\n await applyWorkflowMode(true, execution.context);\n return { message: 'Workflow mode activated.' };\n }\n if (actionId === MODE_ACTION_DEACTIVATE) {\n await applyWorkflowMode(false, execution.context);\n return { message: 'Workflow mode deactivated.' };\n }\n throw new Error(`Unknown workflow mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n /** Kept so callers outside a handler can still resolve the session id. */\n let sessionCtx: ExtensionContext | undefined;\n let activeOverlay: ActiveOverlay | undefined;\n let inspectorHandle: OverlayHandle | undefined;\n let inspectorOpen = false;\n /** The runs the inspector last listed, keyed the way its items are. */\n let inspectorRecords = new Map<string, WorkflowRunRecord>();\n /**\n * The pushed view of runs this session owns.\n *\n * A delegated run executes in a launcher's process, so nothing in here ever\n * observes it directly. What it observes is the registry the run writes to,\n * which is why this replaces polling rather than instrumenting anything.\n */\n let runControl: WorkflowRunControl | undefined;\n const disposeRunControl = new Set<() => void>();\n /**\n * Job and step transitions per run, accumulated from pushed events.\n *\n * The live list derives its current position from this stream and a failed\n * run reuses the same events for its terminal summary. Released after that\n * summary is delivered.\n */\n const runEvents = new Map<string, WorkflowProgressEvent[]>();\n /**\n * Runs the observer has announced, newest first, for the launch handshake.\n *\n * A launch needs the run key of the run it just started, and the launcher\n * process never learns it. Bounded, because a session that launches all day\n * must not accumulate a record per launch for the sake of a lookup that\n * only ever cares about the last few seconds.\n */\n const announcedRuns: WorkflowRunRecord[] = [];\n /** Active records are the authoritative membership of the task-like progress widget. */\n const activeRunRecords = new Map<string, WorkflowRunRecord>();\n /** Invalidates a registry snapshot when a newer pushed lifecycle event lands mid-read. */\n let activeRunRevision = 0;\n const progressOverlay = new WorkflowProgressOverlay();\n\n /**\n * The session that owns this extension's runs.\n *\n * Taken from whatever context Pi hands us, and deliberately the SAME value\n * `launch_workflow` stamps onto a run: reading the stamp from one place and\n * the filter from another is how a run goes invisible to the session that\n * just started it. `session_start` fills this in for a session that has\n * launched nothing yet; before either, it is undefined and every ownership\n * check fails closed, which is correct because such a session owns no runs.\n */\n let knownSessionId: string | undefined;\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx?: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-workflow',\n packageName: '@agimon-ai/doompi-workflow',\n cwd: ctx?.cwd,\n env: options.environment,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n let narrationService: DoomNarrationService | undefined;\n const reportNarrationFailure = (error: unknown): void => {\n void getTelemetry(sessionCtx)\n .recordWarning('doom_workflow.narration_failed', error)\n .catch((telemetryError: unknown) => {\n process.emitWarning(`Doom-workflow could not record a narration failure: ${String(telemetryError)}`);\n });\n };\n const narrationSink: WorkflowNarrationSink = {\n narrate(text) {\n const service = narrationService;\n const request = createNarrationRequest(text);\n if (!service || !request) return;\n try {\n void Promise.resolve(service.request(request)).catch(reportNarrationFailure);\n } catch (error) {\n reportNarrationFailure(error);\n }\n },\n };\n services.push((cordis: Context) => {\n cordis.inject([DOOM_NARRATION_SERVICE], (serviceContext) => {\n const service = requireDoomNarrationService(serviceContext);\n narrationService = service;\n return () => {\n if (narrationService === service) narrationService = undefined;\n };\n });\n });\n const observeSession = (sessionId: string | undefined): void => {\n if (sessionId && isRuntimeActive()) knownSessionId = resolveRootSessionId(sessionId, options.environment);\n };\n const currentSessionId = (): string | undefined => {\n const sessionId = knownSessionId ?? sessionCtx?.sessionManager.getSessionId();\n return sessionId ? resolveRootSessionId(sessionId, options.environment) : undefined;\n };\n const isRootProcess = (ctx: ExtensionContext, rootSessionId: string): boolean =>\n ctx.sessionManager.getSessionId().trim() === rootSessionId;\n\n /**\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so an unscoped tool would let any session\n * list, foreground, stop, or recover any other session's runs. Scoping is a\n * host-level filter on the tool instance, not a caller input: the agent\n * cannot opt out of it, and the CLI (which is how orphaned runs are managed)\n * keeps the global view.\n */\n const recoverTool = feature.createRecoverTool({\n // Ownership follows the recovering session. The host supplies identity\n // out of band; the tool schema cannot choose or override it.\n ownerSessionId: currentSessionId,\n });\n const controlTool = feature.createControlTool();\n\n /**\n * Inline executions still in flight, so shutdown can finalize them.\n *\n * A workflow declaring `launch-command` hands off to tmux or cmux and its\n * promise settles almost immediately; one without runs its whole engine in\n * this process. Only the latter lingers here, so the set needs no launcher\n * check of its own.\n */\n const pendingInlineRuns = new Set<Promise<unknown>>();\n const trackPendingRun = <T>(run: Promise<T>): Promise<T> => {\n const startedAt = Date.now();\n const runTelemetry = getTelemetry();\n pendingInlineRuns.add(run);\n void runTelemetry.recordEvent('doom_workflow.run_started', { outcome: 'started' });\n // Bookkeeping and telemetry share one handler pair on purpose. A separate\n // `finally` derives a promise that rejects with nobody watching, and an\n // unhandled rejection ends the process, TUI included. Since a launch is\n // answered from the registry, nothing else is necessarily awaiting this\n // run by the time it fails, so this pair is the only thing standing\n // between a failed launcher and a dead session.\n void run.then(\n () => {\n pendingInlineRuns.delete(run);\n return runTelemetry.recordEvent('doom_workflow.run_finished', {\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n },\n (error: unknown) => {\n pendingInlineRuns.delete(run);\n return runTelemetry.recordError('doom_workflow.run_failed', error, {\n duration_ms: Date.now() - startedAt,\n });\n },\n );\n return run;\n };\n\n const rejectRunner = (workflowPath: string, runner: string): string | undefined => {\n const compatible = compatibleRunners(parser.parseWorkflowFile(workflowPath));\n if (!compatible || compatible.includes(runner)) return undefined;\n return `Runner ${JSON.stringify(runner)} is not available across this workflow. Compatible runners: ${compatible.join(', ') || 'none'}.`;\n };\n\n const launchExecutor: WorkflowLaunchExecutor = createWorkflowLaunchExecutor({\n environment: options.environment,\n activeRunCount: async () => sessionRunCount,\n observeSession,\n rejectRunner,\n runTool,\n trackPendingRun,\n ...(options.launchAckPollMs === undefined ? {} : { launchAckPollMs: options.launchAckPollMs }),\n ...(options.launchAckTimeoutMs === undefined ? {} : { launchAckTimeoutMs: options.launchAckTimeoutMs }),\n // A run registering is the earliest honest answer to \"did it start?\": the\n // launcher's own process chain can stay open long after the run is\n // working, and a launch that waits for it holds the caller's turn open\n // for as long as that takes.\n //\n // Answered from what the observer has announced, with the poll driving a\n // sweep rather than waiting for one. Reading `announcedRuns` alone would\n // make the handshake hostage to a filesystem notification, and a dropped\n // one would cost the caller the whole acknowledgement budget for a run\n // that had already registered. A sweep costs the registry read this used\n // to do on its own, and every other surface gets its events from it.\n findLaunchedRun: async ({ sessionId, since, workflowPath }) => {\n const expectedId = workflowIdFor(workflowPath);\n const matches = (record: WorkflowRunRecord): boolean => {\n if (!isSessionRun(record, sessionId) || record.stale) return false;\n // Matched on identity as well as time so two launches in flight from\n // one session cannot report each other's run key.\n if (record.workflowId && record.workflowId !== expectedId) return false;\n const startedAt = Date.parse(record.startedAt);\n return Number.isFinite(startedAt) && startedAt >= since - LAUNCH_ACK_CLOCK_SKEW_MS;\n };\n // No observer here: the dispatcher bridge runs the launch tool without\n // a session of its own, so it still has to look for itself.\n if (!runControl) return (await listAllRuns(registry)).find(matches);\n await runControl.refresh();\n return announcedRuns.find(matches);\n },\n // A launch answered early still owes the user its failure.\n onLateFailure: (error, ctx) => {\n const detail = error instanceof Error ? error.message : String(error);\n ctx.ui.notify(launchNotice(`Workflow launch failed after it was reported started.\\n${detail}`), 'warning');\n },\n onLaunch: async (ctx) => {\n await getTelemetry(ctx).recordEvent(LAUNCH_REQUESTED_EVENT, { outcome: 'requested' });\n return refreshStatus(ctx, false);\n },\n });\n\n /** Repaint the live list from pushed state without writing progress into chat. */\n const publishProgressOverlay = (): void => {\n const records = [...activeRunRecords.values()].sort(\n (left, right) =>\n Date.parse(left.startedAt) - Date.parse(right.startedAt) || runIdentity(left).localeCompare(runIdentity(right)),\n );\n progressOverlay.update(\n records.map((record) => workflowProgressRow(record, runEvents.get(runIdentity(record)) ?? [])),\n );\n };\n\n /** Add, refresh, or remove one run from the live list. */\n const noteActiveRecord = (record: WorkflowRunRecord): void => {\n activeRunRevision += 1;\n const identity = runIdentity(record);\n if (record.stage === RUNNING_STATUS && !record.stale) activeRunRecords.set(identity, record);\n else activeRunRecords.delete(identity);\n publishProgressOverlay();\n };\n\n /** Replace widget membership from an authoritative registry snapshot. */\n const replaceActiveRecords = (records: readonly WorkflowRunRecord[]): void => {\n activeRunRecords.clear();\n for (const record of records) activeRunRecords.set(runIdentity(record), record);\n publishProgressOverlay();\n };\n\n /** Keep every pushed progress event for both the live row and terminal summary. */\n const noteProgressEvent = (identity: string, event: WorkflowProgressEvent): void => {\n const events = runEvents.get(identity) ?? [];\n events.push(event);\n runEvents.set(identity, events);\n };\n\n /**\n * Ask for a status refresh, collapsing a burst of events into one.\n *\n * The live list updates from the event itself, but terminal detection still\n * needs the session's authoritative record set, and that costs a registry\n * page. A run emitting six transitions at once must not buy six.\n */\n let statusRefreshTimer: NodeJS.Timeout | undefined;\n const scheduleStatusRefresh = (ctx: ExtensionContext): void => {\n if (!isRuntimeActive() || ctx !== sessionCtx || statusRefreshTimer) return;\n statusRefreshTimer = setTimeout(() => {\n statusRefreshTimer = undefined;\n if (isRuntimeActive() && ctx === sessionCtx) void refreshStatus(ctx, true);\n }, STATUS_REFRESH_DEBOUNCE_MS);\n statusRefreshTimer.unref?.();\n };\n\n /** Everything remembered about a run, released once it can produce no more. */\n const forgetRun = (identity: string): void => {\n runEvents.delete(identity);\n };\n\n /**\n * Subscribe to the registry instead of asking it what changed.\n *\n * A run this session launched executes in a launcher's own process, so the\n * only thing connecting it to this one is the session stamp on its record.\n * The filter is that stamp, and it is applied inside the observer so a\n * shared registry never leaks another session's runs into this UI.\n */\n const startRunControl = async (ctx: ExtensionContext): Promise<void> => {\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const control = feature.createRunControl({\n recordFilter: (candidate) => isSessionRun(candidate, sessionId),\n });\n runControl = control;\n const controlIsCurrent = (): boolean => isRuntimeActive() && ctx === sessionCtx && runControl === control;\n\n const controlDisposers = [\n control.on('step', (event) => {\n if (!controlIsCurrent()) return;\n const identity = runIdentity(event.record);\n noteProgressEvent(identity, {\n at: event.at,\n job: event.job,\n status: event.status,\n step: event.step,\n type: 'step',\n ...(event.reason === undefined ? {} : { reason: event.reason }),\n });\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('job', (event) => {\n if (!controlIsCurrent()) return;\n const identity = runIdentity(event.record);\n noteProgressEvent(identity, {\n at: event.at,\n job: event.job,\n status: event.status,\n type: 'job',\n ...(event.index === undefined ? {} : { index: event.index }),\n ...(event.reason === undefined ? {} : { reason: event.reason }),\n ...(event.total === undefined ? {} : { total: event.total }),\n });\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('runStarted', (event) => {\n if (!controlIsCurrent()) return;\n announcedRuns.unshift(event.record);\n if (announcedRuns.length > ANNOUNCED_RUN_HISTORY) announcedRuns.length = ANNOUNCED_RUN_HISTORY;\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('runUpdated', (event) => {\n if (!controlIsCurrent()) return;\n noteActiveRecord(event.record);\n void refreshStatus(ctx, true);\n }),\n control.on('runFinished', (event) => {\n if (!controlIsCurrent()) return;\n noteActiveRecord(event.record);\n void refreshStatus(ctx, true);\n }),\n ];\n for (const dispose of controlDisposers) disposeRunControl.add(dispose);\n\n try {\n await control.start();\n } catch (error) {\n for (const dispose of controlDisposers) {\n disposeRunControl.delete(dispose);\n dispose();\n }\n control.dispose();\n if (runControl === control) runControl = undefined;\n throw error;\n }\n if (!isRuntimeActive() || ctx !== sessionCtx || runControl !== control) {\n for (const dispose of controlDisposers) {\n disposeRunControl.delete(dispose);\n dispose();\n }\n control.dispose();\n if (runControl === control) runControl = undefined;\n }\n };\n\n const stopRunControl = (): void => {\n if (statusRefreshTimer) clearTimeout(statusRefreshTimer);\n statusRefreshTimer = undefined;\n for (const dispose of disposeRunControl) dispose();\n disposeRunControl.clear();\n runControl?.dispose();\n runControl = undefined;\n runEvents.clear();\n activeRunRevision += 1;\n activeRunRecords.clear();\n publishProgressOverlay();\n };\n\n /** Dismiss the run panel entirely, leaving the run itself alone. */\n const closeOverlay = (): void => {\n activeOverlay?.teardown();\n activeOverlay?.handle?.hide();\n activeOverlay = undefined;\n };\n\n const runIdentity = (record: WorkflowRunRecord): string => record.runId ?? `${record.workspace}/${record.runKey}`;\n\n const publishModeWidget = (): void => {\n const contribution = modeContribution;\n if (!contribution) return;\n const next = workflowModeState(workflowMode, sessionRunCount);\n const serialized = JSON.stringify(next);\n if (serialized === publishedWorkflowState) return;\n publishedWorkflowState = serialized;\n contribution.publish();\n };\n\n const refreshStatus = async (ctx: ExtensionContext, notifyChanges: boolean): Promise<void> => {\n const refreshGeneration = sessionGeneration;\n const refreshIsCurrent = (): boolean =>\n isRuntimeActive() && refreshGeneration === sessionGeneration && ctx === sessionCtx;\n if (!refreshIsCurrent()) return;\n // Resolved before the guard is latched. Anything that can throw between\n // setting the flag and entering the try would strand it set, and a\n // stranded flag turns every later refresh into the early return above:\n // the run snapshot freezes, so the loop's launch budget never recovers.\n const activeTelemetry = getTelemetry(ctx);\n if (monitorRefreshGeneration === refreshGeneration) {\n void activeTelemetry.recordEvent('doom_workflow.monitor_skipped', { outcome: 'already_running' });\n return;\n }\n const startedAt = Date.now();\n const activeRevisionAtRead = activeRunRevision;\n monitorRefreshGeneration = refreshGeneration;\n try {\n const records = await listAllRuns(registry);\n if (!refreshIsCurrent()) return;\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const rootProcess = isRootProcess(ctx, sessionId);\n const sessionRecords = records.filter((record) => isSessionRun(record, sessionId));\n const running = sessionRecords.filter((record) => record.stage === RUNNING_STATUS && !record.stale);\n const failed = sessionRecords.filter((record) => record.stage === ERROR_STAGE);\n // Never let a snapshot taken before a pushed terminal event resurrect\n // the row that event just removed. The next refresh can reconcile from\n // a fresh snapshot if any lifecycle event landed during this read.\n if (activeRevisionAtRead === activeRunRevision) replaceActiveRecords(running);\n void activeTelemetry.recordEvent('doom_workflow.monitor_counts', {\n 'workflow.run_count': sessionRecords.length,\n 'workflow.running_count': running.length,\n 'workflow.failed_count': failed.length,\n mode: workflowMode ? 'on' : 'off',\n });\n\n // Runs this Pi session launched, identified by the session stamp the\n // launch tool puts in the run environment. Publishing them lets other\n // extensions size their own work without reaching into this one.\n const mine = runsForSession(records, sessionId).filter((record) => !record.stale);\n sessionRunCount = mine.length;\n publishModeWidget();\n\n // A run that has left the session's set can never produce output again,\n // so its cached screen is dead weight.\n forgetLauncherScreens(new Set(sessionRecords.map((record) => runIdentity(record))));\n\n const nextStages = new Map(sessionRecords.map((record) => [runIdentity(record), record.stage]));\n for (const record of sessionRecords) {\n const identity = runIdentity(record);\n const previous = previousStages.get(identity);\n const startedAt = Date.parse(record.startedAt);\n const startedDuringSession =\n previous === undefined &&\n (sessionStartedAt === 0 || !Number.isFinite(startedAt) || startedAt >= sessionStartedAt);\n if (lifecycleNarrationReady) {\n const narratedPrevious =\n previous === RUNNING_STATUS || previous === COMPLETED_STATUS || previous === ERROR_STAGE\n ? previous\n : undefined;\n narrateWorkflowTransition(narrationSink, record, narratedPrevious, startedDuringSession);\n }\n if (!notifyChanges || !rootProcess || record.stage === RUNNING_STATUS) continue;\n if (!deliveredTerminalRuns.has(identity) && (previous === RUNNING_STATUS || startedDuringSession)) {\n pendingTerminalRuns.set(identity, record);\n }\n }\n\n // A terminal run remains background work until Pi accepts the completion\n // turn. Otherwise another producer can observe an empty snapshot and\n // continue the agent before the workflow result has been queued.\n const retainedWork = new Map(mine.map((record) => [runIdentity(record), record]));\n for (const [identity, record] of pendingTerminalRuns) retainedWork.set(identity, record);\n if (!refreshIsCurrent()) return;\n runProvider?.update(\n [...retainedWork.values()].map((record) => ({ id: record.runId ?? record.runKey, sessionId })),\n );\n // Accumulated transitions belong to runs still going or still owed a\n // summary. Detect terminal deliveries before pruning so a failed run's\n // in-memory events remain available to its terminal message.\n const retainedEventIdentities = new Set([\n ...sessionRecords\n .filter((record) => record.stage === RUNNING_STATUS && !record.stale)\n .map((record) => runIdentity(record)),\n ...pendingTerminalRuns.keys(),\n ]);\n for (const identity of runEvents.keys()) {\n if (!retainedEventIdentities.has(identity)) forgetRun(identity);\n }\n\n if (notifyChanges) {\n for (const record of sessionRecords) {\n const previous = previousStages.get(runIdentity(record));\n if (previous !== RUNNING_STATUS || record.stage === RUNNING_STATUS) continue;\n const completed = record.stage === COMPLETED_STATUS;\n const detail = record.failedJob ? ` at ${record.failedJob}` : '';\n ctx.ui.notify(\n completed\n ? `${GLYPH.completed} ${record.runKey} completed`\n : `${GLYPH.failed} ${record.runKey} ${stageLabel(record)}${detail}`,\n completed ? 'info' : 'warning',\n );\n void activeTelemetry.recordEvent('doom_workflow.run_transition', {\n outcome: completed ? 'completed' : stageLabel(record),\n });\n }\n }\n\n if (rootProcess && pendingTerminalRuns.size > 0) {\n try {\n const terminalRecords = [...pendingTerminalRuns.values()];\n const summaries = await Promise.all(\n terminalRecords.map(async (record) => {\n if (record.stage === COMPLETED_STATUS) return finishedRunSummary(record, []);\n // A failure needs the job tree to say which job died. The\n // transitions pushed while the run was going are already in\n // hand; only a run that finished before this session began\n // watching has nothing accumulated and has to be read.\n const identity = runIdentity(record);\n const events =\n runEvents.get(identity) ??\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record)));\n return finishedRunSummary(record, summarizeWorkflowProgress(events));\n }),\n );\n if (!refreshIsCurrent()) return;\n pi.sendMessage(\n {\n customType: WORKFLOW_FINISHED_MESSAGE,\n content: summaries.join('\\n\\n'),\n display: true,\n details: {\n runIds: terminalRecords.map((record) => record.runId ?? runIdentity(record)),\n runs: terminalRecords.map((record): WorkflowFinishedRun => ({\n runKey: record.runKey,\n workspace: record.workspace,\n stage: record.stage,\n ...(record.workflowId ? { workflowId: record.workflowId } : {}),\n ...(record.failedJob ? { failedJob: record.failedJob } : {}),\n ...(record.errorMessage ? { error: record.errorMessage } : {}),\n })),\n },\n },\n { triggerTurn: true, deliverAs: 'steer' },\n );\n if (!refreshIsCurrent()) return;\n for (const record of terminalRecords) {\n const identity = runIdentity(record);\n deliveredTerminalRuns.add(identity);\n pendingTerminalRuns.delete(identity);\n // Its summary has been delivered, so the accumulated transitions\n // can never be needed again.\n forgetRun(identity);\n }\n runProvider?.update(mine.map((record) => ({ id: record.runId ?? record.runKey, sessionId })));\n } catch (error) {\n await activeTelemetry.recordError('doom_workflow.terminal_delivery_failed', error, {\n 'workflow.pending_terminal_count': pendingTerminalRuns.size,\n });\n }\n }\n\n if (!refreshIsCurrent()) return;\n previousStages = nextStages;\n void activeTelemetry.recordEvent('doom_workflow.monitor_finished', {\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n } catch (error) {\n await activeTelemetry.recordError('doom_workflow.monitor_failed', error, {\n duration_ms: Date.now() - startedAt,\n });\n if (refreshIsCurrent()) {\n ctx.ui.notify(\n `Workflow status refresh failed: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n }\n } finally {\n if (monitorRefreshGeneration === refreshGeneration) monitorRefreshGeneration = undefined;\n }\n };\n\n const clearFollow = (ctx: ExtensionContext): void => {\n if (followTimer) clearInterval(followTimer);\n followTimer = undefined;\n followedRun = undefined;\n ctx.ui.setWidget(FOLLOW_WIDGET_KEY, undefined);\n };\n\n /**\n * This session's view of the terminals its runs were launched into.\n *\n * The engine owns how a launcher is read and driven; this owns how often,\n * which is a property of the surface rather than of the run. Every panel\n * here repaints five times a second and a scrape forks a CLI, so the two\n * concerns stayed separate when the reads moved down into the engine.\n */\n const terminalFacade = new WorkflowTerminalService({\n run: async (command, args, options) => {\n const result = await pi.exec(command, [...args], { timeout: options.timeoutMs });\n return { code: result.code, stdout: result.stdout, stderr: result.stderr };\n },\n lines: TAIL_LINES,\n timeoutMs: PI_EXEC_TIMEOUT_MS,\n });\n const terminals = createWorkflowTerminalService<WorkflowRunRecord>({\n terminal: terminalFacade,\n now: () => Date.now(),\n refreshMs: SCREEN_REFRESH_MS,\n });\n\n /**\n * Geometry last asked of each run, so a repaint that changes nothing costs\n * no exec. Keyed by run identity, like every other per-run cache here.\n */\n const launcherGeometry = new Map<string, string>();\n\n /**\n * Match the run's own terminal to the panel showing it.\n *\n * A run draws at whatever geometry its launcher gave it, so a panel\n * narrower than that shows a clipped window onto a wider screen rather than\n * a smaller rendering of it. Which launchers can be told a size is the\n * engine's business; not asking twice for the same size is this one's.\n *\n * The size is NOT restored when the panel closes: the window belongs to this\n * run, and a run that is watched at panel size should stay readable at panel\n * size for whoever attaches to it next.\n */\n const resizeLauncherViewport = (record: WorkflowRunRecord, columns: number, rows: number): void => {\n const identity = runIdentity(record);\n const geometry = `${columns}x${rows}`;\n if (launcherGeometry.get(identity) === geometry) return;\n launcherGeometry.set(identity, geometry);\n void terminalFacade.resize(record, columns, rows);\n };\n\n /**\n * A run's recent output, reusing a recent read rather than forking again.\n *\n * Rendering stays as fast as it ever was: the caller gets the cached lines\n * immediately and the next repaint picks up whatever the refresh found.\n */\n const cachedLauncherScreen = (record: WorkflowRunRecord): Promise<string[]> => {\n // Answered here rather than by the engine: the engine cannot know that\n // the caller's own terminal is a Pi session with a status surface to\n // send the reader to instead.\n if (terminalFacade.targetsCurrentTerminal(record)) return Promise.resolve([HOST_TERMINAL_OUTPUT_BLOCKED]);\n return terminals.screen(runIdentity(record), record, TAIL_LINES);\n };\n\n /** Runs whose screens can never change again cannot earn their memory back. */\n const forgetLauncherScreens = (live: Set<string>): void => {\n terminals.forget(live);\n // The geometry cache is per run for the same reason the screens are: a\n // run that is gone can never be resized again.\n for (const identity of launcherGeometry.keys()) {\n if (!live.has(identity)) launcherGeometry.delete(identity);\n }\n };\n\n /**\n * Bring a run's launcher to the foreground.\n *\n * Returns a status line rather than notifying, because its only caller is now\n * the `workflow_run` tool's `open` action and the agent needs to read the outcome.\n */\n const openLauncher = async (record: WorkflowRunRecord): Promise<string> => {\n const launcher = record.launcher;\n if (!launcher) return NO_LAUNCHER_RECORDED;\n if (terminalFacade.targetsCurrentTerminal(record)) return HOST_TERMINAL_OUTPUT_BLOCKED;\n if (launcher.type === LAUNCHER_NATIVE) {\n return 'This run is hosted natively rather than in a multiplexer, so there is no separate window to bring forward.';\n }\n if (launcher.type === LAUNCHER_CMUX) {\n await pi.exec(LAUNCHER_CMUX, ['select-workspace', '--workspace', launcher.workspaceId], {\n timeout: PI_EXEC_TIMEOUT_MS,\n });\n return `Opened ${record.runKey} in cmux.`;\n }\n if (!options.environment.TMUX) {\n return 'Pi is not attached to tmux. Follow the output instead, or attach to the recorded tmux session manually.';\n }\n const target = launcher.sessionId ?? launcher.sessionName;\n const result = await pi.exec(LAUNCHER_TMUX, ['switch-client', '-t', target], { timeout: PI_EXEC_TIMEOUT_MS });\n if (result.code !== 0) return result.stderr.trim() || `Unable to open tmux session ${target}.`;\n if (launcher.paneId) {\n await pi.exec(LAUNCHER_TMUX, ['select-pane', '-t', launcher.paneId], { timeout: PI_EXEC_TIMEOUT_MS });\n }\n return `Opened ${record.runKey} in tmux.`;\n };\n\n const renderFollow = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n if (followRefreshActive) return;\n followRefreshActive = true;\n try {\n // Prefer the run's own progress log: it says which job and step are in\n // flight, which a scraped screen cannot. Runs started before progress\n // recording existed, and any run whose log is not readable, still get\n // the terminal tail.\n const jobs = summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n );\n const lines = jobs.length > 0 ? undefined : await cachedLauncherScreen(record);\n // Component factory rather than a string array, for two reasons the\n // string form cannot give us: render() receives the terminal width, so\n // launcher output can be fitted instead of overflowing, and the theme is\n // applied fresh on every render, so a theme switch repaints correctly\n // without any cached colours to invalidate.\n ctx.ui.setWidget(\n FOLLOW_WIDGET_KEY,\n (_tui, theme) => ({\n render: (width: number) =>\n renderFollowLines(record, lines ?? renderProgressLines(jobs, theme, width), theme, width),\n invalidate: () => {\n // Nothing cached: render() rebuilds from the current theme.\n },\n }),\n { placement: 'aboveEditor' },\n );\n } finally {\n followRefreshActive = false;\n }\n };\n\n const followRun = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n clearFollow(ctx);\n followedRun = record;\n await renderFollow(record, ctx);\n followTimer = setInterval(() => {\n if (followedRun) void renderFollow(followedRun, ctx);\n }, followIntervalMs);\n followTimer.unref?.();\n };\n\n /**\n * Forward literal text to a run's terminal.\n *\n * `tmux send-keys -l` and `cmux send` both take text verbatim, which keeps\n * escape sequences intact: an arrow key must arrive as one sequence, not as\n * a bracket and a letter. A natively hosted run has no multiplexer to\n * address, so it reports rather than silently dropping the keystrokes.\n */\n const sendToRun = async (record: WorkflowRunRecord, text: string): Promise<void> => {\n // Silently, because a panel only builds a keyboard for a run whose\n // capabilities already said yes: reaching here with an unwritable run\n // means the run changed under the panel, which is not the typist's problem.\n if (!terminalFacade.capabilities(record).writable) return;\n await terminalFacade.write(record, text);\n };\n\n /**\n * Show a run over Pi: job tree, live output, and a keyboard that reaches it.\n *\n * Blocks until the user closes it, which is what makes it feel like the run\n * rather than a report about the run. The refresh runs faster than the\n * background widget because a foregrounded terminal that lags behind your\n * own typing reads as broken.\n */\n /**\n * Show a run over Pi as a persistent panel, not a modal.\n *\n * Returns as soon as the panel is up rather than awaiting its close. An\n * awaited overlay would hold the tool call open, which freezes the agent\n * mid-turn and makes \"switch back to the main agent\" impossible: there is\n * nothing to switch back to while it is still waiting for a tool result.\n *\n * Focus, not lifetime, is what the user toggles. The panel stays on screen\n * while typing goes back to Pi, so Escape stays free for the run's own\n * agent, which uses it to interrupt.\n */\n const openOverlay = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<string> => {\n closeOverlay();\n // Exactly what the engine says this run's terminal will take. A run with\n // no reachable terminal gets a panel that is a view rather than a\n // keyboard, and saying so up front beats letting the user type into nothing.\n const interactive = terminalFacade.capabilities(record).writable;\n const input = new TerminalInputBatcher((text) => sendToRun(record, text));\n let jobs: WorkflowProgressJob[] = [];\n let output: string[] = [];\n let refresh: NodeJS.Timeout | undefined;\n\n let polling = false;\n const poll = async (): Promise<void> => {\n jobs = summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n );\n output = await cachedLauncherScreen(record);\n };\n await poll();\n\n const teardown = (): void => {\n if (refresh) clearInterval(refresh);\n refresh = undefined;\n input.dispose();\n };\n\n const entry: ActiveOverlay = { interactive, runKey: record.runKey, teardown };\n activeOverlay = entry;\n\n /** Shared by the panel footer, the close chord, and the double-Escape failsafe. */\n const closeWithNotice = (): void => {\n closeOverlay();\n ctx.ui.notify(`Closed the ${record.runKey} view. The run keeps going.`, 'info');\n };\n\n // Deliberately not awaited: the panel outlives this tool call.\n void ctx.ui.custom<void>(\n (tui, theme, _keybindings, done) => {\n // Guarded, because a tick that outlives its interval would otherwise\n // start another read on top of the last one and keep doing so. The\n // progress log is a local file and the screen read is coalesced, so a\n // skipped tick costs nothing: the next one repaints from the same state.\n refresh = setInterval(() => {\n if (polling) return;\n polling = true;\n void poll().finally(() => {\n polling = false;\n tui.requestRender();\n });\n }, OVERLAY_REFRESH_MS);\n refresh.unref?.();\n\n return new WorkflowRunPanelComponent(tui, theme, {\n runKey: record.runKey,\n label: `${GLYPH.running} ${runLabel(record)}`,\n breadcrumb: RUN_PANEL_BREADCRUMB,\n interactive,\n footer: panelHint(interactive),\n hints: panelHints(interactive),\n snapshot: (width) => ({ progress: renderProgressLines(jobs, theme, width), output }),\n onViewport: (columns, rows) => resizeLauncherViewport(record, columns, rows),\n onUnfollow: () => {\n entry.handle?.unfocus();\n ctx.ui.notify('Typing goes to this session. The run keeps going.', 'info');\n },\n onClose: closeWithNotice,\n sendInput: (data) => input.write(data),\n // `flush` takes the pending bytes synchronously and sends them in the\n // background, so the panel still closes on the same keystroke.\n // Without it the run would be interrupted or not depending on whether\n // the user out-typed a 16ms timer, which is not a behaviour anyone can\n // predict or rely on.\n flushInput: () => void input.flush(),\n unfollowShortcut: UNFOLLOW_SHORTCUT,\n closeShortcut: CLOSE_OVERLAY_SHORTCUT,\n onDispose: () => {\n teardown();\n if (activeOverlay === entry) activeOverlay = undefined;\n done();\n },\n });\n },\n {\n ...runPanelUiOptions(interactive),\n onHandle: (handle) => {\n entry.handle = handle;\n },\n },\n );\n\n // Told to the user directly, not only through the tool result. The result\n // is addressed to the agent, and the panel's own footer is one dim line\n // that a user watching a run scroll past can easily miss. A view you\n // cannot work out how to leave is the thing to avoid here.\n ctx.ui.notify(\n interactive\n ? `${record.runKey}: typing goes to the run. Press Esc twice to close, ${shortcutLabel(UNFOLLOW_SHORTCUT)} to type here instead.`\n : `${record.runKey}: view only, because this run is hosted natively. ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes it.`,\n 'info',\n );\n\n if (!interactive) {\n return [\n `Showing ${record.runKey} over Pi, as a view only:`,\n 'the run is hosted natively rather than in a multiplexer, so there is no terminal to type into.',\n `Typing stays with this session, and ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes the view.`,\n ].join(' ');\n }\n\n return [\n `Showing ${record.runKey} over Pi. Typing goes to the run.`,\n 'Pressing Escape twice quickly closes the view, and a single Escape still reaches the run.',\n `${shortcutLabel(UNFOLLOW_SHORTCUT)} moves typing between the run and this session,`,\n `and ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes the view. The run keeps going either way.`,\n ].join(' ');\n };\n\n const openInspector = async (ctx: ExtensionContext, manage = false): Promise<void> => {\n if (inspectorOpen || activeOverlay || followedRun) return;\n inspectorOpen = true;\n try {\n const selection = await ctx.ui.custom<WorkflowInspectorSelection | undefined>(\n (tui, theme, _keybindings, done) =>\n new WorkflowInspectorComponent(\n tui,\n theme,\n {\n list: async () => {\n const sessionId = currentSessionId();\n const records = (await listAllRuns(registry)).filter(\n (record) => record.stage === RUNNING_STATUS && !record.stale && isSessionRun(record, sessionId),\n );\n // Kept so `output` can address the run under the cursor without\n // paging the whole registry a second time on every refresh.\n inspectorRecords = new Map(records.map((record) => [runIdentity(record), record]));\n return Promise.all(\n records.map(async (record) => ({\n displayName: record.displayName,\n executionState: record.executionState,\n jobs: summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n ),\n key: runIdentity(record),\n output: [],\n runKey: record.runKey,\n startedAt: record.startedAt,\n workspace: record.workspace,\n })),\n );\n },\n output: async (item) => {\n const record = inspectorRecords.get(item.key);\n return record ? cachedLauncherScreen(record) : ['Workflow is no longer active.'];\n },\n },\n done,\n ),\n {\n ...DOOM_FULLSCREEN_UI_OPTIONS,\n onHandle: (handle) => {\n inspectorHandle = handle;\n },\n },\n );\n if (selection) {\n const record = await requireRun(selection);\n if (manage) await manageWorkflow(record, ctx);\n else await openOverlay(record, ctx);\n }\n } finally {\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n }\n };\n\n /**\n * Resolve a run this session owns, erroring rather than picking blindly.\n *\n * A run another session launched is reported exactly like one that does not\n * exist. Distinguishing them would leak the shared registry's contents into\n * a session that has no way to act on them anyway, and would invite the\n * agent to keep trying keys it can never use.\n */\n const requireRun = async (\n input: { runKey: string; workspace?: string },\n sessionId: string | undefined = currentSessionId(),\n ): Promise<WorkflowRunRecord> => {\n observeSession(sessionId);\n const records = await listAllRuns(registry, input.workspace);\n const matches = records.filter(\n (candidate) => candidate.runKey === input.runKey && isSessionRun(candidate, sessionId),\n );\n if (matches.length > 1) {\n throw new Error(\n withOptions(\n `Workflow run key ${JSON.stringify(input.runKey)} exists in more than one workspace in this session.`,\n ['Retry with the workspace from the run identity.'],\n ),\n );\n }\n const record = matches[0];\n if (!record) {\n throw new Error(\n withOptions(`No workflow run matches ${JSON.stringify(input.runKey)} in this session.`, [\n 'workflow_run with action status: use a run key from this session before retrying.',\n 'Tell the user this session did not launch that run rather than guessing a similar key. A run launched by another Pi session, or from the command line, is managed there or with the workflow-mcp CLI.',\n ]),\n );\n }\n return record;\n };\n\n /**\n * Resolve a failed run that this session may adopt through recovery.\n *\n * Failed runs are terminal and have no live owner to conflict with. This is\n * intentionally the only cross-session lookup. Recovery-specific status\n * and durable evidence reads may use it; live output, lifecycle controls,\n * and running-run UI stay scoped to the launching session.\n */\n const requireRecoverableRun = async (input: { runKey: string; workspace?: string }): Promise<WorkflowRunRecord> => {\n const matches = (await listAllRuns(registry, input.workspace)).filter(\n (candidate) => candidate.runKey === input.runKey && candidate.stage === ERROR_STAGE,\n );\n if (matches.length > 1) {\n throw new Error(\n withOptions(`Failed workflow run key ${JSON.stringify(input.runKey)} exists in more than one workspace.`, [\n 'Retry with the workspace from the recovery picker or run identity.',\n ]),\n );\n }\n const record = matches[0];\n if (!record) {\n throw new Error(\n withOptions(`No failed workflow run matches ${JSON.stringify(input.runKey)}.`, [\n 'Use the recovery picker to select an interrupted or failed run, or retry with its workspace.',\n 'Do not recover a running or completed workflow.',\n ]),\n );\n }\n return record;\n };\n\n const readRecoveryEvidenceTail = async (record: WorkflowRunRecord): Promise<string[]> => {\n const runDir = registry.runDirectoryFor(record);\n const paths = [resolve(runDir, 'changelog.md'), resolve(runDir, 'context.md'), resolve(runDir, 'progress.ndjson')];\n const sections: string[] = [];\n for (const path of paths) {\n try {\n const content = await readFile(path, 'utf-8');\n sections.push(`--- ${basename(path)} ---`, content.slice(-RECOVERY_EVIDENCE_MAX_BYTES).trimEnd());\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n }\n return sections.length > 0 ? sections : ['No durable recovery evidence files are recorded for this run.'];\n };\n\n /** Read-only evidence access for the one globally adoptable record class. */\n const readRecoverableRunEvidence = async (\n input: { runKey: string; workspace?: string },\n ctx: ExtensionContext,\n ): Promise<string> => {\n const record = await requireRecoverableRun(input);\n await getTelemetry(ctx).recordEvent('doom_workflow.recovery_evidence_requested', { outcome: 'requested' });\n return [\n `Workflow: ${runLabel(record)}`,\n '--- run.json ---',\n JSON.stringify(record, null, 2),\n ...(await readRecoveryEvidenceTail(record)),\n ].join('\\n');\n };\n\n /**\n * Recover a run in a launcher of its own instead of replaying it here.\n *\n * `RecoverWorkflowService` replays with the launch step skipped, so an\n * in-process recovery runs every job inside this process. A workflow whose\n * steps are `interactiveRun` then has its agent spawned with inherited\n * stdio, because that agent needs a real TTY to draw. Inside Pi that TTY is\n * the TUI: the agent draws over it, and the reset sequence written when the\n * step ends is one Pi never issued and cannot repaint from. Delegating\n * costs a process and keeps the screen.\n *\n * Undefined leaves the caller on the in-process path: a workflow that\n * declares no `launch-command` has no launcher to delegate to, and a\n * definition that cannot be read is better diagnosed by the replay itself.\n */\n const delegateRecovery = async (\n input: { runKey: string; workspace?: string; runner?: string },\n ctx: ExtensionContext,\n ): Promise<string | undefined> => {\n const cli = resolveWorkflowCli();\n if (!cli) return undefined;\n const record = await requireRecoverableRun(input);\n let workflow: Workflow;\n try {\n workflow = parser.parseWorkflowFile(record.workflowPath);\n } catch {\n return undefined;\n }\n if (!workflow['launch-command']) return undefined;\n\n // Mint the transfer capability in the shared registry before spawning.\n // The delegated CLI can only adopt this exact terminal record and gets\n // the owner identity from the claim rather than caller-controlled argv.\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const claim = await registry.claimRunRecovery(record.workspace, record.runKey, sessionId);\n const cwd = record.originalRepoPath ?? ctx.cwd;\n const recoverCommand = shellCommand([\n process.execPath,\n cli,\n RECOVER_COMMAND,\n record.runKey,\n '--workspace',\n record.workspace,\n '--recovery-claim',\n claim.claimId,\n ...(input.runner ? ['--runner', input.runner] : []),\n ]);\n const launcher = preferredLauncher(options.environment);\n try {\n await spawnDetached(\n process.execPath,\n [\n cli,\n LAUNCH_PROCESS_COMMAND,\n ...(launcher ? ['--launcher', launcher] : []),\n '--name',\n `${record.displayName} recover`,\n '--cwd',\n cwd,\n '--command',\n recoverCommand,\n ],\n { cwd, env: launcherEnvironment(options.environment) },\n );\n } catch (error) {\n await registry.releaseRunRecoveryClaim(record.workspace, record.runKey, claim.claimId);\n throw error;\n }\n await getTelemetry(ctx).recordEvent('doom_workflow.recover_delegated', {\n launcher: launcher ?? 'auto',\n outcome: 'delegated',\n });\n return `Recovering ${record.runKey} in a launcher of its own, so this session keeps its terminal. It reports back here when it ends.`;\n };\n\n const manageWorkflow = async (selected: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n let record = selected;\n while (true) {\n const actions = ['Open output'];\n const state = record.executionState ?? RUNNING_STATUS;\n if (state === RUNNING_STATUS) actions.push('Pause');\n if (state === PAUSED_EXECUTION_STATE) actions.push('Resume');\n if (record.stage === RUNNING_STATUS) actions.push('Stop');\n actions.push('Back');\n const action = await openWorkflowChoice(ctx, {\n title: `Manage ${record.runKey}`,\n breadcrumb: MANAGE_BREADCRUMB,\n choices: actions,\n });\n if (!action || action === 'Back') return;\n\n record = await requireRun(record);\n if (record.stage !== RUNNING_STATUS) {\n ctx.ui.notify(`${record.runKey} is no longer running.`, 'warning');\n return;\n }\n if (action === 'Open output') {\n await openOverlay(record, ctx);\n return;\n }\n if (action === 'Stop') {\n const confirmed = await ctx.ui.confirm(\n `Stop ${record.runKey}?`,\n 'The workflow will be interrupted and will not be restarted automatically.',\n );\n if (!confirmed) continue;\n record = await requireRun(record);\n if (record.stage !== RUNNING_STATUS) {\n ctx.ui.notify(`${record.runKey} is no longer running.`, 'warning');\n return;\n }\n }\n if (action !== 'Pause' && action !== 'Resume' && action !== 'Stop') continue;\n if (!record.runId) throw new Error(`${record.runKey} has no controllable run generation.`);\n const result = await controlTool.execute({\n action: action.toLowerCase() as 'pause' | 'resume' | 'stop',\n expectedRunId: record.runId,\n ...(action === 'Stop' ? { reason: 'Stopped from the workflow manager.' } : {}),\n runKey: record.runKey,\n workspace: record.workspace,\n });\n if (result.isError) throw new Error(toolResultText(result) || `Unable to ${action.toLowerCase()} workflow.`);\n ctx.ui.notify(toolResultText(result) || `${action} requested for ${record.runKey}.`, 'info');\n await refreshStatus(ctx, false);\n record = await requireRun(record);\n }\n };\n\n /**\n * The wizard's prompts, backed by doom overlays instead of Pi's native\n * widgets, so a launch reads as one framed sequence rather than three styles.\n *\n * `editor` stays with Pi: the workflow prompt is multi-line authoring, and\n * reimplementing a text editor to match a frame would be a poor trade.\n */\n const doomLauncherUi = (ctx: ExtensionContext, breadcrumb: string): WorkflowLauncherUi => ({\n editor: (title, prefill) => ctx.ui.editor(title, prefill),\n input: (title, placeholder) =>\n openWorkflowInput(ctx, { title, breadcrumb, ...(placeholder ? { fallback: placeholder } : {}) }),\n notify: (message, type) => ctx.ui.notify(message, type),\n select: (title, options) => openWorkflowChoice(ctx, { title, breadcrumb, choices: options }),\n });\n\n /**\n * `SPC w l`: the repository's workflows, the cursor workflow's parsed\n * detail beside it, and `r` to launch that one. Launching closes the board\n * first - the launch prompts are host dialogs, and a fullscreen overlay\n * would sit over them.\n */\n const openWorkflowCatalog = async (ctx: ExtensionContext): Promise<void> => {\n if (!ctx.hasUI) {\n ctx.ui.notify('The workflow list needs an interactive Pi session.', 'warning');\n return;\n }\n const entries = await loadWorkflowCatalog(feature.listWorkflowsTool, ctx.cwd);\n const byPath = new Map(entries.map((entry) => [entry.path, entry]));\n const launchOptions = {\n compatibleRunners,\n launch: (input: WorkflowLaunchInput, launchContext: ExtensionContext) =>\n launchExecutor.execute(input, launchContext),\n parseWorkflow: (workflowPath: string) => parser.parseWorkflowFile(workflowPath),\n ui: doomLauncherUi(ctx, CATALOG_BREADCRUMB),\n };\n await openWorkflowCatalogOverlay(\n ctx,\n entries.map((entry) => ({\n key: entry.path,\n name: entry.name,\n relativePath: entry.relativePath,\n description: entry.description,\n tags: entry.tags,\n })),\n {\n loadDetail: (row) => summarizeWorkflowFile(row.key, launchOptions),\n launchWorkflow: (row) => {\n const entry = byPath.get(row.key);\n if (!entry) return;\n void launchWorkflowEntry(launchOptions, entry, ctx).then(\n (result) => {\n // Trimmed, because a launch that ran in this process answers\n // with the engine's whole console log, and notifying that\n // verbatim paints tens of lines of banner and job tree over\n // the transcript.\n if (result) ctx.ui.notify(launchNotice(toolResultText(result)), 'info');\n },\n (error: unknown) => {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n },\n );\n },\n },\n );\n };\n\n /**\n * `/workflow-launch`: the same launch the catalog board performs, as a line.\n *\n * The cockpit can only send a session a prompt frame, so this is how a\n * browser starts a workflow; typing it by hand does the same thing. Every\n * value the board would have asked for in a dialog arrives on the line, and\n * what the workflow requires is checked before anything is started, because\n * a run missing its prompt starts and then waits for terminal input that is\n * never coming.\n */\n const launchFromCommand = async (args: string, ctx: ExtensionContext): Promise<void> => {\n const parsed = parseWorkflowLaunchCommand(args);\n if (isLaunchParseFailure(parsed)) {\n ctx.ui.notify(parsed.error, 'error');\n return;\n }\n const entries = await loadWorkflowCatalog(feature.listWorkflowsTool, ctx.cwd);\n const entry = resolveWorkflowEntry(entries, parsed.workflow);\n if (!entry) {\n ctx.ui.notify(`No workflow matches '${parsed.workflow}' under ${ctx.cwd}.`, 'error');\n return;\n }\n const detail = summarizeWorkflowFile(entry.path, {\n compatibleRunners,\n parseWorkflow: (workflowPath: string) => parser.parseWorkflowFile(workflowPath),\n });\n if (detail.error !== undefined) {\n ctx.ui.notify(`${entry.name} could not be read: ${detail.error}`, 'error');\n return;\n }\n const problems = validateWorkflowLaunch(detail, parsed);\n if (problems.length > 0) {\n ctx.ui.notify(problems.join(' '), 'error');\n return;\n }\n const workflow = parser.parseWorkflowFile(entry.path);\n const input: WorkflowLaunchInput = {\n workflowPath: entry.path,\n ...(parsed.runner === undefined ? {} : { runner: parsed.runner }),\n ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n ...(parsed.prompt === undefined ? {} : { prompt: parsed.prompt }),\n ...(Object.keys(parsed.inputs).length === 0 ? {} : { inputs: parsed.inputs }),\n };\n const result = await launchExecutor.execute(input, ctx);\n // Trimmed for the same reason the board trims it: a launch that ran in\n // this process answers with the engine's whole console log.\n ctx.ui.notify(launchNotice(toolResultText(result)), 'info');\n };\n\n const commands: WorkflowPiRuntime['commands'] = [\n [\n WORKFLOW_LAUNCH_COMMAND,\n {\n description: 'Launch a workflow: /workflow-launch <workflow> [runner=x] [key=value …] [prompt]',\n handler: async (args, ctx) => {\n await waitForReadiness();\n try {\n await launchFromCommand(args, ctx);\n } catch (error) {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n }\n },\n },\n ],\n ];\n\n const openRecoveryHandoff = async (ctx: ExtensionContext): Promise<void> => {\n // Recovery adopts terminal work. Include failed runs from dead or other\n // sessions here; passive UI and all controls over live runs stay scoped.\n const records = (await listAllRuns(registry)).filter((record) => record.stage === ERROR_STAGE);\n if (records.length === 0) {\n ctx.ui.notify('No failed workflows are available to recover.', 'info');\n return;\n }\n const chosen = await openWorkflowPickerOverlay(\n ctx,\n {\n title: 'WORKFLOW RECOVERY',\n breadcrumb: RECOVER_BREADCRUMB,\n unit: 'failed runs',\n action: 'recover',\n filterPlaceholder: 'type to filter by name, run key or failed job',\n emptyMessage: 'No failed workflows are available to recover.',\n },\n records.map((record) => ({\n key: `${record.workspace}/${record.runKey}`,\n name: record.displayName,\n detail: `${record.workspace}/${record.runKey}${record.failedJob ? ` · ${record.failedJob}` : ''}`,\n ...(record.failedJob ? { search: record.failedJob } : {}),\n value: record,\n })),\n );\n if (!chosen) return;\n const record = await requireRecoverableRun(chosen);\n if (record.stage !== ERROR_STAGE) throw new Error(`${record.runKey} is no longer failed.`);\n const skillFile = resolve(workflowSkillDirectory(), 'workflow-recovery', 'SKILL.md');\n if (!existsSync(skillFile)) throw new Error(`Workflow recovery skill is unavailable at ${skillFile}.`);\n setWorkflowMode(true);\n ctx.ui.notify(\n 'Workflow tools enabled. The agent will investigate this failure and choose the safe next step.',\n 'info',\n );\n pi.sendUserMessage(\n [\n 'Investigate recovery for this failed workflow run. This selection is permission to investigate, not permission to recover blindly.',\n `Run identity: ${JSON.stringify({ runKey: record.runKey, workspace: record.workspace })}`,\n `Read the package-owned recovery skill with the read tool at ${JSON.stringify(skillFile)} before acting.`,\n 'Inspect status, every relevant log source, process state, the staged run.json, and only the repair referenced by activeRepairId.',\n 'Choose exactly one outcome: recover, launch fresh, or defer. Never edit issue.md or repair.json, never scan historical repairs, and never pass recovery dryRun or a job override.',\n 'Do not recover terminal, approval-pending, blocked, or otherwise unsafe work. If evidence is incomplete, defer and explain what is missing.',\n 'If recovery is justified, preserve the recorded worktree and repair metadata, then verify real process and registry progress before reporting success.',\n ].join('\\n'),\n { deliverAs: 'followUp' },\n );\n };\n\n /**\n * Turn workflow mode on or off.\n *\n * The tools are registered for the whole session, so the mode is a tool\n * surface restriction rather than a registration: dropping it is what makes\n * them visible again, and no other owner's tools are touched either way.\n *\n * Activating also injects each tool's `promptSnippet` and `promptGuidelines`\n * into the system prompt, and deactivating strips them: in Pi, tool gating\n * and instruction injection are the same lever.\n */\n const setWorkflowMode = (enabled: boolean): void => {\n if (!isRuntimeActive()) return;\n workflowMode = enabled;\n restrictionListeners.forEach((listener) => listener());\n // Published here rather than in refreshStatus so the label lands with the\n // toggle: the status refresh is an async registry read, and a label that\n // waits for it looks like the command did nothing.\n publishModeWidget();\n options.onModeChange?.(enabled);\n };\n\n /**\n * What the user sees on every mode change.\n *\n * Leads with the state, then the one thing they can do next. Turning the\n * mode on is useless without knowing that you now just ask in plain\n * language, so that sentence earns its place; the tool count does not, and\n * is left to the README.\n */\n const modeSummary = (): string =>\n workflowMode\n ? [\n `${GLYPH.completed} Workflow mode on`,\n 'Ask for workflows in plain language: the agent can list, launch, inspect, pause, resume, stop, and recover runs.',\n `${shortcutLabel(UNFOLLOW_SHORTCUT)} stops following a run without stopping it.`,\n ].join('\\n')\n : [\n 'Workflow mode off',\n `Press ${LEADER_MODE_BREADCRUMB} to give the agent its workflow tools. Runs already going are unaffected.`,\n ].join('\\n');\n\n /**\n * Toggle the mode from the leader menu.\n *\n * Replaces the `/workflow [on|off|status]` command: the mode line already\n * answers `status` at a glance, and the other two arguments were a keyboard\n * path to a switch the leader menu spells out. Plan mode is reached the same\n * way, so the two modes are no longer toggled through different surfaces.\n */\n const applyWorkflowMode = async (enabled: boolean, ctx: ExtensionContext): Promise<void> => {\n setWorkflowMode(enabled);\n if (!workflowMode) clearFollow(ctx);\n ctx.ui.notify(modeSummary(), 'info');\n // Both directions: turning off has to clear the indicator, not just leave\n // the last one on screen until the monitor next fires.\n await refreshStatus(ctx, false);\n };\n\n // Zero palette cost, unlike a command. Guarded on an active follow so it\n // does not swallow the key when there is nothing to dismiss.\n\n // Dismissing is its own key because the panel cannot use Escape: a focused\n // panel forwards every key to the run so its agent stays interruptible.\n\n // A battery-included mode must not add model-visible skills while dormant.\n // Discovery follows session_start, so environment-driven dispatcher\n // activation is visible at startup while the normal parent remains neutral.\n // The existence guard also fails closed if packaging ever drops the skill.\n const onResourcesDiscover: NonNullable<PiEventHandlers['resources_discover']> = () => {\n if (!workflowMode) return { skillPaths: [] };\n const skillPath = workflowSkillDirectory();\n return { skillPaths: existsSync(skillPath) ? [skillPath] : [] };\n };\n\n const messageRenderers: PiPluginContributions['messageRenderers'] = [\n createWorkflowFinishedRenderer(),\n [\n LEGACY_WORKFLOW_STEP_MESSAGE,\n (message, { outputPad }, theme) => {\n const details = isWorkflowStepMessageDetails(message.details) ? message.details : undefined;\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n return renderWorkflowStepMessage(details, content, outputPad, theme);\n },\n ],\n ];\n\n const toolDependencies: WorkflowPiToolDependencies = {\n environment: options.environment,\n runTool,\n recoverTool,\n launchExecutor,\n controlTool,\n requireSessionRun: requireRun,\n requireRecoverableRun,\n readRecoveryEvidence: readRecoverableRunEvidence,\n delegateRecovery,\n trackPendingRun,\n observeSession,\n activeRunCount: async () => sessionRunCount,\n onLaunch: async (ctx) => {\n await getTelemetry(ctx).recordEvent(LAUNCH_REQUESTED_EVENT, { outcome: 'requested' });\n return refreshStatus(ctx, false);\n },\n followRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.follow_started', { outcome: 'started' });\n await followRun(record, ctx);\n return `Following ${runLabel(record)}. Press ${shortcutLabel(UNFOLLOW_SHORTCUT)} to stop following; the run keeps going.`;\n },\n tailRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.tail_requested', { outcome: 'requested' });\n return [\n `Workflow: ${runLabel(record)}`,\n `Stage: ${stageLabel(record)}`,\n 'Raw launcher output is hidden from chat. Use action follow or open to view it.',\n ].join('\\n');\n },\n openRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.open_requested', { outcome: 'requested' });\n // Without a UI there is nothing to foreground, so fall back to handing\n // the user's own terminal to the launcher.\n if (!ctx.hasUI) return openLauncher(record);\n return openOverlay(record, ctx);\n },\n rejectRunner,\n };\n\n let disposeLeaderActions: (() => void) | undefined;\n services.push((cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const dispose = requireDoomUiHub(uiContext).registerLeaderActions<ExtensionContext>({\n source: PACKAGE_SOURCE,\n handlers: {\n [LEADER_ENABLE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return applyWorkflowMode(true, ctx);\n },\n [LEADER_DISABLE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return applyWorkflowMode(false, ctx);\n },\n [LEADER_MANAGE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openInspector(ctx, true);\n },\n [LEADER_CATALOG_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openWorkflowCatalog(ctx);\n },\n [LEADER_RECOVER_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openRecoveryHandoff(ctx);\n },\n },\n onError: (error, _actionName, ctx) => {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n },\n });\n disposeLeaderActions = dispose;\n return () => {\n dispose();\n if (disposeLeaderActions === dispose) disposeLeaderActions = undefined;\n };\n });\n });\n\n const onSessionStart: NonNullable<PiEventHandlers['session_start']> = (_event, ctx) => {\n if (!runtimeActive || !invocationActive()) return;\n const generation = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort();\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n sessionCtx = ctx;\n const ownsSession = (): boolean =>\n runtimeActive && generation === sessionGeneration && sessionCtx === ctx && invocationActive();\n\n // A second start retires every resource tied to the previous context\n // before this context can publish its own state.\n const retireSessionResources = (): void => {\n stopRunControl();\n if (monitorTimer) clearInterval(monitorTimer);\n monitorTimer = undefined;\n runProvider?.update([]);\n clearFollow(ctx);\n inspectorHandle?.hide();\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n closeOverlay();\n terminals.forget(new Set());\n progressOverlay.setUICtx(ctx.ui);\n };\n if (options.runCleanup) options.runCleanup(retireSessionResources);\n else retireSessionResources();\n\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_workflow.session_started', {\n mode: options.environment.WORKFLOW_MCP_MODE === 'on' ? 'on' : 'off',\n outcome: 'started',\n });\n\n // Tools registered during extension init are auto-activated by Pi, so the\n // default-off state has to be applied here rather than by not registering.\n // WORKFLOW_MCP_MODE=on is the non-interactive dispatcher path.\n const sessionId = ctx.sessionManager.getSessionId();\n const rootSessionId = resolveRootSessionId(sessionId, options.environment);\n observeSession(rootSessionId);\n sessionStartedAt = Date.now();\n lifecycleNarrationReady = false;\n previousStages = new Map<string, WorkflowStage>();\n pendingTerminalRuns.clear();\n deliveredTerminalRuns.clear();\n setWorkflowMode(options.initialMode ?? options.environment.WORKFLOW_MCP_MODE === 'on');\n\n const coordinator = readinessCoordinator(ctx);\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Workflow session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${runtimeGeneration}:${generation}`, async (signal) => {\n const retired = (): boolean => ownReadinessAbort.signal.aborted || !ownsSession();\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n\n // Subscribed before the first status read, so a transition landing\n // during startup is delivered rather than raced past.\n await startRunControl(ctx);\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n await refreshStatus(ctx, false);\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n lifecycleNarrationReady = true;\n // A fallback now, not the mechanism: the observer reports a change\n // within its own debounce, and this only bounds how long a change\n // nothing notified us about stays invisible.\n monitorTimer = setInterval(() => {\n if (ownsSession()) void refreshStatus(ctx, true);\n }, monitorIntervalMs);\n monitorTimer.unref?.();\n return { value: undefined };\n });\n })();\n // The coordinator host owns the single user-facing failure notification;\n // this observer only ensures an idle failed task is still handled.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n };\n\n const runCleanup = async (label: string, cleanup: () => void | Promise<void>): Promise<void> => {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-workflow cleanup could not ${label}: ${String(error)}`);\n }\n };\n\n let disposal: Promise<void> | undefined;\n const dispose = (context: ExtensionContext | undefined = sessionCtx): Promise<void> => {\n disposal ??= (async () => {\n if (!runtimeActive) return;\n runtimeActive = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessAbort?.abort();\n readinessAbort = undefined;\n await runCleanup('stop the workflow observer', stopRunControl);\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) {\n await runCleanup('dispose standalone workflow readiness', () => ownedReadiness.dispose());\n } else if (pendingReadiness) {\n await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n }\n\n // A workflow without a `launch-command` runs its engine inside this\n // process. Interrupt it and wait only for the bounded finalization path.\n if (pendingInlineRuns.size > 0) {\n for (const service of [runService, recoverService]) {\n await runCleanup('interrupt an inline workflow', () =>\n service.interrupt('SIGTERM', { phase: 'workflow', source: 'pi-session-shutdown' }),\n );\n }\n await Promise.race([\n Promise.allSettled(pendingInlineRuns),\n new Promise((settle) => setTimeout(settle, SHUTDOWN_FINALIZE_TIMEOUT_MS).unref?.()),\n ]);\n }\n if (monitorTimer) clearInterval(monitorTimer);\n monitorTimer = undefined;\n if (statusRefreshTimer) clearTimeout(statusRefreshTimer);\n statusRefreshTimer = undefined;\n const provider = runProvider;\n runProvider = undefined;\n if (provider) await runCleanup('unregister the background-work provider', () => provider.dispose());\n lifecycleNarrationReady = false;\n inspectorHandle?.hide();\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n terminals.forget(new Set());\n closeOverlay();\n sessionRunCount = 0;\n if (context) clearFollow(context);\n else if (followTimer) clearInterval(followTimer);\n followTimer = undefined;\n followedRun = undefined;\n progressOverlay.dispose();\n workflowMode = false;\n publishedWorkflowState = undefined;\n const mode = modeContribution;\n\n if (mode) {\n await runCleanup('publish the inactive workflow mode', () => mode.publish());\n await runCleanup('dispose the workflow mode owner', () => mode.detach());\n }\n const leaderActions = disposeLeaderActions;\n disposeLeaderActions = undefined;\n if (leaderActions) await runCleanup('dispose workflow leader actions', leaderActions);\n const pendingCount = pendingInlineRuns.size;\n const activeTelemetry = telemetry;\n telemetry = undefined;\n if (activeTelemetry) {\n await runCleanup('record the workflow session finish', () =>\n activeTelemetry.recordEvent('doom_workflow.session_finished', {\n 'workflow.pending_count': pendingCount,\n outcome: pendingCount === 0 ? 'completed' : 'interrupted',\n }),\n );\n await runCleanup('stop workflow telemetry', () => activeTelemetry.shutdown());\n }\n pendingInlineRuns.clear();\n pendingTerminalRuns.clear();\n deliveredTerminalRuns.clear();\n announcedRuns.length = 0;\n knownSessionId = undefined;\n sessionCtx = undefined;\n })();\n return disposal;\n };\n\n return {\n dispose,\n commands,\n messageRenderers,\n toolDependencies,\n waitForReadiness,\n services: [...(services ?? []), piMinorModes([modeContribution])],\n shortcuts: [\n [\n UNFOLLOW_SHORTCUT,\n {\n description: 'Open workflows or move typing between a workflow run and this session',\n handler: async (ctx) => {\n await waitForReadiness();\n // With a panel up this is a focus toggle, not a dismissal: the run stays\n // visible either way, and the user is only choosing who receives keys.\n const handle = activeOverlay?.handle;\n if (handle) {\n // pi-tui's `focus()` does not honour `nonCapturing`, so a view-only\n // panel would take the keyboard if this were left to fall through,\n // and every key after it would vanish into a run that cannot hear it.\n if (!activeOverlay?.interactive) {\n ctx.ui.notify('This run is hosted natively, so the view takes no typing. Your keys stay here.', 'info');\n return;\n }\n if (handle.isFocused()) {\n handle.unfocus();\n ctx.ui.notify('Typing goes to this session. The run keeps going.', 'info');\n } else {\n handle.focus();\n ctx.ui.notify(`Typing goes to ${activeOverlay?.runKey}.`, 'info');\n }\n return;\n }\n if (followedRun) {\n clearFollow(ctx);\n ctx.ui.notify('Workflow continues in the background.', 'info');\n return;\n }\n await openInspector(ctx);\n },\n },\n ],\n [\n CLOSE_OVERLAY_SHORTCUT,\n {\n description: 'Close the workflow run view',\n handler: async (ctx) => {\n await waitForReadiness();\n // Guarded so the key falls through to Pi when no panel is up.\n if (!activeOverlay) return;\n const runKey = activeOverlay.runKey;\n closeOverlay();\n ctx.ui.notify(`Closed the ${runKey} view. The run keeps going.`, 'info');\n },\n },\n ],\n ],\n events: { session_start: onSessionStart, resources_discover: onResourcesDiscover },\n\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n get restrict() {\n return workflowToolRestriction(workflowMode);\n },\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n };\n}\n","import type { PiPluginContext, PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { definePiTool } from '@agimon-ai/doompi-core/piExtension';\nimport { DOOM_SKILL_SOURCES_SERVICE, requireDoomSkillSourcesService } from '@agimon-ai/doompi-core/skills';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { PACKAGE_SOURCE } from '../../../../../constants/workflow';\nimport {\n createWorkflowFence,\n dispatcherTools,\n dispatcherToolRestriction,\n isWorkflowDispatcherProcess,\n resolveDispatcherParentSession,\n} from '../../../../../services/workflowFence';\nimport { workflowSkillDirectory } from '../../../../../services/workflowResource';\nimport { createWorkflowTools } from '../../../../../services/workflowTools';\nimport { registerLeaderContribution } from '../../../../../tui/leader';\nimport { renderWorkflowToolCall, renderWorkflowToolResult } from '../../../../../tui/workflow/workflowToolRender';\nimport { createWorkflowPiRuntime, type WorkflowPiExtensionOptions } from '../../../../../tui/workflowRuntime';\n\nexport default (({ pi, context, options, signal }) => {\n const environment = options?.environment ?? Object.freeze({ ...process.env });\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const fence = createWorkflowFence(pi, signal);\n let workflowMode = false;\n let leader: ReturnType<typeof registerLeaderContribution> | undefined;\n const runtime = createWorkflowPiRuntime(fence.pi, {\n ...options,\n environment,\n cordis: context,\n initialMode: dispatcher || options?.initialMode,\n isActive: fence.isCurrentInvocation,\n runCleanup: fence.runCleanup,\n onModeChange(enabled) {\n workflowMode = enabled;\n leader?.setMode(enabled);\n options?.onModeChange?.(enabled);\n },\n });\n const nativeTools = createWorkflowTools(runtime.toolDependencies, (name) => ({\n renderCall: (args, theme) => renderWorkflowToolCall(name, args as Record<string, unknown>, theme),\n renderResult: (result, renderOptions, theme, renderContext) =>\n renderWorkflowToolResult(\n name,\n renderContext.args as Record<string, unknown>,\n result,\n { ...renderOptions, isError: renderContext.isError },\n theme,\n ),\n }));\n const selectedTools = dispatcher\n ? dispatcherTools(nativeTools, resolveDispatcherParentSession(environment), environment)\n : nativeTools;\n return {\n services: [\n ...(runtime.services ?? []),\n (cordis: Context) => {\n cordis.inject([DOOM_SKILL_SOURCES_SERVICE], (skillContext) => {\n const directory = workflowSkillDirectory();\n const contribution = requireDoomSkillSourcesService(skillContext).register({\n source: PACKAGE_SOURCE,\n directories: [directory],\n });\n return () => contribution.dispose();\n });\n if (!dispatcher)\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = registerLeaderContribution(requireDoomUiHub(uiContext), workflowMode);\n leader = contribution;\n return () => {\n contribution.dispose();\n if (leader === contribution) leader = undefined;\n };\n });\n },\n ],\n tools: selectedTools.map((tool) =>\n definePiTool(\n fence.tool({\n ...tool,\n async execute(...args) {\n await runtime.waitForReadiness(args[2]);\n return tool.execute(...args);\n },\n }),\n ),\n ),\n commands: runtime.commands.map(([name, command]) => fence.command(name, command)),\n shortcuts: runtime.shortcuts?.map(([key, shortcut]) => fence.shortcut(key, shortcut)),\n events: fence.events(runtime.events ?? {}),\n\n toolRestrictions: [\n ...(runtime.toolRestrictions ?? []),\n ...(dispatcher ? [{ source: `${PACKAGE_SOURCE}/dispatcher`, restrict: dispatcherToolRestriction() }] : []),\n ],\n resources: dispatcher\n ? []\n : [\n {\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-workflow',\n description: 'Author DoomPi workflow definitions, job dependencies and host-executed steps.',\n },\n {\n name: 'doompi-use-workflow',\n description: 'Discover, launch, monitor, control and recover DoomPi workflow runs.',\n },\n ],\n },\n ],\n async onStop() {\n fence.beginDisposal();\n await fence.runCleanup(() => runtime.dispose());\n },\n async onDispose() {\n fence.beginDisposal();\n try {\n await fence.runCleanup(() => runtime.dispose());\n } finally {\n fence.finishDisposal();\n }\n },\n };\n}) satisfies (\n context: PiPluginContext<Partial<WorkflowPiExtensionOptions>>,\n) => PiPluginContributions<Partial<WorkflowPiExtensionOptions>>;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from './_lib/index.cli';\n\nexport default defineRoot((context: Parameters<typeof runtime>[0]) => {\n const value = runtime(context);\n return {\n value,\n services: value.services,\n onStop: () => value.onStop(),\n onDispose: () => value.onDispose(),\n };\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.commands[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (\n context: WithRoot<unknown, ReturnType<typeof runtime>>,\n ): NonNullable<PiEventHandlers['resources_discover']> | undefined => context.root.events?.resources_discover,\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.events?.session_start,\n { cardinality: 'optional' },\n);\n","import type { PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\n\nexport function workflowSkillsResource(\n resources: PiPluginContributions['resources'],\n moduleUrl: string,\n): NonNullable<PiPluginContributions['resources']>[number] | undefined {\n const resource = resources?.[0];\n return resource ? { ...resource, moduleUrl } : undefined;\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\nimport { workflowSkillsResource } from '../_lib/workflowSkillsResource';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) =>\n workflowSkillsResource(context.root.resources, import.meta.url),\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.shortcuts?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.shortcuts?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.toolRestrictions,\n { cardinality: 'many' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools,\n { cardinality: 'many' },\n);\n","/**\n * Renders the `workflow-run-finished` custom message: one line per run that\n * reached a terminal state, rather than the host's default block of the\n * `[workflow-run-finished]` label above raw markdown.\n *\n * The same shape `@agimon-ai/doompi-team` gives a slash launch: a status glyph,\n * the run's identity, its outcome, and anything that went wrong indented under\n * it. A finished run is read at a glance in a transcript that is mostly about\n * something else, so it earns a line, not a card.\n *\n * DESIGN PATTERNS:\n * - A message with no `details` renders its content verbatim. That is a\n * transcript entry written before the field existed, and re-deriving it by\n * parsing the summary back out of markdown is exactly the liability\n * `completionNotice.ts` in the team package refused to port\n * - The full summary is still the message's `content`, which is what the model\n * reads and what `deliverAs: 'steer'` carries. This changes what a person\n * sees, never what the agent is told\n */\n\nimport type { ExtensionAPI, Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, Text } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_FINISHED_MESSAGE = 'workflow-run-finished';\n\n/** One finished run, as the extension records it on the message. */\nexport interface WorkflowFinishedRun {\n runKey: string;\n workspace: string;\n stage: string;\n workflowId?: string;\n failedJob?: string;\n error?: string;\n}\n\nexport interface WorkflowFinishedDetails {\n /** Kept for readers that already index runs by id; the lines come from `runs`. */\n runIds?: string[];\n runs?: WorkflowFinishedRun[];\n}\n\nconst COMPLETED_STAGE = 'completed';\nconst HELD_STAGES = new Set(['stopped', 'paused', 'cancelled']);\n\nfunction statusIcon(stage: string, theme: Theme): string {\n if (stage === COMPLETED_STAGE) return theme.fg('success', '✔');\n // Held is not failed: the run went nowhere wrong, it just stopped short.\n if (HELD_STAGES.has(stage)) return theme.fg('warning', '■');\n return theme.fg('error', '✖');\n}\n\nfunction runLine(run: WorkflowFinishedRun, theme: Theme): string {\n const separator = ` ${theme.fg('dim', '·')} `;\n const identity = [run.runKey, run.workspace].filter(Boolean).join('/');\n const parts = [theme.fg('dim', identity), theme.fg('dim', run.stage)];\n if (run.workflowId) parts.unshift(theme.bold(run.workflowId));\n let text = `${statusIcon(run.stage, theme)} ${parts.join(separator)}`;\n if (run.failedJob) text += `\\n ${theme.fg('dim', `⎿ failed job: ${run.failedJob}`)}`;\n if (run.error) text += `\\n ${theme.fg('dim', `⎿ ${run.error}`)}`;\n return text;\n}\n\n/**\n * Exported for tests: the rendered string before it is wrapped in a `Text`\n * component, so the formatting is assertable without a terminal.\n */\nexport function renderWorkflowFinished(runs: readonly WorkflowFinishedRun[], theme: Theme): string {\n return runs.map((run) => runLine(run, theme)).join('\\n');\n}\n\nexport function isWorkflowFinishedRuns(value: unknown): value is WorkflowFinishedRun[] {\n if (!Array.isArray(value) || value.length === 0) return false;\n return value.every(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as WorkflowFinishedRun).runKey === 'string' &&\n typeof (entry as WorkflowFinishedRun).stage === 'string',\n );\n}\n\nexport function createWorkflowFinishedRenderer(): readonly [...Parameters<ExtensionAPI['registerMessageRenderer']>] {\n return [\n WORKFLOW_FINISHED_MESSAGE,\n (message, _options, theme: Theme): Component => {\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n const runs = (message.details as WorkflowFinishedDetails | undefined)?.runs;\n if (!isWorkflowFinishedRuns(runs)) return new Text(content, 0, 0);\n return new Text(renderWorkflowFinished(runs, theme), 0, 0);\n },\n ];\n}\n","import { defineMessageRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createWorkflowFinishedRenderer } from './_lib/workflowFinishedRenderer';\n\nexport default defineMessageRenderer(...createWorkflowFinishedRenderer());\n","import type { PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { Box, type Component, Text, truncateToWidth } from '@earendil-works/pi-tui';\n\nexport const LEGACY_WORKFLOW_STEP_MESSAGE = 'workflow-step';\n\ninterface WorkflowStepMessageDetails {\n displayName: string;\n duration?: string;\n job: string;\n status: 'STARTED' | 'FINISHED' | 'FAILED';\n step: string;\n}\n\nfunction isWorkflowStepMessageDetails(value: unknown): value is WorkflowStepMessageDetails {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Partial<WorkflowStepMessageDetails>;\n return (\n typeof candidate.displayName === 'string' &&\n typeof candidate.job === 'string' &&\n typeof candidate.step === 'string' &&\n (candidate.status === 'STARTED' || candidate.status === 'FINISHED' || candidate.status === 'FAILED') &&\n (candidate.duration === undefined || typeof candidate.duration === 'string')\n );\n}\n\nclass WorkflowStepMessageLines implements Component {\n constructor(\n private readonly details: WorkflowStepMessageDetails,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n const header = `${this.theme.fg('accent', `[${this.details.displayName}]:`)} ${this.details.job}`;\n const transition = this.details.duration\n ? `${this.details.status}::${this.details.duration}::${this.details.step}`\n : `${this.details.status}::${this.details.step}`;\n const colour =\n this.details.status === 'FAILED' ? 'error' : this.details.status === 'FINISHED' ? 'success' : 'accent';\n return [truncateToWidth(header, width), truncateToWidth(this.theme.fg(colour, transition), width)];\n }\n\n invalidate(): void {}\n}\n\nfunction renderWorkflowStepMessage(\n details: WorkflowStepMessageDetails | undefined,\n fallback: string,\n outputPad: number,\n theme: Theme,\n): Component {\n const box = new Box(outputPad, 1, (text) => theme.bg('customMessageBg', text));\n box.addChild(details ? new WorkflowStepMessageLines(details, theme) : new Text(fallback, 0, 0));\n return box;\n}\n\nexport const workflowStepRenderer: NonNullable<PiPluginContributions['messageRenderers']>[number][1] = (\n message,\n { outputPad },\n theme,\n) => {\n const details = isWorkflowStepMessageDetails(message.details) ? message.details : undefined;\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n return renderWorkflowStepMessage(details, content, outputPad, theme);\n};\n","import { defineMessageRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { LEGACY_WORKFLOW_STEP_MESSAGE, workflowStepRenderer } from './_lib/workflowStepRenderer';\n\nexport default defineMessageRenderer(LEGACY_WORKFLOW_STEP_MESSAGE, workflowStepRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandWorkflowLaunch from '../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli';\nimport hookResourcesDiscover from '../src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli';\nimport resourceWorkflowSkills from '../src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli';\nimport shortcutWorkflowPanel from '../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli';\nimport shortcutWorkflowViewClose from '../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli';\nimport toolRestrictionWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli';\nimport toolWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool/workflow.cli';\nimport messageWorkflowFinished from '../src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli';\nimport messageWorkflowStep from '../src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandWorkflowLaunch> | OptionsOf<typeof hookResourcesDiscover> | OptionsOf<typeof hookSessionStart> | OptionsOf<typeof resourceWorkflowSkills> | OptionsOf<typeof shortcutWorkflowPanel> | OptionsOf<typeof shortcutWorkflowViewClose> | OptionsOf<typeof toolRestrictionWorkflow> | OptionsOf<typeof toolWorkflow> | OptionsOf<typeof messageWorkflowFinished> | OptionsOf<typeof messageWorkflowStep>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n/* v8 ignore next -- generated normalization branch */\nconst keyed = <T>(key: string, value: T | undefined): Record<string, T> =>\n value === undefined ? {} : { [key]: value };\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-workflow', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return defined([at(commandWorkflowLaunch, contextSession)]); },\n events: {\n ...keyed('resources_discover', at(hookResourcesDiscover, contextSession) as NonNullable<PiPluginContributions['events']>['resources_discover']),\n ...keyed('session_start', at(hookSessionStart, contextSession) as NonNullable<PiPluginContributions['events']>['session_start']),\n },\n get messageRenderers(): PiPluginContributions['messageRenderers'] { return [at(messageWorkflowFinished, contextSession), at(messageWorkflowStep, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return defined([at(resourceWorkflowSkills, contextSession)]); },\n get shortcuts(): PiPluginContributions['shortcuts'] { return defined([at(shortcutWorkflowPanel, contextSession), at(shortcutWorkflowViewClose, contextSession)]); },\n get toolRestrictions(): PiPluginContributions['toolRestrictions'] { return [...many(toolRestrictionWorkflow, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-workflow', [...many(toolWorkflow, contextSession)]),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pi.cjs","names":["WORKFLOW_RUN_TOOL_NAME","resolveRootSessionId","readChildProcessContext","SUBAGENT_PARENT_SESSION_ENV","AsyncLocalStorage","z","resolveRootSessionId","createEmbeddedWorkflowFeature","z","resolve","WORKFLOW_RUN_TOOL_NAME","resolveRootSessionId","asRecord","detailLines","DoomToolResult","DoomToolCall","renderToolHeading","resolve","COMPLETED_STAGE","ERROR_STAGE","truncateToWidth","visibleWidth","ELLIPSIS","DOOM_FULLSCREEN_UI_OPTIONS","visibleWidth","truncateToWidth","ELLIPSIS","HARD_RESET","fit","truncateToWidth","visibleWidth","rightAligned","DOOM_FULLSCREEN_UI_OPTIONS","TITLE","BREADCRUMB","DEFAULT_PAGE_SIZE","META_INDENT","EMPTY_NAME","KEY_CLEAR","FILTER_LABEL","FOOTER","FOOTER_HINTS","visibleWidth","wrapTextWithAnsi","truncateToWidth","matchesKey","Key","fit","rightAligned","WORKFLOW_FINISHED_MESSAGE","COMPLETED_STAGE","HELD_STAGES","statusIcon","runLine","renderWorkflowFinished","isWorkflowFinishedRuns","createWorkflowFinishedRenderer","Text","DOOM_FULLSCREEN_UI_OPTIONS","TITLE","OUTPUT_HEADING","truncateToWidth","visibleWidth","currentWorkflowPosition","matchesKey","isKeyRelease","matchesKey","DOOM_FULLSCREEN_UI_OPTIONS","KEY_CLEAR","DIM","ACCENT","SELECTED_BG","ROW_BG","matchesKey","fit","truncateToWidth","DOOM_FULLSCREEN_UI_OPTIONS","matchesKey","fit","rightAligned","matchesKey","fit","DOOM_FULLSCREEN_UI_OPTIONS","isWorkflowStepMessageDetails","WorkflowStepMessageLines","truncateToWidth","renderWorkflowStepMessage","Box","Text","LEGACY_WORKFLOW_STEP_MESSAGE","truncateToWidth","visibleWidth","SUBAGENT_ROOT_SESSION_ENV","basename","extname","createRequire","spawn","createEmbeddedWorkflowFeature","randomUUID","readDoomReadinessCoordinator","createDoomReadinessCoordinator","registerRunProvider","defineMinorMode","createDoomTelemetry","createNarrationRequest","DOOM_NARRATION_SERVICE","requireDoomNarrationService","resolveRootSessionId","readWorkflowProgress","summarizeWorkflowProgress","WORKFLOW_FINISHED_MESSAGE","WorkflowTerminalService","createWorkflowTerminalService","resolve","readFile","parseWorkflowLaunchCommand","isLaunchParseFailure","resolveWorkflowEntry","validateWorkflowLaunch","workflowSkillDirectory","existsSync","createWorkflowFinishedRenderer","isWorkflowStepMessageDetails","renderWorkflowStepMessage","DOOM_UI_HUB_SERVICE","requireDoomUiHub","piMinorModes","DOOM_SKILL_SOURCES_SERVICE","workflowSkillDirectory","requireDoomSkillSourcesService","DOOM_UI_HUB_SERVICE","requireDoomUiHub","definePiTool","defineRoot","runtime","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","Text","defineMessageRenderer","truncateToWidth","Box","Text","defineMessageRenderer","definePiExtension","rootSession","composeRootHooks","commandWorkflowLaunch","hookResourcesDiscover","hookSessionStart","messageWorkflowFinished","messageWorkflowStep","resourceWorkflowSkills","shortcutWorkflowPanel","shortcutWorkflowViewClose","toolRestrictionWorkflow","piToolContributions","toolWorkflow"],"sources":["../../src/constants/workflow.ts","../../src/services/workflowFence/index.ts","../../src/schemas/workflowPi.ts","../../src/services/piToolBridge/index.ts","../../src/services/workflowExecution/index.ts","../../src/services/workflowTools/index.ts","../../src/tui/leader.ts","../../src/tui/workflow/workflowToolRender.ts","../../src/services/workflowLauncher/index.ts","../../src/services/workflowNarration/index.ts","../../src/tui/workflow/rendering.ts","../../src/tui/workflow/doomOverlay.ts","../../src/tui/workflow/overlayText.ts","../../src/tui/workflow/workflowCatalog.ts","../../src/tui/workflow/workflowFinishedMessage.ts","../../src/tui/workflow/workflowStatusRow.ts","../../src/tui/workflow/workflowInspector.ts","../../src/tui/workflow/workflowOverlay.ts","../../src/tui/workflow/workflowPicker.ts","../../src/tui/workflow/workflowProgressOverlay.ts","../../src/tui/workflow/workflowPrompt.ts","../../src/tui/workflow/workflowRunPanel.ts","../../src/tui/workflow/workflowStepMessage.ts","../../src/tui/workflowRuntime.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/index.cli.ts","../../src/extensions/workspaces/sessions/(backend)/root.cli.ts","../../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/workflowSkillsResource.ts","../../src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli.ts","../../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli.ts","../../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli.ts","../../src/extensions/workspaces/sessions/(backend)/tool/workflow.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowFinishedRenderer.ts","../../src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli.ts","../../src/extensions/workspaces/sessions/(frontend)/message/_lib/workflowStepRenderer.ts","../../src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli.ts","../../generated/pi.ts"],"sourcesContent":["export const COMMAND_DESCRIPTION = 'Doom Pi workflow execution and monitoring integration';\nexport const PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\n\nexport const LEADER_KEY = 'w';\nexport const LEADER_LABEL = 'workflows';\nexport const LEADER_ORDER = 50;\nexport const LEADER_ENABLE_ACTION = 'workflow.enable';\nexport const LEADER_DISABLE_ACTION = 'workflow.disable';\nexport const LEADER_MANAGE_ACTION = 'workflow.manage';\nexport const LEADER_RECOVER_ACTION = 'workflow.recover';\nexport const LEADER_CATALOG_ACTION = 'workflow.catalog';\nexport const LEADER_DETAIL = 'multi-step agent runs';\n\nexport const LIST_WORKFLOWS_TOOL_NAME = 'list_workflows';\nexport const LAUNCH_WORKFLOW_TOOL_NAME = 'launch_workflow';\nexport const WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\nexport const WORKFLOW_PI_TOOL_NAMES = [\n LIST_WORKFLOWS_TOOL_NAME,\n LAUNCH_WORKFLOW_TOOL_NAME,\n WORKFLOW_RUN_TOOL_NAME,\n] as const;\n","import { AsyncLocalStorage } from 'node:async_hooks';\n\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-core/childProcess';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\nimport type { ExtensionAPI, ExtensionContext, ToolDefinition } from '@earendil-works/pi-coding-agent';\n\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\nconst WORKFLOW_RUN_TOOL_NAME = 'workflow_run';\n\ntype ToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\nexport interface WorkflowFence {\n tool<TSchema extends ToolSchema, TDetails>(\n tool: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails>;\n command(name: string, options: CommandOptions): readonly [string, CommandOptions];\n shortcut(\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): readonly [Parameters<ExtensionAPI['registerShortcut']>[0], ShortcutOptions];\n events(handlers: PiEventHandlers): PiEventHandlers;\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/**\n * A dispatcher child launches workflows for its root session and never runs one\n * itself, so `workflow_run` stays off its surface even if something registers it.\n */\nexport function dispatcherToolRestriction(): DoomToolRestriction {\n return (incoming) => incoming.filter((name) => name !== WORKFLOW_RUN_TOOL_NAME);\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function dispatcherTools<TSchema extends ToolSchema, TDetails>(\n tools: readonly ToolDefinition<TSchema, TDetails>[],\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>>,\n): ToolDefinition<TSchema, TDetails>[] {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return tools\n .filter((tool) => DISPATCHER_TOOL_NAMES.has(tool.name))\n .map((tool) => {\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) return tool;\n return {\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n };\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nexport function createWorkflowFence(host: ExtensionAPI, signal?: AbortSignal): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n const currentScope = scope.getStore();\n if (!active || (signal?.aborted && currentScope !== CLEANUP_SCOPE)) return false;\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const tool = <TSchema extends ToolSchema, TDetails>(\n definition: ToolDefinition<TSchema, TDetails>,\n ): ToolDefinition<TSchema, TDetails> => {\n return {\n ...definition,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n definition.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n if (!active || disposing || executionGeneration !== generation) throw new Error(INACTIVE_RUNTIME_MESSAGE);\n return result;\n },\n };\n };\n\n const command: WorkflowFence['command'] = (name, options) => {\n return [\n name,\n {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const shortcut: WorkflowFence['shortcut'] = (key, options) => {\n return [\n key,\n {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n },\n ];\n };\n\n const events = (handlers: PiEventHandlers): PiEventHandlers =>\n Object.fromEntries(\n Object.entries(handlers).map(([eventName, handler]) => [\n eventName,\n (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () =>\n (handler as LifecycleHandler)(event, guardContext(context, eventGeneration)),\n );\n },\n ]),\n ) as PiEventHandlers;\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n tool,\n command,\n shortcut,\n events,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n","import { z } from 'zod';\n\nconst RUN_SELECTOR_FIELDS = {\n runKey: z.string().min(1).describe('Run key of the workflow run.'),\n workspace: z.string().optional().describe('Workspace the run belongs to.'),\n} as const;\n\nexport const workflowRunInputSchema = z.discriminatedUnion('action', [\n z.object({ action: z.literal('status'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('tail'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('recovery-evidence'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('follow'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('open'), ...RUN_SELECTOR_FIELDS }).strict(),\n z.object({ action: z.literal('pause'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z.object({ action: z.literal('resume'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z.object({ action: z.literal('stop'), ...RUN_SELECTOR_FIELDS, reason: z.string().optional() }).strict(),\n z\n .object({\n action: z.literal('recover'),\n ...RUN_SELECTOR_FIELDS,\n dryRun: z.boolean().optional(),\n job: z.string().optional(),\n runner: z.string().optional(),\n })\n .strict(),\n]);\n\nexport type WorkflowRunInput = z.infer<typeof workflowRunInputSchema>;\n\nexport const dispatchInputSchema = z\n .object({\n description: z.string().optional().describe('Description shown for the workflow input.'),\n required: z.boolean().optional().describe('Whether the workflow input must be provided.'),\n default: z.string().optional().describe('Default value for the workflow input.'),\n type: z.string().optional().describe('Declared workflow input type.'),\n options: z.array(z.string()).optional().describe('Allowed values for the workflow input.'),\n })\n .passthrough();\n\nexport type DispatchInput = z.infer<typeof dispatchInputSchema>;\n\nexport const workflowDispatchInputsSchema = z\n .object({\n inputs: z.record(z.string(), dispatchInputSchema).optional().describe('Workflow dispatch input definitions.'),\n })\n .passthrough();\n\nexport const workflowCatalogPageSchema = z\n .object({\n directory: z.string().min(1).describe('Directory searched for workflow definitions.'),\n hasNextPage: z.boolean().describe('Whether another catalog page exists.'),\n page: z.number().int().positive().describe('One-based catalog page number.'),\n pageSize: z.number().int().positive().describe('Catalog page size.'),\n workflows: z\n .array(\n z\n .object({\n path: z.string().min(1).describe('Workflow path relative to the catalog directory.'),\n name: z.string().describe('Workflow display name.'),\n description: z.string().describe('Workflow description.'),\n tags: z.array(z.string()).describe('Workflow tags.'),\n })\n .passthrough(),\n )\n .describe('Workflow definitions on this page.'),\n })\n .passthrough();\n","/**\n * Pure bridging logic between MCP tool results and the Pi tool surface.\n *\n * DESIGN PATTERNS:\n * - Adapter pattern: MCP `CallToolResult` is converted to Pi's result shape\n * - Pure module: no service or tool-class imports, so this is unit-testable\n * without constructing the workflow execution stack\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported functions\n *\n * AVOID:\n * - Importing tool classes or services here (that belongs in `piTools.ts`)\n * - Returning an error flag Pi does not read; Pi tools signal failure by throwing\n */\n\nimport type { WorkflowProgressJob, WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { AgentToolResult } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/server';\n\n/**\n * Environment variable stamped onto every run launched from a Pi session.\n *\n * `RunWorkflowService` forwards `env` to the inner CLI invocation across the\n * `launch-command` delegation boundary and persists it on the run record, so\n * this survives backgrounding and identifies the launching session afterwards.\n */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\n/** Operator override for the per-session launch ceiling. */\nconst MAX_CONCURRENT_ENV = 'WORKFLOW_MCP_MAX_CONCURRENT';\nconst DEFAULT_MAX_CONCURRENT = 5;\n\nexport interface WorkflowToolDetails {\n tool: string;\n}\n\n/** Resolve the per-session launch ceiling from the environment. */\nexport function resolveMaxConcurrent(env: NodeJS.ProcessEnv = process.env): number {\n const parsed = Number(env[MAX_CONCURRENT_ENV]);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT;\n}\n\n/**\n * True when this session launched the run.\n *\n * Fails closed on a missing session id: an unstamped record (a CLI launch) and\n * a call arriving before the session id is known both match nothing, so no run\n * ever leaks across sessions through an undefined-equals-undefined comparison.\n */\nexport function isSessionRun(record: WorkflowRunRecord, sessionId: string | undefined): boolean {\n return sessionId !== undefined && record.env?.[PI_SESSION_ENV] === sessionId;\n}\n\n/** Runs launched by one Pi session that are still running. */\nexport function runsForSession(records: WorkflowRunRecord[], sessionId: string): WorkflowRunRecord[] {\n return records.filter((record) => isSessionRun(record, sessionId) && record.stage === 'running');\n}\n\n/**\n * What the caller is told when the registry, not the launcher, acknowledged a\n * launch.\n *\n * Leads with the run key because it is the handle every other workflow action\n * takes, and it is no longer available any other way: the launcher's own output\n * is not waited for, so nothing else in this result carries it.\n */\nexport function launchedRunSummary(record: WorkflowRunRecord): string {\n return [\n `Started ${record.displayName} in workspace ${record.workspace}.`,\n `Run key: ${record.runKey}`,\n 'The run is registered and going. This call returned at that point rather than waiting for the launcher process to exit.',\n ].join('\\n');\n}\n\n/**\n * What the caller is told when the launch was handed off but no run has\n * registered inside the acknowledgement budget.\n *\n * Deliberately not an error: the launcher is slow rather than broken often\n * enough that failing here would strand runs that go on to start normally.\n * There is no run key to offer yet, so it points at the surfaces that do not\n * need one.\n */\nexport function launchHandoffSummary(workflowPath: string): string {\n return [\n `Launch handed off for ${workflowPath}, but no run has registered yet.`,\n 'Nothing was cancelled: the launcher is still starting, and a run that registers later still reports back here when it finishes.',\n 'Do not launch it again. Ask the user to check the active workflow list if they need to see it sooner.',\n ].join('\\n');\n}\n\n/**\n * Escape sequences a terminal consumes rather than prints.\n *\n * Built from a string with the rule silenced, the way `doom-runner`'s own\n * scrubber does it, because matching the escape byte is the entire job. Not\n * imported from there: that package's published build is a stale artifact\n * missing the export, and a launch notice should not need another package's\n * build to be current.\n */\n// oxlint-disable-next-line no-control-regex -- matching terminal control bytes is the point\nconst ESCAPE_SEQUENCE = new RegExp(\n ['\\\\u001B\\\\[[0-9;?]*[ -/]*[@-~]', '\\\\u001B\\\\][^\\\\u0007\\\\u001B]*(?:\\\\u0007|\\\\u001B\\\\\\\\)', '\\\\u001B[@-Z\\\\\\\\-_]'].join(\n '|',\n ),\n 'g',\n);\n\n/** Rows made only of box-drawing: separators that carry nothing once trimmed. */\nconst RULE_ROW = /^[\\s─-╿]*$/u;\nconst NOTICE_LINE_LIMIT = 3;\n/**\n * Widest a notice row may be before it is clipped.\n *\n * A three-line cap does not bound a toast on its own: the engine announces its\n * delegation by echoing the whole shell command, temp script path included, and\n * one line of that wraps across three rows of a narrow terminal and shoves the\n * transcript around. Clipped at a width every terminal can hold instead.\n */\nconst NOTICE_WIDTH_LIMIT = 100;\n\n/**\n * Cut a tool result down to something a toast can hold.\n *\n * The launch result used to reach `ui.notify` whole, and for a workflow that\n * executes in this process that result is the engine's entire console log:\n * banner, run directory, job tree, rules, colour. Pi rendered every line of it\n * over the transcript, which reads as a broken screen rather than as output.\n * Escape sequences go first: the log carries colour the notification would\n * render as literal text, and a stray clear or cursor-move would do to the\n * screen exactly what this function exists to prevent.\n */\nexport function launchNotice(text: string, limit: number = NOTICE_LINE_LIMIT): string {\n const lines = text\n .replace(ESCAPE_SEQUENCE, '')\n .split('\\n')\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0 && !RULE_ROW.test(line))\n .map((line) => (line.length > NOTICE_WIDTH_LIMIT ? `${line.slice(0, NOTICE_WIDTH_LIMIT - 1)}…` : line));\n if (lines.length === 0) return 'Workflow started.';\n if (lines.length <= limit) return lines.join('\\n');\n return [...lines.slice(0, limit), `… ${lines.length - limit} more lines, in the run's own output.`].join('\\n');\n}\n\n/** Flatten MCP tool content to text for Pi. */\nexport function toolResultText(result: CallToolResult): string {\n return result.content\n .map((part) => (part.type === 'text' ? part.text : ''))\n .filter(Boolean)\n .join('\\n')\n .trim();\n}\n\n/**\n * Convert an MCP tool result into a Pi tool result.\n *\n * Pi signals tool failure by throwing: the agent loop catches it and builds the\n * error result. So an `isError` MCP result becomes a thrown error rather than a\n * successful result carrying a flag Pi would ignore.\n */\nexport function toAgentToolResult(\n tool: string,\n result: CallToolResult,\n errorOptions: string[] = [],\n): AgentToolResult<WorkflowToolDetails> {\n const text = toolResultText(result) || 'No output.';\n if (result.isError) throw new Error(withOptions(text, errorOptions));\n return { content: [{ type: 'text', text }], details: { tool } };\n}\n\n/**\n * Attach a short menu of next steps to a problem.\n *\n * An error with no route forward is where an agent invents one: retrying a\n * capacity limit, relaunching a run that should be recovered, or silently\n * giving up on work the user is waiting for. Naming two or three real options\n * turns an error into a decision, and the decision belongs to the user.\n */\nexport function withOptions(problem: string, options: string[]): string {\n if (options.length === 0) return problem;\n return [problem, '', 'Options, put these to the user rather than picking one yourself:', ...options.map(bullet)].join(\n '\\n',\n );\n}\n\nfunction bullet(option: string): string {\n return `- ${option}`;\n}\n\n/** The job and step a run died on, preferring the progress log to the record. */\nfunction failurePosition(\n record: WorkflowRunRecord,\n jobs: WorkflowProgressJob[],\n): { job?: string; step?: string; reason?: string } {\n // The progress log knows which step was in flight; the record only names the\n // job. Falling back keeps this working for runs that predate the log.\n const failedJob = jobs.find((job) => job.status === 'failed');\n const failedStep = failedJob?.steps.find((step) => step.status === 'failed');\n return {\n job: failedJob?.name ?? record.failedJob,\n step: failedStep?.name,\n reason: failedStep?.reason ?? failedJob?.reason,\n };\n}\n\n/**\n * Describe a finished run for the agent that launched it.\n *\n * Carries the job identifiers back so a dispatching agent can match the run to\n * the work item it launched it for without another lookup. When the run failed,\n * carries the failing step and a set of options too: the agent is being told\n * about this out of band, with no user question in flight, so without them it\n * has to guess whether to recover, relaunch, or report.\n */\nexport function finishedRunSummary(record: WorkflowRunRecord, jobs: WorkflowProgressJob[] = []): string {\n const outcome = record.stage === 'completed' ? 'completed' : `ended in ${record.stage}`;\n const failure = failurePosition(record, jobs);\n const lines: Array<string | undefined> = [\n `Workflow run ${record.runKey} in workspace ${record.workspace} ${outcome}.`,\n record.workflowId ? `Workflow: ${record.workflowId}` : undefined,\n failure.job ? `Failed job: ${failure.job}${failure.step ? ` (step: ${failure.step})` : ''}` : undefined,\n record.errorMessage ? `Error: ${record.errorMessage}` : undefined,\n failure.reason && failure.reason !== record.errorMessage ? `Step reported: ${failure.reason}` : undefined,\n ];\n const jobId = record.env?.AGIFLOW_JOB_ID;\n if (jobId) lines.push(`Agiflow job: ${record.env?.AGIFLOW_JOB_KIND ?? 'unknown'} ${jobId}`);\n\n const summary = lines.filter((line): line is string => Boolean(line)).join('\\n');\n if (record.stage === 'completed') return summary;\n\n // A run the user stopped is not a defect, so it gets no diagnosis step: the\n // question is only whether to pick it back up.\n const stopped = record.outcome === 'interrupted';\n if (stopped) {\n return withOptions(summary, [\n `workflow_run {\"action\":\"recover\",\"runKey\":${JSON.stringify(record.runKey)}}: pick it up where it stopped.`,\n 'Leave it stopped and move on.',\n ]);\n }\n\n const diagnosticText = [record.errorMessage, failure.reason].filter(Boolean).join('\\n');\n if (diagnosticText.includes('JOB_ALREADY_CLAIMED')) {\n return withOptions(summary, [\n 'Report contention: another worker owns this job. Do not unlock, release, or retry the claim automatically.',\n ]);\n }\n if (diagnosticText.includes('WORKFLOW_NOT_OWNED') || /release failed/i.test(diagnosticText)) {\n return withOptions(summary, [\n 'Inspect the current workflow ownership and ask the user before any release or unlock. Never force another worker’s lock.',\n ]);\n }\n if (/running workflow not found/i.test(diagnosticText)) {\n return withOptions(summary, [\n `workflow_run {\"action\":\"status\",\"runKey\":${JSON.stringify(record.runKey)}}: re-check current state before retrying.`,\n 'Report the recorded terminal state when no running owner remains.',\n ]);\n }\n\n return withOptions(summary, [\n `workflow_run {\"action\":\"tail\",\"runKey\":${JSON.stringify(record.runKey)}}: read the run's own output first, when the error above does not explain the failure.`,\n `workflow_run {\"action\":\"recover\",\"runKey\":${JSON.stringify(record.runKey)}}: resume from the failed job, keeping the work already done. Fits a transient or external cause.`,\n 'Report the failure and stop, when it needs a code change or a decision you cannot make.',\n ]);\n}\n","import { resolveRootSessionId } from '@agimon-ai/doompi-core/childProcess';\nimport type { DoomToolRestriction } from '@agimon-ai/doompi-core/toolSurface';\nimport { type EmbeddedWorkflowFeature, type WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/server';\nimport { z } from 'zod';\n\nimport { type WorkflowRunInput } from '../../schemas/workflowPi';\nimport {\n launchedRunSummary,\n launchHandoffSummary,\n PI_SESSION_ENV,\n resolveMaxConcurrent,\n toolResultText,\n withOptions,\n} from '../piToolBridge';\n\nconst AGIFLOW_JOB_ID_ENV = 'AGIFLOW_JOB_ID';\nconst AGIFLOW_JOB_KIND_ENV = 'AGIFLOW_JOB_KIND';\nconst AGIFLOW_PROJECT_ID_ENV = 'AGIFLOW_PROJECT_ID';\n\nimport { WORKFLOW_PI_TOOL_NAMES, LAUNCH_WORKFLOW_TOOL_NAME } from '../../constants/workflow';\n\n/**\n * What workflow mode does to the tool surface: nothing but hide its own tools.\n *\n * The tools are registered for the whole session because Pi has no other way to\n * add one later, so the mode is expressed as a restriction rather than as a\n * registration.\n */\nexport function workflowToolRestriction(enabled: boolean): DoomToolRestriction {\n const hidden = new Set<string>(WORKFLOW_PI_TOOL_NAMES);\n return (incoming) => (enabled ? incoming : incoming.filter((name) => !hidden.has(name)));\n}\n\nexport type WorkflowRunSelector = Pick<WorkflowRunInput, 'runKey' | 'workspace'>;\n\nexport type WorkflowLaunchInput = z.infer<ReturnType<EmbeddedWorkflowFeature['runTool']['getInputSchema']>>;\n\n/**\n * Where a launch was answered from, which decides what the caller is told.\n *\n * Tagged rather than inferred from an absent field: the failure carries an\n * `unknown`, and `unknown` includes `undefined`, so only a tag can tell a\n * rejection apart from a result.\n */\ntype LaunchOutcome = { kind: 'value'; result: CallToolResult } | { kind: 'error'; error: unknown };\ntype LaunchAck =\n | { kind: 'settled'; outcome: LaunchOutcome }\n | { kind: 'record'; record: WorkflowRunRecord }\n | { kind: 'handoff' };\n\n/** How often the registry is asked whether the launch has produced a run. */\nconst LAUNCH_ACK_POLL_MS = 500;\n/**\n * How long to wait for that before answering without a run key.\n *\n * Long enough to cover a launcher that is merely slow, short enough that a\n * caller is never left holding a turn open for a launcher that will not answer.\n */\nconst LAUNCH_ACK_TIMEOUT_MS = 15_000;\n\nexport interface LaunchedRunQuery {\n sessionId: string | undefined;\n /** Epoch milliseconds the launch began, so an earlier run cannot match. */\n since: number;\n workflowPath: string;\n}\n\nexport interface WorkflowLaunchExecutorDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n activeRunCount?: () => Promise<number>;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n observeSession?: (sessionId: string | undefined) => void;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n runTool: EmbeddedWorkflowFeature['runTool'];\n trackPendingRun: <T>(run: Promise<T>) => Promise<T>;\n /**\n * The run this launch registered, or undefined while none has appeared.\n *\n * Its presence is what lets a launch answer on the registry instead of on the\n * launcher process exiting. Left out, the launch waits for the process, which\n * is the behaviour every caller had before.\n */\n findLaunchedRun?: (query: LaunchedRunQuery) => Promise<WorkflowRunRecord | undefined>;\n /** Report a launch that fails after this call already answered \"started\". */\n onLateFailure?: (error: unknown, ctx: ExtensionContext) => void;\n launchAckPollMs?: number;\n launchAckTimeoutMs?: number;\n}\n\nexport interface WorkflowLaunchExecutor {\n execute(\n input: WorkflowLaunchInput,\n ctx: ExtensionContext,\n onUpdate?: AgentToolUpdateCallback<{ tool: string }>,\n ): Promise<CallToolResult>;\n}\n\nexport interface WorkflowPiToolDependencies {\n readonly environment: Readonly<Record<string, string | undefined>>;\n launchExecutor?: WorkflowLaunchExecutor;\n onLaunch?: (ctx: ExtensionContext) => Promise<void> | void;\n activeRunCount?: () => Promise<number>;\n followRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n tailRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n openRun?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n rejectRunner?: (workflowPath: string, runner: string) => string | undefined;\n requireSessionRun?: (input: WorkflowRunSelector, sessionId: string | undefined) => Promise<WorkflowRunRecord>;\n /**\n * Resolve a failed recovery target globally.\n *\n * Recovery is the one ownership-transferring action: a replacement Pi\n * session must be able to adopt a terminal run whose launching session is\n * gone. Every non-recovery action remains session-scoped.\n */\n requireRecoverableRun?: (input: WorkflowRunSelector) => Promise<WorkflowRunRecord>;\n readRecoveryEvidence?: (input: WorkflowRunSelector, ctx: ExtensionContext) => Promise<string>;\n /**\n * Hand a recovery to a terminal launcher, returning what to tell the caller.\n *\n * Undefined means this recovery cannot be delegated, and the in-process\n * replay below is used instead.\n */\n delegateRecovery?: (\n input: { runKey: string; workspace?: string; runner?: string },\n ctx: ExtensionContext,\n ) => Promise<string | undefined>;\n observeSession?: (sessionId: string | undefined) => void;\n trackPendingRun?: <T>(run: Promise<T>) => Promise<T>;\n feature?: EmbeddedWorkflowFeature;\n recoverTool?: {\n execute(input: {\n dryRun?: boolean;\n job?: string;\n runKey: string;\n runner?: string;\n workspace?: string;\n }): Promise<CallToolResult>;\n };\n controlTool?: ReturnType<EmbeddedWorkflowFeature['createControlTool']>;\n runTool?: EmbeddedWorkflowFeature['runTool'];\n listWorkflowsTool?: EmbeddedWorkflowFeature['listWorkflowsTool'];\n}\n\nexport function reportProgress(\n onUpdate: AgentToolUpdateCallback<{ tool: string }> | undefined,\n tool: string,\n message: string,\n): void {\n onUpdate?.({ content: [{ type: 'text', text: message }], details: { tool } });\n}\n\nexport function appendGuidance(\n result: AgentToolResult<{ tool: string }>,\n guidance: string,\n): AgentToolResult<{ tool: string }> {\n return { ...result, content: [...result.content, { type: 'text', text: guidance }] };\n}\n\nfunction statusAction(runKey: string): string {\n return `workflow_run {\"action\":\"status\",\"runKey\":${JSON.stringify(runKey)}}`;\n}\n\nexport function actionGuidance(action: WorkflowRunInput['action'], runKey: string): string[] {\n const status = statusAction(runKey);\n if (action === 'stop') return [`Next: call ${status} to confirm the run reached a terminal stage.`];\n if (action === 'recover') {\n return [\n `Report the recovery failure and do not retry it blindly: call ${status} first.`,\n 'Ask the user before launching fresh work when the recorded recovery is no longer valid.',\n ];\n }\n return [`Next: call ${status} to verify the recorded execution state.`];\n}\n\nexport const launchFailureOptions = [\n 'Report the failure to the user with the error above. A launch failure is usually a bad workflow path, a missing launcher, or a workflow whose own pre-conditions refused.',\n 'list_workflows: confirm the workflow path exists and its description matches the work, if the path may be wrong.',\n 'workflow_run with action status: check whether an earlier attempt is already running before launching again.',\n];\n\n/**\n * An Error, whatever the launch rejected with.\n *\n * A rejection reaches here as `unknown` because it crossed a promise boundary,\n * and rethrowing that as-is hands Pi's tool layer something it cannot read a\n * message or a stack off. The original is kept as the cause rather than\n * flattened into a string.\n */\nfunction asError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value), { cause: value });\n}\n\n/** Resolves to undefined, so a race against it reads as \"nothing settled yet\". */\nfunction sleep(ms: number): Promise<undefined> {\n return new Promise((settle) => {\n const timer = setTimeout(() => settle(undefined), ms);\n timer.unref?.();\n });\n}\n\n/**\n * Wait for whichever answer arrives first: the launch settling, the run\n * appearing in the registry, or the budget running out.\n *\n * A launch that delegates to a terminal launcher settles when that launcher's\n * whole process chain closes, which on a loaded machine has been measured\n * minutes after the run itself was registered and working. The registry is the\n * earlier and more truthful signal: a run recorded there is a run that started.\n */\nasync function awaitLaunchAck(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n query: LaunchedRunQuery,\n): Promise<LaunchAck> {\n const findLaunchedRun = dependencies.findLaunchedRun;\n if (!findLaunchedRun) return { kind: 'settled', outcome: await settled };\n\n const pollMs = dependencies.launchAckPollMs ?? LAUNCH_ACK_POLL_MS;\n const deadline = Date.now() + (dependencies.launchAckTimeoutMs ?? LAUNCH_ACK_TIMEOUT_MS);\n for (;;) {\n const outcome = await Promise.race([settled, sleep(pollMs)]);\n if (outcome) return { kind: 'settled', outcome };\n // A registry read that throws must not fail the launch: the run may be\n // perfectly healthy, and the settled promise is still the fallback.\n const record = await findLaunchedRun(query).catch(() => undefined);\n if (record) return { kind: 'record', record };\n if (Date.now() >= deadline) return { kind: 'handoff' };\n }\n}\n\n/**\n * Carry a failure that lands after the caller was told the run started.\n *\n * Answering early trades the launcher's exit code for timeliness. Dropping that\n * code entirely is not part of the trade: a launch that fails a minute later\n * would otherwise leave a user waiting on a run that never existed.\n */\nfunction reportLateFailure(\n settled: Promise<LaunchOutcome>,\n dependencies: WorkflowLaunchExecutorDependencies,\n ctx: ExtensionContext,\n): void {\n void settled.then((outcome) => {\n if (outcome.kind === 'error') {\n dependencies.onLateFailure?.(asError(outcome.error), ctx);\n return;\n }\n if (outcome.result.isError) {\n dependencies.onLateFailure?.(new Error(toolResultText(outcome.result) || 'Workflow launch failed.'), ctx);\n }\n });\n}\n\nexport function createWorkflowLaunchExecutor(dependencies: WorkflowLaunchExecutorDependencies): WorkflowLaunchExecutor {\n return {\n async execute(input, ctx, onUpdate) {\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), dependencies.environment);\n dependencies.observeSession?.(sessionId);\n const agiflowJobKind = input.env?.[AGIFLOW_JOB_KIND_ENV]?.trim();\n const agiflowJobId = input.env?.[AGIFLOW_JOB_ID_ENV]?.trim();\n const explicitProjectId = input.env?.[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (Boolean(agiflowJobKind) !== Boolean(agiflowJobId)) {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND and AGIFLOW_JOB_ID together.');\n }\n if (agiflowJobKind && agiflowJobKind !== 'task' && agiflowJobKind !== 'work-unit') {\n throw new Error('Agiflow workflow launches require AGIFLOW_JOB_KIND to be task or work-unit.');\n }\n if (agiflowJobKind && !explicitProjectId) {\n throw new Error('Agiflow workflow launches require AGIFLOW_PROJECT_ID with the job identity.');\n }\n if (agiflowJobKind && !input.prompt?.trim()) {\n throw new Error(\n 'Agiflow workflow launches require a non-empty prompt so user_prompt runs do not wait for terminal input.',\n );\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, 'Checking workflow capacity...');\n const maxConcurrent = resolveMaxConcurrent(dependencies.environment);\n const active = (await dependencies.activeRunCount?.()) ?? 0;\n if (active >= maxConcurrent) {\n throw new Error(\n withOptions(`This session is at capacity: ${active}/${maxConcurrent} workflows running.`, [\n 'Wait for a running workflow to finish, then launch again. The extension reports each one as it ends.',\n 'workflow_run with action status: show what is running, so the user can judge whether something is stuck.',\n 'workflow_run with action stop: free a slot by stopping a run the user no longer wants.',\n ]),\n );\n }\n\n if (input.runner) {\n const rejection = dependencies.rejectRunner?.(input.workflowPath, input.runner);\n if (rejection) throw new Error(rejection);\n }\n reportProgress(onUpdate, LAUNCH_WORKFLOW_TOOL_NAME, `Launching workflow ${input.workflowPath}...`);\n const workflowEnv = { ...input.env };\n const dispatcherContextFile = dependencies.environment.AGIFLOW_DISPATCH_CONTEXT_FILE;\n const dispatcherProjectId = dependencies.environment[AGIFLOW_PROJECT_ID_ENV]?.trim();\n if (\n dispatcherContextFile &&\n agiflowJobKind &&\n dispatcherProjectId &&\n explicitProjectId &&\n dispatcherProjectId !== explicitProjectId\n ) {\n throw new Error(\n `Agiflow workflow project identity conflicts with the dispatcher context (${explicitProjectId} versus ${dispatcherProjectId}).`,\n );\n }\n if (dispatcherContextFile) {\n for (const key of [\n 'AGIFLOW_ORGANIZATION_ID',\n 'AGIFLOW_PROJECT_ID',\n 'AGIFLOW_DEVICE_ID',\n 'BACKEND_AGIFLOW_API_ENDPOINT',\n 'AGIFLOW_DISPATCH_SECRET_FILE',\n ] as const) {\n const hostValue = dependencies.environment[key];\n if (hostValue) workflowEnv[key] = hostValue;\n }\n }\n const since = Date.now();\n const launch = dependencies.trackPendingRun(\n dependencies.runTool.execute({\n ...input,\n env: { ...workflowEnv, [PI_SESSION_ENV]: sessionId },\n }),\n );\n // Folded into a value before anything races it. A promise this function\n // may stop awaiting must never be able to reject unobserved, which in\n // Node ends the whole process, Pi's TUI included.\n const settled: Promise<LaunchOutcome> = launch.then(\n (value): LaunchOutcome => ({ kind: 'value', result: value }),\n (error: unknown): LaunchOutcome => ({ kind: 'error', error }),\n );\n\n const ack = await awaitLaunchAck(settled, dependencies, {\n sessionId,\n since,\n workflowPath: input.workflowPath,\n });\n\n if (ack.kind === 'settled') {\n const outcome = ack.outcome;\n if (outcome.kind === 'error') throw asError(outcome.error);\n const result = outcome.result;\n if (result.isError)\n throw new Error(withOptions(toolResultText(result) || 'Workflow launch failed.', launchFailureOptions));\n await dependencies.onLaunch?.(ctx);\n return result;\n }\n\n reportLateFailure(settled, dependencies, ctx);\n await dependencies.onLaunch?.(ctx);\n return {\n content: [\n {\n type: 'text',\n text: ack.kind === 'record' ? launchedRunSummary(ack.record) : launchHandoffSummary(input.workflowPath),\n },\n ],\n };\n },\n };\n}\n","import { resolve } from 'node:path';\n\nimport { resolveRootSessionId } from '@agimon-ai/doompi-core/childProcess';\nimport {\n createEmbeddedWorkflowFeature,\n type WorkflowRunRecord,\n type EmbeddedWorkflowFeature,\n} from '@agimon-ai/workflow-mcp';\nimport type { ExtensionAPI, ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { z } from 'zod';\n\nimport { workflowRunInputSchema } from '../../schemas/workflowPi';\nimport { toAgentToolResult, type WorkflowToolDetails } from '../../services/piToolBridge';\nimport {\n type WorkflowLaunchInput,\n type WorkflowRunSelector,\n launchFailureOptions,\n} from '../../services/workflowExecution';\nimport {\n createWorkflowLaunchExecutor,\n reportProgress,\n appendGuidance,\n actionGuidance,\n type WorkflowPiToolDependencies,\n} from '../../services/workflowExecution';\ntype WorkflowToolSchema = Parameters<ExtensionAPI['registerTool']>[0]['parameters'];\nimport {\n WORKFLOW_PI_TOOL_NAMES,\n LIST_WORKFLOWS_TOOL_NAME,\n LAUNCH_WORKFLOW_TOOL_NAME,\n WORKFLOW_RUN_TOOL_NAME,\n} from '../../constants/workflow';\nconst PI_LAUNCH_FIELDS = {\n workflowPath: true,\n workspace: true,\n runner: true,\n name: true,\n env: true,\n prompt: true,\n job: true,\n inputs: true,\n} as const;\nexport type WorkflowNativeTool = ToolDefinition<WorkflowToolSchema, WorkflowToolDetails>;\nexport type WorkflowToolRenderers = Pick<WorkflowNativeTool, 'renderCall' | 'renderResult'>;\nexport function createWorkflowTools(\n dependencies: WorkflowPiToolDependencies,\n renderers: (name: (typeof WORKFLOW_PI_TOOL_NAMES)[number]) => WorkflowToolRenderers = () => ({}),\n): WorkflowNativeTool[] {\n const feature = dependencies.feature ?? createEmbeddedWorkflowFeature();\n const runTool = dependencies.runTool ?? feature.runTool;\n const listWorkflowsTool = dependencies.listWorkflowsTool ?? feature.listWorkflowsTool;\n const recoverTool = dependencies.recoverTool ?? feature.createRecoverTool();\n const controlTool = dependencies.controlTool ?? feature.createControlTool();\n const trackPendingRun = dependencies.trackPendingRun ?? (<T>(run: Promise<T>): Promise<T> => run);\n const launchExecutor =\n dependencies.launchExecutor ??\n createWorkflowLaunchExecutor({\n environment: dependencies.environment,\n activeRunCount: dependencies.activeRunCount,\n onLaunch: dependencies.onLaunch,\n observeSession: dependencies.observeSession,\n rejectRunner: dependencies.rejectRunner,\n runTool,\n trackPendingRun,\n });\n\n return [\n {\n name: LIST_WORKFLOWS_TOOL_NAME,\n label: 'List Workflows',\n description: 'List the workflow definitions available in this repository.',\n promptSnippet: 'List available workflow definitions',\n parameters: z.toJSONSchema(listWorkflowsTool.getInputSchema()),\n renderShell: 'self',\n ...renderers(LIST_WORKFLOWS_TOOL_NAME),\n async execute(_toolCallId, params, _signal, _onUpdate, ctx) {\n const input = params as Parameters<EmbeddedWorkflowFeature['listWorkflowsTool']['execute']>[0];\n return toAgentToolResult(\n LIST_WORKFLOWS_TOOL_NAME,\n await listWorkflowsTool.execute({\n ...input,\n directory:\n input?.directory === undefined\n ? ctx.cwd\n : typeof input.directory === 'string'\n ? resolve(ctx.cwd, input.directory)\n : input.directory,\n }),\n );\n },\n },\n\n {\n name: LAUNCH_WORKFLOW_TOOL_NAME,\n label: 'Launch Workflow',\n description:\n 'Start a workflow run. Returns once the run has started, not once it finishes; use workflow_run with action status or wait for the completion notice.',\n promptSnippet: 'Start a workflow run and return its identifier',\n promptGuidelines: [\n 'Before launching, call list_workflows and pick the workflow whose own description matches the work. A workflow description is the source of truth; never infer one from its filename. If nothing matches, say so and stop rather than launching an approximate fit.',\n 'launch_workflow returns when the run has STARTED, not when it has finished. Never report success from its result. Poll workflow_run with action status, or wait for the completion notice the extension delivers on its own.',\n 'When dispatching Agiflow work, pass AGIFLOW_PROJECT_ID, AGIFLOW_JOB_KIND, and AGIFLOW_JOB_ID through env plus a non-empty prompt. Kind must be task or work-unit. The id alone is not a key, and omitting prompt leaves user_prompt workflows waiting for terminal input.',\n 'A workflow claims its own job in its pre step. Never claim a job yourself. JOB_ALREADY_CLAIMED or HTTP 409 means another worker won the race, so report contention and do not unlock, release, or retry automatically.',\n 'If a result says WORKFLOW_NOT_OWNED or a release failed, inspect current ownership and ask the user before any release or unlock. Never force another worker’s lock.',\n 'If a running workflow is not found, call workflow_run with action status to re-check current state before retrying.',\n 'The per-session concurrency ceiling is a real limit. If launch_workflow refuses, wait for a run to finish; do not launch through the shell to get around it.',\n ],\n parameters: z.toJSONSchema(runTool.getInputSchema().pick(PI_LAUNCH_FIELDS)),\n renderShell: 'self',\n ...renderers(LAUNCH_WORKFLOW_TOOL_NAME),\n async execute(_toolCallId, params, _signal, onUpdate, ctx) {\n const input = params as WorkflowLaunchInput;\n const result = await launchExecutor.execute(input, ctx, onUpdate);\n const adapted = toAgentToolResult(LAUNCH_WORKFLOW_TOOL_NAME, result, launchFailureOptions);\n return appendGuidance(\n adapted,\n 'Next: call workflow_run with action status and verify the recorded stage before reporting the workflow outcome.',\n );\n },\n },\n\n {\n name: WORKFLOW_RUN_TOOL_NAME,\n label: 'Workflow Run',\n description:\n 'Inspect or control one workflow run. Use action status, tail, recovery-evidence, follow, open, pause, resume, stop, or recover. Every action requires an exact run key.',\n promptSnippet: 'Inspect or control a workflow run',\n promptGuidelines: [\n 'Use action status as the authority for stage, outcome, execution state, and pause cursor. A run that started is not a run that succeeded.',\n 'Use action pause or resume for cooperative lifecycle control. Pause is not stop: the run keeps its stage running, capacity, services, and heartbeat while paused.',\n 'Use action stop only when the user requests stopping a run. A user-requested stop is not a failure and needs no failure diagnosis.',\n 'Do not use follow or tail merely to wait for a healthy run; use status or the completion notice. Tail returns chat-safe status without raw PTY frames. Use follow only when the user asks to pin live progress, and open only when a human wants the recorded launcher foregrounded.',\n 'Use action recovery-evidence for terminal-only, durable status and artifacts before recovery. It is the only inspection path that may read a failed run from an earlier session and it never reads a live launcher.',\n 'Use action recover only after loading the `workflow-recovery` skill and gathering its required evidence. Recovery may adopt a terminal failed run from an earlier Pi session; it never grants cross-session control of running work. Never edit issue.md or repair.json, and verify real process and registry progress before recovery.',\n 'Never unlock or force-release an Agiflow claim from this tool.',\n ],\n parameters: z.toJSONSchema(workflowRunInputSchema),\n renderShell: 'self',\n ...renderers(WORKFLOW_RUN_TOOL_NAME),\n async execute(_toolCallId, rawParams, _signal, onUpdate, ctx) {\n const input = workflowRunInputSchema.parse(rawParams);\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), dependencies.environment);\n dependencies.observeSession?.(sessionId);\n const selector: WorkflowRunSelector = { runKey: input.runKey, workspace: input.workspace };\n const requireOwnedRun = async (): Promise<WorkflowRunRecord> => {\n if (!dependencies.requireSessionRun) {\n throw new Error('Workflow run ownership is not available in this session.');\n }\n return dependencies.requireSessionRun(selector, sessionId);\n };\n\n if (input.action === 'status') {\n const record = await requireOwnedRun();\n return {\n content: [{ type: 'text', text: JSON.stringify(record, null, 2) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'tail') {\n if (!dependencies.tailRun) throw new Error('Reading workflow output is not available in this session.');\n const record = await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Reading output for workflow ${input.runKey}...`);\n await dependencies.tailRun(selector, ctx);\n return {\n content: [\n {\n type: 'text',\n text: [\n `Workflow: ${record.displayName} (${record.runKey})`,\n `Stage: ${record.effectiveStage ?? record.stage}`,\n 'Raw launcher output is hidden from chat. Use action follow or open to view it.',\n ].join('\\n'),\n },\n ],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'recovery-evidence') {\n if (!dependencies.readRecoveryEvidence) {\n throw new Error('Reading workflow recovery evidence is not available in this session.');\n }\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Reading recovery evidence for workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.readRecoveryEvidence(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'follow') {\n if (!dependencies.followRun) throw new Error('Following workflow output is not available in this session.');\n await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Following workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.followRun(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n if (input.action === 'open') {\n if (!dependencies.openRun) throw new Error('Opening a workflow launcher is not available in this session.');\n await requireOwnedRun();\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Opening workflow ${input.runKey}...`);\n return {\n content: [{ type: 'text', text: await dependencies.openRun(selector, ctx) }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n\n if (input.action === 'recover') {\n if (!dependencies.requireRecoverableRun) {\n throw new Error('Workflow recovery ownership transfer is not available in this session.');\n }\n const recoverable = await dependencies.requireRecoverableRun(selector);\n const recoverySelector = { runKey: recoverable.runKey, workspace: recoverable.workspace };\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Recovering workflow ${input.runKey}...`);\n // A recovery replays the workflow, and the replay skips the launch\n // step, so every job runs in THIS process. For a workflow whose steps\n // are interactive that means an agent TUI spawned onto this process's\n // own terminal. Hand it to a launcher instead, where the workflow says\n // how. A dry run prints rather than executes, so it stays here.\n if (!input.dryRun) {\n const delegated = await dependencies.delegateRecovery?.({ ...recoverySelector, runner: input.runner }, ctx);\n if (delegated) {\n const guidance = actionGuidance(input.action, input.runKey);\n await dependencies.onLaunch?.(ctx);\n return {\n content: [{ type: 'text', text: [delegated, guidance[0]].join('\\n\\n') }],\n details: { tool: WORKFLOW_RUN_TOOL_NAME },\n };\n }\n }\n const recoverInput = {\n dryRun: input.dryRun,\n job: input.job,\n runKey: recoverySelector.runKey,\n runner: input.runner,\n workspace: recoverySelector.workspace,\n };\n const result = await trackPendingRun(recoverTool.execute(recoverInput));\n const guidance = actionGuidance(input.action, input.runKey);\n const adapted = toAgentToolResult(WORKFLOW_RUN_TOOL_NAME, result, guidance);\n await dependencies.onLaunch?.(ctx);\n return appendGuidance(adapted, guidance[0]!);\n }\n\n const ownedRun = await requireOwnedRun();\n if (!ownedRun.runId) throw new Error(`Workflow ${input.runKey} has no controllable run generation.`);\n reportProgress(onUpdate, WORKFLOW_RUN_TOOL_NAME, `Requesting ${input.action} for workflow ${input.runKey}...`);\n const result = await controlTool.execute({\n action: input.action,\n expectedRunId: ownedRun.runId,\n reason: input.reason,\n runKey: input.runKey,\n workspace: input.workspace,\n });\n const guidance = actionGuidance(input.action, input.runKey);\n const adapted = toAgentToolResult(WORKFLOW_RUN_TOOL_NAME, result, guidance);\n return appendGuidance(adapted, guidance[0]!);\n },\n },\n ];\n}\n","import type { LeaderBinding } from '@agimon-ai/doompi-core/leader';\nimport type { DoomUiHubService } from '@agimon-ai/doompi-core/uiHub';\n\nimport {\n LEADER_CATALOG_ACTION,\n LEADER_DETAIL,\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../constants/workflow';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = {\n key: LEADER_KEY,\n label: LEADER_LABEL,\n detail: LEADER_DETAIL,\n order: LEADER_ORDER,\n} as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.catalog`,\n // Launching lives on this board's own `r` key rather than a second menu\n // entry: picking which workflow to run is the same act as reading what\n // one does.\n path: [GROUP_SEGMENT, { key: 'l', label: 'list', detail: 'browse and launch workflows' }],\n action: { name: LEADER_CATALOG_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'runs', detail: 'runs in this session' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools', tone: 'exit' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n // `r` is runs everywhere, so recovery moves off it rather than reading as a\n // third flavour of list in the one space that has both.\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'c', label: 'recover', detail: 'adopt a failed run' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(hub: DoomUiHubService, enabled = false): WorkflowLeaderHandle {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(enabled),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n","import { DoomToolCall, DoomToolResult, renderToolHeading } from '@agimon-ai/doompi-ui/toolChrome';\nimport type { Theme, ThemeColor } from '@earendil-works/pi-coding-agent';\nimport type { Component } from '@earendil-works/pi-tui';\n\nexport type WorkflowToolName = 'launch_workflow' | 'list_workflows' | 'workflow_run';\nexport type WorkflowPiToolName = WorkflowToolName;\n\ninterface WorkflowToolResultLike {\n content?: unknown;\n isError?: boolean;\n}\n\ninterface WorkflowToolRenderOptions {\n expanded: boolean;\n isError?: boolean;\n isPartial?: boolean;\n}\n\ntype JsonRecord = Record<string, unknown>;\n\ntype WorkflowState = {\n color: ThemeColor;\n glyph: string;\n label: string;\n};\n\ninterface WorkflowCatalogItem {\n description: string;\n name: string;\n path: string;\n tags: string[];\n}\n\ninterface WorkflowCatalog {\n directory?: string;\n page: number;\n pageSize: number;\n tags: Array<{ count: number; tag: string }>;\n total: number;\n totalPages: number;\n workflows: WorkflowCatalogItem[];\n}\n\ninterface EvidenceSection {\n body: string[];\n name: string;\n}\n\nconst COLLAPSED_CATALOG_ROWS = 6;\nconst COLLAPSED_DETAIL_LINES = 8;\nconst PARTIAL_DETAIL_LINES = 4;\n\nfunction asRecord(value: unknown): JsonRecord | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;\n return value as JsonRecord;\n}\n\nfunction inlineText(value: string): string {\n let normalized = '';\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n normalized += code <= 31 || code === 127 ? ' ' : character;\n }\n return normalized.replace(/\\s+/gu, ' ').trim();\n}\n\nfunction readString(record: JsonRecord | undefined, key: string): string | undefined {\n const value = record?.[key];\n if (typeof value !== 'string') return undefined;\n return inlineText(value) || undefined;\n}\n\nfunction readNumber(record: JsonRecord | undefined, key: string): number | undefined {\n const value = record?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction readBoolean(record: JsonRecord | undefined, key: string): boolean | undefined {\n const value = record?.[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction readStringArray(record: JsonRecord | undefined, key: string): string[] {\n const value = record?.[key];\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === 'string');\n}\n\nfunction parseJsonRecord(text: string | undefined): JsonRecord | undefined {\n if (!text) return undefined;\n try {\n return asRecord(JSON.parse(text));\n } catch {\n return undefined;\n }\n}\n\nfunction textBlocks(result: WorkflowToolResultLike): string[] {\n if (!Array.isArray(result.content)) return [];\n return result.content.flatMap((item) => {\n const record = asRecord(item);\n return record?.type === 'text' && typeof record.text === 'string' ? [record.text] : [];\n });\n}\n\nfunction detailLines(result: WorkflowToolResultLike): string[] {\n return textBlocks(result)\n .flatMap((block) => block.split('\\n'))\n .map((line) => line.trimEnd())\n .filter((line) => line.length > 0);\n}\n\nfunction firstPayload(result: WorkflowToolResultLike): JsonRecord | undefined {\n return parseJsonRecord(textBlocks(result)[0]);\n}\n\nfunction plural(count: number, singular: string, pluralForm = `${singular}s`): string {\n return count === 1 ? singular : pluralForm;\n}\n\nfunction labelValue(label: string, value: string, theme: Theme): string {\n return `${theme.fg('dim', `${label} `)}${theme.fg('text', value)}`;\n}\n\nfunction targetScope(args: Record<string, unknown>): string | undefined {\n const runKey = readString(args, 'runKey');\n if (!runKey) return undefined;\n const workspace = readString(args, 'workspace');\n return workspace ? `${workspace}/${runKey}` : runKey;\n}\n\nfunction toolAction(toolName: WorkflowPiToolName, args: Record<string, unknown>): string {\n if (toolName === 'list_workflows') return 'list';\n if (toolName === 'launch_workflow') return 'launch';\n return readString(args, 'action') ?? 'run';\n}\n\nfunction toolTarget(toolName: WorkflowPiToolName, args: Record<string, unknown>): string | undefined {\n if (toolName === 'list_workflows') return readString(args, 'directory');\n if (toolName === 'launch_workflow') return readString(args, 'workflowPath');\n return targetScope(args);\n}\n\nfunction renderResult(lines: readonly string[], theme: Theme, expanded: boolean): Component {\n return new DoomToolResult(lines, theme, { wrap: expanded });\n}\n\nfunction hiddenDetailLine(hidden: number, theme: Theme): string {\n return theme.fg('dim', `… ${hidden} more · ctrl+o`);\n}\n\nfunction statusTimestamp(value: string): string {\n return value.replace('T', ' ').replace(/\\.\\d{3}Z$/, 'Z');\n}\n\nfunction workflowNameFromPath(path: string | undefined): string {\n if (!path) return 'workflow';\n const filename = path.split('/').at(-1) ?? path;\n return filename.replace(/\\.workflow\\.ya?ml$/u, '') || filename;\n}\n\nfunction callMetadata(toolName: WorkflowPiToolName, args: Record<string, unknown>, theme: Theme): string[] {\n const values: string[] = [];\n\n if (toolName === 'list_workflows') {\n const page = readNumber(args, 'page');\n const pageSize = readNumber(args, 'pageSize');\n if (page !== undefined) values.push(`page ${page}`);\n if (pageSize !== undefined) values.push(`${pageSize}/page`);\n if (readString(args, 'filter')) values.push('filtered');\n const tags = readStringArray(args, 'tags');\n if (tags.length > 0) values.push(`${tags.length} ${plural(tags.length, 'tag')}`);\n } else if (toolName === 'launch_workflow') {\n const job = readString(args, 'job');\n const runner = readString(args, 'runner');\n const workspace = readString(args, 'workspace');\n const inputCount = Object.keys(asRecord(args.inputs) ?? {}).length;\n const environmentCount = Object.keys(asRecord(args.env) ?? {}).length;\n if (workspace) values.push(`workspace ${workspace}`);\n if (job) values.push(`job ${job}`);\n if (runner) values.push(`runner ${runner}`);\n if (readBoolean(args, 'dryRun')) values.push('dry run');\n if (readString(args, 'prompt')) values.push('with prompt');\n if (inputCount > 0) values.push(`${inputCount} ${plural(inputCount, 'input')}`);\n if (environmentCount > 0) values.push(`${environmentCount} env`);\n } else {\n const expectedRunId = readString(args, 'expectedRunId');\n if (expectedRunId) values.push('generation checked');\n if (readString(args, 'reason')) values.push('with reason');\n if (readBoolean(args, 'dryRun')) values.push('dry run');\n if (readString(args, 'job')) values.push('job override');\n if (readString(args, 'runner')) values.push('runner override');\n }\n\n return values.map((value) => theme.fg('dim', value));\n}\n\nexport function renderWorkflowToolCall(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n theme: Theme,\n): Component {\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const metadata = callMetadata(toolName, args, theme);\n const purpose = [theme.bold(action), target ? theme.fg('muted', target) : undefined, ...metadata]\n .filter((part): part is string => !!part)\n .join(theme.fg('dim', ' · '));\n return new DoomToolCall(renderToolHeading('workflow', purpose, theme));\n}\n\nfunction parseCatalog(payload: JsonRecord | undefined): WorkflowCatalog | undefined {\n if (!Array.isArray(payload?.workflows)) return undefined;\n\n const workflows = payload.workflows.flatMap((value) => {\n const record = asRecord(value);\n const path = readString(record, 'path');\n if (!record || !path) return [];\n return [\n {\n description: readString(record, 'description') ?? '',\n name: readString(record, 'name') ?? '',\n path,\n tags: readStringArray(record, 'tags'),\n },\n ];\n });\n const tags = Array.isArray(payload.tags)\n ? payload.tags.flatMap((value) => {\n const record = asRecord(value);\n const tag = readString(record, 'tag');\n const count = readNumber(record, 'count');\n return tag && count !== undefined ? [{ count, tag }] : [];\n })\n : [];\n\n return {\n directory: readString(payload, 'directory'),\n page: readNumber(payload, 'page') ?? 1,\n pageSize: readNumber(payload, 'pageSize') ?? workflows.length,\n tags,\n total: readNumber(payload, 'total') ?? workflows.length,\n totalPages: readNumber(payload, 'totalPages') ?? (workflows.length > 0 ? 1 : 0),\n workflows,\n };\n}\n\nfunction catalogItemLines(item: WorkflowCatalogItem, expanded: boolean, theme: Theme): string[] {\n const name = item.name || workflowNameFromPath(item.path);\n const lines = [`${theme.fg('accent', '›')} ${theme.bold(name)} ${theme.fg('muted', `· ${item.path}`)}`];\n if (!expanded) return lines;\n if (item.description) lines.push(` ${theme.fg('text', item.description)}`);\n if (item.tags.length > 0) lines.push(` ${labelValue('tags', item.tags.join(', '), theme)}`);\n return lines;\n}\n\nfunction renderCatalogResult(\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component | undefined {\n const catalog = parseCatalog(firstPayload(result));\n if (!catalog) return undefined;\n\n const pageLabel = `page ${catalog.page}/${catalog.totalPages}`;\n const summary = `${theme.fg(catalog.total > 0 ? 'success' : 'muted', catalog.total > 0 ? '✓' : '○')} ${theme.bold(\n `${catalog.total} ${plural(catalog.total, 'workflow')}`,\n )} ${theme.fg('dim', `· ${pageLabel}`)}`;\n const shown = options.expanded ? catalog.workflows : catalog.workflows.slice(0, COLLAPSED_CATALOG_ROWS);\n const lines = [summary, ...shown.flatMap((item) => catalogItemLines(item, options.expanded, theme))];\n const hidden = catalog.workflows.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n\n if (options.expanded) {\n if (catalog.tags.length > 0) {\n const tags = catalog.tags.map(({ count, tag }) => `${tag} (${count})`).join(', ');\n lines.push(labelValue('available tags', tags, theme));\n }\n if (catalog.directory) lines.push(labelValue('directory', catalog.directory, theme));\n lines.push(labelValue('page size', String(catalog.pageSize), theme));\n }\n\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction readWorkflowState(record: JsonRecord): WorkflowState {\n const stage = readString(record, 'effectiveStage') ?? readString(record, 'stage') ?? 'unknown';\n const outcome = readString(record, 'effectiveOutcome') ?? readString(record, 'outcome');\n const executionState = readString(record, 'executionState');\n\n if (outcome === 'interrupted') return { color: 'warning', glyph: '!', label: 'interrupted' };\n if (stage === 'error' || outcome === 'failed') return { color: 'error', glyph: '✗', label: 'failed' };\n if (stage === 'completed' && outcome === 'skipped') return { color: 'muted', glyph: '○', label: 'skipped' };\n if (stage === 'completed') return { color: 'success', glyph: '✓', label: 'completed' };\n if (executionState === 'paused') return { color: 'warning', glyph: 'Ⅱ', label: 'paused' };\n if (executionState === 'pause_requested') return { color: 'warning', glyph: '◐', label: 'pause requested' };\n if (executionState === 'resume_requested') return { color: 'warning', glyph: '◐', label: 'resume requested' };\n if (stage === 'running') return { color: 'accent', glyph: '◐', label: 'running' };\n return { color: 'muted', glyph: '○', label: stage };\n}\n\nfunction recordScope(record: JsonRecord): string {\n const runKey = readString(record, 'runKey') ?? 'unknown run';\n const workspace = readString(record, 'workspace');\n return workspace ? `${workspace}/${runKey}` : runKey;\n}\n\nfunction currentActivity(record: JsonRecord, theme: Theme): string | undefined {\n const cursor = asRecord(record.executionCursor);\n const job = readString(cursor, 'job') ?? readString(record, 'job');\n const step = readString(cursor, 'stepName');\n const phase = readString(cursor, 'phase');\n if (!job && !step && !phase) return undefined;\n const context = job ?? phase ?? 'workflow';\n return ` ${theme.fg('muted', `[${context}]`)} ${theme.fg('text', step ?? phase ?? 'running')}`;\n}\n\nfunction launcherLabel(record: JsonRecord): string | undefined {\n const launcher = asRecord(record.launcher);\n const type = readString(launcher, 'type');\n if (!type) return undefined;\n const identity = readString(launcher, 'sessionName') ?? readString(launcher, 'workspaceId');\n return identity ? `${type} ${identity}` : type;\n}\n\nfunction workflowRecordLines(record: JsonRecord, expanded: boolean, theme: Theme): string[] | undefined {\n const runKey = readString(record, 'runKey');\n const stage = readString(record, 'stage');\n if (!runKey || !stage) return undefined;\n\n const state = readWorkflowState(record);\n const displayName = readString(record, 'displayName') ?? runKey;\n const heading = `${theme.fg(state.color, state.glyph)} ${theme.bold(displayName)} ${theme.fg(\n 'dim',\n `· ${recordScope(record)} ·`,\n )} ${theme.fg(state.color, state.label)}`;\n const lines = [heading];\n const activity = currentActivity(record, theme);\n if (activity) lines.push(activity);\n\n const failure = readString(record, 'errorMessage') ?? readString(record, 'failureReason');\n if (failure) lines.push(`${theme.fg('error', 'error')} ${theme.fg('text', failure)}`);\n const staleReason = readString(record, 'staleReason');\n if (staleReason) lines.push(`${theme.fg('warning', 'stale')} ${theme.fg('text', staleReason)}`);\n\n const conciseMetadata = [\n readString(record, 'runner') ? `runner ${readString(record, 'runner')}` : undefined,\n readBoolean(record, 'dryRun') ? 'dry run' : undefined,\n readNumber(record, 'exitCode') !== undefined ? `exit ${readNumber(record, 'exitCode')}` : undefined,\n readString(record, 'startedAt') ? `started ${statusTimestamp(readString(record, 'startedAt') ?? '')}` : undefined,\n ].filter((value): value is string => !!value);\n if (conciseMetadata.length > 0) lines.push(theme.fg('dim', conciseMetadata.join(' · ')));\n\n if (!expanded) return lines;\n\n const detailedValues: Array<[string, string | undefined]> = [\n ['workflow', readString(record, 'workflowPath')],\n ['workflow id', readString(record, 'workflowId')],\n ['run id', readString(record, 'runId')],\n ['launcher', launcherLabel(record)],\n ['job', readString(record, 'job')],\n ['outcome', readString(record, 'effectiveOutcome') ?? readString(record, 'outcome')],\n [\n 'finished',\n readString(record, 'finishedAt') ? statusTimestamp(readString(record, 'finishedAt') ?? '') : undefined,\n ],\n ['pid', readNumber(record, 'pid')?.toString()],\n ['repair', readString(record, 'activeRepairId') ? `#${readString(record, 'activeRepairId')}` : undefined],\n ['worktree', readString(record, 'worktreeBranch') ?? readString(record, 'worktreePath')],\n ];\n for (const [label, value] of detailedValues) {\n if (value) lines.push(labelValue(label, value, theme));\n }\n return lines;\n}\n\nfunction renderStatusResult(\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component | undefined {\n const payload = firstPayload(result);\n if (!payload) return undefined;\n const lines = workflowRecordLines(payload, options.expanded, theme);\n return lines ? renderResult(lines, theme, options.expanded) : undefined;\n}\n\nfunction nestedRequestedAt(payload: JsonRecord | undefined): string | undefined {\n return readString(asRecord(payload?.request), 'requestedAt') ?? readString(payload, 'requestedAt');\n}\n\nfunction renderControlResult(\n action: string,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const payload = firstPayload(result);\n const scope = targetScope(args) ?? readString(payload, 'runKey') ?? 'workflow';\n const payloadWorkspace = readString(payload, 'workspace');\n const resolvedScope = payloadWorkspace && !scope.includes('/') ? `${payloadWorkspace}/${scope}` : scope;\n const lines = [\n `${theme.fg('warning', '◐')} ${theme.bold(`${action} requested`)} ${theme.fg('dim', `· ${resolvedScope}`)}`,\n ];\n const requestedAt = nestedRequestedAt(payload);\n if (requestedAt) lines.push(labelValue('requested', statusTimestamp(requestedAt), theme));\n if (options.expanded) lines.push(theme.fg('dim', 'verify the transition with workflow_run status'));\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction matchLine(text: string, pattern: RegExp): string | undefined {\n return text.match(pattern)?.[1]?.trim();\n}\n\nfunction launchSummary(\n text: string,\n args: Record<string, unknown>,\n): { name: string; scope: string; state: WorkflowState } {\n const startedName = matchLine(text, /^Started (.+) in workspace .+\\.$/mu);\n const workspace = matchLine(text, /^Started .+ in workspace (.+)\\.$/mu) ?? readString(args, 'workspace');\n const runKey = matchLine(text, /^Run key:\\s*(.+)$/mu);\n const path = readString(args, 'workflowPath');\n const name = startedName ?? workflowNameFromPath(path);\n const scope = runKey ? (workspace ? `${workspace}/${runKey}` : runKey) : (workspace ?? path ?? 'workflow');\n\n if (/Workflow completed successfully/iu.test(text)) {\n return { name, scope, state: { color: 'success', glyph: '✓', label: 'completed' } };\n }\n if (/Workflow skipped/iu.test(text)) {\n return { name, scope, state: { color: 'muted', glyph: '○', label: 'skipped' } };\n }\n if (/no run was registered/iu.test(text)) {\n return { name, scope, state: { color: 'warning', glyph: '◐', label: 'starting · run key pending' } };\n }\n return { name, scope, state: { color: 'accent', glyph: '◐', label: runKey ? 'started' : 'launch accepted' } };\n}\n\nfunction renderLaunchResult(\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const blocks = textBlocks(result);\n const text = blocks.join('\\n');\n const summary = launchSummary(text, args);\n const lines = [\n `${theme.fg(summary.state.color, summary.state.glyph)} ${theme.bold(summary.name)} ${theme.fg(\n 'dim',\n `· ${summary.scope} ·`,\n )} ${theme.fg(summary.state.color, summary.state.label)}`,\n ];\n const metadata = [\n readString(args, 'job') ? `job ${readString(args, 'job')}` : undefined,\n readString(args, 'runner') ? `runner ${readString(args, 'runner')}` : undefined,\n readBoolean(args, 'dryRun') ? 'dry run' : undefined,\n ].filter((value): value is string => !!value);\n if (metadata.length > 0) lines.push(theme.fg('dim', metadata.join(' · ')));\n if (options.expanded) {\n const details = detailLines(result).filter((line) => !line.startsWith('Next steps for the agent:'));\n if (details.length > 0) lines.push(...details);\n }\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction splitEvidence(text: string): EvidenceSection[] {\n const sections: EvidenceSection[] = [];\n let current: EvidenceSection | undefined;\n for (const line of text.split('\\n')) {\n const match = line.match(/^--- (.+) ---$/u);\n if (match?.[1]) {\n current = { body: [], name: match[1] };\n sections.push(current);\n continue;\n }\n current?.body.push(line);\n }\n return sections;\n}\n\nfunction recoveryRecord(sections: EvidenceSection[]): JsonRecord | undefined {\n const runSection = sections.find((section) => section.name === 'run.json');\n return parseJsonRecord(runSection?.body.join('\\n'));\n}\n\nfunction renderRecoveryEvidenceResult(\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const text = textBlocks(result).join('\\n');\n const sections = splitEvidence(text);\n const record = recoveryRecord(sections);\n const recordLines = record ? workflowRecordLines(record, options.expanded, theme) : undefined;\n const evidenceSections = sections.filter((section) => section.name !== 'run.json');\n const scope = targetScope(args) ?? 'workflow';\n const lines = recordLines ?? [\n `${theme.fg('success', '✓')} ${theme.bold('recovery evidence')} ${theme.fg('dim', `· ${scope}`)}`,\n ];\n const names = evidenceSections.map((section) => section.name);\n lines.push(\n names.length > 0\n ? labelValue('evidence', names.join(', '), theme)\n : theme.fg('muted', 'no durable evidence files recorded'),\n );\n\n if (options.expanded) {\n for (const section of evidenceSections) {\n lines.push(theme.bold(section.name), ...section.body.filter((line) => line.length > 0));\n }\n }\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderSimpleActionResult(\n action: string,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const scope = targetScope(args) ?? 'workflow';\n const actionLabel: Record<string, string> = {\n follow: 'following output',\n open: 'launcher opened',\n recover: readBoolean(args, 'dryRun') ? 'recovery dry run finished' : 'recovery accepted',\n tail: 'launcher output checked',\n };\n const state: WorkflowState =\n action === 'recover'\n ? { color: 'accent', glyph: '◐', label: actionLabel[action] ?? action }\n : { color: 'success', glyph: '✓', label: actionLabel[action] ?? action };\n const lines = [`${theme.fg(state.color, state.glyph)} ${theme.bold(state.label)} ${theme.fg('dim', `· ${scope}`)}`];\n const details = detailLines(result);\n if (action === 'tail') {\n const stageLine = details.find((line) => line.startsWith('Stage:'));\n const workflowLine = details.find((line) => line.startsWith('Workflow:'));\n if (workflowLine) lines.push(workflowLine);\n if (stageLine) lines.push(stageLine);\n }\n if (options.expanded && details.length > 0) lines.push(...details);\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderFailure(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const summary = `${theme.fg('error', '✗')} ${theme.bold(`${action} failed`)}${\n target ? theme.fg('dim', ` · ${target}`) : ''\n }`;\n const details = detailLines(result);\n const shown = options.expanded ? details : details.slice(0, COLLAPSED_DETAIL_LINES);\n const lines = [summary, ...(shown.length > 0 ? shown : [theme.fg('error', 'Unknown workflow error')])];\n const hidden = details.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderPartial(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n const details = detailLines(result);\n const shown = details.slice(-PARTIAL_DETAIL_LINES);\n const action = toolAction(toolName, args);\n const target = toolTarget(toolName, args);\n const summary = `${theme.fg('accent', '◐')} ${theme.bold(action)}${target ? theme.fg('dim', ` · ${target}`) : ''}`;\n const hidden = details.length - shown.length;\n const lines = [summary];\n if (hidden > 0) lines.push(theme.fg('dim', `… ${hidden} earlier`));\n lines.push(...shown);\n return renderResult(lines, theme, options.expanded);\n}\n\nfunction renderFallback(result: WorkflowToolResultLike, options: WorkflowToolRenderOptions, theme: Theme): Component {\n const details = detailLines(result);\n if (details.length === 0) return renderResult([theme.fg('muted', 'No workflow output.')], theme, options.expanded);\n const shown = options.expanded ? details : details.slice(0, COLLAPSED_DETAIL_LINES);\n const lines = [...shown];\n const hidden = details.length - shown.length;\n if (hidden > 0) lines.push(hiddenDetailLine(hidden, theme));\n return renderResult(lines, theme, options.expanded);\n}\n\nexport function renderWorkflowToolResult(\n toolName: WorkflowPiToolName,\n args: Record<string, unknown>,\n result: WorkflowToolResultLike,\n options: WorkflowToolRenderOptions,\n theme: Theme,\n): Component {\n if (options.isPartial) return renderPartial(toolName, args, result, options, theme);\n if (options.isError === true || result.isError === true) {\n return renderFailure(toolName, args, result, options, theme);\n }\n\n if (toolName === 'list_workflows') {\n return renderCatalogResult(result, options, theme) ?? renderFallback(result, options, theme);\n }\n if (toolName === 'launch_workflow') return renderLaunchResult(args, result, options, theme);\n\n const action = readString(args, 'action');\n if (action === 'status') {\n return renderStatusResult(result, options, theme) ?? renderFallback(result, options, theme);\n }\n if (action === 'pause' || action === 'resume' || action === 'stop') {\n return renderControlResult(action, args, result, options, theme);\n }\n if (action === 'recovery-evidence') {\n return renderRecoveryEvidenceResult(args, result, options, theme);\n }\n if (action === 'follow' || action === 'open' || action === 'recover' || action === 'tail') {\n return renderSimpleActionResult(action, args, result, options, theme);\n }\n return renderFallback(result, options, theme);\n}\n","import { resolve } from 'node:path';\n\nimport { type EmbeddedWorkflowFeature, type Workflow } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/server';\n\nimport { type DispatchInput, workflowCatalogPageSchema, workflowDispatchInputsSchema } from '../../schemas/workflowPi';\nimport type {\n WorkflowCatalogDetail,\n WorkflowInputSummary,\n WorkflowJobSummary,\n} from '../../tui/workflow/workflowCatalog';\nimport { toolResultText } from '../piToolBridge';\nimport { type WorkflowLaunchExecutor, type WorkflowLaunchInput } from '../workflowExecution';\n\nconst CATALOG_PAGE_SIZE = 100;\nconst USER_PROMPT_TRIGGER = 'user_prompt';\nconst WORKFLOW_DISPATCH_TRIGGER = 'workflow_dispatch';\nconst BOOLEAN_INPUT_TYPE = 'boolean';\n\ntype WorkflowListTool = EmbeddedWorkflowFeature['listWorkflowsTool'];\ntype WorkflowListInput = Parameters<WorkflowListTool['execute']>[0];\n\nexport interface WorkflowCatalogEntry {\n description: string;\n name: string;\n path: string;\n relativePath: string;\n tags: string[];\n}\n\nexport interface WorkflowCatalogPage {\n directory: string;\n hasNextPage: boolean;\n page: number;\n pageSize: number;\n workflows: WorkflowCatalogEntry[];\n}\n\nexport interface WorkflowLauncherUi {\n editor(title: string, prefill?: string): Promise<string | undefined>;\n input(title: string, placeholder?: string): Promise<string | undefined>;\n notify(message: string, type?: 'info' | 'warning' | 'error'): void;\n select(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface WorkflowEntryLaunchOptions {\n compatibleRunners(workflow: Workflow): string[] | undefined;\n launch: WorkflowLaunchExecutor['execute'];\n parseWorkflow(workflowPath: string): Workflow;\n ui: WorkflowLauncherUi;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};\n}\n\nfunction workflowTriggerBlock(workflow: Workflow): Record<string, unknown> {\n return asRecord(workflow.on);\n}\n\nfunction dispatchInputs(workflow: Workflow): Record<string, DispatchInput> {\n const dispatch = workflowTriggerBlock(workflow)[WORKFLOW_DISPATCH_TRIGGER];\n if (dispatch === null || dispatch === undefined) return {};\n const parsed = workflowDispatchInputsSchema.safeParse(dispatch);\n if (!parsed.success) throw new Error(`Invalid workflow_dispatch input definitions: ${parsed.error.message}`);\n return parsed.data.inputs ?? {};\n}\n\nfunction launchResultError(result: CallToolResult): Error {\n return new Error(toolResultText(result) || 'Workflow launch failed.');\n}\n\nexport function parseWorkflowCatalogPage(result: CallToolResult): WorkflowCatalogPage {\n if (result.isError) throw launchResultError(result);\n let value: unknown;\n try {\n value = JSON.parse(toolResultText(result));\n } catch (cause) {\n throw new Error('Workflow catalog returned invalid JSON.', { cause });\n }\n const parsed = workflowCatalogPageSchema.safeParse(value);\n if (!parsed.success) throw new Error(`Workflow catalog response was invalid: ${parsed.error.message}`);\n return {\n directory: parsed.data.directory,\n hasNextPage: parsed.data.hasNextPage,\n page: parsed.data.page,\n pageSize: parsed.data.pageSize,\n workflows: parsed.data.workflows.map((entry) => ({\n description: entry.description,\n name: entry.name,\n path: resolve(parsed.data.directory, entry.path),\n relativePath: entry.path,\n tags: entry.tags,\n })),\n };\n}\n\nexport async function loadWorkflowCatalog(\n listWorkflowsTool: WorkflowListTool,\n directory: string,\n): Promise<WorkflowCatalogEntry[]> {\n const entries: WorkflowCatalogEntry[] = [];\n let page = 1;\n let hasNextPage = true;\n while (hasNextPage) {\n const input: WorkflowListInput = { directory, page, pageSize: CATALOG_PAGE_SIZE };\n const result = await listWorkflowsTool.execute(input);\n const catalogPage = parseWorkflowCatalogPage(result);\n entries.push(...catalogPage.workflows);\n hasNextPage = catalogPage.hasNextPage;\n page += 1;\n }\n return entries;\n}\n\nasync function requestPrompt(ui: WorkflowLauncherUi): Promise<string | undefined> {\n while (true) {\n const value = await ui.editor('Workflow prompt');\n if (value === undefined) return undefined;\n const prompt = value.trim();\n if (prompt) return prompt;\n ui.notify('A workflow prompt is required.', 'warning');\n }\n}\n\nasync function requestDispatchInput(\n ui: WorkflowLauncherUi,\n name: string,\n input: DispatchInput,\n): Promise<string | undefined> {\n const title = input.description ? `${name}: ${input.description}` : `Workflow input: ${name}`;\n if (input.options && input.options.length > 0) return ui.select(title, input.options);\n if (input.type === BOOLEAN_INPUT_TYPE) return ui.select(title, ['true', 'false']);\n\n while (true) {\n const value = await ui.input(title, input.default);\n if (value === undefined) return undefined;\n const normalized = value.trim() || input.default;\n if (normalized || !input.required) return normalized || undefined;\n ui.notify(`A value is required for workflow input ${name}.`, 'warning');\n }\n}\n\nexport async function collectWorkflowInputs(\n workflow: Workflow,\n ui: WorkflowLauncherUi,\n): Promise<{ inputs?: Record<string, string>; prompt?: string } | undefined> {\n const triggers = workflowTriggerBlock(workflow);\n const requiresPrompt = Object.hasOwn(triggers, USER_PROMPT_TRIGGER);\n const prompt = requiresPrompt ? await requestPrompt(ui) : undefined;\n if (requiresPrompt && prompt === undefined) return undefined;\n\n const definitions = dispatchInputs(workflow);\n const inputs: Record<string, string> = {};\n for (const [name, definition] of Object.entries(definitions)) {\n const value = await requestDispatchInput(ui, name, definition);\n if (value === undefined && definition.required) return undefined;\n if (value !== undefined) inputs[name] = value;\n }\n return {\n ...(prompt === undefined ? {} : { prompt }),\n ...(Object.keys(inputs).length === 0 ? {} : { inputs }),\n };\n}\n\n/**\n * Everything a launch needs once the workflow is chosen: the runner, the\n * prompt, and any `workflow_dispatch` inputs, each asked for through the\n * host's own dialogs. Selection is the caller's business - `SPC w l` launches\n * the row under its cursor, so this takes an entry rather than picking one.\n */\nfunction stepLabel(step: { name?: string; uses?: string; run?: unknown; id?: string }, index: number): string {\n if (step.name) return step.name;\n if (step.uses) return step.uses;\n if (step.id) return step.id;\n // A `run:` step without a name is identified by its position; printing the\n // command would put a shell line into a summary pane.\n return `step ${index + 1}`;\n}\n\nfunction catalogInputs(workflow: Workflow): WorkflowInputSummary[] {\n return Object.entries(dispatchInputs(workflow)).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n ...(definition.required === undefined ? {} : { required: definition.required }),\n ...(definition.default === undefined ? {} : { default: definition.default }),\n ...(definition.options ? { options: definition.options } : {}),\n }));\n}\n\nfunction catalogJobs(workflow: Workflow): WorkflowJobSummary[] {\n return Object.entries(workflow.jobs ?? {}).map(([name, job]) => ({\n name,\n steps: (job.steps ?? []).map((step, index) => stepLabel(step, index)),\n }));\n}\n\n/**\n * The parsed shape `SPC w l`'s detail pane shows. A parse failure is returned\n * as `error` rather than thrown: one unparseable file in a repository must not\n * take the whole board down.\n */\nexport function summarizeWorkflowFile(\n workflowPath: string,\n options: Pick<WorkflowEntryLaunchOptions, 'compatibleRunners' | 'parseWorkflow'>,\n): WorkflowCatalogDetail {\n try {\n const workflow = options.parseWorkflow(workflowPath);\n const runners = options.compatibleRunners(workflow);\n return {\n triggers: Object.keys(workflowTriggerBlock(workflow)),\n inputs: catalogInputs(workflow),\n jobs: catalogJobs(workflow),\n ...(runners ? { runners } : {}),\n };\n } catch (cause) {\n return {\n triggers: [],\n inputs: [],\n jobs: [],\n error: cause instanceof Error ? cause.message : String(cause),\n };\n }\n}\n\nexport async function launchWorkflowEntry(\n options: WorkflowEntryLaunchOptions,\n selected: Pick<WorkflowCatalogEntry, 'path'>,\n ctx: ExtensionContext,\n): Promise<CallToolResult | undefined> {\n const workflow = options.parseWorkflow(selected.path);\n const runners = options.compatibleRunners(workflow);\n if (runners && runners.length === 0) throw new Error('No compatible runner is available for this workflow.');\n let runner: string | undefined;\n if (runners) {\n runner = await options.ui.select('Select a workflow runner', runners);\n if (runner === undefined) return undefined;\n }\n\n const triggerInputs = await collectWorkflowInputs(workflow, options.ui);\n if (triggerInputs === undefined) return undefined;\n const launchInput: WorkflowLaunchInput = {\n workflowPath: selected.path,\n ...(runner === undefined ? {} : { runner }),\n ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n ...triggerInputs,\n };\n return options.launch(launchInput, ctx);\n}\n","import type { WorkflowRunRecord, WorkflowStage } from '@agimon-ai/workflow-mcp';\n\n/** Package-local narration sink; the Pi adapter binds it to the injected Cordis service. */\nexport interface WorkflowNarrationSink {\n narrate(text: string): void;\n}\n\nconst RUNNING_STAGE: WorkflowStage = 'running';\nconst COMPLETED_STAGE: WorkflowStage = 'completed';\nconst ERROR_STAGE: WorkflowStage = 'error';\n\ntype NarratedWorkflow = Pick<WorkflowRunRecord, 'displayName' | 'stage'>;\n\n/**\n * Translate an observed workflow lifecycle transition into generic speech.\n * Voice owns delivery and ignores requests while its minor mode is inactive.\n */\nexport function narrateWorkflowTransition(\n requester: WorkflowNarrationSink,\n record: NarratedWorkflow,\n previousStage: WorkflowStage | undefined,\n startedDuringSession: boolean,\n): void {\n const newlyLaunched = previousStage === undefined && startedDuringSession;\n if (newlyLaunched) requester.narrate(`Workflow launched: ${record.displayName}.`);\n\n if (previousStage !== RUNNING_STAGE && !newlyLaunched) return;\n if (record.stage === COMPLETED_STAGE) requester.narrate(`Workflow succeeded: ${record.displayName}.`);\n if (record.stage === ERROR_STAGE) requester.narrate(`Workflow failed: ${record.displayName}.`);\n}\n","import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nconst THOUSAND = 1000;\nconst MILLION = 1_000_000;\n/** Below this many tokens the \"k\" form keeps a decimal, above it rounds. */\nconst K_DECIMAL_LIMIT = 10_000;\n\n/** Compact token count, e.g. `812`, `4.2k`, `186k`, `1.3M`. */\nexport function formatTokens(value: number): string {\n if (value < THOUSAND) return String(value);\n if (value < MILLION) return `${(value / THOUSAND).toFixed(value < K_DECIMAL_LIMIT ? 1 : 0)}k`;\n return `${(value / MILLION).toFixed(1)}M`;\n}\n\nexport function fitLine(text: string, width: number): string {\n return truncateToWidth(text, Math.max(0, width), '');\n}\n\nexport function padLine(text: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const fitted = fitLine(text, safeWidth);\n return `${fitted}${' '.repeat(Math.max(0, safeWidth - visibleWidth(fitted)))}`;\n}\n\nexport function alignLine(left: string, right: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const rightWidth = visibleWidth(right);\n if (!right || rightWidth >= safeWidth) return fitLine(right || left, safeWidth);\n\n const maxLeftWidth = Math.max(0, safeWidth - rightWidth - 1);\n const fittedLeft = fitLine(left, maxLeftWidth);\n const gap = ' '.repeat(Math.max(1, safeWidth - visibleWidth(fittedLeft) - rightWidth));\n return fitLine(`${fittedLeft}${gap}${right}`, safeWidth);\n}\n\nexport function frameLine(content: string, width: number, left = '│', right = '│'): string {\n const safeWidth = Math.max(0, width);\n const frameWidth = visibleWidth(left) + visibleWidth(right);\n if (safeWidth <= frameWidth) return fitLine(`${left}${right}`, safeWidth);\n return `${left}${padLine(content, safeWidth - frameWidth)}${right}`;\n}\n\nexport function packSegments(segments: string[], width: number, separator = ' '): string[] {\n const safeWidth = Math.max(0, width);\n if (safeWidth === 0) return [];\n\n const lines: string[] = [];\n let current = '';\n for (const segment of segments) {\n const candidate = current ? `${current}${separator}${segment}` : segment;\n if (visibleWidth(candidate) <= safeWidth) {\n current = candidate;\n continue;\n }\n if (current) lines.push(fitLine(current, safeWidth));\n current = fitLine(segment, safeWidth);\n }\n if (current) lines.push(current);\n return lines;\n}\n","import type { Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport { fitLine, frameLine, padLine } from './rendering';\n\nconst DEFAULT_TERMINAL_ROWS = 24;\nconst FULL_CHROME_ROWS = 6;\n/** Two frame columns and two gutter columns, leaving content worth framing. */\nconst MIN_FRAMED_WIDTH = 8;\nconst GUTTER = ' ';\nconst GUTTER_COLUMNS = 2;\n/** Blank columns kept between a row's left cluster and its right-aligned status. */\nconst ROW_GAP = 2;\n/** A secondary segment thinner than this is dropped rather than shredded into a stub. */\nconst MIN_SEGMENT_WIDTH = 8;\nconst ELLIPSIS = '…';\nconst BORDER_COLOR = 'borderMuted';\nconst TEXT_COLOR = 'text';\n/** Filled key caps read as pressable, matching the doom mockups' footers. */\nconst HINT_CAP_BACKGROUND = 'selectedBg';\nconst HINT_SEPARATOR = ' ';\n/** A cap's two pad columns plus the space before its label. */\nconst HINT_CHROME_COLUMNS = 6;\nconst TITLE_COLOR = 'accent';\nconst SECONDARY_COLOR = 'dim';\nconst HORIZONTAL_BORDER = '─';\nconst VERTICAL_BORDER = '│';\nconst TOP_CORNERS = ['╭', '╮'] as const;\nconst DIVIDER_JOINTS = ['├', '┤'] as const;\nconst BOTTOM_CORNERS = ['╰', '╯'] as const;\n\nexport interface DoomOverlayTui {\n terminal?: {\n rows: number;\n columns?: number;\n };\n requestRender(force?: boolean): void;\n}\n\nexport interface DoomOverlayChrome {\n title: string;\n breadcrumb?: string;\n headerRight?: string;\n footer: string;\n footerRight?: string;\n /**\n * Key/label pairs rendered as filled caps, e.g. `[ enter ] edit subject`.\n * Takes precedence over `footer`, which stays for surfaces that want a plain\n * sentence rather than a key legend.\n */\n footerHints?: readonly (readonly [string, string])[];\n /**\n * Signature colour for the surface. When set, the frame takes it and the\n * title renders as a filled badge rather than plain accent text, matching the\n * doom mockups. Left unset, the frame stays muted and the title plain.\n */\n accent?: Parameters<Theme['fg']>[0];\n}\n\n/**\n * One signature colour for every doom overlay: the frame and the title badge.\n * Per-surface colours were tried and read as arbitrary, and they also borrowed\n * tokens that mean something else (`warning`, `syntaxNumber`), so a theme edit\n * elsewhere would have repainted a frame. Change it here to change them all.\n */\nexport const DOOM_OVERLAY_ACCENT = 'mdHeading' satisfies DoomOverlayChrome['accent'];\n\nexport const DOOM_FULLSCREEN_UI_OPTIONS = {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n} as const;\n\n/**\n * Fits a secondary segment into `budget`, or drops it entirely when too few\n * columns remain for it to stay readable. Truncating everything to fit is what\n * makes a tight header read as one run-on string.\n */\nfunction fitSegment(text: string | undefined, budget: number): string {\n if (!text || budget <= 0) return '';\n return budget < Math.min(visibleWidth(text), MIN_SEGMENT_WIDTH) ? '' : truncateToWidth(text, budget, ELLIPSIS);\n}\n\nexport abstract class DoomOverlay implements Component {\n protected constructor(\n protected readonly tui: DoomOverlayTui,\n protected readonly theme: Theme,\n ) {}\n\n invalidate(): void {\n this.tui.requestRender();\n }\n\n render(width: number): string[] {\n const safeWidth = Math.max(0, Math.floor(width));\n const height = Math.max(0, Math.floor(this.tui.terminal?.rows ?? DEFAULT_TERMINAL_ROWS));\n if (safeWidth === 0 || height === 0) return [];\n\n const chrome = this.getChrome();\n if (height < FULL_CHROME_ROWS || safeWidth < MIN_FRAMED_WIDTH) {\n return this.renderCompact(chrome, safeWidth, height);\n }\n\n const innerWidth = safeWidth - GUTTER_COLUMNS;\n const contentWidth = innerWidth - GUTTER_COLUMNS;\n const bodyHeight = height - FULL_CHROME_ROWS;\n const body = this.renderBody(contentWidth, bodyHeight).slice(0, bodyHeight);\n while (body.length < bodyHeight) body.push('');\n\n const frame = chrome.accent ?? BORDER_COLOR;\n return [\n this.borderRow(TOP_CORNERS, innerWidth, frame),\n this.contentRow(this.headerRow(chrome, contentWidth), contentWidth, safeWidth, frame),\n this.borderRow(DIVIDER_JOINTS, innerWidth, frame, BORDER_COLOR),\n ...body.map((line) => this.contentRow(line, contentWidth, safeWidth, frame)),\n this.borderRow(DIVIDER_JOINTS, innerWidth, frame, BORDER_COLOR),\n this.contentRow(this.footerRow(chrome, contentWidth), contentWidth, safeWidth, frame),\n this.borderRow(BOTTOM_CORNERS, innerWidth, frame),\n ].map((line) => padLine(line, safeWidth));\n }\n\n protected abstract getChrome(): DoomOverlayChrome;\n\n protected abstract renderBody(width: number, height: number): string[];\n\n /**\n * Edge glyphs and the rule between them are coloured separately: the outer\n * rectangle carries the signature colour while an internal separator stays\n * muted, meeting the frame at accent-coloured junctions.\n */\n private borderRow(\n [left, right]: readonly [string, string],\n innerWidth: number,\n edge: DoomOverlayChrome['accent'] = BORDER_COLOR,\n fill: DoomOverlayChrome['accent'] = edge,\n ): string {\n const edgeColour = edge ?? BORDER_COLOR;\n return [\n this.theme.fg(edgeColour, left),\n this.theme.fg(fill ?? edgeColour, HORIZONTAL_BORDER.repeat(innerWidth)),\n this.theme.fg(edgeColour, right),\n ].join('');\n }\n\n private contentRow(\n content: string,\n contentWidth: number,\n width: number,\n colour: DoomOverlayChrome['accent'] = BORDER_COLOR,\n ): string {\n const edge = this.theme.fg(colour ?? BORDER_COLOR, VERTICAL_BORDER);\n return frameLine(`${GUTTER}${padLine(content, contentWidth)}${GUTTER}`, width, edge, edge);\n }\n\n private headerRow(chrome: DoomOverlayChrome, width: number): string {\n // A signature colour turns the title into a filled badge, as the mockups\n // show; without one it stays plain accent text.\n const accent = chrome.accent;\n const titleBudget = accent ? width - GUTTER_COLUMNS : width;\n const title = truncateToWidth(chrome.title, Math.max(0, titleBudget), ELLIPSIS);\n let left = accent\n ? this.theme.inverse(this.theme.bold(this.theme.fg(accent, ` ${title} `)))\n : this.theme.bold(this.theme.fg(TITLE_COLOR, title));\n let leftWidth = visibleWidth(title) + (accent ? GUTTER_COLUMNS : 0);\n\n // The breadcrumb claims room before the right status: it says where you are,\n // which outranks ambient context when the terminal is narrow.\n const breadcrumb = fitSegment(chrome.breadcrumb, width - leftWidth - ROW_GAP);\n if (breadcrumb) {\n left += `${' '.repeat(ROW_GAP)}${this.theme.fg(SECONDARY_COLOR, breadcrumb)}`;\n leftWidth += ROW_GAP + visibleWidth(breadcrumb);\n }\n return this.withRightStatus(left, leftWidth, chrome.headerRight, width);\n }\n\n private footerRow(chrome: DoomOverlayChrome, width: number): string {\n const footer = chrome.footerHints?.length\n ? this.hintLegend(chrome.footerHints, width)\n : this.theme.fg(SECONDARY_COLOR, truncateToWidth(chrome.footer, width, ELLIPSIS));\n return this.withRightStatus(footer, visibleWidth(footer), chrome.footerRight, width);\n }\n\n /**\n * Key legend with each key in a filled cap. Every segment sets its own colour\n * so the caps survive: a cap's reset would otherwise strip the surrounding\n * dim from the labels that follow it.\n */\n private hintLegend(hints: readonly (readonly [string, string])[], width: number): string {\n let legend = '';\n let used = 0;\n for (const [key, label] of hints) {\n const segmentWidth = visibleWidth(key) + visibleWidth(label) + HINT_CHROME_COLUMNS;\n if (used + segmentWidth > width) break;\n const cap = this.theme.bg(HINT_CAP_BACKGROUND, this.theme.fg(TEXT_COLOR, ` ${key} `));\n legend += `${legend ? HINT_SEPARATOR : ''}${cap}${this.theme.fg(SECONDARY_COLOR, ` ${label}`)}`;\n used += segmentWidth;\n }\n return legend;\n }\n\n /**\n * Right-aligns a status cluster, dropping it whole when the row cannot spare\n * the columns. A clipped status reads as a stub (`doom-log…`) that carries\n * less than the blank space it costs.\n */\n private withRightStatus(left: string, leftWidth: number, right: string | undefined, width: number): string {\n const statusWidth = right ? visibleWidth(right) : 0;\n if (!right || statusWidth === 0 || leftWidth + ROW_GAP + statusWidth > width) return left;\n return `${left}${' '.repeat(width - leftWidth - statusWidth)}${this.theme.fg(SECONDARY_COLOR, right)}`;\n }\n\n private renderCompact(chrome: DoomOverlayChrome, width: number, height: number): string[] {\n const lines = Array.from({ length: height }, () => '');\n lines[0] = this.theme.bold(this.theme.fg(TITLE_COLOR, chrome.title));\n if (height > 1) lines[height - 1] = this.theme.fg(SECONDARY_COLOR, chrome.footer);\n return lines.map((line) => padLine(fitLine(line, width), width));\n }\n}\n","/**\n * Text primitives shared by every doom overlay in this extension.\n *\n * Kept in one place because each of them encodes a decision that has to hold on\n * every surface: how a cell is clipped, which end of a path survives, and what\n * counts as a keystroke that carries text.\n */\n\nimport { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nexport const ELLIPSIS = '…';\nexport const CURSOR_BLOCK = '█';\nexport const SELECTION_MARKER = '›';\n/** pi-tui brackets a truncation ellipsis with this; see `fit`. */\nconst HARD_RESET = '\\x1b[0m';\nconst ESCAPE = '\\x1b';\nconst FIRST_PRINTABLE_CODE_POINT = 0x20;\nconst DELETE_CODE_POINT = 0x7f;\n\n/**\n * Truncates and pads to an exact column count.\n *\n * `truncateToWidth` wraps its ellipsis in a hard `\\x1b[0m`, which would strip a\n * row's background for everything after a clipped cell. Nothing here sets a\n * colour that a full reset is the correct end for -- the theme closes its own\n * with `\\x1b[39m` and `\\x1b[49m` -- so the injected resets are dropped.\n */\nexport function fit(text: string, width: number): string {\n const clipped = truncateToWidth(text, Math.max(0, width), ELLIPSIS).replaceAll(HARD_RESET, '');\n return clipped + ' '.repeat(Math.max(0, width - visibleWidth(clipped)));\n}\n\n/**\n * Fits a line that carries its own colour, keeping every escape it contains.\n *\n * `fit` above drops hard resets, which is right for a themed row whose\n * background must survive a clipped cell and wrong for captured terminal\n * output: those resets are what END the child's colour runs, and deleting them\n * bleeds a colour through the rest of the panel. This closes the line with a\n * reset instead, before the padding, so no attribute escapes the row.\n */\nexport function fitTerminalLine(text: string, width: number): string {\n const safeWidth = Math.max(0, width);\n const clipped = truncateToWidth(text, safeWidth, ELLIPSIS);\n const padding = ' '.repeat(Math.max(0, safeWidth - visibleWidth(clipped)));\n return clipped.includes(ESCAPE) ? `${clipped}${HARD_RESET}${padding}` : `${clipped}${padding}`;\n}\n\n/** Right-aligns a trailing cluster against a left one, both clipped to fit. */\nexport function rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fit(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fit(right, rightWidth);\n}\n\n/**\n * Trims from the front rather than the tail.\n *\n * For a path the file name identifies the thing, while the\n * `automations/marketing-workflows/` prefix every entry shares does not.\n */\nexport function pathTail(text: string, width: number): string {\n if (width <= 0) return '';\n if (visibleWidth(text) <= width) return text;\n return `${ELLIPSIS}${text.slice(text.length - Math.max(0, width - 1))}`;\n}\n\n/**\n * Keystrokes that carry no text: escape sequences, control keys, delete.\n *\n * Indexed rather than iterated so surrogate pairs stay intact; both halves sit\n * far above the control range, so no emoji is ever mistaken for one.\n */\nexport function isControlInput(data: string): boolean {\n for (let index = 0; index < data.length; index++) {\n const code = data.charCodeAt(index);\n if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;\n }\n return false;\n}\n\n/**\n * Whitespace-separated terms, each of which must appear somewhere in the row's\n * searchable text. Splitting on whitespace is what lets `short video` match a\n * row whose words are divided between its title and its file name.\n */\nexport function matchesQuery(haystack: string, query: string): boolean {\n const terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (terms.length === 0) return true;\n const lowered = haystack.toLowerCase();\n return terms.every((term) => lowered.includes(term));\n}\n","/**\n * The `SPC w l` board: every workflow this repository defines, with the cursor\n * workflow's parsed detail beside it and `r` to launch it.\n *\n * WHY NOT `workflowPicker.ts`:\n * That surface answers \"which one\", hands a value back, and closes - which is\n * what `SPC w c` recovery still needs. This one answers \"what is this workflow,\n * and do I want to run it\", so the detail has to be on screen next to the list\n * rather than behind a selection. The picker stays for the pick-and-return case\n * rather than growing a second mode.\n *\n * DESIGN PATTERNS:\n * - Detail is loaded through an injected loader, so parsing a workflow file\n * stays out of the TUI and the surface is assertable as text. Loaded on\n * demand for the cursor row and cached by row key: a repository with fifty\n * workflows must not parse fifty files to draw one pane\n * - A row is two lines, name over path. One line made the name - the field a\n * reader picks a row by - share a third of the overlay with a path that\n * repeats its directory on every row\n * - `/` opens the filter rather than plain letters filtering as they are typed:\n * the letter keys carry commands here (`r` launch, `t`/`i`/`s` tabs)\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport {\n CURSOR_BLOCK,\n ELLIPSIS,\n fit,\n isControlInput,\n matchesQuery,\n pathTail,\n rightAligned,\n SELECTION_MARKER,\n} from './overlayText';\n\nexport const WORKFLOW_CATALOG_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\n/** One workflow file, as the catalog tool reports it. */\nexport interface WorkflowCatalogRow {\n /** Stable identity and the loader's cache key: the absolute path. */\n key: string;\n name: string;\n relativePath: string;\n description: string;\n tags: readonly string[];\n}\n\nexport interface WorkflowInputSummary {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n options?: readonly string[];\n}\n\nexport interface WorkflowJobSummary {\n name: string;\n steps: readonly string[];\n}\n\n/**\n * What the detail pane shows for one workflow. `runners` is undefined when the\n * workflow names no runner map at all, which is not the same as naming an empty\n * one - see `compatibleRunners`.\n */\nexport interface WorkflowCatalogDetail {\n triggers: readonly string[];\n inputs: readonly WorkflowInputSummary[];\n jobs: readonly WorkflowJobSummary[];\n runners?: readonly string[];\n /** Set when the file could not be parsed; the pane shows this instead of guessing. */\n error?: string;\n}\n\nexport type WorkflowDetailLoader = (row: WorkflowCatalogRow) => WorkflowCatalogDetail;\n\n/** Starts one workflow and returns immediately; the overlay closes on launch. */\nexport type WorkflowLaunchDispatcher = (row: WorkflowCatalogRow) => void;\n\nexport interface WorkflowCatalogOptions {\n loadDetail: WorkflowDetailLoader;\n /** Absent until a composition root wires the launch key to a real launcher. */\n launchWorkflow?: WorkflowLaunchDispatcher;\n}\n\nexport type WorkflowDetailTab = 'triggers' | 'inputs' | 'steps';\n\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst TITLE = 'WORKFLOWS';\nconst BREADCRUMB = 'SPC › w / workflows › l / list';\nconst DIVIDER = '│';\nconst DEFAULT_PAGE_SIZE = 1;\nconst ROWS_PER_ENTRY = 2;\n/** Indent under `${SELECTION_MARKER} `, so the path line hangs under the name. */\nconst META_INDENT = ' ';\nconst EMPTY_NAME = '(unnamed)';\nconst LAUNCH_KEY = 'r';\nconst FILTER_KEY = '/';\nconst KEY_CLEAR = '\\x15';\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_MESSAGE = 'No workflow definitions were found in this repository.';\nconst TAB_ORDER: readonly WorkflowDetailTab[] = ['triggers', 'inputs', 'steps'];\nconst TAB_KEYS: Record<string, WorkflowDetailTab> = { t: 'triggers', i: 'inputs', s: 'steps' };\nconst FOOTER = '↑↓ cursor · JK scroll · tab detail · / filter · r launch · esc close';\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'move'],\n ['JK', 'scroll'],\n ['tab', 'cycle'],\n ['/', 'filter'],\n ['r', 'launch'],\n];\nconst FILTER_FOOTER = 'enter keep · esc clear · ctrl+u wipe';\nconst FILTER_FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['enter', 'keep'],\n ['esc', 'clear'],\n ['ctrl+u', 'wipe'],\n];\n\ninterface SplitLayout {\n leftContentWidth: number;\n rightContentWidth: number;\n gutterWidth: number;\n}\n\nfunction splitLayout(width: number): SplitLayout {\n const paneBudget = Math.max(2, width - visibleWidth(DIVIDER));\n const leftPaneWidth = Math.max(1, Math.floor(paneBudget / 3));\n const rightPaneWidth = Math.max(1, paneBudget - leftPaneWidth);\n const gutterWidth = leftPaneWidth >= 3 && rightPaneWidth >= 3 ? 1 : 0;\n return {\n leftContentWidth: Math.max(1, leftPaneWidth - gutterWidth),\n rightContentWidth: Math.max(1, rightPaneWidth - gutterWidth),\n gutterWidth,\n };\n}\n\nfunction appendWrapped(lines: string[], text: string, width: number, colour: ThemeColor, theme: Theme): void {\n for (const line of wrapTextWithAnsi(text, Math.max(1, width))) lines.push(theme.fg(colour, line));\n}\n\nfunction appendSection(lines: string[], heading: string, items: readonly string[], width: number, theme: Theme): void {\n lines.push(theme.bold(theme.fg('accent', heading)));\n if (items.length === 0) lines.push(theme.fg('dim', ' none'));\n else for (const item of items) appendWrapped(lines, ` • ${item}`, width, 'text', theme);\n lines.push('');\n}\n\nfunction inputLabel(input: WorkflowInputSummary): string {\n const qualifiers = [\n input.required ? 'required' : 'optional',\n input.default === undefined ? undefined : `default ${input.default}`,\n input.options && input.options.length > 0 ? `one of ${input.options.join(', ')}` : undefined,\n ].filter((part): part is string => Boolean(part));\n const description = input.description ? `${input.description} · ` : '';\n return `${input.name} — ${description}${qualifiers.join(' · ')}`;\n}\n\nexport function workflowDetailLines(\n detail: WorkflowCatalogDetail,\n tab: WorkflowDetailTab,\n width: number,\n theme: Theme,\n): string[] {\n const lines: string[] = [];\n if (detail.error) {\n lines.push(theme.bold(theme.fg('error', 'WORKFLOW ERROR')));\n appendWrapped(lines, detail.error, width, 'error', theme);\n lines.push('');\n return lines;\n }\n if (tab === 'triggers') {\n appendSection(lines, 'TRIGGERS', detail.triggers, width, theme);\n // No runner map means every runner qualifies, which a bare \"none\" would\n // report as the opposite.\n appendSection(lines, 'RUNNERS', detail.runners ?? ['any available runner'], width, theme);\n return lines;\n }\n if (tab === 'inputs') {\n appendSection(lines, 'DISPATCH INPUTS', detail.inputs.map(inputLabel), width, theme);\n return lines;\n }\n for (const job of detail.jobs) {\n lines.push(theme.bold(theme.fg('accent', job.name)));\n if (job.steps.length === 0) lines.push(theme.fg('dim', ' no steps'));\n else for (const step of job.steps) appendWrapped(lines, ` • ${step}`, width, 'text', theme);\n lines.push('');\n }\n if (detail.jobs.length === 0) appendSection(lines, 'JOBS', [], width, theme);\n return lines;\n}\n\nfunction tabStrip(tab: WorkflowDetailTab, width: number, theme: Theme): string {\n const labels = TAB_ORDER.map((candidate) => {\n const label = candidate.toUpperCase();\n return candidate === tab ? theme.inverse(theme.bold(` ${label} `)) : theme.fg('dim', ` ${label} `);\n }).join(' ');\n return truncateToWidth(labels, Math.max(0, width), ELLIPSIS);\n}\n\nexport function filterWorkflowRows(rows: readonly WorkflowCatalogRow[], query: string): readonly WorkflowCatalogRow[] {\n if (!query.trim()) return rows;\n return rows.filter((row) =>\n matchesQuery([row.name, row.relativePath, row.description, row.tags.join(' ')].join(' '), query),\n );\n}\n\nexport class WorkflowCatalogComponent extends DoomOverlay {\n private readonly rows: readonly WorkflowCatalogRow[];\n private readonly detailCache = new Map<string, WorkflowCatalogDetail>();\n private cursorIndex = 0;\n private tab: WorkflowDetailTab = 'triggers';\n private query = '';\n private filtering = false;\n private notice: string | undefined;\n private listPageSize = DEFAULT_PAGE_SIZE;\n private detailPageSize = DEFAULT_PAGE_SIZE;\n private detailOffset = 0;\n private detailTotal = 0;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n rows: readonly WorkflowCatalogRow[],\n private readonly done: (result: undefined) => void,\n private readonly options: WorkflowCatalogOptions,\n ) {\n super(tui, theme);\n this.rows = [...rows].sort((left, right) => left.name.localeCompare(right.name));\n }\n\n private matches(): readonly WorkflowCatalogRow[] {\n return filterWorkflowRows(this.rows, this.query);\n }\n\n private cursorRow(): WorkflowCatalogRow | undefined {\n const matches = this.matches();\n return matches[Math.min(this.cursorIndex, Math.max(0, matches.length - 1))];\n }\n\n /** Parsed once per workflow, then reused for every repaint of that row. */\n private detailFor(row: WorkflowCatalogRow): WorkflowCatalogDetail {\n const cached = this.detailCache.get(row.key);\n if (cached) return cached;\n const detail = this.options.loadDetail(row);\n this.detailCache.set(row.key, detail);\n return detail;\n }\n\n private moveCursor(delta: number): void {\n const count = this.matches().length;\n if (count === 0) return;\n const next = Math.max(0, Math.min(count - 1, this.cursorIndex + delta));\n if (next === this.cursorIndex) return;\n this.cursorIndex = next;\n // The detail pane follows the cursor, so its scroll belonged to the row\n // that was showing, not the one replacing it.\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private switchTab(tab: WorkflowDetailTab): void {\n if (this.tab === tab) return;\n this.tab = tab;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private cycleTab(): void {\n const current = TAB_ORDER.indexOf(this.tab);\n this.switchTab(TAB_ORDER[(current + 1) % TAB_ORDER.length] ?? 'triggers');\n }\n\n private scrollDetail(delta: number): void {\n if (!this.cursorRow()) return;\n const maximum = Math.max(0, this.detailTotal - this.detailPageSize);\n const next = Math.max(0, Math.min(maximum, this.detailOffset + delta));\n if (next === this.detailOffset) return;\n this.detailOffset = next;\n this.invalidate();\n }\n\n private setNotice(notice: string): void {\n this.notice = notice;\n this.invalidate();\n }\n\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n // The previous index named a row this filter may no longer list.\n this.cursorIndex = 0;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private launchCursor(): void {\n const row = this.cursorRow();\n if (!row) {\n this.setNotice('launch unavailable · no workflow is selected');\n return;\n }\n const launchWorkflow = this.options.launchWorkflow;\n if (!launchWorkflow) {\n this.setNotice('launch unavailable · no workflow launcher is attached');\n return;\n }\n const detail = this.detailFor(row);\n if (detail.error) {\n this.setNotice(`launch unavailable · ${detail.error}`);\n return;\n }\n // Closing first is what makes the launcher's own prompts reachable: they\n // are host dialogs, and a fullscreen overlay sits over them.\n this.done(undefined);\n launchWorkflow(row);\n }\n\n private handleFilterInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.filtering = false;\n this.setQuery('');\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'enter')) {\n this.filtering = false;\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'backspace')) {\n this.setQuery(this.query.slice(0, -1));\n return;\n }\n if (data === KEY_CLEAR) {\n this.setQuery('');\n return;\n }\n if (!isControlInput(data)) this.setQuery(this.query + data);\n }\n\n handleInput(data: string): void {\n if (this.filtering) {\n this.handleFilterInput(data);\n return;\n }\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, Key.shift('k'))) return this.scrollDetail(-1);\n if (matchesKey(data, Key.shift('j'))) return this.scrollDetail(1);\n if (matchesKey(data, 'up') || data === 'k') return this.moveCursor(-1);\n if (matchesKey(data, 'down') || data === 'j') return this.moveCursor(1);\n if (matchesKey(data, 'pageUp')) return this.moveCursor(-this.listPageSize);\n if (matchesKey(data, 'pageDown')) return this.moveCursor(this.listPageSize);\n if (matchesKey(data, 'tab')) return this.cycleTab();\n if (data === FILTER_KEY) {\n this.filtering = true;\n this.notice = undefined;\n this.invalidate();\n return;\n }\n if (data === LAUNCH_KEY) return this.launchCursor();\n const tab = TAB_KEYS[data];\n if (tab) this.switchTab(tab);\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${scope} workflows · ${this.tab}`,\n footer: this.filtering ? FILTER_FOOTER : FOOTER,\n footerHints: this.filtering ? FILTER_FOOTER_HINTS : FOOTER_HINTS,\n footerRight: matches.length\n ? `${Math.min(this.cursorIndex, matches.length - 1) + 1}/${matches.length}`\n : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const filterRows = this.filtering || this.query ? 1 : 0;\n const transientRows = filterRows + (this.notice === undefined ? 0 : 1);\n const mainHeight = Math.max(0, height - transientRows);\n const layout = splitLayout(width);\n const left = this.renderList(layout.leftContentWidth, mainHeight);\n const right = this.renderDetail(layout.rightContentWidth, mainHeight);\n const gutter = ' '.repeat(layout.gutterWidth);\n const divider = this.theme.fg('borderMuted', DIVIDER);\n const lines: string[] = [];\n for (let index = 0; index < mainHeight; index++) {\n lines.push(\n `${fit(left[index] ?? '', layout.leftContentWidth)}${gutter}${divider}${gutter}${fit(\n right[index] ?? '',\n layout.rightContentWidth,\n )}`,\n );\n }\n if (filterRows) {\n const value = this.filtering ? `${this.query}${CURSOR_BLOCK}` : this.query;\n lines.push(` ${this.theme.bold(this.theme.fg('accent', FILTER_LABEL))} ${value}`);\n }\n if (this.notice !== undefined) lines.push(` ${this.theme.fg('muted', this.notice)}`);\n return lines.slice(0, height).map((line) => fit(line, width));\n }\n\n private renderList(width: number, height: number): string[] {\n const matches = this.matches();\n const lines = [this.theme.bold(this.theme.fg('accent', `WORKFLOWS ${matches.length}`))];\n if (matches.length === 0) {\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'dim',\n this.theme,\n );\n this.listPageSize = DEFAULT_PAGE_SIZE;\n return lines.slice(0, height);\n }\n\n this.listPageSize = Math.max(DEFAULT_PAGE_SIZE, Math.floor((height - 1) / ROWS_PER_ENTRY));\n const active = Math.min(this.cursorIndex, matches.length - 1);\n const start = Math.max(\n 0,\n Math.min(active - this.listPageSize + 1, Math.max(0, matches.length - this.listPageSize)),\n );\n for (const [offset, row] of matches.slice(start, start + this.listPageSize).entries()) {\n const current = start + offset === active;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const label = row.name || EMPTY_NAME;\n const name = current ? this.theme.bold(this.theme.fg('accent', label)) : this.theme.fg('text', label);\n const meta = this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, width - META_INDENT.length)));\n lines.push(fit(`${marker} ${name}`, width));\n lines.push(fit(`${META_INDENT}${meta}`, width));\n }\n return lines.slice(0, height);\n }\n\n private renderDetail(width: number, height: number): string[] {\n const row = this.cursorRow();\n if (!row) {\n this.detailTotal = 0;\n this.detailPageSize = Math.max(DEFAULT_PAGE_SIZE, height);\n this.detailOffset = 0;\n const lines = [this.theme.bold(this.theme.fg('accent', 'WORKFLOW DETAIL')), ''];\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'text',\n this.theme,\n );\n return lines.slice(0, height);\n }\n\n const header = [\n rightAligned(\n this.theme.bold(this.theme.fg('accent', `INSPECTING ${row.name || EMPTY_NAME}`)),\n this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, Math.floor(width / 2)))),\n width,\n ),\n ];\n if (row.description) appendWrapped(header, row.description, width, 'text', this.theme);\n if (row.tags.length > 0) appendWrapped(header, row.tags.join(' · '), width, 'dim', this.theme);\n header.push(tabStrip(this.tab, width, this.theme), '');\n\n const body = workflowDetailLines(this.detailFor(row), this.tab, width, this.theme);\n this.detailPageSize = Math.max(0, height - header.length);\n this.detailTotal = body.length;\n this.detailOffset = Math.min(this.detailOffset, Math.max(0, body.length - this.detailPageSize));\n return [...header, ...body.slice(this.detailOffset, this.detailOffset + this.detailPageSize)].slice(0, height);\n }\n}\n\nexport async function openWorkflowCatalogOverlay(\n ctx: ExtensionContext,\n rows: readonly WorkflowCatalogRow[],\n options: WorkflowCatalogOptions,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new WorkflowCatalogComponent(tui, theme, rows, done, options),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Renders the `workflow-run-finished` custom message: one line per run that\n * reached a terminal state, rather than the host's default block of the\n * `[workflow-run-finished]` label above raw markdown.\n *\n * The same shape `@agimon-ai/doompi-team` gives a slash launch: a status glyph,\n * the run's identity, its outcome, and anything that went wrong indented under\n * it. A finished run is read at a glance in a transcript that is mostly about\n * something else, so it earns a line, not a card.\n *\n * DESIGN PATTERNS:\n * - A message with no `details` renders its content verbatim. That is a\n * transcript entry written before the field existed, and re-deriving it by\n * parsing the summary back out of markdown is exactly the liability\n * `completionNotice.ts` in the team package refused to port\n * - The full summary is still the message's `content`, which is what the model\n * reads and what `deliverAs: 'steer'` carries. This changes what a person\n * sees, never what the agent is told\n */\n\nimport type { ExtensionAPI, Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, Text } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_FINISHED_MESSAGE = 'workflow-run-finished';\n\n/** One finished run, as the extension records it on the message. */\nexport interface WorkflowFinishedRun {\n runKey: string;\n workspace: string;\n stage: string;\n workflowId?: string;\n failedJob?: string;\n error?: string;\n}\n\nexport interface WorkflowFinishedDetails {\n /** Kept for readers that already index runs by id; the lines come from `runs`. */\n runIds?: string[];\n runs?: WorkflowFinishedRun[];\n}\n\nconst COMPLETED_STAGE = 'completed';\nconst HELD_STAGES = new Set(['stopped', 'paused', 'cancelled']);\n\nfunction statusIcon(stage: string, theme: Theme): string {\n if (stage === COMPLETED_STAGE) return theme.fg('success', '✔');\n // Held is not failed: the run went nowhere wrong, it just stopped short.\n if (HELD_STAGES.has(stage)) return theme.fg('warning', '■');\n return theme.fg('error', '✖');\n}\n\nfunction runLine(run: WorkflowFinishedRun, theme: Theme): string {\n const separator = ` ${theme.fg('dim', '·')} `;\n const identity = [run.runKey, run.workspace].filter(Boolean).join('/');\n const parts = [theme.fg('dim', identity), theme.fg('dim', run.stage)];\n if (run.workflowId) parts.unshift(theme.bold(run.workflowId));\n let text = `${statusIcon(run.stage, theme)} ${parts.join(separator)}`;\n if (run.failedJob) text += `\\n ${theme.fg('dim', `⎿ failed job: ${run.failedJob}`)}`;\n if (run.error) text += `\\n ${theme.fg('dim', `⎿ ${run.error}`)}`;\n return text;\n}\n\n/**\n * Exported for tests: the rendered string before it is wrapped in a `Text`\n * component, so the formatting is assertable without a terminal.\n */\nexport function renderWorkflowFinished(runs: readonly WorkflowFinishedRun[], theme: Theme): string {\n return runs.map((run) => runLine(run, theme)).join('\\n');\n}\n\nexport function isWorkflowFinishedRuns(value: unknown): value is WorkflowFinishedRun[] {\n if (!Array.isArray(value) || value.length === 0) return false;\n return value.every(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as WorkflowFinishedRun).runKey === 'string' &&\n typeof (entry as WorkflowFinishedRun).stage === 'string',\n );\n}\n\nexport function createWorkflowFinishedRenderer(): readonly [...Parameters<ExtensionAPI['registerMessageRenderer']>] {\n return [\n WORKFLOW_FINISHED_MESSAGE,\n (message, _options, theme: Theme): Component => {\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n const runs = (message.details as WorkflowFinishedDetails | undefined)?.runs;\n if (!isWorkflowFinishedRuns(runs)) return new Text(content, 0, 0);\n return new Text(renderWorkflowFinished(runs, theme), 0, 0);\n },\n ];\n}\n","/**\n * Session reporting for a run's progress log.\n *\n * DESIGN PATTERNS:\n * - Pure derivation. Takes a run's raw progress events and returns report lines,\n * so the behaviour is unit-testable without a registry or a live run.\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported members\n *\n * Live progress now renders through `workflowProgressOverlay.ts`. This module\n * remains the compatibility derivation used by terminal summaries and legacy\n * workflow-step cards already persisted in older sessions.\n */\n\nimport type { WorkflowProgressEvent } from '@agimon-ai/workflow-mcp';\n\n/** Step names come from workflow YAML and can be sentences. */\nconst MAX_STEP_LABEL = 48;\n\n/** One session line, plus the key that stops it being reported twice. */\nexport interface StepReport {\n duration?: string;\n job: string;\n key: string;\n status: 'FAILED' | 'FINISHED' | 'STARTED';\n step: string;\n}\n\nfunction truncateStep(step: string): string {\n return step.length <= MAX_STEP_LABEL ? step : `${step.slice(0, MAX_STEP_LABEL - 1)}…`;\n}\n\n/**\n * Human-scale duration.\n *\n * Rounded hard on purpose: this is read at a glance next to a step name, where\n * milliseconds are noise and \"4m12s\" answers the only question being asked.\n */\nexport function humanizeDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '?';\n if (ms < 1000) return `${ms}ms`;\n const seconds = Math.round(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m${String(seconds % 60).padStart(2, '0')}s`;\n return `${Math.floor(minutes / 60)}h${String(minutes % 60).padStart(2, '0')}m`;\n}\n\n/**\n * Turn a run's raw progress log into session report lines.\n *\n * Derives durations by pairing each step's start with its end rather than\n * recording a duration in the log, so nothing about the log format has to\n * change and old runs read back the same way.\n *\n * Keyed by the event's own timestamp so a caller polling the same append-only\n * file repeatedly reports each transition exactly once, however often it polls.\n */\nexport function stepReportLines(runKey: string, events: WorkflowProgressEvent[]): StepReport[] {\n const startedAt = new Map<string, string>();\n const reports: StepReport[] = [];\n\n for (const event of events) {\n if (event.type !== 'step' || !event.step) continue;\n const id = `${runKey}/${event.job}`;\n const stepKey = `${id}/${event.step}`;\n const label = truncateStep(event.step);\n\n if (event.status === 'running') {\n startedAt.set(stepKey, event.at);\n reports.push({ job: event.job, key: `started:${stepKey}:${event.at}`, status: 'STARTED', step: label });\n continue;\n }\n\n const began = startedAt.get(stepKey);\n const duration = began ? humanizeDuration(Date.parse(event.at) - Date.parse(began)) : '?';\n // A failed step did finish, but calling it FINISHED buries the one outcome\n // the reader needs to see. Same shape, honest verb.\n const status = event.status === 'failed' ? 'FAILED' : 'FINISHED';\n reports.push({ duration, job: event.job, key: `${status}:${stepKey}:${event.at}`, status, step: label });\n }\n\n return reports;\n}\n","/**\n * Workflow Space: the `SPC w l` overlay.\n *\n * A doom overlay rather than a hand-rolled frame: the roster owns the left\n * third, the run under the cursor owns the right two thirds, and the chrome is\n * the same frame, breadcrumb and key legend every other doom surface draws.\n *\n * Rendering is pure -- `renderBody(width, height)` reads the last polled\n * snapshot and returns lines with no side effects -- so the surface can be\n * asserted as text without a live terminal.\n */\n\nimport { currentWorkflowPosition, type WorkflowProgressJob } from '@agimon-ai/workflow-mcp';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fitTerminalLine } from './overlayText';\nimport { humanizeDuration } from './workflowStatusRow';\n\nexport const WORKFLOW_INSPECTOR_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nexport interface WorkflowInspectorSelection {\n runId?: string;\n runKey: string;\n startedAt: string;\n workspace: string;\n}\n\nexport interface WorkflowInspectorItem extends WorkflowInspectorSelection {\n displayName: string;\n executionState?: string;\n jobs: WorkflowProgressJob[];\n key: string;\n output: string[];\n}\n\nexport interface WorkflowInspectorSource {\n list(): Promise<WorkflowInspectorItem[]>;\n output(item: WorkflowInspectorItem): Promise<string[]>;\n}\n\nexport interface WorkflowInspectorOptions {\n initialKey?: string;\n refreshMs?: number;\n}\n\nconst TITLE = 'WORKFLOW SPACE';\nconst BREADCRUMB = 'SPC › w / workflows › l / manage';\nconst ROSTER_HEADING = 'RUNNING · this session';\nconst EMPTY_ROSTER = 'No active workflows';\nconst PROGRESS_HEADING = 'PROGRESS';\nconst OUTPUT_HEADING = 'OUTPUT · newest last';\nconst NO_SELECTION = 'Select a workflow to inspect its jobs and output.';\nconst RUNNING_STATE = 'running';\nconst PAUSED_STATE = 'paused';\n/** Mirrors DoomPi's list-navigation legend without adding a runtime doompi-ui dependency. */\nconst LIST_NAVIGATION_KEYS = '↑↓';\nconst FOOTER = `${LIST_NAVIGATION_KEYS} select · PgUp/PgDn page · enter open · esc close`;\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n [LIST_NAVIGATION_KEYS, 'select'],\n ['PgUp/PgDn', 'page'],\n ['enter', 'open'],\n ['esc', 'close'],\n];\n\nconst DEFAULT_REFRESH_MS = 750;\nconst SELECTION_MARKER = '›';\nconst ELLIPSIS = '…';\n/** pi-tui brackets a truncation ellipsis with this; see `fit`. */\nconst HARD_RESET = '\\x1b[0m';\n/** A third for the roster, two thirds for the run being read. */\nconst LIST_PANE_RATIO = 1 / 3;\n/** One blank column each side of the divider so neither pane touches it. */\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\n/** Below this the roster cannot hold a readable name, so the detail takes the body. */\nconst MIN_TWO_PANE_WIDTH = 48;\n/** Each run occupies a name row and a state row beneath it. */\nconst ROWS_PER_ITEM = 2;\n/** Hanging indent for the state row: clears the marker and the glyph. */\nconst META_INDENT = 4;\n/** Rows the roster heading and its spacer take. */\nconst ROSTER_CHROME_ROWS = 2;\n/** The output tail keeps at least this many rows, or it is not worth a divider. */\nconst MIN_OUTPUT_ROWS = 2;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\n/**\n * Truncates and pads to an exact column count.\n *\n * `truncateToWidth` wraps its ellipsis in a hard `\\x1b[0m`, which would strip a\n * row's background for everything after a clipped name. The theme closes its own\n * colours with `\\x1b[39m` and `\\x1b[49m`, so the injected resets are dropped.\n */\nfunction fit(text: string, width: number): string {\n const clipped = truncateToWidth(text, Math.max(0, width), ELLIPSIS).replaceAll(HARD_RESET, '');\n return clipped + ' '.repeat(Math.max(0, width - visibleWidth(clipped)));\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fit(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fit(right, rightWidth);\n}\n\nfunction jobGlyph(status: string): string {\n return status === 'completed' ? '✓' : status === 'failed' ? '✗' : '●';\n}\n\nfunction jobColour(status: string): ThemeColor {\n return status === 'completed' ? 'success' : status === 'failed' ? 'error' : 'accent';\n}\n\nfunction progressLines(item: WorkflowInspectorItem, width: number, theme: Theme): string[] {\n const lines: string[] = [];\n for (const job of item.jobs) {\n const position = job.total ? ` · ${(job.index ?? 0) + 1}/${job.total}` : '';\n lines.push(\n truncateToWidth(\n theme.fg(jobColour(job.status), `${jobGlyph(job.status)} ${job.name}`) + theme.fg('dim', position),\n width,\n ELLIPSIS,\n ),\n );\n // Only the running job's steps: every finished job's steps would push the\n // live one off the pane, which is the one thing worth watching.\n if (job.status !== RUNNING_STATE) continue;\n for (const step of job.steps) {\n const stepColour: ThemeColor =\n step.status === 'failed' ? 'error' : step.status === RUNNING_STATE ? 'muted' : 'dim';\n lines.push(truncateToWidth(theme.fg(stepColour, ` ${jobGlyph(step.status)} ${step.name}`), width, ELLIPSIS));\n }\n }\n return lines;\n}\n\nfunction detailLines(item: WorkflowInspectorItem | undefined, width: number, height: number, theme: Theme): string[] {\n if (!item) return [theme.fg('dim', NO_SELECTION)];\n\n const position = currentWorkflowPosition(item.jobs);\n const elapsed = humanizeDuration(Math.max(0, Date.now() - Date.parse(item.startedAt)));\n const executionState = item.executionState ?? RUNNING_STATE;\n const stateColour: ThemeColor = executionState === PAUSED_STATE ? 'warning' : 'dim';\n const lines = [\n rightAligned(\n `${theme.fg('accent', '●')} ${theme.bold(item.displayName)}`,\n theme.fg(stateColour, executionState),\n width,\n ),\n truncateToWidth(theme.fg('dim', `${item.runKey} · ${item.workspace} · ${elapsed}`), width, ELLIPSIS),\n position\n ? truncateToWidth(\n `${theme.fg('accent', position.job)}${position.step ? theme.fg('muted', ` · ${position.step}`) : ''}`,\n width,\n ELLIPSIS,\n )\n : theme.fg('dim', 'starting'),\n '',\n theme.fg('dim', PROGRESS_HEADING),\n ];\n\n // The output tail claims its rows first: progress is a list that can be paged\n // to by opening the run, while the tail is the only live signal on screen.\n const reservedOutput = item.output.length > 0 ? MIN_OUTPUT_ROWS + 1 : 0;\n const progressRoom = Math.max(0, height - lines.length - reservedOutput);\n lines.push(...progressLines(item, width, theme).slice(0, progressRoom));\n\n if (item.output.length > 0 && height - lines.length >= MIN_OUTPUT_ROWS) {\n lines.push('', theme.fg('dim', OUTPUT_HEADING));\n const outputRoom = Math.max(0, height - lines.length);\n // Captured output carries the run's own colour, so it is fitted by the\n // escape-preserving path: `fit` below drops hard resets, and a capture that\n // lost its reset bleeds its colour through the divider and down the pane.\n lines.push(...item.output.slice(-outputRoom).map((line) => fitTerminalLine(line, width)));\n }\n\n return lines.slice(0, height);\n}\n\nexport class WorkflowInspectorComponent extends DoomOverlay {\n private bodyHeight = 8;\n private completed = false;\n private error: string | undefined;\n private items: WorkflowInspectorItem[] = [];\n private refreshActive = false;\n private selected = 0;\n private selectedKey: string | undefined;\n private readonly timer: ReturnType<typeof setInterval>;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly source: WorkflowInspectorSource,\n private readonly done: (selection: WorkflowInspectorSelection | undefined) => void,\n options: WorkflowInspectorOptions = {},\n ) {\n super(tui, theme);\n this.selectedKey = options.initialKey;\n void this.refresh();\n this.timer = setInterval(() => void this.refresh(), options.refreshMs ?? DEFAULT_REFRESH_MS);\n this.timer.unref?.();\n }\n\n private async refresh(): Promise<void> {\n if (this.refreshActive || this.completed) return;\n this.refreshActive = true;\n try {\n const previousKey = this.items[this.selected]?.key ?? this.selectedKey;\n const items = await this.source.list();\n if (this.completed) return;\n const preserved = previousKey ? items.findIndex((item) => item.key === previousKey) : -1;\n this.items = items;\n this.selected = preserved >= 0 ? preserved : Math.min(this.selected, Math.max(0, items.length - 1));\n this.selectedKey = items[this.selected]?.key;\n const selected = items[this.selected];\n if (selected) selected.output = await this.source.output(selected);\n this.error = undefined;\n if (!this.completed) this.tui.requestRender();\n } catch (cause) {\n this.error = cause instanceof Error ? cause.message : String(cause);\n if (!this.completed) this.tui.requestRender();\n } finally {\n this.refreshActive = false;\n }\n }\n\n private move(delta: number): void {\n if (this.items.length === 0) return;\n this.selected = Math.max(0, Math.min(this.items.length - 1, this.selected + delta));\n this.selectedKey = this.items[this.selected]?.key;\n void this.refreshSelectedOutput();\n this.tui.requestRender();\n }\n\n private async refreshSelectedOutput(): Promise<void> {\n const selected = this.items[this.selected];\n if (!selected || this.completed) return;\n try {\n selected.output = await this.source.output(selected);\n this.error = undefined;\n } catch (cause) {\n this.error = cause instanceof Error ? cause.message : String(cause);\n }\n if (!this.completed && selected.key === this.selectedKey) this.tui.requestRender();\n }\n\n private finish(selection: WorkflowInspectorSelection | undefined): void {\n if (this.completed) return;\n this.completed = true;\n clearInterval(this.timer);\n this.done(selection);\n }\n\n close(): void {\n this.finish(undefined);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.finish(undefined);\n return;\n }\n if (matchesKey(data, 'up') || data === 'k') {\n this.move(-1);\n return;\n }\n if (matchesKey(data, 'down') || data === 'j') {\n this.move(1);\n return;\n }\n if (matchesKey(data, 'pageUp')) {\n this.move(-this.rosterCapacity());\n return;\n }\n if (matchesKey(data, 'pageDown')) {\n this.move(this.rosterCapacity());\n return;\n }\n if (matchesKey(data, 'enter')) {\n const selected = this.items[this.selected];\n if (selected) {\n this.finish({\n ...(selected.runId ? { runId: selected.runId } : {}),\n runKey: selected.runKey,\n startedAt: selected.startedAt,\n workspace: selected.workspace,\n });\n }\n }\n }\n\n /** Runs the roster can draw, which is also what a page key moves by. */\n private rosterCapacity(): number {\n return Math.max(1, Math.floor((this.bodyHeight - ROSTER_CHROME_ROWS) / ROWS_PER_ITEM));\n }\n\n private current(): WorkflowInspectorItem | undefined {\n if (this.items.length === 0) return undefined;\n return this.items[Math.min(this.selected, this.items.length - 1)];\n }\n\n protected getChrome(): DoomOverlayChrome {\n const selected = this.current();\n const summary = selected\n ? `${selected.displayName} · ${selected.executionState ?? RUNNING_STATE}`\n : 'no active workflows';\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${this.items.length} running · ${summary}`,\n footer: FOOTER,\n footerHints: FOOTER_HINTS,\n footerRight:\n this.items.length > 0 ? `${Math.min(this.selected, this.items.length - 1) + 1}/${this.items.length}` : 'empty',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n this.bodyHeight = height;\n const detailFor = (paneWidth: number): string[] =>\n this.error\n ? [this.theme.fg('warning', `Unable to refresh workflows: ${this.error}`)]\n : detailLines(this.current(), paneWidth, height, this.theme);\n\n // Too narrow for two useful columns: the detail takes the whole body rather\n // than shredding both panes into stubs.\n if (width < MIN_TWO_PANE_WIDTH) return detailFor(width).slice(0, height);\n\n const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * LIST_PANE_RATIO));\n const rightWidth = Math.max(1, width - leftWidth - 1);\n const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n\n const left = this.rosterLines(leftContent);\n const right = detailFor(rightContent);\n const divider = this.theme.fg('borderMuted', '│');\n return Array.from({ length: height }, (_, index) => {\n // The roster keeps `fit`, whose reset stripping protects its row\n // backgrounds; the detail pane has none and may carry captured colour.\n const row = `${fit(left[index] ?? '', leftContent)} ${divider} ${fitTerminalLine(\n right[index] ?? '',\n rightContent,\n )}`;\n return truncateToWidth(row, width, ELLIPSIS);\n });\n }\n\n private rosterLines(width: number): string[] {\n const lines = [this.theme.bold(ROSTER_HEADING), ''];\n if (this.items.length === 0) {\n lines.push(this.theme.fg('dim', EMPTY_ROSTER));\n return lines;\n }\n\n // Two rows per run: at a third of the width a single row left the name with\n // a handful of columns once the stage took its share.\n const budget = this.rosterCapacity();\n const active = Math.min(this.selected, this.items.length - 1);\n const start = Math.max(0, Math.min(active - budget + 1, Math.max(0, this.items.length - budget)));\n for (const [offset, item] of this.items.slice(start, start + budget).entries()) {\n const current = start + offset === active;\n const paused = item.executionState === PAUSED_STATE;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const glyph = this.theme.fg(paused ? 'warning' : 'accent', '●');\n const name = current ? this.theme.bold(item.displayName) : item.displayName;\n const stage = paused ? PAUSED_STATE : (currentWorkflowPosition(item.jobs)?.job ?? 'starting');\n const heading = `${marker} ${glyph} ${name}`;\n const meta = `${' '.repeat(META_INDENT)}${this.theme.fg(paused ? 'warning' : 'dim', stage)}`;\n const background: ThemeBg = current ? 'selectedBg' : 'userMessageBg';\n for (const row of [heading, meta]) lines.push(this.theme.bg(background, fit(row, width)));\n }\n return lines;\n }\n\n /** Overridden: a repaint request is also the cue to re-read the registry. */\n invalidate(): void {\n void this.refresh();\n }\n\n dispose(): void {\n if (this.completed) return;\n this.completed = true;\n clearInterval(this.timer);\n }\n}\n","/**\n * Input plumbing for the run panel: keystroke batching and the escape hatch.\n *\n * The panel's rendering lives in `workflowRunPanel.ts`, which is a doom overlay;\n * what stays here is the behaviour that has nothing to do with drawing.\n *\n * DESIGN PATTERNS:\n * - Input batching. Every keystroke sent individually costs one subprocess\n * round trip, measured at ~18ms, which caps sustained typing near 56 c/s and\n * makes held keys queue visibly. Coalescing a frame's bytes into one send\n * keeps latency at roughly one frame no matter how fast the user types.\n * - Stateless render. The component recomputes from the latest snapshot on\n * every frame, so a theme change needs no cache invalidation.\n * - Terminal-independent escape hatch. The focused panel forwards every key to\n * the run, so the way out cannot itself depend on a modifier the terminal\n * may not transmit.\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported members\n *\n * AVOID:\n * - Sending per keystroke: it is the difference between usable and unusable\n * - Holding the flush timer open after dispose, which would keep writing into\n * a run the user has stopped watching\n */\n\nimport { isKeyRelease, matchesKey } from '@earendil-works/pi-tui';\n\n/** One frame at 60Hz. Long enough to coalesce a burst, short enough to feel direct. */\nconst FLUSH_INTERVAL_MS = 16;\n\n/**\n * How close two Escapes must be to read as \"get me out\".\n *\n * Long enough to be reachable without hurrying, short enough that two\n * deliberate, separate interrupts sent to the run are not mistaken for it.\n */\nexport const DOUBLE_ESCAPE_WINDOW_MS = 350;\n\n/** What the overlay should do with a keystroke. */\nexport type EscapeAction = 'forward' | 'close';\n\n/**\n * The panel's guaranteed way out: press Escape twice, quickly.\n *\n * A focused panel hands every key to the run so its agent stays interruptible,\n * which leaves the two `ctrl+alt` chords as the only exits. Those are exactly\n * the keys a terminal may not deliver: macOS without Option-as-Meta sends plain\n * `ctrl+w` instead, and the byte is forwarded into the run rather than matching.\n * The user is then inside a view they cannot leave. Escape is the one key every\n * terminal transmits identically, which is what makes it the failsafe.\n *\n * The first Escape is still forwarded, so interrupting the step stays as fast as\n * it ever was. Only the second one is consumed, and only when it lands inside\n * the window. The cost is one keystroke: sending the run two literal Escapes in\n * quick succession is no longer possible, which is worth an escapable panel.\n */\nexport class DoubleEscapeDetector {\n private lastEscapeAt: number | undefined;\n\n constructor(private readonly windowMs: number = DOUBLE_ESCAPE_WINDOW_MS) {}\n\n /**\n * Classify one chunk of terminal input.\n *\n * `now` is injected so the decision is a pure function of its inputs, which\n * is what makes the window testable without timers.\n */\n observe(data: string, now: number = Date.now()): EscapeAction {\n // Two Escapes coalesced into one read. A terminal in legacy mode delivers\n // this when they arrive inside the same poll, so it is the same gesture and\n // has to reach the same answer. `matchesKey` never sees it as an escape:\n // it parses as ctrl+alt+[, which has no meaning to a run either way.\n if (data === '\\x1b\\x1b') {\n this.lastEscapeAt = undefined;\n return 'close';\n }\n\n // A Kitty release event repeats the press's own bytes. Counting it would\n // turn one deliberate press into a pair and close the panel under the user.\n if (isKeyRelease(data)) return 'forward';\n\n if (!matchesKey(data, 'escape')) {\n // Anything typed in between makes these two separate interrupts rather\n // than one gesture, so the pair has to start over.\n this.lastEscapeAt = undefined;\n return 'forward';\n }\n\n if (this.lastEscapeAt !== undefined && now - this.lastEscapeAt <= this.windowMs) {\n this.lastEscapeAt = undefined;\n return 'close';\n }\n\n this.lastEscapeAt = now;\n return 'forward';\n }\n}\n\n/**\n * Collects keystrokes and forwards them in frame-sized batches.\n *\n * Failures are swallowed on purpose: a dropped keystroke is a nuisance, but an\n * exception raised from a terminal input handler would tear down the overlay.\n */\nexport class TerminalInputBatcher {\n private pending = '';\n private timer: NodeJS.Timeout | undefined;\n private disposed = false;\n\n constructor(\n private readonly send: (text: string) => Promise<void>,\n private readonly flushIntervalMs: number = FLUSH_INTERVAL_MS,\n ) {}\n\n write(data: string): void {\n if (this.disposed || data.length === 0) return;\n this.pending += data;\n if (this.timer) return;\n this.timer = setTimeout(() => void this.flush(), this.flushIntervalMs);\n this.timer.unref?.();\n }\n\n /** Send whatever has accumulated. Safe to call with nothing pending. */\n async flush(): Promise<void> {\n if (this.timer) clearTimeout(this.timer);\n this.timer = undefined;\n const text = this.pending;\n this.pending = '';\n if (!text || this.disposed) return;\n try {\n await this.send(text);\n } catch {\n // A dropped keystroke must not take the overlay down with it.\n }\n }\n\n /** Stop accepting and forwarding input. Pending bytes are discarded. */\n dispose(): void {\n this.disposed = true;\n if (this.timer) clearTimeout(this.timer);\n this.timer = undefined;\n this.pending = '';\n }\n\n /** Exposed for tests: whether a flush is scheduled. */\n hasPending(): boolean {\n return this.pending.length > 0;\n }\n}\n","/**\n * Scrollable, filterable list picker for every long list this extension shows.\n *\n * Replaces a bare `ui.select`, which wrapped each `name · detail` pair across\n * two or three terminal rows and left no way to reach a row other than scrolling\n * past all of them. This is a doom overlay instead: one row per item, a windowed\n * list that scrolls with the selection, and a filter field that narrows as you\n * type.\n *\n * Generic over the value it hands back. `SPC w c` picks a failed run to recover\n * through it; browsing and launching workflows moved to `workflowCatalog.ts`,\n * which needs the detail on screen beside the list rather than behind a pick.\n *\n * Rendering is pure, so the surface can be asserted as text without a terminal.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { CURSOR_BLOCK, fit, isControlInput, matchesQuery, pathTail, SELECTION_MARKER } from './overlayText';\n\nexport const WORKFLOW_PICKER_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_NAME = '(unnamed)';\nconst KEY_CLEAR = '\\x15';\n/** Rows the filter field and its trailing spacer take from the body. */\nconst FILTER_ROWS = 3;\n/** Columns the marker and its trailing space take from a row. */\nconst MARKER_COLUMNS = 2;\n/** Blank columns between the name column and the detail column. */\nconst COLUMN_GAP = 2;\nconst MIN_NAME_WIDTH = 16;\nconst NAME_RATIO = 0.45;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst DIM: ThemeColor = 'dim';\nconst ACCENT: ThemeColor = 'accent';\nconst SELECTED_BG: ThemeBg = 'selectedBg';\nconst ROW_BG: ThemeBg = 'userMessageBg';\n\nexport interface PickerRow<T> {\n /** Stable identity, used only to keep rows distinct. */\n key: string;\n /** Left column. */\n name: string;\n /** Right column, trimmed from the front so its tail survives. */\n detail: string;\n /** Extra text the filter should match but the row does not show. */\n search?: string;\n value: T;\n}\n\nexport interface WorkflowPickerConfig {\n title: string;\n breadcrumb: string;\n /** Plural noun for the header count, e.g. `workflows`. */\n unit: string;\n /** Verb on the enter key cap, e.g. `launch`. */\n action: string;\n filterPlaceholder: string;\n /** Shown when the source list itself is empty, as opposed to over-filtered. */\n emptyMessage: string;\n}\n\nexport function filterPickerRows<T>(rows: readonly PickerRow<T>[], query: string): PickerRow<T>[] {\n if (!query.trim()) return [...rows];\n return rows.filter((row) => matchesQuery([row.name, row.detail, row.search ?? ''].join(' '), query));\n}\n\nexport class WorkflowPickerComponent<T> extends DoomOverlay {\n private query = '';\n private selected = 0;\n private bodyHeight = 1;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly config: WorkflowPickerConfig,\n private readonly rows: readonly PickerRow<T>[],\n private readonly done: (value: T | undefined) => void,\n ) {\n super(tui, theme);\n }\n\n private matches(): PickerRow<T>[] {\n return filterPickerRows(this.rows, this.query);\n }\n\n /** Rows the list can draw, once the filter field has taken its share. */\n private capacity(): number {\n return Math.max(1, this.bodyHeight - FILTER_ROWS);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n const matches = this.matches();\n if (matchesKey(data, 'enter')) {\n const row = matches[Math.min(this.selected, matches.length - 1)];\n if (row) this.done(row.value);\n return;\n }\n\n if (matchesKey(data, 'up') || matchesKey(data, 'ctrl+p')) this.move(-1, matches.length);\n else if (matchesKey(data, 'down') || matchesKey(data, 'ctrl+n')) this.move(1, matches.length);\n else if (matchesKey(data, 'pageUp')) this.move(-this.capacity(), matches.length);\n else if (matchesKey(data, 'pageDown')) this.move(this.capacity(), matches.length);\n else if (matchesKey(data, 'backspace')) this.setQuery(this.query.slice(0, -1));\n else if (data === KEY_CLEAR) this.setQuery('');\n else if (!isControlInput(data)) this.setQuery(this.query + data);\n else return;\n\n this.tui.requestRender();\n }\n\n /** Editing the filter resets the cursor: the previous index named another row. */\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n this.selected = 0;\n }\n\n private move(delta: number, count: number): void {\n if (count === 0) return;\n this.selected = Math.max(0, Math.min(count - 1, this.selected + delta));\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: this.config.title,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.config.breadcrumb,\n headerRight: `${scope} ${this.config.unit}`,\n footer: `↑↓ select · enter ${this.config.action} · type to filter · ctrl+u clear · esc cancel`,\n footerHints: [\n ['↑↓', 'select'],\n ['enter', this.config.action],\n ['type', 'filter'],\n ['ctrl+u', 'clear'],\n ['esc', 'cancel'],\n ],\n footerRight:\n matches.length > 0 ? `${Math.min(this.selected, matches.length - 1) + 1}/${matches.length}` : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n this.bodyHeight = height;\n return [...this.filterField(width), ...this.listLines(width)].slice(0, height);\n }\n\n private filterField(width: number): string[] {\n const value = this.query\n ? `${this.query}${CURSOR_BLOCK}`\n : `${CURSOR_BLOCK}${this.theme.fg(DIM, this.config.filterPlaceholder)}`;\n return [this.theme.fg(DIM, FILTER_LABEL), this.theme.bg(SELECTED_BG, fit(` ${value}`, width)), ''];\n }\n\n private listLines(width: number): string[] {\n if (this.rows.length === 0) return [this.theme.fg(DIM, this.config.emptyMessage)];\n const matches = this.matches();\n if (matches.length === 0) return [this.theme.fg(DIM, `No ${this.config.unit} match \"${this.query}\".`)];\n\n const capacity = this.capacity();\n const active = Math.min(this.selected, matches.length - 1);\n // The window follows the cursor rather than the other way round, so a filter\n // that shrinks the list can never strand the selection off-screen.\n const start = Math.max(0, Math.min(active - capacity + 1, Math.max(0, matches.length - capacity)));\n\n const nameWidth = Math.max(MIN_NAME_WIDTH, Math.floor((width - MARKER_COLUMNS - COLUMN_GAP) * NAME_RATIO));\n const detailWidth = Math.max(0, width - MARKER_COLUMNS - COLUMN_GAP - nameWidth);\n return matches.slice(start, start + capacity).map((row, offset) => {\n const current = start + offset === active;\n const marker = current ? this.theme.fg(ACCENT, SELECTION_MARKER) : ' ';\n const name = row.name || EMPTY_NAME;\n const label = current ? this.theme.bold(fit(name, nameWidth)) : fit(name, nameWidth);\n const detail = this.theme.fg(DIM, fit(pathTail(row.detail, detailWidth), detailWidth));\n const background: ThemeBg = current ? SELECTED_BG : ROW_BG;\n return this.theme.bg(background, fit(`${marker} ${label}${' '.repeat(COLUMN_GAP)}${detail}`, width));\n });\n }\n}\n\nexport async function openWorkflowPickerOverlay<T>(\n ctx: ExtensionContext,\n config: WorkflowPickerConfig,\n rows: readonly PickerRow<T>[],\n): Promise<T | undefined> {\n return ctx.ui.custom<T | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowPickerComponent(tui, theme, config, rows, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Task-like live workflow list shown above Pi's editor.\n *\n * DESIGN PATTERNS:\n * - The extension owns run/event state; this component only projects and renders it.\n * - Register the widget once, then request redraws as progress, elapsed time, or the spinner changes.\n * - Terminal runs are absent from `rows`, so the widget disappears when the last run ends.\n *\n * CODING STANDARDS:\n * - Every rendered line is ANSI-aware and truncated to the available terminal width.\n * - Theme colors come from Pi's live UI context so theme changes repaint correctly.\n * - Named exports only and explicit return types on exported members.\n *\n * AVOID:\n * - Persisting progress in the chat transcript.\n * - Starting timers while no workflow is visible.\n */\n\nimport type { WorkflowProgressEvent, WorkflowRunRecord } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionUIContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type TUI, truncateToWidth } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_PROGRESS_WIDGET_KEY = 'workflow-mcp-progress';\n\nconst OVERLAY_HEADING = 'Workflows';\nconst PROGRESS_TICK_MS = 200;\nconst RUNNING_SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] as const;\nconst STATIC_PROGRESS_MARKER = '*';\nconst MILLISECONDS_PER_SECOND = 1000;\nconst SECONDS_PER_MINUTE = 60;\nconst MINUTES_PER_HOUR = 60;\nconst STARTING_JOB_STEP = 'Starting job';\nconst STARTING_WORKFLOW_STEP = 'Starting workflow';\nconst PREPARING_WORKFLOW_STEP = 'Preparing workflow';\nconst FINALIZING_WORKFLOW_STEP = 'Finalizing workflow';\n\ntype WorkflowProgressColor = Parameters<Theme['fg']>[0];\n\nexport type WorkflowProgressState = 'completed' | 'failed' | 'paused' | 'running' | 'skipped' | 'starting';\n\n/** One explicit palette makes every workflow state visually stable across the list. */\nexport const WORKFLOW_PROGRESS_COLORS: Readonly<Record<WorkflowProgressState, WorkflowProgressColor>> = {\n starting: 'dim',\n running: 'accent',\n completed: 'success',\n paused: 'warning',\n failed: 'error',\n skipped: 'muted',\n};\n\nexport interface WorkflowProgressRow {\n job: string;\n key: string;\n name: string;\n startedAt: string;\n state: WorkflowProgressState;\n step: string;\n}\n\nfunction latestStep(events: readonly WorkflowProgressEvent[]): WorkflowProgressEvent | undefined {\n return events.findLast((event) => event.type === 'step' && !!event.step);\n}\n\nfunction latestEvent(events: readonly WorkflowProgressEvent[]): WorkflowProgressEvent | undefined {\n return events.at(-1);\n}\n\nfunction progressState(record: WorkflowRunRecord, event: WorkflowProgressEvent | undefined): WorkflowProgressState {\n if (record.stage === 'error') return 'failed';\n if (record.stage === 'completed') return 'completed';\n if (record.executionState === 'paused' || record.executionState === 'pause_requested') return 'paused';\n\n switch (event?.status) {\n case 'failed':\n return 'failed';\n case 'paused':\n case 'pause_requested':\n return 'paused';\n case 'completed':\n return 'completed';\n case 'skipped':\n return 'skipped';\n case 'resumed':\n case 'running':\n return 'running';\n default:\n return record.executionCursor?.stepName ? 'running' : 'starting';\n }\n}\n\nfunction fallbackStep(record: WorkflowRunRecord): string {\n switch (record.executionCursor?.phase) {\n case 'pre':\n return PREPARING_WORKFLOW_STEP;\n case 'post':\n return FINALIZING_WORKFLOW_STEP;\n case 'job':\n case 'step':\n return STARTING_JOB_STEP;\n default:\n return STARTING_WORKFLOW_STEP;\n }\n}\n\n/** Derive the single current line for one run from its record and pushed progress events. */\nexport function workflowProgressRow(\n record: WorkflowRunRecord,\n events: readonly WorkflowProgressEvent[],\n): WorkflowProgressRow {\n const stepEvent = latestStep(events);\n const event = latestEvent(events);\n const cursor = record.executionCursor;\n const job = cursor?.job ?? stepEvent?.job ?? event?.job ?? record.job ?? cursor?.phase ?? 'workflow';\n const step = cursor?.stepName ?? (stepEvent?.job === job ? stepEvent.step : undefined) ?? fallbackStep(record);\n\n return {\n job,\n key: record.runId ?? `${record.workspace}/${record.runKey}`,\n name: record.displayName,\n startedAt: record.startedAt,\n state: progressState(record, event),\n step,\n };\n}\n\n/** Task-style elapsed time: whole seconds stay stable and compact between animation ticks. */\nexport function formatWorkflowDuration(durationMs: number): string {\n if (!Number.isFinite(durationMs) || durationMs < 0) return '?';\n const totalSeconds = Math.floor(durationMs / MILLISECONDS_PER_SECOND);\n const seconds = totalSeconds % SECONDS_PER_MINUTE;\n const totalMinutes = Math.floor(totalSeconds / SECONDS_PER_MINUTE);\n if (totalMinutes < MINUTES_PER_HOUR) {\n return totalMinutes === 0 ? `${seconds}s` : `${totalMinutes}m${String(seconds).padStart(2, '0')}s`;\n }\n const minutes = totalMinutes % MINUTES_PER_HOUR;\n const hours = Math.floor(totalMinutes / MINUTES_PER_HOUR);\n return `${hours}h${String(minutes).padStart(2, '0')}m${String(seconds).padStart(2, '0')}s`;\n}\n\nfunction progressMarker(state: WorkflowProgressState, nowMs: number): string {\n if (state !== 'running' && state !== 'starting') return STATIC_PROGRESS_MARKER;\n const tick = Number.isFinite(nowMs) ? Math.floor(Math.max(0, nowMs) / PROGRESS_TICK_MS) : 0;\n return RUNNING_SPINNER_FRAMES[tick % RUNNING_SPINNER_FRAMES.length] ?? RUNNING_SPINNER_FRAMES[0];\n}\n\n/** Render exactly: `<workflow name>[<duration>][<job>] <activity> <step>`. */\nexport function formatWorkflowProgressRow(row: WorkflowProgressRow, theme: Theme, nowMs = Date.now()): string {\n const startedAt = Date.parse(row.startedAt);\n const duration = formatWorkflowDuration(Number.isFinite(startedAt) ? nowMs - startedAt : Number.NaN);\n const color = WORKFLOW_PROGRESS_COLORS[row.state];\n return [\n theme.fg(color, row.name),\n theme.fg('muted', `[${duration}][${row.job}]`),\n theme.fg(color, ` ${progressMarker(row.state, nowMs)} `),\n theme.fg('text', row.step),\n ].join('');\n}\n\n/** Persistent workflow widget with the same heading/tree shape as Doom's task list. */\nexport class WorkflowProgressOverlay {\n private rows: readonly WorkflowProgressRow[] = [];\n private uiCtx: ExtensionUIContext | undefined;\n private widgetRegistered = false;\n private tui: TUI | undefined;\n private progressTimer: NodeJS.Timeout | undefined;\n\n /** Identity-compare so repeated session starts do not register duplicate widgets. */\n setUICtx(ctx: ExtensionUIContext): void {\n if (ctx === this.uiCtx) return;\n if (this.uiCtx && this.widgetRegistered) this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.stopProgressTimer();\n this.uiCtx = ctx;\n this.widgetRegistered = false;\n this.tui = undefined;\n }\n\n update(rows: readonly WorkflowProgressRow[]): void {\n this.rows = rows;\n if (!this.uiCtx) {\n this.stopProgressTimer();\n return;\n }\n\n if (rows.length === 0) {\n if (this.widgetRegistered) {\n this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.widgetRegistered = false;\n this.tui = undefined;\n }\n this.stopProgressTimer();\n return;\n }\n\n if (this.widgetRegistered) {\n this.syncProgressTimer();\n this.tui?.requestRender();\n return;\n }\n\n this.uiCtx.setWidget(\n WORKFLOW_PROGRESS_WIDGET_KEY,\n (tui, factoryTheme) => {\n this.tui = tui;\n return {\n render: (width: number) => this.renderWidget(this.uiCtx?.theme ?? factoryTheme, width),\n invalidate: () => {\n // Nothing cached: the next render reads the current rows, clock, and theme.\n },\n };\n },\n { placement: 'aboveEditor' },\n );\n this.widgetRegistered = true;\n this.syncProgressTimer();\n }\n\n private syncProgressTimer(): void {\n if (!this.widgetRegistered || this.rows.length === 0) {\n this.stopProgressTimer();\n return;\n }\n if (this.progressTimer) return;\n this.progressTimer = setInterval(() => this.tui?.requestRender(), PROGRESS_TICK_MS);\n this.progressTimer.unref?.();\n }\n\n private stopProgressTimer(): void {\n if (this.progressTimer) clearInterval(this.progressTimer);\n this.progressTimer = undefined;\n }\n\n private renderWidget(theme: Theme, width: number): string[] {\n if (this.rows.length === 0) return [];\n const truncate = (line: string): string => truncateToWidth(line, width, '…');\n const heading = truncate(\n `${theme.fg('accent', '●')} ${theme.fg('accent', `${OVERLAY_HEADING} (${this.rows.length})`)}`,\n );\n const nowMs = Date.now();\n const lines = [heading];\n\n for (const [index, row] of this.rows.entries()) {\n const branch = index === this.rows.length - 1 ? '└─' : '├─';\n lines.push(truncate(`${theme.fg('dim', branch)} ${formatWorkflowProgressRow(row, theme, nowMs)}`));\n }\n\n // Pi adds space above widgets but not below; keep the list off the editor border.\n lines.push('');\n return lines;\n }\n\n dispose(): void {\n this.stopProgressTimer();\n if (this.uiCtx) this.uiCtx.setWidget(WORKFLOW_PROGRESS_WIDGET_KEY, undefined);\n this.rows = [];\n this.widgetRegistered = false;\n this.tui = undefined;\n this.uiCtx = undefined;\n }\n}\n","/**\n * The short prompts: pick one of a few options, or type one value.\n *\n * These were `ui.select` and `ui.input`, which meant the run manager, the runner\n * picker and every `workflow_dispatch` input rendered as native Pi widgets in the\n * middle of a flow whose other steps are framed doom overlays. Same surface for\n * all of them now, so a launch reads as one sequence rather than three styles.\n *\n * Rendering is pure, so both modes can be asserted as text without a terminal.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { CURSOR_BLOCK, fit, isControlInput, rightAligned, SELECTION_MARKER } from './overlayText';\n\nexport const WORKFLOW_PROMPT_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nconst CHOICE_TITLE = 'WORKFLOW PROMPT';\nconst CHOOSE_LABEL = 'CHOOSE';\nconst VALUE_LABEL = 'VALUE';\nconst DEFAULT_MARKER = 'default';\nconst EMPTY_CHOICES = 'No options are available.';\nconst CHOICE_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'select'],\n ['enter', 'confirm'],\n ['esc', 'cancel'],\n];\nconst INPUT_HINTS: readonly (readonly [string, string])[] = [\n ['type', 'edit'],\n ['enter', 'confirm'],\n ['ctrl+u', 'clear'],\n ['esc', 'cancel'],\n];\nconst KEY_CLEAR = '\\x15';\n/** Rows the heading and its spacer take before the first option. */\nconst HEADING_ROWS = 2;\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst DIM: ThemeColor = 'dim';\nconst ACCENT: ThemeColor = 'accent';\nconst SELECTED_BG: ThemeBg = 'selectedBg';\nconst ROW_BG: ThemeBg = 'userMessageBg';\n\nexport interface WorkflowChoiceOptions {\n title: string;\n breadcrumb: string;\n choices: readonly string[];\n /** Marked `default` in the list and pre-selected. */\n preselect?: string;\n}\n\nexport interface WorkflowInputOptions {\n title: string;\n breadcrumb: string;\n /** Committed when the field is left empty, and shown beside the label. */\n fallback?: string;\n}\n\nexport class WorkflowChoiceComponent extends DoomOverlay {\n private selected: number;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowChoiceOptions,\n private readonly done: (choice: string | undefined) => void,\n ) {\n super(tui, theme);\n this.selected = Math.max(0, options.preselect ? options.choices.indexOf(options.preselect) : 0);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, 'enter')) {\n const choice = this.options.choices[this.selected];\n if (choice !== undefined) this.done(choice);\n return;\n }\n const count = this.options.choices.length;\n if (count === 0) return;\n if (matchesKey(data, 'up') || matchesKey(data, 'ctrl+p')) this.selected = Math.max(0, this.selected - 1);\n else if (matchesKey(data, 'down') || matchesKey(data, 'ctrl+n'))\n this.selected = Math.min(count - 1, this.selected + 1);\n else return;\n this.tui.requestRender();\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: CHOICE_TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: `${this.options.choices.length} options`,\n footer: '↑↓ select · enter confirm · esc cancel',\n footerHints: CHOICE_HINTS,\n footerRight:\n this.options.choices.length > 0 ? `${this.selected + 1}/${this.options.choices.length}` : 'no options',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const lines = [this.theme.bold(fit(this.options.title, width)), ''];\n if (this.options.choices.length === 0) {\n lines.push(this.theme.fg(DIM, EMPTY_CHOICES));\n return lines.slice(0, height);\n }\n\n lines.push(this.theme.fg(DIM, CHOOSE_LABEL));\n // The window follows the cursor, so a list longer than the body still scrolls.\n const capacity = Math.max(1, height - HEADING_ROWS - 1);\n const start = Math.max(\n 0,\n Math.min(this.selected - capacity + 1, Math.max(0, this.options.choices.length - capacity)),\n );\n for (const [offset, choice] of this.options.choices.slice(start, start + capacity).entries()) {\n const current = start + offset === this.selected;\n const marker = current ? this.theme.fg(ACCENT, SELECTION_MARKER) : ' ';\n const label = current ? this.theme.bold(choice) : choice;\n const note = choice === this.options.preselect ? this.theme.fg(DIM, DEFAULT_MARKER) : '';\n const background: ThemeBg = current ? SELECTED_BG : ROW_BG;\n lines.push(this.theme.bg(background, rightAligned(`${marker} ${label}`, note, width)));\n }\n return lines.slice(0, height);\n }\n}\n\nexport class WorkflowInputComponent extends DoomOverlay {\n private draft = '';\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowInputOptions,\n private readonly done: (value: string | undefined) => void,\n ) {\n super(tui, theme);\n }\n\n handleInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, 'enter')) {\n // An empty field commits the fallback rather than an empty string: the\n // caller offered a default, and pressing enter is how you accept it.\n this.done(this.draft.trim() || this.options.fallback || '');\n return;\n }\n if (matchesKey(data, 'backspace')) this.draft = this.draft.slice(0, -1);\n else if (data === KEY_CLEAR) this.draft = '';\n else if (!isControlInput(data)) this.draft += data;\n else return;\n this.tui.requestRender();\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: CHOICE_TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: this.options.fallback ? `default ${this.options.fallback}` : 'no default',\n footer: 'type to edit · enter confirm · ctrl+u clear · esc cancel',\n footerHints: INPUT_HINTS,\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const label = this.options.fallback\n ? rightAligned(\n this.theme.fg(DIM, VALUE_LABEL),\n this.theme.fg(DIM, `${DEFAULT_MARKER} ${this.options.fallback}`),\n width,\n )\n : this.theme.fg(DIM, VALUE_LABEL);\n return [\n this.theme.bold(fit(this.options.title, width)),\n '',\n label,\n this.theme.bg(SELECTED_BG, fit(` ${this.draft}${CURSOR_BLOCK}`, width)),\n ].slice(0, height);\n }\n}\n\nexport async function openWorkflowChoice(\n ctx: ExtensionContext,\n options: WorkflowChoiceOptions,\n): Promise<string | undefined> {\n return ctx.ui.custom<string | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowChoiceComponent(tui, theme, options, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n\nexport async function openWorkflowInput(\n ctx: ExtensionContext,\n options: WorkflowInputOptions,\n): Promise<string | undefined> {\n return ctx.ui.custom<string | undefined>(\n (tui, theme, _keybindings, done) => new WorkflowInputComponent(tui, theme, options, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n","/**\n * Run panel: the live view of one run's job tree and its terminal.\n *\n * A doom overlay rather than the bare header/body/footer it used to draw, so the\n * one surface a user sits inside for minutes at a time carries the same frame,\n * breadcrumb and key legend as every other. The base class owns the chrome and\n * hands the body an exact height, which also retires the hand-rolled row\n * arithmetic that existed only to stop Pi clipping the footer.\n *\n * Key routing is the reason this is a component rather than a renderer: a\n * focused panel receives input before Pi's global dispatcher, so the view\n * controls have to be handled here or the run's TTY swallows them.\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type KeyId, matchesKey } from '@earendil-works/pi-tui';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay';\nimport { fit, fitTerminalLine } from './overlayText';\nimport { DoubleEscapeDetector } from './workflowOverlay';\n\nconst TITLE = 'WORKFLOW RUN';\nconst VIEW_ONLY = 'view only · this run is hosted natively';\nconst OUTPUT_HEADING = 'OUTPUT · newest last';\nconst WAITING = 'Waiting for output…';\n/** A divider and its heading earn their rows only when output sits beneath them. */\nconst OUTPUT_CHROME_ROWS = 2;\n\nexport interface WorkflowRunPanelSnapshot {\n /** Job tree lines, already themed by the caller. */\n progress: string[];\n /** Recent terminal output for the running step. */\n output: string[];\n}\n\nexport interface WorkflowRunPanelOptions {\n runKey: string;\n /** Full run label for the header, e.g. `name · workspace/runKey`. */\n label: string;\n breadcrumb: string;\n /** False for a natively hosted run, which has no terminal to type into. */\n interactive: boolean;\n /** Plain-sentence footer, used when the terminal cannot fit the key caps. */\n footer: string;\n /** Key legend, which differs between a typeable panel and a view. */\n hints: readonly (readonly [string, string])[];\n /** Given the body width, because the job tree is fitted as it is built. */\n snapshot: (width: number) => WorkflowRunPanelSnapshot;\n /**\n * The columns and rows the output pane can actually show, reported on each\n * paint so a launcher that supports resizing can match the run to them.\n * Called from render, so an implementation must not do the work inline: the\n * run's geometry changes out of band and the next poll picks up the reflow.\n */\n onViewport?: (columns: number, rows: number) => void;\n /** Hand typing back to the session, leaving the panel open. */\n onUnfollow: () => void;\n onClose: () => void;\n /** Forward a keystroke to the run. */\n sendInput: (data: string) => void;\n /**\n * Send whatever is buffered before the panel goes away, or the Escape that\n * closed it dies with the batcher.\n */\n flushInput: () => void;\n unfollowShortcut: KeyId;\n closeShortcut: KeyId;\n onDispose: () => void;\n}\n\nexport class WorkflowRunPanelComponent extends DoomOverlay {\n private readonly escapes = new DoubleEscapeDetector();\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n private readonly options: WorkflowRunPanelOptions,\n ) {\n super(tui, theme);\n }\n\n /**\n * The chords are matched against the whole chunk, as Pi delivers one per key\n * event. A chord buried in a coalesced burst therefore misses, which is\n * acceptable now that double-Escape guarantees an exit: scanning for the bytes\n * anywhere in a chunk would instead eat legitimate input, since `\\x1b\\x17` is\n * also a valid Escape-then-ctrl+w for the run's own editor.\n */\n handleInput(data: string): void {\n if (matchesKey(data, this.options.unfollowShortcut)) {\n this.options.onUnfollow();\n return;\n }\n if (matchesKey(data, this.options.closeShortcut)) {\n this.options.onClose();\n return;\n }\n // The failsafe. The first Escape falls through to the run, so interrupting\n // the step is as fast as it ever was; only the second one inside the window\n // is consumed.\n if (this.escapes.observe(data) === 'close') {\n this.options.flushInput();\n this.options.onClose();\n return;\n }\n this.options.sendInput(data);\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: this.options.breadcrumb,\n headerRight: this.options.interactive ? this.options.label : `${this.options.label} · ${VIEW_ONLY}`,\n footer: this.options.footer,\n footerHints: this.options.hints,\n footerRight: this.options.interactive ? 'typing goes to the run' : 'typing stays here',\n };\n }\n\n /**\n * The tree is never truncated: knowing which job is running matters more than\n * seeing another line of output, so the terminal pane absorbs whatever the\n * tree does not use.\n */\n protected renderBody(width: number, height: number): string[] {\n const { progress, output } = this.options.snapshot(width);\n const tree = progress.slice(0, height).map((line) => fit(line, width));\n\n const spare = height - tree.length;\n if (spare <= OUTPUT_CHROME_ROWS) return tree.slice(0, height);\n\n const rows = spare - OUTPUT_CHROME_ROWS;\n this.options.onViewport?.(width, rows);\n // Output keeps its own colour, so it is fitted by the escape-preserving\n // path rather than the themed-row one; see `fitTerminalLine`.\n const tail = output.slice(-rows).map((line) => fitTerminalLine(line, width));\n return [\n ...tree,\n '',\n this.theme.fg('dim', OUTPUT_HEADING),\n ...(tail.length > 0 ? tail : [this.theme.fg('dim', WAITING)]),\n ].slice(0, height);\n }\n\n dispose(): void {\n this.options.onDispose();\n }\n}\n\n/**\n * A panel whose keys cannot reach anything must never take them. Pi focuses an\n * overlay on show unless told otherwise, which for a native run would swallow\n * the user's typing into a run with no terminal to receive it.\n */\nexport function runPanelUiOptions(interactive: boolean): Record<string, unknown> {\n return {\n ...DOOM_FULLSCREEN_UI_OPTIONS,\n overlayOptions: {\n ...DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions,\n ...(interactive ? {} : { nonCapturing: true }),\n },\n };\n}\n\nexport type WorkflowRunPanelHost = Pick<ExtensionContext['ui'], 'custom'>;\n","import type { Theme } from '@earendil-works/pi-coding-agent';\nimport { Box, type Component, Text, truncateToWidth } from '@earendil-works/pi-tui';\n\nimport type { StepReport } from './workflowStatusRow';\n\nexport interface WorkflowStepMessageDetails {\n displayName: string;\n duration?: string;\n job: string;\n status: StepReport['status'];\n step: string;\n}\n\nexport function workflowStepMessageDetails(displayName: string, report: StepReport): WorkflowStepMessageDetails {\n return {\n displayName,\n job: report.job,\n status: report.status,\n step: report.step,\n ...(report.duration ? { duration: report.duration } : {}),\n };\n}\n\nexport function formatWorkflowStepMessage(details: WorkflowStepMessageDetails): string {\n const transition = details.duration\n ? `${details.status}::${details.duration}::${details.step}`\n : `${details.status}::${details.step}`;\n return `[${details.displayName}]: ${details.job}\\n${transition}`;\n}\n\nexport function isWorkflowStepMessageDetails(value: unknown): value is WorkflowStepMessageDetails {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Partial<WorkflowStepMessageDetails>;\n return (\n typeof candidate.displayName === 'string' &&\n typeof candidate.job === 'string' &&\n typeof candidate.step === 'string' &&\n (candidate.status === 'STARTED' || candidate.status === 'FINISHED' || candidate.status === 'FAILED') &&\n (candidate.duration === undefined || typeof candidate.duration === 'string')\n );\n}\n\nclass WorkflowStepMessageLines implements Component {\n constructor(\n private readonly details: WorkflowStepMessageDetails,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n const header = `${this.theme.fg('accent', `[${this.details.displayName}]:`)} ${this.details.job}`;\n const transition = this.details.duration\n ? `${this.details.status}::${this.details.duration}::${this.details.step}`\n : `${this.details.status}::${this.details.step}`;\n const colour =\n this.details.status === 'FAILED' ? 'error' : this.details.status === 'FINISHED' ? 'success' : 'accent';\n return [truncateToWidth(header, width), truncateToWidth(this.theme.fg(colour, transition), width)];\n }\n\n invalidate(): void {}\n}\n\nexport function renderWorkflowStepMessage(\n details: WorkflowStepMessageDetails | undefined,\n fallback: string,\n outputPad: number,\n theme: Theme,\n): Component {\n const box = new Box(outputPad, 1, (text) => theme.bg('customMessageBg', text));\n box.addChild(details ? new WorkflowStepMessageLines(details, theme) : new Text(fallback, 0, 0));\n return box;\n}\n","import { spawn } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { basename, extname, resolve } from 'node:path';\n\nimport { resolveRootSessionId, SUBAGENT_ROOT_SESSION_ENV } from '@agimon-ai/doompi-core/childProcess';\nimport {\n createNarrationRequest,\n DOOM_NARRATION_SERVICE,\n type DoomNarrationService,\n requireDoomNarrationService,\n} from '@agimon-ai/doompi-core/narration';\nimport type { PiPluginContributions, PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n type DoomReadinessHandle,\n type DoomReadinessNotification,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-core/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport { piMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport {\n defineMinorMode,\n type MinorModeOwner,\n type MinorModeOwnerActionContext,\n type MinorModeState,\n} from '@agimon-ai/doompi-minor-mode';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport {\n createEmbeddedWorkflowFeature,\n type EmbeddedWorkflowFeature,\n readWorkflowProgress,\n summarizeWorkflowProgress,\n type Workflow,\n type WorkflowProgressEvent,\n type WorkflowProgressJob,\n type WorkflowRunControl,\n type WorkflowRunRecord,\n type WorkflowStage,\n WorkflowTerminalService,\n} from '@agimon-ai/workflow-mcp';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { type OverlayHandle, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_CATALOG_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../constants/workflow';\nimport { type RunProviderHandle, registerRunProvider } from '../services/backgroundWork';\nimport {\n finishedRunSummary,\n isSessionRun,\n launchNotice,\n runsForSession,\n toolResultText,\n withOptions,\n} from '../services/piToolBridge';\nimport {\n createWorkflowLaunchExecutor,\n type WorkflowPiToolDependencies,\n workflowToolRestriction,\n type WorkflowLaunchExecutor,\n type WorkflowLaunchInput,\n} from '../services/workflowExecution';\nimport {\n isLaunchParseFailure,\n parseWorkflowLaunchCommand,\n resolveWorkflowEntry,\n validateWorkflowLaunch,\n} from '../services/workflowLaunchCommand';\nimport {\n launchWorkflowEntry,\n loadWorkflowCatalog,\n summarizeWorkflowFile,\n type WorkflowLauncherUi,\n} from '../services/workflowLauncher';\nimport { narrateWorkflowTransition, type WorkflowNarrationSink } from '../services/workflowNarration';\nimport { workflowSkillDirectory } from '../services/workflowResource';\nimport { createWorkflowTerminalService } from '../services/workflowTerminal';\nimport { openWorkflowCatalogOverlay } from './workflow/workflowCatalog';\nimport {\n createWorkflowFinishedRenderer,\n type WorkflowFinishedRun,\n WORKFLOW_FINISHED_MESSAGE,\n} from './workflow/workflowFinishedMessage';\nimport { WorkflowInspectorComponent, type WorkflowInspectorSelection } from './workflow/workflowInspector';\nimport { TerminalInputBatcher } from './workflow/workflowOverlay';\nimport { openWorkflowPickerOverlay } from './workflow/workflowPicker';\nimport { WorkflowProgressOverlay, workflowProgressRow } from './workflow/workflowProgressOverlay';\nimport { openWorkflowChoice, openWorkflowInput } from './workflow/workflowPrompt';\nimport { runPanelUiOptions, WorkflowRunPanelComponent } from './workflow/workflowRunPanel';\nimport { isWorkflowStepMessageDetails, renderWorkflowStepMessage } from './workflow/workflowStepMessage';\n\nconst DOOM_FULLSCREEN_UI_OPTIONS = {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n} as const;\n\n/** A run panel currently on screen, and how to take it down. */\ninterface ActiveOverlay {\n handle?: OverlayHandle;\n /**\n * Whether keys typed at this panel can reach the run.\n *\n * False for a natively hosted run, which has no multiplexer to address. Such\n * a panel is opened without focus and must never be given it: typing into it\n * would go nowhere at all.\n */\n interactive: boolean;\n runKey: string;\n teardown: () => void;\n}\n\n/** Renderer retained for step cards already persisted by older package versions. */\nconst LEGACY_WORKFLOW_STEP_MESSAGE = 'workflow-step';\nconst FOLLOW_WIDGET_KEY = 'workflow-mcp-follow';\nconst MODE_ID = 'workflow';\nconst MODE_LABEL = 'Workflow';\nconst MODE_LABEL_STYLE = 'accent';\nconst MODE_ORDER = 20;\nconst MODE_ACTION_ACTIVATE = 'activate';\nconst MODE_ACTION_DEACTIVATE = 'deactivate';\n\nfunction workflowModeState(active: boolean, runCount: number): MinorModeState {\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: runCount > 0 ? `${runCount} active runs` : 'tools enabled', color: MODE_LABEL_STYLE } : {}),\n actions: [\n ...(active\n ? [{ id: MODE_ACTION_ACTIVATE, enabled: false, disabledReason: 'Workflow mode is active.' } as const]\n : [{ id: MODE_ACTION_ACTIVATE, enabled: true } as const]),\n ...(active\n ? [{ id: MODE_ACTION_DEACTIVATE, enabled: true } as const]\n : [{ id: MODE_ACTION_DEACTIVATE, enabled: false, disabledReason: 'Workflow mode is inactive.' } as const]),\n ],\n };\n}\n\nconst LEADER_MODE_BREADCRUMB = 'SPC w e';\nconst CATALOG_BREADCRUMB = 'SPC › w / workflows › l / list';\nconst MANAGE_BREADCRUMB = 'SPC › w / workflows › r / runs';\nconst RECOVER_BREADCRUMB = 'SPC › w / workflows › c / recover';\nconst RUN_PANEL_BREADCRUMB = 'SPC › w / workflows › run';\nconst PAUSED_EXECUTION_STATE = 'paused';\n\nconst UNFOLLOW_SHORTCUT = 'ctrl+alt+w';\n/**\n * Dismisses the run panel.\n *\n * Separate from the focus toggle because a focused panel hands every key to the\n * run, Escape included, so a plain \"Escape closes an overlay\" is unavailable:\n * interrupting the agent inside a step is worth more than a close key. Folding\n * closing into the focus toggle instead would leave an unfocused panel with no\n * way back to typing into the run.\n *\n * Not the only way out. This chord relies on a modifier some terminals do not\n * transmit, so `DoubleEscapeDetector` backs it with a plain double-Escape that\n * every terminal can send.\n */\nconst CLOSE_OVERLAY_SHORTCUT = 'ctrl+alt+q';\n\n/** Modifier glyphs macOS users read on their own keyboards and in every menu. */\nconst MAC_MODIFIER_GLYPHS: Record<string, string> = {\n alt: '⌥',\n cmd: '⌘',\n ctrl: '⌃',\n meta: '⌘',\n shift: '⇧',\n};\n\n/**\n * Render a binding the way the user's own platform writes it.\n *\n * The binding string Pi registers stays canonical (`ctrl+alt+w`) on every\n * platform; only the label changes. A macOS user reading \"alt\" has to translate\n * it to the Option key they actually press, and the modifier is not even\n * labelled \"alt\" on most Apple keyboards.\n *\n * Pi branches on `process.platform` for its own keybindings, so this follows a\n * convention already in the host rather than inventing one.\n */\nexport function shortcutLabel(binding: string, platform: NodeJS.Platform = process.platform): string {\n const parts = binding.split('+');\n if (platform === 'darwin') {\n // Glyphs join without separators, as they do in a macOS menu: ⌃⌥W.\n return parts.map((part) => MAC_MODIFIER_GLYPHS[part] ?? part.toUpperCase()).join('');\n }\n return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('+');\n}\nconst DEFAULT_PAGE_SIZE = 100;\n/**\n * The reconcile sweep, which is a fallback rather than the mechanism.\n *\n * The observer reports a change as it happens, so this only bounds how long a\n * change nothing notified us about stays invisible. It was 5s when it was the\n * only way anything was noticed.\n */\nconst MONITOR_INTERVAL_MS = 30_000;\n/**\n * Coalescing window for event-driven status refreshes.\n *\n * A run emits several transitions at once, and each one would otherwise page\n * the registry for the authoritative lifecycle snapshot. One page per burst.\n */\nconst STATUS_REFRESH_DEBOUNCE_MS = 120;\nconst PI_EXEC_TIMEOUT_MS = 10_000;\nconst RECOVERY_EVIDENCE_MAX_BYTES = 64 * 1024;\nconst RUNNING_STATUS = 'running';\nconst COMPLETED_STATUS = 'completed';\nconst FAILED_STATUS = 'failed';\nconst ERROR_STAGE = 'error';\nconst ERROR_COLOUR = 'error';\n/**\n * How long shutdown waits for an interrupted inline run to finalize its record.\n *\n * Long enough for a step that honours SIGTERM to unwind and for the registry\n * write that follows, short enough that a step ignoring it does not strand the\n * user in a session that will not close.\n */\nconst SHUTDOWN_FINALIZE_TIMEOUT_MS = 10_000;\nconst FOLLOW_INTERVAL_MS = 2_000;\nconst TAIL_LINES = 24;\n/** Below these a resized run has no room left to draw, so it keeps its own size and the panel clips. */\n/**\n * Overlay refresh cadence and size.\n *\n * Faster than the background widget's 2s: a foregrounded terminal that lags\n * behind your own typing reads as broken, and only the one run being watched\n * pays for it.\n */\nconst OVERLAY_REFRESH_MS = 200;\n/**\n * Slowest part of a refresh, given its own cadence.\n *\n * Reading a run's screen means forking `tmux capture-pane` or `cmux read-screen`,\n * measured at ~75ms. Repainting at 200ms is right for a panel; forking at 200ms\n * is not, so the two are decoupled and only the render keeps the fast tick. A\n * terminal tail is a rolling window of the last few seconds either way, so the\n * slower read costs the reader nothing they can perceive.\n */\nconst SCREEN_REFRESH_MS = 750;\n/**\n * How many recent run announcements the launch handshake can look back through.\n *\n * Only ever searched for a run that registered within the acknowledgement\n * window, so this needs to cover concurrent launches, not session history. The\n * per-session concurrency ceiling is five.\n */\nconst ANNOUNCED_RUN_HISTORY = 32;\n/**\n * Telemetry name for a launch being asked for.\n *\n * Named once because both launch paths, the wizard and the tool, report it and\n * a query that spans them only works while the two agree.\n */\nconst LAUNCH_REQUESTED_EVENT = 'doom_workflow.launch_requested';\n/**\n * Recovery skill shipped by this package, offered to Pi at resource discovery.\n *\n * Recovery is the one path here complex enough to deserve a real skill rather\n * than a few tool guidelines, and this package owns that domain: it cannot\n * assume the host repository provides one. Discovery is cheap, since Pi puts\n * only the name, description, and location in the system prompt and reads the\n * body on demand.\n *\n * Resolved from the module directory, not the module file: `resolve` treats a\n * trailing filename as a path segment. Both `src/extensions` and\n * `dist/extensions` sit two levels below the package root.\n */\n\n/**\n * Glyphs for widgets, panels, and notices.\n *\n * Deliberately restricted to characters that render in a default terminal font.\n * A box-drawing or emoji glyph that falls back to tofu is worse than no glyph.\n */\nconst GLYPH = {\n running: '▸',\n repair: '⚠',\n completed: '✔',\n failed: '✖',\n separator: '·',\n} as const;\n\n/**\n * The panel's footer: how to leave, in the order a stuck user needs it.\n *\n * Escape leads on an interactive panel because it is the key every terminal\n * transmits, and the one someone reaches for first when a view will not let go.\n * A view-only panel says so instead: a user who does not know the run is\n * unreachable reads the silence as the panel being broken.\n */\nexport function panelHint(interactive: boolean, platform: NodeJS.Platform = process.platform): string {\n const close = shortcutLabel(CLOSE_OVERLAY_SHORTCUT, platform);\n if (!interactive) return `view only ${GLYPH.separator} ${close} closes this view`;\n return [\n 'Esc Esc closes this view',\n `${shortcutLabel(UNFOLLOW_SHORTCUT, platform)} switches typing`,\n `${close} closes`,\n ].join(` ${GLYPH.separator} `);\n}\n\n/** The same hints as key caps, for the doom footer legend. */\nexport function panelHints(\n interactive: boolean,\n platform: NodeJS.Platform = process.platform,\n): readonly (readonly [string, string])[] {\n const close: readonly [string, string] = [shortcutLabel(CLOSE_OVERLAY_SHORTCUT, platform), 'close'];\n if (!interactive) return [close];\n // Leads the legend, and spelled as the copy says it: this cap is the escape\n // hatch, and the chords beside it ride on a modifier some terminals never send.\n return [['Esc Esc', 'close'], [shortcutLabel(UNFOLLOW_SHORTCUT, platform), 'switch typing'], close];\n}\n\n/**\n * Header and output lines for the follow widget, fitted to the terminal.\n *\n * Every line a component renders must fit the given width, so the header sheds\n * detail right to left as the terminal narrows: the dismissal hint goes first,\n * then the workspace/stage context, and the run key survives longest because it\n * is the identifier the user needs to name the run.\n *\n * Colour is applied after fitting. Measuring plain text and styling afterwards\n * keeps the arithmetic honest, since escape codes occupy no visible columns.\n */\nfunction renderFollowLines(record: WorkflowRunRecord, output: string[], theme: Theme, width: number): string[] {\n const key = `${GLYPH.running} ${record.runKey}`;\n const meta = [record.workspace, stageLabel(record), record.runner].filter(Boolean).join(` ${GLYPH.separator} `);\n const hint = `${shortcutLabel(UNFOLLOW_SHORTCUT)} to background`;\n const gap = ' ';\n\n let header = theme.fg('accent', truncateToWidth(key, width));\n if (visibleWidth(key) + gap.length + visibleWidth(meta) <= width) {\n header += gap + theme.fg('muted', meta);\n const used = visibleWidth(key) + gap.length + visibleWidth(meta);\n if (used + gap.length + visibleWidth(hint) <= width) header += gap + theme.fg('dim', hint);\n }\n\n return [header, ...output.map((line) => truncateToWidth(line, width))];\n}\n\n/**\n * Job tree for the follow widget, in the shape a CI run reads best.\n *\n * Finished jobs collapse to a single line so the eye lands on the one still\n * running, whose steps are listed. That is the whole reason this exists: a\n * scraped terminal shows whatever the runner last printed, which is not the\n * same as knowing which job of how many is in flight.\n */\nfunction renderProgressLines(jobs: WorkflowProgressJob[], theme: Theme, width: number): string[] {\n const lines: string[] = [];\n for (const job of jobs) {\n const glyph =\n job.status === COMPLETED_STATUS ? GLYPH.completed : job.status === FAILED_STATUS ? GLYPH.failed : GLYPH.running;\n const colour = job.status === COMPLETED_STATUS ? 'success' : job.status === FAILED_STATUS ? ERROR_COLOUR : 'accent';\n const position = job.total ? ` ${GLYPH.separator} ${(job.index ?? 0) + 1}/${job.total}` : '';\n lines.push(truncateToWidth(theme.fg(colour, `${glyph} ${job.name}`) + theme.fg('dim', position), width));\n\n // Only the job in flight expands. A finished job's steps are noise.\n if (job.status !== RUNNING_STATUS) continue;\n for (const step of job.steps) {\n const stepGlyph =\n step.status === COMPLETED_STATUS\n ? GLYPH.completed\n : step.status === FAILED_STATUS\n ? GLYPH.failed\n : GLYPH.running;\n const stepColour =\n step.status === RUNNING_STATUS ? 'muted' : step.status === FAILED_STATUS ? ERROR_COLOUR : 'dim';\n lines.push(truncateToWidth(theme.fg(stepColour, ` ${stepGlyph} ${step.name}`), width));\n }\n }\n return lines;\n}\n\nfunction progressEventsForRun(record: WorkflowRunRecord, events: WorkflowProgressEvent[]): WorkflowProgressEvent[] {\n const startedAt = Date.parse(record.startedAt);\n if (!Number.isFinite(startedAt)) return events;\n return events.filter((event) => {\n const eventAt = Date.parse(event.at);\n return !Number.isFinite(eventAt) || eventAt >= startedAt;\n });\n}\n\n/** Human-readable stage, rather than leaking the raw registry enum. */\nfunction stageLabel(record: WorkflowRunRecord): string {\n if (record.stale) return 'stale';\n if (record.stage === ERROR_STAGE) return FAILED_STATUS;\n return record.stage;\n}\n\ninterface ParsedArguments {\n invalidLauncher?: string;\n launcher?: MultiplexerLauncher;\n name?: string;\n positionals: string[];\n runner?: string;\n workspace?: string;\n}\n\n/** Spawn a launcher and forget it, which is all a delegated run needs from us. */\nexport type DetachedSpawn = (\n command: string,\n args: readonly string[],\n options: { cwd: string; env: NodeJS.ProcessEnv },\n) => Promise<void>;\n\nexport interface WorkflowPiExtensionOptions {\n /** Captured environment used for session lineage and external child processes. */\n readonly environment: Readonly<Record<string, string | undefined>>;\n /** Package plugin context used to resolve session-scoped Cordis services. */\n cordis?: Context;\n followIntervalMs?: number;\n monitorIntervalMs?: number;\n /** Initial session mode, used by the non-interactive dispatcher composition. */\n initialMode?: boolean;\n /** Told about every mode change, so the leader menu can offer the way out rather than the way in. */\n onModeChange?: (enabled: boolean) => void;\n featureFactory?: () => EmbeddedWorkflowFeature;\n /** Reject work inherited from a stale session or disposed package root. */\n isActive?: () => boolean;\n runCleanup?: <T>(operation: () => T) => T;\n /** Injected so a test can read the delegated command without running it. */\n spawnDetached?: DetachedSpawn;\n launchAckPollMs?: number;\n launchAckTimeoutMs?: number;\n}\n\nexport interface WorkflowPiRuntime extends Pick<\n PiPluginContributions,\n 'events' | 'shortcuts' | 'messageRenderers' | 'services' | 'toolRestrictions'\n> {\n readonly commands: readonly (readonly [...Parameters<ExtensionAPI['registerCommand']>])[];\n readonly toolDependencies: WorkflowPiToolDependencies;\n waitForReadiness(signal?: AbortSignal): Promise<void>;\n dispose(context?: ExtensionContext): Promise<void>;\n}\n\n/**\n * Multiplexer identity of THIS process, which a launcher spawn must not carry.\n *\n * A child that inherits it records Pi's own workspace as the run's launcher, so\n * every later `open` or `tail` would foreground or scrape this session's screen\n * instead of the run's. The status file is per-step and equally non-inheritable.\n */\nconst CMUX_WORKSPACE_ID_ENV = 'CMUX_WORKSPACE_ID';\nconst TMUX_PANE_ENV = 'TMUX_PANE';\nconst WORKFLOW_TMUX_SESSION_NAME_ENV = 'WORKFLOW_TMUX_SESSION_NAME';\nconst LAUNCHER_ENVIRONMENT_STRIPPED = [\n 'CMUX_SURFACE_ID',\n SUBAGENT_ROOT_SESSION_ENV,\n CMUX_WORKSPACE_ID_ENV,\n TMUX_PANE_ENV,\n 'WORKFLOW_LAUNCHER_TYPE',\n WORKFLOW_TMUX_SESSION_NAME_ENV,\n 'WORKFLOW_STATUS_FILE',\n] as const;\n\n/**\n * Slack between this process's clock and the run record's timestamp.\n *\n * The record is written by another process, and a launch acknowledged a\n * fraction of a second \"before\" it began is a clock difference, not somebody\n * else's run.\n */\nconst LAUNCH_ACK_CLOCK_SKEW_MS = 2_000;\n\nconst LAUNCHER_ENV = 'WORKFLOW_LAUNCHER';\nconst RECOVER_COMMAND = 'recover-workflow';\nconst LAUNCH_PROCESS_COMMAND = 'launch-process';\n\n/**\n * How a run is hosted, which is also the name of the binary that addresses it.\n *\n * One token per launcher rather than two, because they are the same token: a\n * record's `launcher.type` is `tmux` precisely because tmux is what hosts it and\n * `tmux` is what reads it back. `native` has no binary, which is exactly why\n * every surface has to branch on it.\n */\nconst LAUNCHER_TMUX = 'tmux';\nconst LAUNCHER_CMUX = 'cmux';\nconst LAUNCHER_NATIVE = 'native';\n/** The cmux socket method that answers with a styled render grid rather than plain text. */\n/** The verb the cockpit's launch dialog sends; the leader board does the same work. */\nconst WORKFLOW_LAUNCH_COMMAND = 'workflow-launch';\ntype MultiplexerLauncher = typeof LAUNCHER_TMUX | typeof LAUNCHER_CMUX;\n\nconst HOST_TERMINAL_OUTPUT_BLOCKED =\n \"This run points at Pi's own terminal, so its launcher screen is hidden. Use workflow status instead.\";\n\n/**\n * Whether stale or inherited launcher metadata addresses this Pi process.\n *\n * Reading such a target recursively captures the chat into its own widget;\n * opening or sending to it can foreground or type into Pi itself. New embedded\n * runs record `native`, but this guard also makes older records safe.\n */\n/**\n * A run with no recorded launcher, which reading and foregrounding both hit.\n *\n * Older records predate launcher identity being persisted, so this is a real\n * state rather than a corrupt one, and both surfaces owe the user the same\n * explanation for it.\n */\nconst NO_LAUNCHER_RECORDED = 'No durable launcher identity is recorded for this run.';\n\n/**\n * The identifier a run record carries for its definition.\n *\n * Derived the same way `RunWorkflowService` derives it, so the two agree: the\n * file name without its final extension, which keeps the `.workflow` part.\n */\nfunction workflowIdFor(workflowPath: string): string {\n return basename(workflowPath, extname(workflowPath));\n}\n\nfunction launcherEnvironment(environment: Readonly<Record<string, string | undefined>>): NodeJS.ProcessEnv {\n const env = { ...environment };\n for (const key of LAUNCHER_ENVIRONMENT_STRIPPED) delete env[key];\n return env;\n}\n\n/** The launcher the workflow templates default to, when it is a known one. */\nfunction preferredLauncher(environment: Readonly<Record<string, string | undefined>>): MultiplexerLauncher | undefined {\n const value = environment[LAUNCHER_ENV];\n return value === LAUNCHER_TMUX || value === LAUNCHER_CMUX ? value : undefined;\n}\n\n/**\n * One shell word per argument.\n *\n * `launch-process` hands `--command` to the launcher as a shell string, so a\n * run key or a path with a space in it has to survive one more round of shell\n * parsing than the argv we spawn with.\n */\nfunction shellCommand(argv: readonly string[]): string {\n return argv.map((word) => `'${word.replaceAll(\"'\", `'\\\\''`)}'`).join(' ');\n}\n\n/**\n * The workflow-mcp CLI this extension is built against.\n *\n * Resolved from the dependency rather than PATH: `pnpm exec workflow-mcp` finds\n * whatever the workspace root happens to install, which is not necessarily this\n * version, and it pays for a package-manager resolution on the launch path.\n */\nfunction resolveWorkflowCli(): string | undefined {\n try {\n return createRequire(import.meta.url).resolve('@agimon-ai/workflow-mcp/cli');\n } catch {\n return undefined;\n }\n}\n\nconst detachedSpawn: DetachedSpawn = async (command, args, options) => {\n // Detached with no stdio: the run owns a launcher terminal of its own, and\n // anything inherited from here would be written onto Pi's screen. Wait only\n // for spawn/error so an immediate exec failure releases the recovery claim.\n await new Promise<void>((resolveSpawn, rejectSpawn) => {\n const child = spawn(command, [...args], { ...options, detached: true, stdio: 'ignore' });\n child.once('error', rejectSpawn);\n child.once('spawn', () => {\n child.off('error', rejectSpawn);\n child.unref();\n resolveSpawn();\n });\n });\n};\n\nfunction tokenize(value: string): string[] {\n return (\n value.match(/\"[^\"]*\"|'[^']*'|\\S+/g)?.map((token) => {\n if ((token.startsWith('\"') && token.endsWith('\"')) || (token.startsWith(\"'\") && token.endsWith(\"'\"))) {\n return token.slice(1, -1);\n }\n return token;\n }) ?? []\n );\n}\n\nexport function parseWorkflowCommandArguments(value: string): ParsedArguments {\n const tokens = tokenize(value);\n const parsed: ParsedArguments = { positionals: [] };\n for (let index = 0; index < tokens.length; index += 1) {\n const token = tokens[index];\n const next = tokens[index + 1];\n if (token === '--launcher' && next) {\n if (next === LAUNCHER_CMUX || next === LAUNCHER_TMUX) parsed.launcher = next;\n else parsed.invalidLauncher = next;\n index += 1;\n } else if (token === '--runner' && next) {\n parsed.runner = next;\n index += 1;\n } else if (token === '--workspace' && next) {\n parsed.workspace = next;\n index += 1;\n } else if (token === '--name' && next) {\n parsed.name = next;\n index += 1;\n } else {\n parsed.positionals.push(token);\n }\n }\n return parsed;\n}\n\nfunction collectRunnerMaps(value: unknown, maps: string[][]): void {\n if (Array.isArray(value)) {\n for (const item of value) collectRunnerMaps(item, maps);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, nested] of Object.entries(value)) {\n if ((key === 'interactiveRun' || key === 'run') && nested && typeof nested === 'object' && !Array.isArray(nested)) {\n maps.push(Object.keys(nested));\n } else {\n collectRunnerMaps(nested, maps);\n }\n }\n}\n\nexport function compatibleRunners(workflow: Workflow): string[] | undefined {\n const maps: string[][] = [];\n collectRunnerMaps(workflow, maps);\n if (maps.length === 0) return undefined;\n return maps[0].filter((runner) => maps.every((available) => available.includes(runner))).sort();\n}\n\nasync function listAllRuns(\n registry: EmbeddedWorkflowFeature['registry'],\n workspace?: string,\n): Promise<WorkflowRunRecord[]> {\n const records: WorkflowRunRecord[] = [];\n let page = 1;\n let hasNextPage = true;\n while (hasNextPage) {\n const result = await registry.listRunsPage({ page, pageSize: DEFAULT_PAGE_SIZE, workspace });\n records.push(...result.items);\n hasNextPage = result.hasNextPage;\n page += 1;\n }\n return records;\n}\n\n/**\n * One run, as a person reads it.\n *\n * Middle dots rather than pipes: pipes read as table borders in a terminal and\n * collide visually with the launcher output the widget sits above.\n */\nfunction runLabel(record: WorkflowRunRecord): string {\n return [record.runKey, record.workspace, stageLabel(record), record.runner]\n .filter(Boolean)\n .join(` ${GLYPH.separator} `);\n}\n\nexport function createWorkflowPiRuntime(pi: ExtensionAPI, options: WorkflowPiExtensionOptions): WorkflowPiRuntime {\n const services: NonNullable<PiPluginContributions['services']>[number][] = [];\n const feature = options.featureFactory?.() ?? createEmbeddedWorkflowFeature();\n const runtimeGeneration = randomUUID();\n let runtimeActive = true;\n let sessionGeneration = 0;\n let readinessAbort: AbortController | undefined;\n let readinessHandle: Promise<DoomReadinessHandle<void>> | undefined;\n let standaloneReadiness: DoomReadinessCoordinator | undefined;\n const invocationActive = options.isActive ?? (() => true);\n const isRuntimeActive = (): boolean => runtimeActive && invocationActive();\n const notifyStandaloneReadiness = (notification: DoomReadinessNotification): void => {\n const diagnostics = notification.diagnostics.join('; ');\n const detail = (notification.error?.message ?? diagnostics) || 'Initialization did not complete.';\n const message = `${notification.packageId} initialization ${notification.state}: ${detail}`;\n if (sessionCtx?.hasUI) sessionCtx.ui.notify(message, 'warning');\n else process.emitWarning(message);\n };\n const readinessCoordinator = (_ctx: ExtensionContext): DoomReadinessCoordinator => {\n const shared = options.cordis ? readDoomReadinessCoordinator(options.cordis) : undefined;\n if (shared) return shared;\n standaloneReadiness ??= createDoomReadinessCoordinator({ notify: notifyStandaloneReadiness });\n return standaloneReadiness;\n };\n const waitForReadiness = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n const pending = readinessHandle;\n if (!pending) throw new Error('Workflow session initialization has not started.');\n const handle = await pending;\n signal?.throwIfAborted();\n await handle.wait(signal ? { signal } : undefined);\n if (!isRuntimeActive() || pending !== readinessHandle) {\n throw new Error('Workflow readiness belongs to a stale extension generation.');\n }\n };\n const { parser, recoverService, registry, runService, runTool } = feature;\n const spawnDetached = options.spawnDetached ?? detachedSpawn;\n const monitorIntervalMs = options.monitorIntervalMs ?? MONITOR_INTERVAL_MS;\n const followIntervalMs = options.followIntervalMs ?? FOLLOW_INTERVAL_MS;\n let monitorTimer: NodeJS.Timeout | undefined;\n let monitorRefreshGeneration: number | undefined;\n let followTimer: NodeJS.Timeout | undefined;\n let followRefreshActive = false;\n let followedRun: WorkflowRunRecord | undefined;\n let previousStages = new Map<string, WorkflowStage>();\n const pendingTerminalRuns = new Map<string, WorkflowRunRecord>();\n const deliveredTerminalRuns = new Set<string>();\n let sessionStartedAt = 0;\n let runProvider: RunProviderHandle | undefined;\n services.push((context: Context) => {\n runProvider = registerRunProvider(context);\n });\n let lifecycleNarrationReady = false;\n let sessionRunCount = 0;\n let workflowMode = false;\n let publishedWorkflowState: string | undefined;\n const restrictionListeners = new Set<() => void>();\n const modeContribution: MinorModeOwner<MinorModeOwnerActionContext<ExtensionContext>> = defineMinorMode<\n undefined,\n MinorModeOwnerActionContext<ExtensionContext>\n >({\n descriptor: {\n source: PACKAGE_SOURCE,\n id: MODE_ID,\n label: MODE_LABEL,\n description: 'Workflow discovery, launch, inspection, control, and recovery tools.',\n order: MODE_ORDER,\n actions: [\n {\n id: MODE_ACTION_ACTIVATE,\n label: 'Activate',\n description: 'Enable workflow tools for this session.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n {\n id: MODE_ACTION_DEACTIVATE,\n label: 'Deactivate',\n description: 'Disable workflow tools without stopping active runs.',\n contexts: ['tui', 'headless'],\n parameters: [],\n },\n ],\n },\n state: () => workflowModeState(workflowMode, sessionRunCount),\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n await waitForReadiness();\n if (actionId === MODE_ACTION_ACTIVATE) {\n await applyWorkflowMode(true, execution.context);\n return { message: 'Workflow mode activated.' };\n }\n if (actionId === MODE_ACTION_DEACTIVATE) {\n await applyWorkflowMode(false, execution.context);\n return { message: 'Workflow mode deactivated.' };\n }\n throw new Error(`Unknown workflow mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n /** Kept so callers outside a handler can still resolve the session id. */\n let sessionCtx: ExtensionContext | undefined;\n let activeOverlay: ActiveOverlay | undefined;\n let inspectorHandle: OverlayHandle | undefined;\n let inspectorOpen = false;\n /** The runs the inspector last listed, keyed the way its items are. */\n let inspectorRecords = new Map<string, WorkflowRunRecord>();\n /**\n * The pushed view of runs this session owns.\n *\n * A delegated run executes in a launcher's process, so nothing in here ever\n * observes it directly. What it observes is the registry the run writes to,\n * which is why this replaces polling rather than instrumenting anything.\n */\n let runControl: WorkflowRunControl | undefined;\n const disposeRunControl = new Set<() => void>();\n /**\n * Job and step transitions per run, accumulated from pushed events.\n *\n * The live list derives its current position from this stream and a failed\n * run reuses the same events for its terminal summary. Released after that\n * summary is delivered.\n */\n const runEvents = new Map<string, WorkflowProgressEvent[]>();\n /**\n * Runs the observer has announced, newest first, for the launch handshake.\n *\n * A launch needs the run key of the run it just started, and the launcher\n * process never learns it. Bounded, because a session that launches all day\n * must not accumulate a record per launch for the sake of a lookup that\n * only ever cares about the last few seconds.\n */\n const announcedRuns: WorkflowRunRecord[] = [];\n /** Active records are the authoritative membership of the task-like progress widget. */\n const activeRunRecords = new Map<string, WorkflowRunRecord>();\n /** Invalidates a registry snapshot when a newer pushed lifecycle event lands mid-read. */\n let activeRunRevision = 0;\n const progressOverlay = new WorkflowProgressOverlay();\n\n /**\n * The session that owns this extension's runs.\n *\n * Taken from whatever context Pi hands us, and deliberately the SAME value\n * `launch_workflow` stamps onto a run: reading the stamp from one place and\n * the filter from another is how a run goes invisible to the session that\n * just started it. `session_start` fills this in for a session that has\n * launched nothing yet; before either, it is undefined and every ownership\n * check fails closed, which is correct because such a session owns no runs.\n */\n let knownSessionId: string | undefined;\n let telemetry: DoomTelemetry | undefined;\n const getTelemetry = (ctx?: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-workflow',\n packageName: '@agimon-ai/doompi-workflow',\n cwd: ctx?.cwd,\n env: options.environment,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n let narrationService: DoomNarrationService | undefined;\n const reportNarrationFailure = (error: unknown): void => {\n void getTelemetry(sessionCtx)\n .recordWarning('doom_workflow.narration_failed', error)\n .catch((telemetryError: unknown) => {\n process.emitWarning(`Doom-workflow could not record a narration failure: ${String(telemetryError)}`);\n });\n };\n const narrationSink: WorkflowNarrationSink = {\n narrate(text) {\n const service = narrationService;\n const request = createNarrationRequest(text);\n if (!service || !request) return;\n try {\n void Promise.resolve(service.request(request)).catch(reportNarrationFailure);\n } catch (error) {\n reportNarrationFailure(error);\n }\n },\n };\n services.push((cordis: Context) => {\n cordis.inject([DOOM_NARRATION_SERVICE], (serviceContext) => {\n const service = requireDoomNarrationService(serviceContext);\n narrationService = service;\n return () => {\n if (narrationService === service) narrationService = undefined;\n };\n });\n });\n const observeSession = (sessionId: string | undefined): void => {\n if (sessionId && isRuntimeActive()) knownSessionId = resolveRootSessionId(sessionId, options.environment);\n };\n const currentSessionId = (): string | undefined => {\n const sessionId = knownSessionId ?? sessionCtx?.sessionManager.getSessionId();\n return sessionId ? resolveRootSessionId(sessionId, options.environment) : undefined;\n };\n const isRootProcess = (ctx: ExtensionContext, rootSessionId: string): boolean =>\n ctx.sessionManager.getSessionId().trim() === rootSessionId;\n\n /**\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so an unscoped tool would let any session\n * list, foreground, stop, or recover any other session's runs. Scoping is a\n * host-level filter on the tool instance, not a caller input: the agent\n * cannot opt out of it, and the CLI (which is how orphaned runs are managed)\n * keeps the global view.\n */\n const recoverTool = feature.createRecoverTool({\n // Ownership follows the recovering session. The host supplies identity\n // out of band; the tool schema cannot choose or override it.\n ownerSessionId: currentSessionId,\n });\n const controlTool = feature.createControlTool();\n\n /**\n * Inline executions still in flight, so shutdown can finalize them.\n *\n * A workflow declaring `launch-command` hands off to tmux or cmux and its\n * promise settles almost immediately; one without runs its whole engine in\n * this process. Only the latter lingers here, so the set needs no launcher\n * check of its own.\n */\n const pendingInlineRuns = new Set<Promise<unknown>>();\n const trackPendingRun = <T>(run: Promise<T>): Promise<T> => {\n const startedAt = Date.now();\n const runTelemetry = getTelemetry();\n pendingInlineRuns.add(run);\n void runTelemetry.recordEvent('doom_workflow.run_started', { outcome: 'started' });\n // Bookkeeping and telemetry share one handler pair on purpose. A separate\n // `finally` derives a promise that rejects with nobody watching, and an\n // unhandled rejection ends the process, TUI included. Since a launch is\n // answered from the registry, nothing else is necessarily awaiting this\n // run by the time it fails, so this pair is the only thing standing\n // between a failed launcher and a dead session.\n void run.then(\n () => {\n pendingInlineRuns.delete(run);\n return runTelemetry.recordEvent('doom_workflow.run_finished', {\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n },\n (error: unknown) => {\n pendingInlineRuns.delete(run);\n return runTelemetry.recordError('doom_workflow.run_failed', error, {\n duration_ms: Date.now() - startedAt,\n });\n },\n );\n return run;\n };\n\n const rejectRunner = (workflowPath: string, runner: string): string | undefined => {\n const compatible = compatibleRunners(parser.parseWorkflowFile(workflowPath));\n if (!compatible || compatible.includes(runner)) return undefined;\n return `Runner ${JSON.stringify(runner)} is not available across this workflow. Compatible runners: ${compatible.join(', ') || 'none'}.`;\n };\n\n const launchExecutor: WorkflowLaunchExecutor = createWorkflowLaunchExecutor({\n environment: options.environment,\n activeRunCount: async () => sessionRunCount,\n observeSession,\n rejectRunner,\n runTool,\n trackPendingRun,\n ...(options.launchAckPollMs === undefined ? {} : { launchAckPollMs: options.launchAckPollMs }),\n ...(options.launchAckTimeoutMs === undefined ? {} : { launchAckTimeoutMs: options.launchAckTimeoutMs }),\n // A run registering is the earliest honest answer to \"did it start?\": the\n // launcher's own process chain can stay open long after the run is\n // working, and a launch that waits for it holds the caller's turn open\n // for as long as that takes.\n //\n // Answered from what the observer has announced, with the poll driving a\n // sweep rather than waiting for one. Reading `announcedRuns` alone would\n // make the handshake hostage to a filesystem notification, and a dropped\n // one would cost the caller the whole acknowledgement budget for a run\n // that had already registered. A sweep costs the registry read this used\n // to do on its own, and every other surface gets its events from it.\n findLaunchedRun: async ({ sessionId, since, workflowPath }) => {\n const expectedId = workflowIdFor(workflowPath);\n const matches = (record: WorkflowRunRecord): boolean => {\n if (!isSessionRun(record, sessionId) || record.stale) return false;\n // Matched on identity as well as time so two launches in flight from\n // one session cannot report each other's run key.\n if (record.workflowId && record.workflowId !== expectedId) return false;\n const startedAt = Date.parse(record.startedAt);\n return Number.isFinite(startedAt) && startedAt >= since - LAUNCH_ACK_CLOCK_SKEW_MS;\n };\n // No observer here: the dispatcher bridge runs the launch tool without\n // a session of its own, so it still has to look for itself.\n if (!runControl) return (await listAllRuns(registry)).find(matches);\n await runControl.refresh();\n return announcedRuns.find(matches);\n },\n // A launch answered early still owes the user its failure.\n onLateFailure: (error, ctx) => {\n const detail = error instanceof Error ? error.message : String(error);\n ctx.ui.notify(launchNotice(`Workflow launch failed after it was reported started.\\n${detail}`), 'warning');\n },\n onLaunch: async (ctx) => {\n await getTelemetry(ctx).recordEvent(LAUNCH_REQUESTED_EVENT, { outcome: 'requested' });\n return refreshStatus(ctx, false);\n },\n });\n\n /** Repaint the live list from pushed state without writing progress into chat. */\n const publishProgressOverlay = (): void => {\n const records = [...activeRunRecords.values()].sort(\n (left, right) =>\n Date.parse(left.startedAt) - Date.parse(right.startedAt) || runIdentity(left).localeCompare(runIdentity(right)),\n );\n progressOverlay.update(\n records.map((record) => workflowProgressRow(record, runEvents.get(runIdentity(record)) ?? [])),\n );\n };\n\n /** Add, refresh, or remove one run from the live list. */\n const noteActiveRecord = (record: WorkflowRunRecord): void => {\n activeRunRevision += 1;\n const identity = runIdentity(record);\n if (record.stage === RUNNING_STATUS && !record.stale) activeRunRecords.set(identity, record);\n else activeRunRecords.delete(identity);\n publishProgressOverlay();\n };\n\n /** Replace widget membership from an authoritative registry snapshot. */\n const replaceActiveRecords = (records: readonly WorkflowRunRecord[]): void => {\n activeRunRecords.clear();\n for (const record of records) activeRunRecords.set(runIdentity(record), record);\n publishProgressOverlay();\n };\n\n /** Keep every pushed progress event for both the live row and terminal summary. */\n const noteProgressEvent = (identity: string, event: WorkflowProgressEvent): void => {\n const events = runEvents.get(identity) ?? [];\n events.push(event);\n runEvents.set(identity, events);\n };\n\n /**\n * Ask for a status refresh, collapsing a burst of events into one.\n *\n * The live list updates from the event itself, but terminal detection still\n * needs the session's authoritative record set, and that costs a registry\n * page. A run emitting six transitions at once must not buy six.\n */\n let statusRefreshTimer: NodeJS.Timeout | undefined;\n const scheduleStatusRefresh = (ctx: ExtensionContext): void => {\n if (!isRuntimeActive() || ctx !== sessionCtx || statusRefreshTimer) return;\n statusRefreshTimer = setTimeout(() => {\n statusRefreshTimer = undefined;\n if (isRuntimeActive() && ctx === sessionCtx) void refreshStatus(ctx, true);\n }, STATUS_REFRESH_DEBOUNCE_MS);\n statusRefreshTimer.unref?.();\n };\n\n /** Everything remembered about a run, released once it can produce no more. */\n const forgetRun = (identity: string): void => {\n runEvents.delete(identity);\n };\n\n /**\n * Subscribe to the registry instead of asking it what changed.\n *\n * A run this session launched executes in a launcher's own process, so the\n * only thing connecting it to this one is the session stamp on its record.\n * The filter is that stamp, and it is applied inside the observer so a\n * shared registry never leaks another session's runs into this UI.\n */\n const startRunControl = async (ctx: ExtensionContext): Promise<void> => {\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const control = feature.createRunControl({\n recordFilter: (candidate) => isSessionRun(candidate, sessionId),\n });\n runControl = control;\n const controlIsCurrent = (): boolean => isRuntimeActive() && ctx === sessionCtx && runControl === control;\n\n const controlDisposers = [\n control.on('step', (event) => {\n if (!controlIsCurrent()) return;\n const identity = runIdentity(event.record);\n noteProgressEvent(identity, {\n at: event.at,\n job: event.job,\n status: event.status,\n step: event.step,\n type: 'step',\n ...(event.reason === undefined ? {} : { reason: event.reason }),\n });\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('job', (event) => {\n if (!controlIsCurrent()) return;\n const identity = runIdentity(event.record);\n noteProgressEvent(identity, {\n at: event.at,\n job: event.job,\n status: event.status,\n type: 'job',\n ...(event.index === undefined ? {} : { index: event.index }),\n ...(event.reason === undefined ? {} : { reason: event.reason }),\n ...(event.total === undefined ? {} : { total: event.total }),\n });\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('runStarted', (event) => {\n if (!controlIsCurrent()) return;\n announcedRuns.unshift(event.record);\n if (announcedRuns.length > ANNOUNCED_RUN_HISTORY) announcedRuns.length = ANNOUNCED_RUN_HISTORY;\n noteActiveRecord(event.record);\n scheduleStatusRefresh(ctx);\n }),\n control.on('runUpdated', (event) => {\n if (!controlIsCurrent()) return;\n noteActiveRecord(event.record);\n void refreshStatus(ctx, true);\n }),\n control.on('runFinished', (event) => {\n if (!controlIsCurrent()) return;\n noteActiveRecord(event.record);\n void refreshStatus(ctx, true);\n }),\n ];\n for (const dispose of controlDisposers) disposeRunControl.add(dispose);\n\n try {\n await control.start();\n } catch (error) {\n for (const dispose of controlDisposers) {\n disposeRunControl.delete(dispose);\n dispose();\n }\n control.dispose();\n if (runControl === control) runControl = undefined;\n throw error;\n }\n if (!isRuntimeActive() || ctx !== sessionCtx || runControl !== control) {\n for (const dispose of controlDisposers) {\n disposeRunControl.delete(dispose);\n dispose();\n }\n control.dispose();\n if (runControl === control) runControl = undefined;\n }\n };\n\n const stopRunControl = (): void => {\n if (statusRefreshTimer) clearTimeout(statusRefreshTimer);\n statusRefreshTimer = undefined;\n for (const dispose of disposeRunControl) dispose();\n disposeRunControl.clear();\n runControl?.dispose();\n runControl = undefined;\n runEvents.clear();\n activeRunRevision += 1;\n activeRunRecords.clear();\n publishProgressOverlay();\n };\n\n /** Dismiss the run panel entirely, leaving the run itself alone. */\n const closeOverlay = (): void => {\n activeOverlay?.teardown();\n activeOverlay?.handle?.hide();\n activeOverlay = undefined;\n };\n\n const runIdentity = (record: WorkflowRunRecord): string => record.runId ?? `${record.workspace}/${record.runKey}`;\n\n const publishModeWidget = (): void => {\n const contribution = modeContribution;\n if (!contribution) return;\n const next = workflowModeState(workflowMode, sessionRunCount);\n const serialized = JSON.stringify(next);\n if (serialized === publishedWorkflowState) return;\n publishedWorkflowState = serialized;\n contribution.publish();\n };\n\n const refreshStatus = async (ctx: ExtensionContext, notifyChanges: boolean): Promise<void> => {\n const refreshGeneration = sessionGeneration;\n const refreshIsCurrent = (): boolean =>\n isRuntimeActive() && refreshGeneration === sessionGeneration && ctx === sessionCtx;\n if (!refreshIsCurrent()) return;\n // Resolved before the guard is latched. Anything that can throw between\n // setting the flag and entering the try would strand it set, and a\n // stranded flag turns every later refresh into the early return above:\n // the run snapshot freezes, so the loop's launch budget never recovers.\n const activeTelemetry = getTelemetry(ctx);\n if (monitorRefreshGeneration === refreshGeneration) {\n void activeTelemetry.recordEvent('doom_workflow.monitor_skipped', { outcome: 'already_running' });\n return;\n }\n const startedAt = Date.now();\n const activeRevisionAtRead = activeRunRevision;\n monitorRefreshGeneration = refreshGeneration;\n try {\n const records = await listAllRuns(registry);\n if (!refreshIsCurrent()) return;\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const rootProcess = isRootProcess(ctx, sessionId);\n const sessionRecords = records.filter((record) => isSessionRun(record, sessionId));\n const running = sessionRecords.filter((record) => record.stage === RUNNING_STATUS && !record.stale);\n const failed = sessionRecords.filter((record) => record.stage === ERROR_STAGE);\n // Never let a snapshot taken before a pushed terminal event resurrect\n // the row that event just removed. The next refresh can reconcile from\n // a fresh snapshot if any lifecycle event landed during this read.\n if (activeRevisionAtRead === activeRunRevision) replaceActiveRecords(running);\n void activeTelemetry.recordEvent('doom_workflow.monitor_counts', {\n 'workflow.run_count': sessionRecords.length,\n 'workflow.running_count': running.length,\n 'workflow.failed_count': failed.length,\n mode: workflowMode ? 'on' : 'off',\n });\n\n // Runs this Pi session launched, identified by the session stamp the\n // launch tool puts in the run environment. Publishing them lets other\n // extensions size their own work without reaching into this one.\n const mine = runsForSession(records, sessionId).filter((record) => !record.stale);\n sessionRunCount = mine.length;\n publishModeWidget();\n\n // A run that has left the session's set can never produce output again,\n // so its cached screen is dead weight.\n forgetLauncherScreens(new Set(sessionRecords.map((record) => runIdentity(record))));\n\n const nextStages = new Map(sessionRecords.map((record) => [runIdentity(record), record.stage]));\n for (const record of sessionRecords) {\n const identity = runIdentity(record);\n const previous = previousStages.get(identity);\n const startedAt = Date.parse(record.startedAt);\n const startedDuringSession =\n previous === undefined &&\n (sessionStartedAt === 0 || !Number.isFinite(startedAt) || startedAt >= sessionStartedAt);\n if (lifecycleNarrationReady) {\n const narratedPrevious =\n previous === RUNNING_STATUS || previous === COMPLETED_STATUS || previous === ERROR_STAGE\n ? previous\n : undefined;\n narrateWorkflowTransition(narrationSink, record, narratedPrevious, startedDuringSession);\n }\n if (!notifyChanges || !rootProcess || record.stage === RUNNING_STATUS) continue;\n if (!deliveredTerminalRuns.has(identity) && (previous === RUNNING_STATUS || startedDuringSession)) {\n pendingTerminalRuns.set(identity, record);\n }\n }\n\n // A terminal run remains background work until Pi accepts the completion\n // turn. Otherwise another producer can observe an empty snapshot and\n // continue the agent before the workflow result has been queued.\n const retainedWork = new Map(mine.map((record) => [runIdentity(record), record]));\n for (const [identity, record] of pendingTerminalRuns) retainedWork.set(identity, record);\n if (!refreshIsCurrent()) return;\n runProvider?.update(\n [...retainedWork.values()].map((record) => ({ id: record.runId ?? record.runKey, sessionId })),\n );\n // Accumulated transitions belong to runs still going or still owed a\n // summary. Detect terminal deliveries before pruning so a failed run's\n // in-memory events remain available to its terminal message.\n const retainedEventIdentities = new Set([\n ...sessionRecords\n .filter((record) => record.stage === RUNNING_STATUS && !record.stale)\n .map((record) => runIdentity(record)),\n ...pendingTerminalRuns.keys(),\n ]);\n for (const identity of runEvents.keys()) {\n if (!retainedEventIdentities.has(identity)) forgetRun(identity);\n }\n\n if (notifyChanges) {\n for (const record of sessionRecords) {\n const previous = previousStages.get(runIdentity(record));\n if (previous !== RUNNING_STATUS || record.stage === RUNNING_STATUS) continue;\n const completed = record.stage === COMPLETED_STATUS;\n const detail = record.failedJob ? ` at ${record.failedJob}` : '';\n ctx.ui.notify(\n completed\n ? `${GLYPH.completed} ${record.runKey} completed`\n : `${GLYPH.failed} ${record.runKey} ${stageLabel(record)}${detail}`,\n completed ? 'info' : 'warning',\n );\n void activeTelemetry.recordEvent('doom_workflow.run_transition', {\n outcome: completed ? 'completed' : stageLabel(record),\n });\n }\n }\n\n if (rootProcess && pendingTerminalRuns.size > 0) {\n try {\n const terminalRecords = [...pendingTerminalRuns.values()];\n const summaries = await Promise.all(\n terminalRecords.map(async (record) => {\n if (record.stage === COMPLETED_STATUS) return finishedRunSummary(record, []);\n // A failure needs the job tree to say which job died. The\n // transitions pushed while the run was going are already in\n // hand; only a run that finished before this session began\n // watching has nothing accumulated and has to be read.\n const identity = runIdentity(record);\n const events =\n runEvents.get(identity) ??\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record)));\n return finishedRunSummary(record, summarizeWorkflowProgress(events));\n }),\n );\n if (!refreshIsCurrent()) return;\n pi.sendMessage(\n {\n customType: WORKFLOW_FINISHED_MESSAGE,\n content: summaries.join('\\n\\n'),\n display: true,\n details: {\n runIds: terminalRecords.map((record) => record.runId ?? runIdentity(record)),\n runs: terminalRecords.map((record): WorkflowFinishedRun => ({\n runKey: record.runKey,\n workspace: record.workspace,\n stage: record.stage,\n ...(record.workflowId ? { workflowId: record.workflowId } : {}),\n ...(record.failedJob ? { failedJob: record.failedJob } : {}),\n ...(record.errorMessage ? { error: record.errorMessage } : {}),\n })),\n },\n },\n { triggerTurn: true, deliverAs: 'steer' },\n );\n if (!refreshIsCurrent()) return;\n for (const record of terminalRecords) {\n const identity = runIdentity(record);\n deliveredTerminalRuns.add(identity);\n pendingTerminalRuns.delete(identity);\n // Its summary has been delivered, so the accumulated transitions\n // can never be needed again.\n forgetRun(identity);\n }\n runProvider?.update(mine.map((record) => ({ id: record.runId ?? record.runKey, sessionId })));\n } catch (error) {\n await activeTelemetry.recordError('doom_workflow.terminal_delivery_failed', error, {\n 'workflow.pending_terminal_count': pendingTerminalRuns.size,\n });\n }\n }\n\n if (!refreshIsCurrent()) return;\n previousStages = nextStages;\n void activeTelemetry.recordEvent('doom_workflow.monitor_finished', {\n duration_ms: Date.now() - startedAt,\n outcome: 'completed',\n });\n } catch (error) {\n await activeTelemetry.recordError('doom_workflow.monitor_failed', error, {\n duration_ms: Date.now() - startedAt,\n });\n if (refreshIsCurrent()) {\n ctx.ui.notify(\n `Workflow status refresh failed: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n }\n } finally {\n if (monitorRefreshGeneration === refreshGeneration) monitorRefreshGeneration = undefined;\n }\n };\n\n const clearFollow = (ctx: ExtensionContext): void => {\n if (followTimer) clearInterval(followTimer);\n followTimer = undefined;\n followedRun = undefined;\n ctx.ui.setWidget(FOLLOW_WIDGET_KEY, undefined);\n };\n\n /**\n * This session's view of the terminals its runs were launched into.\n *\n * The engine owns how a launcher is read and driven; this owns how often,\n * which is a property of the surface rather than of the run. Every panel\n * here repaints five times a second and a scrape forks a CLI, so the two\n * concerns stayed separate when the reads moved down into the engine.\n */\n const terminalFacade = new WorkflowTerminalService({\n run: async (command, args, options) => {\n const result = await pi.exec(command, [...args], { timeout: options.timeoutMs });\n return { code: result.code, stdout: result.stdout, stderr: result.stderr };\n },\n lines: TAIL_LINES,\n timeoutMs: PI_EXEC_TIMEOUT_MS,\n });\n const terminals = createWorkflowTerminalService<WorkflowRunRecord>({\n terminal: terminalFacade,\n now: () => Date.now(),\n refreshMs: SCREEN_REFRESH_MS,\n });\n\n /**\n * Geometry last asked of each run, so a repaint that changes nothing costs\n * no exec. Keyed by run identity, like every other per-run cache here.\n */\n const launcherGeometry = new Map<string, string>();\n\n /**\n * Match the run's own terminal to the panel showing it.\n *\n * A run draws at whatever geometry its launcher gave it, so a panel\n * narrower than that shows a clipped window onto a wider screen rather than\n * a smaller rendering of it. Which launchers can be told a size is the\n * engine's business; not asking twice for the same size is this one's.\n *\n * The size is NOT restored when the panel closes: the window belongs to this\n * run, and a run that is watched at panel size should stay readable at panel\n * size for whoever attaches to it next.\n */\n const resizeLauncherViewport = (record: WorkflowRunRecord, columns: number, rows: number): void => {\n const identity = runIdentity(record);\n const geometry = `${columns}x${rows}`;\n if (launcherGeometry.get(identity) === geometry) return;\n launcherGeometry.set(identity, geometry);\n void terminalFacade.resize(record, columns, rows);\n };\n\n /**\n * A run's recent output, reusing a recent read rather than forking again.\n *\n * Rendering stays as fast as it ever was: the caller gets the cached lines\n * immediately and the next repaint picks up whatever the refresh found.\n */\n const cachedLauncherScreen = (record: WorkflowRunRecord): Promise<string[]> => {\n // Answered here rather than by the engine: the engine cannot know that\n // the caller's own terminal is a Pi session with a status surface to\n // send the reader to instead.\n if (terminalFacade.targetsCurrentTerminal(record)) return Promise.resolve([HOST_TERMINAL_OUTPUT_BLOCKED]);\n return terminals.screen(runIdentity(record), record, TAIL_LINES);\n };\n\n /** Runs whose screens can never change again cannot earn their memory back. */\n const forgetLauncherScreens = (live: Set<string>): void => {\n terminals.forget(live);\n // The geometry cache is per run for the same reason the screens are: a\n // run that is gone can never be resized again.\n for (const identity of launcherGeometry.keys()) {\n if (!live.has(identity)) launcherGeometry.delete(identity);\n }\n };\n\n /**\n * Bring a run's launcher to the foreground.\n *\n * Returns a status line rather than notifying, because its only caller is now\n * the `workflow_run` tool's `open` action and the agent needs to read the outcome.\n */\n const openLauncher = async (record: WorkflowRunRecord): Promise<string> => {\n const launcher = record.launcher;\n if (!launcher) return NO_LAUNCHER_RECORDED;\n if (terminalFacade.targetsCurrentTerminal(record)) return HOST_TERMINAL_OUTPUT_BLOCKED;\n if (launcher.type === LAUNCHER_NATIVE) {\n return 'This run is hosted natively rather than in a multiplexer, so there is no separate window to bring forward.';\n }\n if (launcher.type === LAUNCHER_CMUX) {\n await pi.exec(LAUNCHER_CMUX, ['select-workspace', '--workspace', launcher.workspaceId], {\n timeout: PI_EXEC_TIMEOUT_MS,\n });\n return `Opened ${record.runKey} in cmux.`;\n }\n if (!options.environment.TMUX) {\n return 'Pi is not attached to tmux. Follow the output instead, or attach to the recorded tmux session manually.';\n }\n const target = launcher.sessionId ?? launcher.sessionName;\n const result = await pi.exec(LAUNCHER_TMUX, ['switch-client', '-t', target], { timeout: PI_EXEC_TIMEOUT_MS });\n if (result.code !== 0) return result.stderr.trim() || `Unable to open tmux session ${target}.`;\n if (launcher.paneId) {\n await pi.exec(LAUNCHER_TMUX, ['select-pane', '-t', launcher.paneId], { timeout: PI_EXEC_TIMEOUT_MS });\n }\n return `Opened ${record.runKey} in tmux.`;\n };\n\n const renderFollow = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n if (followRefreshActive) return;\n followRefreshActive = true;\n try {\n // Prefer the run's own progress log: it says which job and step are in\n // flight, which a scraped screen cannot. Runs started before progress\n // recording existed, and any run whose log is not readable, still get\n // the terminal tail.\n const jobs = summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n );\n const lines = jobs.length > 0 ? undefined : await cachedLauncherScreen(record);\n // Component factory rather than a string array, for two reasons the\n // string form cannot give us: render() receives the terminal width, so\n // launcher output can be fitted instead of overflowing, and the theme is\n // applied fresh on every render, so a theme switch repaints correctly\n // without any cached colours to invalidate.\n ctx.ui.setWidget(\n FOLLOW_WIDGET_KEY,\n (_tui, theme) => ({\n render: (width: number) =>\n renderFollowLines(record, lines ?? renderProgressLines(jobs, theme, width), theme, width),\n invalidate: () => {\n // Nothing cached: render() rebuilds from the current theme.\n },\n }),\n { placement: 'aboveEditor' },\n );\n } finally {\n followRefreshActive = false;\n }\n };\n\n const followRun = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n clearFollow(ctx);\n followedRun = record;\n await renderFollow(record, ctx);\n followTimer = setInterval(() => {\n if (followedRun) void renderFollow(followedRun, ctx);\n }, followIntervalMs);\n followTimer.unref?.();\n };\n\n /**\n * Forward literal text to a run's terminal.\n *\n * `tmux send-keys -l` and `cmux send` both take text verbatim, which keeps\n * escape sequences intact: an arrow key must arrive as one sequence, not as\n * a bracket and a letter. A natively hosted run has no multiplexer to\n * address, so it reports rather than silently dropping the keystrokes.\n */\n const sendToRun = async (record: WorkflowRunRecord, text: string): Promise<void> => {\n // Silently, because a panel only builds a keyboard for a run whose\n // capabilities already said yes: reaching here with an unwritable run\n // means the run changed under the panel, which is not the typist's problem.\n if (!terminalFacade.capabilities(record).writable) return;\n await terminalFacade.write(record, text);\n };\n\n /**\n * Show a run over Pi: job tree, live output, and a keyboard that reaches it.\n *\n * Blocks until the user closes it, which is what makes it feel like the run\n * rather than a report about the run. The refresh runs faster than the\n * background widget because a foregrounded terminal that lags behind your\n * own typing reads as broken.\n */\n /**\n * Show a run over Pi as a persistent panel, not a modal.\n *\n * Returns as soon as the panel is up rather than awaiting its close. An\n * awaited overlay would hold the tool call open, which freezes the agent\n * mid-turn and makes \"switch back to the main agent\" impossible: there is\n * nothing to switch back to while it is still waiting for a tool result.\n *\n * Focus, not lifetime, is what the user toggles. The panel stays on screen\n * while typing goes back to Pi, so Escape stays free for the run's own\n * agent, which uses it to interrupt.\n */\n const openOverlay = async (record: WorkflowRunRecord, ctx: ExtensionContext): Promise<string> => {\n closeOverlay();\n // Exactly what the engine says this run's terminal will take. A run with\n // no reachable terminal gets a panel that is a view rather than a\n // keyboard, and saying so up front beats letting the user type into nothing.\n const interactive = terminalFacade.capabilities(record).writable;\n const input = new TerminalInputBatcher((text) => sendToRun(record, text));\n let jobs: WorkflowProgressJob[] = [];\n let output: string[] = [];\n let refresh: NodeJS.Timeout | undefined;\n\n let polling = false;\n const poll = async (): Promise<void> => {\n jobs = summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n );\n output = await cachedLauncherScreen(record);\n };\n await poll();\n\n const teardown = (): void => {\n if (refresh) clearInterval(refresh);\n refresh = undefined;\n input.dispose();\n };\n\n const entry: ActiveOverlay = { interactive, runKey: record.runKey, teardown };\n activeOverlay = entry;\n\n /** Shared by the panel footer, the close chord, and the double-Escape failsafe. */\n const closeWithNotice = (): void => {\n closeOverlay();\n ctx.ui.notify(`Closed the ${record.runKey} view. The run keeps going.`, 'info');\n };\n\n // Deliberately not awaited: the panel outlives this tool call.\n void ctx.ui.custom<void>(\n (tui, theme, _keybindings, done) => {\n // Guarded, because a tick that outlives its interval would otherwise\n // start another read on top of the last one and keep doing so. The\n // progress log is a local file and the screen read is coalesced, so a\n // skipped tick costs nothing: the next one repaints from the same state.\n refresh = setInterval(() => {\n if (polling) return;\n polling = true;\n void poll().finally(() => {\n polling = false;\n tui.requestRender();\n });\n }, OVERLAY_REFRESH_MS);\n refresh.unref?.();\n\n return new WorkflowRunPanelComponent(tui, theme, {\n runKey: record.runKey,\n label: `${GLYPH.running} ${runLabel(record)}`,\n breadcrumb: RUN_PANEL_BREADCRUMB,\n interactive,\n footer: panelHint(interactive),\n hints: panelHints(interactive),\n snapshot: (width) => ({ progress: renderProgressLines(jobs, theme, width), output }),\n onViewport: (columns, rows) => resizeLauncherViewport(record, columns, rows),\n onUnfollow: () => {\n entry.handle?.unfocus();\n ctx.ui.notify('Typing goes to this session. The run keeps going.', 'info');\n },\n onClose: closeWithNotice,\n sendInput: (data) => input.write(data),\n // `flush` takes the pending bytes synchronously and sends them in the\n // background, so the panel still closes on the same keystroke.\n // Without it the run would be interrupted or not depending on whether\n // the user out-typed a 16ms timer, which is not a behaviour anyone can\n // predict or rely on.\n flushInput: () => void input.flush(),\n unfollowShortcut: UNFOLLOW_SHORTCUT,\n closeShortcut: CLOSE_OVERLAY_SHORTCUT,\n onDispose: () => {\n teardown();\n if (activeOverlay === entry) activeOverlay = undefined;\n done();\n },\n });\n },\n {\n ...runPanelUiOptions(interactive),\n onHandle: (handle) => {\n entry.handle = handle;\n },\n },\n );\n\n // Told to the user directly, not only through the tool result. The result\n // is addressed to the agent, and the panel's own footer is one dim line\n // that a user watching a run scroll past can easily miss. A view you\n // cannot work out how to leave is the thing to avoid here.\n ctx.ui.notify(\n interactive\n ? `${record.runKey}: typing goes to the run. Press Esc twice to close, ${shortcutLabel(UNFOLLOW_SHORTCUT)} to type here instead.`\n : `${record.runKey}: view only, because this run is hosted natively. ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes it.`,\n 'info',\n );\n\n if (!interactive) {\n return [\n `Showing ${record.runKey} over Pi, as a view only:`,\n 'the run is hosted natively rather than in a multiplexer, so there is no terminal to type into.',\n `Typing stays with this session, and ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes the view.`,\n ].join(' ');\n }\n\n return [\n `Showing ${record.runKey} over Pi. Typing goes to the run.`,\n 'Pressing Escape twice quickly closes the view, and a single Escape still reaches the run.',\n `${shortcutLabel(UNFOLLOW_SHORTCUT)} moves typing between the run and this session,`,\n `and ${shortcutLabel(CLOSE_OVERLAY_SHORTCUT)} closes the view. The run keeps going either way.`,\n ].join(' ');\n };\n\n const openInspector = async (ctx: ExtensionContext, manage = false): Promise<void> => {\n if (inspectorOpen || activeOverlay || followedRun) return;\n inspectorOpen = true;\n try {\n const selection = await ctx.ui.custom<WorkflowInspectorSelection | undefined>(\n (tui, theme, _keybindings, done) =>\n new WorkflowInspectorComponent(\n tui,\n theme,\n {\n list: async () => {\n const sessionId = currentSessionId();\n const records = (await listAllRuns(registry)).filter(\n (record) => record.stage === RUNNING_STATUS && !record.stale && isSessionRun(record, sessionId),\n );\n // Kept so `output` can address the run under the cursor without\n // paging the whole registry a second time on every refresh.\n inspectorRecords = new Map(records.map((record) => [runIdentity(record), record]));\n return Promise.all(\n records.map(async (record) => ({\n displayName: record.displayName,\n executionState: record.executionState,\n jobs: summarizeWorkflowProgress(\n progressEventsForRun(record, await readWorkflowProgress(registry.runDirectoryFor(record))),\n ),\n key: runIdentity(record),\n output: [],\n runKey: record.runKey,\n startedAt: record.startedAt,\n workspace: record.workspace,\n })),\n );\n },\n output: async (item) => {\n const record = inspectorRecords.get(item.key);\n return record ? cachedLauncherScreen(record) : ['Workflow is no longer active.'];\n },\n },\n done,\n ),\n {\n ...DOOM_FULLSCREEN_UI_OPTIONS,\n onHandle: (handle) => {\n inspectorHandle = handle;\n },\n },\n );\n if (selection) {\n const record = await requireRun(selection);\n if (manage) await manageWorkflow(record, ctx);\n else await openOverlay(record, ctx);\n }\n } finally {\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n }\n };\n\n /**\n * Resolve a run this session owns, erroring rather than picking blindly.\n *\n * A run another session launched is reported exactly like one that does not\n * exist. Distinguishing them would leak the shared registry's contents into\n * a session that has no way to act on them anyway, and would invite the\n * agent to keep trying keys it can never use.\n */\n const requireRun = async (\n input: { runKey: string; workspace?: string },\n sessionId: string | undefined = currentSessionId(),\n ): Promise<WorkflowRunRecord> => {\n observeSession(sessionId);\n const records = await listAllRuns(registry, input.workspace);\n const matches = records.filter(\n (candidate) => candidate.runKey === input.runKey && isSessionRun(candidate, sessionId),\n );\n if (matches.length > 1) {\n throw new Error(\n withOptions(\n `Workflow run key ${JSON.stringify(input.runKey)} exists in more than one workspace in this session.`,\n ['Retry with the workspace from the run identity.'],\n ),\n );\n }\n const record = matches[0];\n if (!record) {\n throw new Error(\n withOptions(`No workflow run matches ${JSON.stringify(input.runKey)} in this session.`, [\n 'workflow_run with action status: use a run key from this session before retrying.',\n 'Tell the user this session did not launch that run rather than guessing a similar key. A run launched by another Pi session, or from the command line, is managed there or with the workflow-mcp CLI.',\n ]),\n );\n }\n return record;\n };\n\n /**\n * Resolve a failed run that this session may adopt through recovery.\n *\n * Failed runs are terminal and have no live owner to conflict with. This is\n * intentionally the only cross-session lookup. Recovery-specific status\n * and durable evidence reads may use it; live output, lifecycle controls,\n * and running-run UI stay scoped to the launching session.\n */\n const requireRecoverableRun = async (input: { runKey: string; workspace?: string }): Promise<WorkflowRunRecord> => {\n const matches = (await listAllRuns(registry, input.workspace)).filter(\n (candidate) => candidate.runKey === input.runKey && candidate.stage === ERROR_STAGE,\n );\n if (matches.length > 1) {\n throw new Error(\n withOptions(`Failed workflow run key ${JSON.stringify(input.runKey)} exists in more than one workspace.`, [\n 'Retry with the workspace from the recovery picker or run identity.',\n ]),\n );\n }\n const record = matches[0];\n if (!record) {\n throw new Error(\n withOptions(`No failed workflow run matches ${JSON.stringify(input.runKey)}.`, [\n 'Use the recovery picker to select an interrupted or failed run, or retry with its workspace.',\n 'Do not recover a running or completed workflow.',\n ]),\n );\n }\n return record;\n };\n\n const readRecoveryEvidenceTail = async (record: WorkflowRunRecord): Promise<string[]> => {\n const runDir = registry.runDirectoryFor(record);\n const paths = [resolve(runDir, 'changelog.md'), resolve(runDir, 'context.md'), resolve(runDir, 'progress.ndjson')];\n const sections: string[] = [];\n for (const path of paths) {\n try {\n const content = await readFile(path, 'utf-8');\n sections.push(`--- ${basename(path)} ---`, content.slice(-RECOVERY_EVIDENCE_MAX_BYTES).trimEnd());\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n }\n return sections.length > 0 ? sections : ['No durable recovery evidence files are recorded for this run.'];\n };\n\n /** Read-only evidence access for the one globally adoptable record class. */\n const readRecoverableRunEvidence = async (\n input: { runKey: string; workspace?: string },\n ctx: ExtensionContext,\n ): Promise<string> => {\n const record = await requireRecoverableRun(input);\n await getTelemetry(ctx).recordEvent('doom_workflow.recovery_evidence_requested', { outcome: 'requested' });\n return [\n `Workflow: ${runLabel(record)}`,\n '--- run.json ---',\n JSON.stringify(record, null, 2),\n ...(await readRecoveryEvidenceTail(record)),\n ].join('\\n');\n };\n\n /**\n * Recover a run in a launcher of its own instead of replaying it here.\n *\n * `RecoverWorkflowService` replays with the launch step skipped, so an\n * in-process recovery runs every job inside this process. A workflow whose\n * steps are `interactiveRun` then has its agent spawned with inherited\n * stdio, because that agent needs a real TTY to draw. Inside Pi that TTY is\n * the TUI: the agent draws over it, and the reset sequence written when the\n * step ends is one Pi never issued and cannot repaint from. Delegating\n * costs a process and keeps the screen.\n *\n * Undefined leaves the caller on the in-process path: a workflow that\n * declares no `launch-command` has no launcher to delegate to, and a\n * definition that cannot be read is better diagnosed by the replay itself.\n */\n const delegateRecovery = async (\n input: { runKey: string; workspace?: string; runner?: string },\n ctx: ExtensionContext,\n ): Promise<string | undefined> => {\n const cli = resolveWorkflowCli();\n if (!cli) return undefined;\n const record = await requireRecoverableRun(input);\n let workflow: Workflow;\n try {\n workflow = parser.parseWorkflowFile(record.workflowPath);\n } catch {\n return undefined;\n }\n if (!workflow['launch-command']) return undefined;\n\n // Mint the transfer capability in the shared registry before spawning.\n // The delegated CLI can only adopt this exact terminal record and gets\n // the owner identity from the claim rather than caller-controlled argv.\n const sessionId = resolveRootSessionId(ctx.sessionManager.getSessionId(), options.environment);\n const claim = await registry.claimRunRecovery(record.workspace, record.runKey, sessionId);\n const cwd = record.originalRepoPath ?? ctx.cwd;\n const recoverCommand = shellCommand([\n process.execPath,\n cli,\n RECOVER_COMMAND,\n record.runKey,\n '--workspace',\n record.workspace,\n '--recovery-claim',\n claim.claimId,\n ...(input.runner ? ['--runner', input.runner] : []),\n ]);\n const launcher = preferredLauncher(options.environment);\n try {\n await spawnDetached(\n process.execPath,\n [\n cli,\n LAUNCH_PROCESS_COMMAND,\n ...(launcher ? ['--launcher', launcher] : []),\n '--name',\n `${record.displayName} recover`,\n '--cwd',\n cwd,\n '--command',\n recoverCommand,\n ],\n { cwd, env: launcherEnvironment(options.environment) },\n );\n } catch (error) {\n await registry.releaseRunRecoveryClaim(record.workspace, record.runKey, claim.claimId);\n throw error;\n }\n await getTelemetry(ctx).recordEvent('doom_workflow.recover_delegated', {\n launcher: launcher ?? 'auto',\n outcome: 'delegated',\n });\n return `Recovering ${record.runKey} in a launcher of its own, so this session keeps its terminal. It reports back here when it ends.`;\n };\n\n const manageWorkflow = async (selected: WorkflowRunRecord, ctx: ExtensionContext): Promise<void> => {\n let record = selected;\n while (true) {\n const actions = ['Open output'];\n const state = record.executionState ?? RUNNING_STATUS;\n if (state === RUNNING_STATUS) actions.push('Pause');\n if (state === PAUSED_EXECUTION_STATE) actions.push('Resume');\n if (record.stage === RUNNING_STATUS) actions.push('Stop');\n actions.push('Back');\n const action = await openWorkflowChoice(ctx, {\n title: `Manage ${record.runKey}`,\n breadcrumb: MANAGE_BREADCRUMB,\n choices: actions,\n });\n if (!action || action === 'Back') return;\n\n record = await requireRun(record);\n if (record.stage !== RUNNING_STATUS) {\n ctx.ui.notify(`${record.runKey} is no longer running.`, 'warning');\n return;\n }\n if (action === 'Open output') {\n await openOverlay(record, ctx);\n return;\n }\n if (action === 'Stop') {\n const confirmed = await ctx.ui.confirm(\n `Stop ${record.runKey}?`,\n 'The workflow will be interrupted and will not be restarted automatically.',\n );\n if (!confirmed) continue;\n record = await requireRun(record);\n if (record.stage !== RUNNING_STATUS) {\n ctx.ui.notify(`${record.runKey} is no longer running.`, 'warning');\n return;\n }\n }\n if (action !== 'Pause' && action !== 'Resume' && action !== 'Stop') continue;\n if (!record.runId) throw new Error(`${record.runKey} has no controllable run generation.`);\n const result = await controlTool.execute({\n action: action.toLowerCase() as 'pause' | 'resume' | 'stop',\n expectedRunId: record.runId,\n ...(action === 'Stop' ? { reason: 'Stopped from the workflow manager.' } : {}),\n runKey: record.runKey,\n workspace: record.workspace,\n });\n if (result.isError) throw new Error(toolResultText(result) || `Unable to ${action.toLowerCase()} workflow.`);\n ctx.ui.notify(toolResultText(result) || `${action} requested for ${record.runKey}.`, 'info');\n await refreshStatus(ctx, false);\n record = await requireRun(record);\n }\n };\n\n /**\n * The wizard's prompts, backed by doom overlays instead of Pi's native\n * widgets, so a launch reads as one framed sequence rather than three styles.\n *\n * `editor` stays with Pi: the workflow prompt is multi-line authoring, and\n * reimplementing a text editor to match a frame would be a poor trade.\n */\n const doomLauncherUi = (ctx: ExtensionContext, breadcrumb: string): WorkflowLauncherUi => ({\n editor: (title, prefill) => ctx.ui.editor(title, prefill),\n input: (title, placeholder) =>\n openWorkflowInput(ctx, { title, breadcrumb, ...(placeholder ? { fallback: placeholder } : {}) }),\n notify: (message, type) => ctx.ui.notify(message, type),\n select: (title, options) => openWorkflowChoice(ctx, { title, breadcrumb, choices: options }),\n });\n\n /**\n * `SPC w l`: the repository's workflows, the cursor workflow's parsed\n * detail beside it, and `r` to launch that one. Launching closes the board\n * first - the launch prompts are host dialogs, and a fullscreen overlay\n * would sit over them.\n */\n const openWorkflowCatalog = async (ctx: ExtensionContext): Promise<void> => {\n if (!ctx.hasUI) {\n ctx.ui.notify('The workflow list needs an interactive Pi session.', 'warning');\n return;\n }\n const entries = await loadWorkflowCatalog(feature.listWorkflowsTool, ctx.cwd);\n const byPath = new Map(entries.map((entry) => [entry.path, entry]));\n const launchOptions = {\n compatibleRunners,\n launch: (input: WorkflowLaunchInput, launchContext: ExtensionContext) =>\n launchExecutor.execute(input, launchContext),\n parseWorkflow: (workflowPath: string) => parser.parseWorkflowFile(workflowPath),\n ui: doomLauncherUi(ctx, CATALOG_BREADCRUMB),\n };\n await openWorkflowCatalogOverlay(\n ctx,\n entries.map((entry) => ({\n key: entry.path,\n name: entry.name,\n relativePath: entry.relativePath,\n description: entry.description,\n tags: entry.tags,\n })),\n {\n loadDetail: (row) => summarizeWorkflowFile(row.key, launchOptions),\n launchWorkflow: (row) => {\n const entry = byPath.get(row.key);\n if (!entry) return;\n void launchWorkflowEntry(launchOptions, entry, ctx).then(\n (result) => {\n // Trimmed, because a launch that ran in this process answers\n // with the engine's whole console log, and notifying that\n // verbatim paints tens of lines of banner and job tree over\n // the transcript.\n if (result) ctx.ui.notify(launchNotice(toolResultText(result)), 'info');\n },\n (error: unknown) => {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n },\n );\n },\n },\n );\n };\n\n /**\n * `/workflow-launch`: the same launch the catalog board performs, as a line.\n *\n * The cockpit can only send a session a prompt frame, so this is how a\n * browser starts a workflow; typing it by hand does the same thing. Every\n * value the board would have asked for in a dialog arrives on the line, and\n * what the workflow requires is checked before anything is started, because\n * a run missing its prompt starts and then waits for terminal input that is\n * never coming.\n */\n const launchFromCommand = async (args: string, ctx: ExtensionContext): Promise<void> => {\n const parsed = parseWorkflowLaunchCommand(args);\n if (isLaunchParseFailure(parsed)) {\n ctx.ui.notify(parsed.error, 'error');\n return;\n }\n const entries = await loadWorkflowCatalog(feature.listWorkflowsTool, ctx.cwd);\n const entry = resolveWorkflowEntry(entries, parsed.workflow);\n if (!entry) {\n ctx.ui.notify(`No workflow matches '${parsed.workflow}' under ${ctx.cwd}.`, 'error');\n return;\n }\n const detail = summarizeWorkflowFile(entry.path, {\n compatibleRunners,\n parseWorkflow: (workflowPath: string) => parser.parseWorkflowFile(workflowPath),\n });\n if (detail.error !== undefined) {\n ctx.ui.notify(`${entry.name} could not be read: ${detail.error}`, 'error');\n return;\n }\n const problems = validateWorkflowLaunch(detail, parsed);\n if (problems.length > 0) {\n ctx.ui.notify(problems.join(' '), 'error');\n return;\n }\n const workflow = parser.parseWorkflowFile(entry.path);\n const input: WorkflowLaunchInput = {\n workflowPath: entry.path,\n ...(parsed.runner === undefined ? {} : { runner: parsed.runner }),\n ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n ...(parsed.prompt === undefined ? {} : { prompt: parsed.prompt }),\n ...(Object.keys(parsed.inputs).length === 0 ? {} : { inputs: parsed.inputs }),\n };\n const result = await launchExecutor.execute(input, ctx);\n // Trimmed for the same reason the board trims it: a launch that ran in\n // this process answers with the engine's whole console log.\n ctx.ui.notify(launchNotice(toolResultText(result)), 'info');\n };\n\n const commands: WorkflowPiRuntime['commands'] = [\n [\n WORKFLOW_LAUNCH_COMMAND,\n {\n description: 'Launch a workflow: /workflow-launch <workflow> [runner=x] [key=value …] [prompt]',\n handler: async (args, ctx) => {\n await waitForReadiness();\n try {\n await launchFromCommand(args, ctx);\n } catch (error) {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n }\n },\n },\n ],\n ];\n\n const openRecoveryHandoff = async (ctx: ExtensionContext): Promise<void> => {\n // Recovery adopts terminal work. Include failed runs from dead or other\n // sessions here; passive UI and all controls over live runs stay scoped.\n const records = (await listAllRuns(registry)).filter((record) => record.stage === ERROR_STAGE);\n if (records.length === 0) {\n ctx.ui.notify('No failed workflows are available to recover.', 'info');\n return;\n }\n const chosen = await openWorkflowPickerOverlay(\n ctx,\n {\n title: 'WORKFLOW RECOVERY',\n breadcrumb: RECOVER_BREADCRUMB,\n unit: 'failed runs',\n action: 'recover',\n filterPlaceholder: 'type to filter by name, run key or failed job',\n emptyMessage: 'No failed workflows are available to recover.',\n },\n records.map((record) => ({\n key: `${record.workspace}/${record.runKey}`,\n name: record.displayName,\n detail: `${record.workspace}/${record.runKey}${record.failedJob ? ` · ${record.failedJob}` : ''}`,\n ...(record.failedJob ? { search: record.failedJob } : {}),\n value: record,\n })),\n );\n if (!chosen) return;\n const record = await requireRecoverableRun(chosen);\n if (record.stage !== ERROR_STAGE) throw new Error(`${record.runKey} is no longer failed.`);\n const skillFile = resolve(workflowSkillDirectory(), 'workflow-recovery', 'SKILL.md');\n if (!existsSync(skillFile)) throw new Error(`Workflow recovery skill is unavailable at ${skillFile}.`);\n setWorkflowMode(true);\n ctx.ui.notify(\n 'Workflow tools enabled. The agent will investigate this failure and choose the safe next step.',\n 'info',\n );\n pi.sendUserMessage(\n [\n 'Investigate recovery for this failed workflow run. This selection is permission to investigate, not permission to recover blindly.',\n `Run identity: ${JSON.stringify({ runKey: record.runKey, workspace: record.workspace })}`,\n `Read the package-owned recovery skill with the read tool at ${JSON.stringify(skillFile)} before acting.`,\n 'Inspect status, every relevant log source, process state, the staged run.json, and only the repair referenced by activeRepairId.',\n 'Choose exactly one outcome: recover, launch fresh, or defer. Never edit issue.md or repair.json, never scan historical repairs, and never pass recovery dryRun or a job override.',\n 'Do not recover terminal, approval-pending, blocked, or otherwise unsafe work. If evidence is incomplete, defer and explain what is missing.',\n 'If recovery is justified, preserve the recorded worktree and repair metadata, then verify real process and registry progress before reporting success.',\n ].join('\\n'),\n { deliverAs: 'followUp' },\n );\n };\n\n /**\n * Turn workflow mode on or off.\n *\n * The tools are registered for the whole session, so the mode is a tool\n * surface restriction rather than a registration: dropping it is what makes\n * them visible again, and no other owner's tools are touched either way.\n *\n * Activating also injects each tool's `promptSnippet` and `promptGuidelines`\n * into the system prompt, and deactivating strips them: in Pi, tool gating\n * and instruction injection are the same lever.\n */\n const setWorkflowMode = (enabled: boolean): void => {\n if (!isRuntimeActive()) return;\n workflowMode = enabled;\n restrictionListeners.forEach((listener) => listener());\n // Published here rather than in refreshStatus so the label lands with the\n // toggle: the status refresh is an async registry read, and a label that\n // waits for it looks like the command did nothing.\n publishModeWidget();\n options.onModeChange?.(enabled);\n };\n\n /**\n * What the user sees on every mode change.\n *\n * Leads with the state, then the one thing they can do next. Turning the\n * mode on is useless without knowing that you now just ask in plain\n * language, so that sentence earns its place; the tool count does not, and\n * is left to the README.\n */\n const modeSummary = (): string =>\n workflowMode\n ? [\n `${GLYPH.completed} Workflow mode on`,\n 'Ask for workflows in plain language: the agent can list, launch, inspect, pause, resume, stop, and recover runs.',\n `${shortcutLabel(UNFOLLOW_SHORTCUT)} stops following a run without stopping it.`,\n ].join('\\n')\n : [\n 'Workflow mode off',\n `Press ${LEADER_MODE_BREADCRUMB} to give the agent its workflow tools. Runs already going are unaffected.`,\n ].join('\\n');\n\n /**\n * Toggle the mode from the leader menu.\n *\n * Replaces the `/workflow [on|off|status]` command: the mode line already\n * answers `status` at a glance, and the other two arguments were a keyboard\n * path to a switch the leader menu spells out. Plan mode is reached the same\n * way, so the two modes are no longer toggled through different surfaces.\n */\n const applyWorkflowMode = async (enabled: boolean, ctx: ExtensionContext): Promise<void> => {\n setWorkflowMode(enabled);\n if (!workflowMode) clearFollow(ctx);\n ctx.ui.notify(modeSummary(), 'info');\n // Both directions: turning off has to clear the indicator, not just leave\n // the last one on screen until the monitor next fires.\n await refreshStatus(ctx, false);\n };\n\n // Zero palette cost, unlike a command. Guarded on an active follow so it\n // does not swallow the key when there is nothing to dismiss.\n\n // Dismissing is its own key because the panel cannot use Escape: a focused\n // panel forwards every key to the run so its agent stays interruptible.\n\n // A battery-included mode must not add model-visible skills while dormant.\n // Discovery follows session_start, so environment-driven dispatcher\n // activation is visible at startup while the normal parent remains neutral.\n // The existence guard also fails closed if packaging ever drops the skill.\n const onResourcesDiscover: NonNullable<PiEventHandlers['resources_discover']> = () => {\n if (!workflowMode) return { skillPaths: [] };\n const skillPath = workflowSkillDirectory();\n return { skillPaths: existsSync(skillPath) ? [skillPath] : [] };\n };\n\n const messageRenderers: PiPluginContributions['messageRenderers'] = [\n createWorkflowFinishedRenderer(),\n [\n LEGACY_WORKFLOW_STEP_MESSAGE,\n (message, { outputPad }, theme) => {\n const details = isWorkflowStepMessageDetails(message.details) ? message.details : undefined;\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n return renderWorkflowStepMessage(details, content, outputPad, theme);\n },\n ],\n ];\n\n const toolDependencies: WorkflowPiToolDependencies = {\n environment: options.environment,\n runTool,\n recoverTool,\n launchExecutor,\n controlTool,\n requireSessionRun: requireRun,\n requireRecoverableRun,\n readRecoveryEvidence: readRecoverableRunEvidence,\n delegateRecovery,\n trackPendingRun,\n observeSession,\n activeRunCount: async () => sessionRunCount,\n onLaunch: async (ctx) => {\n await getTelemetry(ctx).recordEvent(LAUNCH_REQUESTED_EVENT, { outcome: 'requested' });\n return refreshStatus(ctx, false);\n },\n followRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.follow_started', { outcome: 'started' });\n await followRun(record, ctx);\n return `Following ${runLabel(record)}. Press ${shortcutLabel(UNFOLLOW_SHORTCUT)} to stop following; the run keeps going.`;\n },\n tailRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.tail_requested', { outcome: 'requested' });\n return [\n `Workflow: ${runLabel(record)}`,\n `Stage: ${stageLabel(record)}`,\n 'Raw launcher output is hidden from chat. Use action follow or open to view it.',\n ].join('\\n');\n },\n openRun: async (input, ctx) => {\n const record = await requireRun(input, ctx.sessionManager.getSessionId());\n await getTelemetry(ctx).recordEvent('doom_workflow.open_requested', { outcome: 'requested' });\n // Without a UI there is nothing to foreground, so fall back to handing\n // the user's own terminal to the launcher.\n if (!ctx.hasUI) return openLauncher(record);\n return openOverlay(record, ctx);\n },\n rejectRunner,\n };\n\n let disposeLeaderActions: (() => void) | undefined;\n services.push((cordis: Context) => {\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const dispose = requireDoomUiHub(uiContext).registerLeaderActions<ExtensionContext>({\n source: PACKAGE_SOURCE,\n handlers: {\n [LEADER_ENABLE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return applyWorkflowMode(true, ctx);\n },\n [LEADER_DISABLE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return applyWorkflowMode(false, ctx);\n },\n [LEADER_MANAGE_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openInspector(ctx, true);\n },\n [LEADER_CATALOG_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openWorkflowCatalog(ctx);\n },\n [LEADER_RECOVER_ACTION]: async (ctx) => {\n await waitForReadiness();\n return openRecoveryHandoff(ctx);\n },\n },\n onError: (error, _actionName, ctx) => {\n ctx.ui.notify(error instanceof Error ? error.message : String(error), 'error');\n },\n });\n disposeLeaderActions = dispose;\n return () => {\n dispose();\n if (disposeLeaderActions === dispose) disposeLeaderActions = undefined;\n };\n });\n });\n\n const onSessionStart: NonNullable<PiEventHandlers['session_start']> = (_event, ctx) => {\n if (!runtimeActive || !invocationActive()) return;\n const generation = ++sessionGeneration;\n const previousReadiness = readinessHandle;\n readinessAbort?.abort();\n const ownReadinessAbort = new AbortController();\n readinessAbort = ownReadinessAbort;\n sessionCtx = ctx;\n const ownsSession = (): boolean =>\n runtimeActive && generation === sessionGeneration && sessionCtx === ctx && invocationActive();\n\n // A second start retires every resource tied to the previous context\n // before this context can publish its own state.\n const retireSessionResources = (): void => {\n stopRunControl();\n if (monitorTimer) clearInterval(monitorTimer);\n monitorTimer = undefined;\n runProvider?.update([]);\n clearFollow(ctx);\n inspectorHandle?.hide();\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n closeOverlay();\n terminals.forget(new Set());\n progressOverlay.setUICtx(ctx.ui);\n };\n if (options.runCleanup) options.runCleanup(retireSessionResources);\n else retireSessionResources();\n\n const activeTelemetry = getTelemetry(ctx);\n void activeTelemetry.recordEvent('doom_workflow.session_started', {\n mode: options.environment.WORKFLOW_MCP_MODE === 'on' ? 'on' : 'off',\n outcome: 'started',\n });\n\n // Tools registered during extension init are auto-activated by Pi, so the\n // default-off state has to be applied here rather than by not registering.\n // WORKFLOW_MCP_MODE=on is the non-interactive dispatcher path.\n const sessionId = ctx.sessionManager.getSessionId();\n const rootSessionId = resolveRootSessionId(sessionId, options.environment);\n observeSession(rootSessionId);\n sessionStartedAt = Date.now();\n lifecycleNarrationReady = false;\n previousStages = new Map<string, WorkflowStage>();\n pendingTerminalRuns.clear();\n deliveredTerminalRuns.clear();\n setWorkflowMode(options.initialMode ?? options.environment.WORKFLOW_MCP_MODE === 'on');\n\n const coordinator = readinessCoordinator(ctx);\n readinessHandle = (async (): Promise<DoomReadinessHandle<void>> => {\n if (previousReadiness) {\n await Promise.allSettled([previousReadiness.then((handle) => handle.wait())]);\n }\n if (!ownsSession()) throw new Error('Workflow session initialization was superseded.');\n return coordinator.start(PACKAGE_SOURCE, `${runtimeGeneration}:${generation}`, async (signal) => {\n const retired = (): boolean => ownReadinessAbort.signal.aborted || !ownsSession();\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n\n // Subscribed before the first status read, so a transition landing\n // during startup is delivered rather than raced past.\n await startRunControl(ctx);\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n await refreshStatus(ctx, false);\n signal.throwIfAborted();\n if (retired()) return { value: undefined };\n lifecycleNarrationReady = true;\n // A fallback now, not the mechanism: the observer reports a change\n // within its own debounce, and this only bounds how long a change\n // nothing notified us about stays invisible.\n monitorTimer = setInterval(() => {\n if (ownsSession()) void refreshStatus(ctx, true);\n }, monitorIntervalMs);\n monitorTimer.unref?.();\n return { value: undefined };\n });\n })();\n // The coordinator host owns the single user-facing failure notification;\n // this observer only ensures an idle failed task is still handled.\n void Promise.allSettled([readinessHandle.then((handle) => handle.wait())]);\n };\n\n const runCleanup = async (label: string, cleanup: () => void | Promise<void>): Promise<void> => {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-workflow cleanup could not ${label}: ${String(error)}`);\n }\n };\n\n let disposal: Promise<void> | undefined;\n const dispose = (context: ExtensionContext | undefined = sessionCtx): Promise<void> => {\n disposal ??= (async () => {\n if (!runtimeActive) return;\n runtimeActive = false;\n sessionGeneration += 1;\n const pendingReadiness = readinessHandle;\n readinessHandle = undefined;\n readinessAbort?.abort();\n readinessAbort = undefined;\n await runCleanup('stop the workflow observer', stopRunControl);\n const ownedReadiness = standaloneReadiness;\n standaloneReadiness = undefined;\n if (ownedReadiness) {\n await runCleanup('dispose standalone workflow readiness', () => ownedReadiness.dispose());\n } else if (pendingReadiness) {\n await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);\n }\n\n // A workflow without a `launch-command` runs its engine inside this\n // process. Interrupt it and wait only for the bounded finalization path.\n if (pendingInlineRuns.size > 0) {\n for (const service of [runService, recoverService]) {\n await runCleanup('interrupt an inline workflow', () =>\n service.interrupt('SIGTERM', { phase: 'workflow', source: 'pi-session-shutdown' }),\n );\n }\n await Promise.race([\n Promise.allSettled(pendingInlineRuns),\n new Promise((settle) => setTimeout(settle, SHUTDOWN_FINALIZE_TIMEOUT_MS).unref?.()),\n ]);\n }\n if (monitorTimer) clearInterval(monitorTimer);\n monitorTimer = undefined;\n if (statusRefreshTimer) clearTimeout(statusRefreshTimer);\n statusRefreshTimer = undefined;\n const provider = runProvider;\n runProvider = undefined;\n if (provider) await runCleanup('unregister the background-work provider', () => provider.dispose());\n lifecycleNarrationReady = false;\n inspectorHandle?.hide();\n inspectorHandle = undefined;\n inspectorOpen = false;\n inspectorRecords.clear();\n terminals.forget(new Set());\n closeOverlay();\n sessionRunCount = 0;\n if (context) clearFollow(context);\n else if (followTimer) clearInterval(followTimer);\n followTimer = undefined;\n followedRun = undefined;\n progressOverlay.dispose();\n workflowMode = false;\n publishedWorkflowState = undefined;\n const mode = modeContribution;\n\n if (mode) {\n await runCleanup('publish the inactive workflow mode', () => mode.publish());\n await runCleanup('dispose the workflow mode owner', () => mode.detach());\n }\n const leaderActions = disposeLeaderActions;\n disposeLeaderActions = undefined;\n if (leaderActions) await runCleanup('dispose workflow leader actions', leaderActions);\n const pendingCount = pendingInlineRuns.size;\n const activeTelemetry = telemetry;\n telemetry = undefined;\n if (activeTelemetry) {\n await runCleanup('record the workflow session finish', () =>\n activeTelemetry.recordEvent('doom_workflow.session_finished', {\n 'workflow.pending_count': pendingCount,\n outcome: pendingCount === 0 ? 'completed' : 'interrupted',\n }),\n );\n await runCleanup('stop workflow telemetry', () => activeTelemetry.shutdown());\n }\n pendingInlineRuns.clear();\n pendingTerminalRuns.clear();\n deliveredTerminalRuns.clear();\n announcedRuns.length = 0;\n knownSessionId = undefined;\n sessionCtx = undefined;\n })();\n return disposal;\n };\n\n return {\n dispose,\n commands,\n messageRenderers,\n toolDependencies,\n waitForReadiness,\n services: [...(services ?? []), piMinorModes([modeContribution])],\n shortcuts: [\n [\n UNFOLLOW_SHORTCUT,\n {\n description: 'Open workflows or move typing between a workflow run and this session',\n handler: async (ctx) => {\n await waitForReadiness();\n // With a panel up this is a focus toggle, not a dismissal: the run stays\n // visible either way, and the user is only choosing who receives keys.\n const handle = activeOverlay?.handle;\n if (handle) {\n // pi-tui's `focus()` does not honour `nonCapturing`, so a view-only\n // panel would take the keyboard if this were left to fall through,\n // and every key after it would vanish into a run that cannot hear it.\n if (!activeOverlay?.interactive) {\n ctx.ui.notify('This run is hosted natively, so the view takes no typing. Your keys stay here.', 'info');\n return;\n }\n if (handle.isFocused()) {\n handle.unfocus();\n ctx.ui.notify('Typing goes to this session. The run keeps going.', 'info');\n } else {\n handle.focus();\n ctx.ui.notify(`Typing goes to ${activeOverlay?.runKey}.`, 'info');\n }\n return;\n }\n if (followedRun) {\n clearFollow(ctx);\n ctx.ui.notify('Workflow continues in the background.', 'info');\n return;\n }\n await openInspector(ctx);\n },\n },\n ],\n [\n CLOSE_OVERLAY_SHORTCUT,\n {\n description: 'Close the workflow run view',\n handler: async (ctx) => {\n await waitForReadiness();\n // Guarded so the key falls through to Pi when no panel is up.\n if (!activeOverlay) return;\n const runKey = activeOverlay.runKey;\n closeOverlay();\n ctx.ui.notify(`Closed the ${runKey} view. The run keeps going.`, 'info');\n },\n },\n ],\n ],\n events: { session_start: onSessionStart, resources_discover: onResourcesDiscover },\n\n toolRestrictions: [\n {\n source: PACKAGE_SOURCE,\n get restrict() {\n return workflowToolRestriction(workflowMode);\n },\n subscribe(listener) {\n restrictionListeners.add(listener);\n return () => {\n restrictionListeners.delete(listener);\n };\n },\n },\n ],\n };\n}\n","import type { PiPluginContext, PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { definePiTool } from '@agimon-ai/doompi-core/piExtension';\nimport { DOOM_SKILL_SOURCES_SERVICE, requireDoomSkillSourcesService } from '@agimon-ai/doompi-core/skills';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-core/uiHub';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport { PACKAGE_SOURCE } from '../../../../../constants/workflow';\nimport {\n createWorkflowFence,\n dispatcherTools,\n dispatcherToolRestriction,\n isWorkflowDispatcherProcess,\n resolveDispatcherParentSession,\n} from '../../../../../services/workflowFence';\nimport { workflowSkillDirectory } from '../../../../../services/workflowResource';\nimport { createWorkflowTools } from '../../../../../services/workflowTools';\nimport { registerLeaderContribution } from '../../../../../tui/leader';\nimport { renderWorkflowToolCall, renderWorkflowToolResult } from '../../../../../tui/workflow/workflowToolRender';\nimport { createWorkflowPiRuntime, type WorkflowPiExtensionOptions } from '../../../../../tui/workflowRuntime';\n\nexport default (({ pi, context, options, signal }) => {\n const environment = options?.environment ?? Object.freeze({ ...process.env });\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const fence = createWorkflowFence(pi, signal);\n let workflowMode = false;\n let leader: ReturnType<typeof registerLeaderContribution> | undefined;\n const runtime = createWorkflowPiRuntime(fence.pi, {\n ...options,\n environment,\n cordis: context,\n initialMode: dispatcher || options?.initialMode,\n isActive: fence.isCurrentInvocation,\n runCleanup: fence.runCleanup,\n onModeChange(enabled) {\n workflowMode = enabled;\n leader?.setMode(enabled);\n options?.onModeChange?.(enabled);\n },\n });\n const nativeTools = createWorkflowTools(runtime.toolDependencies, (name) => ({\n renderCall: (args, theme) => renderWorkflowToolCall(name, args as Record<string, unknown>, theme),\n renderResult: (result, renderOptions, theme, renderContext) =>\n renderWorkflowToolResult(\n name,\n renderContext.args as Record<string, unknown>,\n result,\n { ...renderOptions, isError: renderContext.isError },\n theme,\n ),\n }));\n const selectedTools = dispatcher\n ? dispatcherTools(nativeTools, resolveDispatcherParentSession(environment), environment)\n : nativeTools;\n return {\n services: [\n ...(runtime.services ?? []),\n (cordis: Context) => {\n cordis.inject([DOOM_SKILL_SOURCES_SERVICE], (skillContext) => {\n const directory = workflowSkillDirectory();\n const contribution = requireDoomSkillSourcesService(skillContext).register({\n source: PACKAGE_SOURCE,\n directories: [directory],\n });\n return () => contribution.dispose();\n });\n if (!dispatcher)\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = registerLeaderContribution(requireDoomUiHub(uiContext), workflowMode);\n leader = contribution;\n return () => {\n contribution.dispose();\n if (leader === contribution) leader = undefined;\n };\n });\n },\n ],\n tools: selectedTools.map((tool) =>\n definePiTool(\n fence.tool({\n ...tool,\n async execute(...args) {\n await runtime.waitForReadiness(args[2]);\n return tool.execute(...args);\n },\n }),\n ),\n ),\n commands: runtime.commands.map(([name, command]) => fence.command(name, command)),\n shortcuts: runtime.shortcuts?.map(([key, shortcut]) => fence.shortcut(key, shortcut)),\n events: fence.events(runtime.events ?? {}),\n\n toolRestrictions: [\n ...(runtime.toolRestrictions ?? []),\n ...(dispatcher ? [{ source: `${PACKAGE_SOURCE}/dispatcher`, restrict: dispatcherToolRestriction() }] : []),\n ],\n resources: dispatcher\n ? []\n : [\n {\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-workflow',\n description: 'Author DoomPi workflow definitions, job dependencies and host-executed steps.',\n },\n {\n name: 'doompi-use-workflow',\n description: 'Discover, launch, monitor, control and recover DoomPi workflow runs.',\n },\n ],\n },\n ],\n async onStop() {\n fence.beginDisposal();\n await fence.runCleanup(() => runtime.dispose());\n },\n async onDispose() {\n fence.beginDisposal();\n try {\n await fence.runCleanup(() => runtime.dispose());\n } finally {\n fence.finishDisposal();\n }\n },\n };\n}) satisfies (\n context: PiPluginContext<Partial<WorkflowPiExtensionOptions>>,\n) => PiPluginContributions<Partial<WorkflowPiExtensionOptions>>;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from './_lib/index.cli';\n\nexport default defineRoot((context: Parameters<typeof runtime>[0]) => {\n const value = runtime(context);\n return {\n value,\n services: value.services,\n onStop: () => value.onStop(),\n onDispose: () => value.onDispose(),\n };\n});\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.commands[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport type { PiEventHandlers } from '@agimon-ai/doompi-core/piExtension';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (\n context: WithRoot<unknown, ReturnType<typeof runtime>>,\n ): NonNullable<PiEventHandlers['resources_discover']> | undefined => context.root.events?.resources_discover,\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.events?.session_start,\n { cardinality: 'optional' },\n);\n","import type { PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\n\nexport function workflowSkillsResource(\n resources: PiPluginContributions['resources'],\n moduleUrl: string,\n): NonNullable<PiPluginContributions['resources']>[number] | undefined {\n const resource = resources?.[0];\n return resource ? { ...resource, moduleUrl } : undefined;\n}\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\nimport { workflowSkillsResource } from '../_lib/workflowSkillsResource';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) =>\n workflowSkillsResource(context.root.resources, import.meta.url),\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.shortcuts?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.shortcuts?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.toolRestrictions,\n { cardinality: 'many' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.cli';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools,\n { cardinality: 'many' },\n);\n","/**\n * Renders the `workflow-run-finished` custom message: one line per run that\n * reached a terminal state, rather than the host's default block of the\n * `[workflow-run-finished]` label above raw markdown.\n *\n * The same shape `@agimon-ai/doompi-team` gives a slash launch: a status glyph,\n * the run's identity, its outcome, and anything that went wrong indented under\n * it. A finished run is read at a glance in a transcript that is mostly about\n * something else, so it earns a line, not a card.\n *\n * DESIGN PATTERNS:\n * - A message with no `details` renders its content verbatim. That is a\n * transcript entry written before the field existed, and re-deriving it by\n * parsing the summary back out of markdown is exactly the liability\n * `completionNotice.ts` in the team package refused to port\n * - The full summary is still the message's `content`, which is what the model\n * reads and what `deliverAs: 'steer'` carries. This changes what a person\n * sees, never what the agent is told\n */\n\nimport type { ExtensionAPI, Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, Text } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_FINISHED_MESSAGE = 'workflow-run-finished';\n\n/** One finished run, as the extension records it on the message. */\nexport interface WorkflowFinishedRun {\n runKey: string;\n workspace: string;\n stage: string;\n workflowId?: string;\n failedJob?: string;\n error?: string;\n}\n\nexport interface WorkflowFinishedDetails {\n /** Kept for readers that already index runs by id; the lines come from `runs`. */\n runIds?: string[];\n runs?: WorkflowFinishedRun[];\n}\n\nconst COMPLETED_STAGE = 'completed';\nconst HELD_STAGES = new Set(['stopped', 'paused', 'cancelled']);\n\nfunction statusIcon(stage: string, theme: Theme): string {\n if (stage === COMPLETED_STAGE) return theme.fg('success', '✔');\n // Held is not failed: the run went nowhere wrong, it just stopped short.\n if (HELD_STAGES.has(stage)) return theme.fg('warning', '■');\n return theme.fg('error', '✖');\n}\n\nfunction runLine(run: WorkflowFinishedRun, theme: Theme): string {\n const separator = ` ${theme.fg('dim', '·')} `;\n const identity = [run.runKey, run.workspace].filter(Boolean).join('/');\n const parts = [theme.fg('dim', identity), theme.fg('dim', run.stage)];\n if (run.workflowId) parts.unshift(theme.bold(run.workflowId));\n let text = `${statusIcon(run.stage, theme)} ${parts.join(separator)}`;\n if (run.failedJob) text += `\\n ${theme.fg('dim', `⎿ failed job: ${run.failedJob}`)}`;\n if (run.error) text += `\\n ${theme.fg('dim', `⎿ ${run.error}`)}`;\n return text;\n}\n\n/**\n * Exported for tests: the rendered string before it is wrapped in a `Text`\n * component, so the formatting is assertable without a terminal.\n */\nexport function renderWorkflowFinished(runs: readonly WorkflowFinishedRun[], theme: Theme): string {\n return runs.map((run) => runLine(run, theme)).join('\\n');\n}\n\nexport function isWorkflowFinishedRuns(value: unknown): value is WorkflowFinishedRun[] {\n if (!Array.isArray(value) || value.length === 0) return false;\n return value.every(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as WorkflowFinishedRun).runKey === 'string' &&\n typeof (entry as WorkflowFinishedRun).stage === 'string',\n );\n}\n\nexport function createWorkflowFinishedRenderer(): readonly [...Parameters<ExtensionAPI['registerMessageRenderer']>] {\n return [\n WORKFLOW_FINISHED_MESSAGE,\n (message, _options, theme: Theme): Component => {\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n const runs = (message.details as WorkflowFinishedDetails | undefined)?.runs;\n if (!isWorkflowFinishedRuns(runs)) return new Text(content, 0, 0);\n return new Text(renderWorkflowFinished(runs, theme), 0, 0);\n },\n ];\n}\n","import { defineMessageRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { createWorkflowFinishedRenderer } from './_lib/workflowFinishedRenderer';\n\nexport default defineMessageRenderer(...createWorkflowFinishedRenderer());\n","import type { PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport type { Theme } from '@earendil-works/pi-coding-agent';\nimport { Box, type Component, Text, truncateToWidth } from '@earendil-works/pi-tui';\n\nexport const LEGACY_WORKFLOW_STEP_MESSAGE = 'workflow-step';\n\ninterface WorkflowStepMessageDetails {\n displayName: string;\n duration?: string;\n job: string;\n status: 'STARTED' | 'FINISHED' | 'FAILED';\n step: string;\n}\n\nfunction isWorkflowStepMessageDetails(value: unknown): value is WorkflowStepMessageDetails {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Partial<WorkflowStepMessageDetails>;\n return (\n typeof candidate.displayName === 'string' &&\n typeof candidate.job === 'string' &&\n typeof candidate.step === 'string' &&\n (candidate.status === 'STARTED' || candidate.status === 'FINISHED' || candidate.status === 'FAILED') &&\n (candidate.duration === undefined || typeof candidate.duration === 'string')\n );\n}\n\nclass WorkflowStepMessageLines implements Component {\n constructor(\n private readonly details: WorkflowStepMessageDetails,\n private readonly theme: Theme,\n ) {}\n\n render(width: number): string[] {\n const header = `${this.theme.fg('accent', `[${this.details.displayName}]:`)} ${this.details.job}`;\n const transition = this.details.duration\n ? `${this.details.status}::${this.details.duration}::${this.details.step}`\n : `${this.details.status}::${this.details.step}`;\n const colour =\n this.details.status === 'FAILED' ? 'error' : this.details.status === 'FINISHED' ? 'success' : 'accent';\n return [truncateToWidth(header, width), truncateToWidth(this.theme.fg(colour, transition), width)];\n }\n\n invalidate(): void {}\n}\n\nfunction renderWorkflowStepMessage(\n details: WorkflowStepMessageDetails | undefined,\n fallback: string,\n outputPad: number,\n theme: Theme,\n): Component {\n const box = new Box(outputPad, 1, (text) => theme.bg('customMessageBg', text));\n box.addChild(details ? new WorkflowStepMessageLines(details, theme) : new Text(fallback, 0, 0));\n return box;\n}\n\nexport const workflowStepRenderer: NonNullable<PiPluginContributions['messageRenderers']>[number][1] = (\n message,\n { outputPad },\n theme,\n) => {\n const details = isWorkflowStepMessageDetails(message.details) ? message.details : undefined;\n const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n return renderWorkflowStepMessage(details, content, outputPad, theme);\n};\n","import { defineMessageRenderer } from '@agimon-ai/doompi-core/piExtension';\n\nimport { LEGACY_WORKFLOW_STEP_MESSAGE, workflowStepRenderer } from './_lib/workflowStepRenderer';\n\nexport default defineMessageRenderer(LEGACY_WORKFLOW_STEP_MESSAGE, workflowStepRenderer);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { definePiExtension, piToolContributions, type PiPluginContext, type PiPluginContributions } from '@agimon-ai/doompi-core/piExtension';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.cli';\nimport commandWorkflowLaunch from '../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.cli';\nimport hookResourcesDiscover from '../src/extensions/workspaces/sessions/(backend)/hook/resources-discover.cli';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.cli';\nimport resourceWorkflowSkills from '../src/extensions/workspaces/sessions/(backend)/resource/workflow-skills.cli';\nimport shortcutWorkflowPanel from '../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-panel.cli';\nimport shortcutWorkflowViewClose from '../src/extensions/workspaces/sessions/(backend)/shortcut/workflow-view-close.cli';\nimport toolRestrictionWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool-restriction/workflow.cli';\nimport toolWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool/workflow.cli';\nimport messageWorkflowFinished from '../src/extensions/workspaces/sessions/(frontend)/message/workflow-finished.cli';\nimport messageWorkflowStep from '../src/extensions/workspaces/sessions/(frontend)/message/workflow-step.cli';\n\ntype OptionsOf<T> = T extends (context: PiPluginContext<infer Options>) => unknown ? Options : never;\ntype InferredOptions = Exclude<OptionsOf<typeof rootSession> | OptionsOf<typeof commandWorkflowLaunch> | OptionsOf<typeof hookResourcesDiscover> | OptionsOf<typeof hookSessionStart> | OptionsOf<typeof resourceWorkflowSkills> | OptionsOf<typeof shortcutWorkflowPanel> | OptionsOf<typeof shortcutWorkflowViewClose> | OptionsOf<typeof toolRestrictionWorkflow> | OptionsOf<typeof toolWorkflow> | OptionsOf<typeof messageWorkflowFinished> | OptionsOf<typeof messageWorkflowStep>, undefined>;\ntype Intersect<Union> =\n (Union extends unknown ? (value: Union) => void : never) extends (value: infer Value) => void ? Value : never;\ntype ExtensionOptions = [InferredOptions] extends [never] ? undefined : Intersect<InferredOptions>;\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\ntype ManyFactory<T, C> = (context: C) => T | readonly T[];\nconst many = <T, C>(value: T | readonly T[] | ManyFactory<T, C>, context: C): readonly T[] => {\n const resolved = typeof value === 'function' ? (value as ManyFactory<T, C>)(context) : value;\n return Array.isArray(resolved) ? resolved : [resolved as T];\n};\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n/* v8 ignore next -- generated normalization branch */\nconst keyed = <T>(key: string, value: T | undefined): Record<string, T> =>\n value === undefined ? {} : { [key]: value };\n\nexport const extension = definePiExtension<ExtensionOptions>('@agimon-ai/doompi-workflow', async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get commands(): PiPluginContributions['commands'] { return defined([at(commandWorkflowLaunch, contextSession)]); },\n events: {\n ...keyed('resources_discover', at(hookResourcesDiscover, contextSession) as NonNullable<PiPluginContributions['events']>['resources_discover']),\n ...keyed('session_start', at(hookSessionStart, contextSession) as NonNullable<PiPluginContributions['events']>['session_start']),\n },\n get messageRenderers(): PiPluginContributions['messageRenderers'] { return [at(messageWorkflowFinished, contextSession), at(messageWorkflowStep, contextSession)]; },\n get resources(): PiPluginContributions['resources'] { return defined([at(resourceWorkflowSkills, contextSession)]); },\n get shortcuts(): PiPluginContributions['shortcuts'] { return defined([at(shortcutWorkflowPanel, contextSession), at(shortcutWorkflowViewClose, contextSession)]); },\n get toolRestrictions(): PiPluginContributions['toolRestrictions'] { return [...many(toolRestrictionWorkflow, contextSession)]; },\n ...piToolContributions('@agimon-ai/doompi-workflow', [...many(toolWorkflow, contextSession)]),\n services: [...(scopeSession.services ?? [])],\n };\n});\n\nexport default extension;\n"],"mappings":"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"}
|