@worca/app 0.1.0 → 1.0.0-rc.1

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.
@@ -46,7 +46,7 @@
46
46
  <div class="nav-sect">Build</div>
47
47
  <button type="button" data-nav="composer">
48
48
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="9" width="6" height="6" rx="1.6"></rect><rect x="15" y="4" width="6" height="5.5" rx="1.6"></rect><rect x="15" y="14.5" width="6" height="5.5" rx="1.6"></rect><path d="M9 12h2.5M11.5 12V6.8H15M11.5 12v5.3H15"></path></svg>
49
- <span>Pipeline Composer</span>
49
+ <span>Workflow Composer</span>
50
50
  </button>
51
51
  <button type="button" data-nav="agents">
52
52
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.2"></circle><path d="M3.5 19c.6-3 2.8-4.6 5.5-4.6S13.9 16 14.5 19"></path><circle cx="17.5" cy="9.5" r="2.4"></circle><path d="M15.5 14.6c2.7 0 4.4 1.4 5 4.4"></path></svg>
@@ -193,32 +193,30 @@
193
193
  <small class="hint">Leave empty and Worca will propose one.</small>
194
194
  </div>
195
195
 
196
- <!-- Task source switch and the workflow that will act on it, on one
197
- row same proportion as Target/Project above. The panes below
198
- span the full width. -->
199
- <div class="split-row">
200
- <div class="field field-compact">
201
- <label>Task source</label>
202
- <div class="seg" id="source-seg">
203
- <button type="button" data-src="prompt" class="on" aria-pressed="true">Prompt</button>
204
- <button type="button" data-src="markdown" aria-pressed="false">Markdown</button>
205
- </div>
206
- <!-- hidden radios kept as the source of truth read at submit -->
207
- <input type="radio" name="source" value="prompt" checked hidden />
208
- <input type="radio" name="source" value="markdown" hidden />
196
+ <!-- Workflow picker (Default + saved). app.js populates from GET
197
+ /api/workflows. Choosing a workflow is a run decision, so it
198
+ stays here; tuning its agents is not, and lives in Advanced.
199
+ Own full-width line ABOVE the task source: the workflow frames
200
+ what the run does, the source only says how the task arrives. -->
201
+ <div class="field field-compact">
202
+ <label for="workflowSelect">Workflow</label>
203
+ <div class="select-wrap">
204
+ <select id="workflowSelect" class="select" aria-label="Workflow">
205
+ <option value="wf_default">Default</option>
206
+ </select>
209
207
  </div>
208
+ </div>
210
209
 
211
- <!-- Workflow picker (Default + saved). app.js populates from GET
212
- /api/workflows. Choosing a workflow is a run decision, so it
213
- stays here; tuning its agents is not, and lives in Advanced. -->
214
- <div class="field field-compact">
215
- <label for="workflowSelect">Workflow</label>
216
- <div class="select-wrap">
217
- <select id="workflowSelect" class="select" aria-label="Workflow">
218
- <option value="wf_default">Default</option>
219
- </select>
220
- </div>
210
+ <!-- Task source switch; the panes below span the full width. -->
211
+ <div class="field field-compact">
212
+ <label>Task source</label>
213
+ <div class="seg" id="source-seg">
214
+ <button type="button" data-src="prompt" class="on" aria-pressed="true">Prompt</button>
215
+ <button type="button" data-src="markdown" aria-pressed="false">Markdown</button>
221
216
  </div>
217
+ <!-- hidden radios kept as the source of truth read at submit -->
218
+ <input type="radio" name="source" value="prompt" checked hidden />
219
+ <input type="radio" name="source" value="markdown" hidden />
222
220
  </div>
223
221
 
224
222
  <div class="field">
@@ -244,7 +242,8 @@
244
242
  <div id="config-error" class="hint" style="margin:-6px 0 14px;color:var(--red-ink)" hidden></div>
245
243
 
246
244
  <!-- Extra files belong WITH the task: they are more of the same
247
- input, just as files. -->
245
+ input, just as files. Selected files render as removable
246
+ pills below the picker (app.js#renderExtrasPills). -->
248
247
  <div class="field field-compact">
249
248
  <label>Extra files <span class="opt">(optional)</span></label>
250
249
  <div class="file">
@@ -252,6 +251,7 @@
252
251
  <span class="state" id="extrasNote">Leave empty and the run gets no extra files.</span>
253
252
  <input id="extras" type="file" multiple hidden />
254
253
  </div>
254
+ <div id="extrasPills" class="extras-pills" hidden></div>
255
255
  </div>
256
256
 
257
257
  <!-- Branch pair: one decision (from → into), so one compact row. -->
@@ -344,146 +344,308 @@
344
344
 
345
345
  <!-- ===== VIEW: RUNNING ===== -->
346
346
  <section class="view hidden" data-view="running">
347
+ <div class="run-shell" id="run-shell">
348
+ <div class="run-screen run-screen-list">
347
349
  <div class="topbar">
348
350
  <div>
349
351
  <h1>Running</h1>
350
352
  <div class="sub" id="running-sub">0 pipelines executing · 0 need your input</div>
351
353
  </div>
352
354
  <span class="pill-run amber hidden" id="running-status-pill" style="box-shadow:var(--shadow-soft)"><span class="pdot"></span> 0 needs input</span>
355
+ <div class="run-density" role="group" aria-label="List density">
356
+ <button type="button" class="rc-dseg" data-density="compact" aria-pressed="false" title="Compact — three runs per screen">
357
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="3" y="5" width="18" height="3" rx="1.5"></rect><rect x="3" y="10.5" width="18" height="3" rx="1.5"></rect><rect x="3" y="16" width="18" height="3" rx="1.5"></rect></svg>
358
+ </button>
359
+ <button type="button" class="rc-dseg" data-density="detailed" aria-pressed="true" title="Detailed — one run with graph and log">
360
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="2.5"></rect><path d="M6.5 8.5h7" stroke-linecap="round"></path><path d="M6.5 12.5h11" stroke-linecap="round" opacity=".45"></path><path d="M6.5 16h8" stroke-linecap="round" opacity=".45"></path></svg>
361
+ </button>
362
+ </div>
363
+ </div>
364
+
365
+ <!-- Inert status line (design D14): the per-card question pills are the
366
+ affordance; this only says how many runs are parked. No listener,
367
+ no role=button, no tabindex. -->
368
+ <div class="run-ask-banner" hidden>
369
+ <span class="rab-mark" aria-hidden="true">?</span>
370
+ <span class="rab-text"></span>
353
371
  </div>
354
372
 
355
373
  <div class="run-list" id="run-list"></div>
356
374
 
357
375
  <!-- clone target for one run card (Task 3 fills it) -->
358
376
  <template id="run-card-tpl">
359
- <section class="card run-card" data-run-id="">
360
- <div class="run-top">
361
- <div><div class="run-title"></div><div class="run-meta"><span class="rm-text"></span><span class="run-time mono"></span><span class="run-cost mono"></span></div></div>
362
- <span class="pill-run"><span class="pdot"></span><span class="pill-text"></span></span>
363
- </div>
364
- <div class="run-flow-wrap"><div class="run-flow"></div></div>
365
- <div class="run-foot"><span class="chip"></span><button type="button" class="btn-resume sm" title="Resume — restart this paused pipeline where it left off" hidden><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5l12 7-12 7z"></path></svg> Resume</button><button type="button" class="btn-pause sm" title="Pause — gracefully stop the session so it can be resumed"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg> Pause</button><button type="button" class="btn-stop sm"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg> Stop</button></div>
366
- <div class="cost-banner" hidden></div>
367
- <div class="subs-bar" hidden>
368
- <button type="button" class="btn-subs" aria-expanded="false">
369
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="6" cy="6" r="2.4"/><circle cx="6" cy="18" r="2.4"/><circle cx="18" cy="12" r="2.4"/><path d="M8 6h5a3 3 0 0 1 3 3v0M8 18h5a3 3 0 0 0 3-3v0" stroke-linecap="round"/></svg>
370
- Agents
371
- <span class="sb-count grey"></span>
372
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
373
- </button>
374
- <div class="subs-panel" hidden></div>
377
+ <section class="card run-card" data-run-id="" data-density="detailed">
378
+ <div class="rc-head" role="button" tabindex="0">
379
+ <span class="rc-sic" role="img">
380
+ <svg class="sic sic-spin" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6"><path d="M12 3a9 9 0 1 0 9 9" stroke-linecap="round"></path></svg>
381
+ <svg class="sic sic-ask" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M9.1 9a3 3 0 1 1 4.6 2.5c-.9.6-1.7 1.2-1.7 2.3"></path><path d="M12 17.4h.01"></path></svg>
382
+ <svg class="sic sic-pause" width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg>
383
+ <svg class="sic sic-check" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
384
+ <svg class="sic sic-square" width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg>
385
+ <svg class="sic sic-bang" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M12 6.5v7"></path><path d="M12 17.4h.01"></path></svg>
386
+ </span>
387
+ <div class="rc-body">
388
+ <div class="rc-title run-title"></div>
389
+ <div class="rc-meta">
390
+ <span class="rc-status-word"></span>
391
+ <span class="rc-seg"><span class="rc-dot">·</span><span class="rm-text"></span></span>
392
+ <span class="rc-seg"><span class="rc-dot">·</span><span class="run-time mono"></span></span>
393
+ <span class="rc-seg"><span class="rc-dot">·</span><span class="run-cost mono"></span></span>
394
+ </div>
395
+ <span class="rc-branch mono" hidden>
396
+ <span class="rc-base" hidden></span>
397
+ <button type="button" class="rc-branch-copy" title="Copy branch name" aria-label="Copy branch name">
398
+ <span class="rc-branch-name"></span>
399
+ <svg class="ico-copy" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2.5"></rect><path d="M5 15H4.5A1.5 1.5 0 0 1 3 13.5v-9A1.5 1.5 0 0 1 4.5 3h9A1.5 1.5 0 0 1 15 4.5V5" stroke-linecap="round"></path></svg>
400
+ <svg class="ico-check" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M4 12.5l5.5 5.5L20 6.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
401
+ </button>
402
+ <!-- "Copied" feedback with NO JS: the CSS sibling of copyBranchToClipboard's
403
+ own 1200ms `.copied` window (app.js:3666-3672), exactly like .hd-copied
404
+ (index.html:501) / .hist-copied. No `hidden` attribute — that would
405
+ desync the a11y tree from the visual. -->
406
+ <span class="rc-copied">Copied</span>
407
+ </span>
408
+ </div>
409
+ <div class="rc-acts">
410
+ <span class="rc-qpill" hidden></span>
411
+ <button type="button" class="btn-resume" title="Resume — restart this paused pipeline where it left off" aria-label="Resume" hidden><svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5l12 7-12 7z"></path></svg></button>
412
+ <button type="button" class="btn-pause" title="Pause — gracefully stop the session so it can be resumed" aria-label="Pause"><svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg></button>
413
+ <button type="button" class="btn-stop" title="Stop this pipeline" aria-label="Stop"><svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg></button>
414
+ <button type="button" class="rc-open" title="Open run" aria-label="Open run"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M9 6l6 6-6 6" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>
415
+ </div>
375
416
  </div>
376
- <div class="run-log">
377
- <div class="run-log-head"><span class="ll-label">Live log</span><div class="log-filters"><select class="log-f log-f-source" title="Filter by source" aria-label="Filter by source"></select><select class="log-f log-f-level" title="Filter by level" aria-label="Filter by level"></select><select class="log-f log-f-step" title="Filter by step" aria-label="Filter by step"></select><select class="log-f log-f-cycle" title="Filter by cycle" aria-label="Filter by cycle"></select><input type="search" class="log-f log-search" placeholder="search" title="Search the log text" aria-label="Search the log text"><button type="button" class="log-f log-copy" title="Copy the visible log lines" aria-label="Copy the visible log lines">copy</button></div><div class="switch-row"><div class="switch on autoscroll" role="switch" aria-checked="true" tabindex="0"></div><span class="txt">Auto-scroll</span></div></div>
378
- <div class="log"></div>
417
+ <div class="rc-compact">
418
+ <span class="rc-step-chip"></span>
419
+ <span class="rc-step-name"></span>
420
+ <span class="rc-step-model mono" hidden></span>
379
421
  </div>
422
+ <div class="cost-banner" hidden></div>
423
+ <div class="rc-detailed">
424
+ <div class="run-flow-wrap"><div class="run-flow"></div></div>
425
+ <div class="run-log">
426
+ <div class="run-log-head"><span class="ll-label">Live log</span><div class="log-filters"><select class="log-f log-f-source" title="Filter by source" aria-label="Filter by source"></select><select class="log-f log-f-level" title="Filter by level" aria-label="Filter by level"></select><select class="log-f log-f-step" title="Filter by step" aria-label="Filter by step"></select><select class="log-f log-f-cycle" title="Filter by cycle" aria-label="Filter by cycle"></select><input type="search" class="log-f log-search" placeholder="search" title="Search the log text" aria-label="Search the log text"><button type="button" class="log-f log-copy" title="Copy the visible log lines" aria-label="Copy the visible log lines">copy</button></div><div class="switch-row"><div class="switch on autoscroll" role="switch" aria-checked="true" tabindex="0"></div><span class="txt">Auto-scroll</span></div></div>
427
+ <div class="log"></div>
428
+ </div>
429
+ </div><!-- /.rc-detailed -->
380
430
  <div class="qpanel hidden"></div>
381
431
  </section>
382
432
  </template>
433
+ </div>
434
+ <div class="run-screen run-screen-detail" id="run-detail" aria-hidden="true" inert></div>
435
+ </div>
436
+
437
+ <!-- clone target for the Running detail screen (#running/<runId>) -->
438
+ <template id="run-detail-tpl">
439
+ <div class="rd">
440
+ <header class="rd-header">
441
+ <div class="rd-row1">
442
+ <button type="button" class="rd-back btn-ghost" aria-label="Back to running list">
443
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M15 6l-6 6 6 6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
444
+ Back
445
+ </button>
446
+ <h1 class="rd-title"></h1>
447
+ <span class="rd-status pill-run"><span class="pdot"></span><span class="rd-status-word"></span></span>
448
+ </div>
449
+ <div class="rd-meta mono"></div>
450
+ <div class="rd-row3">
451
+ <span class="rd-base mono" hidden></span>
452
+ <button type="button" class="rd-branch-copy mono" hidden title="Copy branch name" aria-label="Copy branch name">
453
+ <span class="rd-branch-name"></span>
454
+ <svg class="ico-copy" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2.5"></rect><path d="M5 15H4.5A1.5 1.5 0 0 1 3 13.5v-9A1.5 1.5 0 0 1 4.5 3h9A1.5 1.5 0 0 1 15 4.5V5" stroke-linecap="round"></path></svg>
455
+ <svg class="ico-check" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M4 12.5l5.5 5.5L20 6.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
456
+ </button>
457
+ <!-- NO `hidden`: the caption is driven purely by the CSS sibling rule
458
+ off copyBranchToClipboard's own 1200ms `.copied` window
459
+ (app.js:3666-3672), exactly as .hd-copied does (index.html:501). -->
460
+ <span class="rd-copied">Copied</span>
461
+ <span class="rd-spacer"></span>
462
+ <!-- One control for Pause/Resume (spec §5.2 row 3). The label lives in
463
+ its own span so a busy state swaps only the word and the inline SVG
464
+ survives — the .hd-btn-label idiom. NB none of the three wired
465
+ handlers actually swaps the label today (pauseRun:7831-7850 and
466
+ stopRun:7806-7825 only set `disabled`; resumeRunFromCard:7920
467
+ replaces the whole textContent), so the span is for
468
+ paintRdHeader's Pause/Resume swap, not for a busy state. -->
469
+ <button type="button" class="rd-pause" data-action="pause" hidden>
470
+ <svg class="ico-pause" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg>
471
+ <svg class="ico-play" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5l12 7-12 7z"></path></svg>
472
+ <span class="rd-btn-label">Pause</span>
473
+ </button>
474
+ <button type="button" class="rd-stop" hidden>
475
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg>
476
+ <span class="rd-btn-label">Stop</span>
477
+ </button>
478
+ </div>
479
+ <!-- Inline error slot for failed actions, on the HEADER so it is never
480
+ pushed below the fold by the graph or a tab body (mirrors .hd-error). -->
481
+ <div class="rd-error" hidden></div>
482
+ </header>
483
+ <div class="rd-body">
484
+ <div class="rd-banners">
485
+ <div class="retained-banner" role="alert" hidden></div>
486
+ <button type="button" class="hist-discard btn-ghost" hidden>Discard worktree</button>
487
+ </div>
488
+ <div class="rd-graph"><div class="run-flow-wrap"><div class="run-flow"></div></div></div>
489
+ <div class="rd-questions" hidden><div class="qpanel hidden"></div></div>
490
+ <!-- C12: the tab engine does `screen.querySelector('.rd-tabs').innerHTML = ''`.
491
+ These two hosts MUST exist in the template or Task 7's tab bar
492
+ silently paints NOTHING (initDetailTabs returns early on a
493
+ missing host). Mirrors index.html:528-529 (.hd-tabs / .hd-sections),
494
+ including the role="tablist" the engine does NOT set itself. -->
495
+ <div class="rd-tabs" role="tablist"></div>
496
+ <div class="rd-sections"></div>
497
+ </div>
498
+ </div>
499
+ </template>
383
500
  </section>
384
501
  <!-- /view running -->
385
502
 
386
503
  <!-- ===== VIEW: HISTORY ===== -->
387
504
  <section class="view hidden" data-view="history">
388
- <div class="topbar">
389
- <div>
390
- <h1>History</h1>
391
- <div class="sub">Completed and stopped pipelines</div>
505
+ <div class="hist-shell" id="hist-shell">
506
+ <div class="hist-screen hist-screen-list">
507
+ <div class="topbar">
508
+ <div>
509
+ <h1>History</h1>
510
+ <div class="sub">Completed and stopped pipelines</div>
511
+ </div>
512
+ <button type="button" id="refresh-history" class="btn-ghost" style="padding:11px 20px">Refresh</button>
513
+ </div>
514
+
515
+ <!-- Project filter pills: "All Projects" + one per project that has history.
516
+ Built by renderHistoryPills() from the /api/history dataset. -->
517
+ <div class="hist-filter" id="historyFilter" aria-label="Filter history by project"></div>
518
+
519
+ <div class="run-list" id="history"></div>
520
+
521
+ <!-- clone target for one history card. The card is a LINK to the detail
522
+ screen (#history/<projectKey>/<id>) — it never expands in place. -->
523
+ <template id="hist-card-tpl">
524
+ <section class="card hist-card">
525
+ <div class="hist-head" role="button" tabindex="0">
526
+ <span class="hist-sic" role="img">
527
+ <svg class="sic sic-done" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
528
+ <svg class="sic sic-stopped" width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg>
529
+ <svg class="sic sic-paused" width="15" height="15" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg>
530
+ <svg class="sic sic-error" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M12 6.5v7"></path><path d="M12 17.4h.01"></path></svg>
531
+ </span>
532
+ <div class="h-meta">
533
+ <b></b>
534
+ <span class="badge hist-retained-badge" hidden>Work retained</span>
535
+ <div class="hist-meta-line">
536
+ <span class="hist-status-word"></span>
537
+ <!-- Plain <span>s: each segment is typed by its own
538
+ .hist-day/.hist-clock/.hist-time rule, not by an element
539
+ selector. -->
540
+ <span class="hm-seg hist-day-seg"><span class="hm-dot">·</span><span class="hist-day"></span></span>
541
+ <span class="hm-seg hist-clock-seg"><span class="hm-dot">·</span><span class="hist-clock"></span></span>
542
+ <span class="hm-seg hist-time-seg"><span class="hm-dot">·</span><span class="hist-time mono"></span></span>
543
+ <span class="hm-seg hist-total-seg"><span class="hm-dot">·</span><span class="hist-total mono"></span></span>
544
+ <span class="hist-diff-pill" hidden>
545
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M6 3h8l4 4v14H6z" stroke-linejoin="round"></path><path d="M14 3v4h4" stroke-linejoin="round"></path></svg>
546
+ <span class="hist-diff mono" aria-label="lines changed"></span>
547
+ <span class="hist-nodiff mono" hidden>no diff</span>
548
+ </span>
549
+ </div>
550
+ <span class="hist-branch mono" hidden>
551
+ <span class="hist-branch-src" hidden></span>
552
+ <svg class="hist-branch-arrow" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" aria-label="into" role="img" hidden><path d="M4 12h15M13 6l6 6-6 6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
553
+ <span class="hist-branch-dst"></span>
554
+ <button type="button" class="hist-branch-copy" title="Copy branch name" aria-label="Copy branch name">
555
+ <svg class="ico-copy" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2.5"></rect><path d="M5 15H4.5A1.5 1.5 0 0 1 3 13.5v-9A1.5 1.5 0 0 1 4.5 3h9A1.5 1.5 0 0 1 15 4.5V5" stroke-linecap="round"></path></svg>
556
+ <svg class="ico-check" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M4 12.5l5.5 5.5L20 6.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
557
+ </button>
558
+ <!-- "Copied" feedback on the CARD too, not just the detail header.
559
+ Same mechanism as `.hd-copied`: no JS, purely the CSS sibling of
560
+ copyBranchToClipboard's own ~1200ms `.copied` window, and NO
561
+ `hidden` attribute (that would desync the a11y tree from the
562
+ visual state). -->
563
+ <span class="hist-copied">Copied</span>
564
+ </span>
565
+ <span class="hist-pausenote" hidden></span>
566
+ </div>
567
+ <div class="hist-aside">
568
+ <button type="button" class="hist-pr btn-ghost" hidden>Create PR</button>
569
+ <button type="button" class="hist-open" aria-label="Open run details">
570
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M9 6l6 6-6 6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
571
+ </button>
572
+ </div>
573
+ </div>
574
+ </section>
575
+ </template>
392
576
  </div>
393
- <button type="button" id="refresh-history" class="btn-ghost" style="padding:11px 20px">Refresh</button>
577
+ <div class="hist-screen hist-screen-detail" id="hist-detail" aria-hidden="true"></div>
394
578
  </div>
395
579
 
396
- <!-- Project filter pills: "All Projects" + one per project that has history.
397
- Built by renderHistoryPills() from the /api/history dataset. -->
398
- <div class="hist-filter" id="historyFilter" aria-label="Filter history by project"></div>
399
-
400
- <div class="run-list" id="history"></div>
401
-
402
- <!-- clone target for one history card (Task 5 fills it) -->
403
- <template id="hist-card-tpl">
404
- <section class="card hist-card">
405
- <div class="hist-head" role="button" tabindex="0" aria-expanded="false">
406
- <span class="badge"></span>
407
- <span class="badge hist-retained-badge" hidden>Work retained</span>
408
- <div class="h-meta">
409
- <b></b><small></small><span class="hist-time mono"></span><span class="hist-total mono"></span>
410
- <span class="hist-branch mono"></span>
411
- <span class="hist-pausenote" hidden></span>
412
- </div>
413
- <div class="hist-aside">
414
- <span class="hist-diff" aria-label="lines changed"></span>
580
+ <!-- clone target for the History detail screen (#history/<projectKey>/<id>) -->
581
+ <template id="hist-detail-tpl">
582
+ <div class="hd">
583
+ <header class="hd-header">
584
+ <div class="hd-row1">
585
+ <button type="button" class="hd-back btn-ghost" aria-label="Back to history">
586
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M15 6l-6 6 6 6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
587
+ Back
588
+ </button>
589
+ <h1 class="hd-title"></h1>
415
590
  <span class="hist-merge" hidden></span>
416
- <button type="button" class="hist-pr btn-ghost" hidden>Create PR</button>
417
- <button type="button" class="hist-resume btn-ghost" hidden>Resume</button>
591
+ <button type="button" class="hd-pr" hidden>Create PR</button>
592
+ <a class="hd-pr-link" hidden target="_blank" rel="noopener"></a>
418
593
  </div>
419
- <svg class="chev" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
420
- </div>
421
- <div class="hist-detail" hidden>
422
- <div class="retained-banner" role="alert" hidden></div>
423
- <div class="run-flow-wrap"><div class="run-flow"></div></div>
424
- <!-- Results view (Layer 1 mechanical + Layer 2 overview) -->
425
- <div class="results-section"></div>
426
- <!-- Diff dropdown (New/Changed files) collapsed by default -->
427
- <div class="diff-bar" hidden>
428
- <button type="button" class="btn-subs" aria-expanded="false">
429
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3h8l4 4v14H6z" stroke-linejoin="round"/><path d="M14 3v4h4" stroke-linejoin="round"/></svg>
430
- Diff
431
- <span class="sb-count diff-changed grey"></span>
432
- <span class="sb-count diff-removed grey"></span>
433
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
434
- </button>
435
- <div class="subs-panel diff-panel" hidden></div>
594
+ <!-- Status pip leads the META line, not row 1: it reads as the icon
595
+ for the status WORD it now sits next to (same pairing the list
596
+ card uses), and row 1 stays title + PR actions. -->
597
+ <div class="hd-row2">
598
+ <span class="hd-sic hist-sic" role="img">
599
+ <svg class="sic sic-done" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
600
+ <svg class="sic sic-stopped" width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg>
601
+ <svg class="sic sic-paused" width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg>
602
+ <svg class="sic sic-error" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"><path d="M12 6.5v7"></path><path d="M12 17.4h.01"></path></svg>
603
+ </span>
604
+ <div class="hd-meta mono"></div>
436
605
  </div>
437
- <!-- Overview dropdown (Layer-2 summary) — collapsed; Generate button built on first expand -->
438
- <div class="overview-bar" hidden>
439
- <button type="button" class="btn-subs" aria-expanded="false">
440
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="8"/><path d="M12 8h.01M11 12h1v4h1" stroke-linecap="round" stroke-linejoin="round"/></svg>
441
- Overview
442
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
606
+ <div class="hd-row3">
607
+ <span class="hd-base mono"></span>
608
+ <button type="button" class="hd-branch-copy mono" hidden title="Copy branch name" aria-label="Copy branch name">
609
+ <span class="hd-branch-name"></span>
610
+ <svg class="ico-copy" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="12" height="12" rx="2.5"></rect><path d="M5 15H4.5A1.5 1.5 0 0 1 3 13.5v-9A1.5 1.5 0 0 1 4.5 3h9A1.5 1.5 0 0 1 15 4.5V5" stroke-linecap="round"></path></svg>
611
+ <svg class="ico-check" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M4 12.5l5.5 5.5L20 6.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
443
612
  </button>
444
- <div class="subs-panel overview-panel" hidden></div>
445
- </div>
446
- <div class="subs-bar" hidden>
447
- <button type="button" class="btn-subs" aria-expanded="false">
448
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="6" cy="6" r="2.4"/><circle cx="6" cy="18" r="2.4"/><circle cx="18" cy="12" r="2.4"/><path d="M8 6h5a3 3 0 0 1 3 3v0M8 18h5a3 3 0 0 0 3-3v0" stroke-linecap="round"/></svg>
449
- Agents
450
- <span class="sb-count grey"></span>
451
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
613
+ <!-- NO `hidden` attribute: the caption is driven purely by the CSS
614
+ sibling rule off copyBranchToClipboard's own 1200ms `.copied`
615
+ window. Shipping `hidden` here would leave the node hidden from
616
+ assistive tech while visually shown, because the author rule
617
+ outranks the UA [hidden] rule either way. -->
618
+ <span class="hd-copied">Copied</span>
619
+ <span class="hd-spacer"></span>
620
+ <!-- The label lives in its own span: the busy states ("Resuming…" /
621
+ "Archiving…") swap ONLY that node, so the inline SVG survives and
622
+ the error path can restore the word. -->
623
+ <button type="button" class="hd-resume btn-ghost" hidden>
624
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5l12 7-12 7z"></path></svg>
625
+ <span class="hd-btn-label">Resume</span>
452
626
  </button>
453
- <div class="subs-panel" hidden></div>
454
- </div>
455
- <!-- Clarify dropdown (Q&A) — under Sub-agents -->
456
- <div class="clarify-bar" hidden>
457
- <button type="button" class="btn-subs" aria-expanded="false">
458
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.9.4-1.5 1-1.5 2.2M12 17h.01" stroke-linecap="round" stroke-linejoin="round"/></svg>
459
- Clarify
460
- <span class="sb-count grey"></span>
461
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
462
- </button>
463
- <div class="subs-panel clarify-panel" hidden></div>
464
- </div>
465
- <!-- Live logs dropdown — under Clarify -->
466
- <div class="logs-bar" hidden>
467
- <button type="button" class="btn-subs" aria-expanded="false">
468
- <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 6h16M4 12h16M4 18h10" stroke-linecap="round"/></svg>
469
- Live logs
470
- <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
627
+ <button type="button" class="hd-archive" hidden>
628
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2m2 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
629
+ <span class="hd-btn-label">Archive</span>
471
630
  </button>
472
- <div class="subs-panel logs-panel" hidden></div>
473
631
  </div>
474
- <div class="hist-actions">
632
+ <!-- The inline error lives on the HEADER, not in .hd-body, so an archive
633
+ failure is not pushed below the fold by a long Diff or Logs tab.
634
+ Both writers (the load-failure path and the archive catch) resolve
635
+ it with screen.querySelector, so the position is free to be correct. -->
636
+ <div class="hd-error" hidden></div>
637
+ </header>
638
+ <div class="hd-body">
639
+ <div class="hd-banners">
640
+ <span class="badge hist-retained-badge" hidden>Work retained</span>
641
+ <div class="retained-banner" role="alert" hidden></div>
475
642
  <button type="button" class="hist-discard btn-ghost" hidden>Discard worktree</button>
476
- <button type="button" class="hist-delete btn-danger" hidden>
477
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
478
- stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
479
- <path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2m2 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path>
480
- <line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line>
481
- </svg>
482
- Archive
483
- </button>
484
643
  </div>
644
+ <div class="hd-graph"><div class="run-flow-wrap"><div class="run-flow"></div></div></div>
645
+ <div class="hd-tabs" role="tablist"></div>
646
+ <div class="hd-sections"></div>
485
647
  </div>
486
- </section>
648
+ </div>
487
649
  </template>
488
650
  </section>
489
651
  <!-- /view history -->
@@ -886,12 +1048,12 @@
886
1048
  </section>
887
1049
  <!-- /view agent-create -->
888
1050
 
889
- <!-- ===== VIEW: PIPELINE COMPOSER ===== -->
1051
+ <!-- ===== VIEW: WORKFLOW COMPOSER ===== -->
890
1052
  <section class="view hidden" data-view="composer">
891
1053
  <div class="topbar">
892
1054
  <div>
893
- <h1>Pipeline Composer</h1>
894
- <div class="sub">Compose how your agents collaborate — drag, stack, and loop them into a pipeline</div>
1055
+ <h1>Workflow Composer</h1>
1056
+ <div class="sub">Compose how your agents collaborate — drag, stack, and loop them into a workflow</div>
895
1057
  </div>
896
1058
  <button type="button" class="btn-ghost" id="composer-reset" style="padding:11px 20px">Reset to default</button>
897
1059
  </div>
@@ -900,7 +1062,7 @@
900
1062
  <div class="palette">
901
1063
  <span class="p-label">
902
1064
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="6" cy="6" r="2"></circle><circle cx="6" cy="18" r="2"></circle><circle cx="18" cy="6" r="2"></circle><circle cx="18" cy="18" r="2"></circle></svg>
903
- Agents · drag onto the canvas to build your pipeline
1065
+ Agents · drag onto the canvas to build your workflow
904
1066
  <input id="composer-agent-filter" class="pal-filter" type="search" placeholder="Filter agents…" aria-label="Filter agents by name or description">
905
1067
  </span>
906
1068
  <div id="composer-palette" style="display:contents"></div>
@@ -929,14 +1091,14 @@
929
1091
  <button type="button" class="btn-ghost" id="composer-clear" style="padding:10px 18px">Clear canvas</button>
930
1092
  <button type="button" class="btn-go" id="composer-save">
931
1093
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
932
- Save pipeline
1094
+ Save workflow
933
1095
  </button>
934
1096
  </div>
935
1097
  </section>
936
1098
 
937
1099
  <section class="card saved-card">
938
1100
  <div class="saved-head">
939
- <div><b>Saved pipelines</b><span class="cnt" id="composer-saved-count"></span></div>
1101
+ <div><b>Saved workflows</b><span class="cnt" id="composer-saved-count"></span></div>
940
1102
  </div>
941
1103
  <div class="saved-list" id="composer-saved-list"></div>
942
1104
  </section>
@@ -1103,6 +1265,74 @@
1103
1265
  </div>
1104
1266
  </div>
1105
1267
 
1268
+ <!-- ===== "Ship it?" PR confirm modal (History detail) ===== -->
1269
+ <!-- No z-index of its own: #confirm-modal.viewer-modal{z-index:60} (style.css:781)
1270
+ exists because #confirm-modal precedes #plugin-modal in the DOM, and this
1271
+ dialog never coexists with another overlay — the Escape guard and the
1272
+ double-open guard keep them mutually exclusive. -->
1273
+ <div id="shipit-modal" class="viewer-modal hidden" role="dialog" aria-modal="true" aria-label="Open a pull request">
1274
+ <div class="card shipit-card">
1275
+ <div class="shipit-ico-wrap">
1276
+ <div class="shipit-spark"></div>
1277
+ <div class="shipit-ico">
1278
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6.5" cy="6" r="2.4"></circle><circle cx="6.5" cy="18" r="2.4"></circle><circle cx="17.5" cy="12" r="2.4"></circle><path d="M6.5 8.4v7.2M8.9 17c4.1 0 6-1.8 6.2-3.6M8.9 7c4.1 0 6 1.8 6.2 3.6"></path></svg>
1279
+ </div>
1280
+ </div>
1281
+ <h2>Ship it?</h2>
1282
+ <p class="shipit-sub"></p>
1283
+ <div class="shipit-summary mono">
1284
+ <span class="shipit-files"></span>
1285
+ <!-- spec §5.10 writes the summary as "N files · +A −R"; the middot is markup
1286
+ so the CSS can drop it when the file count is absent. -->
1287
+ <span class="shipit-dot">·</span>
1288
+ <span class="diff-add shipit-add"></span>
1289
+ <span class="diff-del shipit-del"></span>
1290
+ <span class="shipit-break"></span>
1291
+ <b class="shipit-branch"></b>
1292
+ <span class="shipit-arrow">→</span>
1293
+ <span class="shipit-base"></span>
1294
+ </div>
1295
+ <!-- `hint err`, not `err`: style.css has no standalone .err rule, only
1296
+ .hint.err (:284). .hint sets display:block, so .shipit-err ships an
1297
+ explicit [hidden] twin. -->
1298
+ <div class="shipit-err hint err" hidden></div>
1299
+ <div class="shipit-actions">
1300
+ <button type="button" class="shipit-cancel btn-ghost">Cancel</button>
1301
+ <button type="button" class="shipit-ok">Open pull request</button>
1302
+ </div>
1303
+ </div>
1304
+ </div>
1305
+
1306
+ <!-- ===== "Stop this pipeline?" confirm modal (Running card + detail) ===== -->
1307
+ <!-- No z-index of its own: it inherits .viewer-modal's z-index:50
1308
+ (style.css:781) and, following #shipit-modal in the DOM, paints above every
1309
+ other z-index:50 overlay. NOT above #confirm-modal, which carries an
1310
+ explicit z-index:60 (style.css:785) and would win from anywhere in the
1311
+ document — that is fine, because the two never coexist: the Running Escape
1312
+ guard bails while #confirm-modal is open, openStopModal refuses to open
1313
+ twice, and no flow opens both. Do not "fix" this with a z-index of its
1314
+ own; the .cb-override confirm on the detail page depends on #confirm-modal
1315
+ staying on top. -->
1316
+ <div id="stop-modal" class="viewer-modal hidden" role="dialog" aria-modal="true" aria-labelledby="stop-title">
1317
+ <div class="card stop-card">
1318
+ <h2 id="stop-title" class="stop-title">Stop this pipeline?</h2>
1319
+ <p class="stop-body">Agents in flight are cancelled at their next checkpoint. The run moves to History as stopped; its worktree and branch stay in place so you can resume from there.</p>
1320
+ <div class="stop-ident">
1321
+ <div class="stop-ident-title"></div>
1322
+ <div class="stop-ident-branch" hidden></div>
1323
+ </div>
1324
+ <!-- `hint err`, not `err`: style.css has no standalone .err rule, only
1325
+ .hint.err (:286). .hint (:285) sets display:block, so .stop-err ships
1326
+ an explicit [hidden] twin in the stylesheet — same as .shipit-err
1327
+ (base :1891, [hidden] :1896). -->
1328
+ <div class="stop-err hint err" hidden></div>
1329
+ <div class="stop-actions">
1330
+ <button type="button" class="stop-cancel">Keep running</button>
1331
+ <button type="button" class="stop-confirm">Stop pipeline</button>
1332
+ </div>
1333
+ </div>
1334
+ </div>
1335
+
1106
1336
  <!-- ===== Add-project modal ===== -->
1107
1337
  <div id="project-add-modal" class="viewer-modal confirm-modal hidden" role="dialog" aria-modal="true" aria-labelledby="proj-add-title">
1108
1338
  <div class="card">