@walwal-harness/cli 7.1.44 → 7.1.46

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.
@@ -52,6 +52,28 @@
52
52
  .viewscroll{ flex:1; overflow:auto; padding:var(--gap); }
53
53
  .viewscroll-graph{ overflow:hidden; }
54
54
 
55
+ /* Consolidated single-screen layout: COMMAND + ORCHESTRATION + TIMELINE stacked. */
56
+ .viewstack{ flex:1; min-height:0; overflow:auto; display:flex; flex-direction:column; }
57
+ .viewsection{ flex:none; display:flex; flex-direction:column; border-top:1px solid var(--bd2); }
58
+ .viewsection:first-child{ border-top:none; }
59
+ .viewsection-head{ position:sticky; top:0; z-index:6; display:flex; align-items:baseline; gap:10px;
60
+ padding:7px var(--gap); background:rgba(13,17,24,.92); backdrop-filter:blur(4px);
61
+ border-bottom:1px solid var(--bd);
62
+ font-family:var(--mono); font-size:10px; letter-spacing:.16em; text-transform:uppercase; color:var(--tx-lo); }
63
+ .viewsection-head b{ color:var(--tx-hi); font-weight:600; letter-spacing:.18em; }
64
+ .viewsection-body{ flex:1; min-height:0; overflow:auto; padding:var(--gap); }
65
+ /* Content-driven height so a short agents grid / empty WORK·IN·FLIGHT doesn't
66
+ leave a tall blank gap. The stream rail is capped so many events scroll
67
+ instead of stretching the section. */
68
+ .viewsection-command{ height:auto; }
69
+ .viewsection-command .gridview-rail{ max-height:60vh; }
70
+ .viewsection-graph{ height:80vh; }
71
+ .viewsection-graph .viewsection-body{ overflow:hidden; }
72
+ /* Heatmap (timeline) section: content-height like COMMAND, with the swimlane
73
+ rows capped so many lanes scroll instead of leaving a tall blank gap. */
74
+ .viewsection-timeline{ height:auto; }
75
+ .viewsection-timeline .swim-rows{ max-height:56vh; }
76
+
55
77
  /* ===================== HEADER ===================== */
56
78
  .hdr{
57
79
  height:46px; flex:0 0 auto; display:flex; align-items:center; gap:18px;
@@ -105,7 +127,9 @@
105
127
  .sb-sub{ font-family:var(--mono); font-size:10px; color:var(--tx-lo); }
106
128
  .sb-toggle{ color:var(--tx-lo); font-size:15px; padding:2px 6px; border-radius:4px; }
107
129
  .sb-toggle:hover{ color:var(--tx-hi); background:var(--bg2); }
108
- .sb-list{ flex:1; overflow:auto; padding:8px; display:flex; flex-direction:column; gap:1px; }
130
+ .sb-list{ flex:1 1 0; min-height:0; overflow:auto; padding:8px; display:flex; flex-direction:column; gap:1px; }
131
+ .sb-footer{ flex:1 1 0; min-height:0; display:flex; flex-direction:column; border-top:1px solid var(--bd2); overflow:hidden; padding:8px; }
132
+ .sb-footer .alertpanel{ flex:1 1 0; min-height:0; }
109
133
  .sb-item{ display:flex; flex-direction:column; gap:3px; text-align:left; padding:7px 9px; border-radius:5px; transition:.12s; border:1px solid transparent; }
110
134
  .sb-item:hover{ background:var(--bg2); }
111
135
  .sb-item.is-active{ background:var(--bg2); border-color:var(--bd2); }
@@ -206,7 +230,8 @@
206
230
  .sl-done{ color:var(--ok); }
207
231
 
208
232
  /* alerts */
209
- .alertpanel{ flex:0 0 auto; }
233
+ .alertpanel{ flex:1.3 1 0; min-height:0; }
234
+ .alertpanel .panel-body{ flex:1; min-height:0; }
210
235
  .alertlist{ display:flex; flex-direction:column; gap:7px; }
211
236
  .alertitem{ position:relative; display:flex; gap:9px; background:var(--bg2); border:1px solid var(--bd); border-radius:5px; padding:8px 10px 8px 9px; overflow:hidden; }
212
237
  .alert-bar{ position:absolute; left:0; top:0; bottom:0; width:2px; }
@@ -249,7 +274,7 @@
249
274
  @keyframes spawnpop{ from{ opacity:0; transform:translate(-10px,-50%) scale(.8); } to{ opacity:1; transform:translate(0,-50%) scale(1); } }
250
275
  .graph-legend{ position:absolute; left:12px; bottom:10px; font-family:var(--mono); font-size:9.5px; color:var(--tx-faint); }
251
276
 
252
- .graph-detail{ flex:0 0 312px; background:var(--bg1); border:1px solid var(--bd); border-radius:var(--radius); padding:var(--pad); overflow:auto; }
277
+ .graph-detail{ flex:0 0 312px; background:var(--bg1); border:1px solid var(--bd); border-radius:var(--radius); padding:var(--pad); overflow:auto; min-height:0; }
253
278
  .gd-head{ display:flex; align-items:center; gap:11px; margin-bottom:12px; }
254
279
  .gd-role{ font-size:12px; color:var(--tx-mid); }
255
280
  .gd-status{ display:flex; align-items:center; gap:6px; font-family:var(--mono); font-size:10.5px; margin-top:3px; }
@@ -27,7 +27,7 @@ import type { AgentRole, DocTarget } from "../../lib/brick/contract";
27
27
  import type { MetricsSample } from "../../lib/metrics/sampler";
28
28
 
29
29
  import { Header, Sidebar, type BrickView } from "./ui";
30
- import { GridView } from "./views-grid";
30
+ import { GridView, AlertRail } from "./views-grid";
31
31
  import { GraphView } from "./views-graph";
32
32
  import { TimelineView } from "./views-timeline";
33
33
  import { DocViewer } from "./reports";
@@ -100,6 +100,13 @@ export function BrickDashboard({
100
100
  s.ctrend = metrics.ctrend ?? [];
101
101
  }
102
102
 
103
+ // All three views render on one screen; the header buttons jump to a section.
104
+ useEffect(() => {
105
+ const id =
106
+ view === "grid" ? "view-command" : view === "graph" ? "view-orchestration" : "view-timeline";
107
+ document.getElementById(id)?.scrollIntoView({ behavior: "smooth", block: "start" });
108
+ }, [view]);
109
+
103
110
  const openDoc = (target: DocTarget): void => setDoc(target);
104
111
  const closeDoc = (): void => setDoc(null);
105
112
 
@@ -113,23 +120,36 @@ export function BrickDashboard({
113
120
  onToggle={() => setCollapsed((c) => !c)}
114
121
  missions={snapshot.missions}
115
122
  ownerHistory={snapshot.ownerHistory}
123
+ footer={
124
+ s.alerts.length ? (
125
+ <AlertRail alerts={s.alerts} now={s.now} openDoc={openDoc} />
126
+ ) : undefined
127
+ }
116
128
  />
117
129
  <div className="app-main">
118
- {view === "grid" && (
119
- <div className="viewscroll">
120
- <GridView s={s} layout={t.agentLayout} openDoc={openDoc} />
121
- </div>
122
- )}
123
- {view === "graph" && (
124
- <div className="viewscroll viewscroll-graph">
125
- <GraphView s={s} sel={sel} setSel={setSel} openDoc={openDoc} />
126
- </div>
127
- )}
128
- {view === "timeline" && (
129
- <div className="viewscroll">
130
- <TimelineView s={s} openDoc={openDoc} />
131
- </div>
132
- )}
130
+ {/* All three views consolidated on one scrolling screen — no
131
+ switching. The header COMMAND/ORCHESTRATION/TIMELINE buttons
132
+ jump to the matching section. */}
133
+ <div className="viewstack">
134
+ <section className="viewsection viewsection-command" id="view-command">
135
+ <div className="viewsection-head"><b>Command</b><span>agents · work in flight · live stream</span></div>
136
+ <div className="viewsection-body">
137
+ <GridView s={s} layout={t.agentLayout} openDoc={openDoc} />
138
+ </div>
139
+ </section>
140
+ <section className="viewsection viewsection-timeline" id="view-timeline">
141
+ <div className="viewsection-head"><b>Heatmap</b><span>cadence · swimlanes · last 12h</span></div>
142
+ <div className="viewsection-body">
143
+ <TimelineView s={s} openDoc={openDoc} />
144
+ </div>
145
+ </section>
146
+ <section className="viewsection viewsection-graph" id="view-orchestration">
147
+ <div className="viewsection-head"><b>Orchestration</b><span>CEO → CXX → workers</span></div>
148
+ <div className="viewsection-body">
149
+ <GraphView s={s} sel={sel} setSel={setSel} openDoc={openDoc} />
150
+ </div>
151
+ </section>
152
+ </div>
133
153
  </div>
134
154
  </div>
135
155
 
@@ -418,6 +418,8 @@ export interface SidebarProps {
418
418
  missions?: MissionDoc[];
419
419
  /** Real owner prompt history; used when missions are absent. */
420
420
  ownerHistory?: OwnerPromptEntry[];
421
+ /** Optional bottom-half content (e.g. the ATTENTION rail), split 1:1 under the list. */
422
+ footer?: React.ReactNode;
421
423
  }
422
424
 
423
425
  export function Sidebar({
@@ -425,6 +427,7 @@ export function Sidebar({
425
427
  onToggle,
426
428
  missions,
427
429
  ownerHistory,
430
+ footer,
428
431
  }: SidebarProps): React.JSX.Element {
429
432
  const entries = buildSidebarEntries(missions, ownerHistory);
430
433
  const [sel, setSel] = useState<string>(entries[0]?.id ?? "");
@@ -458,6 +461,7 @@ export function Sidebar({
458
461
  ))}
459
462
  </div>
460
463
  )}
464
+ {!collapsed && footer && <div className="sb-footer">{footer}</div>}
461
465
  </aside>
462
466
  );
463
467
  }
@@ -455,7 +455,7 @@ export interface AlertRailProps {
455
455
  export function AlertRail({ alerts, now, openDoc }: AlertRailProps) {
456
456
  if (!alerts.length) return null;
457
457
  return (
458
- <Panel title="ATTENTION · IN-LOOP" right={alerts.length} className="alertpanel">
458
+ <Panel title="ATTENTION · IN-LOOP" right={alerts.length} className="alertpanel" scroll>
459
459
  <div className="alertlist">
460
460
  {alerts.map((al) => {
461
461
  const a = defOf(al.agent);
@@ -534,7 +534,8 @@ export function GridView({ s, layout = "card", openDoc }: GridViewProps) {
534
534
  <TaskRail s={s} openDoc={openDoc} />
535
535
  </div>
536
536
  <div className="gridview-rail">
537
- <AlertRail alerts={s.alerts} now={s.now} openDoc={openDoc} />
537
+ {/* ATTENTION rail moved to the sidebar footer; the command rail now
538
+ carries just the live stream (shorter section). */}
538
539
  <LiveStream events={s.events} openDoc={openDoc} />
539
540
  </div>
540
541
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.44",
3
+ "version": "7.1.46",
4
4
  "description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"