@walwal-harness/cli 7.1.26 → 7.1.28
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 +8 -1
- package/apps/harness-dashboard/app/globals.css +165 -3
- package/apps/harness-dashboard/app/layout.tsx +1 -5
- package/apps/harness-dashboard/app/page.tsx +3 -7
- package/apps/harness-dashboard/components/Drawer.tsx +7 -7
- package/apps/harness-dashboard/components/MissionTimeline.tsx +4 -4
- package/apps/harness-dashboard/components/OrgTree.tsx +7 -7
- package/apps/harness-dashboard/components/Scene.tsx +1620 -487
- package/apps/harness-dashboard/lib/harness-state.ts +132 -10
- package/apps/harness-dashboard/lib/types.ts +39 -0
- package/apps/harness-dashboard/package-lock.json +1519 -53
- package/apps/harness-dashboard/package.json +2 -0
- package/assets/templates/AGENTS.md.template +8 -4
- package/assets/templates/HARNESS.md +6 -1
- package/assets/templates/todos-state.json.template +12 -0
- package/bin/init.js +43 -0
- package/package.json +1 -1
- package/scripts/harness-user-prompt-submit.sh +42 -0
- package/scripts/lib/harness-structured-log.sh +59 -0
package/README.md
CHANGED
|
@@ -52,6 +52,9 @@ What `init` installs:
|
|
|
52
52
|
| `.claude/commands/hot-fix.md` | `/hot-fix` Owner command |
|
|
53
53
|
| `.claude/skills/harness-{ceo,coo,cdo,cto,cqo,ops}/` | CXX agent skills |
|
|
54
54
|
| `.harness/shared/HR-Resource/` | Hireable worker skill pool |
|
|
55
|
+
| `.harness/events.jsonl` | Structured append-only runtime event stream |
|
|
56
|
+
| `.harness/todos/state.json` | Machine-readable CXX todo queues |
|
|
57
|
+
| `.harness/todos/events.jsonl` | Structured todo transition history |
|
|
55
58
|
| `AGENTS.md` ← `CLAUDE.md` symlink | Project harness config |
|
|
56
59
|
|
|
57
60
|
---
|
|
@@ -106,6 +109,7 @@ Owner /submission → CEO → [relevant CXX] → [workers] → [convention updat
|
|
|
106
109
|
| 8 | No verdict without worker evidence — CQO self-inspection is not valid |
|
|
107
110
|
| 9 | Hierarchical worker ownership — worker reports live under `.harness/documents/{goal-or-child-mission}/{owning-cxx}/workers/` |
|
|
108
111
|
| 10 | Implementation Notes required — `ceo.md`, every `{cxx}.md`, and every worker report must end with one English `## Implementation Notes` section in the same file |
|
|
112
|
+
| 11 | Structured runtime state — queues, heartbeats, preemption/resume state, and harness-parsed evidence belong in JSON/JSONL, not free-form Markdown |
|
|
109
113
|
|
|
110
114
|
### Implementation Notes Format
|
|
111
115
|
|
|
@@ -133,7 +137,7 @@ Use `None` when a subsection has no entries. This section is mandatory even for
|
|
|
133
137
|
|
|
134
138
|
## Harness Dashboard
|
|
135
139
|
|
|
136
|
-
The harness ships with a real-time dashboard that reads `.harness
|
|
140
|
+
The harness ships with a real-time dashboard that reads `.harness/` runtime state directly. The current dashboard is process-oriented: it highlights CXX todo readiness, active workers, incidents, mission flow, and structured runtime events alongside the organization view.
|
|
137
141
|
|
|
138
142
|
```bash
|
|
139
143
|
bash scripts/harness-dashboard-up.sh
|
|
@@ -199,6 +203,8 @@ npx walwal-harness init --force --project-root /path/to/project
|
|
|
199
203
|
|
|
200
204
|
Features:
|
|
201
205
|
|
|
206
|
+
- **Company Harness Observatory** — glass/aurora process monitor showing active CXX todos, workers, incidents, missions, and current loop state
|
|
207
|
+
- **Structured Runtime State** — `/goal`, `/submission`, and `/hot-fix` append to `.harness/events.jsonl` and update `.harness/todos/state.json`; `migrate` backfills these files for existing projects
|
|
202
208
|
- **Split Workspace** — full-viewport left/right panes keep Org Tree + Mission Timeline beside the selected mission detail; both panes scroll independently with hidden scrollbars, and the detail pane resets to top on selection changes
|
|
203
209
|
- **Org Tree** — live status of Owner → CEO → CXX → Workers hierarchy, with worker cards created only from hired `hr-roster.json` entries backed by `.harness/shared/HR-Resource/{worker}/SKILL.md`; running hired workers are highlighted under their owning CXX
|
|
204
210
|
- **Mission Timeline** — clickable history of goal/submission/hot-fix missions showing the full dispatch chain
|
|
@@ -253,6 +259,7 @@ harness-hiring → register and onboard worker
|
|
|
253
259
|
|
|
254
260
|
| Version | Summary |
|
|
255
261
|
|---|---|
|
|
262
|
+
| 7.1.28 | Dashboard APM rewrite: top header consolidation, Knowledge Base panel (gotchas/conventions), Layer Activity (CEO/CXX/Worker TODO·DONE·Remain via goal-scope inference), Recent Report list (worker mtime desc), Cadence strip with click-to-prompt tooltip in local timezone, heatmap click-tooltip with empty-cell guard, Document Viewer expand-to-50vw with docmeta hidden, Command Log bubble popover |
|
|
256
263
|
| 7.1.19 | `migrate` now carries OPS verification rules into existing installs: runtime.verification merge, HARNESS refresh, and AGENTS migration block |
|
|
257
264
|
| 7.1.18 | OPS watches CQO runnable verification and production incidents; Implementation Notes stay in the same role/worker report |
|
|
258
265
|
| 7.1.17 | Dashboard: fix /submission and /hot-fix missions displaying as /goal; runtime strip shows live owner command in mission flow tab |
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
html,
|
|
6
6
|
body {
|
|
7
7
|
background:
|
|
8
|
-
radial-gradient(circle at
|
|
9
|
-
radial-gradient(circle at
|
|
10
|
-
|
|
8
|
+
radial-gradient(circle at 16% -8%, rgba(125, 211, 252, 0.24), transparent 30rem),
|
|
9
|
+
radial-gradient(circle at 78% 2%, rgba(216, 180, 254, 0.2), transparent 28rem),
|
|
10
|
+
radial-gradient(circle at 52% 104%, rgba(52, 211, 153, 0.14), transparent 34rem),
|
|
11
|
+
linear-gradient(135deg, #080b13 0%, #101728 48%, #070910 100%);
|
|
11
12
|
color: #e5e7eb;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -24,3 +25,164 @@ body {
|
|
|
24
25
|
.scrollbar-hidden::-webkit-scrollbar {
|
|
25
26
|
display: none;
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
/* hide scrollbars globally — scroll still works via wheel/drag/touch */
|
|
30
|
+
* {
|
|
31
|
+
scrollbar-width: none;
|
|
32
|
+
-ms-overflow-style: none;
|
|
33
|
+
}
|
|
34
|
+
*::-webkit-scrollbar {
|
|
35
|
+
width: 0;
|
|
36
|
+
height: 0;
|
|
37
|
+
display: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* document viewer aside expand/minimize */
|
|
41
|
+
.doc-aside {
|
|
42
|
+
width: 380px;
|
|
43
|
+
transition: width 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
44
|
+
}
|
|
45
|
+
.doc-aside.expanded {
|
|
46
|
+
width: 50vw;
|
|
47
|
+
}
|
|
48
|
+
.doc-toggle-icon {
|
|
49
|
+
transition: transform 280ms ease;
|
|
50
|
+
display: inline-block;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* panel / inset shells (translated from mockup) */
|
|
54
|
+
.panel-shell {
|
|
55
|
+
border-radius: 6px;
|
|
56
|
+
border: 1px solid rgba(148, 163, 184, 0.18);
|
|
57
|
+
background: #0b1328;
|
|
58
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
|
|
59
|
+
transition: border-color 200ms ease, box-shadow 200ms ease, transform 200ms ease;
|
|
60
|
+
}
|
|
61
|
+
.panel-shell:hover {
|
|
62
|
+
border-color: rgba(34, 211, 238, 0.25);
|
|
63
|
+
box-shadow: 0 16px 50px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(34, 211, 238, 0.1);
|
|
64
|
+
}
|
|
65
|
+
.inset-shell {
|
|
66
|
+
border-radius: 4px;
|
|
67
|
+
border: 1px solid rgba(15, 23, 42, 0.9);
|
|
68
|
+
background: #071022;
|
|
69
|
+
transition: border-color 200ms ease, transform 160ms ease;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ==== Dynamic / animated bits ==== */
|
|
73
|
+
|
|
74
|
+
/* Panel mount fade-in (used on initial render) */
|
|
75
|
+
@keyframes fade-in-up {
|
|
76
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
77
|
+
to { opacity: 1; transform: translateY(0); }
|
|
78
|
+
}
|
|
79
|
+
.fade-in {
|
|
80
|
+
animation: fade-in-up 360ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* List item slide-in (Recent Report cards) */
|
|
84
|
+
@keyframes slide-in-fade {
|
|
85
|
+
from { opacity: 0; transform: translateX(-6px); }
|
|
86
|
+
to { opacity: 1; transform: translateX(0); }
|
|
87
|
+
}
|
|
88
|
+
.slide-in {
|
|
89
|
+
animation: slide-in-fade 280ms ease-out both;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Heatmap cell baseline transition */
|
|
93
|
+
.heat-cell {
|
|
94
|
+
transition: transform 140ms ease, filter 140ms ease, border-color 140ms ease;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Cadence cell soft pulse when count is at peak */
|
|
98
|
+
@keyframes cad-pulse {
|
|
99
|
+
0%, 100% { filter: brightness(1); }
|
|
100
|
+
50% { filter: brightness(1.4); }
|
|
101
|
+
}
|
|
102
|
+
.cad-peak {
|
|
103
|
+
animation: cad-pulse 1800ms ease-in-out infinite;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Tooltip / popover enter */
|
|
107
|
+
@keyframes pop-in {
|
|
108
|
+
from { opacity: 0; transform: scale(0.96) translateY(4px); }
|
|
109
|
+
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
110
|
+
}
|
|
111
|
+
.pop-in {
|
|
112
|
+
animation: pop-in 180ms cubic-bezier(0.2, 0.9, 0.3, 1) both;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Stacked bar segment width tween */
|
|
116
|
+
.stack-seg {
|
|
117
|
+
will-change: flex-grow;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Worker bar inner shimmer for active CXX (very subtle) */
|
|
121
|
+
@keyframes shimmer-sweep {
|
|
122
|
+
0% { background-position: -200% 0; }
|
|
123
|
+
100% { background-position: 200% 0; }
|
|
124
|
+
}
|
|
125
|
+
.shimmer {
|
|
126
|
+
background-image: linear-gradient(
|
|
127
|
+
100deg,
|
|
128
|
+
rgba(255, 255, 255, 0) 30%,
|
|
129
|
+
rgba(255, 255, 255, 0.18) 50%,
|
|
130
|
+
rgba(255, 255, 255, 0) 70%
|
|
131
|
+
);
|
|
132
|
+
background-size: 200% 100%;
|
|
133
|
+
animation: shimmer-sweep 3.2s linear infinite;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.glass-panel {
|
|
137
|
+
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
138
|
+
background:
|
|
139
|
+
linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.045)),
|
|
140
|
+
rgba(7, 10, 18, 0.58);
|
|
141
|
+
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.16);
|
|
142
|
+
backdrop-filter: blur(22px) saturate(150%);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.brutal-tile {
|
|
146
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
147
|
+
background: rgba(3, 7, 18, 0.64);
|
|
148
|
+
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.34);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.aurora-line {
|
|
152
|
+
background: linear-gradient(90deg, #67e8f9, #c084fc, #f0abfc, #34d399);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.isometric-stage {
|
|
156
|
+
background:
|
|
157
|
+
radial-gradient(circle at 48% 42%, rgba(34, 211, 238, 0.18), transparent 20rem),
|
|
158
|
+
radial-gradient(circle at 78% 24%, rgba(99, 102, 241, 0.14), transparent 18rem),
|
|
159
|
+
radial-gradient(circle at 20% 84%, rgba(16, 185, 129, 0.12), transparent 22rem),
|
|
160
|
+
linear-gradient(135deg, rgba(2, 6, 23, 0.94), rgba(8, 13, 26, 0.98));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@keyframes apm-request-fall {
|
|
164
|
+
0% {
|
|
165
|
+
opacity: 0;
|
|
166
|
+
top: -12px;
|
|
167
|
+
transform: translateX(-50%) scale(0.75);
|
|
168
|
+
}
|
|
169
|
+
12% {
|
|
170
|
+
opacity: 1;
|
|
171
|
+
}
|
|
172
|
+
82% {
|
|
173
|
+
opacity: 1;
|
|
174
|
+
}
|
|
175
|
+
100% {
|
|
176
|
+
opacity: 0;
|
|
177
|
+
top: 184px;
|
|
178
|
+
transform: translateX(-50%) scale(1.15);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.apm-falling-dot {
|
|
183
|
+
top: -12px;
|
|
184
|
+
animation-name: apm-request-fall;
|
|
185
|
+
animation-timing-function: linear;
|
|
186
|
+
animation-iteration-count: infinite;
|
|
187
|
+
box-shadow: 0 0 14px currentColor;
|
|
188
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import type { Metadata } from "next";
|
|
3
3
|
import "./globals.css";
|
|
4
|
-
import { Header } from "@/components/Header";
|
|
5
4
|
import { resolveHarnessRoot } from "@/lib/harness-root";
|
|
6
5
|
|
|
7
6
|
export async function generateMetadata(): Promise<Metadata> {
|
|
@@ -20,10 +19,7 @@ export default function RootLayout({
|
|
|
20
19
|
}) {
|
|
21
20
|
return (
|
|
22
21
|
<html lang="ko">
|
|
23
|
-
<body>
|
|
24
|
-
<Header />
|
|
25
|
-
{children}
|
|
26
|
-
</body>
|
|
22
|
+
<body>{children}</body>
|
|
27
23
|
</html>
|
|
28
24
|
);
|
|
29
25
|
}
|
|
@@ -10,26 +10,22 @@ export default function Page() {
|
|
|
10
10
|
const banner = snapshot.errorBanner;
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<main className="
|
|
13
|
+
<main className="h-[100dvh]">
|
|
14
14
|
{banner && (
|
|
15
15
|
<div
|
|
16
16
|
role="alert"
|
|
17
17
|
data-testid="error-banner"
|
|
18
|
-
className={`mx-
|
|
18
|
+
className={`mx-3 mt-2 rounded border px-3 py-2 text-xs ${
|
|
19
19
|
banner.level === "error"
|
|
20
20
|
? "border-aura-alert/60 bg-aura-alert/10 text-aura-alert"
|
|
21
21
|
: "border-aura-talking/60 bg-aura-talking/10 text-aura-talking"
|
|
22
22
|
}`}
|
|
23
23
|
>
|
|
24
24
|
<div>{banner.message_ko}</div>
|
|
25
|
-
<div className="
|
|
25
|
+
<div className="mt-1 text-[10px] opacity-60">{banner.message_en}</div>
|
|
26
26
|
</div>
|
|
27
27
|
)}
|
|
28
28
|
<Scene snapshot={snapshot} />
|
|
29
|
-
<footer className="mx-auto max-w-[1280px] px-6 pb-8 text-xs text-gray-500 font-mono flex items-center justify-between">
|
|
30
|
-
<span>Sprint 1 / Phase C-1 — Foundation</span>
|
|
31
|
-
<span data-testid="snapshot-ts">{snapshot.ts}</span>
|
|
32
|
-
</footer>
|
|
33
29
|
</main>
|
|
34
30
|
);
|
|
35
31
|
}
|
|
@@ -52,14 +52,14 @@ export function Drawer({ open, tab, title, onClose, onTabChange, children, mode
|
|
|
52
52
|
aria-label="Detail panel"
|
|
53
53
|
data-testid="drawer"
|
|
54
54
|
data-open="true"
|
|
55
|
-
className="h-full min-h-0 rounded-
|
|
55
|
+
className="glass-panel h-full min-h-0 rounded-lg flex flex-col overflow-hidden"
|
|
56
56
|
>
|
|
57
|
-
<header className="flex items-center justify-between border-b border-
|
|
58
|
-
<h2 className="text-sm font-
|
|
57
|
+
<header className="flex items-center justify-between border-b border-white/10 px-4 py-3">
|
|
58
|
+
<h2 className="text-sm font-semibold tracking-tight text-gray-100 truncate">
|
|
59
59
|
{title}
|
|
60
60
|
</h2>
|
|
61
61
|
</header>
|
|
62
|
-
<nav className="flex flex-wrap border-b border-
|
|
62
|
+
<nav className="flex flex-wrap border-b border-white/10 px-2 py-2 text-[11px] font-mono">
|
|
63
63
|
{TABS.map((t) => (
|
|
64
64
|
<button
|
|
65
65
|
key={t.id}
|
|
@@ -67,10 +67,10 @@ export function Drawer({ open, tab, title, onClose, onTabChange, children, mode
|
|
|
67
67
|
data-testid={`drawer-tab-${t.id}`}
|
|
68
68
|
data-active={t.id === tab}
|
|
69
69
|
onClick={() => onTabChange(t.id)}
|
|
70
|
-
className={`min-w-[33%] flex-1 px-2 py-2 transition-colors ${
|
|
70
|
+
className={`min-w-[33%] flex-1 rounded-md px-2 py-2 transition-colors ${
|
|
71
71
|
t.id === tab
|
|
72
|
-
? "bg-
|
|
73
|
-
: "text-gray-500 hover:text-gray-200"
|
|
72
|
+
? "bg-white/12 text-gray-100 shadow-inner"
|
|
73
|
+
: "text-gray-500 hover:bg-white/6 hover:text-gray-200"
|
|
74
74
|
}`}
|
|
75
75
|
>
|
|
76
76
|
{t.label}
|
|
@@ -140,7 +140,7 @@ export function MissionTimeline({
|
|
|
140
140
|
}: Props) {
|
|
141
141
|
if (!missions.length) {
|
|
142
142
|
return (
|
|
143
|
-
<div className="
|
|
143
|
+
<div className="glass-panel rounded-lg px-3 py-4 text-center text-[11px] text-gray-500">
|
|
144
144
|
No missions found in .harness/documents/
|
|
145
145
|
</div>
|
|
146
146
|
);
|
|
@@ -178,10 +178,10 @@ export function MissionTimeline({
|
|
|
178
178
|
key={mission.missionId}
|
|
179
179
|
type="button"
|
|
180
180
|
onClick={() => onMissionClick(mission)}
|
|
181
|
-
className={`w-full rounded
|
|
181
|
+
className={`w-full rounded-lg px-3 py-2.5 text-left transition-colors ${
|
|
182
182
|
isActive
|
|
183
|
-
? "
|
|
184
|
-
: "border-
|
|
183
|
+
? "glass-panel"
|
|
184
|
+
: "border border-white/10 bg-white/[0.035] hover:border-white/20"
|
|
185
185
|
}`}
|
|
186
186
|
>
|
|
187
187
|
<div className="flex items-start justify-between gap-2 mb-1.5">
|
|
@@ -50,7 +50,7 @@ function OrgCard({
|
|
|
50
50
|
<button
|
|
51
51
|
type="button"
|
|
52
52
|
onClick={() => onClick(node)}
|
|
53
|
-
className={`relative rounded-
|
|
53
|
+
className={`brutal-tile relative rounded-md p-3 text-left transition-all cursor-pointer ${roleColor} ${widths[size]} ${active ? "ring-2 ring-cyan-300 border-cyan-300/80" : "hover:border-white/35"}`}
|
|
54
54
|
>
|
|
55
55
|
<StatusDot status={node.status} />
|
|
56
56
|
<div className="font-mono text-[9px] uppercase tracking-[0.2em] text-gray-500 mb-0.5">{node.role}</div>
|
|
@@ -263,7 +263,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
263
263
|
|
|
264
264
|
return (
|
|
265
265
|
<div className="select-none">
|
|
266
|
-
<div className="flex items-center justify-between border-b border-white/10 bg-
|
|
266
|
+
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-3 py-2 backdrop-blur">
|
|
267
267
|
<div className="min-w-0">
|
|
268
268
|
{currentMission && (
|
|
269
269
|
<div className="truncate font-mono text-[10px] text-cyan-300/70">
|
|
@@ -275,7 +275,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
275
275
|
<button
|
|
276
276
|
type="button"
|
|
277
277
|
onClick={() => setBoundedZoom(zoom - 0.08)}
|
|
278
|
-
className="h-7 w-7 rounded border border-
|
|
278
|
+
className="h-7 w-7 rounded-md border border-white/15 bg-black/35 font-mono text-xs text-gray-200 hover:border-cyan-300/60"
|
|
279
279
|
title="Zoom out"
|
|
280
280
|
>
|
|
281
281
|
-
|
|
@@ -283,7 +283,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
283
283
|
<button
|
|
284
284
|
type="button"
|
|
285
285
|
onClick={() => setBoundedZoom(defaultZoom)}
|
|
286
|
-
className="h-7 min-w-12 rounded border border-
|
|
286
|
+
className="h-7 min-w-12 rounded-md border border-white/15 bg-black/35 px-2 font-mono text-[10px] text-gray-300 hover:border-cyan-300/60"
|
|
287
287
|
title="Reset zoom"
|
|
288
288
|
>
|
|
289
289
|
{Math.round(zoom * 100)}%
|
|
@@ -291,7 +291,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
291
291
|
<button
|
|
292
292
|
type="button"
|
|
293
293
|
onClick={() => setBoundedZoom(zoom + 0.08)}
|
|
294
|
-
className="h-7 w-7 rounded border border-
|
|
294
|
+
className="h-7 w-7 rounded-md border border-white/15 bg-black/35 font-mono text-xs text-gray-200 hover:border-cyan-300/60"
|
|
295
295
|
title="Zoom in"
|
|
296
296
|
>
|
|
297
297
|
+
|
|
@@ -306,7 +306,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
306
306
|
onPointerMove={handlePointerMove}
|
|
307
307
|
onPointerUp={endDrag}
|
|
308
308
|
onPointerCancel={endDrag}
|
|
309
|
-
className="scrollbar-hidden h-[390px] cursor-grab overflow-auto active:cursor-grabbing"
|
|
309
|
+
className="scrollbar-hidden isometric-stage h-[390px] cursor-grab overflow-auto active:cursor-grabbing"
|
|
310
310
|
>
|
|
311
311
|
<div
|
|
312
312
|
className="relative"
|
|
@@ -417,7 +417,7 @@ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
|
|
|
417
417
|
agentIds: [],
|
|
418
418
|
})
|
|
419
419
|
}
|
|
420
|
-
className={`relative rounded
|
|
420
|
+
className={`brutal-tile relative rounded-md px-2 py-1.5 text-left min-w-[130px] max-w-[160px] transition-all hover:border-white/25 ${
|
|
421
421
|
workerActive
|
|
422
422
|
? "border-cyan-300/70 bg-cyan-400/10 shadow-[0_0_18px_rgba(34,211,238,0.18)]"
|
|
423
423
|
: "border-gray-700/40 bg-gray-800/30"
|