@jterrats/open-orchestra 0.1.0

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.
Files changed (93) hide show
  1. package/AGENTS.md +151 -0
  2. package/CLAUDE.md +157 -0
  3. package/README.md +60 -0
  4. package/bin/orchestra.js +8 -0
  5. package/dist/args.d.ts +3 -0
  6. package/dist/args.js +30 -0
  7. package/dist/args.js.map +1 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +190 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands.d.ts +44 -0
  12. package/dist/commands.js +883 -0
  13. package/dist/commands.js.map +1 -0
  14. package/dist/constants.d.ts +15 -0
  15. package/dist/constants.js +69 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/defaults.d.ts +72 -0
  18. package/dist/defaults.js +694 -0
  19. package/dist/defaults.js.map +1 -0
  20. package/dist/fs-utils.d.ts +8 -0
  21. package/dist/fs-utils.js +35 -0
  22. package/dist/fs-utils.js.map +1 -0
  23. package/dist/model-providers.d.ts +19 -0
  24. package/dist/model-providers.js +78 -0
  25. package/dist/model-providers.js.map +1 -0
  26. package/dist/types.d.ts +550 -0
  27. package/dist/types.js +2 -0
  28. package/dist/types.js.map +1 -0
  29. package/dist/validation.d.ts +10 -0
  30. package/dist/validation.js +163 -0
  31. package/dist/validation.js.map +1 -0
  32. package/dist/web-api.d.ts +16 -0
  33. package/dist/web-api.js +220 -0
  34. package/dist/web-api.js.map +1 -0
  35. package/dist/web-chart-contracts.d.ts +13 -0
  36. package/dist/web-chart-contracts.js +13 -0
  37. package/dist/web-chart-contracts.js.map +1 -0
  38. package/dist/web-console.d.ts +1 -0
  39. package/dist/web-console.js +232 -0
  40. package/dist/web-console.js.map +1 -0
  41. package/dist/web-evidence.d.ts +25 -0
  42. package/dist/web-evidence.js +67 -0
  43. package/dist/web-evidence.js.map +1 -0
  44. package/dist/web-playwright.d.ts +3 -0
  45. package/dist/web-playwright.js +14 -0
  46. package/dist/web-playwright.js.map +1 -0
  47. package/dist/web-roles.d.ts +33 -0
  48. package/dist/web-roles.js +70 -0
  49. package/dist/web-roles.js.map +1 -0
  50. package/dist/workflow-gates.d.ts +7 -0
  51. package/dist/workflow-gates.js +291 -0
  52. package/dist/workflow-gates.js.map +1 -0
  53. package/dist/workflow-services.d.ts +56 -0
  54. package/dist/workflow-services.js +1240 -0
  55. package/dist/workflow-services.js.map +1 -0
  56. package/dist/workspace-validator.d.ts +6 -0
  57. package/dist/workspace-validator.js +189 -0
  58. package/dist/workspace-validator.js.map +1 -0
  59. package/dist/workspace.d.ts +10 -0
  60. package/dist/workspace.js +72 -0
  61. package/dist/workspace.js.map +1 -0
  62. package/docs/multi-agent-orchestrator-backlog.md +445 -0
  63. package/docs/multi-agent-orchestrator-sprint-1.md +433 -0
  64. package/docs/orchestra-mvp.md +176 -0
  65. package/package.json +63 -0
  66. package/rules/agent-collaboration.mdc +58 -0
  67. package/rules/agent-roles.mdc +105 -0
  68. package/rules/ai-assisted-development.mdc +31 -0
  69. package/rules/api-design.mdc +31 -0
  70. package/rules/architecture-decisions.mdc +27 -0
  71. package/rules/code-review-engineering.mdc +34 -0
  72. package/rules/concurrency-async.mdc +32 -0
  73. package/rules/configuration-management.mdc +31 -0
  74. package/rules/data-modeling-domain.mdc +31 -0
  75. package/rules/delivery-quality-gates.mdc +40 -0
  76. package/rules/dependency-management.mdc +31 -0
  77. package/rules/devops-tooling.mdc +55 -0
  78. package/rules/documentation-standards.mdc +26 -0
  79. package/rules/dry-clean-code.mdc +30 -0
  80. package/rules/error-handling.mdc +28 -0
  81. package/rules/frontend-engineering.mdc +32 -0
  82. package/rules/git-discipline.mdc +39 -0
  83. package/rules/infra-data-encryption.mdc +81 -0
  84. package/rules/performance-reliability.mdc +32 -0
  85. package/rules/readiness-done.mdc +32 -0
  86. package/rules/release-rollback.mdc +32 -0
  87. package/rules/rule-composition.mdc +28 -0
  88. package/rules/security-guardrails.mdc +37 -0
  89. package/rules/solid-architecture.mdc +32 -0
  90. package/rules/static-analysis-githooks.mdc +32 -0
  91. package/rules/testing-discipline.mdc +42 -0
  92. package/rules/ux-ui-product-experience.mdc +51 -0
  93. package/rules/work-intake-sequencing.mdc +39 -0
@@ -0,0 +1,232 @@
1
+ export function renderWebConsoleHtml() {
2
+ return String.raw `<!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <title>Open Orchestra Console</title>
8
+ <style>
9
+ :root { color-scheme: light; --bg: #f6f7f9; --panel: #ffffff; --ink: #17202a; --muted: #5f6b7a; --line: #d8dee6; --accent: #146c94; --ok: #137a44; --warn: #a35f00; --focus: rgba(20, 108, 148, 0.25); }
10
+ @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { color-scheme: dark; --bg: #111418; --panel: #1a2027; --ink: #edf1f5; --muted: #aab5c2; --line: #313b46; --accent: #6fb6d8; --ok: #68d391; --warn: #f0b45b; --focus: rgba(111, 182, 216, 0.32); } }
11
+ :root[data-theme="dark"] { color-scheme: dark; --bg: #111418; --panel: #1a2027; --ink: #edf1f5; --muted: #aab5c2; --line: #313b46; --accent: #6fb6d8; --ok: #68d391; --warn: #f0b45b; --focus: rgba(111, 182, 216, 0.32); }
12
+ * { box-sizing: border-box; }
13
+ body { margin: 0; min-width: 320px; background: var(--bg); color: var(--ink); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1.45; }
14
+ button { font: inherit; }
15
+ .app-shell { display: grid; min-height: 100vh; grid-template-rows: auto 1fr; }
16
+ .topbar { border-bottom: 1px solid var(--line); background: var(--panel); }
17
+ .topbar-inner, main { width: min(1180px, 100%); margin: 0 auto; padding: 16px; }
18
+ .brand-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
19
+ .brand h1 { margin: 0; font-size: 1.15rem; font-weight: 750; letter-spacing: 0; }
20
+ .brand p { margin: 2px 0 0; color: var(--muted); font-size: 0.92rem; }
21
+ .header-actions { display: flex; align-items: center; gap: 8px; }
22
+ .icon-button { display: inline-flex; align-items: center; justify-content: center; min-width: 40px; min-height: 40px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); color: var(--ink); cursor: pointer; }
23
+ .icon-button svg { width: 18px; height: 18px; stroke: currentColor; }
24
+ .refresh-button { min-height: 40px; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: white; padding: 0 14px; cursor: pointer; }
25
+ .refresh-button:focus-visible, .icon-button:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
26
+ main { display: grid; gap: 16px; }
27
+ .status-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; color: var(--muted); font-size: 0.92rem; }
28
+ .pill { display: inline-flex; align-items: center; min-height: 28px; border: 1px solid var(--line); border-radius: 999px; background: var(--panel); padding: 0 10px; color: var(--muted); }
29
+ .pill.ok { border-color: rgba(19, 122, 68, 0.35); color: var(--ok); }
30
+ .pill.warn { border-color: rgba(163, 95, 0, 0.35); color: var(--warn); }
31
+ .grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
32
+ .panel { border: 1px solid var(--line); border-radius: 8px; background: var(--panel); padding: 14px; }
33
+ .panel h2 { margin: 0 0 10px; font-size: 0.98rem; letter-spacing: 0; }
34
+ .metric-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
35
+ .chart-grid { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 12px; }
36
+ .chart-card { border: 1px solid var(--line); border-radius: 6px; padding: 10px; min-height: 220px; }
37
+ .chart-card h3 { margin: 0 0 8px; font-size: 0.9rem; letter-spacing: 0; }
38
+ .chart-frame { position: relative; min-height: 170px; }
39
+ .chart-frame canvas { width: 100%; height: 170px; }
40
+ .metric { border: 1px solid var(--line); border-radius: 6px; padding: 10px; min-height: 76px; }
41
+ .metric strong { display: block; font-size: 1.45rem; line-height: 1.1; }
42
+ .metric span, .list-item span { display: block; margin-top: 4px; color: var(--muted); font-size: 0.85rem; }
43
+ .list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
44
+ .list-item { border: 1px solid var(--line); border-radius: 6px; padding: 10px; }
45
+ .list-item strong { display: block; font-size: 0.94rem; }
46
+ .control-row { display: grid; grid-template-columns: 1fr; gap: 8px; margin-bottom: 10px; }
47
+ .field { display: grid; gap: 4px; }
48
+ .field label { color: var(--muted); font-size: 0.82rem; }
49
+ .field input, .field select { min-height: 38px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); color: var(--ink); padding: 0 10px; }
50
+ .text-button { min-height: 38px; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: white; padding: 0 12px; cursor: pointer; }
51
+ .tag-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
52
+ .tag { border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; color: var(--muted); font-size: 0.78rem; }
53
+ .artifact-link { color: var(--accent); font-size: 0.85rem; }
54
+ .missing { color: var(--warn); font-size: 0.85rem; }
55
+ .scenario { margin-top: 8px; }
56
+ .empty-state { border: 1px dashed var(--line); border-radius: 8px; padding: 18px; background: color-mix(in srgb, var(--panel) 85%, var(--bg)); }
57
+ .empty-state strong { display: block; margin-bottom: 4px; }
58
+ .empty-state p { margin: 0; color: var(--muted); }
59
+ @media (min-width: 760px) { .topbar-inner, main { padding: 20px 24px; } .grid { grid-template-columns: minmax(0, 1.5fr) minmax(300px, 0.9fr); } .metric-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } .chart-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .control-row { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: end; } }
60
+ </style>
61
+ </head>
62
+ <body>
63
+ <div class="app-shell">
64
+ <header class="topbar"><div class="topbar-inner"><div class="brand-row"><div class="brand"><h1>Open Orchestra</h1><p>Local workflow console</p></div><div class="header-actions"><button class="icon-button" id="theme-toggle" type="button" title="Toggle color theme" aria-label="Toggle color theme"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M12 3v2.2M12 18.8V21M4.6 4.6l1.6 1.6M17.8 17.8l1.6 1.6M3 12h2.2M18.8 12H21M4.6 19.4l1.6-1.6M17.8 6.2l1.6-1.6M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></button><button class="refresh-button" id="refresh" type="button" title="Reload workflow data">Refresh</button></div></div></div></header>
65
+ <main>
66
+ <section class="status-line" aria-live="polite"><span class="pill" id="load-state">Loading workflow</span><span id="last-updated">Waiting for local API data</span></section>
67
+ <section class="grid"><div class="panel"><h2>Dashboard</h2><div class="metric-grid" id="metrics"></div><div class="chart-grid" id="charts"><div class="chart-card"><h3>Task Status</h3><div class="chart-frame"><canvas id="task-status-chart" aria-label="Task status distribution" role="img"></canvas></div></div><div class="chart-card"><h3>Graph State</h3><div class="chart-frame"><canvas id="graph-state-chart" aria-label="Graph state distribution" role="img"></canvas></div></div></div></div><div class="panel"><h2>Validation</h2><div id="validation"></div></div></section>
68
+ <section class="grid"><div class="panel"><h2>Graph Plan</h2><ul class="list" id="graph"></ul></div><div class="panel"><h2>Next Actions</h2><ul class="list" id="actions"></ul></div></section><section class="grid"><div class="panel"><h2>Evidence</h2><div class="control-row"><div class="field"><label for="evidence-task">Task</label><select id="evidence-task"></select></div><div class="field"><label for="evidence-type">Type</label><select id="evidence-type"></select></div><button class="text-button" id="evidence-filter" type="button">Apply</button></div><ul class="list" id="evidence-list"></ul></div><div class="panel"><h2>Roles</h2><ul class="list" id="roles-view"></ul></div></section><section class="grid"><div class="panel"><h2>Planning</h2><ul class="list" id="planning-view"></ul></div><div class="panel"><h2>Playwright</h2><div class="control-row"><div class="field"><label for="playwright-task">Task</label><select id="playwright-task"></select></div><div class="field"><label for="playwright-kind">Kind</label><select id="playwright-kind"><option>screenshot</option><option>trace</option><option>video</option><option>report</option></select></div><div class="field"><label for="playwright-path">Artifact path</label><input id="playwright-path" placeholder="reports/smoke.png" /></div><div class="field"><label for="playwright-summary">Summary</label><input id="playwright-summary" placeholder="Evidence summary" /></div><button class="text-button" id="playwright-attach" type="button">Attach</button></div><ul class="list" id="playwright-plan"></ul></div></section>
69
+ </main>
70
+ </div>
71
+ <script src="/vendor/chart.umd.js"></script>
72
+ <script>
73
+ const endpoints = [["status", "/api/status"], ["validation", "/api/validate"], ["graph", "/api/graph/plan"], ["roles", "/api/roles"], ["evidence", "/api/evidence"], ["approvals", "/api/approvals"], ["tasks", "/api/tasks"], ["evidenceView", "/api/evidence/view"], ["roleActivation", "/api/roles/activation"]];
74
+ const statePill = document.querySelector("#load-state");
75
+ const lastUpdated = document.querySelector("#last-updated");
76
+ const metrics = document.querySelector("#metrics");
77
+ const validation = document.querySelector("#validation");
78
+ const graph = document.querySelector("#graph");
79
+ const actions = document.querySelector("#actions");
80
+ const charts = document.querySelector("#charts");
81
+ const evidenceTask = document.querySelector("#evidence-task");
82
+ const evidenceType = document.querySelector("#evidence-type");
83
+ const evidenceList = document.querySelector("#evidence-list");
84
+ const rolesView = document.querySelector("#roles-view");
85
+ const planningView = document.querySelector("#planning-view");
86
+ const playwrightTask = document.querySelector("#playwright-task");
87
+ const playwrightPlan = document.querySelector("#playwright-plan");
88
+ let taskStatusChart;
89
+ let graphStateChart;
90
+ const themeToggle = document.querySelector("#theme-toggle");
91
+ applyStoredTheme();
92
+ themeToggle.addEventListener("click", toggleTheme);
93
+ document.querySelector("#refresh").addEventListener("click", loadDashboard);
94
+ document.querySelector("#evidence-filter").addEventListener("click", loadEvidence);
95
+ document.querySelector("#playwright-task").addEventListener("change", loadPlaywrightPlan);
96
+ document.querySelector("#playwright-attach").addEventListener("click", attachPlaywrightEvidence);
97
+ loadDashboard();
98
+ function applyStoredTheme() {
99
+ const stored = localStorage.getItem("open-orchestra-theme");
100
+ if (stored === "dark" || stored === "light") { document.documentElement.dataset.theme = stored; }
101
+ }
102
+ function toggleTheme() {
103
+ const current = document.documentElement.dataset.theme || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
104
+ const next = current === "dark" ? "light" : "dark";
105
+ document.documentElement.dataset.theme = next;
106
+ localStorage.setItem("open-orchestra-theme", next);
107
+ loadDashboard();
108
+ }
109
+ async function loadDashboard() {
110
+ setLoading("Loading workflow", "");
111
+ try {
112
+ const entries = await Promise.all(endpoints.map(async function (entry) {
113
+ const response = await fetch(entry[1]);
114
+ if (!response.ok) { throw new Error(entry[1] + " returned " + response.status); }
115
+ return [entry[0], await response.json()];
116
+ }));
117
+ render(Object.fromEntries(entries));
118
+ setLoading("Workflow loaded", "ok");
119
+ lastUpdated.textContent = "Updated " + new Date().toLocaleTimeString();
120
+ } catch (error) {
121
+ setLoading("Console unavailable", "warn");
122
+ renderEmpty("The local API is not ready yet.", String(error.message || error));
123
+ }
124
+ }
125
+ function render(data) {
126
+ replace(metrics, [metric(String(data.status.tasks.total), "Tasks"), metric(String(data.graph.ready.length), "Ready"), metric(String(data.graph.blocked.length), "Blocked"), metric(String(data.graph.locked.length), "Locked"), metric(String(data.roles.length), "Roles"), metric(String(data.evidence.length), "Evidence"), metric(String(data.approvals.length), "Approvals"), metric(data.validation.valid ? "Valid" : "Needs work", "Workspace")]);
127
+ renderValidation(data.validation); renderGraph(data.graph); renderActions(data); renderCharts(data); renderEvidenceControls(data); renderEvidence(data.evidenceView); renderRoles(data.roleActivation); renderPlanning(data.roleActivation); renderPlaywrightTasks(data.tasks); loadPlaywrightPlan();
128
+ }
129
+ function renderCharts(data) {
130
+ const chartData = buildDashboardChartData(data);
131
+ const hasChartData = chartData.taskStatus.length > 0 || chartData.graphState.length > 0;
132
+ charts.hidden = !hasChartData;
133
+ if (!hasChartData || !window.Chart) { return; }
134
+ taskStatusChart = renderChart(taskStatusChart, "task-status-chart", "doughnut", chartData.taskStatus);
135
+ graphStateChart = renderChart(graphStateChart, "graph-state-chart", "bar", chartData.graphState);
136
+ }
137
+ function buildDashboardChartData(data) {
138
+ return {
139
+ taskStatus: Object.entries(data.status.tasks.byStatus).map(function (entry) { return { label: entry[0], value: entry[1] }; }).filter(function (slice) { return slice.value > 0; }),
140
+ graphState: [["ready", data.graph.ready.length], ["blocked", data.graph.blocked.length], ["locked", data.graph.locked.length], ["complete", data.graph.complete.length]].map(function (entry) { return { label: entry[0], value: entry[1] }; }).filter(function (slice) { return slice.value > 0; }),
141
+ };
142
+ }
143
+ function renderChart(current, canvasId, type, slices) {
144
+ const style = getComputedStyle(document.documentElement);
145
+ const colors = [style.getPropertyValue("--accent").trim(), style.getPropertyValue("--ok").trim(), style.getPropertyValue("--warn").trim(), "#8a6fdf", "#d36d8c", "#5f9ea0"];
146
+ const textColor = style.getPropertyValue("--ink").trim();
147
+ const lineColor = style.getPropertyValue("--line").trim();
148
+ if (current) { current.destroy(); }
149
+ return new Chart(document.getElementById(canvasId), {
150
+ type,
151
+ data: { labels: slices.map(function (slice) { return slice.label; }), datasets: [{ data: slices.map(function (slice) { return slice.value; }), backgroundColor: colors, borderColor: lineColor, borderWidth: 1 }] },
152
+ options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: "bottom", labels: { color: textColor } } }, scales: type === "bar" ? { x: { ticks: { color: textColor }, grid: { color: lineColor } }, y: { beginAtZero: true, ticks: { color: textColor, precision: 0 }, grid: { color: lineColor } } } : {} },
153
+ });
154
+ }
155
+ async function loadEvidence() {
156
+ const query = new URLSearchParams();
157
+ if (evidenceTask.value) { query.set("task", evidenceTask.value); }
158
+ if (evidenceType.value) { query.set("type", evidenceType.value); }
159
+ const response = await fetch("/api/evidence/view?" + query.toString());
160
+ renderEvidence(await response.json());
161
+ }
162
+ function renderEvidenceControls(data) {
163
+ replace(evidenceTask, [option("", "All tasks")].concat(data.tasks.map(function (task) { return option(task.id, task.id); })));
164
+ replace(evidenceType, [option("", "All types")].concat(["command", "file", "screenshot", "trace", "video", "log", "report"].map(function (type) { return option(type, type); })));
165
+ replace(playwrightTask, data.tasks.map(function (task) { return option(task.id, task.id); }));
166
+ }
167
+ function renderEvidence(items) {
168
+ replace(evidenceList, items.length > 0 ? items.map(evidenceItem) : [empty("No evidence yet", "Attach command, report, screenshot, trace, video, or log evidence.")]);
169
+ }
170
+ function evidenceItem(item) {
171
+ const node = listItem(item.summary, (item.taskId || "no-task") + " - " + item.type + " - " + item.actor);
172
+ const row = document.createElement("div"); row.className = "tag-row";
173
+ item.artifacts.forEach(function (artifact) {
174
+ if (artifact.exists) { const link = document.createElement("a"); link.className = "artifact-link"; link.href = artifact.url; link.target = "_blank"; link.rel = "noreferrer"; link.textContent = artifact.path; row.append(link); }
175
+ else { const miss = document.createElement("span"); miss.className = "missing"; miss.textContent = "Missing: " + artifact.path; row.append(miss); }
176
+ });
177
+ node.append(row); return node;
178
+ }
179
+ function renderRoles(report) {
180
+ replace(rolesView, report.roles.slice(0, 12).map(function (entry) {
181
+ const node = listItem(entry.role.name, entry.state + " - " + entry.role.description);
182
+ const tags = document.createElement("div"); tags.className = "tag-row";
183
+ ["activationCriteria", "expectedEvidence", "gateParticipation"].forEach(function (field) { (entry.role[field] || []).slice(0, 3).forEach(function (value) { const tag = document.createElement("span"); tag.className = "tag"; tag.textContent = value; tags.append(tag); }); });
184
+ node.append(tags); return node;
185
+ }));
186
+ }
187
+ function renderPlanning(report) {
188
+ const totals = report.planning.totals;
189
+ const rows = [listItem("Graph totals", "ready " + totals.ready + " - blocked " + totals.blocked + " - locked " + totals.locked + " - complete " + totals.complete)].concat(report.planning.byRole.map(function (role) { return listItem(role.roleId, "ready " + role.ready + " - blocked " + role.blocked + " - locked " + role.locked + " - complete " + role.complete); }));
190
+ replace(planningView, rows);
191
+ }
192
+ function renderPlaywrightTasks(tasks) { if (tasks.length === 0) { replace(playwrightTask, [option("", "No tasks")]); } }
193
+ async function loadPlaywrightPlan() {
194
+ if (!playwrightTask.value) { replace(playwrightPlan, [empty("No task selected", "Create a task to generate a Playwright plan.")]); return; }
195
+ const response = await fetch("/api/playwright/plan?task=" + encodeURIComponent(playwrightTask.value));
196
+ const plan = await response.json();
197
+ replace(playwrightPlan, plan.scenarios.map(function (scenario) { return listItem(scenario.name, scenario.assertions.join(" | ")); }));
198
+ }
199
+ async function attachPlaywrightEvidence() {
200
+ const body = { task: playwrightTask.value, kind: document.querySelector("#playwright-kind").value, path: document.querySelector("#playwright-path").value, summary: document.querySelector("#playwright-summary").value };
201
+ const response = await fetch("/api/playwright/evidence", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
202
+ if (!response.ok) { setLoading("Evidence attach failed", "warn"); return; }
203
+ await loadDashboard();
204
+ }
205
+ function option(value, label) { const node = document.createElement("option"); node.value = value; node.textContent = label; return node; }
206
+ function renderValidation(report) {
207
+ if (report.valid && report.warnings.length === 0) { replace(validation, [empty("Workspace is valid", "No validation issues were reported.")]); return; }
208
+ replace(validation, report.errors.concat(report.warnings).map(function (message) { return listItem(message, report.errors.includes(message) ? "Error" : "Warning"); }));
209
+ }
210
+ function renderGraph(plan) {
211
+ const rows = [["Ready", plan.ready], ["Blocked", plan.blocked], ["Locked", plan.locked], ["Complete", plan.complete]].flatMap(function (group) { return group[1].slice(0, 4).map(function (item) { return listItem(item.title, group[0] + " - " + item.id + " - " + item.ownerRole); }); });
212
+ replace(graph, rows.length > 0 ? rows : [empty("No tasks yet", "Add tasks with orchestra task add to start planning.")]);
213
+ }
214
+ function renderActions(data) {
215
+ const next = [];
216
+ if (!data.validation.valid) { next.push(listItem("Fix workspace validation", "Run orchestra validate for full details.")); }
217
+ if (data.graph.ready.length > 0) { next.push(listItem("Start ready work", data.graph.ready.length + " task(s) can run now.")); }
218
+ if (data.approvals.length > 0) { next.push(listItem("Review pending approvals", data.approvals.length + " approval artifact(s) found.")); }
219
+ if (data.status.tasks.total === 0) { next.push(listItem("Create the first task", "Use a backlog item, owner role, scope, and acceptance criteria.")); }
220
+ replace(actions, next.length > 0 ? next : [empty("No immediate action", "The workflow has no blocking console actions.")]);
221
+ }
222
+ function metric(value, label) { const node = document.createElement("div"); node.className = "metric"; const strong = document.createElement("strong"); strong.textContent = value; const span = document.createElement("span"); span.textContent = label; node.append(strong, span); return node; }
223
+ function listItem(title, detail) { const node = document.createElement("li"); node.className = "list-item"; const strong = document.createElement("strong"); strong.textContent = title; const span = document.createElement("span"); span.textContent = detail; node.append(strong, span); return node; }
224
+ function empty(title, detail) { const node = document.createElement("div"); node.className = "empty-state"; const strong = document.createElement("strong"); strong.textContent = title; const p = document.createElement("p"); p.textContent = detail; node.append(strong, p); return node; }
225
+ function replace(parent, nodes) { parent.replaceChildren(...nodes); }
226
+ function renderEmpty(title, detail) { replace(metrics, [empty(title, detail)]); charts.hidden = true; replace(validation, []); replace(graph, []); replace(actions, []); }
227
+ function setLoading(label, tone) { statePill.textContent = label; statePill.className = ("pill " + tone).trim(); }
228
+ </script>
229
+ </body>
230
+ </html>`;
231
+ }
232
+ //# sourceMappingURL=web-console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-console.js","sourceRoot":"","sources":["../src/web-console.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAoOX,CAAC;AACT,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface WebArtifactInfo {
2
+ path: string;
3
+ exists: boolean;
4
+ url?: string;
5
+ }
6
+ export interface WebEvidenceEntry {
7
+ id: string;
8
+ taskId: string | null;
9
+ actor: string;
10
+ summary: string;
11
+ type: string;
12
+ timestamp: string;
13
+ artifacts: WebArtifactInfo[];
14
+ }
15
+ export interface WebArtifactReadResult {
16
+ path: string;
17
+ contentType: string;
18
+ content: string;
19
+ }
20
+ export declare function listWebEvidence(root: string, filters?: {
21
+ task?: string;
22
+ type?: string;
23
+ }): Promise<WebEvidenceEntry[]>;
24
+ export declare function readWorkspaceArtifact(root: string, relativePath: string): Promise<WebArtifactReadResult>;
25
+ export declare function resolveWorkspaceLocalPath(root: string, relativePath: string): string;
@@ -0,0 +1,67 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { exists } from "./fs-utils.js";
4
+ import { listEvidence } from "./workflow-services.js";
5
+ export async function listWebEvidence(root, filters = {}) {
6
+ const events = await listEvidence(filters.task, root);
7
+ const filtered = filters.type
8
+ ? events.filter((event) => String(event.metadata.type ?? "") === filters.type)
9
+ : events;
10
+ return Promise.all(filtered.map((event) => toWebEvidenceEntry(root, event)));
11
+ }
12
+ export async function readWorkspaceArtifact(root, relativePath) {
13
+ const filePath = resolveWorkspaceLocalPath(root, relativePath);
14
+ if (!(await exists(filePath))) {
15
+ throw new Error(`artifact does not exist: ${relativePath}`);
16
+ }
17
+ return {
18
+ path: relativePath,
19
+ contentType: contentTypeForPath(relativePath),
20
+ content: await readFile(filePath, "utf8"),
21
+ };
22
+ }
23
+ export function resolveWorkspaceLocalPath(root, relativePath) {
24
+ if (path.isAbsolute(relativePath)) {
25
+ throw new Error("artifact path must be workspace-relative");
26
+ }
27
+ const normalizedRoot = path.resolve(root);
28
+ const resolved = path.resolve(normalizedRoot, relativePath);
29
+ if (resolved !== normalizedRoot &&
30
+ !resolved.startsWith(`${normalizedRoot}${path.sep}`)) {
31
+ throw new Error("artifact path escapes workspace");
32
+ }
33
+ return resolved;
34
+ }
35
+ async function toWebEvidenceEntry(root, event) {
36
+ const artifacts = await Promise.all((event.artifacts ?? []).map(async (artifact) => {
37
+ const artifactExists = await exists(resolveWorkspaceLocalPath(root, artifact));
38
+ const info = { path: artifact, exists: artifactExists };
39
+ if (artifactExists) {
40
+ info.url = `/api/artifacts?path=${encodeURIComponent(artifact)}`;
41
+ }
42
+ return info;
43
+ }));
44
+ return {
45
+ id: event.id,
46
+ taskId: event.taskId,
47
+ actor: event.actor,
48
+ summary: event.summary,
49
+ type: String(event.metadata.type ?? "unknown"),
50
+ timestamp: event.timestamp,
51
+ artifacts,
52
+ };
53
+ }
54
+ function contentTypeForPath(filePath) {
55
+ const extension = path.extname(filePath).toLowerCase();
56
+ if (extension === ".md" || extension === ".txt" || extension === ".log") {
57
+ return "text/plain; charset=utf-8";
58
+ }
59
+ if (extension === ".json") {
60
+ return "application/json; charset=utf-8";
61
+ }
62
+ if (extension === ".svg") {
63
+ return "image/svg+xml; charset=utf-8";
64
+ }
65
+ return "application/octet-stream";
66
+ }
67
+ //# sourceMappingURL=web-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-evidence.js","sourceRoot":"","sources":["../src/web-evidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ArtifactResult, PlaywrightEvidenceInput, PlaywrightTestPlan } from "./types.js";
2
+ export declare function getWebPlaywrightPlan(root: string, taskId: string): Promise<PlaywrightTestPlan>;
3
+ export declare function attachWebPlaywrightEvidence(root: string, input: PlaywrightEvidenceInput): Promise<ArtifactResult>;
@@ -0,0 +1,14 @@
1
+ import { exists } from "./fs-utils.js";
2
+ import { addPlaywrightEvidence, generatePlaywrightTestPlan, } from "./workflow-services.js";
3
+ import { resolveWorkspaceLocalPath } from "./web-evidence.js";
4
+ export async function getWebPlaywrightPlan(root, taskId) {
5
+ return generatePlaywrightTestPlan(taskId, root);
6
+ }
7
+ export async function attachWebPlaywrightEvidence(root, input) {
8
+ const filePath = resolveWorkspaceLocalPath(root, input.path);
9
+ if (!(await exists(filePath))) {
10
+ throw new Error(`playwright artifact does not exist: ${input.path}`);
11
+ }
12
+ return addPlaywrightEvidence(input, root);
13
+ }
14
+ //# sourceMappingURL=web-playwright.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-playwright.js","sourceRoot":"","sources":["../src/web-playwright.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAO9D,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAY,EACZ,MAAc;IAEd,OAAO,0BAA0B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,IAAY,EACZ,KAA8B;IAE9B,MAAM,QAAQ,GAAG,yBAAyB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7D,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,uCAAuC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { Role } from "./types.js";
2
+ export type WebRoleState = "active" | "recommended" | "blocked" | "available";
3
+ export interface WebRoleActivationEntry {
4
+ role: Role;
5
+ state: WebRoleState;
6
+ taskCounts: {
7
+ active: number;
8
+ ready: number;
9
+ blocked: number;
10
+ locked: number;
11
+ complete: number;
12
+ };
13
+ }
14
+ export interface WebPlanningRoleSummary {
15
+ roleId: string;
16
+ ready: number;
17
+ blocked: number;
18
+ locked: number;
19
+ complete: number;
20
+ }
21
+ export interface WebRoleActivationReport {
22
+ roles: WebRoleActivationEntry[];
23
+ planning: {
24
+ totals: {
25
+ ready: number;
26
+ blocked: number;
27
+ locked: number;
28
+ complete: number;
29
+ };
30
+ byRole: WebPlanningRoleSummary[];
31
+ };
32
+ }
33
+ export declare function getWebRoleActivation(root: string): Promise<WebRoleActivationReport>;
@@ -0,0 +1,70 @@
1
+ import { generateTaskGraphPlan, listRoles, listTasks, } from "./workflow-services.js";
2
+ export async function getWebRoleActivation(root) {
3
+ const [roles, tasks, graph] = await Promise.all([
4
+ listRoles(root),
5
+ listTasks(root),
6
+ generateTaskGraphPlan(root),
7
+ ]);
8
+ const activeRoleIds = new Set(tasks
9
+ .filter((task) => task.status === "in_progress" || task.status === "review")
10
+ .map((task) => task.ownerRole));
11
+ const readyRoleIds = new Set(graph.ready.map((task) => task.ownerRole));
12
+ const blockedRoleIds = new Set([
13
+ ...graph.blocked.map((task) => task.ownerRole),
14
+ ...graph.locked.map((task) => task.ownerRole),
15
+ ]);
16
+ return {
17
+ roles: roles.map((role) => ({
18
+ role,
19
+ state: stateForRole(role.id, activeRoleIds, readyRoleIds, blockedRoleIds),
20
+ taskCounts: countsForRole(role.id, graph, activeRoleIds.has(role.id)),
21
+ })),
22
+ planning: {
23
+ totals: {
24
+ ready: graph.ready.length,
25
+ blocked: graph.blocked.length,
26
+ locked: graph.locked.length,
27
+ complete: graph.complete.length,
28
+ },
29
+ byRole: roles
30
+ .map((role) => ({
31
+ roleId: role.id,
32
+ ready: graph.ready.filter((task) => task.ownerRole === role.id)
33
+ .length,
34
+ blocked: graph.blocked.filter((task) => task.ownerRole === role.id)
35
+ .length,
36
+ locked: graph.locked.filter((task) => task.ownerRole === role.id)
37
+ .length,
38
+ complete: graph.complete.filter((task) => task.ownerRole === role.id)
39
+ .length,
40
+ }))
41
+ .filter((summary) => summary.ready +
42
+ summary.blocked +
43
+ summary.locked +
44
+ summary.complete >
45
+ 0),
46
+ },
47
+ };
48
+ }
49
+ function stateForRole(roleId, activeRoleIds, readyRoleIds, blockedRoleIds) {
50
+ if (activeRoleIds.has(roleId)) {
51
+ return "active";
52
+ }
53
+ if (readyRoleIds.has(roleId)) {
54
+ return "recommended";
55
+ }
56
+ if (blockedRoleIds.has(roleId)) {
57
+ return "blocked";
58
+ }
59
+ return "available";
60
+ }
61
+ function countsForRole(roleId, graph, isActive) {
62
+ return {
63
+ active: isActive ? 1 : 0,
64
+ ready: graph.ready.filter((task) => task.ownerRole === roleId).length,
65
+ blocked: graph.blocked.filter((task) => task.ownerRole === roleId).length,
66
+ locked: graph.locked.filter((task) => task.ownerRole === roleId).length,
67
+ complete: graph.complete.filter((task) => task.ownerRole === roleId).length,
68
+ };
69
+ }
70
+ //# sourceMappingURL=web-roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-roles.js","sourceRoot":"","sources":["../src/web-roles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { WorkflowGate } from "./types.js";
2
+ export declare const architectureApprovalGate: WorkflowGate;
3
+ export declare const qaReleaseGate: WorkflowGate;
4
+ export declare const riskReviewGate: WorkflowGate;
5
+ export declare const releaseReadinessGate: WorkflowGate;
6
+ export declare const workflowGates: Map<string, WorkflowGate>;
7
+ export declare function getWorkflowGate(gateId: string): WorkflowGate;