{"version":3,"file":"index.cjs","names":["workflowDispatchInputsSchema","toolResultText","workflowCatalogPageSchema","resolve"],"sources":["../../../../src/services/workflowLauncher/index.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport { type EmbeddedWorkflowFeature, type Workflow } from '@agimon-ai/workflow-mcp';\nimport type { ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { type DispatchInput, workflowCatalogPageSchema, workflowDispatchInputsSchema } from '../../schemas/workflowPi';\nimport type {\n  WorkflowCatalogDetail,\n  WorkflowInputSummary,\n  WorkflowJobSummary,\n} from '../../tui/workflow/workflowCatalog';\nimport { toolResultText } from '../piToolBridge';\nimport { type WorkflowLaunchExecutor, type WorkflowLaunchInput } from '../workflowExecution';\n\nconst CATALOG_PAGE_SIZE = 100;\nconst USER_PROMPT_TRIGGER = 'user_prompt';\nconst WORKFLOW_DISPATCH_TRIGGER = 'workflow_dispatch';\nconst BOOLEAN_INPUT_TYPE = 'boolean';\n\ntype WorkflowListTool = EmbeddedWorkflowFeature['listWorkflowsTool'];\ntype WorkflowListInput = Parameters<WorkflowListTool['execute']>[0];\n\nexport interface WorkflowCatalogEntry {\n  description: string;\n  name: string;\n  path: string;\n  relativePath: string;\n  tags: string[];\n}\n\nexport interface WorkflowCatalogPage {\n  directory: string;\n  hasNextPage: boolean;\n  page: number;\n  pageSize: number;\n  workflows: WorkflowCatalogEntry[];\n}\n\nexport interface WorkflowLauncherUi {\n  editor(title: string, prefill?: string): Promise<string | undefined>;\n  input(title: string, placeholder?: string): Promise<string | undefined>;\n  notify(message: string, type?: 'info' | 'warning' | 'error'): void;\n  select(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface WorkflowEntryLaunchOptions {\n  compatibleRunners(workflow: Workflow): string[] | undefined;\n  launch: WorkflowLaunchExecutor['execute'];\n  parseWorkflow(workflowPath: string): Workflow;\n  ui: WorkflowLauncherUi;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n  return value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};\n}\n\nfunction workflowTriggerBlock(workflow: Workflow): Record<string, unknown> {\n  return asRecord(workflow.on);\n}\n\nfunction dispatchInputs(workflow: Workflow): Record<string, DispatchInput> {\n  const dispatch = workflowTriggerBlock(workflow)[WORKFLOW_DISPATCH_TRIGGER];\n  if (dispatch === null || dispatch === undefined) return {};\n  const parsed = workflowDispatchInputsSchema.safeParse(dispatch);\n  if (!parsed.success) throw new Error(`Invalid workflow_dispatch input definitions: ${parsed.error.message}`);\n  return parsed.data.inputs ?? {};\n}\n\nfunction launchResultError(result: CallToolResult): Error {\n  return new Error(toolResultText(result) || 'Workflow launch failed.');\n}\n\nexport function parseWorkflowCatalogPage(result: CallToolResult): WorkflowCatalogPage {\n  if (result.isError) throw launchResultError(result);\n  let value: unknown;\n  try {\n    value = JSON.parse(toolResultText(result));\n  } catch (cause) {\n    throw new Error('Workflow catalog returned invalid JSON.', { cause });\n  }\n  const parsed = workflowCatalogPageSchema.safeParse(value);\n  if (!parsed.success) throw new Error(`Workflow catalog response was invalid: ${parsed.error.message}`);\n  return {\n    directory: parsed.data.directory,\n    hasNextPage: parsed.data.hasNextPage,\n    page: parsed.data.page,\n    pageSize: parsed.data.pageSize,\n    workflows: parsed.data.workflows.map((entry) => ({\n      description: entry.description,\n      name: entry.name,\n      path: resolve(parsed.data.directory, entry.path),\n      relativePath: entry.path,\n      tags: entry.tags,\n    })),\n  };\n}\n\nexport async function loadWorkflowCatalog(\n  listWorkflowsTool: WorkflowListTool,\n  directory: string,\n): Promise<WorkflowCatalogEntry[]> {\n  const entries: WorkflowCatalogEntry[] = [];\n  let page = 1;\n  let hasNextPage = true;\n  while (hasNextPage) {\n    const input: WorkflowListInput = { directory, page, pageSize: CATALOG_PAGE_SIZE };\n    const result = await listWorkflowsTool.execute(input);\n    const catalogPage = parseWorkflowCatalogPage(result);\n    entries.push(...catalogPage.workflows);\n    hasNextPage = catalogPage.hasNextPage;\n    page += 1;\n  }\n  return entries;\n}\n\nasync function requestPrompt(ui: WorkflowLauncherUi): Promise<string | undefined> {\n  while (true) {\n    const value = await ui.editor('Workflow prompt');\n    if (value === undefined) return undefined;\n    const prompt = value.trim();\n    if (prompt) return prompt;\n    ui.notify('A workflow prompt is required.', 'warning');\n  }\n}\n\nasync function requestDispatchInput(\n  ui: WorkflowLauncherUi,\n  name: string,\n  input: DispatchInput,\n): Promise<string | undefined> {\n  const title = input.description ? `${name}: ${input.description}` : `Workflow input: ${name}`;\n  if (input.options && input.options.length > 0) return ui.select(title, input.options);\n  if (input.type === BOOLEAN_INPUT_TYPE) return ui.select(title, ['true', 'false']);\n\n  while (true) {\n    const value = await ui.input(title, input.default);\n    if (value === undefined) return undefined;\n    const normalized = value.trim() || input.default;\n    if (normalized || !input.required) return normalized || undefined;\n    ui.notify(`A value is required for workflow input ${name}.`, 'warning');\n  }\n}\n\nexport async function collectWorkflowInputs(\n  workflow: Workflow,\n  ui: WorkflowLauncherUi,\n): Promise<{ inputs?: Record<string, string>; prompt?: string } | undefined> {\n  const triggers = workflowTriggerBlock(workflow);\n  const requiresPrompt = Object.hasOwn(triggers, USER_PROMPT_TRIGGER);\n  const prompt = requiresPrompt ? await requestPrompt(ui) : undefined;\n  if (requiresPrompt && prompt === undefined) return undefined;\n\n  const definitions = dispatchInputs(workflow);\n  const inputs: Record<string, string> = {};\n  for (const [name, definition] of Object.entries(definitions)) {\n    const value = await requestDispatchInput(ui, name, definition);\n    if (value === undefined && definition.required) return undefined;\n    if (value !== undefined) inputs[name] = value;\n  }\n  return {\n    ...(prompt === undefined ? {} : { prompt }),\n    ...(Object.keys(inputs).length === 0 ? {} : { inputs }),\n  };\n}\n\n/**\n * Everything a launch needs once the workflow is chosen: the runner, the\n * prompt, and any `workflow_dispatch` inputs, each asked for through the\n * host's own dialogs. Selection is the caller's business - `SPC w l` launches\n * the row under its cursor, so this takes an entry rather than picking one.\n */\nfunction stepLabel(step: { name?: string; uses?: string; run?: unknown; id?: string }, index: number): string {\n  if (step.name) return step.name;\n  if (step.uses) return step.uses;\n  if (step.id) return step.id;\n  // A `run:` step without a name is identified by its position; printing the\n  // command would put a shell line into a summary pane.\n  return `step ${index + 1}`;\n}\n\nfunction catalogInputs(workflow: Workflow): WorkflowInputSummary[] {\n  return Object.entries(dispatchInputs(workflow)).map(([name, definition]) => ({\n    name,\n    ...(definition.description ? { description: definition.description } : {}),\n    ...(definition.required === undefined ? {} : { required: definition.required }),\n    ...(definition.default === undefined ? {} : { default: definition.default }),\n    ...(definition.options ? { options: definition.options } : {}),\n  }));\n}\n\nfunction catalogJobs(workflow: Workflow): WorkflowJobSummary[] {\n  return Object.entries(workflow.jobs ?? {}).map(([name, job]) => ({\n    name,\n    steps: (job.steps ?? []).map((step, index) => stepLabel(step, index)),\n  }));\n}\n\n/**\n * The parsed shape `SPC w l`'s detail pane shows. A parse failure is returned\n * as `error` rather than thrown: one unparseable file in a repository must not\n * take the whole board down.\n */\nexport function summarizeWorkflowFile(\n  workflowPath: string,\n  options: Pick<WorkflowEntryLaunchOptions, 'compatibleRunners' | 'parseWorkflow'>,\n): WorkflowCatalogDetail {\n  try {\n    const workflow = options.parseWorkflow(workflowPath);\n    const runners = options.compatibleRunners(workflow);\n    return {\n      triggers: Object.keys(workflowTriggerBlock(workflow)),\n      inputs: catalogInputs(workflow),\n      jobs: catalogJobs(workflow),\n      ...(runners ? { runners } : {}),\n    };\n  } catch (cause) {\n    return {\n      triggers: [],\n      inputs: [],\n      jobs: [],\n      error: cause instanceof Error ? cause.message : String(cause),\n    };\n  }\n}\n\nexport async function launchWorkflowEntry(\n  options: WorkflowEntryLaunchOptions,\n  selected: Pick<WorkflowCatalogEntry, 'path'>,\n  ctx: ExtensionContext,\n): Promise<CallToolResult | undefined> {\n  const workflow = options.parseWorkflow(selected.path);\n  const runners = options.compatibleRunners(workflow);\n  if (runners && runners.length === 0) throw new Error('No compatible runner is available for this workflow.');\n  let runner: string | undefined;\n  if (runners) {\n    runner = await options.ui.select('Select a workflow runner', runners);\n    if (runner === undefined) return undefined;\n  }\n\n  const triggerInputs = await collectWorkflowInputs(workflow, options.ui);\n  if (triggerInputs === undefined) return undefined;\n  const launchInput: WorkflowLaunchInput = {\n    workflowPath: selected.path,\n    ...(runner === undefined ? {} : { runner }),\n    ...(typeof workflow.workspace === 'string' ? { workspace: workflow.workspace } : {}),\n    ...triggerInputs,\n  };\n  return options.launch(launchInput, ctx);\n}\n"],"mappings":"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"}