@jterrats/open-orchestra 0.4.2-beta.1 → 0.5.0-beta.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 (170) hide show
  1. package/AGENTS.md +5 -3
  2. package/README.md +29 -5
  3. package/dist/advisory-artifacts.d.ts +20 -0
  4. package/dist/advisory-artifacts.js +136 -0
  5. package/dist/advisory-artifacts.js.map +1 -0
  6. package/dist/assets/web-console.js +436 -4
  7. package/dist/cli.js +16 -117
  8. package/dist/cli.js.map +1 -1
  9. package/dist/command-manifest.d.ts +6 -0
  10. package/dist/command-manifest.js +141 -43
  11. package/dist/command-manifest.js.map +1 -1
  12. package/dist/command-utils.d.ts +5 -0
  13. package/dist/command-utils.js +23 -0
  14. package/dist/command-utils.js.map +1 -1
  15. package/dist/commands.d.ts +7 -42
  16. package/dist/commands.js +214 -1356
  17. package/dist/commands.js.map +1 -1
  18. package/dist/constants.js +3 -0
  19. package/dist/constants.js.map +1 -1
  20. package/dist/context-budget.d.ts +4 -0
  21. package/dist/context-budget.js +119 -0
  22. package/dist/context-budget.js.map +1 -0
  23. package/dist/delivery-commands.d.ts +10 -0
  24. package/dist/delivery-commands.js +152 -0
  25. package/dist/delivery-commands.js.map +1 -0
  26. package/dist/github.d.ts +50 -1
  27. package/dist/github.js +234 -0
  28. package/dist/github.js.map +1 -1
  29. package/dist/health-checks.d.ts +1 -0
  30. package/dist/health-checks.js +11 -1
  31. package/dist/health-checks.js.map +1 -1
  32. package/dist/health-commands.js +2 -0
  33. package/dist/health-commands.js.map +1 -1
  34. package/dist/mcp-oauth-proxy.d.ts +32 -0
  35. package/dist/mcp-oauth-proxy.js +120 -0
  36. package/dist/mcp-oauth-proxy.js.map +1 -1
  37. package/dist/memory.d.ts +2 -1
  38. package/dist/memory.js +71 -10
  39. package/dist/memory.js.map +1 -1
  40. package/dist/package-update-check.d.ts +5 -1
  41. package/dist/package-update-check.js +20 -8
  42. package/dist/package-update-check.js.map +1 -1
  43. package/dist/planning-commands.d.ts +14 -0
  44. package/dist/planning-commands.js +372 -0
  45. package/dist/planning-commands.js.map +1 -0
  46. package/dist/release-candidate.d.ts +2 -0
  47. package/dist/release-candidate.js +9 -14
  48. package/dist/release-candidate.js.map +1 -1
  49. package/dist/release-commands.d.ts +2 -0
  50. package/dist/release-commands.js +58 -6
  51. package/dist/release-commands.js.map +1 -1
  52. package/dist/release-readiness.d.ts +49 -0
  53. package/dist/release-readiness.js +172 -0
  54. package/dist/release-readiness.js.map +1 -0
  55. package/dist/runtime-commands.js +11 -4
  56. package/dist/runtime-commands.js.map +1 -1
  57. package/dist/runtime-execution-renderer.js +2 -0
  58. package/dist/runtime-execution-renderer.js.map +1 -1
  59. package/dist/runtime-execution.d.ts +4 -2
  60. package/dist/runtime-execution.js +11 -4
  61. package/dist/runtime-execution.js.map +1 -1
  62. package/dist/setup-agents-import.d.ts +42 -0
  63. package/dist/setup-agents-import.js +335 -0
  64. package/dist/setup-agents-import.js.map +1 -0
  65. package/dist/skills-catalog-service.d.ts +2 -0
  66. package/dist/skills-catalog-service.js +8 -0
  67. package/dist/skills-catalog-service.js.map +1 -0
  68. package/dist/skills-catalog.d.ts +2 -0
  69. package/dist/skills-catalog.js +389 -0
  70. package/dist/skills-catalog.js.map +1 -0
  71. package/dist/skills-commands.js +1 -11
  72. package/dist/skills-commands.js.map +1 -1
  73. package/dist/skills-events.d.ts +9 -0
  74. package/dist/skills-events.js +50 -0
  75. package/dist/skills-events.js.map +1 -0
  76. package/dist/skills-memory.d.ts +18 -0
  77. package/dist/skills-memory.js +127 -0
  78. package/dist/skills-memory.js.map +1 -0
  79. package/dist/skills-planning.d.ts +2 -0
  80. package/dist/skills-planning.js +87 -0
  81. package/dist/skills-planning.js.map +1 -0
  82. package/dist/skills-render.d.ts +14 -0
  83. package/dist/skills-render.js +83 -0
  84. package/dist/skills-render.js.map +1 -0
  85. package/dist/skills-validation.d.ts +2 -0
  86. package/dist/skills-validation.js +49 -0
  87. package/dist/skills-validation.js.map +1 -0
  88. package/dist/skills.d.ts +6 -42
  89. package/dist/skills.js +6 -773
  90. package/dist/skills.js.map +1 -1
  91. package/dist/task-graph-commands.d.ts +14 -0
  92. package/dist/task-graph-commands.js +367 -0
  93. package/dist/task-graph-commands.js.map +1 -0
  94. package/dist/tool-commands.js +8 -0
  95. package/dist/tool-commands.js.map +1 -1
  96. package/dist/types/context.d.ts +12 -0
  97. package/dist/types/context.js +2 -0
  98. package/dist/types/context.js.map +1 -0
  99. package/dist/types/metrics.d.ts +114 -0
  100. package/dist/types/metrics.js +2 -0
  101. package/dist/types/metrics.js.map +1 -0
  102. package/dist/types/model-config.d.ts +212 -0
  103. package/dist/types/model-config.js +2 -0
  104. package/dist/types/model-config.js.map +1 -0
  105. package/dist/types/runtime.d.ts +93 -0
  106. package/dist/types/runtime.js +2 -0
  107. package/dist/types/runtime.js.map +1 -0
  108. package/dist/types/skills.d.ts +147 -0
  109. package/dist/types/skills.js +2 -0
  110. package/dist/types/skills.js.map +1 -0
  111. package/dist/types/tasks.d.ts +171 -0
  112. package/dist/types/tasks.js +2 -0
  113. package/dist/types/tasks.js.map +1 -0
  114. package/dist/types/workflow-run.d.ts +79 -0
  115. package/dist/types/workflow-run.js +2 -0
  116. package/dist/types/workflow-run.js.map +1 -0
  117. package/dist/types.d.ts +13 -798
  118. package/dist/types.js +1 -1
  119. package/dist/types.js.map +1 -1
  120. package/dist/upgrade-commands.d.ts +2 -0
  121. package/dist/upgrade-commands.js +65 -0
  122. package/dist/upgrade-commands.js.map +1 -0
  123. package/dist/web-api-read-routes.d.ts +5 -0
  124. package/dist/web-api-read-routes.js +37 -0
  125. package/dist/web-api-read-routes.js.map +1 -0
  126. package/dist/web-api.d.ts +1 -3
  127. package/dist/web-api.js +145 -44
  128. package/dist/web-api.js.map +1 -1
  129. package/dist/web-console-sections.d.ts +2 -0
  130. package/dist/web-console-sections.js +7 -0
  131. package/dist/web-console-sections.js.map +1 -0
  132. package/dist/web-console.js +23 -3
  133. package/dist/web-console.js.map +1 -1
  134. package/dist/workflow-approval-service.d.ts +9 -0
  135. package/dist/workflow-approval-service.js +126 -0
  136. package/dist/workflow-approval-service.js.map +1 -0
  137. package/dist/workflow-approval-utils.d.ts +10 -0
  138. package/dist/workflow-approval-utils.js +82 -0
  139. package/dist/workflow-approval-utils.js.map +1 -0
  140. package/dist/workflow-budget-utils.d.ts +7 -0
  141. package/dist/workflow-budget-utils.js +96 -0
  142. package/dist/workflow-budget-utils.js.map +1 -0
  143. package/dist/workflow-evidence-service.d.ts +7 -0
  144. package/dist/workflow-evidence-service.js +100 -0
  145. package/dist/workflow-evidence-service.js.map +1 -0
  146. package/dist/workflow-run-commands.d.ts +8 -0
  147. package/dist/workflow-run-commands.js +479 -0
  148. package/dist/workflow-run-commands.js.map +1 -0
  149. package/dist/workflow-services.d.ts +8 -18
  150. package/dist/workflow-services.js +30 -481
  151. package/dist/workflow-services.js.map +1 -1
  152. package/dist/workflow-summary-service.d.ts +4 -0
  153. package/dist/workflow-summary-service.js +82 -0
  154. package/dist/workflow-summary-service.js.map +1 -0
  155. package/dist/workflow-templates.d.ts +1 -0
  156. package/dist/workflow-templates.js +1 -0
  157. package/dist/workflow-templates.js.map +1 -1
  158. package/dist/workspace.d.ts +18 -1
  159. package/dist/workspace.js +72 -4
  160. package/dist/workspace.js.map +1 -1
  161. package/docs/command-contracts.md +22 -0
  162. package/docs/mcp-oauth-proxy-evaluation.md +14 -0
  163. package/docs/orchestra-mvp.md +158 -114
  164. package/docs/package-naming.md +20 -0
  165. package/docs/persona-workflows.md +209 -0
  166. package/docs/runtime-adapters.md +19 -14
  167. package/docs/runtime-llm-flow.md +29 -28
  168. package/docs/setup-agents-bridge.md +61 -0
  169. package/docs/traceability-flow.md +89 -0
  170. package/package.json +9 -7
@@ -1,3 +1,4 @@
1
+ import { renderAdoptionGuideSections, renderDashboardSections, } from "./web-console-sections.js";
1
2
  export function renderWebConsoleHtml() {
2
3
  return String.raw `<!doctype html>
3
4
  <html lang="en">
@@ -40,17 +41,35 @@ export function renderWebConsoleHtml() {
40
41
  .metric { border: 1px solid var(--line); border-radius: 6px; padding: 10px; min-height: 76px; }
41
42
  .metric strong { display: block; font-size: 1.45rem; line-height: 1.1; }
42
43
  .metric span, .list-item span { display: block; margin-top: 4px; color: var(--muted); font-size: 0.85rem; }
44
+ .guide-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
45
+ .guide-card { border: 1px solid var(--line); border-radius: 8px; background: var(--panel); padding: 14px; }
46
+ .guide-card h2 { margin: 0 0 8px; font-size: 1rem; letter-spacing: 0; }
47
+ .guide-card p { margin: 0; color: var(--muted); }
48
+ .step-list { display: grid; gap: 8px; margin: 12px 0 0; padding: 0; list-style: none; }
49
+ .step-list li { display: grid; grid-template-columns: 28px 1fr; gap: 8px; align-items: start; }
50
+ .step-list b { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 999px; background: color-mix(in srgb, var(--accent) 18%, var(--panel)); color: var(--accent); font-size: 0.84rem; }
51
+ .step-list span { color: var(--muted); font-size: 0.88rem; }
52
+ .command-list { display: grid; gap: 8px; margin-top: 12px; }
53
+ .command-chip { display: block; border: 1px solid var(--line); border-radius: 6px; background: color-mix(in srgb, var(--panel) 82%, var(--bg)); padding: 9px 10px; color: var(--ink); font: 0.84rem/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; white-space: normal; word-break: break-word; }
43
54
  .list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
44
55
  .list-item { border: 1px solid var(--line); border-radius: 6px; padding: 10px; }
45
56
  .list-item strong { display: block; font-size: 0.94rem; }
57
+ .list-item button { margin-top: 8px; }
46
58
  .control-row { display: grid; grid-template-columns: 1fr; gap: 8px; margin-bottom: 10px; }
47
59
  .field { display: grid; gap: 4px; }
48
60
  .field label { color: var(--muted); font-size: 0.82rem; }
49
61
  .field input, .field select, .field textarea { min-height: 38px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); color: var(--ink); padding: 0 10px; }
50
62
  .field textarea { min-height: 72px; padding-top: 8px; resize: vertical; }
51
63
  .text-button { min-height: 38px; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: white; padding: 0 12px; cursor: pointer; }
64
+ .text-button.secondary { border-color: var(--line); background: var(--panel); color: var(--ink); }
52
65
  .tag-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
53
66
  .tag { border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; color: var(--muted); font-size: 0.78rem; }
67
+ .tag.ok { border-color: rgba(19, 122, 68, 0.35); color: var(--ok); }
68
+ .tag.warn { border-color: rgba(163, 95, 0, 0.35); color: var(--warn); }
69
+ .detail-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
70
+ .detail-block { border-top: 1px solid var(--line); padding-top: 10px; }
71
+ .detail-block h3 { margin: 0 0 6px; font-size: 0.9rem; letter-spacing: 0; }
72
+ .detail-block ul { margin: 0; padding-left: 18px; color: var(--muted); }
54
73
  .artifact-link { color: var(--accent); font-size: 0.85rem; }
55
74
  .missing { color: var(--warn); font-size: 0.85rem; }
56
75
  .preview { max-height: 340px; overflow: auto; border: 1px solid var(--line); border-radius: 6px; background: color-mix(in srgb, var(--panel) 78%, var(--bg)); padding: 10px; white-space: pre-wrap; word-break: break-word; font: 0.82rem/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
@@ -58,7 +77,7 @@ export function renderWebConsoleHtml() {
58
77
  .empty-state { border: 1px dashed var(--line); border-radius: 8px; padding: 18px; background: color-mix(in srgb, var(--panel) 85%, var(--bg)); }
59
78
  .empty-state strong { display: block; margin-bottom: 4px; }
60
79
  .empty-state p { margin: 0; color: var(--muted); }
61
- @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; } }
80
+ @media (min-width: 760px) { .topbar-inner, main { padding: 20px 24px; } .grid { grid-template-columns: minmax(0, 1.5fr) minmax(300px, 0.9fr); } .guide-grid { grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr); } .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; } }
62
81
  </style>
63
82
  </head>
64
83
  <body>
@@ -66,8 +85,9 @@ export function renderWebConsoleHtml() {
66
85
  <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>
67
86
  <main>
68
87
  <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>
69
- <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 class="chart-card"><h3>Cost by Provider</h3><div class="chart-frame"><canvas id="provider-cost-chart" aria-label="Estimated cost by provider" role="img"></canvas></div></div></div></div><div class="panel"><h2>Workspace</h2><ul class="list" id="workspace-view"></ul><h2>Validation</h2><div id="validation"></div></div></section>
70
- <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>Cost</h2><ul class="list" id="cost-view"></ul></div><div class="panel"><h2>Add Task</h2><div class="control-row"><div class="field"><label for="task-id">ID</label><input id="task-id" placeholder="WEB-001" /></div><div class="field"><label for="task-title">Title</label><input id="task-title" placeholder="Implement workflow task" /></div><div class="field"><label for="task-owner">Owner</label><select id="task-owner"></select></div><div class="field"><label for="task-paths">Paths</label><input id="task-paths" placeholder="src/web-api.ts, test/orchestra.test.js" /></div></div><div class="control-row"><div class="field"><label for="task-acceptance">Acceptance</label><input id="task-acceptance" placeholder="comma separated criteria" /></div><div class="field"><label for="task-risks">Risks</label><input id="task-risks" placeholder="security, release" /></div><button class="text-button" id="task-add" type="button">Add Task</button></div></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><section class="grid"><div class="panel"><h2>Skills</h2><div class="control-row"><div class="field"><label for="skills-task">Task</label><select id="skills-task"></select></div><div class="field"><label for="skills-target">Target</label><select id="skills-target"><option>generic</option><option>claude</option><option>cursor</option><option>codex</option><option>vscode</option><option>windsurf</option></select></div><button class="text-button" id="skills-plan" type="button">Plan</button><button class="text-button" id="skills-render" type="button">Render</button></div><ul class="list" id="skills-plan-list"></ul></div><div class="panel"><h2>Skill Catalog</h2><ul class="list" id="skills-list"></ul><h2>Render Preview</h2><pre class="preview" id="skills-preview">No skill render yet.</pre></div></section><section class="grid"><div class="panel"><h2>Source of Truth</h2><ul class="list" id="sources-list"></ul></div><div class="panel"><h2>Lessons Learned</h2><div class="control-row"><div class="field"><label for="lesson-promote-target">Promote to</label><select id="lesson-promote-target"><option>doc</option><option>skill</option><option>rule</option></select></div><div class="field"><label for="lesson-promote-filter">Filter</label><input id="lesson-promote-filter" placeholder="operation or error" /></div><button class="text-button" id="lesson-promote" type="button">Promote</button></div><ul class="list" id="lesson-promotion-result"></ul><ul class="list" id="lessons-list"></ul></div></section><section class="grid"><div class="panel"><h2>Add Lesson</h2><div class="control-row"><div class="field"><label for="lesson-task">Task</label><select id="lesson-task"></select></div><div class="field"><label for="lesson-actor">Actor</label><input id="lesson-actor" value="parent" data-lesson-required required /></div><div class="field"><label for="lesson-operation">Operation</label><input id="lesson-operation" placeholder="generated-doc-update" data-lesson-required required /></div><div class="field"><label for="lesson-error-signature">Error signature</label><input id="lesson-error-signature" placeholder="syntax error" data-lesson-required required /></div></div><div class="control-row"><div class="field"><label for="lesson-failed-action">Failed action</label><input id="lesson-failed-action" placeholder="command or attempted step" data-lesson-required required /></div><div class="field"><label for="lesson-root-cause">Root cause</label><input id="lesson-root-cause" placeholder="why it failed" data-lesson-required required /></div><div class="field"><label for="lesson-fix">Fix</label><input id="lesson-fix" placeholder="working correction" data-lesson-required required /></div><div class="field"><label for="lesson-prevention">Prevention</label><input id="lesson-prevention" placeholder="how to avoid repeat" data-lesson-required required /></div></div><div class="control-row"><div class="field"><label for="lesson-applies-to">Applies to</label><input id="lesson-applies-to" placeholder="web, skills" /></div><div class="field"><label for="lesson-verified-by">Verified by</label><input id="lesson-verified-by" placeholder="test, precommit" /></div><button class="text-button" id="lesson-add" type="button">Add Lesson</button></div></div></section>
88
+ ${renderAdoptionGuideSections()}
89
+ ${renderDashboardSections()}
90
+ <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="panel" aria-labelledby="task-detail-heading"><h2 id="task-detail-heading">Task Detail</h2><div class="control-row"><div class="field"><label for="task-detail-select">Task</label><select id="task-detail-select"></select></div><button class="text-button secondary" id="task-detail-refresh" type="button">Refresh Detail</button></div><div id="task-detail"></div></section><section class="grid"><div class="panel"><h2>Cost</h2><ul class="list" id="cost-view"></ul></div><div class="panel"><h2>Add Task</h2><div class="control-row"><div class="field"><label for="task-id">ID</label><input id="task-id" placeholder="WEB-001" /></div><div class="field"><label for="task-title">Title</label><input id="task-title" placeholder="Implement workflow task" /></div><div class="field"><label for="task-owner">Owner</label><select id="task-owner"></select></div><div class="field"><label for="task-paths">Paths</label><input id="task-paths" placeholder="src/web-api.ts, test/orchestra.test.js" /></div></div><div class="control-row"><div class="field"><label for="task-acceptance">Acceptance</label><input id="task-acceptance" placeholder="comma separated criteria" /></div><div class="field"><label for="task-risks">Risks</label><input id="task-risks" placeholder="security, release" /></div><button class="text-button" id="task-add" type="button">Add Task</button></div></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>Workflow Runs</h2><div class="control-row"><div class="field"><label for="workflow-task">Task</label><select id="workflow-task"></select></div><div class="field"><label for="workflow-gates">Gates</label><select id="workflow-gates"><option>phase</option><option>none</option><option>all</option></select></div><div class="field"><label for="workflow-approver">Approver</label><input id="workflow-approver" value="web-console" /></div><button class="text-button" id="workflow-start" type="button">Start Workflow</button></div><div class="control-row"><div class="field"><label for="workflow-rationale">Gate rationale</label><input id="workflow-rationale" value="Approved from web console" /></div></div><ul class="list" id="workflow-runs"></ul></div></section><section class="grid"><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><div class="panel"><h2>Skills</h2><div class="control-row"><div class="field"><label for="skills-task">Task</label><select id="skills-task"></select></div><div class="field"><label for="skills-target">Target</label><select id="skills-target"><option>generic</option><option>claude</option><option>cursor</option><option>codex</option><option>vscode</option><option>windsurf</option></select></div><button class="text-button" id="skills-plan" type="button">Plan</button><button class="text-button" id="skills-render" type="button">Render</button></div><ul class="list" id="skills-plan-list"></ul></div></section><section class="grid"><div class="panel"><h2>Skill Catalog</h2><ul class="list" id="skills-list"></ul><h2>Render Preview</h2><pre class="preview" id="skills-preview">No skill render yet.</pre></div><div class="panel"><h2>Source of Truth</h2><ul class="list" id="sources-list"></ul></div></section><section class="grid"><div class="panel"><h2>Lessons Learned</h2><div class="control-row"><div class="field"><label for="lesson-promote-target">Promote to</label><select id="lesson-promote-target"><option>doc</option><option>skill</option><option>rule</option></select></div><div class="field"><label for="lesson-promote-filter">Filter</label><input id="lesson-promote-filter" placeholder="operation or error" /></div><button class="text-button" id="lesson-promote" type="button">Promote</button></div><ul class="list" id="lesson-promotion-result"></ul><ul class="list" id="lessons-list"></ul></div><div class="panel"><h2>Add Lesson</h2><div class="control-row"><div class="field"><label for="lesson-task">Task</label><select id="lesson-task"></select></div><div class="field"><label for="lesson-actor">Actor</label><input id="lesson-actor" value="parent" data-lesson-required required /></div><div class="field"><label for="lesson-operation">Operation</label><input id="lesson-operation" placeholder="generated-doc-update" data-lesson-required required /></div><div class="field"><label for="lesson-error-signature">Error signature</label><input id="lesson-error-signature" placeholder="syntax error" data-lesson-required required /></div></div><div class="control-row"><div class="field"><label for="lesson-failed-action">Failed action</label><input id="lesson-failed-action" placeholder="command or attempted step" data-lesson-required required /></div><div class="field"><label for="lesson-root-cause">Root cause</label><input id="lesson-root-cause" placeholder="why it failed" data-lesson-required required /></div><div class="field"><label for="lesson-fix">Fix</label><input id="lesson-fix" placeholder="working correction" data-lesson-required required /></div><div class="field"><label for="lesson-prevention">Prevention</label><input id="lesson-prevention" placeholder="how to avoid repeat" data-lesson-required required /></div></div><div class="control-row"><div class="field"><label for="lesson-applies-to">Applies to</label><input id="lesson-applies-to" placeholder="web, skills" /></div><div class="field"><label for="lesson-verified-by">Verified by</label><input id="lesson-verified-by" placeholder="test, precommit" /></div><button class="text-button" id="lesson-add" type="button">Add Lesson</button></div></div></section>
71
91
  </main>
72
92
  </div>
73
93
  <script src="/vendor/chart.umd.js"></script>
@@ -1 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0EX,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"web-console.js","sourceRoot":"","sources":["../src/web-console.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAqFT,2BAA2B,EAAE;UAC7B,uBAAuB,EAAE;;;;;;;QAO3B,CAAC;AACT,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ApprovalDecisionInput, ApprovalRecord, BudgetFallbackProposal, WorkflowGateApprovalInput, WorkflowGateApprovalResult } from "./types.js";
2
+ export declare function listApprovals(taskId?: string, root?: string): Promise<ApprovalRecord[]>;
3
+ export declare function approveWorkflowGate(input: WorkflowGateApprovalInput, root?: string): Promise<WorkflowGateApprovalResult>;
4
+ export declare function showApproval(id: string, root?: string): Promise<ApprovalRecord & {
5
+ content: string;
6
+ }>;
7
+ export declare function approveApproval(input: ApprovalDecisionInput, root?: string): Promise<ApprovalRecord>;
8
+ export declare function rejectApproval(input: ApprovalDecisionInput, root?: string): Promise<ApprovalRecord>;
9
+ export declare function findStoredApprovalForProposal(proposal: BudgetFallbackProposal, root: string): Promise<ApprovalRecord | undefined>;
@@ -0,0 +1,126 @@
1
+ import path from "node:path";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { removeUndefined } from "./command-utils.js";
4
+ import { exists, resolveWorkflowPath } from "./fs-utils.js";
5
+ import { appendEvent, readEvents } from "./workspace.js";
6
+ import { persistRun, readAutonomousRun } from "./autonomous-run-store.js";
7
+ import { approvalArtifactForId, approvalEventsForArtifact, approvalRecordForArtifact, gateApprovalRecords, gateIdForPhase, } from "./workflow-approval-utils.js";
8
+ export async function listApprovals(taskId, root = process.cwd()) {
9
+ const approvalDir = resolveWorkflowPath(root, "approvals");
10
+ const fileNames = (await exists(approvalDir))
11
+ ? (await readdir(approvalDir)).filter((fileName) => fileName.endsWith(".md"))
12
+ : [];
13
+ const events = await readEvents(root);
14
+ const records = fileNames.map((fileName) => approvalRecordForArtifact(path.join(".agent-workflow", "approvals", fileName), events));
15
+ records.push(...gateApprovalRecords(events));
16
+ const filtered = taskId
17
+ ? records.filter((record) => record.taskId === taskId)
18
+ : records;
19
+ return filtered.sort((left, right) => left.id.localeCompare(right.id));
20
+ }
21
+ export async function approveWorkflowGate(input, root = process.cwd()) {
22
+ const run = await readAutonomousRun(root, input.runId);
23
+ if (!run) {
24
+ throw new Error(`workflow run not found: ${input.runId}`);
25
+ }
26
+ const phaseIndex = run.phases.findLastIndex((phase) => phase.status === "gate_paused");
27
+ if (phaseIndex < 0) {
28
+ throw new Error(`workflow run ${input.runId} has no paused gate`);
29
+ }
30
+ const phase = run.phases[phaseIndex];
31
+ const gateId = phase.gateId ?? gateIdForPhase(run, phaseIndex);
32
+ if (input.gateId !== gateId) {
33
+ throw new Error(`wrong gate id: ${input.gateId}. Expected gate: ${gateId}`);
34
+ }
35
+ if (phase.approvedBy && phase.approvedAt) {
36
+ return {
37
+ run,
38
+ gateId,
39
+ approver: phase.approvedBy,
40
+ approvedAt: phase.approvedAt,
41
+ alreadyApproved: true,
42
+ };
43
+ }
44
+ const approvedAt = new Date().toISOString();
45
+ const approvedPhase = {
46
+ ...phase,
47
+ gateId,
48
+ approvedBy: input.approver,
49
+ approvedAt,
50
+ approvalRationale: input.rationale,
51
+ };
52
+ const updatedRun = {
53
+ ...run,
54
+ phases: run.phases.map((candidate, index) => index === phaseIndex ? approvedPhase : candidate),
55
+ updatedAt: approvedAt,
56
+ };
57
+ await persistRun(root, updatedRun);
58
+ await appendEvent(root, removeUndefined({
59
+ type: "GATE_APPROVED",
60
+ taskId: run.taskId,
61
+ actor: "parent",
62
+ summary: `Gate approved: ${gateId}`,
63
+ artifacts: phase.reviewArtifact ? [phase.reviewArtifact] : undefined,
64
+ metadata: {
65
+ runId: run.id,
66
+ gateId,
67
+ approver: input.approver,
68
+ rationale: input.rationale,
69
+ approvedAt,
70
+ },
71
+ }));
72
+ return {
73
+ run: updatedRun,
74
+ gateId,
75
+ approver: input.approver,
76
+ approvedAt,
77
+ alreadyApproved: false,
78
+ };
79
+ }
80
+ export async function showApproval(id, root = process.cwd()) {
81
+ const record = await getApprovalRecord(id, root);
82
+ const content = await readFile(path.join(root, record.artifact), "utf8");
83
+ return { ...record, content };
84
+ }
85
+ export async function approveApproval(input, root = process.cwd()) {
86
+ return recordApprovalDecision(input, "approved", root);
87
+ }
88
+ export async function rejectApproval(input, root = process.cwd()) {
89
+ return recordApprovalDecision(input, "rejected", root);
90
+ }
91
+ async function getApprovalRecord(id, root) {
92
+ const artifact = approvalArtifactForId(id);
93
+ if (!(await exists(path.join(root, artifact)))) {
94
+ throw new Error(`unknown approval: ${id}`);
95
+ }
96
+ const events = await readEvents(root);
97
+ return approvalRecordForArtifact(artifact, events);
98
+ }
99
+ export async function findStoredApprovalForProposal(proposal, root) {
100
+ if (!proposal.artifact) {
101
+ return undefined;
102
+ }
103
+ const events = await readEvents(root);
104
+ return approvalRecordForArtifact(proposal.artifact, events);
105
+ }
106
+ async function recordApprovalDecision(input, status, root) {
107
+ const current = await getApprovalRecord(input.id, root);
108
+ const requested = approvalEventsForArtifact(await readEvents(root), current.artifact).find((event) => event.type === "BUDGET_ESCALATION_REQUESTED");
109
+ await appendEvent(root, removeUndefined({
110
+ type: status === "approved"
111
+ ? "BUDGET_ESCALATION_APPROVED"
112
+ : "BUDGET_ESCALATION_REJECTED",
113
+ taskId: current.taskId,
114
+ actor: "parent",
115
+ summary: `Budget escalation ${status}: ${input.id}`,
116
+ artifacts: [current.artifact],
117
+ metadata: {
118
+ approvalId: input.id,
119
+ proposal: requested?.metadata.proposal,
120
+ approver: input.approver,
121
+ rationale: input.rationale,
122
+ },
123
+ }));
124
+ return getApprovalRecord(input.id, root);
125
+ }
126
+ //# sourceMappingURL=workflow-approval-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-approval-service.js","sourceRoot":"","sources":["../src/workflow-approval-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ApprovalRecord, EventEntry } from "./types.js";
2
+ export declare function approvalRecordForArtifact(artifact: string, events: EventEntry[]): ApprovalRecord;
3
+ export declare function gateApprovalRecords(events: EventEntry[]): ApprovalRecord[];
4
+ export declare function gateIdForPhase(run: {
5
+ phases: Array<{
6
+ phase: string;
7
+ }>;
8
+ }, phaseIndex: number): string;
9
+ export declare function approvalEventsForArtifact(events: EventEntry[], artifact: string): EventEntry[];
10
+ export declare function approvalArtifactForId(id: string): string;
@@ -0,0 +1,82 @@
1
+ import path from "node:path";
2
+ import { removeUndefined } from "./command-utils.js";
3
+ import { AUTONOMOUS_PHASE_SEQUENCE } from "./autonomous-workflow-constants.js";
4
+ export function approvalRecordForArtifact(artifact, events) {
5
+ const id = approvalIdForArtifact(artifact);
6
+ const related = approvalEventsForArtifact(events, artifact);
7
+ const requested = related.find((event) => event.type === "BUDGET_ESCALATION_REQUESTED");
8
+ const decision = [...related]
9
+ .reverse()
10
+ .find((event) => ["BUDGET_ESCALATION_APPROVED", "BUDGET_ESCALATION_REJECTED"].includes(event.type));
11
+ const status = decisionStatus(decision);
12
+ return removeUndefined({
13
+ id,
14
+ taskId: String(requested?.taskId ?? decision?.taskId ?? "") || undefined,
15
+ artifact,
16
+ status,
17
+ summary: requested?.summary ?? `Approval proposal ${id}`,
18
+ requestedAt: requested?.timestamp,
19
+ decidedAt: decision?.timestamp,
20
+ approver: typeof decision?.metadata.approver === "string"
21
+ ? decision.metadata.approver
22
+ : undefined,
23
+ rationale: typeof decision?.metadata.rationale === "string"
24
+ ? decision.metadata.rationale
25
+ : undefined,
26
+ });
27
+ }
28
+ export function gateApprovalRecords(events) {
29
+ return events
30
+ .filter((event) => event.type === "GATE_APPROVED")
31
+ .map((event) => {
32
+ const runId = typeof event.metadata.runId === "string" ? event.metadata.runId : "run";
33
+ const gateId = typeof event.metadata.gateId === "string"
34
+ ? event.metadata.gateId
35
+ : "gate";
36
+ return removeUndefined({
37
+ id: `gate-${runId}-${gateId}`.replace(/[^a-zA-Z0-9._-]/g, "-"),
38
+ taskId: event.taskId ?? undefined,
39
+ artifact: event.artifacts?.[0] ?? "events.jsonl",
40
+ status: "approved",
41
+ summary: event.summary,
42
+ requestedAt: event.timestamp,
43
+ decidedAt: typeof event.metadata.approvedAt === "string"
44
+ ? event.metadata.approvedAt
45
+ : event.timestamp,
46
+ approver: typeof event.metadata.approver === "string"
47
+ ? event.metadata.approver
48
+ : undefined,
49
+ rationale: typeof event.metadata.rationale === "string"
50
+ ? event.metadata.rationale
51
+ : undefined,
52
+ });
53
+ });
54
+ }
55
+ export function gateIdForPhase(run, phaseIndex) {
56
+ const phase = run.phases[phaseIndex]?.phase;
57
+ const sequenceIndex = AUTONOMOUS_PHASE_SEQUENCE.findIndex((candidate) => candidate.phase === phase);
58
+ const next = AUTONOMOUS_PHASE_SEQUENCE[sequenceIndex + 1]?.phase ?? "end";
59
+ return `${phase}->${next}`;
60
+ }
61
+ export function approvalEventsForArtifact(events, artifact) {
62
+ return events.filter((event) => event.artifacts?.includes(artifact));
63
+ }
64
+ function decisionStatus(decision) {
65
+ if (decision?.type === "BUDGET_ESCALATION_APPROVED") {
66
+ return "approved";
67
+ }
68
+ if (decision?.type === "BUDGET_ESCALATION_REJECTED") {
69
+ return "rejected";
70
+ }
71
+ return "pending";
72
+ }
73
+ export function approvalArtifactForId(id) {
74
+ if (!/^[a-zA-Z0-9._-]+$/.test(id)) {
75
+ throw new Error(`invalid approval id: ${id}`);
76
+ }
77
+ return path.join(".agent-workflow", "approvals", `${id}.md`);
78
+ }
79
+ function approvalIdForArtifact(artifact) {
80
+ return path.basename(artifact, ".md");
81
+ }
82
+ //# sourceMappingURL=workflow-approval-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-approval-utils.js","sourceRoot":"","sources":["../src/workflow-approval-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { BudgetLimit, BudgetPolicy, BudgetThresholdWarning, BudgetViolation, ModelProvenanceRecord, UsageBreakdown, UsageReport } from "./types.js";
2
+ export declare function aggregateUsage(key: string, records: ModelProvenanceRecord[]): UsageBreakdown;
3
+ export declare function aggregateUsageBy(records: ModelProvenanceRecord[], keyFor: (record: ModelProvenanceRecord) => string): UsageBreakdown[];
4
+ export declare function budgetViolations(scope: string, usage: UsageBreakdown, budget: BudgetLimit): BudgetViolation[];
5
+ export declare function projectUsageCost(usage: UsageReport, ownerRole: string, estimatedCostUsd: number): UsageReport;
6
+ export declare function emptyUsageBreakdown(key: string): UsageBreakdown;
7
+ export declare function budgetEstimateWarningsForBudgets(taskId: string, ownerRole: string, usage: UsageReport, budgets: BudgetPolicy | undefined): BudgetThresholdWarning[];
@@ -0,0 +1,96 @@
1
+ export function aggregateUsage(key, records) {
2
+ const inputTokens = records.reduce((sum, record) => sum + record.inputTokens, 0);
3
+ const outputTokens = records.reduce((sum, record) => sum + record.outputTokens, 0);
4
+ const estimatedCostUsd = records.reduce((sum, record) => sum + record.estimatedCostUsd, 0);
5
+ return {
6
+ key,
7
+ requests: records.length,
8
+ inputTokens,
9
+ outputTokens,
10
+ totalTokens: inputTokens + outputTokens,
11
+ estimatedCostUsd,
12
+ };
13
+ }
14
+ export function aggregateUsageBy(records, keyFor) {
15
+ const groups = new Map();
16
+ for (const record of records) {
17
+ const key = keyFor(record);
18
+ groups.set(key, [...(groups.get(key) ?? []), record]);
19
+ }
20
+ return [...groups.entries()].map(([key, group]) => aggregateUsage(key, group));
21
+ }
22
+ export function budgetViolations(scope, usage, budget) {
23
+ return [
24
+ budgetViolation(scope, "requests", usage.requests, budget.maxRequests),
25
+ budgetViolation(scope, "inputTokens", usage.inputTokens, budget.maxInputTokens),
26
+ budgetViolation(scope, "outputTokens", usage.outputTokens, budget.maxOutputTokens),
27
+ budgetViolation(scope, "totalTokens", usage.totalTokens, budget.maxTotalTokens),
28
+ budgetViolation(scope, "estimatedCostUsd", usage.estimatedCostUsd, budget.maxEstimatedCostUsd),
29
+ ].filter((violation) => Boolean(violation));
30
+ }
31
+ export function projectUsageCost(usage, ownerRole, estimatedCostUsd) {
32
+ const byRole = [...usage.byRole];
33
+ const roleIndex = byRole.findIndex((entry) => entry.key === ownerRole);
34
+ if (roleIndex >= 0) {
35
+ const roleUsage = byRole[roleIndex] ?? emptyUsageBreakdown(ownerRole);
36
+ byRole[roleIndex] = addEstimatedCost(roleUsage, estimatedCostUsd);
37
+ }
38
+ else {
39
+ byRole.push(addEstimatedCost(emptyUsageBreakdown(ownerRole), estimatedCostUsd));
40
+ }
41
+ return {
42
+ ...usage,
43
+ totals: addEstimatedCost(usage.totals, estimatedCostUsd),
44
+ byRole,
45
+ };
46
+ }
47
+ export function emptyUsageBreakdown(key) {
48
+ return {
49
+ key,
50
+ requests: 0,
51
+ inputTokens: 0,
52
+ outputTokens: 0,
53
+ totalTokens: 0,
54
+ estimatedCostUsd: 0,
55
+ };
56
+ }
57
+ export function budgetEstimateWarningsForBudgets(taskId, ownerRole, usage, budgets) {
58
+ const warnings = [];
59
+ pushCostWarning(warnings, "defaults", usage.totals, budgets?.defaults);
60
+ pushCostWarning(warnings, `task:${taskId}`, usage.totals, budgets?.byTask?.[taskId]);
61
+ pushCostWarning(warnings, `role:${ownerRole}`, usage.byRole.find((roleUsage) => roleUsage.key === ownerRole) ??
62
+ emptyUsageBreakdown(ownerRole), budgets?.byRole?.[ownerRole]);
63
+ return warnings;
64
+ }
65
+ function budgetViolation(scope, metric, actual, limit) {
66
+ if (limit === undefined || actual <= limit) {
67
+ return undefined;
68
+ }
69
+ return {
70
+ scope,
71
+ metric,
72
+ actual,
73
+ limit,
74
+ };
75
+ }
76
+ function addEstimatedCost(usage, estimatedCostUsd) {
77
+ return {
78
+ ...usage,
79
+ estimatedCostUsd: usage.estimatedCostUsd + estimatedCostUsd,
80
+ };
81
+ }
82
+ function pushCostWarning(warnings, scope, usage, budget) {
83
+ const thresholdPercent = 80;
84
+ const limit = budget?.maxEstimatedCostUsd;
85
+ if (limit !== undefined &&
86
+ usage.estimatedCostUsd >= limit * (thresholdPercent / 100)) {
87
+ warnings.push({
88
+ scope,
89
+ metric: "estimatedCostUsd",
90
+ actual: usage.estimatedCostUsd,
91
+ limit,
92
+ thresholdPercent,
93
+ });
94
+ }
95
+ }
96
+ //# sourceMappingURL=workflow-budget-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-budget-utils.js","sourceRoot":"","sources":["../src/workflow-budget-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type NotificationTransports } from "./notifications.js";
2
+ import type { ArtifactResult, EventEntry, EvidenceInput, PlaywrightEvidenceInput, ReviewInput } from "./types.js";
3
+ export declare function recordReview(input: ReviewInput, root?: string, notificationTransports?: NotificationTransports): Promise<ArtifactResult>;
4
+ export declare function listReviews(taskId?: string, root?: string): Promise<EventEntry[]>;
5
+ export declare function addEvidence(input: EvidenceInput, root?: string): Promise<ArtifactResult>;
6
+ export declare function listEvidence(taskId?: string, root?: string): Promise<EventEntry[]>;
7
+ export declare function addPlaywrightEvidence(input: PlaywrightEvidenceInput, root?: string): Promise<ArtifactResult>;
@@ -0,0 +1,100 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import path from "node:path";
3
+ import { removeUndefined } from "./command-utils.js";
4
+ import { exists } from "./fs-utils.js";
5
+ import { appendEvent, loadWorkspace, readEvents, writeArtifact, } from "./workspace.js";
6
+ import { normalizeEvidenceType, normalizeReviewRole, validateEvidenceInput, validateReviewInput, } from "./validation.js";
7
+ import { notifyWorkflowLifecycle, } from "./notifications.js";
8
+ export async function recordReview(input, root = process.cwd(), notificationTransports = {}) {
9
+ const workspace = await loadWorkspace(root);
10
+ const reviewInput = removeUndefined({
11
+ ...input,
12
+ role: normalizeReviewRole(input.role, workspace.roleIds) ?? input.role,
13
+ });
14
+ validateReviewInput(reviewInput, workspace.roleIds);
15
+ const fileName = `${reviewInput.task}-${reviewInput.role}-review.md`;
16
+ const content = [
17
+ `# Review ${reviewInput.task}: ${reviewInput.role}`,
18
+ "",
19
+ `- Result: ${reviewInput.result}`,
20
+ `- Severity: ${reviewInput.severity}`,
21
+ `- Findings: ${reviewInput.findings}`,
22
+ `- Recommendation: ${reviewInput.recommendation}`,
23
+ "",
24
+ ].join("\n");
25
+ const artifact = await writeArtifact(root, "reviews", fileName, content);
26
+ await appendEvent(root, {
27
+ type: "REVIEW_RECORDED",
28
+ taskId: reviewInput.task,
29
+ actor: reviewInput.role,
30
+ summary: `Review recorded: ${reviewInput.result}`,
31
+ artifacts: [artifact],
32
+ metadata: { result: reviewInput.result, severity: reviewInput.severity },
33
+ });
34
+ if (reviewInput.result === "block" && reviewInput.severity === "critical") {
35
+ await notifyWorkflowLifecycle({
36
+ root,
37
+ taskId: reviewInput.task,
38
+ kind: "critical_blocking_review",
39
+ actor: reviewInput.role,
40
+ detail: reviewInput.findings,
41
+ artifact,
42
+ idempotencyKey: `critical_blocking_review:${reviewInput.task}:${artifact}`,
43
+ }, notificationTransports);
44
+ }
45
+ return { artifact, content };
46
+ }
47
+ export async function listReviews(taskId, root = process.cwd()) {
48
+ return filterEvents("REVIEW_RECORDED", taskId, root);
49
+ }
50
+ export async function addEvidence(input, root = process.cwd()) {
51
+ const evidenceInput = removeUndefined({
52
+ ...input,
53
+ type: normalizeEvidenceType(input.type) ?? input.type,
54
+ });
55
+ const workspace = await loadWorkspace(root);
56
+ validateEvidenceInput(evidenceInput, workspace.roleIds);
57
+ if (typeof evidenceInput.path === "string" &&
58
+ !(await exists(path.resolve(root, evidenceInput.path)))) {
59
+ throw new Error(`evidence path does not exist: ${evidenceInput.path}`);
60
+ }
61
+ const fileName = `${evidenceInput.task}-${Date.now()}-${randomUUID()}-${evidenceInput.type}.md`;
62
+ const content = [
63
+ `# Evidence ${evidenceInput.task}: ${evidenceInput.type}`,
64
+ "",
65
+ `- Role: ${evidenceInput.role}`,
66
+ `- Summary: ${evidenceInput.summary}`,
67
+ `- Path: ${evidenceInput.path ?? "not applicable"}`,
68
+ `- Command: ${evidenceInput.command ?? "not applicable"}`,
69
+ `- Exit code: ${evidenceInput.exitCode ?? "not applicable"}`,
70
+ "",
71
+ ].join("\n");
72
+ const artifact = await writeArtifact(root, "evidence", fileName, content);
73
+ await appendEvent(root, {
74
+ type: "EVIDENCE_ADDED",
75
+ taskId: evidenceInput.task,
76
+ actor: evidenceInput.role,
77
+ summary: evidenceInput.summary,
78
+ artifacts: [artifact],
79
+ metadata: { type: evidenceInput.type },
80
+ });
81
+ return { artifact, content };
82
+ }
83
+ export async function listEvidence(taskId, root = process.cwd()) {
84
+ return filterEvents("EVIDENCE_ADDED", taskId, root);
85
+ }
86
+ export async function addPlaywrightEvidence(input, root = process.cwd()) {
87
+ return addEvidence(removeUndefined({
88
+ task: input.task,
89
+ role: "qa",
90
+ type: input.kind,
91
+ summary: input.summary,
92
+ path: input.path,
93
+ command: input.runId,
94
+ }), root);
95
+ }
96
+ async function filterEvents(type, taskId, root) {
97
+ const events = (await readEvents(root)).filter((event) => event.type === type);
98
+ return taskId ? events.filter((event) => event.taskId === taskId) : events;
99
+ }
100
+ //# sourceMappingURL=workflow-evidence-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-evidence-service.js","sourceRoot":"","sources":["../src/workflow-evidence-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { CliIo, CliOptions } from "./types.js";
2
+ export declare function workflowRunCommand(options: CliOptions, io: CliIo): Promise<void>;
3
+ export declare function workflowRunListCommand(options: CliOptions, io: CliIo): Promise<void>;
4
+ export declare function workflowCancelCommand(options: CliOptions, io: CliIo): Promise<void>;
5
+ export declare function workflowGateApproveCommand(options: CliOptions, io: CliIo): Promise<void>;
6
+ export declare function workflowClarifyCommand(options: CliOptions, io: CliIo): Promise<void>;
7
+ export declare function workflowClarifyRespondCommand(options: CliOptions, io: CliIo): Promise<void>;
8
+ export declare function workflowClarifyListCommand(options: CliOptions, io: CliIo): Promise<void>;