@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,463 @@
1
+ "use client";
2
+
3
+ /* =============================================================
4
+ walwal-harness · BRICK OFFICE shared UI primitives + chrome
5
+ Ported from design_handoff_harness_dashboard/harness/ui.jsx.
6
+
7
+ Babel-inline globals -> ES modules. No window.* access.
8
+ classNames/CSS preserved verbatim (CSS lives in app/brick.css).
9
+ `statusColor` lives in lib/brick/contract — imported here.
10
+
11
+ Exports: StatusDot, Pill, Label, Panel, Spark, Bars, AgentGlyph,
12
+ Header, Sidebar.
13
+ ============================================================= */
14
+
15
+ import React, { useState } from "react";
16
+ import {
17
+ statusColor,
18
+ type AgentDef,
19
+ type ContractMetrics,
20
+ type ContractAlert,
21
+ } from "../../lib/brick/contract";
22
+ import type { MissionDoc, OwnerPromptEntry } from "../../lib/types";
23
+
24
+ /* ---- the three top-level views (COMMAND / ORCHESTRATION / TIMELINE) --- */
25
+ export type BrickView = "grid" | "graph" | "timeline";
26
+
27
+ /* ---- StatusDot -------------------------------------------------------- */
28
+ export interface StatusDotProps {
29
+ status: string;
30
+ /** Optional override colour; defaults to `statusColor(status)`. */
31
+ hue?: string;
32
+ size?: number;
33
+ pulse?: boolean;
34
+ }
35
+
36
+ export function StatusDot({
37
+ status,
38
+ hue,
39
+ size = 8,
40
+ pulse = true,
41
+ }: StatusDotProps): React.JSX.Element {
42
+ const c = hue || statusColor(status);
43
+ const animate =
44
+ pulse &&
45
+ (status === "live" ||
46
+ status === "typing" ||
47
+ status === "talking" ||
48
+ status === "active" ||
49
+ status === "alert");
50
+ return (
51
+ <span className="dot-wrap" style={{ width: size, height: size }}>
52
+ {animate && <span className="dot-pulse" style={{ background: c }} />}
53
+ <span
54
+ className="dot-core"
55
+ style={{ background: c, width: size, height: size }}
56
+ />
57
+ </span>
58
+ );
59
+ }
60
+
61
+ /* ---- Pill ------------------------------------------------------------- */
62
+ export interface PillProps {
63
+ children: React.ReactNode;
64
+ tone?: "mute" | "ok" | "alert";
65
+ glow?: string;
66
+ onClick?: () => void;
67
+ active?: boolean;
68
+ }
69
+
70
+ export function Pill({
71
+ children,
72
+ tone = "mute",
73
+ glow,
74
+ onClick,
75
+ active,
76
+ }: PillProps): React.JSX.Element {
77
+ return (
78
+ <span
79
+ className={"pill pill-" + tone + (active ? " is-active" : "")}
80
+ onClick={onClick}
81
+ style={onClick ? { cursor: "pointer" } : undefined}
82
+ >
83
+ {glow && <span className="pill-glow" style={{ background: glow }} />}
84
+ {children}
85
+ </span>
86
+ );
87
+ }
88
+
89
+ /* ---- Label ------------------------------------------------------------ */
90
+ export interface LabelProps {
91
+ children: React.ReactNode;
92
+ right?: React.ReactNode;
93
+ }
94
+
95
+ export function Label({ children, right }: LabelProps): React.JSX.Element {
96
+ return (
97
+ <div className="seclabel">
98
+ <span>{children}</span>
99
+ {right != null && <span className="seclabel-right">{right}</span>}
100
+ </div>
101
+ );
102
+ }
103
+
104
+ /* ---- Panel ------------------------------------------------------------ */
105
+ export interface PanelProps {
106
+ title?: React.ReactNode;
107
+ right?: React.ReactNode;
108
+ children: React.ReactNode;
109
+ className?: string;
110
+ flush?: boolean;
111
+ scroll?: boolean;
112
+ }
113
+
114
+ export function Panel({
115
+ title,
116
+ right,
117
+ children,
118
+ className = "",
119
+ flush,
120
+ scroll,
121
+ }: PanelProps): React.JSX.Element {
122
+ return (
123
+ <section className={"panel " + className}>
124
+ {title && <Label right={right}>{title}</Label>}
125
+ <div
126
+ className={
127
+ "panel-body" + (flush ? " flush" : "") + (scroll ? " scroll" : "")
128
+ }
129
+ >
130
+ {children}
131
+ </div>
132
+ </section>
133
+ );
134
+ }
135
+
136
+ /* ---- Spark (SVG line/area sparkline) ---------------------------------- */
137
+ export interface SparkProps {
138
+ data: number[];
139
+ color?: string;
140
+ w?: number;
141
+ h?: number;
142
+ fill?: boolean;
143
+ }
144
+
145
+ export function Spark({
146
+ data,
147
+ color = "#4cc2ff",
148
+ w = 80,
149
+ h = 22,
150
+ fill = true,
151
+ }: SparkProps): React.JSX.Element | null {
152
+ if (!data || !data.length) return null;
153
+ const max = Math.max(...data, 1);
154
+ const min = Math.min(...data, 0);
155
+ const span = max - min || 1;
156
+ const step = w / (data.length - 1);
157
+ const pts = data.map(
158
+ (v, i): [number, number] => [i * step, h - ((v - min) / span) * (h - 3) - 1.5]
159
+ );
160
+ const line = pts
161
+ .map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1))
162
+ .join(" ");
163
+ const area = line + ` L${w} ${h} L0 ${h} Z`;
164
+ const gid = "sg" + color.replace("#", "");
165
+ return (
166
+ <svg
167
+ width={w}
168
+ height={h}
169
+ className="spark"
170
+ preserveAspectRatio="none"
171
+ viewBox={`0 0 ${w} ${h}`}
172
+ >
173
+ <defs>
174
+ <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
175
+ <stop offset="0" stopColor={color} stopOpacity="0.28" />
176
+ <stop offset="1" stopColor={color} stopOpacity="0" />
177
+ </linearGradient>
178
+ </defs>
179
+ {fill && <path d={area} fill={`url(#${gid})`} />}
180
+ <path
181
+ d={line}
182
+ fill="none"
183
+ stroke={color}
184
+ strokeWidth="1.4"
185
+ strokeLinejoin="round"
186
+ />
187
+ </svg>
188
+ );
189
+ }
190
+
191
+ /* ---- Bars (bar-style sparkline, for spark counts) --------------------- */
192
+ export interface BarsProps {
193
+ data: number[];
194
+ color?: string;
195
+ w?: number;
196
+ h?: number;
197
+ }
198
+
199
+ export function Bars({
200
+ data,
201
+ color = "#4cc2ff",
202
+ w = 80,
203
+ h = 22,
204
+ }: BarsProps): React.JSX.Element {
205
+ const max = Math.max(...data, 1);
206
+ const bw = w / data.length;
207
+ return (
208
+ <svg width={w} height={h} className="spark" viewBox={`0 0 ${w} ${h}`}>
209
+ {data.map((v, i) => {
210
+ const bh = Math.max(1, (v / max) * (h - 2));
211
+ return (
212
+ <rect
213
+ key={i}
214
+ x={i * bw + 0.5}
215
+ y={h - bh}
216
+ width={Math.max(1, bw - 1)}
217
+ height={bh}
218
+ fill={color}
219
+ opacity={0.35 + 0.65 * (i / data.length)}
220
+ rx="0.5"
221
+ />
222
+ );
223
+ })}
224
+ </svg>
225
+ );
226
+ }
227
+
228
+ /* ---- AgentGlyph ------------------------------------------------------- */
229
+ export interface AgentGlyphProps {
230
+ agent: Pick<AgentDef, "name" | "hue">;
231
+ size?: number;
232
+ }
233
+
234
+ export function AgentGlyph({
235
+ agent,
236
+ size = 26,
237
+ }: AgentGlyphProps): React.JSX.Element {
238
+ return (
239
+ <span
240
+ className="glyph"
241
+ style={{ width: size, height: size, color: agent.hue, borderColor: agent.hue + "55" }}
242
+ >
243
+ {agent.name}
244
+ </span>
245
+ );
246
+ }
247
+
248
+ /* ---- Header ----------------------------------------------------------- */
249
+ export interface HeaderProps {
250
+ metrics: ContractMetrics;
251
+ view: BrickView;
252
+ setView: (v: BrickView) => void;
253
+ alerts: ContractAlert[];
254
+ }
255
+
256
+ const HEADER_VIEWS: ReadonlyArray<{ id: BrickView; label: string }> = [
257
+ { id: "grid", label: "COMMAND" },
258
+ { id: "graph", label: "ORCHESTRATION" },
259
+ { id: "timeline", label: "TIMELINE" },
260
+ ];
261
+
262
+ const HEADER_LEGEND: ReadonlyArray<string> = [
263
+ "idle",
264
+ "typing",
265
+ "talking",
266
+ "alert",
267
+ ];
268
+
269
+ export function Header({
270
+ metrics,
271
+ view,
272
+ setView,
273
+ alerts,
274
+ }: HeaderProps): React.JSX.Element {
275
+ return (
276
+ <header className="hdr">
277
+ <div className="hdr-left">
278
+ <div className="logo">
279
+ WALWAL<span className="logo-dot">·</span>HARNESS
280
+ </div>
281
+ <span className="hdr-tag">ai_camera_web</span>
282
+ <span className="hdr-crumb">live operations dashboard</span>
283
+ </div>
284
+
285
+ <nav className="viewswitch">
286
+ {HEADER_VIEWS.map((v) => (
287
+ <button
288
+ key={v.id}
289
+ className={"vs-btn" + (view === v.id ? " is-active" : "")}
290
+ onClick={() => setView(v.id)}
291
+ >
292
+ {v.label}
293
+ </button>
294
+ ))}
295
+ </nav>
296
+
297
+ <div className="hdr-right">
298
+ <Pill tone="ok" glow="#3fd17a">
299
+ SSE <b>{metrics.sse}</b>
300
+ </Pill>
301
+ <Pill tone="mute">
302
+ Hot-fix <b>{metrics.hotfix}</b>
303
+ </Pill>
304
+ {alerts.length > 0 && (
305
+ <Pill tone="alert" glow="#f0506b">
306
+ alerts <b>{alerts.length}</b>
307
+ </Pill>
308
+ )}
309
+ <span className="legend">
310
+ {HEADER_LEGEND.map((s) => (
311
+ <span key={s} className="legend-item">
312
+ <StatusDot status={s} size={6} pulse={false} />
313
+ {s}
314
+ </span>
315
+ ))}
316
+ </span>
317
+ </div>
318
+ </header>
319
+ );
320
+ }
321
+
322
+ /* ---- Sidebar ---------------------------------------------------------- */
323
+
324
+ /** One row in the workflow-history list. */
325
+ export interface SidebarEntry {
326
+ /** Stable id for selection / React key. */
327
+ id: string;
328
+ /** The displayed tag, e.g. "GOAL" | "HOT-FIX" | "SUBMIT" | "SESSION". */
329
+ tag: string;
330
+ /** The displayed workflow name. */
331
+ name: string;
332
+ }
333
+
334
+ /** The mockup's static look (used when no real data is supplied). */
335
+ const GOAL_HISTORY_FALLBACK: ReadonlyArray<SidebarEntry> = [
336
+ { id: "goal-3-test-coverage-scenario", tag: "GOAL", name: "goal-3-test-coverage-scenario" },
337
+ { id: "ops-dev-session", tag: "SESSION", name: "ops-dev-session" },
338
+ { id: "goal-2-rule-preset", tag: "GOAL", name: "goal-2-rule-preset" },
339
+ { id: "hotfix-6-preset-apply", tag: "HOT-FIX", name: "hotfix-6-preset-apply" },
340
+ { id: "hotfix-5-preset-save", tag: "HOT-FIX", name: "hotfix-5-preset-save" },
341
+ { id: "hotfix-4-preset-apply", tag: "HOT-FIX", name: "hotfix-4-preset-apply" },
342
+ { id: "hotfix-3-preset-save", tag: "HOT-FIX", name: "hotfix-3-preset-save" },
343
+ { id: "hotfix-2-rename-safe", tag: "HOT-FIX", name: "hotfix-2-rename-safe" },
344
+ { id: "hotfix-1-preset-apply", tag: "HOT-FIX", name: "hotfix-1-preset-apply" },
345
+ { id: "submission-1-preset", tag: "SUBMIT", name: "submission-1-preset" },
346
+ { id: "goal-1-prd-spec-docs", tag: "GOAL", name: "goal-1-prd-spec-docs" },
347
+ ];
348
+
349
+ /** Map a real mission type to a sidebar display tag. */
350
+ function missionTag(type: MissionDoc["type"]): string {
351
+ switch (type) {
352
+ case "goal":
353
+ return "GOAL";
354
+ case "hotfix":
355
+ return "HOT-FIX";
356
+ case "submission":
357
+ return "SUBMIT";
358
+ case "feature":
359
+ return "GOAL";
360
+ default:
361
+ return "SESSION";
362
+ }
363
+ }
364
+
365
+ /** Map a real owner-prompt type to a sidebar display tag. */
366
+ function promptTag(type: OwnerPromptEntry["type"]): string {
367
+ switch (type) {
368
+ case "goal":
369
+ return "GOAL";
370
+ case "hot-fix":
371
+ return "HOT-FIX";
372
+ case "submission":
373
+ return "SUBMIT";
374
+ default:
375
+ return "SESSION";
376
+ }
377
+ }
378
+
379
+ /** CSS class suffix for a tag, matching the mockup: lowercase, no dash. */
380
+ function tagClass(tag: string): string {
381
+ return "tag-" + tag.toLowerCase().replace("-", "");
382
+ }
383
+
384
+ /**
385
+ * Build the workflow-history list from real data when available.
386
+ * Prefers missions (richer label/type); falls back to ownerHistory; and
387
+ * finally to the static mockup list so the design renders unchanged offline.
388
+ */
389
+ export function buildSidebarEntries(
390
+ missions?: MissionDoc[],
391
+ ownerHistory?: OwnerPromptEntry[]
392
+ ): SidebarEntry[] {
393
+ if (missions && missions.length > 0) {
394
+ return missions.map((m) => ({
395
+ id: m.missionId,
396
+ tag: missionTag(m.type),
397
+ name: m.label || m.missionId,
398
+ }));
399
+ }
400
+ if (ownerHistory && ownerHistory.length > 0) {
401
+ return ownerHistory.map((p, i) => {
402
+ const firstLine = (p.content ?? "").split("\n", 1)[0].trim();
403
+ const name = firstLine.length > 0 ? firstLine : p.type;
404
+ return {
405
+ id: `prompt-${i}-${p.ts}`,
406
+ tag: promptTag(p.type),
407
+ name,
408
+ };
409
+ });
410
+ }
411
+ return GOAL_HISTORY_FALLBACK.map((e) => ({ ...e }));
412
+ }
413
+
414
+ export interface SidebarProps {
415
+ collapsed: boolean;
416
+ onToggle: () => void;
417
+ /** Real missions; when present the list shows real goals/hotfixes/etc. */
418
+ missions?: MissionDoc[];
419
+ /** Real owner prompt history; used when missions are absent. */
420
+ ownerHistory?: OwnerPromptEntry[];
421
+ }
422
+
423
+ export function Sidebar({
424
+ collapsed,
425
+ onToggle,
426
+ missions,
427
+ ownerHistory,
428
+ }: SidebarProps): React.JSX.Element {
429
+ const entries = buildSidebarEntries(missions, ownerHistory);
430
+ const [sel, setSel] = useState<string>(entries[0]?.id ?? "");
431
+ return (
432
+ <aside className={"sidebar" + (collapsed ? " is-collapsed" : "")}>
433
+ <div className="sb-head">
434
+ <span className="sb-avatar">AI</span>
435
+ {!collapsed && (
436
+ <div className="sb-id">
437
+ <div className="sb-name">Administrator</div>
438
+ <div className="sb-sub">workflow history</div>
439
+ </div>
440
+ )}
441
+ <button className="sb-toggle" onClick={onToggle} title="collapse">
442
+ {collapsed ? "›" : "‹"}
443
+ </button>
444
+ </div>
445
+ {!collapsed && (
446
+ <div className="sb-list">
447
+ {entries.map((g) => (
448
+ <button
449
+ key={g.id}
450
+ className={"sb-item" + (sel === g.id ? " is-active" : "")}
451
+ onClick={() => setSel(g.id)}
452
+ >
453
+ <span className={"sb-tag " + tagClass(g.tag)}>
454
+ /{g.tag.toLowerCase()}
455
+ </span>
456
+ <span className="sb-itemname">{g.name}</span>
457
+ </button>
458
+ ))}
459
+ </div>
460
+ )}
461
+ </aside>
462
+ );
463
+ }