@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,89 @@
1
+ "use client";
2
+ import { useState } from "react";
3
+ import type { GotchaEntry } from "@/lib/types";
4
+ import { MarkdownView } from "@/lib/markdown";
5
+
6
+ interface Props {
7
+ gotchas: GotchaEntry[];
8
+ }
9
+
10
+ export function GotchasTab({ gotchas }: Props) {
11
+ const [selected, setSelected] = useState<GotchaEntry | null>(null);
12
+ const [search, setSearch] = useState("");
13
+
14
+ if (selected) {
15
+ return (
16
+ <div className="space-y-3">
17
+ <button
18
+ type="button"
19
+ onClick={() => setSelected(null)}
20
+ className="flex items-center gap-1.5 font-mono text-[10px] text-cyan-400/70 hover:text-cyan-300 transition-colors"
21
+ >
22
+ ← Back
23
+ </button>
24
+ <div className="font-mono text-[10px] text-gray-500">
25
+ .harness/gotchas/{selected.id}.md
26
+ </div>
27
+ <MarkdownView source={selected.content} />
28
+ </div>
29
+ );
30
+ }
31
+
32
+ const filtered = search.trim()
33
+ ? gotchas.filter(
34
+ (g) =>
35
+ g.title.toLowerCase().includes(search.toLowerCase()) ||
36
+ g.id.toLowerCase().includes(search.toLowerCase()) ||
37
+ g.tags.some((t) => t.toLowerCase().includes(search.toLowerCase()))
38
+ )
39
+ : gotchas;
40
+
41
+ if (gotchas.length === 0) {
42
+ return <div className="text-gray-500 text-xs">No gotchas found in .harness/gotchas/</div>;
43
+ }
44
+
45
+ return (
46
+ <div className="space-y-2">
47
+ {/* Search */}
48
+ <input
49
+ type="text"
50
+ value={search}
51
+ onChange={(e) => setSearch(e.target.value)}
52
+ placeholder="Search gotchas…"
53
+ className="w-full rounded border border-gray-700/60 bg-black/30 px-2.5 py-1.5 font-mono text-[11px] text-gray-300 placeholder-gray-600 focus:border-cyan-400/40 focus:outline-none"
54
+ />
55
+
56
+ <div className="font-mono text-[9px] text-gray-600 px-0.5">
57
+ {filtered.length} / {gotchas.length} gotchas
58
+ </div>
59
+
60
+ <div className="space-y-1.5">
61
+ {filtered.map((g) => (
62
+ <button
63
+ key={g.id}
64
+ type="button"
65
+ onClick={() => setSelected(g)}
66
+ className="w-full text-left rounded border border-gray-700/50 bg-black/20 px-3 py-2 hover:border-amber-400/30 hover:bg-amber-400/5 transition-colors group"
67
+ >
68
+ <div className="font-mono text-[11px] text-gray-200 group-hover:text-amber-200 leading-snug">
69
+ {g.title}
70
+ </div>
71
+ <div className="font-mono text-[9px] text-gray-600 mt-0.5">{g.id}</div>
72
+ {g.tags.length > 0 && (
73
+ <div className="flex flex-wrap gap-1 mt-1">
74
+ {g.tags.slice(0, 5).map((tag) => (
75
+ <span
76
+ key={tag}
77
+ className="rounded bg-gray-700/40 px-1.5 py-0.5 font-mono text-[8px] text-gray-500"
78
+ >
79
+ {tag}
80
+ </span>
81
+ ))}
82
+ </div>
83
+ )}
84
+ </button>
85
+ ))}
86
+ </div>
87
+ </div>
88
+ );
89
+ }
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import type { HypothesisEntry } from "@/lib/types";
3
+
4
+ const VERDICT_TONE: Record<string, string> = {
5
+ pending: "border-aura-talking/40 bg-aura-talking/10 text-aura-talking",
6
+ valid: "border-aura-typing/40 bg-aura-typing/10 text-aura-typing",
7
+ invalid: "border-aura-alert/40 bg-aura-alert/10 text-aura-alert",
8
+ };
9
+
10
+ interface HypothesisTabProps {
11
+ hypothesis: HypothesisEntry[];
12
+ }
13
+
14
+ export function HypothesisTab({ hypothesis }: HypothesisTabProps) {
15
+ if (hypothesis.length === 0) {
16
+ return (
17
+ <div className="text-gray-500" data-testid="hypothesis-empty">
18
+ No active hypothesis.
19
+ </div>
20
+ );
21
+ }
22
+ return (
23
+ <ul className="space-y-2" data-testid="hypothesis-list">
24
+ {hypothesis.map((h) => (
25
+ <li
26
+ key={h.id}
27
+ data-testid={`hypothesis-row-${h.id}`}
28
+ className={`rounded border px-2 py-1.5 ${
29
+ VERDICT_TONE[h.verdict] ?? VERDICT_TONE.pending
30
+ }`}
31
+ >
32
+ <div className="flex items-center justify-between text-[11px]">
33
+ <span className="font-semibold">{h.id}</span>
34
+ <span className="uppercase tracking-wider text-[9px]">{h.verdict}</span>
35
+ </div>
36
+ <div className="mt-1 text-[11px] text-gray-100">{h.brief}</div>
37
+ {h.ts && <div className="mt-0.5 text-[9px] text-gray-500">{h.ts}</div>}
38
+ </li>
39
+ ))}
40
+ </ul>
41
+ );
42
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import type { IncidentEntry } from "@/lib/types";
3
+
4
+ const SEVERITY_TONE: Record<string, string> = {
5
+ low: "border-aura-idle/40 bg-aura-idle/10 text-gray-300",
6
+ medium: "border-aura-talking/40 bg-aura-talking/10 text-aura-talking",
7
+ high: "border-aura-alert/40 bg-aura-alert/10 text-aura-alert",
8
+ critical: "border-aura-alert bg-aura-alert/30 text-aura-alert",
9
+ };
10
+
11
+ interface IncidentsTabProps {
12
+ incidents: IncidentEntry[];
13
+ }
14
+
15
+ export function IncidentsTab({ incidents }: IncidentsTabProps) {
16
+ if (incidents.length === 0) {
17
+ return (
18
+ <div className="text-gray-500" data-testid="incidents-empty">
19
+ No open incidents.
20
+ </div>
21
+ );
22
+ }
23
+ return (
24
+ <ul className="space-y-2" data-testid="incidents-list">
25
+ {incidents.map((it) => (
26
+ <li
27
+ key={it.id}
28
+ data-testid={`incident-${it.id}`}
29
+ className={`rounded border px-2 py-1.5 ${
30
+ SEVERITY_TONE[it.severity] ?? SEVERITY_TONE.medium
31
+ }`}
32
+ >
33
+ <div className="flex items-center justify-between text-[11px]">
34
+ <span className="font-semibold">{it.id}</span>
35
+ <span className="uppercase tracking-wider text-[9px]">
36
+ {it.severity}
37
+ </span>
38
+ </div>
39
+ <div className="text-[10px] opacity-80">dept: {it.dept}</div>
40
+ {it.message && (
41
+ <div className="mt-1 text-[11px] text-gray-100">{it.message}</div>
42
+ )}
43
+ {it.ts && (
44
+ <div className="mt-0.5 text-[9px] text-gray-500">{it.ts}</div>
45
+ )}
46
+ </li>
47
+ ))}
48
+ </ul>
49
+ );
50
+ }
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { useState } from "react";
3
+ import type { MissionDoc } from "@/lib/types";
4
+ import { MarkdownView } from "@/lib/markdown";
5
+
6
+ interface Props {
7
+ missions: MissionDoc[];
8
+ role: "ceo" | "cto" | "cqo" | "coo" | "cdo" | "ops" | "worker";
9
+ workerName?: string;
10
+ fromLabel: string;
11
+ toLabel: string;
12
+ }
13
+
14
+ export function MissionDocTab({ missions, role, workerName, fromLabel, toLabel }: Props) {
15
+ const [selectedIdx, setSelectedIdx] = useState(0);
16
+ const mission = missions[selectedIdx];
17
+
18
+ if (!missions.length) {
19
+ return (
20
+ <div className="text-gray-500">
21
+ No mission documents found in .harness/documents/
22
+ </div>
23
+ );
24
+ }
25
+
26
+ const getContent = (m: MissionDoc): string | null => {
27
+ if (role === "worker" && workerName) {
28
+ return m.workers.find((w) => w.name === workerName)?.content ?? null;
29
+ }
30
+ const cxxRole = role as Exclude<typeof role, "worker">;
31
+ return m[cxxRole] ?? null;
32
+ };
33
+
34
+ const content = getContent(mission);
35
+
36
+ return (
37
+ <div className="space-y-3">
38
+ {/* Routing breadcrumb */}
39
+ <div className="flex items-center gap-2 flex-wrap">
40
+ <span className="font-mono text-[9px] uppercase tracking-[0.2em] text-gray-500">flow</span>
41
+ <span className="rounded bg-amber-500/10 border border-amber-500/30 px-2 py-0.5 text-[10px] text-amber-300 font-mono">
42
+ {fromLabel}
43
+ </span>
44
+ <span className="text-gray-600">→</span>
45
+ <span className="rounded border border-cyan-400/30 bg-cyan-400/10 px-2 py-0.5 text-[10px] text-cyan-300 font-mono">
46
+ this
47
+ </span>
48
+ <span className="text-gray-600">→</span>
49
+ <span className="rounded border border-gray-600/40 bg-gray-800/30 px-2 py-0.5 text-[10px] text-gray-400 font-mono">
50
+ {toLabel}
51
+ </span>
52
+ </div>
53
+
54
+ {/* Mission selector */}
55
+ <div className="flex gap-1 flex-wrap">
56
+ {missions.slice(0, 6).map((m, i) => (
57
+ <button
58
+ key={m.missionId}
59
+ type="button"
60
+ onClick={() => setSelectedIdx(i)}
61
+ className={`rounded px-2 py-1 font-mono text-[9px] transition-colors ${
62
+ i === selectedIdx
63
+ ? "bg-cyan-400/15 text-cyan-300 border border-cyan-400/30"
64
+ : "text-gray-500 hover:text-gray-300 border border-transparent"
65
+ }`}
66
+ >
67
+ {i === 0 ? "current" : m.missionId.slice(0, 16)}
68
+ </button>
69
+ ))}
70
+ </div>
71
+
72
+ {/* Mission ID */}
73
+ <div className="font-mono text-[10px] text-gray-500">
74
+ {mission.missionId} · {new Date(mission.ts).toLocaleDateString()}
75
+ </div>
76
+
77
+ {/* Document content */}
78
+ {!content ? (
79
+ <div className="text-gray-500 text-[11px]">
80
+ No {role} document for this mission.
81
+ <div className="mt-1 text-[10px] text-gray-600">
82
+ Present: {mission.cxxPresent.join(", ") || "none"}
83
+ </div>
84
+ </div>
85
+ ) : (
86
+ <div className="rounded border border-gray-700/60 bg-black/20 p-3 max-h-[60vh] overflow-y-auto">
87
+ <MarkdownView source={content} />
88
+ </div>
89
+ )}
90
+ </div>
91
+ );
92
+ }