@qaick/runner 0.2.0-alpha.11 → 0.2.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qaick/runner",
3
3
  "description": "Reusable QAick Runner module and standalone execution application.",
4
- "version": "0.2.0-alpha.11",
4
+ "version": "0.2.0-alpha.13",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "package-dist",
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@qaick/contract": "0.2.10",
56
56
  "@qaick/executor": "0.1.0-alpha.1",
57
- "@qaick/http-executor": "0.1.0-alpha.1",
57
+ "@qaick/http-executor": "0.1.0-alpha.2",
58
58
  "@qaick/runtime": "0.1.0-alpha.2",
59
59
  "zustand": "^5.0.15"
60
60
  },
@@ -63,12 +63,12 @@
63
63
  "react-dom": ">=19.0.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@vitejs/plugin-react": "^6.1.1",
67
66
  "@testing-library/dom": "^10.4.2",
68
67
  "@testing-library/react": "^16.3.3",
69
68
  "@types/node": "^24.13.3",
70
69
  "@types/react": "^19.2.18",
71
70
  "@types/react-dom": "^19.2.7",
71
+ "@vitejs/plugin-react": "^6.1.1",
72
72
  "jsdom": "^30.0.1",
73
73
  "oxlint": "^1.81.0",
74
74
  "react": "^19.2.8",
@@ -1,4 +1,4 @@
1
- import packageJson from '../package.json';
1
+ import packageJson from '../package.json' with { type: 'json' };
2
2
  export const RUNNER_VERSION = packageJson.version;
3
3
  export const RUNNER_BUILD_ID = import.meta.env.VITE_BUILD_ID ?? import.meta.env.MODE;
4
4
  export const RUNNER_BUILD_LABEL = `v${RUNNER_VERSION} · ${RUNNER_BUILD_ID}`;
@@ -1,14 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from 'react';
3
- import { checkoutNestedPackage, checkoutPackage, checkoutProjectPackage } from './fixture';
4
- import { loadExecutionPackage, PackageLoadError } from './package-loader';
5
- import { PackageCatalog } from './catalog';
6
- import { RUNNER_CONTRACT_VERSION } from './types';
7
- import { RunnerWalkthrough } from '../demo/RunnerWalkthrough';
8
- import { RUNNER_BUILD_LABEL } from '../build-info';
9
- import { collectSecretValues, redactExecutionEvent, redactExecutionResult, redactKeyValuePairs } from './redaction';
10
- import { createResultExport } from './result-export';
11
- import { persistRunHistory } from './history';
3
+ import { checkoutNestedPackage, checkoutPackage, checkoutProjectPackage } from './fixture.js';
4
+ import { loadExecutionPackage, PackageLoadError } from './package-loader.js';
5
+ import { PackageCatalog } from './catalog.js';
6
+ import { RUNNER_CONTRACT_VERSION } from './types.js';
7
+ import { RunnerWalkthrough } from '../demo/RunnerWalkthrough.js';
8
+ import { RUNNER_BUILD_LABEL } from '../build-info.js';
9
+ import { collectSecretValues, redactExecutionEvent, redactExecutionResult, redactKeyValuePairs } from './redaction.js';
10
+ import { createResultExport } from './result-export.js';
11
+ import { persistRunHistory } from './history.js';
12
12
  const HISTORY_KEY = 'qaick-runner.history.v1';
13
13
  const HISTORY_RETENTION_KEY = 'qaick-runner.history-retention.v1';
14
14
  const IMPORTED_PACKAGE_KEY = 'qaick-runner.imported-package.v1';
@@ -215,13 +215,13 @@ function RunnerApp({ client, onExit }) {
215
215
  return undefined; const timer = window.setInterval(() => setClock(Date.now()), 250); return () => window.clearInterval(timer); }, [runState]);
216
216
  useEffect(() => { const navigateIssue = (event) => { const target = event.target; const issue = target.closest('.validation-issue'); const stepId = issue?.dataset.stepId; const eventRow = target.closest('.event-row'); const index = stepId ? displaySteps.findIndex(step => step.id === stepId || step.id.endsWith(`.${stepId}`)) : eventRow ? displaySteps.findIndex(step => eventRow.textContent?.includes(step.name)) : -1; if (index >= 0)
217
217
  setSelectedStep(index); }; document.addEventListener('click', navigateIssue); return () => document.removeEventListener('click', navigateIssue); }, [displaySteps]);
218
- return _jsxs("div", { className: "runner-shell", children: [_jsxs("header", { className: "runner-header", children: [_jsxs("div", { className: "runner-brand", children: [_jsx("span", { className: "runner-brand-mark", children: "QAICK" }), _jsx("span", { className: "runner-brand-product", children: "Runner" }), _jsx("span", { className: "alpha-label", children: "Alpha 11" }), onExit && _jsx("button", { className: "about-button", onClick: onExit, children: "Studio" })] }), _jsx("span", { className: "header-spacer" }), _jsx("a", { className: "demo-entry", href: "?demo", children: "View demo" }), _jsx("button", { className: "about-button", onClick: () => setShowAbout(true), children: "About" }), _jsxs("label", { className: "theme-picker", children: ["Theme", _jsxs("select", { value: theme, onChange: event => setTheme(event.target.value), children: [_jsx("option", { value: "light", children: "Light" }), _jsx("option", { value: "dark", children: "Dark" })] })] })] }), _jsxs("main", { className: "runner-main", children: [_jsxs("nav", { className: "runner-nav", children: [_jsx("p", { className: "nav-label", children: "Workspace" }), _jsx(NavItem, { active: true, icon: "\u25C8", text: "Execution Package" }), _jsx(NavItem, { icon: "\u25A1", text: "Projects" }), _jsx(NavItem, { icon: "\u2318", text: "Flows" }), _jsx(NavItem, { icon: "\u21B6", text: "Run History" }), _jsxs("div", { className: "package-card", children: [_jsx("small", { children: "Loaded package" }), _jsxs("strong", { children: [executionPackage.packageId, ".qaick.json"] }), _jsxs("small", { children: ["Schema ", executionPackage.schemaVersion, " \u00B7 ", executionPackage.definitions.length, " definitions"] })] })] }), _jsxs("section", { className: "runner-workspace", children: [_jsx("div", { className: "eyebrow", children: "EXECUTION PACKAGE" }), _jsx("h1", { children: executionPackage.target.name }), _jsxs("p", { className: "description", children: ["Execute the selected QAick ", executionPackage.target.kind === 'project' ? 'Project' : 'Flow', " and capture structured evidence."] }), _jsxs("div", { className: "run-controls", children: [_jsxs("label", { children: ["Target", _jsx("select", { value: executionPackage.packageId, onChange: event => { const next = packageCatalog.get(event.target.value); setExecutionPackage(next); setBreakpoints(new Set()); breakpointsRef.current = new Set(); setStopAfterStepId(undefined); setLoadError(undefined); setLoadIssues([]); setRuntimeValues(Object.fromEntries((next.runtimeRequirements ?? []).map(name => [name, '']))); setStepStates((next.target.kind === 'project' ? next.flows?.flatMap(flow => flattenDisplaySteps(flow.steps)) ?? [] : flattenDisplaySteps(next.steps)).map(() => 'pending')); setLoopProgress(loopProgressFor(next.target.kind === 'project' ? next.flows?.flatMap(flow => flow.steps) ?? [] : next.steps)); setSelectedStep(0); setResult(undefined); setEvents([]); setRunState('ready'); }, children: packageCatalog.targets().map(item => _jsx("option", { value: item.packageId, children: item.target.name }, item.packageId)) })] }), _jsxs("label", { children: ["Environment", _jsxs("select", { value: environment, onChange: event => setEnvironment(event.target.value), children: [_jsx("option", { children: "test" }), _jsx("option", { children: "local" }), _jsx("option", { children: "staging" })] })] }), _jsxs("label", { children: ["Timeout", _jsxs("select", { value: timeoutMs, onChange: event => setTimeoutMs(event.target.value), children: [_jsx("option", { value: "none", children: "None" }), _jsx("option", { value: "1000", children: "1 second" }), _jsx("option", { value: "3000", children: "3 seconds" }), _jsx("option", { value: "10000", children: "10 seconds" })] })] }), _jsxs("label", { children: ["Run configuration", _jsxs("select", { defaultValue: "Default", children: [_jsx("option", { children: "Default" }), _jsx("option", { children: "Debug" })] })] }), _jsxs("label", { className: "file-button", children: ["Load package", _jsx("input", { type: "file", accept: "application/json,.json", onChange: event => void loadPackage(event.target.files?.[0]) })] }), _jsx("button", { className: "button", onClick: () => setEditingInputs(value => !value), children: editingInputs ? 'Done inputs' : 'Edit inputs' }), _jsx("button", { className: "button primary", onClick: () => void run(), disabled: runState === 'preflighting' || runState === 'running', children: "\u25B6\u00A0 Run" }), _jsx("button", { className: "button dry-run", onClick: () => void run(true), disabled: runState === "preflighting" || runState === "running", children: "\u25CE\u00A0 Pre-run validation" }), _jsx("button", { className: "button stop", onClick: () => void stop(), disabled: runState !== 'preflighting' && runState !== 'running', children: "\u25A0\u00A0 Stop" }), _jsx("button", { className: "button", onClick: () => void pause(), disabled: controlState !== 'running', children: "\u2161\u00A0 Pause" }), _jsx("button", { className: `button ${controlState === 'paused' ? 'resume-highlight' : ''}`, onClick: () => void resume(), disabled: controlState !== 'paused', children: "\u25B6\u00A0 Resume" }), _jsx("button", { className: "button", onClick: () => void stepExecution(), disabled: controlState !== 'paused', children: "\u21A6\u00A0 Step" }), breakpoints.size > 0 && _jsxs("span", { className: "debug-session-badge", children: [breakpoints.size, " breakpoint", breakpoints.size === 1 ? "" : "s", " armed"] })] }), viewingHistoryEntry && _jsxs("div", { className: "history-view-banner", children: ["Viewing stored results \u00B7 ", viewingHistoryEntry] }), loadError && _jsx("p", { className: "load-error", children: loadError }), loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues, title: "Artifact validation" }), result?.issues !== undefined && _jsx(PreRunValidation, { issues: result.issues }), result?.warnings !== undefined && result.warnings.length > 0 && _jsx(PreRunValidation, { issues: result.warnings, title: "Browser execution warnings" }), editingInputs && _jsxs("section", { className: "inputs-panel panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Invocation Inputs" }), _jsx("span", { className: "panel-spacer" }), _jsx("span", { className: "input-hint", children: "Values are sent with the next run" })] }), _jsxs("div", { className: "input-grid", children: [_jsx(InputField, { label: "customerId", value: String(inputs.customerId ?? ''), onChange: value => setInputs(previous => ({ ...previous, customerId: value })) }), _jsx(InputField, { label: "orderId", value: String(inputs.orderId ?? ''), onChange: value => setInputs(previous => ({ ...previous, orderId: value })) }), _jsx(InputField, { label: "amount", value: String(inputs.amount ?? ''), onChange: value => setInputs(previous => ({ ...previous, amount: value })) }), (executionPackage.requiredInputs ?? []).filter(name => !['customerId', 'orderId', 'amount'].includes(name)).map(name => _jsx(InputField, { label: name, value: String(inputs[name] ?? ''), onChange: value => setInputs(previous => ({ ...previous, [name]: value })) }, name)), (executionPackage.runtimeRequirements ?? []).map(name => _jsx(InputField, { label: `Runtime · ${name}`, value: runtimeValues[name] ?? '', onChange: value => setRuntimeValues(previous => ({ ...previous, [name]: value })) }, name))] })] }), _jsxs("section", { className: "panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Live Execution" }), _jsx("span", { className: "panel-spacer" }), _jsxs("span", { className: "execution-menu-label", children: ["Right-click a row to manage its breakpoint \u00B7 Selected: ", displaySteps[selectedStep]?.name ?? 'None'] }), _jsxs("span", { className: runState === 'running' ? 'running' : runState === 'failed' ? 'stopped' : 'run-status', children: ["\u25CF ", statusLabel] })] }), hasNestedSteps && _jsxs("div", { className: "hierarchy-hint", children: [_jsx("strong", { children: "Nested execution" }), _jsx("span", { children: "Use \u2212 / + to collapse or expand nested Operations, Control Blocks, and loops." }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(true), children: "Collapse all" }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(false), children: "Expand all" })] }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "#" }), _jsx("th", { children: "Step hierarchy" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Start time" }), _jsx("th", { children: "Duration" })] }) }), _jsx("tbody", { children: displaySteps.map((step, index) => { const progress = step.loopTotal ? loopProgress[step.id] ?? { current: 0, total: step.loopTotal } : undefined; const percent = progress ? Math.round(progress.current / progress.total * 100) : 0; const isLoop = Boolean(step.loopTotal); const displayState = displayResults[index]?.state ?? stepStates[index] ?? 'pending'; const isLoopContent = Boolean(step.loopId); const isLoopEnd = isLoopContent && displaySteps[index + 1]?.loopId !== step.loopId; const elapsed = step.loopId && loopStartedAt[step.loopId] ? formatElapsed(clock - loopStartedAt[step.loopId]) : undefined; return _jsxs("tr", { className: `${selectedStep === index ? 'selected ' : ''}${isLoop ? 'loop-row ' : ''}${isLoopContent ? 'loop-content ' : ''}${isLoopEnd ? 'loop-end ' : ''}${step.depth > 0 ? 'nested-row' : 'parent-row'}`, tabIndex: 0, onKeyDown: event => { if (event.key === "ArrowDown") {
218
+ return _jsxs("div", { className: "runner-shell", children: [_jsxs("header", { className: "runner-header", children: [_jsxs("div", { className: "runner-brand", children: [_jsx("span", { className: "runner-brand-mark", children: "QAICK" }), _jsx("span", { className: "runner-brand-product", children: "Runner" }), _jsx("span", { className: "alpha-label", children: "Alpha 12" }), onExit && _jsx("button", { className: "about-button", onClick: onExit, children: "Studio" })] }), _jsx("span", { className: "header-spacer" }), _jsx("a", { className: "demo-entry", href: "?demo", children: "View demo" }), _jsx("button", { className: "about-button", onClick: () => setShowAbout(true), children: "About" }), _jsxs("label", { className: "theme-picker", children: ["Theme", _jsxs("select", { value: theme, onChange: event => setTheme(event.target.value), children: [_jsx("option", { value: "light", children: "Light" }), _jsx("option", { value: "dark", children: "Dark" })] })] })] }), _jsxs("main", { className: "runner-main", children: [_jsxs("nav", { className: "runner-nav", children: [_jsx("p", { className: "nav-label", children: "Workspace" }), _jsx(NavItem, { active: true, icon: "\u25C8", text: "Execution Package" }), _jsx(NavItem, { icon: "\u25A1", text: "Projects" }), _jsx(NavItem, { icon: "\u2318", text: "Flows" }), _jsx(NavItem, { icon: "\u21B6", text: "Run History" }), _jsxs("div", { className: "package-card", children: [_jsx("small", { children: "Loaded package" }), _jsxs("strong", { children: [executionPackage.packageId, ".qaick.json"] }), _jsxs("small", { children: ["Schema ", executionPackage.schemaVersion, " \u00B7 ", executionPackage.definitions.length, " definitions"] })] })] }), _jsxs("section", { className: "runner-workspace", children: [_jsx("div", { className: "eyebrow", children: "EXECUTION PACKAGE" }), _jsx("h1", { children: executionPackage.target.name }), _jsxs("p", { className: "description", children: ["Execute the selected QAick ", executionPackage.target.kind === 'project' ? 'Project' : 'Flow', " and capture structured evidence."] }), _jsxs("div", { className: "run-controls", children: [_jsxs("label", { children: ["Target", _jsx("select", { value: executionPackage.packageId, onChange: event => { const next = packageCatalog.get(event.target.value); setExecutionPackage(next); setBreakpoints(new Set()); breakpointsRef.current = new Set(); setStopAfterStepId(undefined); setLoadError(undefined); setLoadIssues([]); setRuntimeValues(Object.fromEntries((next.runtimeRequirements ?? []).map(name => [name, '']))); setStepStates((next.target.kind === 'project' ? next.flows?.flatMap(flow => flattenDisplaySteps(flow.steps)) ?? [] : flattenDisplaySteps(next.steps)).map(() => 'pending')); setLoopProgress(loopProgressFor(next.target.kind === 'project' ? next.flows?.flatMap(flow => flow.steps) ?? [] : next.steps)); setSelectedStep(0); setResult(undefined); setEvents([]); setRunState('ready'); }, children: packageCatalog.targets().map(item => _jsx("option", { value: item.packageId, children: item.target.name }, item.packageId)) })] }), _jsxs("label", { children: ["Environment", _jsxs("select", { value: environment, onChange: event => setEnvironment(event.target.value), children: [_jsx("option", { children: "test" }), _jsx("option", { children: "local" }), _jsx("option", { children: "staging" })] })] }), _jsxs("label", { children: ["Timeout", _jsxs("select", { value: timeoutMs, onChange: event => setTimeoutMs(event.target.value), children: [_jsx("option", { value: "none", children: "None" }), _jsx("option", { value: "1000", children: "1 second" }), _jsx("option", { value: "3000", children: "3 seconds" }), _jsx("option", { value: "10000", children: "10 seconds" })] })] }), _jsxs("label", { children: ["Run configuration", _jsxs("select", { defaultValue: "Default", children: [_jsx("option", { children: "Default" }), _jsx("option", { children: "Debug" })] })] }), _jsxs("label", { className: "file-button", children: ["Load package", _jsx("input", { type: "file", accept: "application/json,.json", onChange: event => void loadPackage(event.target.files?.[0]) })] }), _jsx("button", { className: "button", onClick: () => setEditingInputs(value => !value), children: editingInputs ? 'Done inputs' : 'Edit inputs' }), _jsx("button", { className: "button primary", onClick: () => void run(), disabled: runState === 'preflighting' || runState === 'running', children: "\u25B6\u00A0 Run" }), _jsx("button", { className: "button dry-run", onClick: () => void run(true), disabled: runState === "preflighting" || runState === "running", children: "\u25CE\u00A0 Pre-run validation" }), _jsx("button", { className: "button stop", onClick: () => void stop(), disabled: runState !== 'preflighting' && runState !== 'running', children: "\u25A0\u00A0 Stop" }), _jsx("button", { className: "button", onClick: () => void pause(), disabled: controlState !== 'running', children: "\u2161\u00A0 Pause" }), _jsx("button", { className: `button ${controlState === 'paused' ? 'resume-highlight' : ''}`, onClick: () => void resume(), disabled: controlState !== 'paused', children: "\u25B6\u00A0 Resume" }), _jsx("button", { className: "button", onClick: () => void stepExecution(), disabled: controlState !== 'paused', children: "\u21A6\u00A0 Step" }), breakpoints.size > 0 && _jsxs("span", { className: "debug-session-badge", children: [breakpoints.size, " breakpoint", breakpoints.size === 1 ? "" : "s", " armed"] })] }), viewingHistoryEntry && _jsxs("div", { className: "history-view-banner", children: ["Viewing stored results \u00B7 ", viewingHistoryEntry] }), loadError && _jsx("p", { className: "load-error", children: loadError }), loadIssues.length > 0 && _jsx(PreRunValidation, { issues: loadIssues, title: "Artifact validation" }), result?.issues !== undefined && _jsx(PreRunValidation, { issues: result.issues }), result?.warnings !== undefined && result.warnings.length > 0 && _jsx(PreRunValidation, { issues: result.warnings, title: "Browser execution warnings" }), editingInputs && _jsxs("section", { className: "inputs-panel panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Invocation Inputs" }), _jsx("span", { className: "panel-spacer" }), _jsx("span", { className: "input-hint", children: "Values are sent with the next run" })] }), _jsxs("div", { className: "input-grid", children: [_jsx(InputField, { label: "customerId", value: String(inputs.customerId ?? ''), onChange: value => setInputs(previous => ({ ...previous, customerId: value })) }), _jsx(InputField, { label: "orderId", value: String(inputs.orderId ?? ''), onChange: value => setInputs(previous => ({ ...previous, orderId: value })) }), _jsx(InputField, { label: "amount", value: String(inputs.amount ?? ''), onChange: value => setInputs(previous => ({ ...previous, amount: value })) }), (executionPackage.requiredInputs ?? []).filter(name => !['customerId', 'orderId', 'amount'].includes(name)).map(name => _jsx(InputField, { label: name, value: String(inputs[name] ?? ''), onChange: value => setInputs(previous => ({ ...previous, [name]: value })) }, name)), (executionPackage.runtimeRequirements ?? []).map(name => _jsx(InputField, { label: `Runtime · ${name}`, value: runtimeValues[name] ?? '', onChange: value => setRuntimeValues(previous => ({ ...previous, [name]: value })) }, name))] })] }), _jsxs("section", { className: "panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Live Execution" }), _jsx("span", { className: "panel-spacer" }), _jsxs("span", { className: "execution-menu-label", children: ["Right-click a row to manage its breakpoint \u00B7 Selected: ", displaySteps[selectedStep]?.name ?? 'None'] }), _jsxs("span", { className: runState === 'running' ? 'running' : runState === 'failed' ? 'stopped' : 'run-status', children: ["\u25CF ", statusLabel] })] }), hasNestedSteps && _jsxs("div", { className: "hierarchy-hint", children: [_jsx("strong", { children: "Nested execution" }), _jsx("span", { children: "Use \u2212 / + to collapse or expand nested Operations, Control Blocks, and loops." }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(true), children: "Collapse all" }), _jsx("button", { className: "hierarchy-action", onClick: () => setAllCollapsed(false), children: "Expand all" })] }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "#" }), _jsx("th", { children: "Step hierarchy" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Start time" }), _jsx("th", { children: "Duration" })] }) }), _jsx("tbody", { children: displaySteps.map((step, index) => { const progress = step.loopTotal ? loopProgress[step.id] ?? { current: 0, total: step.loopTotal } : undefined; const percent = progress ? Math.round(progress.current / progress.total * 100) : 0; const isLoop = Boolean(step.loopTotal); const displayState = displayResults[index]?.state ?? stepStates[index] ?? 'pending'; const isLoopContent = Boolean(step.loopId); const isLoopEnd = isLoopContent && displaySteps[index + 1]?.loopId !== step.loopId; const elapsed = step.loopId && loopStartedAt[step.loopId] ? formatElapsed(clock - loopStartedAt[step.loopId]) : undefined; return _jsxs("tr", { className: `${selectedStep === index ? 'selected ' : ''}${isLoop ? 'loop-row ' : ''}${isLoopContent ? 'loop-content ' : ''}${isLoopEnd ? 'loop-end ' : ''}${step.depth > 0 ? 'nested-row' : 'parent-row'}`, tabIndex: 0, onKeyDown: event => { if (event.key === "ArrowDown") {
219
219
  event.preventDefault();
220
220
  setSelectedStep(Math.min(displaySteps.length - 1, index + 1));
221
221
  } if (event.key === "ArrowUp") {
222
222
  event.preventDefault();
223
223
  setSelectedStep(Math.max(0, index - 1));
224
- } }, onClick: () => setSelectedStep(index), onContextMenu: event => { event.preventDefault(); setSelectedStep(index); setContextMenu({ x: event.clientX, y: event.clientY, stepId: step.id }); }, children: [_jsx("td", { children: index + 1 }), _jsxs("td", { children: [_jsx("span", { className: `step-icon ${isLoop ? 'loop-icon' : displayState}`, children: isLoop ? '↻' : displayState === 'finished' ? '✓' : displayState === 'waiting' ? '◷' : displayState === 'skipped' ? '–' : '' }), _jsxs("span", { className: "hierarchy-name", style: { paddingLeft: `${step.depth * 18}px` }, children: [step.depth > 0 && _jsx("span", { className: "branch-marker", children: "\u2514" }), step.hasChildren && _jsx("button", { className: "collapse-toggle", "aria-label": `${collapsedSteps.has(step.id) ? 'Expand' : 'Collapse'} ${step.name}`, onClick: event => { event.stopPropagation(); toggleStep(step.id); }, children: collapsedSteps.has(step.id) ? '+' : '−' }), _jsx("span", { children: step.name }), breakpoints.has(step.id) && _jsx("small", { className: "breakpoint-marker", "aria-label": "Breakpoint armed", title: "Breakpoint armed", children: "STOP" }), isLoop && _jsx("small", { className: "kind-label loop-label", children: "LOOP" }), step.depth > 0 ? _jsx("small", { className: "kind-label nested-label", children: "NESTED STEP" }) : !isLoop && _jsx("small", { className: "kind-label", children: step.kind.toUpperCase() })] }), selectedStep === index && _jsx("small", { className: "selected-label", children: "SELECTED" })] }), _jsxs("td", { children: [progress && _jsxs("div", { className: "loop-progress", children: [_jsxs("strong", { children: ["REPEAT LOOP \u00B7 ITERATION ", progress.current, " OF ", progress.total] }), _jsx("span", { className: "loop-bar", children: _jsx("i", { style: { width: `${percent}%` } }) }), _jsx("small", { children: elapsed ? `Elapsed ${elapsed}` : 'Waiting to start' })] }), _jsx("span", { className: `status ${displayState}`, children: isLoop ? 'LOOP' : displayState.toUpperCase() })] }), _jsx("td", { children: displayResults[index] ? new Date(result?.finishedAt ?? '').toLocaleTimeString() : '—' }), _jsx("td", { children: displayResults[index] ? `${displayResults[index].durationMs} ms` : '—' })] }, `${step.id}-${index}`); }) })] }), contextMenu && _jsxs("div", { className: "runner-context-menu", style: { left: contextMenu.x, top: contextMenu.y }, onClick: event => event.stopPropagation(), onContextMenu: event => event.preventDefault(), children: [_jsx("strong", { children: "Breakpoint" }), breakpoints.has(contextMenu.stepId) ? _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Remove breakpoint" }) : _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Add breakpoint" })] })] }), _jsxs("section", { className: "panel event-panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Event Log" }), _jsx("span", { className: "panel-spacer" }), _jsx("input", { className: "event-search", "aria-label": "Search event log", placeholder: "Search events", value: eventSearch, onChange: event => setEventSearch(event.target.value) }), _jsxs("select", { className: "event-filter", value: eventFilter, onChange: event => setEventFilter(event.target.value), children: [_jsx("option", { value: "all", children: "All events" }), _jsx("option", { value: "steps", children: "Step events" }), _jsx("option", { value: "parallel", children: "Parallel groups" }), _jsx("option", { value: "lifecycle", children: "Lifecycle" }), _jsx("option", { value: "failures", children: "Failures" })] })] }), _jsx("table", { children: _jsx("tbody", { children: visibleEvents.map(event => _jsxs("tr", { className: "event-row", children: [_jsx("td", { children: new Date(event.timestamp).toLocaleTimeString() }), _jsx("td", { children: event.state.toUpperCase() }), _jsx("td", { children: _jsx("code", { children: event.type.toUpperCase() }) }), _jsxs("td", { children: [event.message, event.parallel && _jsxs("small", { className: "parallel-event", children: [" \u00B7 Parallel ", event.parallel.completed, "/", event.parallel.total, " (", event.parallel.join, ")"] })] })] }, event.sequence)) }) }), events.length > 0 && visibleEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No events match the current filter." })] }), _jsx(HistoryPanel, { entries: runHistory, onReload: reloadHistoryEntry, retention: historyRetention, onRetentionChange: changeHistoryRetention, onClear: clearHistory, onDelete: deleteHistoryEntry, onExport: exportResult })] }), _jsxs("aside", { className: "inspector", children: [_jsx("h2", { children: "Selected execution" }), _jsx("p", { className: "selected-detail-name", children: _jsx("strong", { children: displaySteps[selectedStep]?.name ?? 'No step selected' }) }), _jsxs("p", { className: "run-id", children: ["Run ID: ", requestId ?? 'No run started'] }), _jsx(InspectorSection, { title: "Artifact summary", children: _jsx(KeyValues, { values: ["Target", executionPackage.target.name, "Type", executionPackage.target.kind, "Package", executionPackage.packageId, "Artifact schema", String(executionPackage.schemaVersion), "Definitions", String(executionPackage.definitions.length), "Required inputs", (executionPackage.requiredInputs ?? []).join(", ") || "None", "Runtime values", (executionPackage.runtimeRequirements ?? []).join(", ") || "None"] }) }), _jsx(InspectorSection, { title: "Run outcome", children: _jsxs("div", { className: "notice", children: [_jsx("strong", { children: result?.terminalReason?.toUpperCase() ?? 'NOT STARTED' }), _jsx("br", {}), result ? `${result.environment} · ${result.state}` : 'Run the package to inspect its terminal outcome.'] }) }), _jsx(InspectorSection, { title: "Selected step inputs", children: _jsx(KeyValues, { values: Object.entries(displayResults[selectedStep]?.inputs ?? inputs).flatMap(([key, value]) => [key, String(value)]) }) }), _jsx(InspectorSection, { title: "Selected step outputs", children: _jsx(KeyValues, { values: displayResults[selectedStep]?.outputs ? Object.entries(displayResults[selectedStep]?.outputs ?? {}).flatMap(([key, value]) => [key, String(value)]) : ['—', 'Available after execution'] }) }), (result?.error || displayResults[selectedStep]?.error) && _jsx(InspectorSection, { title: "Error", children: _jsxs("div", { className: "error-notice", children: [_jsx("strong", { children: displayResults[selectedStep]?.error?.code ?? result?.error?.code }), _jsx("br", {}), displayResults[selectedStep]?.error?.message ?? result?.error?.message] }) }), result?.issues !== undefined && _jsx(InspectorSection, { title: "Pre-run validation", children: _jsx(PreRunValidation, { issues: result.issues }) }), _jsx(InspectorSection, { title: "Invocation path", children: _jsx("div", { className: "notice", children: displayResults[selectedStep]?.invocationPath?.join(" › ") ?? "No invocation path available." }) }), _jsx(InspectorSection, { title: "Iteration history", children: _jsx(IterationHistory, { result: displayResults[selectedStep] }) }), _jsx(InspectorSection, { title: "Execution timing", children: _jsxs("div", { className: "timing-details", children: [_jsxs("span", { children: ["Wall ", result?.executionTiming?.wallDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Active ", result?.executionTiming?.activeDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Paused ", result?.executionTiming?.pausedDurationMs ?? "—", " ms"] })] }) }), _jsx(InspectorSection, { title: "Selected step attempts", children: _jsx("div", { className: "attempt-history", children: displayResults[selectedStep]?.attempts?.map(attempt => _jsxs("div", { className: "iteration-entry", children: [_jsxs("strong", { children: ["Attempt ", attempt.attempt] }), _jsxs("span", { children: [attempt.kind.toUpperCase(), " \u00B7 ", attempt.state.toUpperCase(), " \u00B7 ", attempt.durationMs, " ms"] })] }, `${attempt.attempt}-${attempt.kind}`)) ?? _jsx("div", { className: "notice", children: "No retry attempts recorded." }) }) }), _jsxs(InspectorSection, { title: "Selected step", children: [_jsxs("div", { className: "notice", children: [_jsx("strong", { children: displaySteps[selectedStep]?.name ?? 'No step selected' }), _jsx("br", {}), displayResults[selectedStep] ? displayResults[selectedStep].error ? 'This step failed. See the error details above.' : `Completed in ${displayResults[selectedStep].durationMs} ms.` : 'Run the package to inspect execution details.', _jsxs("div", { className: "inspector-actions", children: [_jsx("button", { className: "button", onClick: () => void retrySelected(), disabled: !displayResults[selectedStep] || (!displayResults[selectedStep]?.error && runState !== "completed"), children: "Retry Action" }), _jsx("button", { className: `button ${stopAfterStepId === displaySteps[selectedStep]?.id ? "active" : ""}`, onClick: () => displaySteps[selectedStep] && toggleStopAfter(displaySteps[selectedStep].id), disabled: !displaySteps[selectedStep], children: "Stop After" }), _jsx("button", { className: "button", onClick: () => void runFromSelected(), disabled: !displayResults[selectedStep] || runState === "running", children: "Run From Here" })] })] }), _jsxs("div", { className: "selection-nav", children: [_jsx("button", { className: "button", disabled: selectedStep <= 0, onClick: () => setSelectedStep(index => Math.max(0, index - 1)), children: "\u2039 Previous" }), _jsx("span", { children: displaySteps.length ? `${selectedStep + 1} / ${displaySteps.length}` : '0 / 0' }), _jsx("button", { className: "button", disabled: selectedStep >= displaySteps.length - 1, onClick: () => setSelectedStep(index => Math.min(displaySteps.length - 1, index + 1)), children: "Next \u203A" })] })] })] })] }), showAbout && _jsx("div", { className: "about-backdrop", onClick: () => setShowAbout(false), children: _jsxs("section", { className: "about-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "about-title", onClick: event => event.stopPropagation(), children: [_jsx("button", { className: "about-close", onClick: () => setShowAbout(false), "aria-label": "Close About", children: "\u00D7" }), _jsx("div", { className: "runner-logo", children: "\u25B6" }), _jsx("h2", { id: "about-title", children: "QAick Runner" }), _jsx("p", { children: "Standalone execution and evidence viewer for QAick packages." }), _jsxs("small", { children: ["Alpha 11 \u00B7 ", RUNNER_BUILD_LABEL, " \u00B7 QAick contract"] }), _jsx("footer", { children: "\u00A9 2006\u20132026 QAick. All rights reserved." })] }) })] });
224
+ } }, onClick: () => setSelectedStep(index), onContextMenu: event => { event.preventDefault(); setSelectedStep(index); setContextMenu({ x: event.clientX, y: event.clientY, stepId: step.id }); }, children: [_jsx("td", { children: index + 1 }), _jsxs("td", { children: [_jsx("span", { className: `step-icon ${isLoop ? 'loop-icon' : displayState}`, children: isLoop ? '↻' : displayState === 'finished' ? '✓' : displayState === 'waiting' ? '◷' : displayState === 'skipped' ? '–' : '' }), _jsxs("span", { className: "hierarchy-name", style: { paddingLeft: `${step.depth * 18}px` }, children: [step.depth > 0 && _jsx("span", { className: "branch-marker", children: "\u2514" }), step.hasChildren && _jsx("button", { className: "collapse-toggle", "aria-label": `${collapsedSteps.has(step.id) ? 'Expand' : 'Collapse'} ${step.name}`, onClick: event => { event.stopPropagation(); toggleStep(step.id); }, children: collapsedSteps.has(step.id) ? '+' : '−' }), _jsx("span", { children: step.name }), breakpoints.has(step.id) && _jsx("small", { className: "breakpoint-marker", "aria-label": "Breakpoint armed", title: "Breakpoint armed", children: "STOP" }), isLoop && _jsx("small", { className: "kind-label loop-label", children: "LOOP" }), step.depth > 0 ? _jsx("small", { className: "kind-label nested-label", children: "NESTED STEP" }) : !isLoop && _jsx("small", { className: "kind-label", children: step.kind.toUpperCase() })] }), selectedStep === index && _jsx("small", { className: "selected-label", children: "SELECTED" })] }), _jsxs("td", { children: [progress && _jsxs("div", { className: "loop-progress", children: [_jsxs("strong", { children: ["REPEAT LOOP \u00B7 ITERATION ", progress.current, " OF ", progress.total] }), _jsx("span", { className: "loop-bar", children: _jsx("i", { style: { width: `${percent}%` } }) }), _jsx("small", { children: elapsed ? `Elapsed ${elapsed}` : 'Waiting to start' })] }), _jsx("span", { className: `status ${displayState}`, children: isLoop ? 'LOOP' : displayState.toUpperCase() })] }), _jsx("td", { children: displayResults[index] ? new Date(result?.finishedAt ?? '').toLocaleTimeString() : '—' }), _jsx("td", { children: displayResults[index] ? `${displayResults[index].durationMs} ms` : '—' })] }, `${step.id}-${index}`); }) })] }), contextMenu && _jsxs("div", { className: "runner-context-menu", style: { left: contextMenu.x, top: contextMenu.y }, onClick: event => event.stopPropagation(), onContextMenu: event => event.preventDefault(), children: [_jsx("strong", { children: "Breakpoint" }), breakpoints.has(contextMenu.stepId) ? _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Remove breakpoint" }) : _jsx("button", { onClick: () => { toggleBreakpoint(contextMenu.stepId); setContextMenu(undefined); }, children: "Add breakpoint" })] })] }), _jsxs("section", { className: "panel event-panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Event Log" }), _jsx("span", { className: "panel-spacer" }), _jsx("input", { className: "event-search", "aria-label": "Search event log", placeholder: "Search events", value: eventSearch, onChange: event => setEventSearch(event.target.value) }), _jsxs("select", { className: "event-filter", value: eventFilter, onChange: event => setEventFilter(event.target.value), children: [_jsx("option", { value: "all", children: "All events" }), _jsx("option", { value: "steps", children: "Step events" }), _jsx("option", { value: "parallel", children: "Parallel groups" }), _jsx("option", { value: "lifecycle", children: "Lifecycle" }), _jsx("option", { value: "failures", children: "Failures" })] })] }), _jsx("table", { children: _jsx("tbody", { children: visibleEvents.map(event => _jsxs("tr", { className: "event-row", children: [_jsx("td", { children: new Date(event.timestamp).toLocaleTimeString() }), _jsx("td", { children: event.state.toUpperCase() }), _jsx("td", { children: _jsx("code", { children: event.type.toUpperCase() }) }), _jsxs("td", { children: [event.message, event.parallel && _jsxs("small", { className: "parallel-event", children: [" \u00B7 Parallel ", event.parallel.completed, "/", event.parallel.total, " (", event.parallel.join, ")"] })] })] }, event.sequence)) }) }), events.length > 0 && visibleEvents.length === 0 && _jsx("p", { className: "empty-state", children: "No events match the current filter." })] }), _jsx(HistoryPanel, { entries: runHistory, onReload: reloadHistoryEntry, retention: historyRetention, onRetentionChange: changeHistoryRetention, onClear: clearHistory, onDelete: deleteHistoryEntry, onExport: exportResult })] }), _jsxs("aside", { className: "inspector", children: [_jsx("h2", { children: "Selected execution" }), _jsx("p", { className: "selected-detail-name", children: _jsx("strong", { children: displaySteps[selectedStep]?.name ?? 'No step selected' }) }), _jsxs("p", { className: "run-id", children: ["Run ID: ", requestId ?? 'No run started'] }), _jsx(InspectorSection, { title: "Artifact summary", children: _jsx(KeyValues, { values: ["Target", executionPackage.target.name, "Type", executionPackage.target.kind, "Package", executionPackage.packageId, "Artifact schema", String(executionPackage.schemaVersion), "Definitions", String(executionPackage.definitions.length), "Required inputs", (executionPackage.requiredInputs ?? []).join(", ") || "None", "Runtime values", (executionPackage.runtimeRequirements ?? []).join(", ") || "None"] }) }), _jsx(InspectorSection, { title: "Run outcome", children: _jsxs("div", { className: "notice", children: [_jsx("strong", { children: result?.terminalReason?.toUpperCase() ?? 'NOT STARTED' }), _jsx("br", {}), result ? `${result.environment} · ${result.state}` : 'Run the package to inspect its terminal outcome.'] }) }), _jsx(InspectorSection, { title: "Selected step inputs", children: _jsx(KeyValues, { values: Object.entries(displayResults[selectedStep]?.inputs ?? inputs).flatMap(([key, value]) => [key, String(value)]) }) }), _jsx(InspectorSection, { title: "Selected step outputs", children: _jsx(KeyValues, { values: displayResults[selectedStep]?.outputs ? Object.entries(displayResults[selectedStep]?.outputs ?? {}).flatMap(([key, value]) => [key, String(value)]) : ['—', 'Available after execution'] }) }), (result?.error || displayResults[selectedStep]?.error) && _jsx(InspectorSection, { title: "Error", children: _jsxs("div", { className: "error-notice", children: [_jsx("strong", { children: displayResults[selectedStep]?.error?.code ?? result?.error?.code }), _jsx("br", {}), displayResults[selectedStep]?.error?.message ?? result?.error?.message] }) }), result?.issues !== undefined && _jsx(InspectorSection, { title: "Pre-run validation", children: _jsx(PreRunValidation, { issues: result.issues }) }), _jsx(InspectorSection, { title: "Invocation path", children: _jsx("div", { className: "notice", children: displayResults[selectedStep]?.invocationPath?.join(" › ") ?? "No invocation path available." }) }), _jsx(InspectorSection, { title: "Iteration history", children: _jsx(IterationHistory, { result: displayResults[selectedStep] }) }), _jsx(InspectorSection, { title: "Execution timing", children: _jsxs("div", { className: "timing-details", children: [_jsxs("span", { children: ["Wall ", result?.executionTiming?.wallDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Active ", result?.executionTiming?.activeDurationMs ?? "—", " ms"] }), _jsxs("span", { children: ["Paused ", result?.executionTiming?.pausedDurationMs ?? "—", " ms"] })] }) }), _jsx(InspectorSection, { title: "Selected step attempts", children: _jsx("div", { className: "attempt-history", children: displayResults[selectedStep]?.attempts?.map(attempt => _jsxs("div", { className: "iteration-entry", children: [_jsxs("strong", { children: ["Attempt ", attempt.attempt] }), _jsxs("span", { children: [attempt.kind.toUpperCase(), " \u00B7 ", attempt.state.toUpperCase(), " \u00B7 ", attempt.durationMs, " ms"] })] }, `${attempt.attempt}-${attempt.kind}`)) ?? _jsx("div", { className: "notice", children: "No retry attempts recorded." }) }) }), _jsxs(InspectorSection, { title: "Selected step", children: [_jsxs("div", { className: "notice", children: [_jsx("strong", { children: displaySteps[selectedStep]?.name ?? 'No step selected' }), _jsx("br", {}), displayResults[selectedStep] ? displayResults[selectedStep].error ? 'This step failed. See the error details above.' : `Completed in ${displayResults[selectedStep].durationMs} ms.` : 'Run the package to inspect execution details.', _jsxs("div", { className: "inspector-actions", children: [_jsx("button", { className: "button", onClick: () => void retrySelected(), disabled: !displayResults[selectedStep] || (!displayResults[selectedStep]?.error && runState !== "completed"), children: "Retry Action" }), _jsx("button", { className: `button ${stopAfterStepId === displaySteps[selectedStep]?.id ? "active" : ""}`, onClick: () => displaySteps[selectedStep] && toggleStopAfter(displaySteps[selectedStep].id), disabled: !displaySteps[selectedStep], children: "Stop After" }), _jsx("button", { className: "button", onClick: () => void runFromSelected(), disabled: !displayResults[selectedStep] || runState === "running", children: "Run From Here" })] })] }), _jsxs("div", { className: "selection-nav", children: [_jsx("button", { className: "button", disabled: selectedStep <= 0, onClick: () => setSelectedStep(index => Math.max(0, index - 1)), children: "\u2039 Previous" }), _jsx("span", { children: displaySteps.length ? `${selectedStep + 1} / ${displaySteps.length}` : '0 / 0' }), _jsx("button", { className: "button", disabled: selectedStep >= displaySteps.length - 1, onClick: () => setSelectedStep(index => Math.min(displaySteps.length - 1, index + 1)), children: "Next \u203A" })] })] })] })] }), showAbout && _jsx("div", { className: "about-backdrop", onClick: () => setShowAbout(false), children: _jsxs("section", { className: "about-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "about-title", onClick: event => event.stopPropagation(), children: [_jsx("button", { className: "about-close", onClick: () => setShowAbout(false), "aria-label": "Close About", children: "\u00D7" }), _jsx("div", { className: "runner-logo", children: "\u25B6" }), _jsx("h2", { id: "about-title", children: "QAick Runner" }), _jsx("p", { children: "Standalone execution and evidence viewer for QAick packages." }), _jsxs("small", { children: ["Alpha 12 \u00B7 ", RUNNER_BUILD_LABEL, " \u00B7 QAick contract"] }), _jsx("footer", { children: "\u00A9 2006\u20132026 QAick. All rights reserved." })] }) })] });
225
225
  }
226
226
  function NavItem({ icon, text, active = false }) { const scrollTarget = text === 'Run History' ? '.history-panel' : text === 'Flows' ? '.runner-workspace table' : '.runner-workspace'; return _jsxs("a", { className: `nav-item ${active ? 'active' : ''}`, href: `#${text.toLowerCase().replaceAll(' ', '-')}`, onClick: event => { event.preventDefault(); document.querySelector(scrollTarget)?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }, children: [_jsx("span", { children: icon }), text] }); }
227
227
  function HistoryPanel({ entries, retention, onRetentionChange, onClear, onDelete, onExport, onReload }) { return _jsxs("section", { className: "panel history-panel", children: [_jsxs("div", { className: "panel-heading", children: [_jsx("h2", { children: "Run History" }), _jsx("span", { className: "panel-spacer" }), _jsxs("label", { className: "history-retention", children: ["Keep", _jsxs("select", { "aria-label": "Run history retention", value: retention, onChange: event => onRetentionChange(Number(event.target.value)), children: [_jsx("option", { value: "10", children: "10 runs" }), _jsx("option", { value: "20", children: "20 runs" }), _jsx("option", { value: "50", children: "50 runs" }), _jsx("option", { value: "100", children: "100 runs" })] })] }), _jsx("button", { className: "button", onClick: onClear, disabled: !entries.length, children: "Clear history" })] }), entries.length ? _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Target" }), _jsx("th", { children: "Started" }), _jsx("th", { children: "State" }), _jsx("th", { children: "Duration" }), _jsx("th", { children: "Result" })] }) }), _jsx("tbody", { children: entries.map(entry => _jsxs("tr", { children: [_jsxs("td", { children: [entry.target, _jsxs("small", { className: "history-meta", children: [entry.result.provenance ? 'Run From Here' : entry.result.steps.some(step => step.attempts?.some(attempt => attempt.kind === 'interactive')) ? 'Interactive retry' : 'Normal run', " \u00B7 ", entry.packageId ?? 'legacy result', " \u00B7 schema ", entry.artifactSchemaVersion ?? '—', _jsx("br", {}), "hash ", entry.result.artifactHash ?? 'legacy result'] })] }), _jsx("td", { children: new Date(entry.startedAt).toLocaleString() }), _jsx("td", { children: _jsx("span", { className: `status ${entry.state}`, children: entry.state.toUpperCase() }) }), _jsxs("td", { children: [entry.durationMs, " ms"] }), _jsxs("td", { children: [_jsx("button", { className: "button", onClick: () => onReload(entry), children: "View results" }), _jsx("button", { className: "button", onClick: () => onExport(entry.result, entry.packageId, entry.artifactSchemaVersion), children: "Export JSON" }), _jsx("button", { className: "button history-delete", onClick: () => onDelete(entry.requestId), children: "Delete" })] })] }, entry.requestId)) })] }) : _jsx("p", { className: "empty-state", children: "Completed and failed runs will be kept here in this browser." })] }); }
@@ -1,4 +1,4 @@
1
- import { loadExecutionPackage } from './package-loader';
1
+ import { loadExecutionPackage } from './package-loader.js';
2
2
  export class PackageCatalog {
3
3
  packages = new Map();
4
4
  add(serialized) {
@@ -1,4 +1,4 @@
1
- import nestedSerializedFixture from '../../fixtures/checkout-nested.qaick.json';
1
+ import nestedSerializedFixture from '../../fixtures/checkout-nested.qaick.json' with { type: 'json' };
2
2
  export const checkoutPackage = {
3
3
  schemaVersion: 6, packageId: 'checkout-regression',
4
4
  target: { kind: 'flow', id: 'customer-checkout', name: 'Customer Checkout' },
@@ -1,4 +1,4 @@
1
- import { redactExecutionResult } from './redaction';
1
+ import { redactExecutionResult } from './redaction.js';
2
2
  export function persistRunHistory(storage, key, entries, retention, secretValues = []) {
3
3
  const next = entries.slice(0, retention).map(entry => ({ ...entry, result: redactExecutionResult(entry.result, secretValues) }));
4
4
  storage.setItem(key, JSON.stringify(next));
@@ -1,8 +1,8 @@
1
- import { RUNNER_PACKAGE_SCHEMA_VERSION, STUDIO_ARTIFACT_SCHEMA_VERSION } from './types';
1
+ import { RUNNER_PACKAGE_SCHEMA_VERSION, STUDIO_ARTIFACT_SCHEMA_VERSION } from './types.js';
2
2
  import { validateArtifact } from '@qaick/contract';
3
- import { loadStudioFlowArtifact, loadStudioProjectFile } from './studio-artifact-loader';
4
- import { PackageLoadError } from './package-load-error';
5
- export { PackageLoadError } from './package-load-error';
3
+ import { loadStudioFlowArtifact, loadStudioProjectFile } from './studio-artifact-loader.js';
4
+ import { PackageLoadError } from './package-load-error.js';
5
+ export { PackageLoadError } from './package-load-error.js';
6
6
  export function loadExecutionPackage(serialized) {
7
7
  let candidate;
8
8
  try {
@@ -1,4 +1,4 @@
1
- import { redactExecutionResult } from './redaction';
1
+ import { redactExecutionResult } from './redaction.js';
2
2
  export function createResultExport(value, packageId, schemaVersion, secretValues = []) {
3
3
  return {
4
4
  runnerResultVersion: 1,
@@ -1,6 +1,6 @@
1
- import { RUNNER_PACKAGE_SCHEMA_VERSION, STUDIO_ARTIFACT_SCHEMA_VERSION } from './types';
1
+ import { RUNNER_PACKAGE_SCHEMA_VERSION, STUDIO_ARTIFACT_SCHEMA_VERSION } from './types.js';
2
2
  import { isApiResponseField } from '@qaick/contract';
3
- import { PackageLoadError } from './package-load-error';
3
+ import { PackageLoadError } from './package-load-error.js';
4
4
  /** Converts the Studio schema 7 Flow envelope into Runner's execution port. */
5
5
  export function loadStudioFlowArtifact(candidate) {
6
6
  if (candidate.artifactKind !== 'flow' || candidate.schemaVersion !== 7 || !isRecord(candidate.flow)) {
@@ -1,39 +1,39 @@
1
- :root { font-family: Inter, ui-sans-serif, system-ui, sans-serif; color: #182234; background: #f7f9fc; font-size: 13px; color-scheme: light; }
1
+ :root { font-family: Inter, ui-sans-serif, system-ui, sans-serif; color: #182234; background: #f7f8fc; font-size: 13px; color-scheme: light; }
2
2
  :root[data-theme='dark'] { color: #e6edf7; background: #111827; color-scheme: dark; }
3
3
  * { box-sizing: border-box; } body { margin: 0; min-width: 1120px; } button, select { font: inherit; }
4
- .runner-shell { height: 100vh; min-height: 100vh; display: grid; grid-template-rows: 44px minmax(0, 1fr); } .runner-header { display: flex; align-items: center; gap: 18px; padding: 0 12px 0 16px; border-bottom: 1px solid #dfe4ec; background: #fff; font-size: 13px; }
5
- .runner-brand { display: flex; align-items: baseline; gap: 6px; flex: none; } .runner-brand-mark { color: #3569d4; font-size: 13px; font-weight: 700; letter-spacing: .04em; } .runner-brand-product { color: #182234; font-size: 13px; font-weight: 500; } .runner-brand .about-button { height: 25px; margin-left: 6px; padding: 0 9px; border: 0; border-radius: 4px; background: transparent; color: #40516c; font-size: 12px; font-weight: 650; } .runner-brand .about-button:hover { background: #f0f3f8; color: #182234; } .runner-logo { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 8px; color: white; background: #3569d4; font-size: 13px; } .alpha-label { color: #70809a; font-size: 13px; } .header-spacer, .panel-spacer { flex: 1; }
4
+ .runner-shell { height: 100vh; min-height: 100vh; display: grid; grid-template-rows: 44px minmax(0, 1fr); } .runner-header { display: flex; align-items: center; gap: 18px; padding: 0 12px 0 16px; border-bottom: 1px solid #cbd1d8; background: #fff; font-size: 13px; }
5
+ .runner-brand { display: flex; align-items: baseline; gap: 6px; flex: none; } .runner-brand-mark { color: #4f46d8; font-size: 13px; font-weight: 700; letter-spacing: .04em; } .runner-brand-product { color: #182234; font-size: 13px; font-weight: 500; } .runner-brand .about-button { height: 25px; margin-left: 6px; padding: 0 9px; border: 0; border-radius: 4px; background: transparent; color: #34435b; font-size: 12px; font-weight: 650; } .runner-brand .about-button:hover { background: #f0f3f8; color: #182234; } .runner-logo { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 8px; color: white; background: #4f46d8; font-size: 13px; } .alpha-label { color: #70809a; font-size: 13px; } .header-spacer, .panel-spacer { flex: 1; }
6
6
  .engine-status { display: flex; align-items: center; gap: 7px; color: #14804a; font-size: 12px; font-weight: 700; } .engine-status i { width: 8px; height: 8px; border-radius: 50%; background: #19a463; }
7
- .theme-picker { display: flex; align-items: center; gap: 7px; color: #596a82; font-size: 12px; font-weight: 700; } .theme-picker select { min-width: 82px; height: 30px; padding: 0 8px; border: 1px solid #cdd7e5; border-radius: 6px; background: white; color: #182234; }
8
- .runner-main { display: grid; grid-template-columns: 218px minmax(560px, 1fr) 350px; min-height: 0; overflow: hidden; } .runner-nav, .inspector { min-height: 0; overflow-y: auto; background: #fff; } .runner-nav { padding: 18px 12px; border-right: 1px solid #dfe4ec; }
7
+ .theme-picker { display: flex; align-items: center; gap: 7px; color: #617089; font-size: 12px; font-weight: 700; } .theme-picker select { min-width: 82px; height: 30px; padding: 0 8px; border: 1px solid #cfd5dd; border-radius: 6px; background: white; color: #182234; }
8
+ .runner-main { display: grid; grid-template-columns: 218px minmax(560px, 1fr) 350px; min-height: 0; overflow: hidden; } .runner-nav, .inspector { min-height: 0; overflow-y: auto; background: #fff; } .runner-nav { padding: 18px 12px; border-right: 1px solid #cbd1d8; }
9
9
  .nav-label, .eyebrow { color: #8794a8; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; } .nav-label { margin: 4px 12px 10px; }
10
- .nav-item { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border-radius: 7px; color: #40516c; font-size: 14px; text-decoration: none; cursor: pointer; } .nav-item span { width: 20px; text-align: center; } .nav-item.active { color: #2458c4; background: #e9f0ff; font-weight: 700; }
11
- .package-card { margin: 24px 8px 0; padding: 12px; border: 1px solid #dce4f0; border-radius: 8px; background: #f8faff; } .package-card small { display: block; color: #77869b; } .package-card strong { display: block; margin: 5px 0; font-size: 12px; overflow-wrap: anywhere; }
12
- .runner-workspace { min-height: 0; overflow-y: auto; padding: 26px 30px; background: #f7f9fc; } .eyebrow { color: #687a95; } h1 { margin: 5px 0 4px; font-size: 25px; letter-spacing: -.02em; } .description { margin: 0; color: #66758c; }
13
- .run-controls { display: flex; align-items: end; flex-wrap: wrap; gap: 10px 14px; margin-top: 25px; } label { display: grid; gap: 6px; color: #596a82; font-size: 12px; font-weight: 700; } select { min-width: 145px; height: 36px; padding: 0 10px; border: 1px solid #cdd7e5; border-radius: 6px; background: white; color: #182234; }
14
- .button { height: 36px; padding: 0 15px; border: 1px solid #cdd7e5; border-radius: 6px; background: white; color: #334560; font-weight: 700; cursor: pointer; } .button.primary { border-color: #3569d4; background: #3569d4; color: white; } .button.dry-run { border-color: #8a9fc4; color: #315da9; background: #eef3fc; } .button.stop { color: #b33a30; }
15
- .file-button { position: relative; display: inline-grid; height: 36px; padding: 0 15px; place-items: center; border: 1px solid #cdd7e5; border-radius: 6px; background: white; color: #334560; cursor: pointer; } .file-button input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; } .load-error { margin: 12px 0 -8px; color: #b33a30; font-size: 12px; font-weight: 700; }
16
- .inputs-panel { margin-top: 18px; } .input-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; padding: 16px; } .input-field { color: #596a82; } .input-field input { width: 100%; height: 34px; padding: 0 9px; border: 1px solid #cdd7e5; border-radius: 6px; color: #182234; background: #fff; font: inherit; font-weight: 500; } .input-hint { color: #7a899d; font-size: 11px; }
10
+ .nav-item { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border-radius: 7px; color: #34435b; font-size: 14px; text-decoration: none; cursor: pointer; } .nav-item span { width: 20px; text-align: center; } .nav-item.active { color: #3f37b8; background: #e8eeff; font-weight: 700; }
11
+ .package-card { margin: 24px 8px 0; padding: 12px; border: 1px solid #e5e7eb; border-radius: 8px; background: #f8faff; } .package-card small { display: block; color: #77869b; } .package-card strong { display: block; margin: 5px 0; font-size: 12px; overflow-wrap: anywhere; }
12
+ .runner-workspace { min-height: 0; overflow-y: auto; padding: 26px 30px; background: #f7f8fc; } .eyebrow { color: #7c8aa0; } h1 { margin: 5px 0 4px; font-size: 25px; letter-spacing: -.02em; } .description { margin: 0; color: #617089; }
13
+ .run-controls { display: flex; align-items: end; flex-wrap: wrap; gap: 10px 14px; margin-top: 25px; } label { display: grid; gap: 6px; color: #617089; font-size: 12px; font-weight: 700; } select { min-width: 145px; height: 36px; padding: 0 10px; border: 1px solid #cfd5dd; border-radius: 6px; background: white; color: #182234; }
14
+ .button { height: 36px; padding: 0 15px; border: 1px solid #cfd5dd; border-radius: 6px; background: white; color: #334560; font-weight: 700; cursor: pointer; } .button.primary { border-color: #4f46d8; background: #4f46d8; color: white; } .button.dry-run { border-color: #8a9fc4; color: #315da9; background: #eef3fc; } .button.stop { color: #b33a30; }
15
+ .file-button { position: relative; display: inline-grid; height: 36px; padding: 0 15px; place-items: center; border: 1px solid #cfd5dd; border-radius: 6px; background: white; color: #334560; cursor: pointer; } .file-button input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; } .load-error { margin: 12px 0 -8px; color: #b33a30; font-size: 12px; font-weight: 700; }
16
+ .inputs-panel { margin-top: 18px; } .input-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; padding: 16px; } .input-field { color: #617089; } .input-field input { width: 100%; height: 34px; padding: 0 9px; border: 1px solid #cfd5dd; border-radius: 6px; color: #182234; background: #fff; font: inherit; font-weight: 500; } .input-hint { color: #7a899d; font-size: 11px; }
17
17
  .history-view-banner { margin-top: 12px; padding: 9px 12px; border: 1px solid #b9cbed; border-radius: 6px; color: #315da9; background: #eaf2ff; font-size: 12px; font-weight: 700; }
18
- .panel { margin-top: 24px; border: 1px solid #dce4ed; border-radius: 8px; background: white; overflow: hidden; } .panel-heading { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid #e6ebf2; } h2 { margin: 0; font-size: 16px; } .running { color: #14804a; font-size: 12px; font-weight: 750; } .stopped { color: #b33a30; font-size: 12px; font-weight: 750; }
19
- table { width: 100%; border-collapse: collapse; font-size: 13px; } th { padding: 10px 14px; color: #7b899d; background: #fafbfd; font-size: 11px; text-align: left; text-transform: uppercase; letter-spacing: .04em; } td { padding: 13px 14px; border-top: 1px solid #edf0f5; } tr.parent-row td { background: #fbfdff; } tr.nested-row td { background: #f3f7fd; } tr.selected td { background: #dce8ff !important; border-top-color: #9db9ed; } tr.selected td:first-child { border-left: 4px solid #3569d4; } tr.selected .hierarchy-name { color: #173e91; font-weight: 700; } tbody tr { cursor: pointer; }
20
- .hierarchy-hint { display: flex; align-items: center; gap: 10px; padding: 9px 16px; border-bottom: 1px solid #dbe6fa; color: #315da9; background: #f2f6ff; font-size: 11px; } .hierarchy-hint span { color: #637897; } .hierarchy-action { padding: 4px 7px; border: 1px solid #b9cbed; border-radius: 4px; color: #315da9; background: #fff; font-size: 10px; font-weight: 700; cursor: pointer; } .hierarchy-action:first-of-type { margin-left: auto; } .hierarchy-name { display: inline-flex; align-items: center; gap: 7px; min-height: 22px; } .collapse-toggle { display: inline-grid; width: 18px; height: 18px; place-items: center; padding: 0; border: 1px solid #9eb5df; border-radius: 4px; color: #315da9; background: #eaf1ff; font-size: 14px; line-height: 1; cursor: pointer; } .branch-marker { color: #5d82ca; font-size: 18px; font-weight: 400; } .kind-label { display: inline-flex; padding: 3px 5px; border-radius: 4px; color: #6c7890; background: #edf1f7; font-size: 9px; font-weight: 800; letter-spacing: .05em; } .nested-label { color: #315da9; background: #e5efff; } .nested-row td:first-child { border-left: 3px solid #8eaded; } .parent-row td:first-child { border-left: 3px solid transparent; }
18
+ .panel { margin-top: 24px; border: 1px solid #e5e7eb; border-radius: 8px; background: white; overflow: hidden; } .panel-heading { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid #e5e7eb; } h2 { margin: 0; font-size: 16px; } .running { color: #14804a; font-size: 12px; font-weight: 750; } .stopped { color: #b33a30; font-size: 12px; font-weight: 750; }
19
+ table { width: 100%; border-collapse: collapse; font-size: 13px; } th { padding: 10px 14px; color: #7b899d; background: #fafbfd; font-size: 11px; text-align: left; text-transform: uppercase; letter-spacing: .04em; } td { padding: 13px 14px; border-top: 1px solid #edf0f7; } tr.parent-row td { background: #ffffff; } tr.nested-row td { background: #f3f7fd; } tr.selected td { background: #dce8ff !important; border-top-color: #9db9ed; } tr.selected td:first-child { border-left: 4px solid #4f46d8; } tr.selected .hierarchy-name { color: #173e91; font-weight: 700; } tbody tr { cursor: pointer; }
20
+ .hierarchy-hint { display: flex; align-items: center; gap: 10px; padding: 9px 16px; border-bottom: 1px solid #dbe6fa; color: #315da9; background: #f2f6ff; font-size: 11px; } .hierarchy-hint span { color: #637897; } .hierarchy-action { padding: 4px 7px; border: 1px solid #b9cbed; border-radius: 4px; color: #315da9; background: #fff; font-size: 10px; font-weight: 700; cursor: pointer; } .hierarchy-action:first-of-type { margin-left: auto; } .hierarchy-name { display: inline-flex; align-items: center; gap: 7px; min-height: 22px; } .collapse-toggle { display: inline-grid; width: 18px; height: 18px; place-items: center; padding: 0; border: 1px solid #9eb5df; border-radius: 4px; color: #315da9; background: #eaf1ff; font-size: 14px; line-height: 1; cursor: pointer; } .branch-marker { color: #5d82ca; font-size: 18px; font-weight: 400; } .kind-label { display: inline-flex; padding: 3px 5px; border-radius: 4px; color: #6c7890; background: #edf0f7; font-size: 9px; font-weight: 800; letter-spacing: .05em; } .nested-label { color: #315da9; background: #e5efff; } .nested-row td:first-child { border-left: 3px solid #8eaded; } .parent-row td:first-child { border-left: 3px solid transparent; }
21
21
  .step-icon { display: inline-grid; width: 20px; height: 20px; margin-right: 7px; place-items: center; border-radius: 50%; color: white; background: #18a15d; font-size: 11px; } .nested-row .step-icon { margin-left: 18px; } .nested-row .hierarchy-name { padding-left: 0 !important; } .step-icon.waiting { background: #efaa18; } .step-icon.skipped { color: #62738c; background: #edf1f6; } .step-icon.failed, .step-icon.cancelled { background: #c94b42; } .step-icon.pending { border: 2px solid #aab6c7; background: transparent; }
22
- .selected-label { display: inline-flex; margin-left: 8px; padding: 3px 5px; border-radius: 4px; color: #2458c4; background: #c4d7ff; font-size: 9px; font-weight: 800; letter-spacing: .05em; }
22
+ .selected-label { display: inline-flex; margin-left: 8px; padding: 3px 5px; border-radius: 4px; color: #3f37b8; background: #c4d7ff; font-size: 9px; font-weight: 800; letter-spacing: .05em; }
23
23
  .status { display: inline-flex; padding: 4px 8px; border-radius: 5px; font-size: 10px; font-weight: 800; letter-spacing: .03em; } .status.finished { color: #14804a; background: #e7f6ed; } .status.waiting { color: #98660b; background: #fff2d5; } .status.pending, .status.skipped { color: #62738c; background: #edf1f6; } .status.failed, .status.cancelled { color: #a33a32; background: #ffebe8; }
24
- .loop-row td { background: #f5f8fe; border-top: 1px solid #c8d7f0; border-bottom: 1px solid #dce6f6; } .loop-row td:first-child { border-left: 3px solid #668bd2; border-radius: 9px 0 0 0; } .loop-row td:last-child { border-right: 1px solid #c8d7f0; border-radius: 0 9px 0 0; } .loop-icon { color: #fff; background: #668bd2; font-size: 15px; } .loop-label { color: #315da9; background: #e7efff; } .loop-progress { display: flex; align-items: center; flex-wrap: wrap; gap: 5px 8px; min-width: 220px; margin-bottom: 4px; color: #315da9; font-size: 10px; letter-spacing: .02em; } .loop-progress small { flex-basis: 100%; color: #71839c; font-size: 10px; } .loop-bar { width: 92px; height: 6px; overflow: hidden; border-radius: 99px; background: #dce6f6; } .loop-bar i { display: block; height: 100%; border-radius: inherit; background: #668bd2; transition: width .2s ease; } .loop-content td { border-top: 0; border-bottom: 0; background: #fbfdff; } .loop-content td:first-child { border-left: 3px solid #c8d7f0; } .loop-content td:last-child { border-right: 1px solid #c8d7f0; } .loop-end td { border-bottom: 1px solid #c8d7f0; } .loop-end td:first-child { border-radius: 0 0 0 9px; } .loop-end td:last-child { border-radius: 0 0 9px 0; }
24
+ .loop-row td { background: #f5f8fe; border-top: 1px solid #c8d7f0; border-bottom: 1px solid #dce6f6; } .loop-row td:first-child { border-left: 3px solid #668bd2; border-radius: 9px 0 0 0; } .loop-row td:last-child { border-right: 1px solid #c8d7f0; border-radius: 0 9px 0 0; } .loop-icon { color: #fff; background: #668bd2; font-size: 15px; } .loop-label { color: #315da9; background: #e7efff; } .loop-progress { display: flex; align-items: center; flex-wrap: wrap; gap: 5px 8px; min-width: 220px; margin-bottom: 4px; color: #315da9; font-size: 10px; letter-spacing: .02em; } .loop-progress small { flex-basis: 100%; color: #71839c; font-size: 10px; } .loop-bar { width: 92px; height: 6px; overflow: hidden; border-radius: 99px; background: #dce6f6; } .loop-bar i { display: block; height: 100%; border-radius: inherit; background: #668bd2; transition: width .2s ease; } .loop-content td { border-top: 0; border-bottom: 0; background: #ffffff; } .loop-content td:first-child { border-left: 3px solid #c8d7f0; } .loop-content td:last-child { border-right: 1px solid #c8d7f0; } .loop-end td { border-bottom: 1px solid #c8d7f0; } .loop-end td:first-child { border-radius: 0 0 0 9px; } .loop-end td:last-child { border-radius: 0 0 9px 0; }
25
25
  .event-panel { margin-top: 18px; } .event-row td { padding: 9px 14px; font-size: 12px; } code { color: #294d9c; font-family: ui-monospace, monospace; font-size: 11px; }
26
- .inspector { padding: 22px 18px; border-left: 1px solid #dfe4ec; } .inspector h2 { font-size: 17px; } .selected-detail-name { margin: 6px 0 0; color: #2458c4; font-size: 13px; } .run-id { margin: 5px 0 20px; color: #7a899d; font-family: ui-monospace, monospace; font-size: 10px; } .inspector-section { padding: 17px 0; border-top: 1px solid #e6ebf2; } .inspector-section h3 { margin: 0 0 11px; font-size: 13px; }
26
+ .inspector { padding: 22px 18px; border-left: 1px solid #cbd1d8; } .inspector h2 { font-size: 17px; } .selected-detail-name { margin: 6px 0 0; color: #3f37b8; font-size: 13px; } .run-id { margin: 5px 0 20px; color: #7a899d; font-family: ui-monospace, monospace; font-size: 10px; } .inspector-section { padding: 17px 0; border-top: 1px solid #e5e7eb; } .inspector-section h3 { margin: 0 0 11px; font-size: 13px; }
27
27
  .selection-nav { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; } .selection-nav .button { padding: 5px 8px; font-size: 11px; }
28
- .parallel-event { color: #66758c; font-size: 10px; }
28
+ .parallel-event { color: #617089; font-size: 10px; }
29
29
  .event-filter { min-width: 120px; padding: 6px 8px; font-size: 11px; }
30
30
  .key-values { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid #e0e6ef; border-radius: 6px; overflow: hidden; font-size: 12px; } .key-values span { padding: 9px 10px; border-bottom: 1px solid #e9edf3; } .key-values span:nth-child(odd) { color: #63738a; background: #fafbfd; } .key-values span:nth-last-child(-n+2) { border-bottom: 0; }
31
- .iteration-history { display: grid; gap: 7px; } .iteration-entry { display: grid; gap: 3px; padding: 9px 10px; border: 1px solid #dce4ed; border-radius: 6px; background: #fbfdff; font-size: 11px; } .iteration-entry span { color: #637897; font-size: 10px; } .iteration-entry small { color: #71839c; line-height: 1.35; } .timing-details { display: grid; gap: 4px; margin-top: 8px; padding: 9px 10px; border: 1px solid #dce4ed; border-radius: 6px; color: #637897; background: #fbfdff; font-size: 10px; } .timing-details strong { color: #40516c; font-size: 11px; }
32
- .notice { padding: 12px; border-radius: 6px; color: #59708e; background: #f3f6fa; font-size: 12px; line-height: 1.5; } .draft-badge { position: fixed; right: 18px; bottom: 14px; padding: 7px 10px; border: 1px solid #e5c987; border-radius: 5px; color: #85600e; background: #fff7df; font-size: 11px; font-weight: 750; }
33
- .about-button { height: 30px; padding: 0 10px; border: 1px solid #cdd7e5; border-radius: 6px; background: white; color: #40516c; font-size: 12px; font-weight: 700; cursor: pointer; }
31
+ .iteration-history { display: grid; gap: 7px; } .iteration-entry { display: grid; gap: 3px; padding: 9px 10px; border: 1px solid #e5e7eb; border-radius: 6px; background: #ffffff; font-size: 11px; } .iteration-entry span { color: #637897; font-size: 10px; } .iteration-entry small { color: #71839c; line-height: 1.35; } .timing-details { display: grid; gap: 4px; margin-top: 8px; padding: 9px 10px; border: 1px solid #e5e7eb; border-radius: 6px; color: #637897; background: #ffffff; font-size: 10px; } .timing-details strong { color: #34435b; font-size: 11px; }
32
+ .notice { padding: 12px; border-radius: 6px; color: #59708e; background: #edf0f7; font-size: 12px; line-height: 1.5; } .draft-badge { position: fixed; right: 18px; bottom: 14px; padding: 7px 10px; border: 1px solid #e5c987; border-radius: 5px; color: #85600e; background: #fff7df; font-size: 11px; font-weight: 750; }
33
+ .about-button { height: 30px; padding: 0 10px; border: 1px solid #cfd5dd; border-radius: 6px; background: white; color: #34435b; font-size: 12px; font-weight: 700; cursor: pointer; }
34
34
  .about-backdrop { position: fixed; inset: 0; z-index: 20; display: grid; place-items: center; background: rgb(7 12 24 / 48%); }
35
- .about-dialog { position: relative; width: min(360px, calc(100vw - 40px)); padding: 28px; border: 1px solid #dce4ed; border-radius: 12px; background: white; color: #40516c; box-shadow: 0 20px 60px rgb(0 0 0 / 24%); text-align: center; }
36
- .about-dialog .runner-logo { margin: 0 auto 14px; }.about-dialog h2 { margin: 0 0 8px; color: #182234; }.about-dialog p { margin: 0 0 8px; color: #66758c; line-height: 1.5; }.about-dialog small { color: #8794a8; }.about-dialog footer { margin-top: 24px; color: #7a899d; font-size: 11px; }.about-close { position: absolute; top: 10px; right: 12px; border: 0; background: transparent; color: #7a899d; font-size: 22px; cursor: pointer; }
35
+ .about-dialog { position: relative; width: min(360px, calc(100vw - 40px)); padding: 28px; border: 1px solid #e5e7eb; border-radius: 12px; background: white; color: #34435b; box-shadow: 0 20px 60px rgb(0 0 0 / 24%); text-align: center; }
36
+ .about-dialog .runner-logo { margin: 0 auto 14px; }.about-dialog h2 { margin: 0 0 8px; color: #182234; }.about-dialog p { margin: 0 0 8px; color: #617089; line-height: 1.5; }.about-dialog small { color: #8794a8; }.about-dialog footer { margin-top: 24px; color: #7a899d; font-size: 11px; }.about-close { position: absolute; top: 10px; right: 12px; border: 0; background: transparent; color: #7a899d; font-size: 22px; cursor: pointer; }
37
37
  .error-notice { padding: 12px; border: 1px solid #f0c5c1; border-radius: 6px; color: #9d332b; background: #fff1ef; font-size: 12px; line-height: 1.5; } .dry-run-issues { display: grid; gap: 8px; } .dry-run-issues .error-notice { font-size: 11px; } .dry-run-issues small { display: block; margin-top: 5px; color: inherit; opacity: .8; }
38
38
  .validation-panel { display: flex; gap: 11px; align-items: flex-start; margin-top: 18px; padding: 13px 16px; border: 1px solid; border-radius: 8px; font-size: 12px; } .validation-panel strong { display: block; } .validation-panel small { display: block; margin-top: 3px; color: inherit; opacity: .8; } .validation-pass { border-color: #b9dfca; color: #176d41; background: #effaf3; } .validation-failed { display: grid; gap: 11px; border-color: #edc2bd; color: #963b33; background: #fff5f3; } .validation-heading { display: flex; gap: 11px; align-items: flex-start; } .validation-icon, .issue-icon { display: inline-grid; flex: 0 0 auto; width: 22px; height: 22px; place-items: center; border-radius: 50%; color: white; background: #1b9a5b; font-size: 14px; font-weight: 800; } .validation-failed .validation-icon, .issue-icon { background: #c94b42; } .validation-issues { display: grid; gap: 6px; padding-left: 33px; } .validation-issue { display: flex; gap: 8px; align-items: flex-start; padding: 8px 9px; border: 1px solid #f0d1cd; border-radius: 5px; background: rgba(255,255,255,.55); } .validation-issue .issue-icon { width: 16px; height: 16px; font-size: 12px; } .validation-issue span, .validation-issue small { display: block; } .validation-issue strong { font-size: 10px; letter-spacing: .04em; } .validation-issue span { margin-top: 2px; font-size: 11px; } .validation-issue small { margin-top: 3px; opacity: .75; }
39
39
 
@@ -64,13 +64,13 @@ table { width: 100%; border-collapse: collapse; font-size: 13px; } th { padding:
64
64
  .history-retention select { min-width: 92px; height: 30px; font-size: 11px; }
65
65
  .history-delete { margin-left: 6px; color: #a33a32; }
66
66
  .validation-issue[data-step-id] { cursor: pointer; }
67
- .branch-path { display: grid; gap: 6px; margin-top: 8px; padding: 9px 10px; border: 1px solid #dce4ed; border-radius: 6px; background: #fbfdff; font-size: 11px; }
67
+ .branch-path { display: grid; gap: 6px; margin-top: 8px; padding: 9px 10px; border: 1px solid #e5e7eb; border-radius: 6px; background: #ffffff; font-size: 11px; }
68
68
  .branch-path-row { display: grid; grid-template-columns: auto 1fr auto; gap: 7px; align-items: center; }
69
69
  .branch-path-row small { color: #71839c; font-size: 10px; }
70
70
  .parallel-details { color: #637897; }
71
71
  .parallel-details > span { font-size: 10px; }
72
- .result-summary { display: grid; gap: 4px; margin-top: 8px; padding: 9px 10px; border: 1px solid #dce4ed; border-radius: 6px; color: #637897; background: #fbfdff; font-size: 10px; }
73
- .result-summary strong { color: #40516c; font-size: 11px; }
72
+ .result-summary { display: grid; gap: 4px; margin-top: 8px; padding: 9px 10px; border: 1px solid #e5e7eb; border-radius: 6px; color: #637897; background: #ffffff; font-size: 10px; }
73
+ .result-summary strong { color: #34435b; font-size: 11px; }
74
74
  .demo-entry { padding: 7px 10px; border: 1px solid var(--border); border-radius: 5px; background: var(--panel); color: var(--accent); font-size: 12px; font-weight: 650; text-decoration: none; }
75
75
 
76
76
  .breakpoint-toggle { border: 0; background: transparent; color: var(--muted, #718096); cursor: pointer; margin-left: .4rem; padding: 0 .2rem; }
@@ -87,7 +87,7 @@ table { width: 100%; border-collapse: collapse; font-size: 13px; } th { padding:
87
87
  .runner-context-menu button:hover { background: #edf3ff; color: #173e91; }
88
88
  .breakpoint-marker { display: inline-grid; width: 22px; height: 22px; place-items: center; color: #fff; background: #b93645; clip-path: polygon(30% 0, 70% 0, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0 70%, 0 30%); filter: drop-shadow(0 1px 1px rgba(62, 20, 27, .25)); font-family: Arial, sans-serif; font-size: 4.5px; font-weight: 900; letter-spacing: .06em; line-height: 1; }
89
89
 
90
- .button.resume-highlight { border-color: #3569d4; background: #3569d4; color: #fff; box-shadow: 0 0 0 3px rgba(53, 105, 212, .18); }
90
+ .button.resume-highlight { border-color: #4f46d8; background: #4f46d8; color: #fff; box-shadow: 0 0 0 3px rgba(53, 105, 212, .18); }
91
91
 
92
92
  /* Match Studio's compact toolbar rhythm and quiet menu controls. */
93
93
  .runner-header { border-color: var(--runner-line); background: var(--runner-surface); }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qaick/runner",
3
3
  "description": "Reusable QAick Runner module and standalone execution application.",
4
- "version": "0.2.0-alpha.11",
4
+ "version": "0.2.0-alpha.13",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "package-dist",
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@qaick/contract": "0.2.10",
56
56
  "@qaick/executor": "0.1.0-alpha.1",
57
- "@qaick/http-executor": "0.1.0-alpha.1",
57
+ "@qaick/http-executor": "0.1.0-alpha.2",
58
58
  "@qaick/runtime": "0.1.0-alpha.2",
59
59
  "zustand": "^5.0.15"
60
60
  },
@@ -63,12 +63,12 @@
63
63
  "react-dom": ">=19.0.0"
64
64
  },
65
65
  "devDependencies": {
66
- "@vitejs/plugin-react": "^6.1.1",
67
66
  "@testing-library/dom": "^10.4.2",
68
67
  "@testing-library/react": "^16.3.3",
69
68
  "@types/node": "^24.13.3",
70
69
  "@types/react": "^19.2.18",
71
70
  "@types/react-dom": "^19.2.7",
71
+ "@vitejs/plugin-react": "^6.1.1",
72
72
  "jsdom": "^30.0.1",
73
73
  "oxlint": "^1.81.0",
74
74
  "react": "^19.2.8",