@agimon-ai/doompi-workflow 0.0.1-alpha.89 → 0.0.1-alpha.90
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":"server.cjs","names":["readWorkflowCatalog","summarizeWorkflow","statSync","resolve","os","path","fs","createEmbeddedWorkflowFeature","defineMinorMode","serverMinorModes","registerRunProvider","skill","z","resolve","parseWorkflowLaunchCommand","resolveWorkflowEntry","validateWorkflowLaunch","defineApiRoutes","apiResponse","WorkflowRegistryService","WorkflowTerminalFacade","createWorkflowTerminalService","Hono","routes","streamSSE","randomUUID","path","fs","Readable","defineRoot","runtime","defineRoutedContribution","legacy","defineChannel","defineChannel","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineServerPlugin","apiRoute","channelWorkflowCatalog","channelWorkflows","rootSession","composeRootHooks","apiRoute2","commandWorkflowLaunch","hookSessionShutdown","hookToolExecutionEnd","resourceDoompiAuthorWorkflow","resourceDoompiUseWorkflow","resourceWorkflowRecovery","toolLaunchWorkflow","toolListWorkflows","toolWorkflowRun"],"sources":["../../src/services/webWorkflowCatalog/index.ts","../../src/services/workflowCatalogDeps/index.ts","../../src/services/workflowRuns/index.ts","../../src/services/workflowWatcher/index.ts","../../src/types/webWorkflows.ts","../../src/services/serverRuntime/index.ts","../../src/types/apiRoutes.ts","../../src/types/webWorkflowTerminal.ts","../../src/services/workflowHubApi/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/index.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/services/workflowCatalogChannel/index.ts","../../src/services/workflowsHubChannel/index.ts","../../src/extensions/(backend)/_lib/index.server.ts","../../src/extensions/(backend)/api/workflow/route.server.ts","../../src/extensions/(backend)/channel/workflow-catalog.server.ts","../../src/extensions/(backend)/channel/workflows.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.ts","../../generated/server.ts"],"sourcesContent":["import type {\n WorkflowCatalogArtifactView,\n WorkflowCatalogEntryView,\n WorkflowCatalogInputView,\n WorkflowCatalogJobView,\n} from '../../types/webWorkflows';\n/**\n * The cockpit's view of the workflows a session can launch.\n *\n * The engine already reads a repository's workflow files and parses one of\n * them into triggers, inputs, jobs, artifacts and compatible runners, so this\n * module only shapes that answer for the wire and remembers what it read.\n *\n * WHY A CACHE:\n * A session reads the catalog for its initial projection and when its lifecycle\n * publishes a workflow update. Entries are kept per path and reused while the\n * file's size and modification time are unchanged, which is the same test a\n * build tool makes and costs one stat per file.\n */\n\n/** What the engine reports for one workflow file before it is parsed. */\nexport interface CatalogListEntry {\n path: string;\n relativePath: string;\n name: string;\n description: string;\n tags: string[];\n}\n\n/** One file's parsed detail, or the reason it could not be read. */\nexport interface CatalogDetail {\n triggers: string[];\n inputs: WorkflowCatalogInputView[];\n jobs: WorkflowCatalogJobView[];\n artifacts: WorkflowCatalogArtifactView[];\n runners?: string[];\n error?: string;\n}\n\n/** What a file looked like when it was last parsed. */\nexport interface CatalogFileStamp {\n size: number;\n modifiedAt: number;\n}\n\nexport interface WorkflowCatalogReaderDeps {\n /** Every workflow file under a directory. */\n list(directory: string): Promise<CatalogListEntry[]>;\n /** One file's parsed detail; never throws, so a bad file cannot empty a board. */\n summarize(path: string): CatalogDetail;\n /** Size and modification time, or undefined when the file is gone. */\n stamp(path: string): CatalogFileStamp | undefined;\n}\n\ninterface CachedEntry {\n stamp: CatalogFileStamp;\n detail: CatalogDetail;\n}\n\n/** Reads one directory's catalog, reusing what it parsed last time. */\nexport interface WorkflowCatalogReader {\n read(directory: string): Promise<WorkflowCatalogEntryView[]>;\n /** Drops what was parsed for files no longer listed, so a cache cannot grow forever. */\n forget(keep: ReadonlySet<string>): void;\n}\n\nfunction unchanged(left: CatalogFileStamp | undefined, right: CatalogFileStamp | undefined): boolean {\n return left !== undefined && right !== undefined && left.size === right.size && left.modifiedAt === right.modifiedAt;\n}\n\nexport function createWorkflowCatalogReader(deps: WorkflowCatalogReaderDeps): WorkflowCatalogReader {\n const cache = new Map<string, CachedEntry>();\n\n const detailFor = (path: string): CatalogDetail => {\n const stamp = deps.stamp(path);\n const cached = cache.get(path);\n if (cached && unchanged(cached.stamp, stamp)) return cached.detail;\n const detail = deps.summarize(path);\n // A file that vanished between listing and stat is parsed anyway, which\n // answers with its own error; it just cannot be cached against a stamp.\n if (stamp !== undefined) cache.set(path, { stamp, detail });\n return detail;\n };\n\n return {\n async read(directory) {\n const listed = await deps.list(directory);\n return listed.map((entry) => {\n const detail = detailFor(entry.path);\n return {\n path: entry.path,\n relativePath: entry.relativePath,\n name: entry.name === '' ? entry.relativePath : entry.name,\n description: entry.description,\n tags: entry.tags,\n triggers: detail.triggers,\n inputs: detail.inputs,\n jobs: detail.jobs,\n artifacts: detail.artifacts,\n ...(detail.runners === undefined ? {} : { runners: detail.runners }),\n ...(detail.error === undefined ? {} : { error: detail.error }),\n };\n });\n },\n forget(keep) {\n for (const path of cache.keys()) {\n if (!keep.has(path)) cache.delete(path);\n }\n },\n };\n}\n\n/** The launchable rows first, then the ones that would not parse, name ordered. */\nexport function presentWorkflowCatalog(entries: readonly WorkflowCatalogEntryView[]): WorkflowCatalogEntryView[] {\n return [...entries].sort((left, right) => {\n if ((left.error === undefined) !== (right.error === undefined)) return left.error === undefined ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n}\n","import { statSync } from 'node:fs';\n\nimport { readWorkflowCatalog, summarizeWorkflow } from '@agimon-ai/workflow-mcp';\n\nimport type { WorkflowCatalogReaderDeps } from '../webWorkflowCatalog';\n\n/** Connect the pure catalog projection service to the workflow engine and filesystem. */\nexport function defaultCatalogDeps(): WorkflowCatalogReaderDeps {\n return {\n list: (directory) => readWorkflowCatalog(directory),\n summarize: (workflowPath) => summarizeWorkflow(workflowPath),\n stamp: (workflowPath) => {\n try {\n const stats = statSync(workflowPath);\n return { size: stats.size, modifiedAt: stats.mtimeMs };\n } catch {\n return undefined;\n }\n },\n };\n}\n","import { resolve } from 'node:path';\n\nimport type {\n WorkflowJobPhase,\n WorkflowJobView,\n WorkflowOutcome,\n WorkflowPosition,\n WorkflowProgressState,\n WorkflowRunView,\n WorkflowStage,\n WorkflowStepView,\n} from '../../types/webWorkflows';\n\n/**\n * MIRRORS @agimon-ai/workflow-mcp's on-disk registry\n * (src/services/WorkflowRegistryService.ts and WorkflowProgressService.ts in\n * that package). The engine keeps one directory per run under\n * `<home>/workspaces/<workspace>/<stage>/<runKey>/` holding a `run.json`\n * record and an append-only `progress.ndjson` job/step log; the hub only ever\n * reads them. The derivation is duplicated rather than imported because\n * doompi-web must not depend on the engine at runtime; the unit suite pins\n * this mirror against the package's published types.\n */\nconst DEFAULT_WORKFLOW_HOME_DIR_NAME = '.workflow-mcp';\nexport const WORKFLOW_HOME_ENV = 'WORKFLOW_MCP_HOME';\nexport const WORKSPACES_DIR_NAME = 'workspaces';\nexport const RUN_RECORD_FILE_NAME = 'run.json';\nexport const PROGRESS_FILE_NAME = 'progress.ndjson';\nexport const WORKFLOW_STAGES: readonly WorkflowStage[] = ['running', 'completed', 'error'];\n\n/**\n * Errored runs stay a day, which is how long recovery has to act on them.\n *\n * Finished runs have no retention of their own: a session keeps every run it\n * launched, grouped by outcome, for as long as the session lives. A run leaves\n * the view when the engine prunes its registry directory, not on a timer here,\n * because \"what did this session run today\" is a question asked long after the\n * run settled.\n */\nexport const WORKFLOW_ERROR_RETENTION_MS = 24 * 60 * 60 * 1000;\n/**\n * Upper bound per outcome group rather than over the whole list.\n *\n * One cap across every run let a long stream of green runs push a failure out\n * of the list, which is the one thing that must never fall off the end.\n */\nexport const MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP = 24;\n\n/** The env key doompi-workflow stamps on runs it launches; ties a run to a Pi session. */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\nconst PROGRESS_STATES: ReadonlySet<string> = new Set([\n 'running',\n 'completed',\n 'skipped',\n 'failed',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\nconst OUTCOMES: ReadonlySet<string> = new Set(['success', 'skipped', 'failed', 'interrupted']);\nconst EXECUTION_STATES: ReadonlySet<string> = new Set(['running', 'pause_requested', 'paused', 'resume_requested']);\nconst STEP_TERMINAL_STATES: ReadonlySet<WorkflowProgressState> = new Set(['completed', 'skipped', 'failed']);\n/** The engine records its pre:/post: blocks under these reserved pseudo-job names. */\nconst PHASE_JOB_PRE = 'pre';\nconst PHASE_JOB_POST = 'post';\n\n// oxlint-disable-next-line no-control-regex -- stripping terminal color codes from errorMessage is the point\nconst ANSI_ESCAPE_PATTERN = /\\u001b\\[[0-9;]*[A-Za-z]/g;\n\nexport interface WorkflowHomeInput {\n /** process.env.WORKFLOW_MCP_HOME, supplied by the caller. */\n envValue: string | undefined;\n /** os.homedir(), supplied by the caller. */\n homeDir: string;\n}\n\n/** Where workflow-mcp keeps its registry, mirroring the engine's own resolution. */\nexport function resolveWorkflowHome(input: WorkflowHomeInput): string {\n return resolve(\n input.envValue !== undefined && input.envValue !== ''\n ? input.envValue\n : resolve(input.homeDir, DEFAULT_WORKFLOW_HOME_DIR_NAME),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n\nfunction asOptionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stripAnsi(text: string): string {\n return text.replace(ANSI_ESCAPE_PATTERN, '').trim();\n}\n\n/**\n * One run record plus the facts the hub needs for session scoping but the\n * page never sees.\n */\nexport interface ParsedWorkflowRun {\n /** The wire view, before the progress log is folded in (jobs empty). */\n view: WorkflowRunView;\n /** env.PI_SESSION_ID from the record, when the launcher stamped one. */\n piSessionId?: string;\n}\n\n/**\n * Validates one run.json into the wire shape plus scoping facts.\n *\n * Returns undefined for anything unreadable or a foreign format. The record\n * is trusted for its own stage: the registry rewrites it when a run moves\n * between stage directories.\n */\nexport function parseWorkflowRunRecord(raw: string): ParsedWorkflowRun | undefined {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const runKey = asOptionalString(parsed.runKey);\n const workspace = asOptionalString(parsed.workspace);\n const workflowPath = asOptionalString(parsed.workflowPath);\n const startedAt = asOptionalString(parsed.startedAt);\n const stage = asOptionalString(parsed.stage);\n if (!runKey || !workspace || !workflowPath || !startedAt) return undefined;\n if (stage === undefined || !WORKFLOW_STAGES.includes(stage as WorkflowStage)) return undefined;\n\n const outcome = asOptionalString(parsed.outcome);\n const executionState = asOptionalString(parsed.executionState);\n const rawError = asOptionalString(parsed.errorMessage);\n const env = isRecord(parsed.env) ? parsed.env : undefined;\n const view: WorkflowRunView = {\n runKey,\n workspace,\n displayName: asOptionalString(parsed.displayName) ?? runKey,\n ...(asOptionalString(parsed.workflowName) === undefined\n ? {}\n : { workflowName: asOptionalString(parsed.workflowName) }),\n workflowPath,\n stage: stage as WorkflowStage,\n ...(outcome !== undefined && OUTCOMES.has(outcome) ? { outcome: outcome as WorkflowOutcome } : {}),\n ...(executionState !== undefined && EXECUTION_STATES.has(executionState)\n ? { executionState: executionState as WorkflowRunView['executionState'] }\n : {}),\n ...(asOptionalString(parsed.prompt) === undefined ? {} : { prompt: asOptionalString(parsed.prompt) }),\n startedAt,\n ...(asOptionalString(parsed.finishedAt) === undefined ? {} : { finishedAt: asOptionalString(parsed.finishedAt) }),\n ...(rawError === undefined ? {} : { errorMessage: stripAnsi(rawError) }),\n ...(asOptionalString(parsed.failedJob) === undefined ? {} : { failedJob: asOptionalString(parsed.failedJob) }),\n ...(parsed.stale === true ? { stale: true } : {}),\n ...(asOptionalString(parsed.staleReason) === undefined\n ? {}\n : { staleReason: asOptionalString(parsed.staleReason) }),\n ...(asOptionalString(parsed.worktreeBranch) === undefined\n ? {}\n : { worktreeBranch: asOptionalString(parsed.worktreeBranch) }),\n jobs: [],\n };\n const piSessionId = env === undefined ? undefined : asOptionalString(env[PI_SESSION_ENV]);\n return { view, ...(piSessionId === undefined ? {} : { piSessionId }) };\n}\n\ninterface WorkflowProgressEvent {\n type: 'job' | 'step';\n status: WorkflowProgressState;\n job: string;\n step?: string;\n index?: number;\n total?: number;\n reason?: string;\n at: string;\n}\n\n/**\n * Parses the append-only progress log. Malformed lines are skipped rather\n * than failing the file: a reader routinely catches a torn final line\n * mid-append.\n */\nexport function parseWorkflowProgress(raw: string): WorkflowProgressEvent[] {\n const events: WorkflowProgressEvent[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n continue;\n }\n if (!isRecord(parsed)) continue;\n const type = parsed.type;\n const status = asOptionalString(parsed.status);\n const job = asOptionalString(parsed.job);\n const at = asOptionalString(parsed.at);\n if ((type !== 'job' && type !== 'step') || !job || !at) continue;\n if (status === undefined || !PROGRESS_STATES.has(status)) continue;\n const step = asOptionalString(parsed.step);\n const index = asOptionalNumber(parsed.index);\n const total = asOptionalNumber(parsed.total);\n const reason = asOptionalString(parsed.reason);\n events.push({\n type,\n status: status as WorkflowProgressState,\n job,\n ...(step === undefined ? {} : { step }),\n ...(index === undefined ? {} : { index }),\n ...(total === undefined ? {} : { total }),\n ...(reason === undefined ? {} : { reason }),\n at,\n });\n }\n return events;\n}\n\nfunction jobPhase(name: string): WorkflowJobPhase {\n if (name === PHASE_JOB_PRE) return PHASE_JOB_PRE;\n if (name === PHASE_JOB_POST) return PHASE_JOB_POST;\n return 'job';\n}\n\n/**\n * Folds the event log into the current job tree; later events win, so a job\n * that started and later failed reads as failed. Jobs and steps keep the\n * order of their first appearance.\n */\nexport function foldWorkflowProgress(events: readonly WorkflowProgressEvent[]): WorkflowJobView[] {\n const jobs: WorkflowJobView[] = [];\n const jobByName = new Map<string, WorkflowJobView>();\n for (const event of events) {\n let job = jobByName.get(event.job);\n if (job === undefined) {\n job = { name: event.job, phase: jobPhase(event.job), status: event.status, steps: [] };\n jobByName.set(event.job, job);\n jobs.push(job);\n }\n if (event.type === 'job') {\n job.status = event.status;\n if (event.reason !== undefined) job.reason = event.reason;\n if (event.index !== undefined) job.index = event.index;\n if (event.total !== undefined) job.total = event.total;\n if (event.status === 'running' && job.startedAt === undefined) job.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) job.endedAt = event.at;\n continue;\n }\n if (event.step === undefined) continue;\n let step: WorkflowStepView | undefined = job.steps.find((candidate) => candidate.name === event.step);\n if (step === undefined) {\n step = { name: event.step, status: event.status };\n job.steps.push(step);\n }\n step.status = event.status;\n if (event.reason !== undefined) step.reason = event.reason;\n if (event.status === 'running' && step.startedAt === undefined) step.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) step.endedAt = event.at;\n }\n return jobs;\n}\n\nconst ACTIVE_PROGRESS_STATES: ReadonlySet<WorkflowProgressState> = new Set([\n 'running',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\n\n/** The job and step a run is on right now, for the NOW breadcrumb. */\nexport function workflowPosition(jobs: readonly WorkflowJobView[]): WorkflowPosition | undefined {\n for (let jobIndex = jobs.length - 1; jobIndex >= 0; jobIndex -= 1) {\n const job = jobs[jobIndex]!;\n if (!ACTIVE_PROGRESS_STATES.has(job.status)) continue;\n for (let stepIndex = job.steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n const step = job.steps[stepIndex]!;\n if (ACTIVE_PROGRESS_STATES.has(step.status)) {\n return {\n job: job.name,\n step: step.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n }\n return {\n job: job.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n return undefined;\n}\n\n/** The finished view: record fields plus the folded job tree and position. */\nexport function completeWorkflowRunView(view: WorkflowRunView, jobs: WorkflowJobView[]): WorkflowRunView {\n const position = view.stage === 'running' ? workflowPosition(jobs) : undefined;\n return { ...view, jobs, ...(position === undefined ? {} : { position }) };\n}\n\n/**\n * Whether a run belongs on a session's workflow tab: launched by that Pi\n * session, which is the same env test doompi-workflow's isSessionRun applies.\n *\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so repository proximity is not ownership.\n * Scoping on it as well let two sessions open in one repo read each other's\n * history, and kept a dead session's runs on the board of every session that\n * replaced it. Fails closed on an unstamped record, which is what a launch\n * from the CLI rather than from a session leaves behind.\n */\nexport function runBelongsToSession(run: ParsedWorkflowRun, sessionId: string): boolean {\n return run.piSessionId !== undefined && run.piSessionId === sessionId;\n}\n\nfunction parseTime(value: string | undefined): number {\n if (value === undefined) return 0;\n const time = Date.parse(value);\n return Number.isFinite(time) ? time : 0;\n}\n\nconst STAGE_ORDER: Readonly<Record<WorkflowStage, number>> = { running: 0, error: 1, completed: 2 };\n\n/**\n * Whether a run still belongs in the view.\n *\n * Only errored runs age out here, and slowly: everything else a session\n * started stays until the engine forgets the run itself.\n */\nfunction withinRetention(run: WorkflowRunView, now: number): boolean {\n if (run.stage !== 'error') return true;\n const settledAt = parseTime(run.finishedAt) || parseTime(run.startedAt);\n return now - settledAt < WORKFLOW_ERROR_RETENTION_MS;\n}\n\n/**\n * When a run last moved, which is what orders it within its group.\n *\n * A running run has only its start; a settled one is ordered by when it\n * settled, because a list kept for the whole session is read as a history and\n * two runs started together can finish an hour apart.\n */\nfunction lastMovedAt(run: WorkflowRunView): number {\n return run.stage === 'running' ? parseTime(run.startedAt) : parseTime(run.finishedAt) || parseTime(run.startedAt);\n}\n\n/**\n * Running runs first, then errored (recovery acts on them), then finished;\n * newest first within a group, and each group capped on its own.\n */\nexport function presentWorkflowRuns(runs: readonly WorkflowRunView[], now: number): WorkflowRunView[] {\n const groups = new Map<WorkflowStage, WorkflowRunView[]>();\n for (const run of runs) {\n if (!withinRetention(run, now)) continue;\n const group = groups.get(run.stage);\n if (group) group.push(run);\n else groups.set(run.stage, [run]);\n }\n return [...groups.entries()]\n .sort(([left], [right]) => STAGE_ORDER[left] - STAGE_ORDER[right])\n .flatMap(([, group]) =>\n group\n .sort((left, right) => lastMovedAt(right) - lastMovedAt(left))\n .slice(0, MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP),\n );\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport {\n completeWorkflowRunView,\n foldWorkflowProgress,\n type ParsedWorkflowRun,\n parseWorkflowProgress,\n parseWorkflowRunRecord,\n PROGRESS_FILE_NAME,\n resolveWorkflowHome,\n RUN_RECORD_FILE_NAME,\n WORKFLOW_HOME_ENV,\n WORKFLOW_STAGES,\n WORKSPACES_DIR_NAME,\n} from '../workflowRuns';\n\nexport interface ReadWorkflowRunsOptions {\n /** Registry home override, primarily for tests. */\n homeDir?: string;\n /** Admitted session environment used to resolve the registry home. */\n environment?: Readonly<Record<string, string | undefined>>;\n}\n\n/**\n * Read the durable workflow registry once.\n *\n * The registry is an initial snapshot only. Live delivery belongs to the\n * session lifecycle and is routed through the host-owned direct event bus.\n */\nexport function readWorkflowRuns(options: ReadWorkflowRunsOptions = {}): ParsedWorkflowRun[] {\n const environment = options.environment;\n const homeDir =\n options.homeDir ??\n resolveWorkflowHome({\n envValue: environment?.[WORKFLOW_HOME_ENV],\n homeDir: os.homedir(),\n });\n const workspacesDir = path.join(homeDir, WORKSPACES_DIR_NAME);\n const recordCache = new Map<string, { size: number; mtimeMs: number; value: ParsedWorkflowRun | undefined }>();\n const progressCache = new Map<\n string,\n { size: number; mtimeMs: number; value: ReturnType<typeof foldWorkflowProgress> }\n >();\n\n const cachedParse = <T>(\n cache: Map<string, { size: number; mtimeMs: number; value: T }>,\n filePath: string,\n parse: (raw: string) => T,\n empty: T,\n ): T => {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(filePath);\n } catch {\n cache.delete(filePath);\n return empty;\n }\n const cached = cache.get(filePath);\n if (cached && cached.size === stat.size && cached.mtimeMs === stat.mtimeMs) return cached.value;\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch {\n cache.delete(filePath);\n return empty;\n }\n const value = parse(raw);\n cache.set(filePath, { size: stat.size, mtimeMs: stat.mtimeMs, value });\n return value;\n };\n\n const listDir = (directory: string): string[] => {\n try {\n return fs.readdirSync(directory).sort();\n } catch {\n return [];\n }\n };\n\n const runs: ParsedWorkflowRun[] = [];\n for (const workspace of listDir(workspacesDir)) {\n for (const stage of WORKFLOW_STAGES) {\n const stageDir = path.join(workspacesDir, workspace, stage);\n for (const runKey of listDir(stageDir)) {\n const runDir = path.join(stageDir, runKey);\n const recordPath = path.join(runDir, RUN_RECORD_FILE_NAME);\n const progressPath = path.join(runDir, PROGRESS_FILE_NAME);\n const parsed = cachedParse(recordCache, recordPath, parseWorkflowRunRecord, undefined);\n if (parsed === undefined) continue;\n const jobs = cachedParse(\n progressCache,\n progressPath,\n (raw) => foldWorkflowProgress(parseWorkflowProgress(raw)),\n [],\n );\n runs.push({ ...parsed, view: completeWorkflowRunView(parsed.view, jobs) });\n }\n }\n }\n return runs;\n}\n","/**\n * Workflow run view types shared by this package's hub channel and its web\n * plugin. The shapes mirror what the embedded workflow-mcp engine records;\n * the cockpit renders them as 'workflow_runs' channel payloads.\n */\n\n/** workflow-mcp's own stage vocabulary; the registry bucket a run record sits in. */\nexport type WorkflowStage = 'running' | 'completed' | 'error';\n\n/** workflow-mcp's terminal outcome for a finished run. */\nexport type WorkflowOutcome = 'success' | 'skipped' | 'failed' | 'interrupted';\n\n/** Job and step states as workflow-mcp records them in the progress log. */\nexport type WorkflowProgressState =\n | 'running'\n | 'completed'\n | 'skipped'\n | 'failed'\n | 'pause_requested'\n | 'paused'\n | 'resumed';\n\nexport interface WorkflowStepView {\n name: string;\n status: WorkflowProgressState;\n /** Why the step is in its state, when the engine recorded one (e.g. a skip condition). */\n reason?: string;\n /** ISO 8601 of the step's first running event. */\n startedAt?: string;\n /** ISO 8601 of the step's terminal event. */\n endedAt?: string;\n}\n\n/** 'pre' and 'post' are the engine's pseudo-jobs for its pre:/post: blocks. */\nexport type WorkflowJobPhase = 'pre' | 'job' | 'post';\n\nexport interface WorkflowJobView {\n name: string;\n phase: WorkflowJobPhase;\n status: WorkflowProgressState;\n reason?: string;\n /** Position among the run's jobs, when the engine recorded one. */\n index?: number;\n total?: number;\n startedAt?: string;\n endedAt?: string;\n steps: WorkflowStepView[];\n}\n\n/** The job and step a run is on right now; drives the NOW breadcrumb. */\nexport interface WorkflowPosition {\n job: string;\n step?: string;\n index?: number;\n total?: number;\n}\n\n/**\n * One workflow run of a session, read from workflow-mcp's registry: the\n * run.json record plus the folded progress.ndjson job tree.\n */\nexport interface WorkflowRunView {\n /** Registry identity within its workspace; unique per workspace+stage. */\n runKey: string;\n workspace: string;\n displayName: string;\n workflowName?: string;\n workflowPath: string;\n stage: WorkflowStage;\n outcome?: WorkflowOutcome;\n /** Present while the engine is pausing or paused; absent for plain running. */\n executionState?: 'running' | 'pause_requested' | 'paused' | 'resume_requested';\n /** The prompt the run was launched with, when one was recorded. */\n prompt?: string;\n /** ISO 8601, from the run record. */\n startedAt: string;\n finishedAt?: string;\n /** Failure cause with ANSI escapes stripped, present when the run errored. */\n errorMessage?: string;\n /** The job the engine blamed for the failure, when it recorded one. */\n failedJob?: string;\n /** True when reconciliation decided the recorded pid is no longer alive. */\n stale?: boolean;\n staleReason?: string;\n worktreeBranch?: string;\n position?: WorkflowPosition;\n jobs: WorkflowJobView[];\n}\n\n/** What the workflow runs channel publishes for one session. */\nexport interface WorkflowRunsPayload {\n runs: WorkflowRunView[];\n}\n\nexport const WORKFLOW_RUNS_TYPE = 'workflow_runs';\n\n/**\n * One workflow the session's directory can launch, as the catalog drawer\n * lists it: the engine's own catalog entry plus the parsed detail the drawer\n * unfolds and the launch dialog turns into fields.\n */\nexport interface WorkflowCatalogEntryView {\n /** Absolute path, the row's stable identity. */\n path: string;\n relativePath: string;\n name: string;\n description: string;\n tags: string[];\n /** The trigger names the file declares, such as workflow_dispatch. */\n triggers: string[];\n inputs: WorkflowCatalogInputView[];\n jobs: WorkflowCatalogJobView[];\n artifacts: WorkflowCatalogArtifactView[];\n /** Absent when the workflow names no runner map, which means any runner will do. */\n runners?: string[];\n /** Set when the file could not be parsed; the row shows this instead of guessing. */\n error?: string;\n}\n\nexport interface WorkflowCatalogInputView {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n type?: string;\n options?: string[];\n}\n\nexport interface WorkflowCatalogJobView {\n name: string;\n steps: string[];\n}\n\nexport interface WorkflowCatalogArtifactView {\n path: string;\n kind: 'file' | 'directory';\n description: string;\n producedBy: string[];\n}\n\n/** What the catalog channel publishes for one session. */\nexport interface WorkflowCatalogPayload {\n /** The directory the catalog was read from, which is the session's own. */\n cwd: string;\n workflows: WorkflowCatalogEntryView[];\n /** Present when the directory could not be read at all. */\n warning?: string;\n}\n\nexport const WORKFLOW_CATALOG_TYPE = 'workflow_catalog';\n","import { resolve } from 'node:path';\n\nimport {\n type DoomHeadlessExecutionContext,\n type DoomHeadlessContent,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { serverMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/doompi-minor-mode';\nimport { createEmbeddedWorkflowFeature } from '@agimon-ai/workflow-mcp';\nimport { z } from 'zod';\n\nimport { registerRunProvider, type RunProviderHandle } from '../../services/backgroundWork';\nimport { createWorkflowCatalogReader, presentWorkflowCatalog } from '../../services/webWorkflowCatalog';\nimport { defaultCatalogDeps } from '../../services/workflowCatalogDeps';\nimport {\n parseWorkflowLaunchCommand,\n resolveWorkflowEntry,\n validateWorkflowLaunch,\n} from '../../services/workflowLaunchCommand';\nimport { readWorkflowSkill as skill } from '../../services/workflowResource';\nimport { PI_SESSION_ENV, presentWorkflowRuns, runBelongsToSession } from '../../services/workflowRuns';\nimport { readWorkflowRuns } from '../../services/workflowWatcher';\nimport { WORKFLOW_CATALOG_TYPE, WORKFLOW_RUNS_TYPE } from '../../types/webWorkflows';\n\nconst SOURCE = '@agimon-ai/doompi-workflow';\nconst WORKFLOW_MODE_ID = 'workflow';\nconst LIST_TOOL = 'list_workflows';\nconst LAUNCH_TOOL = 'launch_workflow';\nconst RUN_TOOL = 'workflow_run';\n\nfunction callResult(value: unknown): DoomHeadlessToolResult {\n const content: DoomHeadlessContent[] = [];\n if (typeof value === 'object' && value !== null && 'content' in value && Array.isArray(value.content)) {\n for (const item of value.content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) continue;\n const record = item as Record<string, unknown>;\n if (record.type === 'text' && typeof record.text === 'string') content.push({ type: 'text', text: record.text });\n else if (record.type === 'image' && typeof record.data === 'string' && typeof record.mimeType === 'string') {\n content.push({ type: 'image', data: record.data, mimeType: record.mimeType });\n }\n }\n }\n if (content.length === 0) content.push({ type: 'text', text: JSON.stringify(value, null, 2) });\n return {\n content,\n details: value,\n ...(typeof value === 'object' && value !== null && 'isError' in value && value.isError === true\n ? { isError: true }\n : {}),\n };\n}\n\nimport { type DoomHeadlessHostService } from '@agimon-ai/doompi-core/headless';\nimport { type DoomServerHostService, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nexport function createWorkflowServerRuntime(\n host: DoomHeadlessHostService,\n serverHost: DoomServerHostService,\n): DoomServerSessionPlugin {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Workflow headless facet requires the session direct event bus.');\n const directEvents = serverHost.context.directEvents;\n let runProvider: RunProviderHandle | undefined;\n const catalogReader = createWorkflowCatalogReader(defaultCatalogDeps());\n const publishLifecycle = async (executionContext: typeof host.context): Promise<boolean> => {\n const records = readWorkflowRuns({ environment: executionContext.environment }).filter((run) =>\n runBelongsToSession(run, executionContext.sessionId),\n );\n const activeItems = records\n .filter((run) => run.view.stage === 'running' && run.view.stale !== true)\n .map((run) => ({ id: `${run.view.workspace}/${run.view.runKey}`, sessionId: executionContext.sessionId }));\n runProvider?.update(activeItems);\n const runs = presentWorkflowRuns(\n records.map((run) => run.view),\n Date.now(),\n );\n directEvents.publish(WORKFLOW_RUNS_TYPE, executionContext.sessionId, { runs });\n try {\n directEvents.publish(WORKFLOW_CATALOG_TYPE, executionContext.sessionId, {\n cwd: executionContext.cwd,\n workflows: presentWorkflowCatalog(await catalogReader.read(executionContext.cwd)),\n });\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n directEvents.publish(WORKFLOW_CATALOG_TYPE, executionContext.sessionId, {\n cwd: executionContext.cwd,\n workflows: [],\n warning,\n });\n }\n return activeItems.length > 0;\n };\n const feature = createEmbeddedWorkflowFeature();\n const launch = (parameters: Parameters<typeof feature.runTool.execute>[0]) =>\n feature.runTool.execute({\n ...parameters,\n env: { ...parameters.env, [PI_SESSION_ENV]: host.context.sessionId },\n });\n let control: ReturnType<typeof feature.createRunControl> | undefined;\n let controlDisposers: (() => void)[] = [];\n const disposeControl = (): void => {\n for (const dispose of controlDisposers.splice(0)) dispose();\n control?.dispose();\n control = undefined;\n };\n let modeOwner: MinorModeOwner | undefined;\n const modeSelected = (): boolean => (host.context.selection.state?.['minor-mode'] ?? []).includes(WORKFLOW_MODE_ID);\n const modeState = (): MinorModeState => {\n const active = modeSelected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: 'workflow tools available' } : {}),\n actions: [\n { id: 'activate', enabled: !active, ...(!active ? {} : { disabledReason: 'Workflow mode is active.' }) },\n { id: 'deactivate', enabled: active, ...(active ? {} : { disabledReason: 'Workflow mode is inactive.' }) },\n ],\n };\n };\n const selectMode = async (enabled: boolean): Promise<void> => {\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== WORKFLOW_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, WORKFLOW_MODE_ID] : modes,\n });\n modeOwner?.publish();\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: SOURCE,\n id: WORKFLOW_MODE_ID,\n label: 'Workflow',\n description: 'Workflow discovery, launch, inspection, control, and recovery tools.',\n order: 20,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Enable workflow tools for this session.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Disable workflow tools without stopping active runs.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: modeState,\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n execution.signal.throwIfAborted();\n if (actionId === 'activate') {\n await selectMode(true);\n return { message: 'Workflow mode activated.' };\n }\n if (actionId === 'deactivate') {\n await selectMode(false);\n return { message: 'Workflow mode deactivated.' };\n }\n throw new Error(`Unknown workflow mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n (context) => {\n const provider = registerRunProvider(context);\n runProvider = provider;\n return () => {\n provider.dispose();\n if (runProvider === provider) runProvider = undefined;\n };\n },\n ],\n hooks: [\n {\n event: 'tool_execution_end',\n handle: async (_event, executionContext) => {\n await publishLifecycle(executionContext);\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n event: 'session_shutdown',\n handle: disposeControl,\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'doompi-author-workflow',\n kind: 'skill',\n read: () => skill('doompi-author-workflow'),\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'doompi-use-workflow',\n kind: 'skill',\n read: () => skill('doompi-use-workflow'),\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'workflow-recovery',\n kind: 'skill',\n read: () => skill('workflow-recovery'),\n },\n ],\n activities: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: SOURCE,\n async start(executionContext) {\n const reportFailure = (error: unknown): void => {\n process.emitWarning(`Could not publish headless workflow state: ${String(error)}`);\n };\n const stopFor =\n (ownedControl: NonNullable<typeof control>): (() => void) =>\n () => {\n void publishLifecycle(executionContext)\n .then((active) => {\n if (!active && !modeSelected() && control === ownedControl) disposeControl();\n })\n .catch(reportFailure);\n };\n if (control !== undefined) {\n const ownedControl = control;\n await publishLifecycle(executionContext);\n return stopFor(ownedControl);\n }\n control = feature.createRunControl({});\n const ownedControl = control;\n const refresh = (): void => {\n void publishLifecycle(executionContext)\n .then((active) => {\n if (!active && !modeSelected() && control === ownedControl) disposeControl();\n })\n .catch(reportFailure);\n };\n controlDisposers = [\n ownedControl.on('runStarted', refresh),\n ownedControl.on('runUpdated', refresh),\n ownedControl.on('runFinished', refresh),\n ];\n try {\n await ownedControl.start();\n await publishLifecycle(executionContext);\n return stopFor(ownedControl);\n } catch (error) {\n if (control === ownedControl) disposeControl();\n throw error;\n }\n },\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: LIST_TOOL,\n label: 'List Workflows',\n description: 'List workflow definitions available in this repository.',\n parameters: z.toJSONSchema(feature.listWorkflowsTool.getInputSchema()),\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n const input = parameters as Parameters<typeof feature.listWorkflowsTool.execute>[0];\n return callResult(\n await feature.listWorkflowsTool.execute({\n ...input,\n directory:\n input?.directory === undefined\n ? context.cwd\n : typeof input.directory === 'string'\n ? resolve(context.cwd, input.directory)\n : input.directory,\n }),\n );\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: LAUNCH_TOOL,\n label: 'Launch Workflow',\n description: 'Start a workflow run and return its recorded launch result.',\n parameters: z.toJSONSchema(feature.runTool.getInputSchema()),\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n signal?.throwIfAborted();\n return callResult(await launch(parameters as Parameters<typeof feature.runTool.execute>[0]));\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: RUN_TOOL,\n label: 'Workflow Run',\n description: 'Inspect the status of a workflow run or request cooperative control.',\n parameters: {\n type: 'object',\n properties: {\n action: { type: 'string', enum: ['status', 'pause', 'resume', 'stop'] },\n runKey: { type: 'string', minLength: 1 },\n workspace: { type: 'string' },\n reason: { type: 'string' },\n expectedRunId: { type: 'string' },\n },\n required: ['action', 'runKey'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n signal?.throwIfAborted();\n const input = parameters as unknown as {\n action: 'status' | 'pause' | 'resume' | 'stop';\n runKey: string;\n workspace?: string;\n reason?: string;\n expectedRunId?: string;\n };\n const runs = readWorkflowRuns({ environment: host.context.environment }).filter(\n (run) =>\n runBelongsToSession(run, host.context.sessionId) &&\n run.view.runKey === input.runKey &&\n (input.workspace === undefined || run.view.workspace === input.workspace),\n );\n if (runs.length !== 1)\n return {\n ...callResult({\n error:\n runs.length === 0\n ? 'Workflow run was not found in this session.'\n : 'Specify the workspace for this run key.',\n }),\n isError: true,\n };\n const run = runs[0]!.view;\n if (input.action === 'status') return callResult(run);\n if (!control) return callResult({ error: 'Workflow activity is not active.' });\n if (typeof input.expectedRunId !== 'string' || input.expectedRunId.length === 0) {\n return callResult({ error: 'expectedRunId is required for workflow control.' });\n }\n const request =\n input.action === 'pause'\n ? await control.pause(input.runKey, input.expectedRunId, input.workspace, input.reason)\n : input.action === 'resume'\n ? await control.resume(input.runKey, input.expectedRunId, input.workspace)\n : await control.stop(input.runKey, input.expectedRunId, input.workspace, input.reason);\n return callResult(request);\n },\n },\n ],\n commands: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'workflow-launch',\n description: 'Launch a workflow from a slash command.',\n async execute(args: string, execution: DoomHeadlessExecutionContext) {\n const parsed = parseWorkflowLaunchCommand(args);\n if ('error' in parsed) {\n await execution.client.notify({ body: parsed.error, level: 'error' });\n return;\n }\n try {\n const entry = resolveWorkflowEntry(await catalogReader.read(execution.cwd), parsed.workflow);\n if (!entry || entry.error) {\n await execution.client.notify({\n body: entry?.error ?? `Workflow not found: ${parsed.workflow}`,\n level: 'error',\n });\n return;\n }\n const problems = validateWorkflowLaunch(entry, parsed);\n if (problems.length > 0) {\n await execution.client.notify({ body: problems.join('\\n'), level: 'error' });\n return;\n }\n const result = callResult(\n await launch({\n workflowPath: entry.path,\n ...(parsed.runner === undefined ? {} : { runner: parsed.runner }),\n ...(Object.keys(parsed.inputs).length === 0 ? {} : { inputs: parsed.inputs }),\n ...(parsed.prompt === undefined ? {} : { prompt: parsed.prompt }),\n }),\n );\n const rendered = result.content.find((item) => item.type === 'text');\n await execution.client.notify({\n body: rendered?.type === 'text' ? rendered.text : 'Workflow launch requested.',\n level: result.isError ? 'error' : 'info',\n });\n } catch (error) {\n await execution.client.notify({ body: String(error), level: 'error' });\n }\n },\n },\n ],\n onDispose() {\n disposeControl();\n runProvider?.dispose();\n runProvider = undefined;\n },\n };\n}\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport type {\n WorkflowArtifactContentResponse,\n WorkflowArtifactsResponse,\n WorkflowControlResponse,\n WorkflowDeleteResponse,\n} from './webWorkflowTerminal';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/workflow/`, so the mount is stated once, by the\n * folder that creates it. The same API answers at all three scopes, because a\n * global contribution cascades into workspace and session; the folder under\n * `workspaces/sessions/` only re-mounts it for a session's own server.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone. The page used to build the hub's own\n * absolute URL and then rewrite its plugin prefix with String.replace to reach\n * a session, which is exactly the kind of copy that can move by one character\n * without anything noticing.\n *\n * `:workspace` and `:runKey` are Hono's own parameter syntax, because the app\n * registers `path` verbatim.\n */\n\n/** One run, which every route below addresses. */\nconst RUN = '/runs/:workspace/:runKey';\n\n/**\n * The artifact route's parameter, as Hono spells a multi-segment match.\n *\n * An artifact is named by its path inside the run directory, so `reports/a.md`\n * is one parameter across two segments. The client's `params` substitution\n * fills a single segment and percent-encodes the slash with it, so the page\n * substitutes this one itself; see the page's `_lib/terminalApi.ts`.\n */\nexport const ARTIFACT_NAME_PARAM = ':name{.+}';\n\n/** Query parameters the artifact route reads, spelled once for both halves. */\nexport const ARTIFACT_RAW_PARAM = 'raw';\nexport const ARTIFACT_DOWNLOAD_PARAM = 'download';\n\nexport default defineApiRoutes({\n /**\n * The terminal, as server-sent events.\n *\n * `stream: true` gets a URL and no call method: the consumer is the browser's\n * own `EventSource`, and a relayed call would buffer a stream that never ends.\n */\n screen: {\n method: 'GET',\n path: `${RUN}/screen/stream`,\n stream: true,\n },\n control: {\n method: 'POST',\n path: `${RUN}/control`,\n response: apiResponse<WorkflowControlResponse>(),\n },\n keys: {\n method: 'POST',\n path: `${RUN}/keys`,\n },\n resize: {\n method: 'POST',\n path: `${RUN}/resize`,\n response: apiResponse<{ resized: boolean }>(),\n },\n remove: {\n method: 'DELETE',\n path: RUN,\n response: apiResponse<WorkflowDeleteResponse>(),\n },\n artifacts: {\n method: 'GET',\n path: `${RUN}/artifacts`,\n response: apiResponse<WorkflowArtifactsResponse>(),\n },\n /** One artifact: its metadata and text, or its raw bytes under `raw=1`. */\n artifact: {\n method: 'GET',\n path: `${RUN}/artifacts/${ARTIFACT_NAME_PARAM}`,\n query: [ARTIFACT_RAW_PARAM, ARTIFACT_DOWNLOAD_PARAM],\n response: apiResponse<WorkflowArtifactContentResponse>(),\n },\n});\n","/**\n * The wire contract between this package's hub API and its cockpit client:\n * one run's terminal, and the files its run directory holds.\n *\n * Both halves of the cockpit import these names, so the route strings and the\n * event names live here rather than being spelled twice.\n */\n\n/**\n * Segment this package's API is mounted under, below /api/plugins/.\n *\n * The same word names `src/extensions/(backend)/api/workflow/`, which is where\n * the build reads the mount for the browser's client, so the two cannot drift.\n * The routes themselves are declared in `apiRoutes.ts`.\n */\nexport const WORKFLOW_API_BASE_PATH = 'workflow';\n\n/** The SSE event name the screen stream writes. */\nexport const WORKFLOW_SCREEN_EVENT = 'screen';\n\n/** What a surface may do with one run's terminal, and why anything is missing. */\nexport interface WorkflowTerminalCapabilitiesView {\n readable: boolean;\n writable: boolean;\n resizable: boolean;\n reason?: string;\n}\n\n/** One frame of a run's terminal, as the stream pushes it. */\nexport interface WorkflowScreenEvent {\n /** The visible screen, newest line last, carrying the colour the run printed. */\n lines: string[];\n capabilities: WorkflowTerminalCapabilitiesView;\n /** True once the run has settled, after which the stream ends. */\n ended?: boolean;\n}\n\n/** Answer to taking or releasing the keyboard for one run. */\nexport interface WorkflowControlResponse {\n /** True when this caller now holds the keyboard. */\n held: boolean;\n /** The token later writes must carry; absent when control was refused or released. */\n token?: string;\n /** Why control was refused, worded for a reader. */\n reason?: string;\n}\n\n/** Answer after a settled run and its directory have been permanently removed. */\nexport interface WorkflowDeleteResponse {\n deleted: true;\n}\n\n/** How a declared run-directory entry compares with what is on disk. */\nexport type WorkflowArtifactState = 'written' | 'empty' | 'pending' | 'unreadable';\n\n/** One file or directory in a run's own folder. */\nexport interface WorkflowArtifactView {\n /** Path relative to the run directory, which is also the read route's parameter. */\n path: string;\n kind: 'file' | 'directory';\n /** What the workflow says this file is for; empty for a file it never declared. */\n description: string;\n /** The jobs the workflow says write it. */\n producedBy: string[];\n /** True when the workflow's run-directory block names this entry. */\n declared: boolean;\n state: WorkflowArtifactState;\n /** Bytes on disk, absent until the file exists. */\n size?: number;\n /** ISO 8601 of the last write, absent until the file exists. */\n modifiedAt?: string;\n}\n\nexport interface WorkflowArtifactsResponse {\n /** Absolute path of the run's own directory, which the reader may want to open. */\n runDir: string;\n /** What the workflow says the directory is for. */\n description: string;\n artifacts: WorkflowArtifactView[];\n}\n\n/** One artifact's metadata and optional text, as the viewer tab reads it. */\nexport interface WorkflowArtifactContentResponse {\n path: string;\n size: number;\n modifiedAt: string;\n /** Media type inferred from the file extension by the trusted hub. Absent on older hubs. */\n mimeType?: string;\n /** Present for text formats; binary files are streamed from the raw route instead. */\n text?: string;\n /** True when textual content was longer than the reader's byte budget. */\n truncated: boolean;\n}\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\n\nimport type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\nimport {\n WorkflowRegistryService,\n WorkflowTerminalService as WorkflowTerminalFacade,\n type WorkflowRunRecord,\n type WorkflowStage,\n} from '@agimon-ai/workflow-mcp';\nimport { type Context, Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { createWorkflowTerminalService } from '../../services/workflowTerminal';\nimport routes, { ARTIFACT_DOWNLOAD_PARAM, ARTIFACT_RAW_PARAM } from '../../types/apiRoutes';\nimport {\n WORKFLOW_API_BASE_PATH,\n WORKFLOW_SCREEN_EVENT,\n type WorkflowArtifactContentResponse,\n type WorkflowArtifactsResponse,\n type WorkflowArtifactView,\n type WorkflowControlResponse,\n type WorkflowDeleteResponse,\n type WorkflowScreenEvent,\n} from '../../types/webWorkflowTerminal';\n\n/** Stages a run can be recorded under, newest first: a live run is the common case. */\nconst STAGES: readonly WorkflowStage[] = ['running', 'error', 'completed'];\n/** Lines of screen the stream sends, which is a terminal's visible height plus room. */\nconst SCREEN_LINES = 48;\n/** How often the stream re-reads; the service coalesces, so this is an upper bound. */\nconst STREAM_TICK_MS = 500;\n/** How often a settled run is re-checked before the stream closes itself. */\nconst SETTLED_POLL_TICKS = 4;\n/** Bytes of one textual artifact returned as JSON; binary previews use a stream. */\nconst MAX_ARTIFACT_BYTES = 512 * 1024;\n/** Path segments a client supplies are names, never paths. */\nconst SAFE_SEGMENT = /^[\\w.@-]+$/;\nconst ARTIFACT_MIME_TYPES: Readonly<Record<string, string>> = {\n '.aac': 'audio/aac',\n '.bmp': 'image/bmp',\n '.css': 'text/css',\n '.csv': 'text/csv',\n '.gif': 'image/gif',\n '.htm': 'text/html',\n '.html': 'text/html',\n '.ico': 'image/x-icon',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.js': 'text/javascript',\n '.json': 'application/json',\n '.jsx': 'text/jsx',\n '.m4a': 'audio/mp4',\n '.markdown': 'text/markdown',\n '.md': 'text/markdown',\n '.mov': 'video/quicktime',\n '.mp3': 'audio/mpeg',\n '.mp4': 'video/mp4',\n '.oga': 'audio/ogg',\n '.ogg': 'audio/ogg',\n '.ogv': 'video/ogg',\n '.pdf': 'application/pdf',\n '.png': 'image/png',\n '.sh': 'text/x-shellscript',\n '.svg': 'image/svg+xml',\n '.toml': 'text/toml',\n '.ts': 'text/typescript',\n '.tsv': 'text/tab-separated-values',\n '.tsx': 'text/tsx',\n '.txt': 'text/plain',\n '.wav': 'audio/wav',\n '.webm': 'video/webm',\n '.webp': 'image/webp',\n '.xml': 'application/xml',\n '.yaml': 'text/yaml',\n '.yml': 'text/yaml',\n};\n\n/**\n * One request's JSON body as a plain record.\n *\n * A body that is absent, malformed, or not an object reads as empty rather\n * than failing the route: every field is checked by the route anyway, and a\n * 400 naming the missing field beats a parse error naming nothing.\n */\nasync function jsonBody(context: Context): Promise<Record<string, unknown>> {\n const parsed: unknown = await context.req.json().catch(() => undefined);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n}\n\n/** Rejects anything that could climb out of the registry before a path is built. */\nfunction isSafeSegment(value: string): boolean {\n return value !== '' && value !== '../adapters' && value !== '..' && SAFE_SEGMENT.test(value);\n}\n\n/** One run's identity for caches and leases, stable across stage moves. */\nfunction runIdentityOf(workspace: string, runKey: string): string {\n return `${workspace}/${runKey}`;\n}\n\nexport interface WorkflowHubApiOptions {\n registry?: WorkflowRegistryService;\n terminal?: WorkflowTerminalFacade;\n now?: () => number;\n}\n\n/**\n * This package's HTTP surface: one workflow run's terminal, and the files its\n * run directory holds.\n *\n * Mounted in the hub rather than in a session's server, because a run's\n * terminal belongs to its multiplexer rather than to the session that launched\n * it: any process can read a tmux pane, and the session's own server cannot\n * reach anything more. The routes therefore name a run, never a session.\n */\nexport function createWorkflowHubApi(options: WorkflowHubApiOptions = {}): Hono {\n const registry = options.registry ?? new WorkflowRegistryService();\n const facade = options.terminal ?? new WorkflowTerminalFacade();\n const terminal = createWorkflowTerminalService<WorkflowRunRecord>({\n terminal: facade,\n now: options.now ?? (() => Date.now()),\n });\n const app = new Hono();\n\n /** The record behind a request, whichever stage it now sits in. */\n const runOf = async (workspace: string, runKey: string): Promise<WorkflowRunRecord | undefined> => {\n if (!isSafeSegment(workspace) || !isSafeSegment(runKey)) return undefined;\n for (const stage of STAGES) {\n try {\n return await registry.readRunByKey(workspace, stage, runKey);\n } catch {\n // Not in this stage. A run moves between them as it settles, so a miss\n // here is ordinary; only a miss in every stage means no such run.\n }\n }\n return undefined;\n };\n\n const missing = (workspace: string, runKey: string): { error: string } => ({\n error: `No workflow run '${runKey}' in workspace '${workspace}'.`,\n });\n\n app.get(routes.screen.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const identity = runIdentityOf(workspace, runKey);\n\n return streamSSE(context, async (stream) => {\n let settledTicks = 0;\n let running = true;\n stream.onAbort(() => {\n running = false;\n });\n while (running) {\n const current = (await runOf(workspace, runKey)) ?? record;\n const capabilities = terminal.capabilities(current);\n const lines = capabilities.readable ? await terminal.screen(identity, current, SCREEN_LINES) : [];\n // A settled run is read a few more times before the stream closes: the\n // last thing a failing step printed is what the reader came for, and it\n // lands after the record has already moved to its final stage.\n const settled = current.stage !== 'running';\n if (settled) settledTicks += 1;\n const ended = settled && settledTicks >= SETTLED_POLL_TICKS;\n const event: WorkflowScreenEvent = { lines, capabilities, ...(ended ? { ended: true } : {}) };\n await stream.writeSSE({ event: WORKFLOW_SCREEN_EVENT, data: JSON.stringify(event) });\n if (ended) break;\n await stream.sleep(STREAM_TICK_MS);\n }\n terminal.forget(new Set());\n });\n });\n\n app.post(routes.control.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const identity = runIdentityOf(workspace, runKey);\n const body = await jsonBody(context);\n const capabilities = terminal.capabilities(record);\n\n if (body.release === true) {\n if (typeof body.token === 'string') terminal.releaseControl(identity, body.token);\n const released: WorkflowControlResponse = { held: false };\n return context.json(released);\n }\n if (!capabilities.writable) {\n const refused: WorkflowControlResponse = { held: false, reason: capabilities.reason };\n return context.json(refused, 409);\n }\n const token = typeof body.token === 'string' && body.token !== '' ? body.token : randomUUID();\n if (!terminal.takeControl(identity, token)) {\n const taken: WorkflowControlResponse = { held: false, reason: 'Another reader holds the keyboard.' };\n return context.json(taken, 409);\n }\n const held: WorkflowControlResponse = { held: true, token };\n return context.json(held);\n });\n\n app.post(routes.keys.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const body = await jsonBody(context);\n if (typeof body.token !== 'string' || typeof body.data !== 'string') {\n return context.json({ error: 'A keystroke needs a control token and its data.' }, 400);\n }\n try {\n await terminal.write(runIdentityOf(workspace, runKey), record, body.token, body.data);\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n return context.body(null, 204);\n });\n\n app.post(routes.resize.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const body = await jsonBody(context);\n const { token, columns, rows } = body;\n if (typeof token !== 'string' || typeof columns !== 'number' || typeof rows !== 'number') {\n return context.json({ error: 'A resize needs a control token, columns and rows.' }, 400);\n }\n try {\n const resized = await terminal.resize(runIdentityOf(workspace, runKey), record, token, columns, rows);\n return context.json({ resized });\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n });\n\n app.delete(routes.remove.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n if (record.stage === 'running') {\n return context.json({ error: 'A running workflow must be stopped before it can be deleted.' }, 409);\n }\n try {\n fs.rmSync(registry.runDirectoryFor(record), { recursive: true, force: true });\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n const response: WorkflowDeleteResponse = { deleted: true };\n return context.json(response);\n });\n\n app.get(routes.artifacts.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const runDir = registry.runDirectoryFor(record);\n const body: WorkflowArtifactsResponse = {\n runDir,\n description: record.runDirectory?.description ?? '',\n artifacts: readArtifacts(runDir, record),\n };\n return context.json(body);\n });\n\n app.get(routes.artifact.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const runDir = registry.runDirectoryFor(record);\n const requested = context.req.param('name');\n const resolved = resolveInside(runDir, requested);\n if (resolved === undefined) return context.json({ error: `'${requested}' is not inside this run.` }, 400);\n if (context.req.query(ARTIFACT_RAW_PARAM) === '1') {\n const response = streamArtifact(\n resolved,\n requested,\n context.req.header('range'),\n context.req.query(ARTIFACT_DOWNLOAD_PARAM) === '1',\n );\n return response ?? context.json({ error: `'${requested}' has not been written.` }, 404);\n }\n const body = readArtifact(resolved, requested);\n if (body === undefined) return context.json({ error: `'${requested}' has not been written.` }, 404);\n return context.json(body);\n });\n\n return app;\n}\n\n/**\n * A path inside the run directory, or undefined when it points anywhere else.\n *\n * The client supplies this one verbatim, unlike the run key, so it is resolved\n * and then checked rather than trusted: without the check the route would read\n * any file the hub can reach.\n */\nfunction resolveInside(runDir: string, requested: string): string | undefined {\n const resolved = path.resolve(runDir, requested);\n const root = path.resolve(runDir);\n if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) return undefined;\n return resolved;\n}\n\n/** Size and modification time of one path, or undefined when it is not there. */\nfunction statOf(target: string): fs.Stats | undefined {\n try {\n return fs.statSync(target);\n } catch {\n return undefined; // Not written yet, which is an ordinary state for an artifact.\n }\n}\n\nfunction stateOf(stats: fs.Stats | undefined): WorkflowArtifactView['state'] {\n if (stats === undefined) return 'pending';\n if (stats.isDirectory()) return 'written';\n return stats.size === 0 ? 'empty' : 'written';\n}\n\nfunction viewOf(\n runDir: string,\n entry: Omit<WorkflowArtifactView, 'state' | 'size' | 'modifiedAt'>,\n): WorkflowArtifactView {\n const stats = statOf(path.join(runDir, entry.path));\n return {\n ...entry,\n state: stateOf(stats),\n ...(stats === undefined ? {} : { size: stats.size, modifiedAt: stats.mtime.toISOString() }),\n };\n}\n\n/**\n * What the run directory holds: the workflow's own declaration first, then the\n * files nobody declared.\n *\n * The declaration is the point of the folder, so it leads and keeps its order\n * even for entries no job has written yet. The rest follows rather than being\n * hidden: the engine's own context.md and progress log are often exactly what a\n * reader is looking for.\n */\nfunction readArtifacts(runDir: string, record: WorkflowRunRecord): WorkflowArtifactView[] {\n const declared = (record.runDirectory?.entries ?? []).map((entry) =>\n viewOf(runDir, {\n path: entry.path,\n kind: entry.kind,\n description: entry.description,\n producedBy: entry['produced-by'] ?? [],\n declared: true,\n }),\n );\n const claimed = new Set(declared.map((entry) => entry.path));\n let names: fs.Dirent[];\n try {\n names = fs.readdirSync(runDir, { withFileTypes: true });\n } catch {\n return declared; // The directory is gone; the declaration is still worth showing.\n }\n const found = names\n .filter((entry) => !claimed.has(entry.name))\n .map((entry) =>\n viewOf(runDir, {\n path: entry.name,\n kind: entry.isDirectory() ? 'directory' : 'file',\n description: '',\n producedBy: [],\n declared: false,\n }),\n )\n .sort((left, right) => left.path.localeCompare(right.path));\n return [...declared, ...found];\n}\n\n/** Browser content type inferred from a filename without trusting client input. */\nfunction artifactMimeType(requested: string): string {\n return ARTIFACT_MIME_TYPES[path.extname(requested).toLowerCase()] ?? 'application/octet-stream';\n}\n\nfunction isTextArtifact(mimeType: string): boolean {\n return mimeType.startsWith('text/') || mimeType === 'application/json' || mimeType === 'application/xml';\n}\n\n/** One artifact's metadata and bounded text, or undefined when it is not readable. */\nfunction readArtifact(resolved: string, requested: string): WorkflowArtifactContentResponse | undefined {\n const stats = statOf(resolved);\n if (stats === undefined || stats.isDirectory()) return undefined;\n const mimeType = artifactMimeType(requested);\n let text: string | undefined;\n if (isTextArtifact(mimeType)) {\n try {\n const handle = fs.openSync(resolved, 'r');\n try {\n const buffer = Buffer.alloc(Math.min(stats.size, MAX_ARTIFACT_BYTES));\n fs.readSync(handle, buffer, 0, buffer.length, 0);\n text = buffer.toString('utf8');\n } finally {\n fs.closeSync(handle);\n }\n } catch {\n return undefined;\n }\n }\n return {\n path: requested,\n size: stats.size,\n modifiedAt: stats.mtime.toISOString(),\n mimeType,\n ...(text === undefined ? {} : { text }),\n truncated: text !== undefined && stats.size > MAX_ARTIFACT_BYTES,\n };\n}\n\n/** Streams media with byte-range support so browser audio, video, and PDF controls can seek. */\nfunction streamArtifact(\n resolved: string,\n requested: string,\n rangeHeader: string | undefined,\n download: boolean,\n): Response | undefined {\n const stats = statOf(resolved);\n if (stats === undefined || stats.isDirectory()) return undefined;\n const mimeType = artifactMimeType(requested);\n let start = 0;\n let end = Math.max(0, stats.size - 1);\n let partial = false;\n const match = rangeHeader?.match(/^bytes=(\\d*)-(\\d*)$/);\n if (match !== null && match !== undefined && stats.size > 0) {\n const requestedStart = match[1] === '' ? undefined : Number(match[1]);\n const requestedEnd = match[2] === '' ? undefined : Number(match[2]);\n if (requestedStart === undefined && requestedEnd !== undefined) {\n start = Math.max(0, stats.size - requestedEnd);\n } else if (requestedStart !== undefined) {\n start = requestedStart;\n end = requestedEnd === undefined ? end : Math.min(requestedEnd, end);\n }\n if (start >= stats.size || start > end) {\n return new Response(null, { status: 416, headers: { 'content-range': `bytes */${String(stats.size)}` } });\n }\n partial = true;\n }\n const filename = path.basename(requested).replace(/[\"\\\\\\r\\n]/g, '_');\n const forceDownload = download || mimeType === 'text/html';\n const headers = new Headers({\n 'accept-ranges': 'bytes',\n 'content-disposition': `${forceDownload ? 'attachment' : 'inline'}; filename=\"${filename}\"`,\n 'content-length': String(stats.size === 0 ? 0 : end - start + 1),\n 'content-type': mimeType,\n 'x-content-type-options': 'nosniff',\n });\n if (partial) headers.set('content-range', `bytes ${String(start)}-${String(end)}/${String(stats.size)}`);\n if (stats.size === 0) return new Response(null, { status: 200, headers });\n const body = Readable.toWeb(fs.createReadStream(resolved, { start, end }));\n return new Response(body, { status: partial ? 206 : 200, headers });\n}\n\n/** The named export a host imports from this package's built hub entry. */\nexport const api: DoomApi = {\n basePath: WORKFLOW_API_BASE_PATH,\n start(_context: DoomApiContext): DoomApiHandler {\n // Hub-scoped: the host hands no session, and these routes want none. A run\n // is addressed by its registry identity, which is machine-wide.\n const app = createWorkflowHubApi();\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request: a stream's loop ends when its own socket\n // aborts, and the caches it touched are per run rather than per client.\n close: () => undefined,\n };\n },\n};\n","import type { DoomServerPluginDefinition } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { createWorkflowServerRuntime } from '../../../../../services/serverRuntime';\nimport { api } from '../../../../../services/workflowHubApi';\n\nexport default (({ agent, host }) => ({\n api: [api],\n ...(agent ? createWorkflowServerRuntime(agent, host) : {}),\n})) satisfies NonNullable<DoomServerPluginDefinition['session']>;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from './_lib/index.server';\n\nexport default defineRoot((context: Parameters<typeof runtime>[0]) => {\n const value = runtime(context);\n return {\n value,\n services: value.services,\n activities: value.activities,\n onStart: value.onStart,\n onStop: value.onStop,\n onDispose: value.onDispose,\n };\n});\n","import type { DoomHubChannelSource, DoomHubSessionScope, DoomHubChannel } from '@agimon-ai/doompi-core/hubChannel';\n\nimport {\n createWorkflowCatalogReader,\n presentWorkflowCatalog,\n type WorkflowCatalogReaderDeps,\n} from '../../services/webWorkflowCatalog';\nimport { defaultCatalogDeps } from '../../services/workflowCatalogDeps';\nimport { WORKFLOW_CATALOG_TYPE, type WorkflowCatalogPayload } from '../../types/webWorkflows';\n\nexport interface WorkflowCatalogChannelOptions {\n deps?: WorkflowCatalogReaderDeps;\n}\n\n/**\n * The workflow catalog channel. Durable state seeds a session once, then\n * session lifecycle events deliver updates over the direct event bus.\n */\nexport function createWorkflowCatalogChannel(options: WorkflowCatalogChannelOptions = {}): DoomHubChannel {\n const reader = createWorkflowCatalogReader(options.deps ?? defaultCatalogDeps());\n return {\n frameType: WORKFLOW_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, DoomHubSessionScope>();\n const latest = new Map<string, WorkflowCatalogPayload>();\n const subscriptions = new Map<string, () => void>();\n const publish = (scope: DoomHubSessionScope, payload: WorkflowCatalogPayload): void => {\n latest.set(scope.sessionId, payload);\n host.publish(scope.sessionId, payload);\n };\n const readInitial = async (scope: DoomHubSessionScope): Promise<void> => {\n let payload: WorkflowCatalogPayload;\n try {\n payload = {\n cwd: scope.cwd,\n workflows: presentWorkflowCatalog(await reader.read(scope.cwd)),\n };\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n payload = { cwd: scope.cwd, workflows: [], warning };\n host.onNotice(`workflow catalog for ${scope.cwd} is unavailable (${warning})`);\n }\n if (scopes.get(scope.sessionId) === scope) publish(scope, payload);\n };\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n return scopes.has(scope.sessionId) ? latest.get(scope.sessionId) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n subscriptions.get(scope.sessionId)?.();\n const unsubscribe = host.directEvents.subscribe(\n WORKFLOW_CATALOG_TYPE,\n scope.sessionId,\n (value) => {\n if (isWorkflowCatalogPayload(value)) publish(scope, value);\n },\n { replayLatest: true },\n );\n subscriptions.set(scope.sessionId, unsubscribe);\n void readInitial(scope);\n },\n sessionRemoved(sessionId) {\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n\nfunction isWorkflowCatalogPayload(value: unknown): value is WorkflowCatalogPayload {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { cwd?: unknown }).cwd === 'string' &&\n Array.isArray((value as { workflows?: unknown }).workflows)\n );\n}\n","import type { DoomHubChannelSource, DoomHubSessionScope, DoomHubChannel } from '@agimon-ai/doompi-core/hubChannel';\n\nimport { presentWorkflowRuns, runBelongsToSession, type ParsedWorkflowRun } from '../../services/workflowRuns';\nimport { readWorkflowRuns, type ReadWorkflowRunsOptions } from '../../services/workflowWatcher';\nimport { WORKFLOW_RUNS_TYPE, type WorkflowRunView, type WorkflowRunsPayload } from '../../types/webWorkflows';\n\nexport interface WorkflowsChannelOptions {\n /** Injectable durable initial snapshot reader for tests. */\n read?: (options: ReadWorkflowRunsOptions) => ParsedWorkflowRun[];\n}\n\nfunction isWorkflowRunsPayload(value: unknown): value is WorkflowRunsPayload {\n return typeof value === 'object' && value !== null && Array.isArray((value as { runs?: unknown }).runs);\n}\n\n/**\n * The workflow runs data channel. Durable registry state seeds each session\n * once; subsequent updates arrive through the host-owned direct event bus.\n */\nexport function createWorkflowsChannel(options: WorkflowsChannelOptions = {}): DoomHubChannel {\n const read = options.read ?? readWorkflowRuns;\n return {\n frameType: WORKFLOW_RUNS_TYPE,\n start(host) {\n const scopes = new Map<string, DoomHubSessionScope>();\n const latest = new Map<string, WorkflowRunsPayload>();\n const subscriptions = new Map<string, () => void>();\n const runsFor = (scope: DoomHubSessionScope, parsed: readonly ParsedWorkflowRun[]): WorkflowRunView[] =>\n presentWorkflowRuns(\n parsed.filter((run) => runBelongsToSession(run, scope.sessionId)).map((run) => run.view),\n Date.now(),\n );\n const publish = (scope: DoomHubSessionScope, payload: WorkflowRunsPayload): void => {\n latest.set(scope.sessionId, payload);\n host.publish(scope.sessionId, payload);\n };\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n return scopes.has(scope.sessionId) ? latest.get(scope.sessionId) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n subscriptions.get(scope.sessionId)?.();\n const unsubscribe = host.directEvents.subscribe(\n WORKFLOW_RUNS_TYPE,\n scope.sessionId,\n (value) => {\n if (isWorkflowRunsPayload(value)) publish(scope, value);\n },\n { replayLatest: true },\n );\n subscriptions.set(scope.sessionId, unsubscribe);\n const payload = { runs: runsFor(scope, read({ environment: scope.environment })) };\n publish(scope, payload);\n },\n sessionRemoved(sessionId) {\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n","import type { DoomServerPluginDefinition } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { createWorkflowCatalogChannel } from '../../../services/workflowCatalogChannel';\nimport { api } from '../../../services/workflowHubApi';\nimport { createWorkflowsChannel } from '../../../services/workflowsHubChannel';\n\nexport default (({ host }) =>\n host.scope === 'session'\n ? {}\n : { channels: [createWorkflowsChannel, createWorkflowCatalogChannel], api: [api] }) satisfies NonNullable<\n DoomServerPluginDefinition['global']\n>;\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\n\nimport legacy from '../../_lib/index.server';\n\nexport default defineRoutedContribution((context: Parameters<typeof legacy>[0]) => legacy(context).api?.[0], {\n cardinality: 'optional',\n});\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createWorkflowCatalogChannel } from '../../../services/workflowCatalogChannel';\n\nexport default defineChannel(createWorkflowCatalogChannel);\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createWorkflowsChannel } from '../../../services/workflowsHubChannel';\n\nexport default defineChannel(createWorkflowsChannel);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.api?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\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';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.hooks?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.hooks?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[2],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[2],\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/workflow/route.server';\nimport channelWorkflowCatalog from '../src/extensions/(backend)/channel/workflow-catalog.server';\nimport channelWorkflows from '../src/extensions/(backend)/channel/workflows.server';\nimport apiRoute2 from '../src/extensions/workspaces/sessions/(backend)/api/workflow/route.server';\nimport commandWorkflowLaunch from '../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server';\nimport hookSessionShutdown from '../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server';\nimport hookToolExecutionEnd from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server';\nimport resourceDoompiAuthorWorkflow from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server';\nimport resourceDoompiUseWorkflow from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server';\nimport resourceWorkflowRecovery from '../src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server';\nimport toolLaunchWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server';\nimport toolListWorkflows from '../src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server';\nimport toolWorkflowRun from '../src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server';\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;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-workflow',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context), at(apiRoute2, contextSession)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n get commands(): DoomServerSessionPlugin['commands'] { return defined([via({ name: 'workflow-launch' }, at(commandWorkflowLaunch, contextSession))]); },\n get hooks(): DoomServerSessionPlugin['hooks'] { return defined([via({ event: 'session_shutdown' }, at(hookSessionShutdown, contextSession)), via({ event: 'tool_execution_end' }, at(hookToolExecutionEnd, contextSession))]); },\n get resources(): DoomServerSessionPlugin['resources'] { return defined([at(resourceDoompiAuthorWorkflow, contextSession), at(resourceDoompiUseWorkflow, contextSession), at(resourceWorkflowRecovery, contextSession)]); },\n get tools(): DoomServerSessionPlugin['tools'] { return defined([via({ name: 'launch_workflow' }, at(toolLaunchWorkflow, contextSession)), via({ name: 'list_workflows' }, at(toolListWorkflows, contextSession)), via({ name: 'workflow_run' }, at(toolWorkflowRun, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.cjs","names":["readWorkflowCatalog","summarizeWorkflow","statSync","resolve","os","path","fs","createEmbeddedWorkflowFeature","defineMinorMode","serverMinorModes","registerRunProvider","skill","z","resolve","parseWorkflowLaunchCommand","resolveWorkflowEntry","validateWorkflowLaunch","defineApiRoutes","apiResponse","WorkflowRegistryService","WorkflowTerminalFacade","createWorkflowTerminalService","Hono","routes","streamSSE","randomUUID","path","fs","Readable","defineRoot","runtime","defineRoutedContribution","legacy","defineChannel","defineChannel","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineRoutedContribution","defineServerPlugin","apiRoute","channelWorkflowCatalog","channelWorkflows","rootSession","composeRootHooks","apiRoute2","commandWorkflowLaunch","hookSessionShutdown","hookToolExecutionEnd","resourceDoompiAuthorWorkflow","resourceDoompiUseWorkflow","resourceWorkflowRecovery","toolLaunchWorkflow","toolListWorkflows","toolWorkflowRun"],"sources":["../../src/services/webWorkflowCatalog/index.ts","../../src/services/workflowCatalogDeps/index.ts","../../src/services/workflowRuns/index.ts","../../src/services/workflowWatcher/index.ts","../../src/types/webWorkflows.ts","../../src/services/serverRuntime/index.ts","../../src/types/apiRoutes.ts","../../src/types/webWorkflowTerminal.ts","../../src/services/workflowHubApi/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/index.server.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/services/workflowCatalogChannel/index.ts","../../src/services/workflowsHubChannel/index.ts","../../src/extensions/(backend)/_lib/index.server.ts","../../src/extensions/(backend)/api/workflow/route.server.ts","../../src/extensions/(backend)/channel/workflow-catalog.server.ts","../../src/extensions/(backend)/channel/workflows.server.ts","../../src/extensions/workspaces/sessions/(backend)/api/workflow/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server.ts","../../generated/server.ts"],"sourcesContent":["import type {\n WorkflowCatalogArtifactView,\n WorkflowCatalogEntryView,\n WorkflowCatalogInputView,\n WorkflowCatalogJobView,\n} from '../../types/webWorkflows';\n/**\n * The cockpit's view of the workflows a session can launch.\n *\n * The engine already reads a repository's workflow files and parses one of\n * them into triggers, inputs, jobs, artifacts and compatible runners, so this\n * module only shapes that answer for the wire and remembers what it read.\n *\n * WHY A CACHE:\n * A session reads the catalog for its initial projection and when its lifecycle\n * publishes a workflow update. Entries are kept per path and reused while the\n * file's size and modification time are unchanged, which is the same test a\n * build tool makes and costs one stat per file.\n */\n\n/** What the engine reports for one workflow file before it is parsed. */\nexport interface CatalogListEntry {\n path: string;\n relativePath: string;\n name: string;\n description: string;\n tags: string[];\n}\n\n/** One file's parsed detail, or the reason it could not be read. */\nexport interface CatalogDetail {\n triggers: string[];\n inputs: WorkflowCatalogInputView[];\n jobs: WorkflowCatalogJobView[];\n artifacts: WorkflowCatalogArtifactView[];\n runners?: string[];\n error?: string;\n}\n\n/** What a file looked like when it was last parsed. */\nexport interface CatalogFileStamp {\n size: number;\n modifiedAt: number;\n}\n\nexport interface WorkflowCatalogReaderDeps {\n /** Every workflow file under a directory. */\n list(directory: string): Promise<CatalogListEntry[]>;\n /** One file's parsed detail; never throws, so a bad file cannot empty a board. */\n summarize(path: string): CatalogDetail;\n /** Size and modification time, or undefined when the file is gone. */\n stamp(path: string): CatalogFileStamp | undefined;\n}\n\ninterface CachedEntry {\n stamp: CatalogFileStamp;\n detail: CatalogDetail;\n}\n\n/** Reads one directory's catalog, reusing what it parsed last time. */\nexport interface WorkflowCatalogReader {\n read(directory: string): Promise<WorkflowCatalogEntryView[]>;\n /** Drops what was parsed for files no longer listed, so a cache cannot grow forever. */\n forget(keep: ReadonlySet<string>): void;\n}\n\nfunction unchanged(left: CatalogFileStamp | undefined, right: CatalogFileStamp | undefined): boolean {\n return left !== undefined && right !== undefined && left.size === right.size && left.modifiedAt === right.modifiedAt;\n}\n\nexport function createWorkflowCatalogReader(deps: WorkflowCatalogReaderDeps): WorkflowCatalogReader {\n const cache = new Map<string, CachedEntry>();\n\n const detailFor = (path: string): CatalogDetail => {\n const stamp = deps.stamp(path);\n const cached = cache.get(path);\n if (cached && unchanged(cached.stamp, stamp)) return cached.detail;\n const detail = deps.summarize(path);\n // A file that vanished between listing and stat is parsed anyway, which\n // answers with its own error; it just cannot be cached against a stamp.\n if (stamp !== undefined) cache.set(path, { stamp, detail });\n return detail;\n };\n\n return {\n async read(directory) {\n const listed = await deps.list(directory);\n return listed.map((entry) => {\n const detail = detailFor(entry.path);\n return {\n path: entry.path,\n relativePath: entry.relativePath,\n name: entry.name === '' ? entry.relativePath : entry.name,\n description: entry.description,\n tags: entry.tags,\n triggers: detail.triggers,\n inputs: detail.inputs,\n jobs: detail.jobs,\n artifacts: detail.artifacts,\n ...(detail.runners === undefined ? {} : { runners: detail.runners }),\n ...(detail.error === undefined ? {} : { error: detail.error }),\n };\n });\n },\n forget(keep) {\n for (const path of cache.keys()) {\n if (!keep.has(path)) cache.delete(path);\n }\n },\n };\n}\n\n/** The launchable rows first, then the ones that would not parse, name ordered. */\nexport function presentWorkflowCatalog(entries: readonly WorkflowCatalogEntryView[]): WorkflowCatalogEntryView[] {\n return [...entries].sort((left, right) => {\n if ((left.error === undefined) !== (right.error === undefined)) return left.error === undefined ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n}\n","import { statSync } from 'node:fs';\n\nimport { readWorkflowCatalog, summarizeWorkflow } from '@agimon-ai/workflow-mcp';\n\nimport type { WorkflowCatalogReaderDeps } from '../webWorkflowCatalog';\n\n/** Connect the pure catalog projection service to the workflow engine and filesystem. */\nexport function defaultCatalogDeps(): WorkflowCatalogReaderDeps {\n return {\n list: (directory) => readWorkflowCatalog(directory),\n summarize: (workflowPath) => summarizeWorkflow(workflowPath),\n stamp: (workflowPath) => {\n try {\n const stats = statSync(workflowPath);\n return { size: stats.size, modifiedAt: stats.mtimeMs };\n } catch {\n return undefined;\n }\n },\n };\n}\n","import { resolve } from 'node:path';\n\nimport type {\n WorkflowJobPhase,\n WorkflowJobView,\n WorkflowOutcome,\n WorkflowPosition,\n WorkflowProgressState,\n WorkflowRunView,\n WorkflowStage,\n WorkflowStepView,\n} from '../../types/webWorkflows';\n\n/**\n * MIRRORS @agimon-ai/workflow-mcp's on-disk registry\n * (src/services/WorkflowRegistryService.ts and WorkflowProgressService.ts in\n * that package). The engine keeps one directory per run under\n * `<home>/workspaces/<workspace>/<stage>/<runKey>/` holding a `run.json`\n * record and an append-only `progress.ndjson` job/step log; the hub only ever\n * reads them. The derivation is duplicated rather than imported because\n * doompi-web must not depend on the engine at runtime; the unit suite pins\n * this mirror against the package's published types.\n */\nconst DEFAULT_WORKFLOW_HOME_DIR_NAME = '.workflow-mcp';\nexport const WORKFLOW_HOME_ENV = 'WORKFLOW_MCP_HOME';\nexport const WORKSPACES_DIR_NAME = 'workspaces';\nexport const RUN_RECORD_FILE_NAME = 'run.json';\nexport const PROGRESS_FILE_NAME = 'progress.ndjson';\nexport const WORKFLOW_STAGES: readonly WorkflowStage[] = ['running', 'completed', 'error'];\n\n/**\n * Errored runs stay a day, which is how long recovery has to act on them.\n *\n * Finished runs have no retention of their own: a session keeps every run it\n * launched, grouped by outcome, for as long as the session lives. A run leaves\n * the view when the engine prunes its registry directory, not on a timer here,\n * because \"what did this session run today\" is a question asked long after the\n * run settled.\n */\nexport const WORKFLOW_ERROR_RETENTION_MS = 24 * 60 * 60 * 1000;\n/**\n * Upper bound per outcome group rather than over the whole list.\n *\n * One cap across every run let a long stream of green runs push a failure out\n * of the list, which is the one thing that must never fall off the end.\n */\nexport const MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP = 24;\n\n/** The env key doompi-workflow stamps on runs it launches; ties a run to a Pi session. */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\nconst PROGRESS_STATES: ReadonlySet<string> = new Set([\n 'running',\n 'completed',\n 'skipped',\n 'failed',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\nconst OUTCOMES: ReadonlySet<string> = new Set(['success', 'skipped', 'failed', 'interrupted']);\nconst EXECUTION_STATES: ReadonlySet<string> = new Set(['running', 'pause_requested', 'paused', 'resume_requested']);\nconst STEP_TERMINAL_STATES: ReadonlySet<WorkflowProgressState> = new Set(['completed', 'skipped', 'failed']);\n/** The engine records its pre:/post: blocks under these reserved pseudo-job names. */\nconst PHASE_JOB_PRE = 'pre';\nconst PHASE_JOB_POST = 'post';\n\n// oxlint-disable-next-line no-control-regex -- stripping terminal color codes from errorMessage is the point\nconst ANSI_ESCAPE_PATTERN = /\\u001b\\[[0-9;]*[A-Za-z]/g;\n\nexport interface WorkflowHomeInput {\n /** process.env.WORKFLOW_MCP_HOME, supplied by the caller. */\n envValue: string | undefined;\n /** os.homedir(), supplied by the caller. */\n homeDir: string;\n}\n\n/** Where workflow-mcp keeps its registry, mirroring the engine's own resolution. */\nexport function resolveWorkflowHome(input: WorkflowHomeInput): string {\n return resolve(\n input.envValue !== undefined && input.envValue !== ''\n ? input.envValue\n : resolve(input.homeDir, DEFAULT_WORKFLOW_HOME_DIR_NAME),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value !== '' ? value : undefined;\n}\n\nfunction asOptionalNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stripAnsi(text: string): string {\n return text.replace(ANSI_ESCAPE_PATTERN, '').trim();\n}\n\n/**\n * One run record plus the facts the hub needs for session scoping but the\n * page never sees.\n */\nexport interface ParsedWorkflowRun {\n /** The wire view, before the progress log is folded in (jobs empty). */\n view: WorkflowRunView;\n /** env.PI_SESSION_ID from the record, when the launcher stamped one. */\n piSessionId?: string;\n}\n\n/**\n * Validates one run.json into the wire shape plus scoping facts.\n *\n * Returns undefined for anything unreadable or a foreign format. The record\n * is trusted for its own stage: the registry rewrites it when a run moves\n * between stage directories.\n */\nexport function parseWorkflowRunRecord(raw: string): ParsedWorkflowRun | undefined {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!isRecord(parsed)) return undefined;\n const runKey = asOptionalString(parsed.runKey);\n const workspace = asOptionalString(parsed.workspace);\n const workflowPath = asOptionalString(parsed.workflowPath);\n const startedAt = asOptionalString(parsed.startedAt);\n const stage = asOptionalString(parsed.stage);\n if (!runKey || !workspace || !workflowPath || !startedAt) return undefined;\n if (stage === undefined || !WORKFLOW_STAGES.includes(stage as WorkflowStage)) return undefined;\n\n const outcome = asOptionalString(parsed.outcome);\n const executionState = asOptionalString(parsed.executionState);\n const rawError = asOptionalString(parsed.errorMessage);\n const env = isRecord(parsed.env) ? parsed.env : undefined;\n const view: WorkflowRunView = {\n runKey,\n workspace,\n displayName: asOptionalString(parsed.displayName) ?? runKey,\n ...(asOptionalString(parsed.workflowName) === undefined\n ? {}\n : { workflowName: asOptionalString(parsed.workflowName) }),\n workflowPath,\n stage: stage as WorkflowStage,\n ...(outcome !== undefined && OUTCOMES.has(outcome) ? { outcome: outcome as WorkflowOutcome } : {}),\n ...(executionState !== undefined && EXECUTION_STATES.has(executionState)\n ? { executionState: executionState as WorkflowRunView['executionState'] }\n : {}),\n ...(asOptionalString(parsed.prompt) === undefined ? {} : { prompt: asOptionalString(parsed.prompt) }),\n startedAt,\n ...(asOptionalString(parsed.finishedAt) === undefined ? {} : { finishedAt: asOptionalString(parsed.finishedAt) }),\n ...(rawError === undefined ? {} : { errorMessage: stripAnsi(rawError) }),\n ...(asOptionalString(parsed.failedJob) === undefined ? {} : { failedJob: asOptionalString(parsed.failedJob) }),\n ...(parsed.stale === true ? { stale: true } : {}),\n ...(asOptionalString(parsed.staleReason) === undefined\n ? {}\n : { staleReason: asOptionalString(parsed.staleReason) }),\n ...(asOptionalString(parsed.worktreeBranch) === undefined\n ? {}\n : { worktreeBranch: asOptionalString(parsed.worktreeBranch) }),\n jobs: [],\n };\n const piSessionId = env === undefined ? undefined : asOptionalString(env[PI_SESSION_ENV]);\n return { view, ...(piSessionId === undefined ? {} : { piSessionId }) };\n}\n\ninterface WorkflowProgressEvent {\n type: 'job' | 'step';\n status: WorkflowProgressState;\n job: string;\n step?: string;\n index?: number;\n total?: number;\n reason?: string;\n at: string;\n}\n\n/**\n * Parses the append-only progress log. Malformed lines are skipped rather\n * than failing the file: a reader routinely catches a torn final line\n * mid-append.\n */\nexport function parseWorkflowProgress(raw: string): WorkflowProgressEvent[] {\n const events: WorkflowProgressEvent[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n continue;\n }\n if (!isRecord(parsed)) continue;\n const type = parsed.type;\n const status = asOptionalString(parsed.status);\n const job = asOptionalString(parsed.job);\n const at = asOptionalString(parsed.at);\n if ((type !== 'job' && type !== 'step') || !job || !at) continue;\n if (status === undefined || !PROGRESS_STATES.has(status)) continue;\n const step = asOptionalString(parsed.step);\n const index = asOptionalNumber(parsed.index);\n const total = asOptionalNumber(parsed.total);\n const reason = asOptionalString(parsed.reason);\n events.push({\n type,\n status: status as WorkflowProgressState,\n job,\n ...(step === undefined ? {} : { step }),\n ...(index === undefined ? {} : { index }),\n ...(total === undefined ? {} : { total }),\n ...(reason === undefined ? {} : { reason }),\n at,\n });\n }\n return events;\n}\n\nfunction jobPhase(name: string): WorkflowJobPhase {\n if (name === PHASE_JOB_PRE) return PHASE_JOB_PRE;\n if (name === PHASE_JOB_POST) return PHASE_JOB_POST;\n return 'job';\n}\n\n/**\n * Folds the event log into the current job tree; later events win, so a job\n * that started and later failed reads as failed. Jobs and steps keep the\n * order of their first appearance.\n */\nexport function foldWorkflowProgress(events: readonly WorkflowProgressEvent[]): WorkflowJobView[] {\n const jobs: WorkflowJobView[] = [];\n const jobByName = new Map<string, WorkflowJobView>();\n for (const event of events) {\n let job = jobByName.get(event.job);\n if (job === undefined) {\n job = { name: event.job, phase: jobPhase(event.job), status: event.status, steps: [] };\n jobByName.set(event.job, job);\n jobs.push(job);\n }\n if (event.type === 'job') {\n job.status = event.status;\n if (event.reason !== undefined) job.reason = event.reason;\n if (event.index !== undefined) job.index = event.index;\n if (event.total !== undefined) job.total = event.total;\n if (event.status === 'running' && job.startedAt === undefined) job.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) job.endedAt = event.at;\n continue;\n }\n if (event.step === undefined) continue;\n let step: WorkflowStepView | undefined = job.steps.find((candidate) => candidate.name === event.step);\n if (step === undefined) {\n step = { name: event.step, status: event.status };\n job.steps.push(step);\n }\n step.status = event.status;\n if (event.reason !== undefined) step.reason = event.reason;\n if (event.status === 'running' && step.startedAt === undefined) step.startedAt = event.at;\n if (STEP_TERMINAL_STATES.has(event.status)) step.endedAt = event.at;\n }\n return jobs;\n}\n\nconst ACTIVE_PROGRESS_STATES: ReadonlySet<WorkflowProgressState> = new Set([\n 'running',\n 'pause_requested',\n 'paused',\n 'resumed',\n]);\n\n/** The job and step a run is on right now, for the NOW breadcrumb. */\nexport function workflowPosition(jobs: readonly WorkflowJobView[]): WorkflowPosition | undefined {\n for (let jobIndex = jobs.length - 1; jobIndex >= 0; jobIndex -= 1) {\n const job = jobs[jobIndex]!;\n if (!ACTIVE_PROGRESS_STATES.has(job.status)) continue;\n for (let stepIndex = job.steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n const step = job.steps[stepIndex]!;\n if (ACTIVE_PROGRESS_STATES.has(step.status)) {\n return {\n job: job.name,\n step: step.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n }\n return {\n job: job.name,\n ...(job.index === undefined ? {} : { index: job.index }),\n ...(job.total === undefined ? {} : { total: job.total }),\n };\n }\n return undefined;\n}\n\n/** The finished view: record fields plus the folded job tree and position. */\nexport function completeWorkflowRunView(view: WorkflowRunView, jobs: WorkflowJobView[]): WorkflowRunView {\n const position = view.stage === 'running' ? workflowPosition(jobs) : undefined;\n return { ...view, jobs, ...(position === undefined ? {} : { position }) };\n}\n\n/**\n * Whether a run belongs on a session's workflow tab: launched by that Pi\n * session, which is the same env test doompi-workflow's isSessionRun applies.\n *\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so repository proximity is not ownership.\n * Scoping on it as well let two sessions open in one repo read each other's\n * history, and kept a dead session's runs on the board of every session that\n * replaced it. Fails closed on an unstamped record, which is what a launch\n * from the CLI rather than from a session leaves behind.\n */\nexport function runBelongsToSession(run: ParsedWorkflowRun, sessionId: string): boolean {\n return run.piSessionId !== undefined && run.piSessionId === sessionId;\n}\n\nfunction parseTime(value: string | undefined): number {\n if (value === undefined) return 0;\n const time = Date.parse(value);\n return Number.isFinite(time) ? time : 0;\n}\n\nconst STAGE_ORDER: Readonly<Record<WorkflowStage, number>> = { running: 0, error: 1, completed: 2 };\n\n/**\n * Whether a run still belongs in the view.\n *\n * Only errored runs age out here, and slowly: everything else a session\n * started stays until the engine forgets the run itself.\n */\nfunction withinRetention(run: WorkflowRunView, now: number): boolean {\n if (run.stage !== 'error') return true;\n const settledAt = parseTime(run.finishedAt) || parseTime(run.startedAt);\n return now - settledAt < WORKFLOW_ERROR_RETENTION_MS;\n}\n\n/**\n * When a run last moved, which is what orders it within its group.\n *\n * A running run has only its start; a settled one is ordered by when it\n * settled, because a list kept for the whole session is read as a history and\n * two runs started together can finish an hour apart.\n */\nfunction lastMovedAt(run: WorkflowRunView): number {\n return run.stage === 'running' ? parseTime(run.startedAt) : parseTime(run.finishedAt) || parseTime(run.startedAt);\n}\n\n/**\n * Running runs first, then errored (recovery acts on them), then finished;\n * newest first within a group, and each group capped on its own.\n */\nexport function presentWorkflowRuns(runs: readonly WorkflowRunView[], now: number): WorkflowRunView[] {\n const groups = new Map<WorkflowStage, WorkflowRunView[]>();\n for (const run of runs) {\n if (!withinRetention(run, now)) continue;\n const group = groups.get(run.stage);\n if (group) group.push(run);\n else groups.set(run.stage, [run]);\n }\n return [...groups.entries()]\n .sort(([left], [right]) => STAGE_ORDER[left] - STAGE_ORDER[right])\n .flatMap(([, group]) =>\n group\n .sort((left, right) => lastMovedAt(right) - lastMovedAt(left))\n .slice(0, MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP),\n );\n}\n","import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport {\n completeWorkflowRunView,\n foldWorkflowProgress,\n type ParsedWorkflowRun,\n parseWorkflowProgress,\n parseWorkflowRunRecord,\n PROGRESS_FILE_NAME,\n resolveWorkflowHome,\n RUN_RECORD_FILE_NAME,\n WORKFLOW_HOME_ENV,\n WORKFLOW_STAGES,\n WORKSPACES_DIR_NAME,\n} from '../workflowRuns';\n\nexport interface ReadWorkflowRunsOptions {\n /** Registry home override, primarily for tests. */\n homeDir?: string;\n /** Admitted session environment used to resolve the registry home. */\n environment?: Readonly<Record<string, string | undefined>>;\n}\n\n/**\n * Read the durable workflow registry once.\n *\n * The registry is an initial snapshot only. Live delivery belongs to the\n * session lifecycle and is routed through the host-owned direct event bus.\n */\nexport function readWorkflowRuns(options: ReadWorkflowRunsOptions = {}): ParsedWorkflowRun[] {\n const environment = options.environment;\n const homeDir =\n options.homeDir ??\n resolveWorkflowHome({\n envValue: environment?.[WORKFLOW_HOME_ENV],\n homeDir: os.homedir(),\n });\n const workspacesDir = path.join(homeDir, WORKSPACES_DIR_NAME);\n const recordCache = new Map<string, { size: number; mtimeMs: number; value: ParsedWorkflowRun | undefined }>();\n const progressCache = new Map<\n string,\n { size: number; mtimeMs: number; value: ReturnType<typeof foldWorkflowProgress> }\n >();\n\n const cachedParse = <T>(\n cache: Map<string, { size: number; mtimeMs: number; value: T }>,\n filePath: string,\n parse: (raw: string) => T,\n empty: T,\n ): T => {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(filePath);\n } catch {\n cache.delete(filePath);\n return empty;\n }\n const cached = cache.get(filePath);\n if (cached && cached.size === stat.size && cached.mtimeMs === stat.mtimeMs) return cached.value;\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch {\n cache.delete(filePath);\n return empty;\n }\n const value = parse(raw);\n cache.set(filePath, { size: stat.size, mtimeMs: stat.mtimeMs, value });\n return value;\n };\n\n const listDir = (directory: string): string[] => {\n try {\n return fs.readdirSync(directory).sort();\n } catch {\n return [];\n }\n };\n\n const runs: ParsedWorkflowRun[] = [];\n for (const workspace of listDir(workspacesDir)) {\n for (const stage of WORKFLOW_STAGES) {\n const stageDir = path.join(workspacesDir, workspace, stage);\n for (const runKey of listDir(stageDir)) {\n const runDir = path.join(stageDir, runKey);\n const recordPath = path.join(runDir, RUN_RECORD_FILE_NAME);\n const progressPath = path.join(runDir, PROGRESS_FILE_NAME);\n const parsed = cachedParse(recordCache, recordPath, parseWorkflowRunRecord, undefined);\n if (parsed === undefined) continue;\n const jobs = cachedParse(\n progressCache,\n progressPath,\n (raw) => foldWorkflowProgress(parseWorkflowProgress(raw)),\n [],\n );\n runs.push({ ...parsed, view: completeWorkflowRunView(parsed.view, jobs) });\n }\n }\n }\n return runs;\n}\n","/**\n * Workflow run view types shared by this package's hub channel and its web\n * plugin. The shapes mirror what the embedded workflow-mcp engine records;\n * the cockpit renders them as 'workflow_runs' channel payloads.\n */\n\n/** workflow-mcp's own stage vocabulary; the registry bucket a run record sits in. */\nexport type WorkflowStage = 'running' | 'completed' | 'error';\n\n/** workflow-mcp's terminal outcome for a finished run. */\nexport type WorkflowOutcome = 'success' | 'skipped' | 'failed' | 'interrupted';\n\n/** Job and step states as workflow-mcp records them in the progress log. */\nexport type WorkflowProgressState =\n | 'running'\n | 'completed'\n | 'skipped'\n | 'failed'\n | 'pause_requested'\n | 'paused'\n | 'resumed';\n\nexport interface WorkflowStepView {\n name: string;\n status: WorkflowProgressState;\n /** Why the step is in its state, when the engine recorded one (e.g. a skip condition). */\n reason?: string;\n /** ISO 8601 of the step's first running event. */\n startedAt?: string;\n /** ISO 8601 of the step's terminal event. */\n endedAt?: string;\n}\n\n/** 'pre' and 'post' are the engine's pseudo-jobs for its pre:/post: blocks. */\nexport type WorkflowJobPhase = 'pre' | 'job' | 'post';\n\nexport interface WorkflowJobView {\n name: string;\n phase: WorkflowJobPhase;\n status: WorkflowProgressState;\n reason?: string;\n /** Position among the run's jobs, when the engine recorded one. */\n index?: number;\n total?: number;\n startedAt?: string;\n endedAt?: string;\n steps: WorkflowStepView[];\n}\n\n/** The job and step a run is on right now; drives the NOW breadcrumb. */\nexport interface WorkflowPosition {\n job: string;\n step?: string;\n index?: number;\n total?: number;\n}\n\n/**\n * One workflow run of a session, read from workflow-mcp's registry: the\n * run.json record plus the folded progress.ndjson job tree.\n */\nexport interface WorkflowRunView {\n /** Registry identity within its workspace; unique per workspace+stage. */\n runKey: string;\n workspace: string;\n displayName: string;\n workflowName?: string;\n workflowPath: string;\n stage: WorkflowStage;\n outcome?: WorkflowOutcome;\n /** Present while the engine is pausing or paused; absent for plain running. */\n executionState?: 'running' | 'pause_requested' | 'paused' | 'resume_requested';\n /** The prompt the run was launched with, when one was recorded. */\n prompt?: string;\n /** ISO 8601, from the run record. */\n startedAt: string;\n finishedAt?: string;\n /** Failure cause with ANSI escapes stripped, present when the run errored. */\n errorMessage?: string;\n /** The job the engine blamed for the failure, when it recorded one. */\n failedJob?: string;\n /** True when reconciliation decided the recorded pid is no longer alive. */\n stale?: boolean;\n staleReason?: string;\n worktreeBranch?: string;\n position?: WorkflowPosition;\n jobs: WorkflowJobView[];\n}\n\n/** What the workflow runs channel publishes for one session. */\nexport interface WorkflowRunsPayload {\n runs: WorkflowRunView[];\n}\n\nexport const WORKFLOW_RUNS_TYPE = 'workflow_runs';\n\n/**\n * One workflow the session's directory can launch, as the catalog drawer\n * lists it: the engine's own catalog entry plus the parsed detail the drawer\n * unfolds and the launch dialog turns into fields.\n */\nexport interface WorkflowCatalogEntryView {\n /** Absolute path, the row's stable identity. */\n path: string;\n relativePath: string;\n name: string;\n description: string;\n tags: string[];\n /** The trigger names the file declares, such as workflow_dispatch. */\n triggers: string[];\n inputs: WorkflowCatalogInputView[];\n jobs: WorkflowCatalogJobView[];\n artifacts: WorkflowCatalogArtifactView[];\n /** Absent when the workflow names no runner map, which means any runner will do. */\n runners?: string[];\n /** Set when the file could not be parsed; the row shows this instead of guessing. */\n error?: string;\n}\n\nexport interface WorkflowCatalogInputView {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n type?: string;\n options?: string[];\n}\n\nexport interface WorkflowCatalogJobView {\n name: string;\n steps: string[];\n}\n\nexport interface WorkflowCatalogArtifactView {\n path: string;\n kind: 'file' | 'directory';\n description: string;\n producedBy: string[];\n}\n\n/** What the catalog channel publishes for one session. */\nexport interface WorkflowCatalogPayload {\n /** The directory the catalog was read from, which is the session's own. */\n cwd: string;\n workflows: WorkflowCatalogEntryView[];\n /** Present when the directory could not be read at all. */\n warning?: string;\n}\n\nexport const WORKFLOW_CATALOG_TYPE = 'workflow_catalog';\n","import { resolve } from 'node:path';\n\nimport {\n type DoomHeadlessExecutionContext,\n type DoomHeadlessContent,\n type DoomHeadlessToolResult,\n} from '@agimon-ai/doompi-core/headless';\nimport { serverMinorModes } from '@agimon-ai/doompi-minor-mode';\nimport { defineMinorMode, type MinorModeOwner, type MinorModeState } from '@agimon-ai/doompi-minor-mode';\nimport { createEmbeddedWorkflowFeature } from '@agimon-ai/workflow-mcp';\nimport { z } from 'zod';\n\nimport { registerRunProvider, type RunProviderHandle } from '../../services/backgroundWork';\nimport { createWorkflowCatalogReader, presentWorkflowCatalog } from '../../services/webWorkflowCatalog';\nimport { defaultCatalogDeps } from '../../services/workflowCatalogDeps';\nimport {\n parseWorkflowLaunchCommand,\n resolveWorkflowEntry,\n validateWorkflowLaunch,\n} from '../../services/workflowLaunchCommand';\nimport { readWorkflowSkill as skill } from '../../services/workflowResource';\nimport { PI_SESSION_ENV, presentWorkflowRuns, runBelongsToSession } from '../../services/workflowRuns';\nimport { readWorkflowRuns } from '../../services/workflowWatcher';\nimport { WORKFLOW_CATALOG_TYPE, WORKFLOW_RUNS_TYPE } from '../../types/webWorkflows';\n\nconst SOURCE = '@agimon-ai/doompi-workflow';\nconst WORKFLOW_MODE_ID = 'workflow';\nconst LIST_TOOL = 'list_workflows';\nconst LAUNCH_TOOL = 'launch_workflow';\nconst RUN_TOOL = 'workflow_run';\n\nfunction callResult(value: unknown): DoomHeadlessToolResult {\n const content: DoomHeadlessContent[] = [];\n if (typeof value === 'object' && value !== null && 'content' in value && Array.isArray(value.content)) {\n for (const item of value.content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) continue;\n const record = item as Record<string, unknown>;\n if (record.type === 'text' && typeof record.text === 'string') content.push({ type: 'text', text: record.text });\n else if (record.type === 'image' && typeof record.data === 'string' && typeof record.mimeType === 'string') {\n content.push({ type: 'image', data: record.data, mimeType: record.mimeType });\n }\n }\n }\n if (content.length === 0) content.push({ type: 'text', text: JSON.stringify(value, null, 2) });\n return {\n content,\n details: value,\n ...(typeof value === 'object' && value !== null && 'isError' in value && value.isError === true\n ? { isError: true }\n : {}),\n };\n}\n\nimport { type DoomHeadlessHostService } from '@agimon-ai/doompi-core/headless';\nimport { type DoomServerHostService, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nexport function createWorkflowServerRuntime(\n host: DoomHeadlessHostService,\n serverHost: DoomServerHostService,\n): DoomServerSessionPlugin {\n if (serverHost.context.directEvents === undefined)\n throw new Error('Workflow headless facet requires the session direct event bus.');\n const directEvents = serverHost.context.directEvents;\n let runProvider: RunProviderHandle | undefined;\n const catalogReader = createWorkflowCatalogReader(defaultCatalogDeps());\n const publishLifecycle = async (executionContext: typeof host.context): Promise<boolean> => {\n const records = readWorkflowRuns({ environment: executionContext.environment }).filter((run) =>\n runBelongsToSession(run, executionContext.sessionId),\n );\n const activeItems = records\n .filter((run) => run.view.stage === 'running' && run.view.stale !== true)\n .map((run) => ({ id: `${run.view.workspace}/${run.view.runKey}`, sessionId: executionContext.sessionId }));\n runProvider?.update(activeItems);\n const runs = presentWorkflowRuns(\n records.map((run) => run.view),\n Date.now(),\n );\n directEvents.publish(WORKFLOW_RUNS_TYPE, executionContext.sessionId, { runs });\n try {\n directEvents.publish(WORKFLOW_CATALOG_TYPE, executionContext.sessionId, {\n cwd: executionContext.cwd,\n workflows: presentWorkflowCatalog(await catalogReader.read(executionContext.cwd)),\n });\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n directEvents.publish(WORKFLOW_CATALOG_TYPE, executionContext.sessionId, {\n cwd: executionContext.cwd,\n workflows: [],\n warning,\n });\n }\n return activeItems.length > 0;\n };\n const feature = createEmbeddedWorkflowFeature();\n const launch = (parameters: Parameters<typeof feature.runTool.execute>[0]) =>\n feature.runTool.execute({\n ...parameters,\n env: { ...parameters.env, [PI_SESSION_ENV]: host.context.sessionId },\n });\n let control: ReturnType<typeof feature.createRunControl> | undefined;\n let controlDisposers: (() => void)[] = [];\n const disposeControl = (): void => {\n for (const dispose of controlDisposers.splice(0)) dispose();\n control?.dispose();\n control = undefined;\n };\n let modeOwner: MinorModeOwner | undefined;\n const modeSelected = (): boolean => (host.context.selection.state?.['minor-mode'] ?? []).includes(WORKFLOW_MODE_ID);\n const modeState = (): MinorModeState => {\n const active = modeSelected();\n return {\n activation: active ? 'active' : 'inactive',\n condition: 'ready',\n ...(active ? { detail: 'workflow tools available' } : {}),\n actions: [\n { id: 'activate', enabled: !active, ...(!active ? {} : { disabledReason: 'Workflow mode is active.' }) },\n { id: 'deactivate', enabled: active, ...(active ? {} : { disabledReason: 'Workflow mode is inactive.' }) },\n ],\n };\n };\n const selectMode = async (enabled: boolean): Promise<void> => {\n const modes = (host.context.selection.state?.['minor-mode'] ?? []).filter((mode) => mode !== WORKFLOW_MODE_ID);\n await host.changeSelection({\n axis: 'state',\n key: 'minor-mode',\n values: enabled ? [...modes, WORKFLOW_MODE_ID] : modes,\n });\n modeOwner?.publish();\n };\n modeOwner = defineMinorMode({\n descriptor: {\n source: SOURCE,\n id: WORKFLOW_MODE_ID,\n label: 'Workflow',\n description: 'Workflow discovery, launch, inspection, control, and recovery tools.',\n order: 20,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Enable workflow tools for this session.',\n contexts: ['headless'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Disable workflow tools without stopping active runs.',\n contexts: ['headless'],\n parameters: [],\n },\n ],\n },\n state: modeState,\n async handleAction(_runtime, actionId, _argumentsValue, execution) {\n execution.signal.throwIfAborted();\n if (actionId === 'activate') {\n await selectMode(true);\n return { message: 'Workflow mode activated.' };\n }\n if (actionId === 'deactivate') {\n await selectMode(false);\n return { message: 'Workflow mode deactivated.' };\n }\n throw new Error(`Unknown workflow mode action: ${actionId}`);\n },\n }).createOwner(undefined);\n return {\n services: [\n serverMinorModes([modeOwner]),\n (context) => {\n const provider = registerRunProvider(context);\n runProvider = provider;\n return () => {\n provider.dispose();\n if (runProvider === provider) runProvider = undefined;\n };\n },\n ],\n hooks: [\n {\n event: 'tool_execution_end',\n handle: async (_event, executionContext) => {\n await publishLifecycle(executionContext);\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n event: 'session_shutdown',\n handle: disposeControl,\n },\n ],\n resources: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'doompi-author-workflow',\n kind: 'skill',\n read: () => skill('doompi-author-workflow'),\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'doompi-use-workflow',\n kind: 'skill',\n read: () => skill('doompi-use-workflow'),\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'workflow-recovery',\n kind: 'skill',\n read: () => skill('workflow-recovery'),\n },\n ],\n activities: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: SOURCE,\n async start(executionContext) {\n const reportFailure = (error: unknown): void => {\n process.emitWarning(`Could not publish headless workflow state: ${String(error)}`);\n };\n const stopFor =\n (ownedControl: NonNullable<typeof control>): (() => void) =>\n () => {\n void publishLifecycle(executionContext)\n .then((active) => {\n if (!active && !modeSelected() && control === ownedControl) disposeControl();\n })\n .catch(reportFailure);\n };\n if (control !== undefined) {\n const ownedControl = control;\n await publishLifecycle(executionContext);\n return stopFor(ownedControl);\n }\n control = feature.createRunControl({});\n const ownedControl = control;\n const refresh = (): void => {\n void publishLifecycle(executionContext)\n .then((active) => {\n if (!active && !modeSelected() && control === ownedControl) disposeControl();\n })\n .catch(reportFailure);\n };\n controlDisposers = [\n ownedControl.on('runStarted', refresh),\n ownedControl.on('runUpdated', refresh),\n ownedControl.on('runFinished', refresh),\n ];\n try {\n await ownedControl.start();\n await publishLifecycle(executionContext);\n return stopFor(ownedControl);\n } catch (error) {\n if (control === ownedControl) disposeControl();\n throw error;\n }\n },\n },\n ],\n tools: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: LIST_TOOL,\n label: 'List Workflows',\n description: 'List workflow definitions available in this repository.',\n parameters: z.toJSONSchema(feature.listWorkflowsTool.getInputSchema()),\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n const input = parameters as Parameters<typeof feature.listWorkflowsTool.execute>[0];\n return callResult(\n await feature.listWorkflowsTool.execute({\n ...input,\n directory:\n input?.directory === undefined\n ? context.cwd\n : typeof input.directory === 'string'\n ? resolve(context.cwd, input.directory)\n : input.directory,\n }),\n );\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: LAUNCH_TOOL,\n label: 'Launch Workflow',\n description: 'Start a workflow run and return its recorded launch result.',\n parameters: z.toJSONSchema(feature.runTool.getInputSchema()),\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n const input = parameters as Parameters<typeof feature.runTool.execute>[0];\n return callResult(\n await launch({\n ...input,\n ...(typeof input.workflowPath === 'string'\n ? { workflowPath: resolve(context.cwd, input.workflowPath) }\n : {}),\n }),\n );\n },\n },\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: RUN_TOOL,\n label: 'Workflow Run',\n description: 'Inspect the status of a workflow run or request cooperative control.',\n parameters: {\n type: 'object',\n properties: {\n action: { type: 'string', enum: ['status', 'pause', 'resume', 'stop'] },\n runKey: { type: 'string', minLength: 1 },\n workspace: { type: 'string' },\n reason: { type: 'string' },\n expectedRunId: { type: 'string' },\n },\n required: ['action', 'runKey'],\n additionalProperties: false,\n },\n executionMode: 'serial',\n async execute(_toolCallId, parameters, signal) {\n signal?.throwIfAborted();\n const input = parameters as unknown as {\n action: 'status' | 'pause' | 'resume' | 'stop';\n runKey: string;\n workspace?: string;\n reason?: string;\n expectedRunId?: string;\n };\n const runs = readWorkflowRuns({ environment: host.context.environment }).filter(\n (run) =>\n runBelongsToSession(run, host.context.sessionId) &&\n run.view.runKey === input.runKey &&\n (input.workspace === undefined || run.view.workspace === input.workspace),\n );\n if (runs.length !== 1)\n return {\n ...callResult({\n error:\n runs.length === 0\n ? 'Workflow run was not found in this session.'\n : 'Specify the workspace for this run key.',\n }),\n isError: true,\n };\n const run = runs[0]!.view;\n if (input.action === 'status') return callResult(run);\n if (!control) return callResult({ error: 'Workflow activity is not active.' });\n if (typeof input.expectedRunId !== 'string' || input.expectedRunId.length === 0) {\n return callResult({ error: 'expectedRunId is required for workflow control.' });\n }\n const request =\n input.action === 'pause'\n ? await control.pause(input.runKey, input.expectedRunId, input.workspace, input.reason)\n : input.action === 'resume'\n ? await control.resume(input.runKey, input.expectedRunId, input.workspace)\n : await control.stop(input.runKey, input.expectedRunId, input.workspace, input.reason);\n return callResult(request);\n },\n },\n ],\n commands: [\n {\n when: { state: { 'minor-mode': WORKFLOW_MODE_ID }, attribution: { kind: 'minor', mode: WORKFLOW_MODE_ID } },\n name: 'workflow-launch',\n description: 'Launch a workflow from a slash command.',\n async execute(args: string, execution: DoomHeadlessExecutionContext) {\n const parsed = parseWorkflowLaunchCommand(args);\n if ('error' in parsed) {\n await execution.client.notify({ body: parsed.error, level: 'error' });\n return;\n }\n try {\n const entry = resolveWorkflowEntry(await catalogReader.read(execution.cwd), parsed.workflow);\n if (!entry || entry.error) {\n await execution.client.notify({\n body: entry?.error ?? `Workflow not found: ${parsed.workflow}`,\n level: 'error',\n });\n return;\n }\n const problems = validateWorkflowLaunch(entry, parsed);\n if (problems.length > 0) {\n await execution.client.notify({ body: problems.join('\\n'), level: 'error' });\n return;\n }\n const result = callResult(\n await launch({\n workflowPath: entry.path,\n ...(parsed.runner === undefined ? {} : { runner: parsed.runner }),\n ...(Object.keys(parsed.inputs).length === 0 ? {} : { inputs: parsed.inputs }),\n ...(parsed.prompt === undefined ? {} : { prompt: parsed.prompt }),\n }),\n );\n const rendered = result.content.find((item) => item.type === 'text');\n await execution.client.notify({\n body: rendered?.type === 'text' ? rendered.text : 'Workflow launch requested.',\n level: result.isError ? 'error' : 'info',\n });\n } catch (error) {\n await execution.client.notify({ body: String(error), level: 'error' });\n }\n },\n },\n ],\n onDispose() {\n disposeControl();\n runProvider?.dispose();\n runProvider = undefined;\n },\n };\n}\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport type {\n WorkflowArtifactContentResponse,\n WorkflowArtifactsResponse,\n WorkflowControlResponse,\n WorkflowDeleteResponse,\n} from './webWorkflowTerminal';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/workflow/`, so the mount is stated once, by the\n * folder that creates it. The same API answers at all three scopes, because a\n * global contribution cascades into workspace and session; the folder under\n * `workspaces/sessions/` only re-mounts it for a session's own server.\n *\n * This is the one file the routes, the Hono app and the browser all read, so a\n * path cannot move on one side alone. The page used to build the hub's own\n * absolute URL and then rewrite its plugin prefix with String.replace to reach\n * a session, which is exactly the kind of copy that can move by one character\n * without anything noticing.\n *\n * `:workspace` and `:runKey` are Hono's own parameter syntax, because the app\n * registers `path` verbatim.\n */\n\n/** One run, which every route below addresses. */\nconst RUN = '/runs/:workspace/:runKey';\n\n/**\n * The artifact route's parameter, as Hono spells a multi-segment match.\n *\n * An artifact is named by its path inside the run directory, so `reports/a.md`\n * is one parameter across two segments. The client's `params` substitution\n * fills a single segment and percent-encodes the slash with it, so the page\n * substitutes this one itself; see the page's `_lib/terminalApi.ts`.\n */\nexport const ARTIFACT_NAME_PARAM = ':name{.+}';\n\n/** Query parameters the artifact route reads, spelled once for both halves. */\nexport const ARTIFACT_RAW_PARAM = 'raw';\nexport const ARTIFACT_DOWNLOAD_PARAM = 'download';\n\nexport default defineApiRoutes({\n /**\n * The terminal, as server-sent events.\n *\n * `stream: true` gets a URL and no call method: the consumer is the browser's\n * own `EventSource`, and a relayed call would buffer a stream that never ends.\n */\n screen: {\n method: 'GET',\n path: `${RUN}/screen/stream`,\n stream: true,\n },\n control: {\n method: 'POST',\n path: `${RUN}/control`,\n response: apiResponse<WorkflowControlResponse>(),\n },\n keys: {\n method: 'POST',\n path: `${RUN}/keys`,\n },\n resize: {\n method: 'POST',\n path: `${RUN}/resize`,\n response: apiResponse<{ resized: boolean }>(),\n },\n remove: {\n method: 'DELETE',\n path: RUN,\n response: apiResponse<WorkflowDeleteResponse>(),\n },\n artifacts: {\n method: 'GET',\n path: `${RUN}/artifacts`,\n response: apiResponse<WorkflowArtifactsResponse>(),\n },\n /** One artifact: its metadata and text, or its raw bytes under `raw=1`. */\n artifact: {\n method: 'GET',\n path: `${RUN}/artifacts/${ARTIFACT_NAME_PARAM}`,\n query: [ARTIFACT_RAW_PARAM, ARTIFACT_DOWNLOAD_PARAM],\n response: apiResponse<WorkflowArtifactContentResponse>(),\n },\n});\n","/**\n * The wire contract between this package's hub API and its cockpit client:\n * one run's terminal, and the files its run directory holds.\n *\n * Both halves of the cockpit import these names, so the route strings and the\n * event names live here rather than being spelled twice.\n */\n\n/**\n * Segment this package's API is mounted under, below /api/plugins/.\n *\n * The same word names `src/extensions/(backend)/api/workflow/`, which is where\n * the build reads the mount for the browser's client, so the two cannot drift.\n * The routes themselves are declared in `apiRoutes.ts`.\n */\nexport const WORKFLOW_API_BASE_PATH = 'workflow';\n\n/** The SSE event name the screen stream writes. */\nexport const WORKFLOW_SCREEN_EVENT = 'screen';\n\n/** What a surface may do with one run's terminal, and why anything is missing. */\nexport interface WorkflowTerminalCapabilitiesView {\n readable: boolean;\n writable: boolean;\n resizable: boolean;\n reason?: string;\n}\n\n/** One frame of a run's terminal, as the stream pushes it. */\nexport interface WorkflowScreenEvent {\n /** The visible screen, newest line last, carrying the colour the run printed. */\n lines: string[];\n capabilities: WorkflowTerminalCapabilitiesView;\n /** True once the run has settled, after which the stream ends. */\n ended?: boolean;\n}\n\n/** Answer to taking or releasing the keyboard for one run. */\nexport interface WorkflowControlResponse {\n /** True when this caller now holds the keyboard. */\n held: boolean;\n /** The token later writes must carry; absent when control was refused or released. */\n token?: string;\n /** Why control was refused, worded for a reader. */\n reason?: string;\n}\n\n/** Answer after a settled run and its directory have been permanently removed. */\nexport interface WorkflowDeleteResponse {\n deleted: true;\n}\n\n/** How a declared run-directory entry compares with what is on disk. */\nexport type WorkflowArtifactState = 'written' | 'empty' | 'pending' | 'unreadable';\n\n/** One file or directory in a run's own folder. */\nexport interface WorkflowArtifactView {\n /** Path relative to the run directory, which is also the read route's parameter. */\n path: string;\n kind: 'file' | 'directory';\n /** What the workflow says this file is for; empty for a file it never declared. */\n description: string;\n /** The jobs the workflow says write it. */\n producedBy: string[];\n /** True when the workflow's run-directory block names this entry. */\n declared: boolean;\n state: WorkflowArtifactState;\n /** Bytes on disk, absent until the file exists. */\n size?: number;\n /** ISO 8601 of the last write, absent until the file exists. */\n modifiedAt?: string;\n}\n\nexport interface WorkflowArtifactsResponse {\n /** Absolute path of the run's own directory, which the reader may want to open. */\n runDir: string;\n /** What the workflow says the directory is for. */\n description: string;\n artifacts: WorkflowArtifactView[];\n}\n\n/** One artifact's metadata and optional text, as the viewer tab reads it. */\nexport interface WorkflowArtifactContentResponse {\n path: string;\n size: number;\n modifiedAt: string;\n /** Media type inferred from the file extension by the trusted hub. Absent on older hubs. */\n mimeType?: string;\n /** Present for text formats; binary files are streamed from the raw route instead. */\n text?: string;\n /** True when textual content was longer than the reader's byte budget. */\n truncated: boolean;\n}\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\n\nimport type { DoomApi, DoomApiContext, DoomApiHandler } from '@agimon-ai/doompi-core/packageApi';\nimport {\n WorkflowRegistryService,\n WorkflowTerminalService as WorkflowTerminalFacade,\n type WorkflowRunRecord,\n type WorkflowStage,\n} from '@agimon-ai/workflow-mcp';\nimport { type Context, Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\n\nimport { createWorkflowTerminalService } from '../../services/workflowTerminal';\nimport routes, { ARTIFACT_DOWNLOAD_PARAM, ARTIFACT_RAW_PARAM } from '../../types/apiRoutes';\nimport {\n WORKFLOW_API_BASE_PATH,\n WORKFLOW_SCREEN_EVENT,\n type WorkflowArtifactContentResponse,\n type WorkflowArtifactsResponse,\n type WorkflowArtifactView,\n type WorkflowControlResponse,\n type WorkflowDeleteResponse,\n type WorkflowScreenEvent,\n} from '../../types/webWorkflowTerminal';\n\n/** Stages a run can be recorded under, newest first: a live run is the common case. */\nconst STAGES: readonly WorkflowStage[] = ['running', 'error', 'completed'];\n/** Lines of screen the stream sends, which is a terminal's visible height plus room. */\nconst SCREEN_LINES = 48;\n/** How often the stream re-reads; the service coalesces, so this is an upper bound. */\nconst STREAM_TICK_MS = 500;\n/** How often a settled run is re-checked before the stream closes itself. */\nconst SETTLED_POLL_TICKS = 4;\n/** Bytes of one textual artifact returned as JSON; binary previews use a stream. */\nconst MAX_ARTIFACT_BYTES = 512 * 1024;\n/** Path segments a client supplies are names, never paths. */\nconst SAFE_SEGMENT = /^[\\w.@-]+$/;\nconst ARTIFACT_MIME_TYPES: Readonly<Record<string, string>> = {\n '.aac': 'audio/aac',\n '.bmp': 'image/bmp',\n '.css': 'text/css',\n '.csv': 'text/csv',\n '.gif': 'image/gif',\n '.htm': 'text/html',\n '.html': 'text/html',\n '.ico': 'image/x-icon',\n '.jpeg': 'image/jpeg',\n '.jpg': 'image/jpeg',\n '.js': 'text/javascript',\n '.json': 'application/json',\n '.jsx': 'text/jsx',\n '.m4a': 'audio/mp4',\n '.markdown': 'text/markdown',\n '.md': 'text/markdown',\n '.mov': 'video/quicktime',\n '.mp3': 'audio/mpeg',\n '.mp4': 'video/mp4',\n '.oga': 'audio/ogg',\n '.ogg': 'audio/ogg',\n '.ogv': 'video/ogg',\n '.pdf': 'application/pdf',\n '.png': 'image/png',\n '.sh': 'text/x-shellscript',\n '.svg': 'image/svg+xml',\n '.toml': 'text/toml',\n '.ts': 'text/typescript',\n '.tsv': 'text/tab-separated-values',\n '.tsx': 'text/tsx',\n '.txt': 'text/plain',\n '.wav': 'audio/wav',\n '.webm': 'video/webm',\n '.webp': 'image/webp',\n '.xml': 'application/xml',\n '.yaml': 'text/yaml',\n '.yml': 'text/yaml',\n};\n\n/**\n * One request's JSON body as a plain record.\n *\n * A body that is absent, malformed, or not an object reads as empty rather\n * than failing the route: every field is checked by the route anyway, and a\n * 400 naming the missing field beats a parse error naming nothing.\n */\nasync function jsonBody(context: Context): Promise<Record<string, unknown>> {\n const parsed: unknown = await context.req.json().catch(() => undefined);\n return parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n}\n\n/** Rejects anything that could climb out of the registry before a path is built. */\nfunction isSafeSegment(value: string): boolean {\n return value !== '' && value !== '../adapters' && value !== '..' && SAFE_SEGMENT.test(value);\n}\n\n/** One run's identity for caches and leases, stable across stage moves. */\nfunction runIdentityOf(workspace: string, runKey: string): string {\n return `${workspace}/${runKey}`;\n}\n\nexport interface WorkflowHubApiOptions {\n registry?: WorkflowRegistryService;\n terminal?: WorkflowTerminalFacade;\n now?: () => number;\n}\n\n/**\n * This package's HTTP surface: one workflow run's terminal, and the files its\n * run directory holds.\n *\n * Mounted in the hub rather than in a session's server, because a run's\n * terminal belongs to its multiplexer rather than to the session that launched\n * it: any process can read a tmux pane, and the session's own server cannot\n * reach anything more. The routes therefore name a run, never a session.\n */\nexport function createWorkflowHubApi(options: WorkflowHubApiOptions = {}): Hono {\n const registry = options.registry ?? new WorkflowRegistryService();\n const facade = options.terminal ?? new WorkflowTerminalFacade();\n const terminal = createWorkflowTerminalService<WorkflowRunRecord>({\n terminal: facade,\n now: options.now ?? (() => Date.now()),\n });\n const app = new Hono();\n\n /** The record behind a request, whichever stage it now sits in. */\n const runOf = async (workspace: string, runKey: string): Promise<WorkflowRunRecord | undefined> => {\n if (!isSafeSegment(workspace) || !isSafeSegment(runKey)) return undefined;\n for (const stage of STAGES) {\n try {\n return await registry.readRunByKey(workspace, stage, runKey);\n } catch {\n // Not in this stage. A run moves between them as it settles, so a miss\n // here is ordinary; only a miss in every stage means no such run.\n }\n }\n return undefined;\n };\n\n const missing = (workspace: string, runKey: string): { error: string } => ({\n error: `No workflow run '${runKey}' in workspace '${workspace}'.`,\n });\n\n app.get(routes.screen.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const identity = runIdentityOf(workspace, runKey);\n\n return streamSSE(context, async (stream) => {\n let settledTicks = 0;\n let running = true;\n stream.onAbort(() => {\n running = false;\n });\n while (running) {\n const current = (await runOf(workspace, runKey)) ?? record;\n const capabilities = terminal.capabilities(current);\n const lines = capabilities.readable ? await terminal.screen(identity, current, SCREEN_LINES) : [];\n // A settled run is read a few more times before the stream closes: the\n // last thing a failing step printed is what the reader came for, and it\n // lands after the record has already moved to its final stage.\n const settled = current.stage !== 'running';\n if (settled) settledTicks += 1;\n const ended = settled && settledTicks >= SETTLED_POLL_TICKS;\n const event: WorkflowScreenEvent = { lines, capabilities, ...(ended ? { ended: true } : {}) };\n await stream.writeSSE({ event: WORKFLOW_SCREEN_EVENT, data: JSON.stringify(event) });\n if (ended) break;\n await stream.sleep(STREAM_TICK_MS);\n }\n terminal.forget(new Set());\n });\n });\n\n app.post(routes.control.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const identity = runIdentityOf(workspace, runKey);\n const body = await jsonBody(context);\n const capabilities = terminal.capabilities(record);\n\n if (body.release === true) {\n if (typeof body.token === 'string') terminal.releaseControl(identity, body.token);\n const released: WorkflowControlResponse = { held: false };\n return context.json(released);\n }\n if (!capabilities.writable) {\n const refused: WorkflowControlResponse = { held: false, reason: capabilities.reason };\n return context.json(refused, 409);\n }\n const token = typeof body.token === 'string' && body.token !== '' ? body.token : randomUUID();\n if (!terminal.takeControl(identity, token)) {\n const taken: WorkflowControlResponse = { held: false, reason: 'Another reader holds the keyboard.' };\n return context.json(taken, 409);\n }\n const held: WorkflowControlResponse = { held: true, token };\n return context.json(held);\n });\n\n app.post(routes.keys.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const body = await jsonBody(context);\n if (typeof body.token !== 'string' || typeof body.data !== 'string') {\n return context.json({ error: 'A keystroke needs a control token and its data.' }, 400);\n }\n try {\n await terminal.write(runIdentityOf(workspace, runKey), record, body.token, body.data);\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n return context.body(null, 204);\n });\n\n app.post(routes.resize.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const body = await jsonBody(context);\n const { token, columns, rows } = body;\n if (typeof token !== 'string' || typeof columns !== 'number' || typeof rows !== 'number') {\n return context.json({ error: 'A resize needs a control token, columns and rows.' }, 400);\n }\n try {\n const resized = await terminal.resize(runIdentityOf(workspace, runKey), record, token, columns, rows);\n return context.json({ resized });\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n });\n\n app.delete(routes.remove.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n if (record.stage === 'running') {\n return context.json({ error: 'A running workflow must be stopped before it can be deleted.' }, 409);\n }\n try {\n fs.rmSync(registry.runDirectoryFor(record), { recursive: true, force: true });\n } catch (error) {\n return context.json({ error: error instanceof Error ? error.message : String(error) }, 409);\n }\n const response: WorkflowDeleteResponse = { deleted: true };\n return context.json(response);\n });\n\n app.get(routes.artifacts.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const runDir = registry.runDirectoryFor(record);\n const body: WorkflowArtifactsResponse = {\n runDir,\n description: record.runDirectory?.description ?? '',\n artifacts: readArtifacts(runDir, record),\n };\n return context.json(body);\n });\n\n app.get(routes.artifact.path, async (context) => {\n const workspace = context.req.param('workspace');\n const runKey = context.req.param('runKey');\n const record = await runOf(workspace, runKey);\n if (record === undefined) return context.json(missing(workspace, runKey), 404);\n const runDir = registry.runDirectoryFor(record);\n const requested = context.req.param('name');\n const resolved = resolveInside(runDir, requested);\n if (resolved === undefined) return context.json({ error: `'${requested}' is not inside this run.` }, 400);\n if (context.req.query(ARTIFACT_RAW_PARAM) === '1') {\n const response = streamArtifact(\n resolved,\n requested,\n context.req.header('range'),\n context.req.query(ARTIFACT_DOWNLOAD_PARAM) === '1',\n );\n return response ?? context.json({ error: `'${requested}' has not been written.` }, 404);\n }\n const body = readArtifact(resolved, requested);\n if (body === undefined) return context.json({ error: `'${requested}' has not been written.` }, 404);\n return context.json(body);\n });\n\n return app;\n}\n\n/**\n * A path inside the run directory, or undefined when it points anywhere else.\n *\n * The client supplies this one verbatim, unlike the run key, so it is resolved\n * and then checked rather than trusted: without the check the route would read\n * any file the hub can reach.\n */\nfunction resolveInside(runDir: string, requested: string): string | undefined {\n const resolved = path.resolve(runDir, requested);\n const root = path.resolve(runDir);\n if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) return undefined;\n return resolved;\n}\n\n/** Size and modification time of one path, or undefined when it is not there. */\nfunction statOf(target: string): fs.Stats | undefined {\n try {\n return fs.statSync(target);\n } catch {\n return undefined; // Not written yet, which is an ordinary state for an artifact.\n }\n}\n\nfunction stateOf(stats: fs.Stats | undefined): WorkflowArtifactView['state'] {\n if (stats === undefined) return 'pending';\n if (stats.isDirectory()) return 'written';\n return stats.size === 0 ? 'empty' : 'written';\n}\n\nfunction viewOf(\n runDir: string,\n entry: Omit<WorkflowArtifactView, 'state' | 'size' | 'modifiedAt'>,\n): WorkflowArtifactView {\n const stats = statOf(path.join(runDir, entry.path));\n return {\n ...entry,\n state: stateOf(stats),\n ...(stats === undefined ? {} : { size: stats.size, modifiedAt: stats.mtime.toISOString() }),\n };\n}\n\n/**\n * What the run directory holds: the workflow's own declaration first, then the\n * files nobody declared.\n *\n * The declaration is the point of the folder, so it leads and keeps its order\n * even for entries no job has written yet. The rest follows rather than being\n * hidden: the engine's own context.md and progress log are often exactly what a\n * reader is looking for.\n */\nfunction readArtifacts(runDir: string, record: WorkflowRunRecord): WorkflowArtifactView[] {\n const declared = (record.runDirectory?.entries ?? []).map((entry) =>\n viewOf(runDir, {\n path: entry.path,\n kind: entry.kind,\n description: entry.description,\n producedBy: entry['produced-by'] ?? [],\n declared: true,\n }),\n );\n const claimed = new Set(declared.map((entry) => entry.path));\n let names: fs.Dirent[];\n try {\n names = fs.readdirSync(runDir, { withFileTypes: true });\n } catch {\n return declared; // The directory is gone; the declaration is still worth showing.\n }\n const found = names\n .filter((entry) => !claimed.has(entry.name))\n .map((entry) =>\n viewOf(runDir, {\n path: entry.name,\n kind: entry.isDirectory() ? 'directory' : 'file',\n description: '',\n producedBy: [],\n declared: false,\n }),\n )\n .sort((left, right) => left.path.localeCompare(right.path));\n return [...declared, ...found];\n}\n\n/** Browser content type inferred from a filename without trusting client input. */\nfunction artifactMimeType(requested: string): string {\n return ARTIFACT_MIME_TYPES[path.extname(requested).toLowerCase()] ?? 'application/octet-stream';\n}\n\nfunction isTextArtifact(mimeType: string): boolean {\n return mimeType.startsWith('text/') || mimeType === 'application/json' || mimeType === 'application/xml';\n}\n\n/** One artifact's metadata and bounded text, or undefined when it is not readable. */\nfunction readArtifact(resolved: string, requested: string): WorkflowArtifactContentResponse | undefined {\n const stats = statOf(resolved);\n if (stats === undefined || stats.isDirectory()) return undefined;\n const mimeType = artifactMimeType(requested);\n let text: string | undefined;\n if (isTextArtifact(mimeType)) {\n try {\n const handle = fs.openSync(resolved, 'r');\n try {\n const buffer = Buffer.alloc(Math.min(stats.size, MAX_ARTIFACT_BYTES));\n fs.readSync(handle, buffer, 0, buffer.length, 0);\n text = buffer.toString('utf8');\n } finally {\n fs.closeSync(handle);\n }\n } catch {\n return undefined;\n }\n }\n return {\n path: requested,\n size: stats.size,\n modifiedAt: stats.mtime.toISOString(),\n mimeType,\n ...(text === undefined ? {} : { text }),\n truncated: text !== undefined && stats.size > MAX_ARTIFACT_BYTES,\n };\n}\n\n/** Streams media with byte-range support so browser audio, video, and PDF controls can seek. */\nfunction streamArtifact(\n resolved: string,\n requested: string,\n rangeHeader: string | undefined,\n download: boolean,\n): Response | undefined {\n const stats = statOf(resolved);\n if (stats === undefined || stats.isDirectory()) return undefined;\n const mimeType = artifactMimeType(requested);\n let start = 0;\n let end = Math.max(0, stats.size - 1);\n let partial = false;\n const match = rangeHeader?.match(/^bytes=(\\d*)-(\\d*)$/);\n if (match !== null && match !== undefined && stats.size > 0) {\n const requestedStart = match[1] === '' ? undefined : Number(match[1]);\n const requestedEnd = match[2] === '' ? undefined : Number(match[2]);\n if (requestedStart === undefined && requestedEnd !== undefined) {\n start = Math.max(0, stats.size - requestedEnd);\n } else if (requestedStart !== undefined) {\n start = requestedStart;\n end = requestedEnd === undefined ? end : Math.min(requestedEnd, end);\n }\n if (start >= stats.size || start > end) {\n return new Response(null, { status: 416, headers: { 'content-range': `bytes */${String(stats.size)}` } });\n }\n partial = true;\n }\n const filename = path.basename(requested).replace(/[\"\\\\\\r\\n]/g, '_');\n const forceDownload = download || mimeType === 'text/html';\n const headers = new Headers({\n 'accept-ranges': 'bytes',\n 'content-disposition': `${forceDownload ? 'attachment' : 'inline'}; filename=\"${filename}\"`,\n 'content-length': String(stats.size === 0 ? 0 : end - start + 1),\n 'content-type': mimeType,\n 'x-content-type-options': 'nosniff',\n });\n if (partial) headers.set('content-range', `bytes ${String(start)}-${String(end)}/${String(stats.size)}`);\n if (stats.size === 0) return new Response(null, { status: 200, headers });\n const body = Readable.toWeb(fs.createReadStream(resolved, { start, end }));\n return new Response(body, { status: partial ? 206 : 200, headers });\n}\n\n/** The named export a host imports from this package's built hub entry. */\nexport const api: DoomApi = {\n basePath: WORKFLOW_API_BASE_PATH,\n start(_context: DoomApiContext): DoomApiHandler {\n // Hub-scoped: the host hands no session, and these routes want none. A run\n // is addressed by its registry identity, which is machine-wide.\n const app = createWorkflowHubApi();\n return {\n fetch: (request) => app.fetch(request),\n // Nothing outlives a request: a stream's loop ends when its own socket\n // aborts, and the caches it touched are per run rather than per client.\n close: () => undefined,\n };\n },\n};\n","import type { DoomServerPluginDefinition } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { createWorkflowServerRuntime } from '../../../../../services/serverRuntime';\nimport { api } from '../../../../../services/workflowHubApi';\n\nexport default (({ agent, host }) => ({\n api: [api],\n ...(agent ? createWorkflowServerRuntime(agent, host) : {}),\n})) satisfies NonNullable<DoomServerPluginDefinition['session']>;\n","import { defineRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from './_lib/index.server';\n\nexport default defineRoot((context: Parameters<typeof runtime>[0]) => {\n const value = runtime(context);\n return {\n value,\n services: value.services,\n activities: value.activities,\n onStart: value.onStart,\n onStop: value.onStop,\n onDispose: value.onDispose,\n };\n});\n","import type { DoomHubChannelSource, DoomHubSessionScope, DoomHubChannel } from '@agimon-ai/doompi-core/hubChannel';\n\nimport {\n createWorkflowCatalogReader,\n presentWorkflowCatalog,\n type WorkflowCatalogReaderDeps,\n} from '../../services/webWorkflowCatalog';\nimport { defaultCatalogDeps } from '../../services/workflowCatalogDeps';\nimport { WORKFLOW_CATALOG_TYPE, type WorkflowCatalogPayload } from '../../types/webWorkflows';\n\nexport interface WorkflowCatalogChannelOptions {\n deps?: WorkflowCatalogReaderDeps;\n}\n\n/**\n * The workflow catalog channel. Durable state seeds a session once, then\n * session lifecycle events deliver updates over the direct event bus.\n */\nexport function createWorkflowCatalogChannel(options: WorkflowCatalogChannelOptions = {}): DoomHubChannel {\n const reader = createWorkflowCatalogReader(options.deps ?? defaultCatalogDeps());\n return {\n frameType: WORKFLOW_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, DoomHubSessionScope>();\n const latest = new Map<string, WorkflowCatalogPayload>();\n const subscriptions = new Map<string, () => void>();\n const publish = (scope: DoomHubSessionScope, payload: WorkflowCatalogPayload): void => {\n latest.set(scope.sessionId, payload);\n host.publish(scope.sessionId, payload);\n };\n const readInitial = async (scope: DoomHubSessionScope): Promise<void> => {\n let payload: WorkflowCatalogPayload;\n try {\n payload = {\n cwd: scope.cwd,\n workflows: presentWorkflowCatalog(await reader.read(scope.cwd)),\n };\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n payload = { cwd: scope.cwd, workflows: [], warning };\n host.onNotice(`workflow catalog for ${scope.cwd} is unavailable (${warning})`);\n }\n if (scopes.get(scope.sessionId) === scope) publish(scope, payload);\n };\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n return scopes.has(scope.sessionId) ? latest.get(scope.sessionId) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n subscriptions.get(scope.sessionId)?.();\n const unsubscribe = host.directEvents.subscribe(\n WORKFLOW_CATALOG_TYPE,\n scope.sessionId,\n (value) => {\n if (isWorkflowCatalogPayload(value)) publish(scope, value);\n },\n { replayLatest: true },\n );\n subscriptions.set(scope.sessionId, unsubscribe);\n void readInitial(scope);\n },\n sessionRemoved(sessionId) {\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n\nfunction isWorkflowCatalogPayload(value: unknown): value is WorkflowCatalogPayload {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { cwd?: unknown }).cwd === 'string' &&\n Array.isArray((value as { workflows?: unknown }).workflows)\n );\n}\n","import type { DoomHubChannelSource, DoomHubSessionScope, DoomHubChannel } from '@agimon-ai/doompi-core/hubChannel';\n\nimport { presentWorkflowRuns, runBelongsToSession, type ParsedWorkflowRun } from '../../services/workflowRuns';\nimport { readWorkflowRuns, type ReadWorkflowRunsOptions } from '../../services/workflowWatcher';\nimport { WORKFLOW_RUNS_TYPE, type WorkflowRunView, type WorkflowRunsPayload } from '../../types/webWorkflows';\n\nexport interface WorkflowsChannelOptions {\n /** Injectable durable initial snapshot reader for tests. */\n read?: (options: ReadWorkflowRunsOptions) => ParsedWorkflowRun[];\n}\n\nfunction isWorkflowRunsPayload(value: unknown): value is WorkflowRunsPayload {\n return typeof value === 'object' && value !== null && Array.isArray((value as { runs?: unknown }).runs);\n}\n\n/**\n * The workflow runs data channel. Durable registry state seeds each session\n * once; subsequent updates arrive through the host-owned direct event bus.\n */\nexport function createWorkflowsChannel(options: WorkflowsChannelOptions = {}): DoomHubChannel {\n const read = options.read ?? readWorkflowRuns;\n return {\n frameType: WORKFLOW_RUNS_TYPE,\n start(host) {\n const scopes = new Map<string, DoomHubSessionScope>();\n const latest = new Map<string, WorkflowRunsPayload>();\n const subscriptions = new Map<string, () => void>();\n const runsFor = (scope: DoomHubSessionScope, parsed: readonly ParsedWorkflowRun[]): WorkflowRunView[] =>\n presentWorkflowRuns(\n parsed.filter((run) => runBelongsToSession(run, scope.sessionId)).map((run) => run.view),\n Date.now(),\n );\n const publish = (scope: DoomHubSessionScope, payload: WorkflowRunsPayload): void => {\n latest.set(scope.sessionId, payload);\n host.publish(scope.sessionId, payload);\n };\n const source: DoomHubChannelSource = {\n payloadFor(scope) {\n return scopes.has(scope.sessionId) ? latest.get(scope.sessionId) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n subscriptions.get(scope.sessionId)?.();\n const unsubscribe = host.directEvents.subscribe(\n WORKFLOW_RUNS_TYPE,\n scope.sessionId,\n (value) => {\n if (isWorkflowRunsPayload(value)) publish(scope, value);\n },\n { replayLatest: true },\n );\n subscriptions.set(scope.sessionId, unsubscribe);\n const payload = { runs: runsFor(scope, read({ environment: scope.environment })) };\n publish(scope, payload);\n },\n sessionRemoved(sessionId) {\n subscriptions.get(sessionId)?.();\n subscriptions.delete(sessionId);\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n for (const unsubscribe of subscriptions.values()) unsubscribe();\n subscriptions.clear();\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n","import type { DoomServerPluginDefinition } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { createWorkflowCatalogChannel } from '../../../services/workflowCatalogChannel';\nimport { api } from '../../../services/workflowHubApi';\nimport { createWorkflowsChannel } from '../../../services/workflowsHubChannel';\n\nexport default (({ host }) =>\n host.scope === 'session'\n ? {}\n : { channels: [createWorkflowsChannel, createWorkflowCatalogChannel], api: [api] }) satisfies NonNullable<\n DoomServerPluginDefinition['global']\n>;\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\n\nimport legacy from '../../_lib/index.server';\n\nexport default defineRoutedContribution((context: Parameters<typeof legacy>[0]) => legacy(context).api?.[0], {\n cardinality: 'optional',\n});\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createWorkflowCatalogChannel } from '../../../services/workflowCatalogChannel';\n\nexport default defineChannel(createWorkflowCatalogChannel);\n","import { defineChannel } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { createWorkflowsChannel } from '../../../services/workflowsHubChannel';\n\nexport default defineChannel(createWorkflowsChannel);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.api?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\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';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.hooks?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.hooks?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.resources?.[2],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[1],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[0],\n { cardinality: 'optional' },\n);\n","import { defineRoutedContribution, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\n\nimport runtime from '../_lib/index.server';\n\nexport default defineRoutedContribution(\n (context: WithRoot<unknown, ReturnType<typeof runtime>>) => context.root.tools?.[2],\n { cardinality: 'optional' },\n);\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/doompi-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport apiRoute from '../src/extensions/(backend)/api/workflow/route.server';\nimport channelWorkflowCatalog from '../src/extensions/(backend)/channel/workflow-catalog.server';\nimport channelWorkflows from '../src/extensions/(backend)/channel/workflows.server';\nimport apiRoute2 from '../src/extensions/workspaces/sessions/(backend)/api/workflow/route.server';\nimport commandWorkflowLaunch from '../src/extensions/workspaces/sessions/(backend)/command/workflow-launch.server';\nimport hookSessionShutdown from '../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server';\nimport hookToolExecutionEnd from '../src/extensions/workspaces/sessions/(backend)/hook/tool-execution-end.server';\nimport resourceDoompiAuthorWorkflow from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-workflow.server';\nimport resourceDoompiUseWorkflow from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-use-workflow.server';\nimport resourceWorkflowRecovery from '../src/extensions/workspaces/sessions/(backend)/resource/workflow-recovery.server';\nimport toolLaunchWorkflow from '../src/extensions/workspaces/sessions/(backend)/tool/launch-workflow.server';\nimport toolListWorkflows from '../src/extensions/workspaces/sessions/(backend)/tool/list-workflows.server';\nimport toolWorkflowRun from '../src/extensions/workspaces/sessions/(backend)/tool/workflow-run.server';\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;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-workflow',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n }),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context), at(apiRoute2, contextSession)]); },\n get channels(): DoomServerSessionPlugin['channels'] { return [() => via({ frameType: 'workflow_catalog' }, channelWorkflowCatalog()), () => via({ frameType: 'workflows' }, channelWorkflows())]; },\n get commands(): DoomServerSessionPlugin['commands'] { return defined([via({ name: 'workflow-launch' }, at(commandWorkflowLaunch, contextSession))]); },\n get hooks(): DoomServerSessionPlugin['hooks'] { return defined([via({ event: 'session_shutdown' }, at(hookSessionShutdown, contextSession)), via({ event: 'tool_execution_end' }, at(hookToolExecutionEnd, contextSession))]); },\n get resources(): DoomServerSessionPlugin['resources'] { return defined([at(resourceDoompiAuthorWorkflow, contextSession), at(resourceDoompiUseWorkflow, contextSession), at(resourceWorkflowRecovery, contextSession)]); },\n get tools(): DoomServerSessionPlugin['tools'] { return defined([via({ name: 'launch_workflow' }, at(toolLaunchWorkflow, contextSession)), via({ name: 'list_workflows' }, at(toolListWorkflows, contextSession)), via({ name: 'workflow_run' }, at(toolWorkflowRun, contextSession))]); },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
|