@walwal-harness/cli 7.1.40 → 7.1.41

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 (69) 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/wake/route.ts +41 -0
  11. package/apps/harness-dashboard/components/Scene.tsx +568 -35
  12. package/apps/harness-dashboard/lib/__tests__/harness-state.test.ts +1 -202
  13. package/apps/harness-dashboard/lib/__tests__/sandbox-e2e.test.ts +490 -0
  14. package/apps/harness-dashboard/lib/harness-state.ts +107 -796
  15. package/apps/harness-dashboard/lib/types.ts +22 -222
  16. package/apps/harness-dashboard/playwright.config.ts +26 -7
  17. package/assets/templates/AGENTS-ko.md.template +1 -1
  18. package/assets/templates/AGENTS.md.template +12 -2
  19. package/assets/templates/HARNESS.md +2 -0
  20. package/assets/templates/company-pipeline-manifest.json +5 -14
  21. package/assets/templates/worker-report.md.template +38 -0
  22. package/bin/init.js +2 -1
  23. package/commands/goal.md +4 -2
  24. package/commands/hot-fix.md +1 -1
  25. package/commands/submission.md +1 -1
  26. package/package.json +1 -1
  27. package/scripts/conductor-tick.sh +12 -0
  28. package/scripts/harness-agenda.sh +105 -0
  29. package/scripts/harness-company-block.sh +89 -0
  30. package/scripts/harness-company-complete.sh +17 -8
  31. package/scripts/harness-company-cycle.sh +54 -0
  32. package/scripts/harness-progress-set.sh +8 -2
  33. package/scripts/harness-stop.sh +76 -0
  34. package/scripts/harness-wake-control.sh +151 -0
  35. package/scripts/harness-wake.sh +5 -0
  36. package/apps/harness-dashboard/components/Drawer.tsx +0 -146
  37. package/apps/harness-dashboard/components/Header.tsx +0 -40
  38. package/apps/harness-dashboard/components/MissionTimeline.tsx +0 -214
  39. package/apps/harness-dashboard/components/OrgTree.tsx +0 -459
  40. package/apps/harness-dashboard/components/drawer/AgentLogTab.tsx +0 -56
  41. package/apps/harness-dashboard/components/drawer/DesignPreviewTab.tsx +0 -160
  42. package/apps/harness-dashboard/components/drawer/GotchasTab.tsx +0 -89
  43. package/apps/harness-dashboard/components/drawer/HypothesisTab.tsx +0 -42
  44. package/apps/harness-dashboard/components/drawer/IncidentsTab.tsx +0 -50
  45. package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +0 -96
  46. package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +0 -576
  47. package/apps/harness-dashboard/components/drawer/OwnerHistoryTab.tsx +0 -160
  48. package/apps/harness-dashboard/components/drawer/RoomMetricsTab.tsx +0 -90
  49. package/apps/harness-dashboard/components/drawer/TracksTab.tsx +0 -47
  50. package/apps/harness-dashboard/components/three/ArchiveBoxes.tsx +0 -95
  51. package/apps/harness-dashboard/components/three/DeptBoard.tsx +0 -175
  52. package/apps/harness-dashboard/components/three/Floor3D.tsx +0 -404
  53. package/apps/harness-dashboard/components/three/GoalCard3D.tsx +0 -123
  54. package/apps/harness-dashboard/components/three/HypothesisCards.tsx +0 -71
  55. package/apps/harness-dashboard/components/three/MeetingWhiteboard.tsx +0 -98
  56. package/apps/harness-dashboard/components/three/Minifig3D.tsx +0 -391
  57. package/apps/harness-dashboard/components/three/OpsSiren.tsx +0 -99
  58. package/apps/harness-dashboard/components/three/Stage3D.tsx +0 -104
  59. package/apps/harness-dashboard/components/three/TrackRibbons.tsx +0 -81
  60. package/apps/harness-dashboard/lib/__tests__/i18n.test.ts +0 -16
  61. package/apps/harness-dashboard/lib/__tests__/iso.test.ts +0 -42
  62. package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +0 -183
  63. package/apps/harness-dashboard/lib/agent-roster.ts +0 -42
  64. package/apps/harness-dashboard/lib/furniture.ts +0 -165
  65. package/apps/harness-dashboard/lib/i18n.ts +0 -26
  66. package/apps/harness-dashboard/lib/iso.ts +0 -150
  67. package/apps/harness-dashboard/lib/markdown.tsx +0 -306
  68. package/apps/harness-dashboard/lib/path-planning.ts +0 -72
  69. package/apps/harness-dashboard/lib/state-mapping.ts +0 -146
@@ -1,146 +0,0 @@
1
- "use client";
2
- import { useEffect, useRef } from "react";
3
-
4
- export type DrawerTab =
5
- | "mission-flow" // Mission document hierarchy (PRIMARY)
6
- | "history" // Owner prompt history
7
- | "gotchas" // Harness gotcha knowledge base
8
- | "design-preview" // CDO visual sample iframe
9
- | "mission-doc" // Single doc markdown view
10
- | "logs"; // Agent log (technical)
11
-
12
- interface DrawerProps {
13
- open: boolean;
14
- tab: DrawerTab;
15
- title: string;
16
- onClose: () => void;
17
- onTabChange: (tab: DrawerTab) => void;
18
- children: React.ReactNode;
19
- mode?: "overlay" | "inline";
20
- scrollResetKey?: string;
21
- }
22
-
23
- const TABS: Array<{ id: DrawerTab; label: string }> = [
24
- { id: "mission-flow", label: "Mission Flow" },
25
- { id: "history", label: "History" },
26
- { id: "gotchas", label: "Gotchas" },
27
- { id: "design-preview", label: "Preview" },
28
- { id: "mission-doc", label: "Document" },
29
- { id: "logs", label: "Agent Log" },
30
- ];
31
-
32
- export function Drawer({ open, tab, title, onClose, onTabChange, children, mode = "overlay", scrollResetKey }: DrawerProps) {
33
- const contentRef = useRef<HTMLDivElement | null>(null);
34
-
35
- useEffect(() => {
36
- if (!open || mode === "inline") return;
37
- const onKey = (e: KeyboardEvent) => {
38
- if (e.key === "Escape") onClose();
39
- };
40
- window.addEventListener("keydown", onKey);
41
- return () => window.removeEventListener("keydown", onKey);
42
- }, [open, onClose, mode]);
43
-
44
- useEffect(() => {
45
- contentRef.current?.scrollTo({ top: 0, left: 0 });
46
- }, [scrollResetKey]);
47
-
48
- if (mode === "inline") {
49
- return (
50
- <aside
51
- role="complementary"
52
- aria-label="Detail panel"
53
- data-testid="drawer"
54
- data-open="true"
55
- className="glass-panel h-full min-h-0 rounded-lg flex flex-col overflow-hidden"
56
- >
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
- {title}
60
- </h2>
61
- </header>
62
- <nav className="flex flex-wrap border-b border-white/10 px-2 py-2 text-[11px] font-mono">
63
- {TABS.map((t) => (
64
- <button
65
- key={t.id}
66
- type="button"
67
- data-testid={`drawer-tab-${t.id}`}
68
- data-active={t.id === tab}
69
- onClick={() => onTabChange(t.id)}
70
- className={`min-w-[33%] flex-1 rounded-md px-2 py-2 transition-colors ${
71
- t.id === tab
72
- ? "bg-white/12 text-gray-100 shadow-inner"
73
- : "text-gray-500 hover:bg-white/6 hover:text-gray-200"
74
- }`}
75
- >
76
- {t.label}
77
- </button>
78
- ))}
79
- </nav>
80
- <div ref={contentRef} className="scrollbar-hidden flex-1 overflow-y-auto px-4 py-3 text-xs text-gray-200 font-mono">
81
- {children}
82
- </div>
83
- </aside>
84
- );
85
- }
86
-
87
- return (
88
- <>
89
- {/* Click-outside backdrop. Pointer-events flip with `open`. */}
90
- <div
91
- data-testid="drawer-backdrop"
92
- aria-hidden="true"
93
- onClick={onClose}
94
- className={`fixed inset-0 bg-black/30 transition-opacity duration-200 ${
95
- open ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"
96
- }`}
97
- />
98
- <aside
99
- role="complementary"
100
- aria-label="Detail panel"
101
- aria-hidden={!open}
102
- data-testid="drawer"
103
- data-open={open}
104
- className={`fixed top-0 right-0 h-[100dvh] w-full sm:w-[50vw] sm:min-w-[600px] bg-brick-bg border-l border-brick-wall shadow-2xl flex flex-col transition-transform duration-300 ease-out ${
105
- open ? "translate-x-0" : "translate-x-full"
106
- }`}
107
- >
108
- <header className="flex items-center justify-between border-b border-brick-wall px-4 py-3">
109
- <h2 className="text-sm font-mono uppercase tracking-widest text-gray-200">
110
- {title}
111
- </h2>
112
- <button
113
- type="button"
114
- onClick={onClose}
115
- aria-label="Close panel"
116
- data-testid="drawer-close"
117
- className="rounded p-1 text-gray-400 hover:text-gray-100 hover:bg-brick-wall/40"
118
- >
119
- ✕
120
- </button>
121
- </header>
122
- <nav className="flex flex-wrap border-b border-brick-wall text-[11px] font-mono">
123
- {TABS.map((t) => (
124
- <button
125
- key={t.id}
126
- type="button"
127
- data-testid={`drawer-tab-${t.id}`}
128
- data-active={t.id === tab}
129
- onClick={() => onTabChange(t.id)}
130
- className={`min-w-[33%] flex-1 px-2 py-2 transition-colors ${
131
- t.id === tab
132
- ? "bg-brick-wall/50 text-gray-100 border-b-2 border-aura-typing"
133
- : "text-gray-500 hover:text-gray-200"
134
- }`}
135
- >
136
- {t.label}
137
- </button>
138
- ))}
139
- </nav>
140
- <div ref={contentRef} className="scrollbar-hidden flex-1 overflow-y-auto px-4 py-3 text-xs text-gray-200 font-mono">
141
- {children}
142
- </div>
143
- </aside>
144
- </>
145
- );
146
- }
@@ -1,40 +0,0 @@
1
- import path from "node:path";
2
- import { Wordmark } from "./Wordmark";
3
- import { resolveHarnessRoot } from "@/lib/harness-root";
4
-
5
- export function Header() {
6
- const root = resolveHarnessRoot();
7
- const projectName = path.basename(root);
8
- return (
9
- <header className="border-b border-brick-wall bg-brick-bg/80 backdrop-blur">
10
- <div className="mx-auto flex max-w-[1280px] items-center justify-between px-6 py-4">
11
- <div className="flex items-baseline gap-4">
12
- <Wordmark />
13
- <span className="hidden items-baseline gap-2 sm:inline-flex">
14
- <span
15
- className="rounded bg-brick-wall/40 px-2 py-0.5 font-mono text-xs font-semibold text-amber-300"
16
- title={root}
17
- >
18
- {projectName}
19
- </span>
20
- <span className="text-xs text-gray-400">walwal-harness 라이브 운영 대시보드</span>
21
- </span>
22
- </div>
23
- <nav className="flex items-center gap-3 text-xs font-mono text-gray-500">
24
- <span className="inline-flex items-center gap-1">
25
- <span className="size-2 rounded-full bg-aura-idle" /> idle
26
- </span>
27
- <span className="inline-flex items-center gap-1">
28
- <span className="size-2 rounded-full bg-aura-typing" /> typing
29
- </span>
30
- <span className="inline-flex items-center gap-1">
31
- <span className="size-2 rounded-full bg-aura-talking" /> talking
32
- </span>
33
- <span className="inline-flex items-center gap-1">
34
- <span className="size-2 rounded-full bg-aura-alert" /> alert
35
- </span>
36
- </nav>
37
- </div>
38
- </header>
39
- );
40
- }
@@ -1,214 +0,0 @@
1
- "use client";
2
- import type { MissionDoc } from "@/lib/types";
3
-
4
- interface Props {
5
- missions: MissionDoc[];
6
- activeMissionId: string | null;
7
- onMissionClick: (mission: MissionDoc) => void;
8
- }
9
-
10
- type ChipRole =
11
- | "owner"
12
- | "ceo"
13
- | "coo"
14
- | "cdo"
15
- | "cto"
16
- | "cqo"
17
- | "ops"
18
- | "worker";
19
-
20
- function chipColor(role: ChipRole): string {
21
- switch (role) {
22
- case "owner":
23
- return "bg-amber-500/15 text-amber-300 border-amber-500/30";
24
- case "ceo":
25
- return "bg-cyan-400/15 text-cyan-300 border-cyan-400/30";
26
- case "coo":
27
- return "bg-emerald-500/15 text-emerald-300 border-emerald-500/30";
28
- case "cdo":
29
- return "bg-purple-500/15 text-purple-300 border-purple-500/30";
30
- case "cto":
31
- return "bg-blue-400/15 text-blue-300 border-blue-400/30";
32
- case "cqo":
33
- return "bg-amber-400/15 text-amber-300 border-amber-400/30";
34
- case "ops":
35
- return "bg-rose-400/15 text-rose-300 border-rose-400/30";
36
- case "worker":
37
- return "bg-gray-500/15 text-gray-300 border-gray-500/30";
38
- default:
39
- return "bg-gray-500/15 text-gray-400 border-gray-600/30";
40
- }
41
- }
42
-
43
- function Chip({
44
- role,
45
- label,
46
- badge,
47
- }: {
48
- role: ChipRole;
49
- label: string;
50
- badge?: string;
51
- }) {
52
- return (
53
- <span
54
- className={`inline-flex items-center gap-1 rounded border px-1.5 py-0.5 font-mono text-[9px] ${chipColor(role)}`}
55
- >
56
- {label}
57
- {badge && <span className="opacity-80">{badge}</span>}
58
- </span>
59
- );
60
- }
61
-
62
- function Arrow() {
63
- return <span className="text-[10px] text-gray-600 shrink-0">→</span>;
64
- }
65
-
66
- function buildFlowChain(mission: MissionDoc): React.ReactNode {
67
- // Pre-worker CXX: planning phase (before implementation)
68
- const preWorker: Array<{ key: "coo" | "cdo" | "cto"; role: ChipRole }> = [
69
- { key: "coo", role: "coo" },
70
- { key: "cdo", role: "cdo" },
71
- { key: "cto", role: "cto" },
72
- ];
73
- // Post-worker CXX: verification phase (after implementation)
74
- const postWorker: Array<{ key: "cqo" | "ops"; role: ChipRole }> = [
75
- { key: "cqo", role: "cqo" },
76
- { key: "ops", role: "ops" },
77
- ];
78
-
79
- const isCqoAccepted =
80
- typeof mission.cqo === "string" && mission.cqo.includes("ACCEPTED");
81
-
82
- const chips: React.ReactNode[] = [];
83
- let key = 0;
84
-
85
- chips.push(<Chip key={key++} role="owner" label="Owner" />);
86
- chips.push(<Arrow key={key++} />);
87
- chips.push(<Chip key={key++} role="ceo" label="CEO" />);
88
-
89
- // Planning phase: COO, CDO, CTO
90
- for (const { key: roleKey, role } of preWorker) {
91
- if (mission.cxxPresent.includes(roleKey)) {
92
- chips.push(<Arrow key={key++} />);
93
- chips.push(<Chip key={key++} role={role} label={roleKey.toUpperCase()} />);
94
- }
95
- }
96
-
97
- // CTO-owned implementation workers. Legacy flat workers remain visible here
98
- // with owner=unknown so protocol bypasses are not hidden.
99
- for (const worker of mission.workers.filter((w) => w.owner === "cto" || w.owner === "unknown")) {
100
- chips.push(<Arrow key={key++} />);
101
- const badge = worker.status === "COMPLETE" ? "✅" : "⏳";
102
- const shortName =
103
- worker.name.length > 12 ? worker.name.slice(0, 12) + "…" : worker.name;
104
- chips.push(
105
- <Chip key={key++} role="worker" label={shortName} badge={badge} />
106
- );
107
- }
108
-
109
- // Verification phase: CQO, OPS
110
- for (const { key: roleKey, role } of postWorker) {
111
- if (mission.cxxPresent.includes(roleKey)) {
112
- chips.push(<Arrow key={key++} />);
113
- const badge = roleKey === "cqo" && isCqoAccepted ? "✅" : undefined;
114
- chips.push(
115
- <Chip key={key++} role={role} label={roleKey.toUpperCase()} badge={badge} />
116
- );
117
- if (roleKey === "cqo") {
118
- for (const worker of mission.workers.filter((w) => w.owner === "cqo")) {
119
- chips.push(<Arrow key={key++} />);
120
- const workerBadge = worker.status === "COMPLETE" ? "✅" : "⏳";
121
- const shortName =
122
- worker.name.length > 12 ? worker.name.slice(0, 12) + "…" : worker.name;
123
- chips.push(
124
- <Chip key={key++} role="worker" label={shortName} badge={workerBadge} />
125
- );
126
- }
127
- }
128
- }
129
- }
130
-
131
- return (
132
- <div className="flex flex-wrap items-center gap-1 min-w-0">{chips}</div>
133
- );
134
- }
135
-
136
- export function MissionTimeline({
137
- missions,
138
- activeMissionId,
139
- onMissionClick,
140
- }: Props) {
141
- if (!missions.length) {
142
- return (
143
- <div className="glass-panel rounded-lg px-3 py-4 text-center text-[11px] text-gray-500">
144
- No missions found in .harness/documents/
145
- </div>
146
- );
147
- }
148
-
149
- return (
150
- <div className="space-y-1.5">
151
- {missions.map((mission) => {
152
- const isActive = mission.missionId === activeMissionId;
153
- const typeBadge =
154
- mission.type === "hotfix"
155
- ? "[🔥 hot-fix]"
156
- : mission.type === "submission"
157
- ? "[+ submission]"
158
- : mission.type === "goal" || mission.type === "feature"
159
- ? "[✦ goal]"
160
- : "[— unknown]";
161
- const shortId =
162
- mission.missionId.length > 28
163
- ? mission.missionId.slice(0, 28) + "…"
164
- : mission.missionId;
165
-
166
- let dateStr = "—";
167
- try {
168
- dateStr = new Date(mission.ts).toLocaleDateString(undefined, {
169
- month: "short",
170
- day: "numeric",
171
- });
172
- } catch {
173
- // ignore invalid date
174
- }
175
-
176
- return (
177
- <button
178
- key={mission.missionId}
179
- type="button"
180
- onClick={() => onMissionClick(mission)}
181
- className={`w-full rounded-lg px-3 py-2.5 text-left transition-colors ${
182
- isActive
183
- ? "glass-panel"
184
- : "border border-white/10 bg-white/[0.035] hover:border-white/20"
185
- }`}
186
- >
187
- <div className="flex items-start justify-between gap-2 mb-1.5">
188
- <div className="flex items-center gap-2 min-w-0">
189
- <span
190
- className={`shrink-0 font-mono text-[9px] rounded px-1.5 py-0.5 border ${
191
- mission.type === "hotfix"
192
- ? "bg-rose-500/15 text-rose-300 border-rose-500/30"
193
- : mission.type === "submission"
194
- ? "bg-sky-500/15 text-sky-300 border-sky-500/30"
195
- : "bg-emerald-500/15 text-emerald-300 border-emerald-500/30"
196
- }`}
197
- >
198
- {typeBadge}
199
- </span>
200
- <span className="font-mono text-[10px] text-gray-200 truncate">
201
- {shortId}
202
- </span>
203
- </div>
204
- <span className="shrink-0 font-mono text-[9px] text-gray-500">
205
- {dateStr}
206
- </span>
207
- </div>
208
- {buildFlowChain(mission)}
209
- </button>
210
- );
211
- })}
212
- </div>
213
- );
214
- }