@walwal-harness/cli 7.1.39 → 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 (74) 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 +20 -2
  7. package/HR-Resource/ops-prompt-inspector/SKILL.md +105 -0
  8. package/HR-Resource/ops-prompt-inspector/agents/installation-agent.json +7 -0
  9. package/HR-Resource/ops-prompt-inspector/assets/PromptInspector.tsx +599 -0
  10. package/HR-Resource/ops-prompt-inspector/assets/prompt-inspector-static.js +180 -0
  11. package/HR-Resource/ops-prompt-inspector/references/handler-templates.md +255 -0
  12. package/HR-Resource/ops-prompt-inspector/scripts/discover_apis.py +509 -0
  13. package/HR-Resource/ops-prompt-inspector/scripts/install.sh +32 -0
  14. package/HR-Resource/ops-prompt-inspector/scripts/setup.py +381 -0
  15. package/apps/harness-dashboard/app/api/wake/route.ts +41 -0
  16. package/apps/harness-dashboard/components/Scene.tsx +568 -35
  17. package/apps/harness-dashboard/lib/__tests__/harness-state.test.ts +1 -202
  18. package/apps/harness-dashboard/lib/__tests__/sandbox-e2e.test.ts +490 -0
  19. package/apps/harness-dashboard/lib/harness-state.ts +107 -796
  20. package/apps/harness-dashboard/lib/types.ts +22 -222
  21. package/apps/harness-dashboard/playwright.config.ts +26 -7
  22. package/assets/templates/AGENTS-ko.md.template +1 -1
  23. package/assets/templates/AGENTS.md.template +12 -2
  24. package/assets/templates/HARNESS.md +2 -0
  25. package/assets/templates/company-pipeline-manifest.json +5 -14
  26. package/assets/templates/worker-report.md.template +38 -0
  27. package/bin/init.js +4 -3
  28. package/commands/goal.md +4 -2
  29. package/commands/hot-fix.md +1 -1
  30. package/commands/submission.md +1 -1
  31. package/package.json +1 -1
  32. package/scripts/conductor-tick.sh +12 -0
  33. package/scripts/harness-agenda.sh +105 -0
  34. package/scripts/harness-company-block.sh +89 -0
  35. package/scripts/harness-company-complete.sh +17 -8
  36. package/scripts/harness-company-cycle.sh +54 -0
  37. package/scripts/harness-progress-set.sh +8 -2
  38. package/scripts/harness-stop.sh +76 -0
  39. package/scripts/harness-wake-control.sh +151 -0
  40. package/scripts/harness-wake.sh +5 -0
  41. package/apps/harness-dashboard/components/Drawer.tsx +0 -146
  42. package/apps/harness-dashboard/components/Header.tsx +0 -40
  43. package/apps/harness-dashboard/components/MissionTimeline.tsx +0 -214
  44. package/apps/harness-dashboard/components/OrgTree.tsx +0 -459
  45. package/apps/harness-dashboard/components/drawer/AgentLogTab.tsx +0 -56
  46. package/apps/harness-dashboard/components/drawer/DesignPreviewTab.tsx +0 -160
  47. package/apps/harness-dashboard/components/drawer/GotchasTab.tsx +0 -89
  48. package/apps/harness-dashboard/components/drawer/HypothesisTab.tsx +0 -42
  49. package/apps/harness-dashboard/components/drawer/IncidentsTab.tsx +0 -50
  50. package/apps/harness-dashboard/components/drawer/MissionDocTab.tsx +0 -96
  51. package/apps/harness-dashboard/components/drawer/MissionFlowTab.tsx +0 -576
  52. package/apps/harness-dashboard/components/drawer/OwnerHistoryTab.tsx +0 -160
  53. package/apps/harness-dashboard/components/drawer/RoomMetricsTab.tsx +0 -90
  54. package/apps/harness-dashboard/components/drawer/TracksTab.tsx +0 -47
  55. package/apps/harness-dashboard/components/three/ArchiveBoxes.tsx +0 -95
  56. package/apps/harness-dashboard/components/three/DeptBoard.tsx +0 -175
  57. package/apps/harness-dashboard/components/three/Floor3D.tsx +0 -404
  58. package/apps/harness-dashboard/components/three/GoalCard3D.tsx +0 -123
  59. package/apps/harness-dashboard/components/three/HypothesisCards.tsx +0 -71
  60. package/apps/harness-dashboard/components/three/MeetingWhiteboard.tsx +0 -98
  61. package/apps/harness-dashboard/components/three/Minifig3D.tsx +0 -391
  62. package/apps/harness-dashboard/components/three/OpsSiren.tsx +0 -99
  63. package/apps/harness-dashboard/components/three/Stage3D.tsx +0 -104
  64. package/apps/harness-dashboard/components/three/TrackRibbons.tsx +0 -81
  65. package/apps/harness-dashboard/lib/__tests__/i18n.test.ts +0 -16
  66. package/apps/harness-dashboard/lib/__tests__/iso.test.ts +0 -42
  67. package/apps/harness-dashboard/lib/__tests__/state-mapping.test.ts +0 -183
  68. package/apps/harness-dashboard/lib/agent-roster.ts +0 -42
  69. package/apps/harness-dashboard/lib/furniture.ts +0 -165
  70. package/apps/harness-dashboard/lib/i18n.ts +0 -26
  71. package/apps/harness-dashboard/lib/iso.ts +0 -150
  72. package/apps/harness-dashboard/lib/markdown.tsx +0 -306
  73. package/apps/harness-dashboard/lib/path-planning.ts +0 -72
  74. 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
- }