@agimon-ai/doompi-workflow 0.0.1-alpha.37 → 0.0.1-alpha.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -0
- package/README.md +14 -8
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/adapters/pi/extension.cjs +1 -1
- package/dist/adapters/pi/extension.mjs +1 -1
- package/dist/adapters/pi/workflow/piExtension.cjs +6 -8
- package/dist/adapters/pi/workflow/piExtension.cjs.map +1 -1
- package/dist/adapters/pi/workflow/piExtension.mjs +6 -8
- package/dist/adapters/pi/workflow/piExtension.mjs.map +1 -1
- package/dist/adapters/pi/workflow/piTools.cjs +3 -3
- package/dist/adapters/pi/workflow/piTools.mjs +3 -3
- package/dist/adapters/pi/workflow/workflowLauncher.cjs +1 -1
- package/dist/adapters/pi/workflow/workflowLauncher.cjs.map +1 -1
- package/dist/adapters/pi/workflow/workflowLauncher.mjs +1 -1
- package/dist/adapters/pi/workflow/workflowLauncher.mjs.map +1 -1
- package/dist/adapters/workflowCatalogChannel.cjs +2 -0
- package/dist/adapters/workflowCatalogChannel.cjs.map +1 -0
- package/dist/adapters/workflowCatalogChannel.d.cts +23 -0
- package/dist/adapters/workflowCatalogChannel.d.cts.map +1 -0
- package/dist/adapters/workflowCatalogChannel.d.mts +23 -0
- package/dist/adapters/workflowCatalogChannel.d.mts.map +1 -0
- package/dist/adapters/workflowCatalogChannel.mjs +2 -0
- package/dist/adapters/workflowCatalogChannel.mjs.map +1 -0
- package/dist/adapters/workflowHubApi.cjs +2 -0
- package/dist/adapters/workflowHubApi.cjs.map +1 -0
- package/dist/adapters/workflowHubApi.d.cts +24 -0
- package/dist/adapters/workflowHubApi.d.cts.map +1 -0
- package/dist/adapters/workflowHubApi.d.mts +24 -0
- package/dist/adapters/workflowHubApi.d.mts.map +1 -0
- package/dist/adapters/workflowHubApi.mjs +2 -0
- package/dist/adapters/workflowHubApi.mjs.map +1 -0
- package/dist/adapters/workflowWatcher.cjs +2 -0
- package/dist/adapters/workflowWatcher.cjs.map +1 -0
- package/dist/adapters/workflowWatcher.d.cts +24 -0
- package/dist/adapters/workflowWatcher.d.cts.map +1 -0
- package/dist/adapters/workflowWatcher.d.mts +24 -0
- package/dist/adapters/workflowWatcher.d.mts.map +1 -0
- package/dist/adapters/workflowWatcher.mjs +2 -0
- package/dist/adapters/workflowWatcher.mjs.map +1 -0
- package/dist/adapters/workflowsHubChannel.cjs +2 -0
- package/dist/adapters/workflowsHubChannel.cjs.map +1 -0
- package/dist/adapters/workflowsHubChannel.d.cts +20 -0
- package/dist/adapters/workflowsHubChannel.d.cts.map +1 -0
- package/dist/adapters/workflowsHubChannel.d.mts +20 -0
- package/dist/adapters/workflowsHubChannel.d.mts.map +1 -0
- package/dist/adapters/workflowsHubChannel.mjs +2 -0
- package/dist/adapters/workflowsHubChannel.mjs.map +1 -0
- package/dist/hubApi.cjs +1 -0
- package/dist/hubApi.d.cts +2 -0
- package/dist/hubApi.d.mts +2 -0
- package/dist/hubApi.mjs +1 -0
- package/dist/schemas/workflowPi.cjs +1 -1
- package/dist/schemas/workflowPi.cjs.map +1 -1
- package/dist/schemas/workflowPi.mjs +1 -1
- package/dist/schemas/workflowPi.mjs.map +1 -1
- package/dist/services/webWorkflowCatalog.cjs +2 -0
- package/dist/services/webWorkflowCatalog.cjs.map +1 -0
- package/dist/services/webWorkflowCatalog.d.cts +49 -0
- package/dist/services/webWorkflowCatalog.d.cts.map +1 -0
- package/dist/services/webWorkflowCatalog.d.mts +49 -0
- package/dist/services/webWorkflowCatalog.d.mts.map +1 -0
- package/dist/services/webWorkflowCatalog.mjs +2 -0
- package/dist/services/webWorkflowCatalog.mjs.map +1 -0
- package/dist/services/workflowLaunchCommand.cjs +2 -0
- package/dist/services/workflowLaunchCommand.cjs.map +1 -0
- package/dist/services/workflowLaunchCommand.mjs +2 -0
- package/dist/services/workflowLaunchCommand.mjs.map +1 -0
- package/dist/services/workflowRuns.cjs +3 -0
- package/dist/services/workflowRuns.cjs.map +1 -0
- package/dist/services/workflowRuns.d.cts +17 -0
- package/dist/services/workflowRuns.d.cts.map +1 -0
- package/dist/services/workflowRuns.d.mts +17 -0
- package/dist/services/workflowRuns.d.mts.map +1 -0
- package/dist/services/workflowRuns.mjs +3 -0
- package/dist/services/workflowRuns.mjs.map +1 -0
- package/dist/services/workflowTerminal.cjs +2 -0
- package/dist/services/workflowTerminal.cjs.map +1 -0
- package/dist/services/workflowTerminal.mjs +2 -0
- package/dist/services/workflowTerminal.mjs.map +1 -0
- package/dist/tui/workflow/workflowCatalog.cjs +1 -1
- package/dist/tui/workflow/workflowCatalog.cjs.map +1 -1
- package/dist/tui/workflow/workflowCatalog.mjs +1 -1
- package/dist/tui/workflow/workflowCatalog.mjs.map +1 -1
- package/dist/types/webWorkflowTerminal.cjs +2 -0
- package/dist/types/webWorkflowTerminal.cjs.map +1 -0
- package/dist/types/webWorkflowTerminal.mjs +2 -0
- package/dist/types/webWorkflowTerminal.mjs.map +1 -0
- package/dist/types/webWorkflows.cjs +2 -0
- package/dist/types/webWorkflows.cjs.map +1 -0
- package/dist/types/webWorkflows.d.cts +95 -0
- package/dist/types/webWorkflows.d.cts.map +1 -0
- package/dist/types/webWorkflows.d.mts +95 -0
- package/dist/types/webWorkflows.d.mts.map +1 -0
- package/dist/types/webWorkflows.mjs +2 -0
- package/dist/types/webWorkflows.mjs.map +1 -0
- package/dist/webHub.cjs +1 -0
- package/dist/webHub.d.cts +3 -0
- package/dist/webHub.d.mts +3 -0
- package/dist/webHub.mjs +1 -0
- package/package.json +47 -11
- package/src/prompts/doompi-author-workflow/SKILL.md +1 -3
- package/src/types/webWorkflowTerminal.ts +92 -0
- package/src/types/webWorkflows.ts +145 -0
- package/web/ArtifactsPane.tsx +433 -0
- package/web/LICENSE +29 -0
- package/web/LaunchWorkflowDialog.tsx +249 -0
- package/web/StepTerminalPanel.tsx +251 -0
- package/web/WorkflowCatalogDrawer.tsx +228 -0
- package/web/WorkflowToolMessage.tsx +54 -0
- package/web/WorkflowsActivitySection.tsx +152 -0
- package/web/WorkflowsPanel.tsx +737 -0
- package/web/ansiSpans.ts +230 -0
- package/web/catalogStore.ts +112 -0
- package/web/index.ts +61 -0
- package/web/launchLine.ts +66 -0
- package/web/runDuration.ts +15 -0
- package/web/terminalApi.ts +151 -0
- package/web/tsconfig.json +22 -0
- package/web/workflowActivity.ts +102 -0
- package/web/workflowToolRender.ts +585 -0
- package/web/workflowsStore.ts +90 -0
- package/dist/tui/workflow/terminalGrid.cjs +0 -2
- package/dist/tui/workflow/terminalGrid.cjs.map +0 -1
- package/dist/tui/workflow/terminalGrid.mjs +0 -2
- package/dist/tui/workflow/terminalGrid.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflowCatalog.mjs","names":[],"sources":["../../../src/tui/workflow/workflowCatalog.ts"],"sourcesContent":["/**\n * The `SPC w l` board: every workflow this repository defines, with the cursor\n * workflow's parsed detail beside it and `r` to launch it.\n *\n * WHY NOT `workflowPicker.ts`:\n * That surface answers \"which one\", hands a value back, and closes - which is\n * what `SPC w c` recovery still needs. This one answers \"what is this workflow,\n * and do I want to run it\", so the detail has to be on screen next to the list\n * rather than behind a selection. The picker stays for the pick-and-return case\n * rather than growing a second mode.\n *\n * DESIGN PATTERNS:\n * - Detail is loaded through an injected loader, so parsing a workflow file\n * stays out of the TUI and the surface is assertable as text. Loaded on\n * demand for the cursor row and cached by row key: a repository with fifty\n * workflows must not parse fifty files to draw one pane\n * - A row is two lines, name over path. One line made the name - the field a\n * reader picks a row by - share a third of the overlay with a path that\n * repeats its directory on every row\n * - `/` opens the filter rather than plain letters filtering as they are typed:\n * the letter keys carry commands here (`r` launch, `t`/`i`/`s` tabs)\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay.ts';\nimport {\n CURSOR_BLOCK,\n ELLIPSIS,\n fit,\n isControlInput,\n matchesQuery,\n pathTail,\n rightAligned,\n SELECTION_MARKER,\n} from './overlayText';\n\nexport const WORKFLOW_CATALOG_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\n/** One workflow file, as the catalog tool reports it. */\nexport interface WorkflowCatalogRow {\n /** Stable identity and the loader's cache key: the absolute path. */\n key: string;\n name: string;\n relativePath: string;\n description: string;\n tags: readonly string[];\n}\n\nexport interface WorkflowInputSummary {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n options?: readonly string[];\n}\n\nexport interface WorkflowJobSummary {\n name: string;\n runsOn?: string;\n steps: readonly string[];\n}\n\n/**\n * What the detail pane shows for one workflow. `runners` is undefined when the\n * workflow names no runner map at all, which is not the same as naming an empty\n * one - see `compatibleRunners`.\n */\nexport interface WorkflowCatalogDetail {\n triggers: readonly string[];\n inputs: readonly WorkflowInputSummary[];\n jobs: readonly WorkflowJobSummary[];\n runners?: readonly string[];\n /** Set when the file could not be parsed; the pane shows this instead of guessing. */\n error?: string;\n}\n\nexport type WorkflowDetailLoader = (row: WorkflowCatalogRow) => WorkflowCatalogDetail;\n\n/** Starts one workflow and returns immediately; the overlay closes on launch. */\nexport type WorkflowLaunchDispatcher = (row: WorkflowCatalogRow) => void;\n\nexport interface WorkflowCatalogOptions {\n loadDetail: WorkflowDetailLoader;\n /** Absent until a composition root wires the launch key to a real launcher. */\n launchWorkflow?: WorkflowLaunchDispatcher;\n}\n\nexport type WorkflowDetailTab = 'triggers' | 'inputs' | 'steps';\n\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst TITLE = 'WORKFLOWS';\nconst BREADCRUMB = 'SPC › w / workflows › l / list';\nconst DIVIDER = '│';\nconst DEFAULT_PAGE_SIZE = 1;\nconst ROWS_PER_ENTRY = 2;\n/** Indent under `${SELECTION_MARKER} `, so the path line hangs under the name. */\nconst META_INDENT = ' ';\nconst EMPTY_NAME = '(unnamed)';\nconst LAUNCH_KEY = 'r';\nconst FILTER_KEY = '/';\nconst KEY_CLEAR = '\\x15';\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_MESSAGE = 'No workflow definitions were found in this repository.';\nconst TAB_ORDER: readonly WorkflowDetailTab[] = ['triggers', 'inputs', 'steps'];\nconst TAB_KEYS: Record<string, WorkflowDetailTab> = { t: 'triggers', i: 'inputs', s: 'steps' };\nconst FOOTER = '↑↓ cursor · JK scroll · tab detail · / filter · r launch · esc close';\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'move'],\n ['JK', 'scroll'],\n ['tab', 'cycle'],\n ['/', 'filter'],\n ['r', 'launch'],\n];\nconst FILTER_FOOTER = 'enter keep · esc clear · ctrl+u wipe';\nconst FILTER_FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['enter', 'keep'],\n ['esc', 'clear'],\n ['ctrl+u', 'wipe'],\n];\n\ninterface SplitLayout {\n leftContentWidth: number;\n rightContentWidth: number;\n gutterWidth: number;\n}\n\nfunction splitLayout(width: number): SplitLayout {\n const paneBudget = Math.max(2, width - visibleWidth(DIVIDER));\n const leftPaneWidth = Math.max(1, Math.floor(paneBudget / 3));\n const rightPaneWidth = Math.max(1, paneBudget - leftPaneWidth);\n const gutterWidth = leftPaneWidth >= 3 && rightPaneWidth >= 3 ? 1 : 0;\n return {\n leftContentWidth: Math.max(1, leftPaneWidth - gutterWidth),\n rightContentWidth: Math.max(1, rightPaneWidth - gutterWidth),\n gutterWidth,\n };\n}\n\nfunction appendWrapped(lines: string[], text: string, width: number, colour: ThemeColor, theme: Theme): void {\n for (const line of wrapTextWithAnsi(text, Math.max(1, width))) lines.push(theme.fg(colour, line));\n}\n\nfunction appendSection(lines: string[], heading: string, items: readonly string[], width: number, theme: Theme): void {\n lines.push(theme.bold(theme.fg('accent', heading)));\n if (items.length === 0) lines.push(theme.fg('dim', ' none'));\n else for (const item of items) appendWrapped(lines, ` • ${item}`, width, 'text', theme);\n lines.push('');\n}\n\nfunction inputLabel(input: WorkflowInputSummary): string {\n const qualifiers = [\n input.required ? 'required' : 'optional',\n input.default === undefined ? undefined : `default ${input.default}`,\n input.options && input.options.length > 0 ? `one of ${input.options.join(', ')}` : undefined,\n ].filter((part): part is string => Boolean(part));\n const description = input.description ? `${input.description} · ` : '';\n return `${input.name} — ${description}${qualifiers.join(' · ')}`;\n}\n\nexport function workflowDetailLines(\n detail: WorkflowCatalogDetail,\n tab: WorkflowDetailTab,\n width: number,\n theme: Theme,\n): string[] {\n const lines: string[] = [];\n if (detail.error) {\n lines.push(theme.bold(theme.fg('error', 'WORKFLOW ERROR')));\n appendWrapped(lines, detail.error, width, 'error', theme);\n lines.push('');\n return lines;\n }\n if (tab === 'triggers') {\n appendSection(lines, 'TRIGGERS', detail.triggers, width, theme);\n // No runner map means every runner qualifies, which a bare \"none\" would\n // report as the opposite.\n appendSection(lines, 'RUNNERS', detail.runners ?? ['any available runner'], width, theme);\n return lines;\n }\n if (tab === 'inputs') {\n appendSection(lines, 'DISPATCH INPUTS', detail.inputs.map(inputLabel), width, theme);\n return lines;\n }\n for (const job of detail.jobs) {\n lines.push(theme.bold(theme.fg('accent', job.name)));\n if (job.runsOn) lines.push(theme.fg('dim', ` runs-on ${job.runsOn}`));\n if (job.steps.length === 0) lines.push(theme.fg('dim', ' no steps'));\n else for (const step of job.steps) appendWrapped(lines, ` • ${step}`, width, 'text', theme);\n lines.push('');\n }\n if (detail.jobs.length === 0) appendSection(lines, 'JOBS', [], width, theme);\n return lines;\n}\n\nfunction tabStrip(tab: WorkflowDetailTab, width: number, theme: Theme): string {\n const labels = TAB_ORDER.map((candidate) => {\n const label = candidate.toUpperCase();\n return candidate === tab ? theme.inverse(theme.bold(` ${label} `)) : theme.fg('dim', ` ${label} `);\n }).join(' ');\n return truncateToWidth(labels, Math.max(0, width), ELLIPSIS);\n}\n\nexport function filterWorkflowRows(rows: readonly WorkflowCatalogRow[], query: string): readonly WorkflowCatalogRow[] {\n if (!query.trim()) return rows;\n return rows.filter((row) =>\n matchesQuery([row.name, row.relativePath, row.description, row.tags.join(' ')].join(' '), query),\n );\n}\n\nexport class WorkflowCatalogComponent extends DoomOverlay {\n private readonly rows: readonly WorkflowCatalogRow[];\n private readonly detailCache = new Map<string, WorkflowCatalogDetail>();\n private cursorIndex = 0;\n private tab: WorkflowDetailTab = 'triggers';\n private query = '';\n private filtering = false;\n private notice: string | undefined;\n private listPageSize = DEFAULT_PAGE_SIZE;\n private detailPageSize = DEFAULT_PAGE_SIZE;\n private detailOffset = 0;\n private detailTotal = 0;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n rows: readonly WorkflowCatalogRow[],\n private readonly done: (result: undefined) => void,\n private readonly options: WorkflowCatalogOptions,\n ) {\n super(tui, theme);\n this.rows = [...rows].sort((left, right) => left.name.localeCompare(right.name));\n }\n\n private matches(): readonly WorkflowCatalogRow[] {\n return filterWorkflowRows(this.rows, this.query);\n }\n\n private cursorRow(): WorkflowCatalogRow | undefined {\n const matches = this.matches();\n return matches[Math.min(this.cursorIndex, Math.max(0, matches.length - 1))];\n }\n\n /** Parsed once per workflow, then reused for every repaint of that row. */\n private detailFor(row: WorkflowCatalogRow): WorkflowCatalogDetail {\n const cached = this.detailCache.get(row.key);\n if (cached) return cached;\n const detail = this.options.loadDetail(row);\n this.detailCache.set(row.key, detail);\n return detail;\n }\n\n private moveCursor(delta: number): void {\n const count = this.matches().length;\n if (count === 0) return;\n const next = Math.max(0, Math.min(count - 1, this.cursorIndex + delta));\n if (next === this.cursorIndex) return;\n this.cursorIndex = next;\n // The detail pane follows the cursor, so its scroll belonged to the row\n // that was showing, not the one replacing it.\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private switchTab(tab: WorkflowDetailTab): void {\n if (this.tab === tab) return;\n this.tab = tab;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private cycleTab(): void {\n const current = TAB_ORDER.indexOf(this.tab);\n this.switchTab(TAB_ORDER[(current + 1) % TAB_ORDER.length] ?? 'triggers');\n }\n\n private scrollDetail(delta: number): void {\n if (!this.cursorRow()) return;\n const maximum = Math.max(0, this.detailTotal - this.detailPageSize);\n const next = Math.max(0, Math.min(maximum, this.detailOffset + delta));\n if (next === this.detailOffset) return;\n this.detailOffset = next;\n this.invalidate();\n }\n\n private setNotice(notice: string): void {\n this.notice = notice;\n this.invalidate();\n }\n\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n // The previous index named a row this filter may no longer list.\n this.cursorIndex = 0;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private launchCursor(): void {\n const row = this.cursorRow();\n if (!row) {\n this.setNotice('launch unavailable · no workflow is selected');\n return;\n }\n const launchWorkflow = this.options.launchWorkflow;\n if (!launchWorkflow) {\n this.setNotice('launch unavailable · no workflow launcher is attached');\n return;\n }\n const detail = this.detailFor(row);\n if (detail.error) {\n this.setNotice(`launch unavailable · ${detail.error}`);\n return;\n }\n // Closing first is what makes the launcher's own prompts reachable: they\n // are host dialogs, and a fullscreen overlay sits over them.\n this.done(undefined);\n launchWorkflow(row);\n }\n\n private handleFilterInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.filtering = false;\n this.setQuery('');\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'enter')) {\n this.filtering = false;\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'backspace')) {\n this.setQuery(this.query.slice(0, -1));\n return;\n }\n if (data === KEY_CLEAR) {\n this.setQuery('');\n return;\n }\n if (!isControlInput(data)) this.setQuery(this.query + data);\n }\n\n handleInput(data: string): void {\n if (this.filtering) {\n this.handleFilterInput(data);\n return;\n }\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, Key.shift('k'))) return this.scrollDetail(-1);\n if (matchesKey(data, Key.shift('j'))) return this.scrollDetail(1);\n if (matchesKey(data, 'up') || data === 'k') return this.moveCursor(-1);\n if (matchesKey(data, 'down') || data === 'j') return this.moveCursor(1);\n if (matchesKey(data, 'pageUp')) return this.moveCursor(-this.listPageSize);\n if (matchesKey(data, 'pageDown')) return this.moveCursor(this.listPageSize);\n if (matchesKey(data, 'tab')) return this.cycleTab();\n if (data === FILTER_KEY) {\n this.filtering = true;\n this.notice = undefined;\n this.invalidate();\n return;\n }\n if (data === LAUNCH_KEY) return this.launchCursor();\n const tab = TAB_KEYS[data];\n if (tab) this.switchTab(tab);\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${scope} workflows · ${this.tab}`,\n footer: this.filtering ? FILTER_FOOTER : FOOTER,\n footerHints: this.filtering ? FILTER_FOOTER_HINTS : FOOTER_HINTS,\n footerRight: matches.length\n ? `${Math.min(this.cursorIndex, matches.length - 1) + 1}/${matches.length}`\n : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const filterRows = this.filtering || this.query ? 1 : 0;\n const transientRows = filterRows + (this.notice === undefined ? 0 : 1);\n const mainHeight = Math.max(0, height - transientRows);\n const layout = splitLayout(width);\n const left = this.renderList(layout.leftContentWidth, mainHeight);\n const right = this.renderDetail(layout.rightContentWidth, mainHeight);\n const gutter = ' '.repeat(layout.gutterWidth);\n const divider = this.theme.fg('borderMuted', DIVIDER);\n const lines: string[] = [];\n for (let index = 0; index < mainHeight; index++) {\n lines.push(\n `${fit(left[index] ?? '', layout.leftContentWidth)}${gutter}${divider}${gutter}${fit(\n right[index] ?? '',\n layout.rightContentWidth,\n )}`,\n );\n }\n if (filterRows) {\n const value = this.filtering ? `${this.query}${CURSOR_BLOCK}` : this.query;\n lines.push(` ${this.theme.bold(this.theme.fg('accent', FILTER_LABEL))} ${value}`);\n }\n if (this.notice !== undefined) lines.push(` ${this.theme.fg('muted', this.notice)}`);\n return lines.slice(0, height).map((line) => fit(line, width));\n }\n\n private renderList(width: number, height: number): string[] {\n const matches = this.matches();\n const lines = [this.theme.bold(this.theme.fg('accent', `WORKFLOWS ${matches.length}`))];\n if (matches.length === 0) {\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'dim',\n this.theme,\n );\n this.listPageSize = DEFAULT_PAGE_SIZE;\n return lines.slice(0, height);\n }\n\n this.listPageSize = Math.max(DEFAULT_PAGE_SIZE, Math.floor((height - 1) / ROWS_PER_ENTRY));\n const active = Math.min(this.cursorIndex, matches.length - 1);\n const start = Math.max(\n 0,\n Math.min(active - this.listPageSize + 1, Math.max(0, matches.length - this.listPageSize)),\n );\n for (const [offset, row] of matches.slice(start, start + this.listPageSize).entries()) {\n const current = start + offset === active;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const label = row.name || EMPTY_NAME;\n const name = current ? this.theme.bold(this.theme.fg('accent', label)) : this.theme.fg('text', label);\n const meta = this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, width - META_INDENT.length)));\n lines.push(fit(`${marker} ${name}`, width));\n lines.push(fit(`${META_INDENT}${meta}`, width));\n }\n return lines.slice(0, height);\n }\n\n private renderDetail(width: number, height: number): string[] {\n const row = this.cursorRow();\n if (!row) {\n this.detailTotal = 0;\n this.detailPageSize = Math.max(DEFAULT_PAGE_SIZE, height);\n this.detailOffset = 0;\n const lines = [this.theme.bold(this.theme.fg('accent', 'WORKFLOW DETAIL')), ''];\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'text',\n this.theme,\n );\n return lines.slice(0, height);\n }\n\n const header = [\n rightAligned(\n this.theme.bold(this.theme.fg('accent', `INSPECTING ${row.name || EMPTY_NAME}`)),\n this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, Math.floor(width / 2)))),\n width,\n ),\n ];\n if (row.description) appendWrapped(header, row.description, width, 'text', this.theme);\n if (row.tags.length > 0) appendWrapped(header, row.tags.join(' · '), width, 'dim', this.theme);\n header.push(tabStrip(this.tab, width, this.theme), '');\n\n const body = workflowDetailLines(this.detailFor(row), this.tab, width, this.theme);\n this.detailPageSize = Math.max(0, height - header.length);\n this.detailTotal = body.length;\n this.detailOffset = Math.min(this.detailOffset, Math.max(0, body.length - this.detailPageSize));\n return [...header, ...body.slice(this.detailOffset, this.detailOffset + this.detailPageSize)].slice(0, height);\n }\n}\n\nexport async function openWorkflowCatalogOverlay(\n ctx: ExtensionContext,\n rows: readonly WorkflowCatalogRow[],\n options: WorkflowCatalogOptions,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new WorkflowCatalogComponent(tui, theme, rows, done, options),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflowCatalog.mjs","names":[],"sources":["../../../src/tui/workflow/workflowCatalog.ts"],"sourcesContent":["/**\n * The `SPC w l` board: every workflow this repository defines, with the cursor\n * workflow's parsed detail beside it and `r` to launch it.\n *\n * WHY NOT `workflowPicker.ts`:\n * That surface answers \"which one\", hands a value back, and closes - which is\n * what `SPC w c` recovery still needs. This one answers \"what is this workflow,\n * and do I want to run it\", so the detail has to be on screen next to the list\n * rather than behind a selection. The picker stays for the pick-and-return case\n * rather than growing a second mode.\n *\n * DESIGN PATTERNS:\n * - Detail is loaded through an injected loader, so parsing a workflow file\n * stays out of the TUI and the surface is assertable as text. Loaded on\n * demand for the cursor row and cached by row key: a repository with fifty\n * workflows must not parse fifty files to draw one pane\n * - A row is two lines, name over path. One line made the name - the field a\n * reader picks a row by - share a third of the overlay with a path that\n * repeats its directory on every row\n * - `/` opens the filter rather than plain letters filtering as they are typed:\n * the letter keys carry commands here (`r` launch, `t`/`i`/`s` tabs)\n */\n\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from './doomOverlay.ts';\nimport {\n CURSOR_BLOCK,\n ELLIPSIS,\n fit,\n isControlInput,\n matchesQuery,\n pathTail,\n rightAligned,\n SELECTION_MARKER,\n} from './overlayText';\n\nexport const WORKFLOW_CATALOG_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\n/** One workflow file, as the catalog tool reports it. */\nexport interface WorkflowCatalogRow {\n /** Stable identity and the loader's cache key: the absolute path. */\n key: string;\n name: string;\n relativePath: string;\n description: string;\n tags: readonly string[];\n}\n\nexport interface WorkflowInputSummary {\n name: string;\n description?: string;\n required?: boolean;\n default?: string;\n options?: readonly string[];\n}\n\nexport interface WorkflowJobSummary {\n name: string;\n steps: readonly string[];\n}\n\n/**\n * What the detail pane shows for one workflow. `runners` is undefined when the\n * workflow names no runner map at all, which is not the same as naming an empty\n * one - see `compatibleRunners`.\n */\nexport interface WorkflowCatalogDetail {\n triggers: readonly string[];\n inputs: readonly WorkflowInputSummary[];\n jobs: readonly WorkflowJobSummary[];\n runners?: readonly string[];\n /** Set when the file could not be parsed; the pane shows this instead of guessing. */\n error?: string;\n}\n\nexport type WorkflowDetailLoader = (row: WorkflowCatalogRow) => WorkflowCatalogDetail;\n\n/** Starts one workflow and returns immediately; the overlay closes on launch. */\nexport type WorkflowLaunchDispatcher = (row: WorkflowCatalogRow) => void;\n\nexport interface WorkflowCatalogOptions {\n loadDetail: WorkflowDetailLoader;\n /** Absent until a composition root wires the launch key to a real launcher. */\n launchWorkflow?: WorkflowLaunchDispatcher;\n}\n\nexport type WorkflowDetailTab = 'triggers' | 'inputs' | 'steps';\n\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\nconst TITLE = 'WORKFLOWS';\nconst BREADCRUMB = 'SPC › w / workflows › l / list';\nconst DIVIDER = '│';\nconst DEFAULT_PAGE_SIZE = 1;\nconst ROWS_PER_ENTRY = 2;\n/** Indent under `${SELECTION_MARKER} `, so the path line hangs under the name. */\nconst META_INDENT = ' ';\nconst EMPTY_NAME = '(unnamed)';\nconst LAUNCH_KEY = 'r';\nconst FILTER_KEY = '/';\nconst KEY_CLEAR = '\\x15';\nconst FILTER_LABEL = 'FILTER';\nconst EMPTY_MESSAGE = 'No workflow definitions were found in this repository.';\nconst TAB_ORDER: readonly WorkflowDetailTab[] = ['triggers', 'inputs', 'steps'];\nconst TAB_KEYS: Record<string, WorkflowDetailTab> = { t: 'triggers', i: 'inputs', s: 'steps' };\nconst FOOTER = '↑↓ cursor · JK scroll · tab detail · / filter · r launch · esc close';\nconst FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'move'],\n ['JK', 'scroll'],\n ['tab', 'cycle'],\n ['/', 'filter'],\n ['r', 'launch'],\n];\nconst FILTER_FOOTER = 'enter keep · esc clear · ctrl+u wipe';\nconst FILTER_FOOTER_HINTS: readonly (readonly [string, string])[] = [\n ['enter', 'keep'],\n ['esc', 'clear'],\n ['ctrl+u', 'wipe'],\n];\n\ninterface SplitLayout {\n leftContentWidth: number;\n rightContentWidth: number;\n gutterWidth: number;\n}\n\nfunction splitLayout(width: number): SplitLayout {\n const paneBudget = Math.max(2, width - visibleWidth(DIVIDER));\n const leftPaneWidth = Math.max(1, Math.floor(paneBudget / 3));\n const rightPaneWidth = Math.max(1, paneBudget - leftPaneWidth);\n const gutterWidth = leftPaneWidth >= 3 && rightPaneWidth >= 3 ? 1 : 0;\n return {\n leftContentWidth: Math.max(1, leftPaneWidth - gutterWidth),\n rightContentWidth: Math.max(1, rightPaneWidth - gutterWidth),\n gutterWidth,\n };\n}\n\nfunction appendWrapped(lines: string[], text: string, width: number, colour: ThemeColor, theme: Theme): void {\n for (const line of wrapTextWithAnsi(text, Math.max(1, width))) lines.push(theme.fg(colour, line));\n}\n\nfunction appendSection(lines: string[], heading: string, items: readonly string[], width: number, theme: Theme): void {\n lines.push(theme.bold(theme.fg('accent', heading)));\n if (items.length === 0) lines.push(theme.fg('dim', ' none'));\n else for (const item of items) appendWrapped(lines, ` • ${item}`, width, 'text', theme);\n lines.push('');\n}\n\nfunction inputLabel(input: WorkflowInputSummary): string {\n const qualifiers = [\n input.required ? 'required' : 'optional',\n input.default === undefined ? undefined : `default ${input.default}`,\n input.options && input.options.length > 0 ? `one of ${input.options.join(', ')}` : undefined,\n ].filter((part): part is string => Boolean(part));\n const description = input.description ? `${input.description} · ` : '';\n return `${input.name} — ${description}${qualifiers.join(' · ')}`;\n}\n\nexport function workflowDetailLines(\n detail: WorkflowCatalogDetail,\n tab: WorkflowDetailTab,\n width: number,\n theme: Theme,\n): string[] {\n const lines: string[] = [];\n if (detail.error) {\n lines.push(theme.bold(theme.fg('error', 'WORKFLOW ERROR')));\n appendWrapped(lines, detail.error, width, 'error', theme);\n lines.push('');\n return lines;\n }\n if (tab === 'triggers') {\n appendSection(lines, 'TRIGGERS', detail.triggers, width, theme);\n // No runner map means every runner qualifies, which a bare \"none\" would\n // report as the opposite.\n appendSection(lines, 'RUNNERS', detail.runners ?? ['any available runner'], width, theme);\n return lines;\n }\n if (tab === 'inputs') {\n appendSection(lines, 'DISPATCH INPUTS', detail.inputs.map(inputLabel), width, theme);\n return lines;\n }\n for (const job of detail.jobs) {\n lines.push(theme.bold(theme.fg('accent', job.name)));\n if (job.steps.length === 0) lines.push(theme.fg('dim', ' no steps'));\n else for (const step of job.steps) appendWrapped(lines, ` • ${step}`, width, 'text', theme);\n lines.push('');\n }\n if (detail.jobs.length === 0) appendSection(lines, 'JOBS', [], width, theme);\n return lines;\n}\n\nfunction tabStrip(tab: WorkflowDetailTab, width: number, theme: Theme): string {\n const labels = TAB_ORDER.map((candidate) => {\n const label = candidate.toUpperCase();\n return candidate === tab ? theme.inverse(theme.bold(` ${label} `)) : theme.fg('dim', ` ${label} `);\n }).join(' ');\n return truncateToWidth(labels, Math.max(0, width), ELLIPSIS);\n}\n\nexport function filterWorkflowRows(rows: readonly WorkflowCatalogRow[], query: string): readonly WorkflowCatalogRow[] {\n if (!query.trim()) return rows;\n return rows.filter((row) =>\n matchesQuery([row.name, row.relativePath, row.description, row.tags.join(' ')].join(' '), query),\n );\n}\n\nexport class WorkflowCatalogComponent extends DoomOverlay {\n private readonly rows: readonly WorkflowCatalogRow[];\n private readonly detailCache = new Map<string, WorkflowCatalogDetail>();\n private cursorIndex = 0;\n private tab: WorkflowDetailTab = 'triggers';\n private query = '';\n private filtering = false;\n private notice: string | undefined;\n private listPageSize = DEFAULT_PAGE_SIZE;\n private detailPageSize = DEFAULT_PAGE_SIZE;\n private detailOffset = 0;\n private detailTotal = 0;\n\n constructor(\n tui: DoomOverlayTui,\n theme: Theme,\n rows: readonly WorkflowCatalogRow[],\n private readonly done: (result: undefined) => void,\n private readonly options: WorkflowCatalogOptions,\n ) {\n super(tui, theme);\n this.rows = [...rows].sort((left, right) => left.name.localeCompare(right.name));\n }\n\n private matches(): readonly WorkflowCatalogRow[] {\n return filterWorkflowRows(this.rows, this.query);\n }\n\n private cursorRow(): WorkflowCatalogRow | undefined {\n const matches = this.matches();\n return matches[Math.min(this.cursorIndex, Math.max(0, matches.length - 1))];\n }\n\n /** Parsed once per workflow, then reused for every repaint of that row. */\n private detailFor(row: WorkflowCatalogRow): WorkflowCatalogDetail {\n const cached = this.detailCache.get(row.key);\n if (cached) return cached;\n const detail = this.options.loadDetail(row);\n this.detailCache.set(row.key, detail);\n return detail;\n }\n\n private moveCursor(delta: number): void {\n const count = this.matches().length;\n if (count === 0) return;\n const next = Math.max(0, Math.min(count - 1, this.cursorIndex + delta));\n if (next === this.cursorIndex) return;\n this.cursorIndex = next;\n // The detail pane follows the cursor, so its scroll belonged to the row\n // that was showing, not the one replacing it.\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private switchTab(tab: WorkflowDetailTab): void {\n if (this.tab === tab) return;\n this.tab = tab;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private cycleTab(): void {\n const current = TAB_ORDER.indexOf(this.tab);\n this.switchTab(TAB_ORDER[(current + 1) % TAB_ORDER.length] ?? 'triggers');\n }\n\n private scrollDetail(delta: number): void {\n if (!this.cursorRow()) return;\n const maximum = Math.max(0, this.detailTotal - this.detailPageSize);\n const next = Math.max(0, Math.min(maximum, this.detailOffset + delta));\n if (next === this.detailOffset) return;\n this.detailOffset = next;\n this.invalidate();\n }\n\n private setNotice(notice: string): void {\n this.notice = notice;\n this.invalidate();\n }\n\n private setQuery(query: string): void {\n if (query === this.query) return;\n this.query = query;\n // The previous index named a row this filter may no longer list.\n this.cursorIndex = 0;\n this.detailOffset = 0;\n this.invalidate();\n }\n\n private launchCursor(): void {\n const row = this.cursorRow();\n if (!row) {\n this.setNotice('launch unavailable · no workflow is selected');\n return;\n }\n const launchWorkflow = this.options.launchWorkflow;\n if (!launchWorkflow) {\n this.setNotice('launch unavailable · no workflow launcher is attached');\n return;\n }\n const detail = this.detailFor(row);\n if (detail.error) {\n this.setNotice(`launch unavailable · ${detail.error}`);\n return;\n }\n // Closing first is what makes the launcher's own prompts reachable: they\n // are host dialogs, and a fullscreen overlay sits over them.\n this.done(undefined);\n launchWorkflow(row);\n }\n\n private handleFilterInput(data: string): void {\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.filtering = false;\n this.setQuery('');\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'enter')) {\n this.filtering = false;\n this.invalidate();\n return;\n }\n if (matchesKey(data, 'backspace')) {\n this.setQuery(this.query.slice(0, -1));\n return;\n }\n if (data === KEY_CLEAR) {\n this.setQuery('');\n return;\n }\n if (!isControlInput(data)) this.setQuery(this.query + data);\n }\n\n handleInput(data: string): void {\n if (this.filtering) {\n this.handleFilterInput(data);\n return;\n }\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, Key.shift('k'))) return this.scrollDetail(-1);\n if (matchesKey(data, Key.shift('j'))) return this.scrollDetail(1);\n if (matchesKey(data, 'up') || data === 'k') return this.moveCursor(-1);\n if (matchesKey(data, 'down') || data === 'j') return this.moveCursor(1);\n if (matchesKey(data, 'pageUp')) return this.moveCursor(-this.listPageSize);\n if (matchesKey(data, 'pageDown')) return this.moveCursor(this.listPageSize);\n if (matchesKey(data, 'tab')) return this.cycleTab();\n if (data === FILTER_KEY) {\n this.filtering = true;\n this.notice = undefined;\n this.invalidate();\n return;\n }\n if (data === LAUNCH_KEY) return this.launchCursor();\n const tab = TAB_KEYS[data];\n if (tab) this.switchTab(tab);\n }\n\n protected getChrome(): DoomOverlayChrome {\n const matches = this.matches();\n const scope = this.query ? `${matches.length} of ${this.rows.length}` : `${this.rows.length}`;\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${scope} workflows · ${this.tab}`,\n footer: this.filtering ? FILTER_FOOTER : FOOTER,\n footerHints: this.filtering ? FILTER_FOOTER_HINTS : FOOTER_HINTS,\n footerRight: matches.length\n ? `${Math.min(this.cursorIndex, matches.length - 1) + 1}/${matches.length}`\n : 'no match',\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n const filterRows = this.filtering || this.query ? 1 : 0;\n const transientRows = filterRows + (this.notice === undefined ? 0 : 1);\n const mainHeight = Math.max(0, height - transientRows);\n const layout = splitLayout(width);\n const left = this.renderList(layout.leftContentWidth, mainHeight);\n const right = this.renderDetail(layout.rightContentWidth, mainHeight);\n const gutter = ' '.repeat(layout.gutterWidth);\n const divider = this.theme.fg('borderMuted', DIVIDER);\n const lines: string[] = [];\n for (let index = 0; index < mainHeight; index++) {\n lines.push(\n `${fit(left[index] ?? '', layout.leftContentWidth)}${gutter}${divider}${gutter}${fit(\n right[index] ?? '',\n layout.rightContentWidth,\n )}`,\n );\n }\n if (filterRows) {\n const value = this.filtering ? `${this.query}${CURSOR_BLOCK}` : this.query;\n lines.push(` ${this.theme.bold(this.theme.fg('accent', FILTER_LABEL))} ${value}`);\n }\n if (this.notice !== undefined) lines.push(` ${this.theme.fg('muted', this.notice)}`);\n return lines.slice(0, height).map((line) => fit(line, width));\n }\n\n private renderList(width: number, height: number): string[] {\n const matches = this.matches();\n const lines = [this.theme.bold(this.theme.fg('accent', `WORKFLOWS ${matches.length}`))];\n if (matches.length === 0) {\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'dim',\n this.theme,\n );\n this.listPageSize = DEFAULT_PAGE_SIZE;\n return lines.slice(0, height);\n }\n\n this.listPageSize = Math.max(DEFAULT_PAGE_SIZE, Math.floor((height - 1) / ROWS_PER_ENTRY));\n const active = Math.min(this.cursorIndex, matches.length - 1);\n const start = Math.max(\n 0,\n Math.min(active - this.listPageSize + 1, Math.max(0, matches.length - this.listPageSize)),\n );\n for (const [offset, row] of matches.slice(start, start + this.listPageSize).entries()) {\n const current = start + offset === active;\n const marker = current ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const label = row.name || EMPTY_NAME;\n const name = current ? this.theme.bold(this.theme.fg('accent', label)) : this.theme.fg('text', label);\n const meta = this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, width - META_INDENT.length)));\n lines.push(fit(`${marker} ${name}`, width));\n lines.push(fit(`${META_INDENT}${meta}`, width));\n }\n return lines.slice(0, height);\n }\n\n private renderDetail(width: number, height: number): string[] {\n const row = this.cursorRow();\n if (!row) {\n this.detailTotal = 0;\n this.detailPageSize = Math.max(DEFAULT_PAGE_SIZE, height);\n this.detailOffset = 0;\n const lines = [this.theme.bold(this.theme.fg('accent', 'WORKFLOW DETAIL')), ''];\n appendWrapped(\n lines,\n this.rows.length === 0 ? EMPTY_MESSAGE : 'No workflow matches this filter.',\n width,\n 'text',\n this.theme,\n );\n return lines.slice(0, height);\n }\n\n const header = [\n rightAligned(\n this.theme.bold(this.theme.fg('accent', `INSPECTING ${row.name || EMPTY_NAME}`)),\n this.theme.fg('dim', pathTail(row.relativePath, Math.max(0, Math.floor(width / 2)))),\n width,\n ),\n ];\n if (row.description) appendWrapped(header, row.description, width, 'text', this.theme);\n if (row.tags.length > 0) appendWrapped(header, row.tags.join(' · '), width, 'dim', this.theme);\n header.push(tabStrip(this.tab, width, this.theme), '');\n\n const body = workflowDetailLines(this.detailFor(row), this.tab, width, this.theme);\n this.detailPageSize = Math.max(0, height - header.length);\n this.detailTotal = body.length;\n this.detailOffset = Math.min(this.detailOffset, Math.max(0, body.length - this.detailPageSize));\n return [...header, ...body.slice(this.detailOffset, this.detailOffset + this.detailPageSize)].slice(0, height);\n }\n}\n\nexport async function openWorkflowCatalogOverlay(\n ctx: ExtensionContext,\n rows: readonly WorkflowCatalogRow[],\n options: WorkflowCatalogOptions,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new WorkflowCatalogComponent(tui, theme, rows, done, options),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n"],"mappings":"iVA2CgD,EAA2B,eAsD3E,MAOM,EAAa,YAKb,EAAgB,yDAChB,EAA0C,CAAC,WAAY,SAAU,OAAO,EACxE,EAA8C,CAAE,EAAG,WAAY,EAAG,SAAU,EAAG,OAAQ,EAEvF,EAAuD,CAC3D,CAAC,KAAM,MAAM,EACb,CAAC,KAAM,QAAQ,EACf,CAAC,MAAO,OAAO,EACf,CAAC,IAAK,QAAQ,EACd,CAAC,IAAK,QAAQ,CAChB,EAEM,EAA8D,CAClE,CAAC,QAAS,MAAM,EAChB,CAAC,MAAO,OAAO,EACf,CAAC,SAAU,MAAM,CACnB,EAQA,SAAS,EAAY,EAA4B,CAC/C,IAAM,EAAa,KAAK,IAAI,EAAG,EAAQ,EAAa,GAAO,CAAC,EACtD,EAAgB,KAAK,IAAI,EAAG,KAAK,MAAM,EAAa,CAAC,CAAC,EACtD,EAAiB,KAAK,IAAI,EAAG,EAAa,CAAa,EACvD,EAAc,KAAiB,GAAK,GAAkB,GAC5D,MAAO,CACL,iBAAkB,KAAK,IAAI,EAAG,EAAgB,CAAW,EACzD,kBAAmB,KAAK,IAAI,EAAG,EAAiB,CAAW,EAC3D,aACF,CACF,CAEA,SAAS,EAAc,EAAiB,EAAc,EAAe,EAAoB,EAAoB,CAC3G,IAAK,IAAM,KAAQ,EAAiB,EAAM,KAAK,IAAI,EAAG,CAAK,CAAC,EAAG,EAAM,KAAK,EAAM,GAAG,EAAQ,CAAI,CAAC,CAClG,CAEA,SAAS,EAAc,EAAiB,EAAiB,EAA0B,EAAe,EAAoB,CAEpH,GADA,EAAM,KAAK,EAAM,KAAK,EAAM,GAAG,SAAU,CAAO,CAAC,CAAC,EAC9C,EAAM,SAAW,EAAG,EAAM,KAAK,EAAM,GAAG,MAAO,QAAQ,CAAC,OACvD,IAAK,IAAM,KAAQ,EAAO,EAAc,EAAO,OAAO,IAAQ,EAAO,OAAQ,CAAK,EACvF,EAAM,KAAK,EAAE,CACf,CAEA,SAAS,EAAW,EAAqC,CACvD,IAAM,EAAa,CACjB,EAAM,SAAW,WAAa,WAC9B,EAAM,UAAY,IAAA,GAAY,IAAA,GAAY,WAAW,EAAM,UAC3D,EAAM,SAAW,EAAM,QAAQ,OAAS,EAAI,UAAU,EAAM,QAAQ,KAAK,IAAI,IAAM,IAAA,EACrF,CAAC,CAAC,OAAQ,GAAyB,EAAQ,CAAK,EAC1C,EAAc,EAAM,YAAc,GAAG,EAAM,YAAY,KAAO,GACpE,MAAO,GAAG,EAAM,KAAK,KAAK,IAAc,EAAW,KAAK,KAAK,GAC/D,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACU,CACV,IAAM,EAAkB,CAAC,EACzB,GAAI,EAAO,MAIT,OAHA,EAAM,KAAK,EAAM,KAAK,EAAM,GAAG,QAAS,gBAAgB,CAAC,CAAC,EAC1D,EAAc,EAAO,EAAO,MAAO,EAAO,QAAS,CAAK,EACxD,EAAM,KAAK,EAAE,EACN,EAET,GAAI,IAAQ,WAKV,OAJA,EAAc,EAAO,WAAY,EAAO,SAAU,EAAO,CAAK,EAG9D,EAAc,EAAO,UAAW,EAAO,SAAW,CAAC,sBAAsB,EAAG,EAAO,CAAK,EACjF,EAET,GAAI,IAAQ,SAEV,OADA,EAAc,EAAO,kBAAmB,EAAO,OAAO,IAAI,CAAU,EAAG,EAAO,CAAK,EAC5E,EAET,IAAK,IAAM,KAAO,EAAO,KAAM,CAE7B,GADA,EAAM,KAAK,EAAM,KAAK,EAAM,GAAG,SAAU,EAAI,IAAI,CAAC,CAAC,EAC/C,EAAI,MAAM,SAAW,EAAG,EAAM,KAAK,EAAM,GAAG,MAAO,YAAY,CAAC,OAC/D,IAAK,IAAM,KAAQ,EAAI,MAAO,EAAc,EAAO,OAAO,IAAQ,EAAO,OAAQ,CAAK,EAC3F,EAAM,KAAK,EAAE,CACf,CAEA,OADI,EAAO,KAAK,SAAW,GAAG,EAAc,EAAO,OAAQ,CAAC,EAAG,EAAO,CAAK,EACpE,CACT,CAEA,SAAS,EAAS,EAAwB,EAAe,EAAsB,CAC7E,IAAM,EAAS,EAAU,IAAK,GAAc,CAC1C,IAAM,EAAQ,EAAU,YAAY,EACpC,OAAO,IAAc,EAAM,EAAM,QAAQ,EAAM,KAAK,IAAI,EAAM,EAAE,CAAC,EAAI,EAAM,GAAG,MAAO,IAAI,EAAM,EAAE,CACnG,CAAC,CAAC,CAAC,KAAK,GAAG,EACX,OAAO,EAAgB,EAAQ,KAAK,IAAI,EAAG,CAAK,EAAA,GAAW,CAC7D,CAEA,SAAgB,EAAmB,EAAqC,EAA8C,CAEpH,OADK,EAAM,KAAK,EACT,EAAK,OAAQ,GAClB,EAAa,CAAC,EAAI,KAAM,EAAI,aAAc,EAAI,YAAa,EAAI,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAG,CAAK,CACjG,EAH0B,CAI5B,CAEA,IAAa,EAAb,cAA8C,CAAY,CAiBrC,KACA,QAjBnB,KACA,YAA+B,IAAI,IACnC,YAAsB,EACtB,IAAiC,WACjC,MAAgB,GAChB,UAAoB,GACpB,OACA,aAAuB,EACvB,eAAyB,EACzB,aAAuB,EACvB,YAAsB,EAEtB,YACE,EACA,EACA,EACA,EACA,EACA,CACA,MAAM,EAAK,CAAK,EAHC,KAAA,KAAA,EACA,KAAA,QAAA,EAGjB,KAAK,KAAO,CAAC,GAAG,CAAI,CAAC,CAAC,MAAM,EAAM,IAAU,EAAK,KAAK,cAAc,EAAM,IAAI,CAAC,CACjF,CAEA,SAAiD,CAC/C,OAAO,EAAmB,KAAK,KAAM,KAAK,KAAK,CACjD,CAEA,WAAoD,CAClD,IAAM,EAAU,KAAK,QAAQ,EAC7B,OAAO,EAAQ,KAAK,IAAI,KAAK,YAAa,KAAK,IAAI,EAAG,EAAQ,OAAS,CAAC,CAAC,EAC3E,CAGA,UAAkB,EAAgD,CAChE,IAAM,EAAS,KAAK,YAAY,IAAI,EAAI,GAAG,EAC3C,GAAI,EAAQ,OAAO,EACnB,IAAM,EAAS,KAAK,QAAQ,WAAW,CAAG,EAE1C,OADA,KAAK,YAAY,IAAI,EAAI,IAAK,CAAM,EAC7B,CACT,CAEA,WAAmB,EAAqB,CACtC,IAAM,EAAQ,KAAK,QAAQ,CAAC,CAAC,OAC7B,GAAI,IAAU,EAAG,OACjB,IAAM,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAQ,EAAG,KAAK,YAAc,CAAK,CAAC,EAClE,IAAS,KAAK,cAClB,KAAK,YAAc,EAGnB,KAAK,aAAe,EACpB,KAAK,WAAW,EAClB,CAEA,UAAkB,EAA8B,CAC1C,KAAK,MAAQ,IACjB,KAAK,IAAM,EACX,KAAK,aAAe,EACpB,KAAK,WAAW,EAClB,CAEA,UAAyB,CACvB,IAAM,EAAU,EAAU,QAAQ,KAAK,GAAG,EAC1C,KAAK,UAAU,GAAW,EAAU,GAAK,EAAU,SAAW,UAAU,CAC1E,CAEA,aAAqB,EAAqB,CACxC,GAAI,CAAC,KAAK,UAAU,EAAG,OACvB,IAAM,EAAU,KAAK,IAAI,EAAG,KAAK,YAAc,KAAK,cAAc,EAC5D,EAAO,KAAK,IAAI,EAAG,KAAK,IAAI,EAAS,KAAK,aAAe,CAAK,CAAC,EACjE,IAAS,KAAK,eAClB,KAAK,aAAe,EACpB,KAAK,WAAW,EAClB,CAEA,UAAkB,EAAsB,CACtC,KAAK,OAAS,EACd,KAAK,WAAW,CAClB,CAEA,SAAiB,EAAqB,CAChC,IAAU,KAAK,QACnB,KAAK,MAAQ,EAEb,KAAK,YAAc,EACnB,KAAK,aAAe,EACpB,KAAK,WAAW,EAClB,CAEA,cAA6B,CAC3B,IAAM,EAAM,KAAK,UAAU,EAC3B,GAAI,CAAC,EAAK,CACR,KAAK,UAAU,8CAA8C,EAC7D,MACF,CACA,IAAM,EAAiB,KAAK,QAAQ,eACpC,GAAI,CAAC,EAAgB,CACnB,KAAK,UAAU,uDAAuD,EACtE,MACF,CACA,IAAM,EAAS,KAAK,UAAU,CAAG,EACjC,GAAI,EAAO,MAAO,CAChB,KAAK,UAAU,wBAAwB,EAAO,OAAO,EACrD,MACF,CAGA,KAAK,KAAK,IAAA,EAAS,EACnB,EAAe,CAAG,CACpB,CAEA,kBAA0B,EAAoB,CAC5C,GAAI,EAAW,EAAM,QAAQ,GAAK,EAAW,EAAM,QAAQ,EAAG,CAC5D,KAAK,UAAY,GACjB,KAAK,SAAS,EAAE,EAChB,KAAK,WAAW,EAChB,MACF,CACA,GAAI,EAAW,EAAM,OAAO,EAAG,CAC7B,KAAK,UAAY,GACjB,KAAK,WAAW,EAChB,MACF,CACA,GAAI,EAAW,EAAM,WAAW,EAAG,CACjC,KAAK,SAAS,KAAK,MAAM,MAAM,EAAG,EAAE,CAAC,EACrC,MACF,CACA,GAAI,IAAS,IAAW,CACtB,KAAK,SAAS,EAAE,EAChB,MACF,CACK,EAAe,CAAI,GAAG,KAAK,SAAS,KAAK,MAAQ,CAAI,CAC5D,CAEA,YAAY,EAAoB,CAC9B,GAAI,KAAK,UAAW,CAClB,KAAK,kBAAkB,CAAI,EAC3B,MACF,CACA,GAAI,EAAW,EAAM,QAAQ,GAAK,EAAW,EAAM,QAAQ,EAAG,CAC5D,KAAK,KAAK,IAAA,EAAS,EACnB,MACF,CACA,GAAI,EAAW,EAAM,EAAI,MAAM,GAAG,CAAC,EAAG,OAAO,KAAK,aAAa,EAAE,EACjE,GAAI,EAAW,EAAM,EAAI,MAAM,GAAG,CAAC,EAAG,OAAO,KAAK,aAAa,CAAC,EAChE,GAAI,EAAW,EAAM,IAAI,GAAK,IAAS,IAAK,OAAO,KAAK,WAAW,EAAE,EACrE,GAAI,EAAW,EAAM,MAAM,GAAK,IAAS,IAAK,OAAO,KAAK,WAAW,CAAC,EACtE,GAAI,EAAW,EAAM,QAAQ,EAAG,OAAO,KAAK,WAAW,CAAC,KAAK,YAAY,EACzE,GAAI,EAAW,EAAM,UAAU,EAAG,OAAO,KAAK,WAAW,KAAK,YAAY,EAC1E,GAAI,EAAW,EAAM,KAAK,EAAG,OAAO,KAAK,SAAS,EAClD,GAAI,IAAS,IAAY,CACvB,KAAK,UAAY,GACjB,KAAK,OAAS,IAAA,GACd,KAAK,WAAW,EAChB,MACF,CACA,GAAI,IAAS,IAAY,OAAO,KAAK,aAAa,EAClD,IAAM,EAAM,EAAS,GACjB,GAAK,KAAK,UAAU,CAAG,CAC7B,CAEA,WAAyC,CACvC,IAAM,EAAU,KAAK,QAAQ,EACvB,EAAQ,KAAK,MAAQ,GAAG,EAAQ,OAAO,MAAM,KAAK,KAAK,SAAW,GAAG,KAAK,KAAK,SACrF,MAAO,CACL,MAAO,YACP,OAAQ,EACR,WAAY,iCACZ,YAAa,GAAG,EAAM,eAAe,KAAK,MAC1C,OAAQ,KAAK,UAAY,uCAAgB,uEACzC,YAAa,KAAK,UAAY,EAAsB,EACpD,YAAa,EAAQ,OACjB,GAAG,KAAK,IAAI,KAAK,YAAa,EAAQ,OAAS,CAAC,EAAI,EAAE,GAAG,EAAQ,SACjE,UACN,CACF,CAEA,WAAqB,EAAe,EAA0B,CAC5D,IAAM,EAAa,KAAK,WAAa,KAAK,MAAQ,EAAI,EAChD,EAAgB,GAAc,KAAK,SAAW,IAAA,GAAY,EAAI,GAC9D,EAAa,KAAK,IAAI,EAAG,EAAS,CAAa,EAC/C,EAAS,EAAY,CAAK,EAC1B,EAAO,KAAK,WAAW,EAAO,iBAAkB,CAAU,EAC1D,EAAQ,KAAK,aAAa,EAAO,kBAAmB,CAAU,EAC9D,EAAS,IAAI,OAAO,EAAO,WAAW,EACtC,EAAU,KAAK,MAAM,GAAG,cAAe,GAAO,EAC9C,EAAkB,CAAC,EACzB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAY,IACtC,EAAM,KACJ,GAAG,EAAI,EAAK,IAAU,GAAI,EAAO,gBAAgB,IAAI,IAAS,IAAU,IAAS,EAC/E,EAAM,IAAU,GAChB,EAAO,iBACT,GACF,EAEF,GAAI,EAAY,CACd,IAAM,EAAQ,KAAK,UAAY,GAAG,KAAK,SAAyB,KAAK,MACrE,EAAM,KAAK,IAAI,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,SAAU,QAAY,CAAC,EAAE,GAAG,GAAO,CAClF,CAEA,OADI,KAAK,SAAW,IAAA,IAAW,EAAM,KAAK,IAAI,KAAK,MAAM,GAAG,QAAS,KAAK,MAAM,GAAG,EAC5E,EAAM,MAAM,EAAG,CAAM,CAAC,CAAC,IAAK,GAAS,EAAI,EAAM,CAAK,CAAC,CAC9D,CAEA,WAAmB,EAAe,EAA0B,CAC1D,IAAM,EAAU,KAAK,QAAQ,EACvB,EAAQ,CAAC,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,SAAU,aAAa,EAAQ,QAAQ,CAAC,CAAC,EACtF,GAAI,EAAQ,SAAW,EASrB,OARA,EACE,EACA,KAAK,KAAK,SAAW,EAAI,EAAgB,mCACzC,EACA,MACA,KAAK,KACP,EACA,KAAK,aAAe,EACb,EAAM,MAAM,EAAG,CAAM,EAG9B,KAAK,aAAe,KAAK,IAAI,EAAmB,KAAK,OAAO,EAAS,GAAK,CAAc,CAAC,EACzF,IAAM,EAAS,KAAK,IAAI,KAAK,YAAa,EAAQ,OAAS,CAAC,EACtD,EAAQ,KAAK,IACjB,EACA,KAAK,IAAI,EAAS,KAAK,aAAe,EAAG,KAAK,IAAI,EAAG,EAAQ,OAAS,KAAK,YAAY,CAAC,CAC1F,EACA,IAAK,GAAM,CAAC,EAAQ,KAAQ,EAAQ,MAAM,EAAO,EAAQ,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAG,CACrF,IAAM,EAAU,EAAQ,IAAW,EAC7B,EAAS,EAAU,KAAK,MAAM,GAAG,SAAA,GAA0B,EAAI,IAC/D,EAAQ,EAAI,MAAQ,EACpB,EAAO,EAAU,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,SAAU,CAAK,CAAC,EAAI,KAAK,MAAM,GAAG,OAAQ,CAAK,EAC9F,EAAO,KAAK,MAAM,GAAG,MAAO,EAAS,EAAI,aAAc,KAAK,IAAI,EAAG,EAAQ,CAAkB,CAAC,CAAC,EACrG,EAAM,KAAK,EAAI,GAAG,EAAO,GAAG,IAAQ,CAAK,CAAC,EAC1C,EAAM,KAAK,EAAI,KAAiB,IAAQ,CAAK,CAAC,CAChD,CACA,OAAO,EAAM,MAAM,EAAG,CAAM,CAC9B,CAEA,aAAqB,EAAe,EAA0B,CAC5D,IAAM,EAAM,KAAK,UAAU,EAC3B,GAAI,CAAC,EAAK,CACR,KAAK,YAAc,EACnB,KAAK,eAAiB,KAAK,IAAI,EAAmB,CAAM,EACxD,KAAK,aAAe,EACpB,IAAM,EAAQ,CAAC,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,SAAU,iBAAiB,CAAC,EAAG,EAAE,EAQ9E,OAPA,EACE,EACA,KAAK,KAAK,SAAW,EAAI,EAAgB,mCACzC,EACA,OACA,KAAK,KACP,EACO,EAAM,MAAM,EAAG,CAAM,CAC9B,CAEA,IAAM,EAAS,CACb,EACE,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,SAAU,cAAc,EAAI,MAAQ,GAAY,CAAC,EAC/E,KAAK,MAAM,GAAG,MAAO,EAAS,EAAI,aAAc,KAAK,IAAI,EAAG,KAAK,MAAM,EAAQ,CAAC,CAAC,CAAC,CAAC,EACnF,CACF,CACF,EACI,EAAI,aAAa,EAAc,EAAQ,EAAI,YAAa,EAAO,OAAQ,KAAK,KAAK,EACjF,EAAI,KAAK,OAAS,GAAG,EAAc,EAAQ,EAAI,KAAK,KAAK,KAAK,EAAG,EAAO,MAAO,KAAK,KAAK,EAC7F,EAAO,KAAK,EAAS,KAAK,IAAK,EAAO,KAAK,KAAK,EAAG,EAAE,EAErD,IAAM,EAAO,EAAoB,KAAK,UAAU,CAAG,EAAG,KAAK,IAAK,EAAO,KAAK,KAAK,EAIjF,MAHA,MAAK,eAAiB,KAAK,IAAI,EAAG,EAAS,EAAO,MAAM,EACxD,KAAK,YAAc,EAAK,OACxB,KAAK,aAAe,KAAK,IAAI,KAAK,aAAc,KAAK,IAAI,EAAG,EAAK,OAAS,KAAK,cAAc,CAAC,EACvF,CAAC,GAAG,EAAQ,GAAG,EAAK,MAAM,KAAK,aAAc,KAAK,aAAe,KAAK,cAAc,CAAC,CAAC,CAAC,MAAM,EAAG,CAAM,CAC/G,CACF,EAEA,eAAsB,EACpB,EACA,EACA,EACe,CACf,MAAM,EAAI,GAAG,QACV,EAAK,EAAO,EAAc,IAAS,IAAI,EAAyB,EAAK,EAAO,EAAM,EAAM,CAAO,EAChG,CACF,CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflowTerminal.cjs","names":[],"sources":["../../src/types/webWorkflowTerminal.ts"],"sourcesContent":["/**\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/** Segment this package's API is mounted under, below /api/plugin/. */\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/** Where a run's routes live, below the mount every hub-scoped package API shares. */\nexport function workflowRunPath(workspace: string, runKey: string): string {\n return `/api/plugin/${WORKFLOW_API_BASE_PATH}/runs/${encodeURIComponent(workspace)}/${encodeURIComponent(runKey)}`;\n}\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"],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflowTerminal.mjs","names":[],"sources":["../../src/types/webWorkflowTerminal.ts"],"sourcesContent":["/**\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/** Segment this package's API is mounted under, below /api/plugin/. */\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/** Where a run's routes live, below the mount every hub-scoped package API shares. */\nexport function workflowRunPath(workspace: string, runKey: string): string {\n return `/api/plugin/${WORKFLOW_API_BASE_PATH}/runs/${encodeURIComponent(workspace)}/${encodeURIComponent(runKey)}`;\n}\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"],"mappings":"AASA,MAAa,EAAyB,WAGzB,EAAwB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflows.cjs","names":[],"sources":["../../src/types/webWorkflows.ts"],"sourcesContent":["/**\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\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"],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
//#region src/types/webWorkflows.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Workflow run view types shared by this package's hub channel and its web
|
|
4
|
+
* plugin. The shapes mirror what the embedded workflow-mcp engine records;
|
|
5
|
+
* the cockpit renders them as 'workflow_runs' channel payloads.
|
|
6
|
+
*/
|
|
7
|
+
/** workflow-mcp's own stage vocabulary; the registry bucket a run record sits in. */
|
|
8
|
+
type WorkflowStage = 'running' | 'completed' | 'error';
|
|
9
|
+
/** workflow-mcp's terminal outcome for a finished run. */
|
|
10
|
+
type WorkflowOutcome = 'success' | 'skipped' | 'failed' | 'interrupted';
|
|
11
|
+
/** Job and step states as workflow-mcp records them in the progress log. */
|
|
12
|
+
type WorkflowProgressState = 'running' | 'completed' | 'skipped' | 'failed' | 'pause_requested' | 'paused' | 'resumed';
|
|
13
|
+
interface WorkflowStepView {
|
|
14
|
+
name: string;
|
|
15
|
+
status: WorkflowProgressState;
|
|
16
|
+
/** Why the step is in its state, when the engine recorded one (e.g. a skip condition). */
|
|
17
|
+
reason?: string;
|
|
18
|
+
/** ISO 8601 of the step's first running event. */
|
|
19
|
+
startedAt?: string;
|
|
20
|
+
/** ISO 8601 of the step's terminal event. */
|
|
21
|
+
endedAt?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 'pre' and 'post' are the engine's pseudo-jobs for its pre:/post: blocks. */
|
|
24
|
+
type WorkflowJobPhase = 'pre' | 'job' | 'post';
|
|
25
|
+
interface WorkflowJobView {
|
|
26
|
+
name: string;
|
|
27
|
+
phase: WorkflowJobPhase;
|
|
28
|
+
status: WorkflowProgressState;
|
|
29
|
+
reason?: string;
|
|
30
|
+
/** Position among the run's jobs, when the engine recorded one. */
|
|
31
|
+
index?: number;
|
|
32
|
+
total?: number;
|
|
33
|
+
startedAt?: string;
|
|
34
|
+
endedAt?: string;
|
|
35
|
+
steps: WorkflowStepView[];
|
|
36
|
+
}
|
|
37
|
+
/** The job and step a run is on right now; drives the NOW breadcrumb. */
|
|
38
|
+
interface WorkflowPosition {
|
|
39
|
+
job: string;
|
|
40
|
+
step?: string;
|
|
41
|
+
index?: number;
|
|
42
|
+
total?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One workflow run of a session, read from workflow-mcp's registry: the
|
|
46
|
+
* run.json record plus the folded progress.ndjson job tree.
|
|
47
|
+
*/
|
|
48
|
+
interface WorkflowRunView {
|
|
49
|
+
/** Registry identity within its workspace; unique per workspace+stage. */
|
|
50
|
+
runKey: string;
|
|
51
|
+
workspace: string;
|
|
52
|
+
displayName: string;
|
|
53
|
+
workflowName?: string;
|
|
54
|
+
workflowPath: string;
|
|
55
|
+
stage: WorkflowStage;
|
|
56
|
+
outcome?: WorkflowOutcome;
|
|
57
|
+
/** Present while the engine is pausing or paused; absent for plain running. */
|
|
58
|
+
executionState?: 'running' | 'pause_requested' | 'paused' | 'resume_requested';
|
|
59
|
+
/** The prompt the run was launched with, when one was recorded. */
|
|
60
|
+
prompt?: string;
|
|
61
|
+
/** ISO 8601, from the run record. */
|
|
62
|
+
startedAt: string;
|
|
63
|
+
finishedAt?: string;
|
|
64
|
+
/** Failure cause with ANSI escapes stripped, present when the run errored. */
|
|
65
|
+
errorMessage?: string;
|
|
66
|
+
/** The job the engine blamed for the failure, when it recorded one. */
|
|
67
|
+
failedJob?: string;
|
|
68
|
+
/** True when reconciliation decided the recorded pid is no longer alive. */
|
|
69
|
+
stale?: boolean;
|
|
70
|
+
staleReason?: string;
|
|
71
|
+
worktreeBranch?: string;
|
|
72
|
+
position?: WorkflowPosition;
|
|
73
|
+
jobs: WorkflowJobView[];
|
|
74
|
+
}
|
|
75
|
+
interface WorkflowCatalogInputView {
|
|
76
|
+
name: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
required?: boolean;
|
|
79
|
+
default?: string;
|
|
80
|
+
type?: string;
|
|
81
|
+
options?: string[];
|
|
82
|
+
}
|
|
83
|
+
interface WorkflowCatalogJobView {
|
|
84
|
+
name: string;
|
|
85
|
+
steps: string[];
|
|
86
|
+
}
|
|
87
|
+
interface WorkflowCatalogArtifactView {
|
|
88
|
+
path: string;
|
|
89
|
+
kind: 'file' | 'directory';
|
|
90
|
+
description: string;
|
|
91
|
+
producedBy: string[];
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { WorkflowCatalogArtifactView, WorkflowCatalogInputView, WorkflowCatalogJobView, WorkflowJobPhase, WorkflowJobView, WorkflowOutcome, WorkflowPosition, WorkflowProgressState, WorkflowRunView, WorkflowStage, WorkflowStepView };
|
|
95
|
+
//# sourceMappingURL=webWorkflows.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflows.d.cts","names":[],"sources":["../../src/types/webWorkflows.ts"],"mappings":";;;;;;;KAOY;;KAGA;;KAGA;UASK;EACf;EACA,QAAQ;;EAER;;EAEA;;EAEA;;;KAIU;UAEK;EACf;EACA,OAAO;EACP,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA,OAAO;;;UAIQ;EACf;EACA;EACA;EACA;;;;;;UAOe;;EAEf;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,UAAU;;EAEV;;EAEA;;EAEA;EACA;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA,WAAW;EACX,MAAM;;UA4BS;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
//#region src/types/webWorkflows.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Workflow run view types shared by this package's hub channel and its web
|
|
4
|
+
* plugin. The shapes mirror what the embedded workflow-mcp engine records;
|
|
5
|
+
* the cockpit renders them as 'workflow_runs' channel payloads.
|
|
6
|
+
*/
|
|
7
|
+
/** workflow-mcp's own stage vocabulary; the registry bucket a run record sits in. */
|
|
8
|
+
type WorkflowStage = 'running' | 'completed' | 'error';
|
|
9
|
+
/** workflow-mcp's terminal outcome for a finished run. */
|
|
10
|
+
type WorkflowOutcome = 'success' | 'skipped' | 'failed' | 'interrupted';
|
|
11
|
+
/** Job and step states as workflow-mcp records them in the progress log. */
|
|
12
|
+
type WorkflowProgressState = 'running' | 'completed' | 'skipped' | 'failed' | 'pause_requested' | 'paused' | 'resumed';
|
|
13
|
+
interface WorkflowStepView {
|
|
14
|
+
name: string;
|
|
15
|
+
status: WorkflowProgressState;
|
|
16
|
+
/** Why the step is in its state, when the engine recorded one (e.g. a skip condition). */
|
|
17
|
+
reason?: string;
|
|
18
|
+
/** ISO 8601 of the step's first running event. */
|
|
19
|
+
startedAt?: string;
|
|
20
|
+
/** ISO 8601 of the step's terminal event. */
|
|
21
|
+
endedAt?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 'pre' and 'post' are the engine's pseudo-jobs for its pre:/post: blocks. */
|
|
24
|
+
type WorkflowJobPhase = 'pre' | 'job' | 'post';
|
|
25
|
+
interface WorkflowJobView {
|
|
26
|
+
name: string;
|
|
27
|
+
phase: WorkflowJobPhase;
|
|
28
|
+
status: WorkflowProgressState;
|
|
29
|
+
reason?: string;
|
|
30
|
+
/** Position among the run's jobs, when the engine recorded one. */
|
|
31
|
+
index?: number;
|
|
32
|
+
total?: number;
|
|
33
|
+
startedAt?: string;
|
|
34
|
+
endedAt?: string;
|
|
35
|
+
steps: WorkflowStepView[];
|
|
36
|
+
}
|
|
37
|
+
/** The job and step a run is on right now; drives the NOW breadcrumb. */
|
|
38
|
+
interface WorkflowPosition {
|
|
39
|
+
job: string;
|
|
40
|
+
step?: string;
|
|
41
|
+
index?: number;
|
|
42
|
+
total?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One workflow run of a session, read from workflow-mcp's registry: the
|
|
46
|
+
* run.json record plus the folded progress.ndjson job tree.
|
|
47
|
+
*/
|
|
48
|
+
interface WorkflowRunView {
|
|
49
|
+
/** Registry identity within its workspace; unique per workspace+stage. */
|
|
50
|
+
runKey: string;
|
|
51
|
+
workspace: string;
|
|
52
|
+
displayName: string;
|
|
53
|
+
workflowName?: string;
|
|
54
|
+
workflowPath: string;
|
|
55
|
+
stage: WorkflowStage;
|
|
56
|
+
outcome?: WorkflowOutcome;
|
|
57
|
+
/** Present while the engine is pausing or paused; absent for plain running. */
|
|
58
|
+
executionState?: 'running' | 'pause_requested' | 'paused' | 'resume_requested';
|
|
59
|
+
/** The prompt the run was launched with, when one was recorded. */
|
|
60
|
+
prompt?: string;
|
|
61
|
+
/** ISO 8601, from the run record. */
|
|
62
|
+
startedAt: string;
|
|
63
|
+
finishedAt?: string;
|
|
64
|
+
/** Failure cause with ANSI escapes stripped, present when the run errored. */
|
|
65
|
+
errorMessage?: string;
|
|
66
|
+
/** The job the engine blamed for the failure, when it recorded one. */
|
|
67
|
+
failedJob?: string;
|
|
68
|
+
/** True when reconciliation decided the recorded pid is no longer alive. */
|
|
69
|
+
stale?: boolean;
|
|
70
|
+
staleReason?: string;
|
|
71
|
+
worktreeBranch?: string;
|
|
72
|
+
position?: WorkflowPosition;
|
|
73
|
+
jobs: WorkflowJobView[];
|
|
74
|
+
}
|
|
75
|
+
interface WorkflowCatalogInputView {
|
|
76
|
+
name: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
required?: boolean;
|
|
79
|
+
default?: string;
|
|
80
|
+
type?: string;
|
|
81
|
+
options?: string[];
|
|
82
|
+
}
|
|
83
|
+
interface WorkflowCatalogJobView {
|
|
84
|
+
name: string;
|
|
85
|
+
steps: string[];
|
|
86
|
+
}
|
|
87
|
+
interface WorkflowCatalogArtifactView {
|
|
88
|
+
path: string;
|
|
89
|
+
kind: 'file' | 'directory';
|
|
90
|
+
description: string;
|
|
91
|
+
producedBy: string[];
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { WorkflowCatalogArtifactView, WorkflowCatalogInputView, WorkflowCatalogJobView, WorkflowJobPhase, WorkflowJobView, WorkflowOutcome, WorkflowPosition, WorkflowProgressState, WorkflowRunView, WorkflowStage, WorkflowStepView };
|
|
95
|
+
//# sourceMappingURL=webWorkflows.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflows.d.mts","names":[],"sources":["../../src/types/webWorkflows.ts"],"mappings":";;;;;;;KAOY;;KAGA;;KAGA;UASK;EACf;EACA,QAAQ;;EAER;;EAEA;;EAEA;;;KAIU;UAEK;EACf;EACA,OAAO;EACP,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA,OAAO;;;UAIQ;EACf;EACA;EACA;EACA;;;;;;UAOe;;EAEf;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,UAAU;;EAEV;;EAEA;;EAEA;EACA;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA,WAAW;EACX,MAAM;;UA4BS;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webWorkflows.mjs","names":[],"sources":["../../src/types/webWorkflows.ts"],"sourcesContent":["/**\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\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"],"mappings":"AAyFA,MAAa,EAAqB,gBAuDrB,EAAwB"}
|
package/dist/webHub.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/workflowCatalogChannel.cjs"),t=require("./adapters/workflowsHubChannel.cjs");exports.createWorkflowCatalogChannel=e.createWorkflowCatalogChannel,exports.createWorkflowsChannel=t.createWorkflowsChannel,exports.defaultCatalogDeps=e.defaultCatalogDeps,exports.webHubChannels=t.webHubChannels;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { WorkflowCatalogChannelOptions, createWorkflowCatalogChannel, defaultCatalogDeps } from "./adapters/workflowCatalogChannel.cjs";
|
|
2
|
+
import { WorkflowsChannelOptions, createWorkflowsChannel, webHubChannels } from "./adapters/workflowsHubChannel.cjs";
|
|
3
|
+
export { type WorkflowCatalogChannelOptions, type WorkflowsChannelOptions, createWorkflowCatalogChannel, createWorkflowsChannel, defaultCatalogDeps, webHubChannels };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { WorkflowCatalogChannelOptions, createWorkflowCatalogChannel, defaultCatalogDeps } from "./adapters/workflowCatalogChannel.mjs";
|
|
2
|
+
import { WorkflowsChannelOptions, createWorkflowsChannel, webHubChannels } from "./adapters/workflowsHubChannel.mjs";
|
|
3
|
+
export { type WorkflowCatalogChannelOptions, type WorkflowsChannelOptions, createWorkflowCatalogChannel, createWorkflowsChannel, defaultCatalogDeps, webHubChannels };
|
package/dist/webHub.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createWorkflowCatalogChannel as e,defaultCatalogDeps as t}from"./adapters/workflowCatalogChannel.mjs";import{createWorkflowsChannel as n,webHubChannels as r}from"./adapters/workflowsHubChannel.mjs";export{e as createWorkflowCatalogChannel,n as createWorkflowsChannel,t as defaultCatalogDeps,r as webHubChannels};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-workflow",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.39",
|
|
4
4
|
"description": "GitHub Actions-style workflow graphs, artifacts, recovery, and asynchronous runs for DoomPi.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
"llms.txt",
|
|
31
31
|
"README.md",
|
|
32
32
|
"src/prompts",
|
|
33
|
-
"skills/workflow-recovery/SKILL.md"
|
|
33
|
+
"skills/workflow-recovery/SKILL.md",
|
|
34
|
+
"web",
|
|
35
|
+
"src/types/webWorkflows.ts",
|
|
36
|
+
"src/types/webWorkflowTerminal.ts"
|
|
34
37
|
],
|
|
35
38
|
"type": "module",
|
|
36
39
|
"main": "./dist/index.cjs",
|
|
@@ -47,6 +50,11 @@
|
|
|
47
50
|
"import": "./dist/extensions/pi.mjs",
|
|
48
51
|
"require": "./dist/extensions/pi.cjs"
|
|
49
52
|
},
|
|
53
|
+
"./web-hub": {
|
|
54
|
+
"types": "./dist/webHub.d.mts",
|
|
55
|
+
"import": "./dist/webHub.mjs",
|
|
56
|
+
"require": "./dist/webHub.cjs"
|
|
57
|
+
},
|
|
50
58
|
"./package.json": "./package.json",
|
|
51
59
|
"./skills/workflow-recovery/SKILL.md": "./skills/workflow-recovery/SKILL.md"
|
|
52
60
|
},
|
|
@@ -54,26 +62,35 @@
|
|
|
54
62
|
"access": "public"
|
|
55
63
|
},
|
|
56
64
|
"dependencies": {
|
|
57
|
-
"@agimon-ai/workflow-mcp": "0.23.
|
|
65
|
+
"@agimon-ai/workflow-mcp": "0.23.19",
|
|
58
66
|
"@deepseek-ai/cordis": "4.0.1",
|
|
59
67
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
68
|
+
"hono": "4.13.3",
|
|
60
69
|
"zod": "4.4.3",
|
|
61
|
-
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.
|
|
62
|
-
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.
|
|
63
|
-
"@agimon-ai/doompi-ui": "0.0.1-alpha.
|
|
70
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.39",
|
|
71
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.39",
|
|
72
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.39",
|
|
73
|
+
"@agimon-ai/doompi-web-components": "0.0.1-alpha.0",
|
|
74
|
+
"@agimon-ai/doompi-web-contracts": "0.0.1-alpha.2"
|
|
64
75
|
},
|
|
65
76
|
"devDependencies": {
|
|
66
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
67
|
-
"@earendil-works/pi-tui": "0.84.
|
|
77
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
78
|
+
"@earendil-works/pi-tui": "0.84.3",
|
|
79
|
+
"@tanstack/react-store": "0.11.1",
|
|
80
|
+
"@tanstack/store": "0.11.1",
|
|
68
81
|
"@types/node": "26.2.0",
|
|
82
|
+
"@types/react": "19.2.7",
|
|
83
|
+
"@types/react-dom": "19.2.3",
|
|
69
84
|
"@vitest/coverage-v8": "4.1.11",
|
|
85
|
+
"react": "19.2.8",
|
|
86
|
+
"react-dom": "19.2.8",
|
|
70
87
|
"tsdown": "0.22.14",
|
|
71
88
|
"typescript": "7.0.2",
|
|
72
89
|
"vitest": "4.1.11"
|
|
73
90
|
},
|
|
74
91
|
"peerDependencies": {
|
|
75
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
76
|
-
"@earendil-works/pi-tui": "0.84.
|
|
92
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
93
|
+
"@earendil-works/pi-tui": "0.84.3"
|
|
77
94
|
},
|
|
78
95
|
"peerDependenciesMeta": {
|
|
79
96
|
"@earendil-works/pi-coding-agent": {
|
|
@@ -86,6 +103,25 @@
|
|
|
86
103
|
"engines": {
|
|
87
104
|
"node": ">=22.19.0"
|
|
88
105
|
},
|
|
106
|
+
"doompiApi": {
|
|
107
|
+
"basePath": "workflow",
|
|
108
|
+
"hub": {
|
|
109
|
+
"entry": "./src/exports/hubApi.ts",
|
|
110
|
+
"dist": "./dist/hubApi.mjs"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"doompiWeb": {
|
|
114
|
+
"pluginId": "workflows",
|
|
115
|
+
"channels": [
|
|
116
|
+
"workflow_runs",
|
|
117
|
+
"workflow_catalog"
|
|
118
|
+
],
|
|
119
|
+
"client": "./web/index.ts",
|
|
120
|
+
"hub": {
|
|
121
|
+
"entry": "./src/exports/webHub.ts",
|
|
122
|
+
"dist": "./dist/webHub.mjs"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
89
125
|
"pi": {
|
|
90
126
|
"extensions": [
|
|
91
127
|
"./dist/extensions/pi.mjs"
|
|
@@ -94,7 +130,7 @@
|
|
|
94
130
|
"scripts": {
|
|
95
131
|
"build": "tsdown",
|
|
96
132
|
"test": "vitest --run",
|
|
97
|
-
"typecheck": "tsc --noEmit",
|
|
133
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p web/tsconfig.json",
|
|
98
134
|
"lint": "oxlint . && oxfmt . --check",
|
|
99
135
|
"fixcode": "oxlint . --fix && oxfmt ."
|
|
100
136
|
}
|
|
@@ -12,13 +12,11 @@ name: verify
|
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
test:
|
|
15
|
-
runs-on: ubuntu-latest
|
|
16
15
|
steps:
|
|
17
16
|
- name: Run tests
|
|
18
17
|
run: pnpm test
|
|
19
18
|
|
|
20
19
|
summarize:
|
|
21
|
-
runs-on: ubuntu-latest
|
|
22
20
|
needs: test
|
|
23
21
|
steps:
|
|
24
22
|
- name: Record result
|
|
@@ -27,6 +25,6 @@ jobs:
|
|
|
27
25
|
|
|
28
26
|
`needs` expresses job ordering. Keep steps small enough that failure evidence identifies the command that needs attention. Use runner-specific `interactiveRun` configuration when a command genuinely requires a TTY.
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
Every `run` command executes on the workflow host with that process's environment and privileges. There is no VM, container, or sandbox. Review workflow changes as executable code, avoid embedding secrets, and make retry-sensitive external side effects explicit.
|
|
31
29
|
|
|
32
30
|
Before relying on the graph, enable Workflow mode, discover it with `list_workflows`, launch a disposable run, and inspect job and step status with `workflow_run`. Test a failure path when recovery behavior matters.
|