@walwal-harness/cli 7.1.7 → 7.1.9

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 (89) hide show
  1. package/HR-Resource/index.json +19 -43
  2. package/HR-Resource/marketing-marketing-cross-border-ecommerce/SKILL.md +108 -223
  3. package/HR-Resource/marketing-marketing-global-marketplace-operator/SKILL.md +175 -0
  4. package/HR-Resource/marketing-marketing-google-seo-specialist/SKILL.md +91 -0
  5. package/HR-Resource/marketing-marketing-instagram-commerce-strategist/SKILL.md +81 -0
  6. package/HR-Resource/marketing-marketing-korea-global-market-localization-strategist/SKILL.md +186 -0
  7. package/HR-Resource/marketing-marketing-livestream-commerce-coach/SKILL.md +88 -272
  8. package/HR-Resource/marketing-marketing-naver-seo-specialist/SKILL.md +88 -0
  9. package/HR-Resource/marketing-marketing-short-video-editing-coach/SKILL.md +99 -395
  10. package/HR-Resource/marketing-marketing-youtube-shopping-strategist/SKILL.md +82 -0
  11. package/README.md +41 -0
  12. package/apps/harness-dashboard/app/api/env/route.ts +62 -0
  13. package/apps/harness-dashboard/app/api/log/route.ts +19 -0
  14. package/apps/harness-dashboard/app/api/missions/route.ts +15 -0
  15. package/apps/harness-dashboard/app/api/snapshot/route.ts +15 -0
  16. package/apps/harness-dashboard/app/api/stream/route.ts +71 -0
  17. package/apps/harness-dashboard/app/globals.css +17 -0
  18. package/apps/harness-dashboard/app/layout.tsx +29 -0
  19. package/apps/harness-dashboard/app/page.tsx +35 -0
  20. package/apps/harness-dashboard/components/Drawer.tsx +97 -0
  21. package/apps/harness-dashboard/components/Header.tsx +40 -0
  22. package/apps/harness-dashboard/components/MissionTimeline.tsx +210 -0
  23. package/apps/harness-dashboard/components/OrgTree.tsx +330 -0
  24. package/apps/harness-dashboard/components/Scene.tsx +563 -0
  25. package/apps/harness-dashboard/components/Wordmark.tsx +14 -0
  26. package/apps/harness-dashboard/components/drawer/AgentLogTab.tsx +56 -0
  27. package/apps/harness-dashboard/components/drawer/GotchasTab.tsx +89 -0
  28. package/apps/harness-dashboard/components/drawer/HypothesisTab.tsx +42 -0
  29. package/apps/harness-dashboard/components/drawer/IncidentsTab.tsx +50 -0
  30. package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +92 -0
  31. package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +517 -0
  32. package/apps/harness-dashboard/components/drawer/OwnerHistoryTab.tsx +156 -0
  33. package/apps/harness-dashboard/components/drawer/RoomMetricsTab.tsx +90 -0
  34. package/apps/harness-dashboard/components/drawer/TracksTab.tsx +47 -0
  35. package/apps/harness-dashboard/components/three/ArchiveBoxes.tsx +95 -0
  36. package/apps/harness-dashboard/components/three/DeptBoard.tsx +175 -0
  37. package/apps/harness-dashboard/components/three/Floor3D.tsx +404 -0
  38. package/apps/harness-dashboard/components/three/GoalCard3D.tsx +123 -0
  39. package/apps/harness-dashboard/components/three/HypothesisCards.tsx +71 -0
  40. package/apps/harness-dashboard/components/three/MeetingWhiteboard.tsx +98 -0
  41. package/apps/harness-dashboard/components/three/Minifig3D.tsx +391 -0
  42. package/apps/harness-dashboard/components/three/OpsSiren.tsx +99 -0
  43. package/apps/harness-dashboard/components/three/Stage3D.tsx +104 -0
  44. package/apps/harness-dashboard/components/three/TrackRibbons.tsx +81 -0
  45. package/apps/harness-dashboard/hooks/useHarnessStream.ts +53 -0
  46. package/apps/harness-dashboard/lib/__tests__/company-flow.test.ts +270 -0
  47. package/apps/harness-dashboard/lib/__tests__/harness-state.test.ts +194 -0
  48. package/apps/harness-dashboard/lib/__tests__/i18n.test.ts +16 -0
  49. package/apps/harness-dashboard/lib/__tests__/iso.test.ts +42 -0
  50. package/apps/harness-dashboard/lib/__tests__/safe-json.test.ts +46 -0
  51. package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +159 -0
  52. package/apps/harness-dashboard/lib/__tests__/watcher.test.ts +48 -0
  53. package/apps/harness-dashboard/lib/agent-roster.ts +42 -0
  54. package/apps/harness-dashboard/lib/furniture.ts +165 -0
  55. package/apps/harness-dashboard/lib/harness-root.ts +20 -0
  56. package/apps/harness-dashboard/lib/harness-state.ts +1162 -0
  57. package/apps/harness-dashboard/lib/i18n.ts +26 -0
  58. package/apps/harness-dashboard/lib/iso.ts +150 -0
  59. package/apps/harness-dashboard/lib/log-filter.ts +23 -0
  60. package/apps/harness-dashboard/lib/markdown.tsx +306 -0
  61. package/apps/harness-dashboard/lib/path-planning.ts +72 -0
  62. package/apps/harness-dashboard/lib/safe-json.ts +24 -0
  63. package/apps/harness-dashboard/lib/state-mapping.ts +126 -0
  64. package/apps/harness-dashboard/lib/types.ts +329 -0
  65. package/apps/harness-dashboard/lib/watcher.ts +64 -0
  66. package/apps/harness-dashboard/next-env.d.ts +6 -0
  67. package/apps/harness-dashboard/next.config.mjs +9 -0
  68. package/apps/harness-dashboard/package-lock.json +4280 -0
  69. package/apps/harness-dashboard/package.json +38 -0
  70. package/apps/harness-dashboard/playwright.config.ts +23 -0
  71. package/apps/harness-dashboard/postcss.config.js +6 -0
  72. package/apps/harness-dashboard/tailwind.config.ts +49 -0
  73. package/apps/harness-dashboard/tsconfig.json +24 -0
  74. package/apps/harness-dashboard/vitest.config.ts +15 -0
  75. package/assets/templates/AGENTS-ko /341/204/207/341/205/251/341/206/250/341/204/211/341/205/241/341/204/207/341/205/251/341/206/253.md" +114 -0
  76. package/package.json +11 -1
  77. package/scripts/harness-dashboard-up.sh +24 -4
  78. package/HR-Resource/engineering-engineering-feishu-integration-developer/SKILL.md +0 -615
  79. package/HR-Resource/engineering-engineering-wechat-mini-program-developer/SKILL.md +0 -367
  80. package/HR-Resource/marketing-marketing-baidu-seo-specialist/SKILL.md +0 -243
  81. package/HR-Resource/marketing-marketing-bilibili-content-strategist/SKILL.md +0 -216
  82. package/HR-Resource/marketing-marketing-china-ecommerce-operator/SKILL.md +0 -300
  83. package/HR-Resource/marketing-marketing-china-market-localization-strategist/SKILL.md +0 -300
  84. package/HR-Resource/marketing-marketing-douyin-strategist/SKILL.md +0 -166
  85. package/HR-Resource/marketing-marketing-kuaishou-strategist/SKILL.md +0 -240
  86. package/HR-Resource/marketing-marketing-wechat-official-account/SKILL.md +0 -162
  87. package/HR-Resource/marketing-marketing-weibo-strategist/SKILL.md +0 -257
  88. package/HR-Resource/marketing-marketing-xiaohongshu-specialist/SKILL.md +0 -155
  89. package/HR-Resource/marketing-marketing-zhihu-strategist/SKILL.md +0 -179
@@ -0,0 +1,330 @@
1
+ "use client";
2
+ import type { AgentId, HarnessSnapshot, MinifigState, OrgNodeDef } from "@/lib/types";
3
+
4
+ interface OrgTreeProps {
5
+ snapshot: HarnessSnapshot;
6
+ activeNodeId: string | null;
7
+ onNodeClick: (node: OrgNodeDef) => void;
8
+ }
9
+
10
+ function StatusDot({ status }: { status: MinifigState }) {
11
+ const cls = {
12
+ "red-alert": "bg-rose-500 animate-ping",
13
+ typing: "bg-cyan-400 animate-pulse",
14
+ talking: "bg-emerald-400",
15
+ queued: "bg-amber-400",
16
+ idle: "bg-gray-600",
17
+ }[status] ?? "bg-gray-600";
18
+ return <span className={`absolute top-2 right-2 h-2 w-2 rounded-full ${cls}`} />;
19
+ }
20
+
21
+ function OrgCard({
22
+ node,
23
+ size = "md",
24
+ active,
25
+ onClick,
26
+ }: {
27
+ node: OrgNodeDef;
28
+ size?: "lg" | "md" | "sm";
29
+ active: boolean;
30
+ onClick: (n: OrgNodeDef) => void;
31
+ }) {
32
+ const roleColor = {
33
+ owner: "border-amber-500/50 bg-amber-500/5",
34
+ ceo: "border-cyan-400/50 bg-cyan-400/5",
35
+ coo: "border-emerald-400/40 bg-emerald-500/5",
36
+ cdo: "border-purple-400/40 bg-purple-500/5",
37
+ cto: "border-blue-400/40 bg-blue-500/5",
38
+ cqo: "border-amber-400/40 bg-amber-500/5",
39
+ ops: "border-rose-400/40 bg-rose-500/5",
40
+ }[node.role] ?? "border-gray-600/40 bg-gray-800/30";
41
+
42
+ const widths = {
43
+ lg: "min-w-[220px] max-w-[260px]",
44
+ md: "min-w-[150px] max-w-[190px]",
45
+ sm: "min-w-[130px] max-w-[160px]",
46
+ };
47
+
48
+ return (
49
+ <button
50
+ type="button"
51
+ onClick={() => onClick(node)}
52
+ className={`relative rounded-lg border p-3 text-left transition-all cursor-pointer ${roleColor} ${widths[size]} ${active ? "ring-2 ring-cyan-300 border-cyan-300/60" : "hover:border-white/30"}`}
53
+ >
54
+ <StatusDot status={node.status} />
55
+ <div className="font-mono text-[9px] uppercase tracking-[0.2em] text-gray-500 mb-0.5">{node.role}</div>
56
+ <div className="text-sm font-semibold text-gray-100 leading-tight">{node.label}</div>
57
+ {node.sublabel && (
58
+ <div className="text-[10px] text-gray-500 mt-0.5">{node.sublabel}</div>
59
+ )}
60
+ {node.activity && (
61
+ <div className="mt-2 text-[10px] text-gray-400 line-clamp-2 leading-relaxed">
62
+ {node.activity}
63
+ </div>
64
+ )}
65
+ </button>
66
+ );
67
+ }
68
+
69
+ function BranchConnector({ count }: { count: number }) {
70
+ const h = 44;
71
+ const stepPct = 100 / count;
72
+ const midY = h * 0.5;
73
+ const centers = Array.from({ length: count }, (_, i) => stepPct * i + stepPct / 2);
74
+ return (
75
+ <svg width="100%" height={h} className="overflow-visible pointer-events-none">
76
+ <line x1="50%" y1="0" x2="50%" y2={midY} stroke="#374151" strokeWidth="1.5" />
77
+ <line
78
+ x1={`${centers[0]}%`}
79
+ y1={midY}
80
+ x2={`${centers[centers.length - 1]}%`}
81
+ y2={midY}
82
+ stroke="#374151"
83
+ strokeWidth="1.5"
84
+ />
85
+ {centers.map((x, i) => (
86
+ <line
87
+ key={i}
88
+ x1={`${x}%`}
89
+ y1={midY}
90
+ x2={`${x}%`}
91
+ y2={h}
92
+ stroke="#374151"
93
+ strokeWidth="1.5"
94
+ />
95
+ ))}
96
+ </svg>
97
+ );
98
+ }
99
+
100
+ export function OrgTree({ snapshot, activeNodeId, onNodeClick }: OrgTreeProps) {
101
+ const agentMap = new Map(snapshot.agents.map((a) => [a.id, a]));
102
+
103
+ const getStatus = (ids: AgentId[]): MinifigState => {
104
+ const states = ids.map((id) => agentMap.get(id)?.minifigState ?? "idle");
105
+ if (states.includes("red-alert")) return "red-alert";
106
+ if (states.includes("typing")) return "typing";
107
+ if (states.includes("talking")) return "talking";
108
+ if (states.includes("queued")) return "queued";
109
+ return "idle";
110
+ };
111
+
112
+ const currentMission = snapshot.missions?.[0] ?? null;
113
+
114
+ // Parse CEO activity from mission doc
115
+ const ceoActivity = (() => {
116
+ if (!currentMission?.ceo) return null;
117
+ const match = currentMission.ceo.match(/##\s*Owner 요청 요약\s*\n([\s\S]*?)(?=\n##)/);
118
+ return (
119
+ match?.[1]
120
+ ?.split("\n")
121
+ .find((l) => l.trim().length > 0)
122
+ ?.replace(/^[-*\d.]\s*/, "")
123
+ .trim()
124
+ .slice(0, 100) ?? null
125
+ );
126
+ })();
127
+
128
+ const ownerNode: OrgNodeDef = {
129
+ id: "owner",
130
+ role: "owner",
131
+ label: "Owner",
132
+ sublabel: "/goal · /hot-fix",
133
+ status: "idle",
134
+ activity: snapshot.ownerHistory?.[0]?.content.slice(0, 80) ?? null,
135
+ agentIds: [],
136
+ };
137
+
138
+ const ceoNode: OrgNodeDef = {
139
+ id: "ceo",
140
+ role: "ceo",
141
+ label: "harness-ceo",
142
+ sublabel: "Dispatcher · Brainstormer",
143
+ status: getStatus(["dispatcher", "brainstormer"] as AgentId[]),
144
+ activity: ceoActivity,
145
+ agentIds: ["dispatcher", "brainstormer"] as AgentId[],
146
+ };
147
+
148
+ const cxxNodes: OrgNodeDef[] = [
149
+ {
150
+ id: "coo",
151
+ role: "coo",
152
+ label: "harness-coo",
153
+ sublabel: "Planner · Research",
154
+ status: getStatus(["planner", "coo-developer", "documentationer"] as AgentId[]),
155
+ activity: null,
156
+ agentIds: ["planner", "coo-developer", "documentationer"] as AgentId[],
157
+ },
158
+ {
159
+ id: "cdo",
160
+ role: "cdo",
161
+ label: "harness-cdo",
162
+ sublabel: "Design · Branding",
163
+ status: "idle",
164
+ activity: null,
165
+ agentIds: [],
166
+ },
167
+ {
168
+ id: "cto",
169
+ role: "cto",
170
+ label: "harness-cto",
171
+ sublabel: "Conductor · Generators",
172
+ status: getStatus([
173
+ "cto",
174
+ "conductor",
175
+ "generator-backend",
176
+ "generator-frontend",
177
+ "generator-designer",
178
+ "generator-devops",
179
+ ] as AgentId[]),
180
+ activity: currentMission?.cto ? "Architecture plan active" : null,
181
+ agentIds: [
182
+ "cto",
183
+ "conductor",
184
+ "generator-backend",
185
+ "generator-frontend",
186
+ "generator-designer",
187
+ "generator-devops",
188
+ ] as AgentId[],
189
+ },
190
+ {
191
+ id: "cqo",
192
+ role: "cqo",
193
+ label: "harness-cqo",
194
+ sublabel: "Evaluators",
195
+ status: getStatus([
196
+ "cqo",
197
+ "evaluator-functional",
198
+ "evaluator-visual",
199
+ "evaluator-code-quality",
200
+ "evaluator-architecture",
201
+ "evaluator-security",
202
+ ] as AgentId[]),
203
+ activity: currentMission?.cqo?.includes("ACCEPTED")
204
+ ? "ACCEPTED"
205
+ : currentMission?.cqo
206
+ ? "Report available"
207
+ : null,
208
+ agentIds: [
209
+ "cqo",
210
+ "evaluator-functional",
211
+ "evaluator-visual",
212
+ "evaluator-code-quality",
213
+ "evaluator-architecture",
214
+ "evaluator-security",
215
+ ] as AgentId[],
216
+ },
217
+ {
218
+ id: "ops",
219
+ role: "ops",
220
+ label: "harness-ops",
221
+ sublabel: "Service Monitor",
222
+ status: getStatus(["service-ops"] as AgentId[]),
223
+ activity: null,
224
+ agentIds: ["service-ops"] as AgentId[],
225
+ },
226
+ ];
227
+
228
+ // Workers from current mission's workers/, shown under CTO column
229
+ const workers = currentMission?.workers ?? [];
230
+
231
+ return (
232
+ <div className="w-full px-4 py-6 select-none">
233
+ {/* Mission label */}
234
+ {currentMission && (
235
+ <div className="mb-4 text-center">
236
+ <span className="font-mono text-[10px] uppercase tracking-[0.2em] text-cyan-300/60">
237
+ current mission
238
+ </span>
239
+ <div className="mt-0.5 font-mono text-xs text-gray-400">{currentMission.missionId}</div>
240
+ </div>
241
+ )}
242
+
243
+ {/* Row 1: Owner */}
244
+ <div className="flex justify-center">
245
+ <OrgCard
246
+ node={ownerNode}
247
+ size="lg"
248
+ active={activeNodeId === "owner"}
249
+ onClick={onNodeClick}
250
+ />
251
+ </div>
252
+
253
+ {/* Connector: Owner → CEO */}
254
+ <div className="flex justify-center">
255
+ <div className="w-px h-6 bg-gray-700" />
256
+ </div>
257
+
258
+ {/* Row 2: CEO */}
259
+ <div className="flex justify-center">
260
+ <OrgCard
261
+ node={ceoNode}
262
+ size="lg"
263
+ active={activeNodeId === "ceo"}
264
+ onClick={onNodeClick}
265
+ />
266
+ </div>
267
+
268
+ {/* Branch connector: CEO → CXX */}
269
+ <BranchConnector count={cxxNodes.length} />
270
+
271
+ {/* Row 3: CXX nodes with workers below */}
272
+ <div className="flex gap-3 justify-center">
273
+ {cxxNodes.map((node) => {
274
+ const nodeWorkers = node.role === "cto" ? workers : [];
275
+
276
+ return (
277
+ <div key={node.id} className="flex flex-col items-center gap-2">
278
+ <OrgCard
279
+ node={node}
280
+ size="md"
281
+ active={activeNodeId === node.id}
282
+ onClick={onNodeClick}
283
+ />
284
+ {/* Worker mini-cards under CTO */}
285
+ {nodeWorkers.length > 0 && (
286
+ <>
287
+ <div className="w-px h-3 bg-gray-700/60" />
288
+ <div className="flex flex-col gap-1.5 w-full">
289
+ {nodeWorkers.map((w) => (
290
+ <button
291
+ key={w.name}
292
+ type="button"
293
+ onClick={() =>
294
+ onNodeClick({
295
+ id: `worker-${w.name}`,
296
+ role: "cto",
297
+ label: w.name,
298
+ sublabel: w.status,
299
+ status: w.status === "COMPLETE" ? "idle" : "typing",
300
+ activity: null,
301
+ agentIds: [],
302
+ })
303
+ }
304
+ className={`rounded border border-gray-700/40 bg-gray-800/30 px-2 py-1.5 text-left min-w-[130px] max-w-[160px] transition-all hover:border-white/20 ${
305
+ activeNodeId === `worker-${w.name}` ? "ring-1 ring-cyan-300" : ""
306
+ }`}
307
+ >
308
+ <div className="font-mono text-[9px] text-gray-500">worker</div>
309
+ <div className="text-[11px] font-medium text-gray-200 truncate">
310
+ {w.name}
311
+ </div>
312
+ <div
313
+ className={`text-[9px] font-mono mt-0.5 ${
314
+ w.status === "COMPLETE" ? "text-emerald-400" : "text-amber-400"
315
+ }`}
316
+ >
317
+ {w.status}
318
+ </div>
319
+ </button>
320
+ ))}
321
+ </div>
322
+ </>
323
+ )}
324
+ </div>
325
+ );
326
+ })}
327
+ </div>
328
+ </div>
329
+ );
330
+ }