@walwal-harness/cli 7.1.40 → 7.1.42

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 (84) hide show
  1. package/HR-Resource/cdo/SKILL.md +9 -1
  2. package/HR-Resource/ceo/SKILL.md +33 -2
  3. package/HR-Resource/coo/SKILL.md +9 -1
  4. package/HR-Resource/cqo/SKILL.md +9 -1
  5. package/HR-Resource/cto/SKILL.md +10 -2
  6. package/HR-Resource/ops/SKILL.md +12 -4
  7. package/HR-Resource/ops-prompt-inspector/SKILL.md +11 -6
  8. package/HR-Resource/ops-prompt-inspector/assets/prompt-inspector-static.js +180 -0
  9. package/HR-Resource/ops-prompt-inspector/scripts/setup.py +66 -3
  10. package/apps/harness-dashboard/app/api/metrics/route.ts +17 -0
  11. package/apps/harness-dashboard/app/api/wake/route.ts +41 -0
  12. package/apps/harness-dashboard/app/brick.css +482 -0
  13. package/apps/harness-dashboard/app/layout.tsx +13 -0
  14. package/apps/harness-dashboard/app/page.tsx +2 -2
  15. package/apps/harness-dashboard/components/Scene.tsx +690 -36
  16. package/apps/harness-dashboard/components/brick/BrickDashboard.tsx +149 -0
  17. package/apps/harness-dashboard/components/brick/reports.tsx +291 -0
  18. package/apps/harness-dashboard/components/brick/tweaks.tsx +738 -0
  19. package/apps/harness-dashboard/components/brick/ui.tsx +463 -0
  20. package/apps/harness-dashboard/components/brick/views-graph.tsx +305 -0
  21. package/apps/harness-dashboard/components/brick/views-grid.tsx +543 -0
  22. package/apps/harness-dashboard/components/brick/views-timeline.tsx +238 -0
  23. package/apps/harness-dashboard/lib/__tests__/harness-state.test.ts +1 -202
  24. package/apps/harness-dashboard/lib/__tests__/sandbox-e2e.test.ts +490 -0
  25. package/apps/harness-dashboard/lib/brick/adapter.ts +423 -0
  26. package/apps/harness-dashboard/lib/brick/contract.ts +247 -0
  27. package/apps/harness-dashboard/lib/harness-state.ts +107 -796
  28. package/apps/harness-dashboard/lib/metrics/sampler.ts +545 -0
  29. package/apps/harness-dashboard/lib/types.ts +22 -222
  30. package/apps/harness-dashboard/playwright.config.ts +26 -7
  31. package/assets/templates/AGENTS-ko.md.template +1 -1
  32. package/assets/templates/AGENTS.md.template +12 -2
  33. package/assets/templates/HARNESS.md +2 -0
  34. package/assets/templates/company-pipeline-manifest.json +5 -14
  35. package/assets/templates/worker-report.md.template +38 -0
  36. package/bin/init.js +2 -1
  37. package/commands/goal.md +4 -2
  38. package/commands/hot-fix.md +1 -1
  39. package/commands/submission.md +1 -1
  40. package/package.json +1 -1
  41. package/scripts/conductor-tick.sh +12 -0
  42. package/scripts/harness-agenda.sh +105 -0
  43. package/scripts/harness-company-block.sh +89 -0
  44. package/scripts/harness-company-complete.sh +17 -8
  45. package/scripts/harness-company-cycle.sh +54 -0
  46. package/scripts/harness-progress-set.sh +8 -2
  47. package/scripts/harness-stop.sh +76 -0
  48. package/scripts/harness-wake-control.sh +151 -0
  49. package/scripts/harness-wake.sh +5 -0
  50. package/scripts/harness-worker-dispatch.sh +31 -7
  51. package/apps/harness-dashboard/components/Drawer.tsx +0 -146
  52. package/apps/harness-dashboard/components/Header.tsx +0 -40
  53. package/apps/harness-dashboard/components/MissionTimeline.tsx +0 -214
  54. package/apps/harness-dashboard/components/OrgTree.tsx +0 -459
  55. package/apps/harness-dashboard/components/drawer/AgentLogTab.tsx +0 -56
  56. package/apps/harness-dashboard/components/drawer/DesignPreviewTab.tsx +0 -160
  57. package/apps/harness-dashboard/components/drawer/GotchasTab.tsx +0 -89
  58. package/apps/harness-dashboard/components/drawer/HypothesisTab.tsx +0 -42
  59. package/apps/harness-dashboard/components/drawer/IncidentsTab.tsx +0 -50
  60. package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +0 -96
  61. package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +0 -576
  62. package/apps/harness-dashboard/components/drawer/OwnerHistoryTab.tsx +0 -160
  63. package/apps/harness-dashboard/components/drawer/RoomMetricsTab.tsx +0 -90
  64. package/apps/harness-dashboard/components/drawer/TracksTab.tsx +0 -47
  65. package/apps/harness-dashboard/components/three/ArchiveBoxes.tsx +0 -95
  66. package/apps/harness-dashboard/components/three/DeptBoard.tsx +0 -175
  67. package/apps/harness-dashboard/components/three/Floor3D.tsx +0 -404
  68. package/apps/harness-dashboard/components/three/GoalCard3D.tsx +0 -123
  69. package/apps/harness-dashboard/components/three/HypothesisCards.tsx +0 -71
  70. package/apps/harness-dashboard/components/three/MeetingWhiteboard.tsx +0 -98
  71. package/apps/harness-dashboard/components/three/Minifig3D.tsx +0 -391
  72. package/apps/harness-dashboard/components/three/OpsSiren.tsx +0 -99
  73. package/apps/harness-dashboard/components/three/Stage3D.tsx +0 -104
  74. package/apps/harness-dashboard/components/three/TrackRibbons.tsx +0 -81
  75. package/apps/harness-dashboard/lib/__tests__/i18n.test.ts +0 -16
  76. package/apps/harness-dashboard/lib/__tests__/iso.test.ts +0 -42
  77. package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +0 -183
  78. package/apps/harness-dashboard/lib/agent-roster.ts +0 -42
  79. package/apps/harness-dashboard/lib/furniture.ts +0 -165
  80. package/apps/harness-dashboard/lib/i18n.ts +0 -26
  81. package/apps/harness-dashboard/lib/iso.ts +0 -150
  82. package/apps/harness-dashboard/lib/markdown.tsx +0 -306
  83. package/apps/harness-dashboard/lib/path-planning.ts +0 -72
  84. package/apps/harness-dashboard/lib/state-mapping.ts +0 -146
@@ -0,0 +1,305 @@
1
+ "use client";
2
+
3
+ /* =============================================================
4
+ walwal-harness · VIEW 2 — ORCHESTRATION (node-edge graph)
5
+ Ported from design_handoff_harness_dashboard/harness/views-graph.jsx.
6
+ Exports: GraphView, useSize
7
+
8
+ Renders the CEO -> exec -> worker node/edge graph (animated active
9
+ edges, ResizeObserver sizing) plus a detail panel for the selected
10
+ node. Every value comes from the real-data Contract (ContractState);
11
+ where the contract is honest about missing data (null heartbeat /
12
+ progress / event time) we render an em-dash, never a fake number.
13
+ ============================================================= */
14
+
15
+ import React, { useState, useRef, useLayoutEffect } from "react";
16
+ import {
17
+ fmt,
18
+ statusColor,
19
+ type AgentRole,
20
+ type AgentStatus,
21
+ type ContractState,
22
+ type ContractAgent,
23
+ type ContractWorker,
24
+ type DocTarget,
25
+ } from "../../lib/brick/contract";
26
+ import { StatusDot, Label } from "./ui";
27
+
28
+ /* ---- sizing hook ------------------------------------------------------ */
29
+
30
+ export interface Size {
31
+ w: number;
32
+ h: number;
33
+ }
34
+
35
+ export function useSize(ref: React.RefObject<HTMLElement | null>): Size {
36
+ const [size, setSize] = useState<Size>({ w: 1000, h: 600 });
37
+ useLayoutEffect(() => {
38
+ if (!ref.current) return;
39
+ const ro = new ResizeObserver((ents) => {
40
+ const r = ents[0].contentRect;
41
+ setSize({ w: r.width, h: r.height });
42
+ });
43
+ ro.observe(ref.current);
44
+ return () => ro.disconnect();
45
+ }, [ref]);
46
+ return size;
47
+ }
48
+
49
+ /* ---- helpers ---------------------------------------------------------- */
50
+
51
+ interface Point {
52
+ x: number;
53
+ y: number;
54
+ }
55
+
56
+ /** Inline `--hue` custom property (kept as the mockup's per-node convention). */
57
+ type HueStyle = React.CSSProperties & { "--hue"?: string };
58
+
59
+ const isActive = (st: AgentStatus): boolean =>
60
+ st === "typing" || st === "talking" || st === "active" || st === "live";
61
+
62
+ const edge = (a: Point, b: Point): string =>
63
+ `M${a.x} ${a.y} C ${(a.x + b.x) / 2} ${a.y}, ${(a.x + b.x) / 2} ${b.y}, ${b.x} ${b.y}`;
64
+
65
+ /** Honest progress width: null -> 0 (no fabricated bar). */
66
+ const progWidth = (p: number | null): number => (p == null ? 0 : Math.round(p));
67
+ /** Honest progress label: null -> em-dash. */
68
+ const progLabel = (p: number | null): string => (p == null ? "—" : Math.round(p) + "%");
69
+
70
+ /* ---- props ------------------------------------------------------------ */
71
+
72
+ export interface GraphViewProps {
73
+ s: ContractState;
74
+ /** Selected node id (controlled). Falls back to an internal default. */
75
+ sel?: AgentRole;
76
+ setSel?: (id: AgentRole) => void;
77
+ /** Open a report document for an agent or worker. */
78
+ openDoc?: (target: DocTarget) => void;
79
+ }
80
+
81
+ /* ---- GraphView -------------------------------------------------------- */
82
+
83
+ export function GraphView({ s, sel: selProp, setSel: setSelProp, openDoc }: GraphViewProps) {
84
+ const wrapRef = useRef<HTMLDivElement | null>(null);
85
+ const { w: W, h: H } = useSize(wrapRef);
86
+ const [selLocal, setSelLocal] = useState<AgentRole>("cto");
87
+ const sel = selProp ?? selLocal;
88
+ const setSel = setSelProp ?? setSelLocal;
89
+
90
+ const pad = 56;
91
+ const order: AgentRole[] = ["ceo", "coo", "cto", "cqo", "cdo", "ops"];
92
+ const execs: ContractAgent[] = order
93
+ .map((id) => s.agents.find((a) => a.id === id))
94
+ .filter((a): a is ContractAgent => Boolean(a));
95
+
96
+ // workers grouped by exec order
97
+ const workers: ContractWorker[] = [];
98
+ execs.forEach((e) =>
99
+ s.workers.filter((w) => w.agent === e.id).forEach((w) => workers.push(w))
100
+ );
101
+ const N = Math.max(workers.length, 1);
102
+
103
+ const xCEO = pad + 24;
104
+ const xExec = Math.max(260, W * 0.4);
105
+ const xWork = Math.max(520, W * 0.8);
106
+
107
+ const wpos: Record<string, Point> = {};
108
+ workers.forEach((w, i) => {
109
+ wpos[w.id] = { x: xWork, y: pad + ((i + 0.5) * (H - 2 * pad)) / N };
110
+ });
111
+ const epos: Record<string, Point> = {};
112
+ execs.forEach((e, i) => {
113
+ const mine = workers.filter((w) => w.agent === e.id);
114
+ const y = mine.length
115
+ ? mine.reduce((acc, w) => acc + wpos[w.id].y, 0) / mine.length
116
+ : pad + ((i + 0.5) * (H - 2 * pad)) / execs.length;
117
+ epos[e.id] = { x: xExec, y };
118
+ });
119
+ const ceoPos: Point = { x: xCEO, y: H / 2 };
120
+
121
+ const selAgent: ContractAgent = s.agents.find((a) => a.id === sel) ?? execs[0];
122
+ const selWorkers = s.workers.filter((w) => w.agent === sel);
123
+ const selEvents = s.events.filter((e) => e.agent === sel).slice(-10).reverse();
124
+
125
+ return (
126
+ <div className="graphview">
127
+ <div className="graph-wrap" ref={wrapRef}>
128
+ <svg className="graph-edges" width={W} height={H}>
129
+ {execs.map((e) => {
130
+ const active = isActive(e.status);
131
+ return (
132
+ <path
133
+ key={"ce" + e.id}
134
+ d={edge(ceoPos, epos[e.id])}
135
+ className={"gedge" + (active ? " is-active" : "")}
136
+ style={{ stroke: e.hue, "--hue": e.hue } as HueStyle}
137
+ />
138
+ );
139
+ })}
140
+ {workers.map((w) => {
141
+ const e = s.agents.find((a) => a.id === w.agent);
142
+ const active = isActive(w.status);
143
+ return (
144
+ <path
145
+ key={"ew" + w.id}
146
+ d={edge(epos[w.agent], wpos[w.id])}
147
+ className={"gedge gedge-w" + (active ? " is-active" : "")}
148
+ style={{ stroke: e?.hue, "--hue": e?.hue } as HueStyle}
149
+ />
150
+ );
151
+ })}
152
+ </svg>
153
+
154
+ {/* CEO root */}
155
+ <div
156
+ className="gnode gnode-root"
157
+ style={{ left: ceoPos.x, top: ceoPos.y, "--hue": "#4cc2ff" } as HueStyle}
158
+ onClick={() => setSel("ceo")}
159
+ >
160
+ <span className="gnode-ring" />
161
+ <span className="glyph" style={{ color: "#4cc2ff", borderColor: "#4cc2ff66" }}>
162
+ CEO
163
+ </span>
164
+ <span className="gnode-cap">root loop</span>
165
+ </div>
166
+
167
+ {/* exec nodes */}
168
+ {execs
169
+ .filter((e) => e.id !== "ceo")
170
+ .map((e) => {
171
+ const active = isActive(e.status);
172
+ return (
173
+ <div
174
+ key={e.id}
175
+ className={
176
+ "gnode gnode-exec" +
177
+ (sel === e.id ? " is-sel" : "") +
178
+ (active ? " is-alive" : "")
179
+ }
180
+ style={{ left: epos[e.id].x, top: epos[e.id].y, "--hue": e.hue } as HueStyle}
181
+ onClick={() => setSel(e.id)}
182
+ >
183
+ {active && <span className="gnode-ring" />}
184
+ <span className="glyph" style={{ color: e.hue, borderColor: e.hue + "66" }}>
185
+ {e.name}
186
+ </span>
187
+ <span className="gnode-meta">
188
+ <StatusDot status={e.status} size={6} />
189
+ {e.workers}w
190
+ </span>
191
+ </div>
192
+ );
193
+ })}
194
+
195
+ {/* worker nodes */}
196
+ {workers.map((w) => {
197
+ const e = s.agents.find((a) => a.id === w.agent);
198
+ const hue = e?.hue;
199
+ const fresh = w.started != null && s.now - w.started < 4000;
200
+ return (
201
+ <div
202
+ key={w.id}
203
+ className={
204
+ "gnode gnode-worker" +
205
+ (sel === w.agent ? " is-dim-on" : "") +
206
+ (fresh ? " is-fresh" : "")
207
+ }
208
+ style={{ left: wpos[w.id].x, top: wpos[w.id].y, "--hue": hue } as HueStyle}
209
+ onClick={() => setSel(w.agent)}
210
+ title={w.name}
211
+ >
212
+ <span className="gw-dot" style={{ background: hue }} />
213
+ <span className="gw-name">{w.name}</span>
214
+ <span className="gw-prog">
215
+ <span style={{ width: progWidth(w.progress) + "%", background: hue }} />
216
+ </span>
217
+ </div>
218
+ );
219
+ })}
220
+
221
+ <div className="graph-legend">
222
+ <span>CEO → exec → worker · animated edge = active dispatch</span>
223
+ </div>
224
+ </div>
225
+
226
+ <aside className="graph-detail">
227
+ <Label right={selAgent.loop}>NODE · {selAgent.name}</Label>
228
+ <div className="gd-head" style={{ "--hue": selAgent.hue } as HueStyle}>
229
+ <span
230
+ className="glyph glyph-lg"
231
+ style={{ color: selAgent.hue, borderColor: selAgent.hue + "66" }}
232
+ >
233
+ {selAgent.name}
234
+ </span>
235
+ <div>
236
+ <div className="gd-role">{selAgent.role}</div>
237
+ <div className="gd-status" style={{ color: statusColor(selAgent.status) }}>
238
+ <StatusDot status={selAgent.status} size={7} />
239
+ {selAgent.status} · loop {selAgent.loop}
240
+ </div>
241
+ </div>
242
+ <button
243
+ className="gd-read"
244
+ onClick={() => openDoc && openDoc({ type: "agent", agent: selAgent.id })}
245
+ >
246
+ read report ↗
247
+ </button>
248
+ </div>
249
+ <div className="gd-work">{selAgent.work}</div>
250
+ <div className="gd-stats">
251
+ <div>
252
+ <b>{selWorkers.length}</b>
253
+ <span>workers</span>
254
+ </div>
255
+ <div>
256
+ <b>{selAgent.todos}</b>
257
+ <span>open todos</span>
258
+ </div>
259
+ <div>
260
+ <b>{selAgent.heartbeat == null ? "—" : fmt.ago(s.now - selAgent.heartbeat)}</b>
261
+ <span>heartbeat</span>
262
+ </div>
263
+ </div>
264
+ <Label>SPAWNED WORKERS</Label>
265
+ <div className="gd-workers">
266
+ {selWorkers.length === 0 && <div className="gd-empty">no active workers</div>}
267
+ {selWorkers.map((w) => (
268
+ <button
269
+ key={w.id}
270
+ className="gd-worker"
271
+ onClick={() => openDoc && openDoc({ type: "worker", agent: selAgent.id, worker: w })}
272
+ >
273
+ <StatusDot status={w.status} size={6} />
274
+ <span className="gd-wname">{w.name}</span>
275
+ <span className="gd-wprog">
276
+ <span className="prog-bar">
277
+ <span
278
+ className="prog-fill"
279
+ style={{ width: progWidth(w.progress) + "%", background: selAgent.hue }}
280
+ />
281
+ </span>
282
+ {progLabel(w.progress)}
283
+ </span>
284
+ </button>
285
+ ))}
286
+ </div>
287
+ <Label>RECENT · {selAgent.name}</Label>
288
+ <div className="gd-events">
289
+ {selEvents.map((e) => (
290
+ <button
291
+ key={e.id}
292
+ className="gd-ev"
293
+ onClick={() => openDoc && openDoc({ type: "agent", agent: selAgent.id })}
294
+ >
295
+ <span className="sl-time">{e.at == null ? "—" : fmt.time(new Date(e.at))}</span>
296
+ <span className="sl-msg">
297
+ {e.verb} <span className="sl-obj">`{e.obj}`</span>
298
+ </span>
299
+ </button>
300
+ ))}
301
+ </div>
302
+ </aside>
303
+ </div>
304
+ );
305
+ }