@cmgmyr/hive 1.9.1 → 1.10.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.
- package/README.md +1 -0
- package/claude-plugin/README.md +4 -0
- package/claude-plugin/crew/.claude-plugin/plugin.json +1 -0
- package/claude-plugin/crew/hooks/hooks.json +1 -0
- package/claude-plugin/crew/hooks/register.tsx +82 -0
- package/claude-plugin/crew/model.mjs +138 -0
- package/claude-plugin/crew/types/index.d.ts +18 -0
- package/dist/build-info.json +1 -1
- package/dist/cli.js +53 -21
- package/dist/crew.js +507 -0
- package/dist/dashboard.js +179 -156
- package/dist/db.js +1 -0
- package/dist/heldLabel.js +17 -0
- package/dist/leadState.js +8 -1
- package/dist/portfolio.js +8 -5
- package/dist/projectYml.js +14 -0
- package/dist/queenDashboard.js +30 -13
- package/dist/spawn.js +3 -3
- package/dist/tools/agents.js +33 -2
- package/dist/transcript.js +135 -2
- package/package.json +1 -1
package/dist/dashboard.js
CHANGED
|
@@ -49,7 +49,7 @@ function formatDate(d) {
|
|
|
49
49
|
return (`${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ` +
|
|
50
50
|
`${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`);
|
|
51
51
|
}
|
|
52
|
-
function formatLocal(utc) {
|
|
52
|
+
export function formatLocal(utc) {
|
|
53
53
|
if (!utc)
|
|
54
54
|
return "-";
|
|
55
55
|
const d = new Date(`${utc.replace(" ", "T")}Z`);
|
|
@@ -559,7 +559,7 @@ function renderCappedList(shownCount, total, pluralNoun, listClass, rowsHtml, em
|
|
|
559
559
|
? `<ul class="rows ${listClass}"${listId ? ` id="${listId}"` : ""}>${rowsHtml}</ul>`
|
|
560
560
|
: emptyHtml));
|
|
561
561
|
}
|
|
562
|
-
function chevron() {
|
|
562
|
+
export function chevron() {
|
|
563
563
|
return `<span class="chev">${icon("chevron")}</span>`;
|
|
564
564
|
}
|
|
565
565
|
const DEFAULT_OPEN_SECTIONS = new Set(["throughput", "board", "todos"]);
|
|
@@ -583,7 +583,7 @@ function renderSectionNav(metas) {
|
|
|
583
583
|
.join("");
|
|
584
584
|
return `<nav class="secnav" aria-label="dashboard sections"><ul>${links}</ul></nav>`;
|
|
585
585
|
}
|
|
586
|
-
const SPRITE = `<svg class="sprite" aria-hidden="true" focusable="false"><defs>
|
|
586
|
+
export const SPRITE = `<svg class="sprite" aria-hidden="true" focusable="false"><defs>
|
|
587
587
|
<symbol id="i-chevron" viewBox="0 0 16 16"><path d="M4 6.5 8 10.5l4-4"/></symbol>
|
|
588
588
|
<symbol id="i-users" viewBox="0 0 16 16"><circle cx="6" cy="5.2" r="2.4"/><path d="M1.9 13.4a4.1 4.1 0 0 1 8.2 0"/><path d="M11 3.2a2.4 2.4 0 0 1 0 4.4"/><path d="M12.1 9.6a4.1 4.1 0 0 1 2 3.8"/></symbol>
|
|
589
589
|
<symbol id="i-clock" viewBox="0 0 16 16"><circle cx="8" cy="8" r="6.2"/><path d="M8 4.4V8l2.6 1.7"/></symbol>
|
|
@@ -598,6 +598,123 @@ const SPRITE = `<svg class="sprite" aria-hidden="true" focusable="false"><defs>
|
|
|
598
598
|
<symbol id="i-inbox" viewBox="0 0 16 16"><path d="M1.9 9.2h3.3l1 2h3.6l1-2h3.3"/><path d="M3.6 2.9h8.8l1.7 6.3v3.3a1.6 1.6 0 0 1-1.6 1.6H3.5a1.6 1.6 0 0 1-1.6-1.6V9.2Z"/></symbol>
|
|
599
599
|
<symbol id="i-info" viewBox="0 0 16 16"><circle cx="8" cy="8" r="6.2"/><path d="M8 7.4v3.6M8 5.2v.1"/></symbol>
|
|
600
600
|
</defs></svg>`;
|
|
601
|
+
export const SECTION_STYLE = `
|
|
602
|
+
[hidden] { display: none !important; }
|
|
603
|
+
svg.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
|
|
604
|
+
.icon { width: 1em; height: 1em; flex: 0 0 auto; fill: none; stroke: currentColor;
|
|
605
|
+
stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
|
|
606
|
+
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
607
|
+
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
608
|
+
.mono { font-family: var(--font-mono); font-size: 0.9em; font-variant-numeric: tabular-nums; }
|
|
609
|
+
.prose { overflow-wrap: anywhere; }
|
|
610
|
+
|
|
611
|
+
.section { margin: 0 0 0.6rem; background: var(--panel); border: 1px solid var(--card-border);
|
|
612
|
+
border-radius: var(--r-card); box-shadow: var(--shadow);
|
|
613
|
+
scroll-margin-top: calc(var(--header-offset) + 0.75rem); }
|
|
614
|
+
summary { cursor: pointer; list-style: none; }
|
|
615
|
+
summary::-webkit-details-marker { display: none; }
|
|
616
|
+
.section > summary { display: flex; align-items: center; gap: 0.55rem; padding: 0.85rem 1rem;
|
|
617
|
+
border-radius: var(--r-card); font-size: 0.9375rem;
|
|
618
|
+
transition: background-color 130ms ease; }
|
|
619
|
+
.sec-icon { display: inline-flex; color: var(--accent); font-size: 1.0625rem; }
|
|
620
|
+
.section > summary .pb-label { font-weight: 600; letter-spacing: -0.006em; }
|
|
621
|
+
.pb-count { color: var(--fg-subtle); font-size: 0.78125rem; font-variant-numeric: tabular-nums;
|
|
622
|
+
margin-left: auto; text-align: right; }
|
|
623
|
+
.chev { display: inline-flex; color: var(--fg-subtle); font-size: 1rem; margin-left: 0.15rem;
|
|
624
|
+
transition: transform 180ms var(--ease-out); }
|
|
625
|
+
details[open] > summary .chev { transform: rotate(180deg); }
|
|
626
|
+
summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: var(--r-ctl); }
|
|
627
|
+
.section-body { padding: 0 1rem 1rem; }
|
|
628
|
+
.section > .section-body { border-top: 1px solid var(--border); padding-top: 0.9rem; margin-top: -0.15rem; }
|
|
629
|
+
|
|
630
|
+
.row-summary { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.6rem;
|
|
631
|
+
border-radius: var(--r-ctl); font-size: 0.875rem;
|
|
632
|
+
transition: background-color 130ms ease; }
|
|
633
|
+
.row-summary .pb-label { display: flex; align-items: center; gap: 0.42rem; flex-wrap: wrap;
|
|
634
|
+
min-width: 0; }
|
|
635
|
+
.row-summary .icon { color: var(--fg-subtle); }
|
|
636
|
+
details.pad-item, details.todo-item { margin: 0; }
|
|
637
|
+
details.pad-item > .section-body, details.todo-item > .section-body { padding: 0.1rem 0.6rem 0.7rem 0.6rem; }
|
|
638
|
+
.todo-body { overflow-wrap: anywhere; white-space: pre-wrap; color: var(--fg-muted);
|
|
639
|
+
font-size: 0.875rem; }
|
|
640
|
+
.todo-body + .todo-body { margin-top: 0.55rem; }
|
|
641
|
+
|
|
642
|
+
.meta, .muted { color: var(--fg-muted); }
|
|
643
|
+
.meta { font-size: 0.8125rem; margin: 0 0 0.75rem; max-width: 72ch; }
|
|
644
|
+
.muted { font-size: 0.8125rem; }
|
|
645
|
+
.cap-note { display: flex; align-items: center; gap: 0.4rem; color: var(--fg-subtle);
|
|
646
|
+
font-size: 0.78125rem; margin: 0 0 0.6rem; }
|
|
647
|
+
pre.board { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; max-height: 60vh; background: var(--panel-sunken);
|
|
648
|
+
border: 1px solid var(--border); border-radius: var(--r-ctl); padding: 0.85rem;
|
|
649
|
+
font-family: var(--font-mono); font-size: 0.8125rem; line-height: 1.5; margin: 0;
|
|
650
|
+
overscroll-behavior: contain; }
|
|
651
|
+
|
|
652
|
+
ul.rows { list-style: none; margin: 0; padding: 0; }
|
|
653
|
+
ul.rows > li { padding: 0.35rem 0; border-bottom: 1px solid var(--border);
|
|
654
|
+
display: flex; flex-direction: column; gap: 0.15rem; }
|
|
655
|
+
ul.rows > li:last-child { border-bottom: none; }
|
|
656
|
+
ul.rows > li.todo, ul.rows > li:has(> details) { padding: 0.1rem 0; }
|
|
657
|
+
.row-main { display: flex; align-items: center; gap: 0.42rem; flex-wrap: wrap; }
|
|
658
|
+
.row-meta { font-size: 0.78125rem; color: var(--fg-subtle); }
|
|
659
|
+
.kind { color: var(--fg-subtle); font-size: 0.78125rem; }
|
|
660
|
+
|
|
661
|
+
.status { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.71875rem;
|
|
662
|
+
font-weight: 600; letter-spacing: 0.01em; padding: 0.12rem 0.5rem; border-radius: var(--r-pill);
|
|
663
|
+
white-space: nowrap; }
|
|
664
|
+
.status::before { content: ""; width: 0.4rem; height: 0.4rem; border-radius: 50%;
|
|
665
|
+
background: currentColor; flex: 0 0 auto; }
|
|
666
|
+
.status-ok { color: var(--ok); background: var(--ok-bg); }
|
|
667
|
+
.status-warn { color: var(--warn); background: var(--warn-bg); }
|
|
668
|
+
.status-fail { color: var(--fail); background: var(--fail-bg); }
|
|
669
|
+
.status-live { color: var(--live); background: var(--live-bg); }
|
|
670
|
+
|
|
671
|
+
.chip { display: inline-flex; align-items: center; gap: 0.28rem; font-size: 0.71875rem;
|
|
672
|
+
font-weight: 600; padding: 0.12rem 0.48rem; border-radius: var(--r-pill); white-space: nowrap; }
|
|
673
|
+
.chip-blocked { color: var(--warn); background: var(--warn-bg); }
|
|
674
|
+
.chip-blocked .icon { stroke-width: 1.6; }
|
|
675
|
+
|
|
676
|
+
.tag { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
|
677
|
+
padding: 0.1rem 0.4rem; border-radius: 5px; background: var(--panel-sunken); color: var(--fg-subtle); }
|
|
678
|
+
|
|
679
|
+
.priority { font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
680
|
+
.priority-high { color: var(--fail); }
|
|
681
|
+
.priority-medium { color: var(--fg-muted); }
|
|
682
|
+
.priority-low { color: var(--fg-subtle); }
|
|
683
|
+
.blockers { font-size: 0.8125rem; color: var(--fg-muted); margin: 0 0 0.45rem 0.6rem; }
|
|
684
|
+
.wake-body { color: var(--fg); font-size: 0.875rem; overflow-wrap: anywhere; }
|
|
685
|
+
.activity-body { font-size: 0.8125rem; color: var(--fg-muted); white-space: pre-wrap;
|
|
686
|
+
overflow-wrap: anywhere; margin-top: 0.1rem; }
|
|
687
|
+
|
|
688
|
+
.filter { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
|
|
689
|
+
.filter-field { display: flex; align-items: center; gap: 0.45rem; flex: 1 1 18rem;
|
|
690
|
+
background: var(--panel-sunken); border: 1px solid var(--border); border-radius: var(--r-ctl);
|
|
691
|
+
padding: 0.4rem 0.65rem; color: var(--fg-subtle);
|
|
692
|
+
transition: border-color 130ms ease, background-color 130ms ease; }
|
|
693
|
+
.filter-field:focus-within { border-color: var(--accent); background: var(--panel); }
|
|
694
|
+
.filter-field input { flex: 1 1 auto; min-width: 0; border: 0; background: transparent;
|
|
695
|
+
font: inherit; font-size: 0.875rem; color: var(--fg); outline: none; padding: 0; }
|
|
696
|
+
.filter-field input::placeholder { color: var(--fg-subtle); }
|
|
697
|
+
.filter-field input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
|
|
698
|
+
.filter-count { color: var(--fg-subtle); font-size: 0.78125rem; font-variant-numeric: tabular-nums;
|
|
699
|
+
margin: 0; flex: 0 0 auto; }
|
|
700
|
+
.filter-none { color: var(--fg-muted); font-size: 0.875rem; margin: 0.5rem 0; }
|
|
701
|
+
|
|
702
|
+
.empty { text-align: center; padding: 1.75rem 1rem 1.85rem; color: var(--fg-muted); }
|
|
703
|
+
.empty .icon { font-size: 1.5rem; color: var(--fg-subtle); stroke-width: 1.2; }
|
|
704
|
+
.empty-title { margin: 0.55rem 0 0.2rem; font-weight: 600; color: var(--fg); font-size: 0.9375rem; }
|
|
705
|
+
.empty-hint { margin: 0; font-size: 0.8125rem; color: var(--fg-subtle); max-width: 42ch;
|
|
706
|
+
margin-inline: auto; }
|
|
707
|
+
|
|
708
|
+
@media (hover: hover) and (pointer: fine) {
|
|
709
|
+
.section > summary:hover { background: var(--hover); }
|
|
710
|
+
.row-summary:hover { background: var(--hover); }
|
|
711
|
+
}
|
|
712
|
+
.section > summary:active, .row-summary:active { transform: scale(0.995); }
|
|
713
|
+
@media (max-width: 40rem) { .pb-count { font-size: 0.75rem; } }
|
|
714
|
+
@media (prefers-reduced-motion: reduce) {
|
|
715
|
+
.section > summary:active, .row-summary:active { transform: none; }
|
|
716
|
+
}
|
|
717
|
+
`;
|
|
601
718
|
const STYLE = `
|
|
602
719
|
:root {
|
|
603
720
|
color-scheme: light dark;
|
|
@@ -665,7 +782,6 @@ const STYLE = `
|
|
|
665
782
|
}
|
|
666
783
|
|
|
667
784
|
*, *::before, *::after { box-sizing: border-box; }
|
|
668
|
-
[hidden] { display: none !important; }
|
|
669
785
|
html { -webkit-text-size-adjust: 100%; }
|
|
670
786
|
body {
|
|
671
787
|
font-family: var(--font-sans);
|
|
@@ -678,13 +794,6 @@ const STYLE = `
|
|
|
678
794
|
accent-color: var(--accent);
|
|
679
795
|
}
|
|
680
796
|
::selection { background: var(--live-bg); color: var(--fg); }
|
|
681
|
-
svg.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
|
|
682
|
-
.icon { width: 1em; height: 1em; flex: 0 0 auto; fill: none; stroke: currentColor;
|
|
683
|
-
stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
|
|
684
|
-
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
685
|
-
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
686
|
-
.mono { font-family: var(--font-mono); font-size: 0.9em; font-variant-numeric: tabular-nums; }
|
|
687
|
-
.prose { overflow-wrap: anywhere; }
|
|
688
797
|
|
|
689
798
|
.skip { position: absolute; left: -999px; top: 0; z-index: 10;
|
|
690
799
|
background: var(--panel); color: var(--fg); padding: 0.6rem 0.9rem; border-radius: var(--r-ctl); }
|
|
@@ -763,102 +872,6 @@ const STYLE = `
|
|
|
763
872
|
.pulse-bar { fill: var(--series-1); }
|
|
764
873
|
.pulse-none { fill: var(--border-strong); }
|
|
765
874
|
|
|
766
|
-
.section { margin: 0 0 0.6rem; background: var(--panel); border: 1px solid var(--card-border);
|
|
767
|
-
border-radius: var(--r-card); box-shadow: var(--shadow);
|
|
768
|
-
scroll-margin-top: calc(var(--header-offset) + 0.75rem); }
|
|
769
|
-
summary { cursor: pointer; list-style: none; }
|
|
770
|
-
summary::-webkit-details-marker { display: none; }
|
|
771
|
-
.section > summary { display: flex; align-items: center; gap: 0.55rem; padding: 0.85rem 1rem;
|
|
772
|
-
border-radius: var(--r-card); font-size: 0.9375rem;
|
|
773
|
-
transition: background-color 130ms ease; }
|
|
774
|
-
.sec-icon { display: inline-flex; color: var(--accent); font-size: 1.0625rem; }
|
|
775
|
-
.section > summary .pb-label { font-weight: 600; letter-spacing: -0.006em; }
|
|
776
|
-
.pb-count { color: var(--fg-subtle); font-size: 0.78125rem; font-variant-numeric: tabular-nums;
|
|
777
|
-
margin-left: auto; text-align: right; }
|
|
778
|
-
.chev { display: inline-flex; color: var(--fg-subtle); font-size: 1rem; margin-left: 0.15rem;
|
|
779
|
-
transition: transform 180ms var(--ease-out); }
|
|
780
|
-
details[open] > summary .chev { transform: rotate(180deg); }
|
|
781
|
-
summary:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: var(--r-ctl); }
|
|
782
|
-
.section-body { padding: 0 1rem 1rem; }
|
|
783
|
-
.section > .section-body { border-top: 1px solid var(--border); padding-top: 0.9rem; margin-top: -0.15rem; }
|
|
784
|
-
|
|
785
|
-
.row-summary { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.6rem;
|
|
786
|
-
border-radius: var(--r-ctl); font-size: 0.875rem;
|
|
787
|
-
transition: background-color 130ms ease; }
|
|
788
|
-
.row-summary .pb-label { display: flex; align-items: center; gap: 0.42rem; flex-wrap: wrap;
|
|
789
|
-
min-width: 0; }
|
|
790
|
-
.row-summary .icon { color: var(--fg-subtle); }
|
|
791
|
-
details.pad-item, details.todo-item { margin: 0; }
|
|
792
|
-
details.pad-item > .section-body, details.todo-item > .section-body { padding: 0.1rem 0.6rem 0.7rem 0.6rem; }
|
|
793
|
-
.todo-body { overflow-wrap: anywhere; white-space: pre-wrap; color: var(--fg-muted);
|
|
794
|
-
font-size: 0.875rem; }
|
|
795
|
-
.todo-body + .todo-body { margin-top: 0.55rem; }
|
|
796
|
-
|
|
797
|
-
.meta, .muted { color: var(--fg-muted); }
|
|
798
|
-
.meta { font-size: 0.8125rem; margin: 0 0 0.75rem; max-width: 72ch; }
|
|
799
|
-
.muted { font-size: 0.8125rem; }
|
|
800
|
-
.cap-note { display: flex; align-items: center; gap: 0.4rem; color: var(--fg-subtle);
|
|
801
|
-
font-size: 0.78125rem; margin: 0 0 0.6rem; }
|
|
802
|
-
pre.board { white-space: pre-wrap; overflow-wrap: anywhere; overflow: auto; max-height: 60vh; background: var(--panel-sunken);
|
|
803
|
-
border: 1px solid var(--border); border-radius: var(--r-ctl); padding: 0.85rem;
|
|
804
|
-
font-family: var(--font-mono); font-size: 0.8125rem; line-height: 1.5; margin: 0;
|
|
805
|
-
overscroll-behavior: contain; }
|
|
806
|
-
|
|
807
|
-
ul.rows { list-style: none; margin: 0; padding: 0; }
|
|
808
|
-
ul.rows > li { padding: 0.35rem 0; border-bottom: 1px solid var(--border);
|
|
809
|
-
display: flex; flex-direction: column; gap: 0.15rem; }
|
|
810
|
-
ul.rows > li:last-child { border-bottom: none; }
|
|
811
|
-
ul.rows > li.todo, ul.rows > li:has(> details) { padding: 0.1rem 0; }
|
|
812
|
-
.row-main { display: flex; align-items: center; gap: 0.42rem; flex-wrap: wrap; }
|
|
813
|
-
.row-meta { font-size: 0.78125rem; color: var(--fg-subtle); }
|
|
814
|
-
.kind { color: var(--fg-subtle); font-size: 0.78125rem; }
|
|
815
|
-
|
|
816
|
-
.status { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.71875rem;
|
|
817
|
-
font-weight: 600; letter-spacing: 0.01em; padding: 0.12rem 0.5rem; border-radius: var(--r-pill);
|
|
818
|
-
white-space: nowrap; }
|
|
819
|
-
.status::before { content: ""; width: 0.4rem; height: 0.4rem; border-radius: 50%;
|
|
820
|
-
background: currentColor; flex: 0 0 auto; }
|
|
821
|
-
.status-ok { color: var(--ok); background: var(--ok-bg); }
|
|
822
|
-
.status-warn { color: var(--warn); background: var(--warn-bg); }
|
|
823
|
-
.status-fail { color: var(--fail); background: var(--fail-bg); }
|
|
824
|
-
.status-live { color: var(--live); background: var(--live-bg); }
|
|
825
|
-
|
|
826
|
-
.chip { display: inline-flex; align-items: center; gap: 0.28rem; font-size: 0.71875rem;
|
|
827
|
-
font-weight: 600; padding: 0.12rem 0.48rem; border-radius: var(--r-pill); white-space: nowrap; }
|
|
828
|
-
.chip-blocked { color: var(--warn); background: var(--warn-bg); }
|
|
829
|
-
.chip-blocked .icon { stroke-width: 1.6; }
|
|
830
|
-
|
|
831
|
-
.tag { font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
|
832
|
-
padding: 0.1rem 0.4rem; border-radius: 5px; background: var(--panel-sunken); color: var(--fg-subtle); }
|
|
833
|
-
|
|
834
|
-
.priority { font-size: 0.6875rem; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
835
|
-
.priority-high { color: var(--fail); }
|
|
836
|
-
.priority-medium { color: var(--fg-muted); }
|
|
837
|
-
.priority-low { color: var(--fg-subtle); }
|
|
838
|
-
.blockers { font-size: 0.8125rem; color: var(--fg-muted); margin: 0 0 0.45rem 0.6rem; }
|
|
839
|
-
.wake-body { color: var(--fg); font-size: 0.875rem; overflow-wrap: anywhere; }
|
|
840
|
-
.activity-body { font-size: 0.8125rem; color: var(--fg-muted); white-space: pre-wrap;
|
|
841
|
-
overflow-wrap: anywhere; margin-top: 0.1rem; }
|
|
842
|
-
|
|
843
|
-
.filter { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
|
|
844
|
-
.filter-field { display: flex; align-items: center; gap: 0.45rem; flex: 1 1 18rem;
|
|
845
|
-
background: var(--panel-sunken); border: 1px solid var(--border); border-radius: var(--r-ctl);
|
|
846
|
-
padding: 0.4rem 0.65rem; color: var(--fg-subtle);
|
|
847
|
-
transition: border-color 130ms ease, background-color 130ms ease; }
|
|
848
|
-
.filter-field:focus-within { border-color: var(--accent); background: var(--panel); }
|
|
849
|
-
.filter-field input { flex: 1 1 auto; min-width: 0; border: 0; background: transparent;
|
|
850
|
-
font: inherit; font-size: 0.875rem; color: var(--fg); outline: none; padding: 0; }
|
|
851
|
-
.filter-field input::placeholder { color: var(--fg-subtle); }
|
|
852
|
-
.filter-field input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
|
|
853
|
-
.filter-count { color: var(--fg-subtle); font-size: 0.78125rem; font-variant-numeric: tabular-nums;
|
|
854
|
-
margin: 0; flex: 0 0 auto; }
|
|
855
|
-
.filter-none { color: var(--fg-muted); font-size: 0.875rem; margin: 0.5rem 0; }
|
|
856
|
-
|
|
857
|
-
.empty { text-align: center; padding: 1.75rem 1rem 1.85rem; color: var(--fg-muted); }
|
|
858
|
-
.empty .icon { font-size: 1.5rem; color: var(--fg-subtle); stroke-width: 1.2; }
|
|
859
|
-
.empty-title { margin: 0.55rem 0 0.2rem; font-weight: 600; color: var(--fg); font-size: 0.9375rem; }
|
|
860
|
-
.empty-hint { margin: 0; font-size: 0.8125rem; color: var(--fg-subtle); max-width: 42ch;
|
|
861
|
-
margin-inline: auto; }
|
|
862
875
|
|
|
863
876
|
svg.chart { width: 100%; height: auto; display: block; margin: 0 0 0.9rem;
|
|
864
877
|
color: var(--fg-muted); }
|
|
@@ -896,29 +909,24 @@ const STYLE = `
|
|
|
896
909
|
.swatch-2 { background: var(--series-2); }
|
|
897
910
|
|
|
898
911
|
@media (hover: hover) and (pointer: fine) {
|
|
899
|
-
.section > summary:hover { background: var(--hover); }
|
|
900
|
-
.row-summary:hover { background: var(--hover); }
|
|
901
912
|
.navchip:hover { background: var(--hover); color: var(--fg); }
|
|
902
913
|
}
|
|
903
|
-
.section > summary:active, .row-summary:active { transform: scale(0.995); }
|
|
904
914
|
.navchip:active { transform: scale(0.97); }
|
|
905
915
|
|
|
906
916
|
@media (max-width: 40rem) {
|
|
907
917
|
.wrap { padding: 0 0.9rem; }
|
|
908
918
|
.now { grid-template-columns: 1fr; }
|
|
909
|
-
.pb-count { font-size: 0.75rem; }
|
|
910
919
|
.navchip-label { position: absolute; width: 1px; height: 1px; padding: 0;
|
|
911
920
|
margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
912
921
|
}
|
|
913
922
|
|
|
914
923
|
@media (prefers-reduced-motion: reduce) {
|
|
915
924
|
* { transition: none !important; animation: none !important; }
|
|
916
|
-
.
|
|
925
|
+
.navchip:active { transform: none; }
|
|
917
926
|
}
|
|
918
|
-
`;
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
var KEY = "hive-dashboard-state";
|
|
927
|
+
${SECTION_STYLE}`;
|
|
928
|
+
export const sectionScript = (key, between = "") => `
|
|
929
|
+
var KEY = "${key}";
|
|
922
930
|
function load() {
|
|
923
931
|
try { return JSON.parse(sessionStorage.getItem(KEY) || "{}"); } catch (e) { return {}; }
|
|
924
932
|
}
|
|
@@ -999,8 +1007,6 @@ const SCRIPT = `
|
|
|
999
1007
|
s.filterCaret = filterInput.selectionStart;
|
|
1000
1008
|
save(s);
|
|
1001
1009
|
applyFilter(filterInput.value);
|
|
1002
|
-
paintStamp();
|
|
1003
|
-
deferReload();
|
|
1004
1010
|
});
|
|
1005
1011
|
}
|
|
1006
1012
|
|
|
@@ -1016,6 +1022,46 @@ const SCRIPT = `
|
|
|
1016
1022
|
}
|
|
1017
1023
|
measureHeader();
|
|
1018
1024
|
|
|
1025
|
+
${between} function absTop(el) { return el.getBoundingClientRect().top + window.scrollY; }
|
|
1026
|
+
var anchorEl = state.anchor && typeof state.anchor.id === "string"
|
|
1027
|
+
? document.getElementById(state.anchor.id) : null;
|
|
1028
|
+
if (anchorEl && typeof state.anchor.offset === "number") {
|
|
1029
|
+
window.scrollTo(0, absTop(anchorEl) + state.anchor.offset);
|
|
1030
|
+
} else if (typeof state.scrollY === "number") {
|
|
1031
|
+
window.scrollTo(0, state.scrollY);
|
|
1032
|
+
}
|
|
1033
|
+
var itemSel = "details.pad-item, details.todo-item";
|
|
1034
|
+
var padItems = document.querySelectorAll("details.pad-item");
|
|
1035
|
+
for (var pi = 0; pi < padItems.length; pi++) {
|
|
1036
|
+
var saved = state.padScroll && state.padScroll[padItems[pi].id];
|
|
1037
|
+
var padPre = padItems[pi].querySelector("pre.board");
|
|
1038
|
+
if (padItems[pi].open && padPre && typeof saved === "number") padPre.scrollTop = saved;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
window.addEventListener("beforeunload", function () {
|
|
1042
|
+
var s = load();
|
|
1043
|
+
s.scrollY = window.scrollY;
|
|
1044
|
+
s.anchor = null;
|
|
1045
|
+
var secs = document.querySelectorAll("details.section");
|
|
1046
|
+
for (var k = 0; k < secs.length; k++) {
|
|
1047
|
+
if (secs[k].getBoundingClientRect().top <= headerOffset) {
|
|
1048
|
+
s.anchor = { id: secs[k].id, offset: window.scrollY - absTop(secs[k]) };
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
s.padScroll = {};
|
|
1052
|
+
var openPads = document.querySelectorAll("details.pad-item");
|
|
1053
|
+
for (var m = 0; m < openPads.length; m++) {
|
|
1054
|
+
var pre = openPads[m].querySelector("pre.board");
|
|
1055
|
+
if (openPads[m].open && pre && pre.scrollTop > 0) s.padScroll[openPads[m].id] = pre.scrollTop;
|
|
1056
|
+
}
|
|
1057
|
+
if (filterInput) {
|
|
1058
|
+
s.filterFocused = document.activeElement === filterInput;
|
|
1059
|
+
s.filterCaret = filterInput.selectionStart;
|
|
1060
|
+
}
|
|
1061
|
+
save(s);
|
|
1062
|
+
});
|
|
1063
|
+
`;
|
|
1064
|
+
const NAV_SCRIPT = `
|
|
1019
1065
|
// Section nav: mark the section the reader is currently in.
|
|
1020
1066
|
var navLinks = document.querySelectorAll(".navchip");
|
|
1021
1067
|
function paintNav() {
|
|
@@ -1040,22 +1086,10 @@ const SCRIPT = `
|
|
|
1040
1086
|
window.addEventListener("resize", function () { measureHeader(); paintNav(); });
|
|
1041
1087
|
}
|
|
1042
1088
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
window.scrollTo(0, absTop(anchorEl) + state.anchor.offset);
|
|
1048
|
-
} else if (typeof state.scrollY === "number") {
|
|
1049
|
-
window.scrollTo(0, state.scrollY);
|
|
1050
|
-
}
|
|
1051
|
-
var itemSel = "details.pad-item, details.todo-item";
|
|
1052
|
-
var padItems = document.querySelectorAll("details.pad-item");
|
|
1053
|
-
for (var pi = 0; pi < padItems.length; pi++) {
|
|
1054
|
-
var saved = state.padScroll && state.padScroll[padItems[pi].id];
|
|
1055
|
-
var padPre = padItems[pi].querySelector("pre.board");
|
|
1056
|
-
if (padItems[pi].open && padPre && typeof saved === "number") padPre.scrollTop = saved;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1089
|
+
`;
|
|
1090
|
+
const SCRIPT = `
|
|
1091
|
+
(function () {
|
|
1092
|
+
${sectionScript("hive-dashboard-state", NAV_SCRIPT)}
|
|
1059
1093
|
// Live toggle. Replaces <meta http-equiv="refresh">, which the browser
|
|
1060
1094
|
// schedules at PARSE TIME - removing the tag afterward does not cancel it,
|
|
1061
1095
|
// so a toggle could never turn it off. A setTimeout can be cleared, so this
|
|
@@ -1102,6 +1136,9 @@ const SCRIPT = `
|
|
|
1102
1136
|
if (toggle) toggle.checked = live;
|
|
1103
1137
|
paintStamp();
|
|
1104
1138
|
deferReload();
|
|
1139
|
+
if (filterInput) {
|
|
1140
|
+
filterInput.addEventListener("input", function () { paintStamp(); deferReload(); });
|
|
1141
|
+
}
|
|
1105
1142
|
var items = document.querySelectorAll(itemSel);
|
|
1106
1143
|
for (var ii = 0; ii < items.length; ii++) {
|
|
1107
1144
|
items[ii].addEventListener("toggle", function () { paintStamp(); deferReload(); });
|
|
@@ -1124,28 +1161,6 @@ const SCRIPT = `
|
|
|
1124
1161
|
if (reloadTimer !== null) deferReload();
|
|
1125
1162
|
}, { passive: true });
|
|
1126
1163
|
|
|
1127
|
-
window.addEventListener("beforeunload", function () {
|
|
1128
|
-
var s = load();
|
|
1129
|
-
s.scrollY = window.scrollY;
|
|
1130
|
-
s.anchor = null;
|
|
1131
|
-
var secs = document.querySelectorAll("details.section");
|
|
1132
|
-
for (var k = 0; k < secs.length; k++) {
|
|
1133
|
-
if (secs[k].getBoundingClientRect().top <= headerOffset) {
|
|
1134
|
-
s.anchor = { id: secs[k].id, offset: window.scrollY - absTop(secs[k]) };
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
s.padScroll = {};
|
|
1138
|
-
var openPads = document.querySelectorAll("details.pad-item");
|
|
1139
|
-
for (var m = 0; m < openPads.length; m++) {
|
|
1140
|
-
var pre = openPads[m].querySelector("pre.board");
|
|
1141
|
-
if (openPads[m].open && pre && pre.scrollTop > 0) s.padScroll[openPads[m].id] = pre.scrollTop;
|
|
1142
|
-
}
|
|
1143
|
-
if (filterInput) {
|
|
1144
|
-
s.filterFocused = document.activeElement === filterInput;
|
|
1145
|
-
s.filterCaret = filterInput.selectionStart;
|
|
1146
|
-
}
|
|
1147
|
-
save(s);
|
|
1148
|
-
});
|
|
1149
1164
|
})();
|
|
1150
1165
|
`;
|
|
1151
1166
|
const BRAND_MARK = `<svg class="mark" viewBox="0 0 32 32" role="img" aria-label="hive">
|
|
@@ -1207,3 +1222,11 @@ export function renderDashboardForWrite(projectId, procs = []) {
|
|
|
1207
1222
|
const contentHash = createHash("sha256").update(projectName).update("\0").update(sections).digest("hex");
|
|
1208
1223
|
return { html, contentHash };
|
|
1209
1224
|
}
|
|
1225
|
+
export function renderBoardPadsTodos(projectId) {
|
|
1226
|
+
const index = [];
|
|
1227
|
+
return [
|
|
1228
|
+
renderBoardSection(index, projectId),
|
|
1229
|
+
renderTodosSection(index, projectId),
|
|
1230
|
+
renderPadsSection(index, projectId),
|
|
1231
|
+
].join("\n");
|
|
1232
|
+
}
|
package/dist/db.js
CHANGED
|
@@ -429,6 +429,7 @@ ALTER TABLE agent_messages ADD COLUMN target_identity TEXT;
|
|
|
429
429
|
ALTER TABLE agent_messages ADD COLUMN sender_tag TEXT;
|
|
430
430
|
CREATE INDEX idx_agent_messages_delivery ON agent_messages(delivery_status, id) WHERE delivery_status IS NOT NULL;
|
|
431
431
|
`,
|
|
432
|
+
`ALTER TABLE agents ADD COLUMN todo_id INTEGER REFERENCES todos(id) ON DELETE SET NULL;`,
|
|
432
433
|
];
|
|
433
434
|
export function storeSchemaAhead(database) {
|
|
434
435
|
try {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { HELD_REASON_CONVERSATION, HELD_REASON_LEAD_PANE_DEAD, isLeadRowClosedHold, isUnclassifiablePaneHold, isUnsubmittedInputHold, wasHeldForPaneIdentity, } from "./scheduler.js";
|
|
2
|
+
// test/docs.test.mjs fails if a label here is missing from docs/install.md. It checks
|
|
3
|
+
// presence only: docs/install.md also counts the set in prose, and nothing guards that number.
|
|
4
|
+
export const HELD_REASON_LABELS = ["typing", "talking", "needs you", "blocked"];
|
|
5
|
+
export function heldReasonLabel(heldReason) {
|
|
6
|
+
if (isUnsubmittedInputHold(heldReason))
|
|
7
|
+
return "typing";
|
|
8
|
+
if (heldReason === HELD_REASON_LEAD_PANE_DEAD ||
|
|
9
|
+
wasHeldForPaneIdentity(heldReason) ||
|
|
10
|
+
isLeadRowClosedHold(heldReason) ||
|
|
11
|
+
isUnclassifiablePaneHold(heldReason)) {
|
|
12
|
+
return "needs you";
|
|
13
|
+
}
|
|
14
|
+
if (heldReason === HELD_REASON_CONVERSATION)
|
|
15
|
+
return "talking";
|
|
16
|
+
return "blocked";
|
|
17
|
+
}
|
package/dist/leadState.js
CHANGED
|
@@ -3,6 +3,12 @@ import { FIRST_MESSAGE_SHA_ENV, firstMessageDigest } from "./firstMessage.js";
|
|
|
3
3
|
export function readLeadTurnState(agentId) {
|
|
4
4
|
return db.prepare("SELECT * FROM lead_turn_state WHERE agent_id = ?").get(agentId) ?? null;
|
|
5
5
|
}
|
|
6
|
+
export function leadSessionEnded(row, ownership) {
|
|
7
|
+
if ((ownership !== "gone" && ownership !== "reissued") || row.pane_pid === "")
|
|
8
|
+
return null;
|
|
9
|
+
const turn = readLeadTurnState(row.id);
|
|
10
|
+
return turn?.last_event === "session_end" && turn.pane_pid === row.pane_pid ? { ended_at: turn.changed_at } : null;
|
|
11
|
+
}
|
|
6
12
|
function isHiveFirstMessage(payload) {
|
|
7
13
|
if (typeof payload.prompt !== "string")
|
|
8
14
|
return false;
|
|
@@ -44,7 +50,8 @@ const applyInTransaction = db.transaction((agentId, panePid, event, payload, sub
|
|
|
44
50
|
cur.pane_pid === next.pane_pid &&
|
|
45
51
|
cur.session_id === next.session_id &&
|
|
46
52
|
cur.state === next.state &&
|
|
47
|
-
cur.idle_seq === next.idle_seq
|
|
53
|
+
cur.idle_seq === next.idle_seq &&
|
|
54
|
+
(event !== "session_end" || cur.last_event === "session_end")) {
|
|
48
55
|
return;
|
|
49
56
|
}
|
|
50
57
|
db.prepare(`INSERT INTO lead_turn_state (agent_id, pane_pid, session_id, state, idle_seq, last_event, changed_at)
|
package/dist/portfolio.js
CHANGED
|
@@ -3,7 +3,7 @@ import { listProjects } from "./context.js";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { parseTags } from "./result.js";
|
|
5
5
|
import { OPEN_BLOCKERS_SQL } from "./tools/todos.js";
|
|
6
|
-
import { readLeadTurnState } from "./leadState.js";
|
|
6
|
+
import { leadSessionEnded, readLeadTurnState } from "./leadState.js";
|
|
7
7
|
import { liveTargets, ownershipLiveness, rowOwnership } from "./tmux.js";
|
|
8
8
|
export const PORTFOLIO_REASONS = [
|
|
9
9
|
"needs_human",
|
|
@@ -88,14 +88,17 @@ function projectRow(project, now, snapshot) {
|
|
|
88
88
|
const workers = { working: 0, idle: 0, needs_input: 0, other: 0, unreachable: 0, unconfirmed: 0 };
|
|
89
89
|
let liveWorking = 0;
|
|
90
90
|
let liveWaiting = 0;
|
|
91
|
-
let lead = { state: "none", agent_id: null, turn: "unknown" };
|
|
91
|
+
let lead = { state: "none", agent_id: null, turn: "unknown", ended_at: null };
|
|
92
92
|
for (const a of agents) {
|
|
93
93
|
if (a.kind === "lead") {
|
|
94
|
-
const
|
|
94
|
+
const ownership = rowOwnership(a, snapshot);
|
|
95
|
+
const live = ownershipLiveness(ownership);
|
|
96
|
+
const ended = leadSessionEnded(a, ownership);
|
|
95
97
|
lead = {
|
|
96
|
-
state: live === true ? "alive" : live === false ? "dead_pane" : "unknown",
|
|
98
|
+
state: live === true ? "alive" : live === false ? (ended ? "dormant" : "dead_pane") : "unknown",
|
|
97
99
|
agent_id: a.id,
|
|
98
100
|
turn: live === true ? leadTurnFor(a.id, a.pane_pid) : "unknown",
|
|
101
|
+
ended_at: ended?.ended_at ?? null,
|
|
99
102
|
};
|
|
100
103
|
continue;
|
|
101
104
|
}
|
|
@@ -135,7 +138,7 @@ function projectRow(project, now, snapshot) {
|
|
|
135
138
|
const found = new Set();
|
|
136
139
|
if (tagged.length > 0)
|
|
137
140
|
found.add("needs_human");
|
|
138
|
-
if (lead.state === "dead_pane" && (todos.in_progress > 0 || wakeCounts.pending > 0))
|
|
141
|
+
if ((lead.state === "dead_pane" || lead.state === "dormant") && (todos.in_progress > 0 || wakeCounts.pending > 0))
|
|
139
142
|
found.add("dead_lead_pane");
|
|
140
143
|
if (!rootExists && (activeTodos > 0 || wakeCounts.pending > 0))
|
|
141
144
|
found.add("missing_root_with_work");
|
package/dist/projectYml.js
CHANGED
|
@@ -18,6 +18,7 @@ export const BUILT_IN_PROJECT_YML = Object.freeze({
|
|
|
18
18
|
context_checkpoint_percent: null,
|
|
19
19
|
lead_turn_budget: null,
|
|
20
20
|
dashboard: false,
|
|
21
|
+
lead_sidebar: false,
|
|
21
22
|
quiet_messaging: false,
|
|
22
23
|
vars: Object.freeze({}),
|
|
23
24
|
processes: Object.freeze({}),
|
|
@@ -199,6 +200,19 @@ function applyLayer(root, path, source, config, sources, warnings) {
|
|
|
199
200
|
else
|
|
200
201
|
warn(`dashboard must be true or false; ignoring "${String(value)}".`);
|
|
201
202
|
}
|
|
203
|
+
if (has("lead_sidebar")) {
|
|
204
|
+
const value = root.lead_sidebar;
|
|
205
|
+
if (value == null) {
|
|
206
|
+
config.lead_sidebar = false;
|
|
207
|
+
sources.lead_sidebar = source;
|
|
208
|
+
}
|
|
209
|
+
else if (typeof value === "boolean") {
|
|
210
|
+
config.lead_sidebar = value;
|
|
211
|
+
sources.lead_sidebar = source;
|
|
212
|
+
}
|
|
213
|
+
else
|
|
214
|
+
warn(`lead_sidebar must be true or false; ignoring "${String(value)}".`);
|
|
215
|
+
}
|
|
202
216
|
if (has("quiet_messaging")) {
|
|
203
217
|
const value = root.quiet_messaging;
|
|
204
218
|
if (value == null) {
|