@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
@@ -0,0 +1,180 @@
1
+ (function () {
2
+ const VERSION = '1.2.0-static';
3
+ const ID = 'harness-ops-prompt-inspector';
4
+ if (window.__HARNESS_OPS_PROMPT_INSPECTOR__) return;
5
+ window.__HARNESS_OPS_PROMPT_INSPECTOR__ = { version: VERSION };
6
+
7
+ const state = {
8
+ selecting: false,
9
+ target: null,
10
+ bindings: [],
11
+ };
12
+
13
+ const css = `
14
+ #${ID}-bar{position:fixed;right:18px;bottom:18px;z-index:2147483647;display:flex;gap:8px;align-items:center;background:#111827;color:#fff;border:1px solid #374151;border-radius:8px;padding:10px;box-shadow:0 16px 36px rgba(0,0,0,.32);font:13px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
15
+ #${ID}-bar button,#${ID}-panel button{border:0;border-radius:6px;padding:8px 10px;background:#2563eb;color:#fff;cursor:pointer;font:inherit}
16
+ #${ID}-bar button.secondary,#${ID}-panel button.secondary{background:#374151}
17
+ #${ID}-bar button.danger{background:#dc2626}
18
+ #${ID}-panel{position:fixed;right:18px;bottom:76px;width:min(420px,calc(100vw - 36px));z-index:2147483647;background:#fff;color:#111827;border:1px solid #d1d5db;border-radius:8px;box-shadow:0 18px 48px rgba(0,0,0,.28);padding:14px;font:13px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
19
+ #${ID}-panel h3{margin:0 0 10px;font-size:15px}
20
+ #${ID}-panel label{display:block;margin:10px 0 4px;color:#374151;font-weight:600}
21
+ #${ID}-panel input,#${ID}-panel textarea,#${ID}-panel select{width:100%;box-sizing:border-box;border:1px solid #d1d5db;border-radius:6px;padding:8px;font:inherit}
22
+ #${ID}-panel textarea{min-height:72px;resize:vertical}
23
+ #${ID}-panel .row{display:flex;gap:8px;margin-top:12px}
24
+ #${ID}-highlight{position:fixed;z-index:2147483646;pointer-events:none;border:2px solid #f59e0b;background:rgba(245,158,11,.12);border-radius:4px}
25
+ .${ID}-badge{position:absolute;z-index:2147483645;background:#f59e0b;color:#111827;border-radius:999px;padding:2px 7px;font:11px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;box-shadow:0 2px 8px rgba(0,0,0,.24)}
26
+ `;
27
+
28
+ const style = document.createElement('style');
29
+ style.textContent = css;
30
+ document.head.appendChild(style);
31
+
32
+ const bar = document.createElement('div');
33
+ bar.id = `${ID}-bar`;
34
+ bar.innerHTML = `
35
+ <strong>Prompt Inspector</strong>
36
+ <button type="button" data-action="select">Select</button>
37
+ <button type="button" class="secondary" data-action="export">Export</button>
38
+ <button type="button" class="danger" data-action="clear">Clear</button>
39
+ `;
40
+ document.body.appendChild(bar);
41
+
42
+ const highlight = document.createElement('div');
43
+ highlight.id = `${ID}-highlight`;
44
+ highlight.hidden = true;
45
+ document.body.appendChild(highlight);
46
+
47
+ function selectorFor(el) {
48
+ if (!el || el === document.body) return 'body';
49
+ if (el.id) return `#${CSS.escape(el.id)}`;
50
+ const parts = [];
51
+ let node = el;
52
+ while (node && node.nodeType === 1 && node !== document.body && parts.length < 4) {
53
+ let part = node.tagName.toLowerCase();
54
+ if (node.classList && node.classList.length) {
55
+ part += `.${Array.from(node.classList).slice(0, 2).map((c) => CSS.escape(c)).join('.')}`;
56
+ }
57
+ const parent = node.parentElement;
58
+ if (parent) {
59
+ const same = Array.from(parent.children).filter((child) => child.tagName === node.tagName);
60
+ if (same.length > 1) part += `:nth-of-type(${same.indexOf(node) + 1})`;
61
+ }
62
+ parts.unshift(part);
63
+ node = parent;
64
+ }
65
+ return parts.join(' > ');
66
+ }
67
+
68
+ function positionHighlight(el) {
69
+ if (!el) {
70
+ highlight.hidden = true;
71
+ return;
72
+ }
73
+ const rect = el.getBoundingClientRect();
74
+ highlight.hidden = false;
75
+ highlight.style.left = `${rect.left}px`;
76
+ highlight.style.top = `${rect.top}px`;
77
+ highlight.style.width = `${rect.width}px`;
78
+ highlight.style.height = `${rect.height}px`;
79
+ }
80
+
81
+ function panelFor(el) {
82
+ const selector = selectorFor(el);
83
+ const panel = document.createElement('div');
84
+ panel.id = `${ID}-panel`;
85
+ panel.innerHTML = `
86
+ <h3>Bind selected element</h3>
87
+ <label>Selector</label>
88
+ <input value="${selector.replace(/"/g, '&quot;')}" data-field="selector">
89
+ <label>Mode</label>
90
+ <select data-field="mode">
91
+ <option value="comment">Comment Only</option>
92
+ <option value="api">Connect API</option>
93
+ </select>
94
+ <label>API / Note</label>
95
+ <input placeholder="GET /api/example or short title" data-field="api">
96
+ <label>Comment</label>
97
+ <textarea placeholder="Describe intended behavior, visual issue, or API binding." data-field="comment"></textarea>
98
+ <div class="row">
99
+ <button type="button" data-action="save">Save</button>
100
+ <button type="button" class="secondary" data-action="cancel">Cancel</button>
101
+ </div>
102
+ `;
103
+ document.body.appendChild(panel);
104
+ panel.querySelector('[data-action="save"]').addEventListener('click', () => {
105
+ const binding = {
106
+ route: `${location.pathname}${location.hash || ''}`,
107
+ selector: panel.querySelector('[data-field="selector"]').value,
108
+ mode: panel.querySelector('[data-field="mode"]').value,
109
+ api: panel.querySelector('[data-field="api"]').value.trim(),
110
+ comment: panel.querySelector('[data-field="comment"]').value.trim(),
111
+ };
112
+ state.bindings.push(binding);
113
+ addBadge(el, state.bindings.length);
114
+ panel.remove();
115
+ state.target = null;
116
+ positionHighlight(null);
117
+ });
118
+ panel.querySelector('[data-action="cancel"]').addEventListener('click', () => {
119
+ panel.remove();
120
+ state.target = null;
121
+ positionHighlight(null);
122
+ });
123
+ }
124
+
125
+ function addBadge(el, index) {
126
+ const rect = el.getBoundingClientRect();
127
+ const badge = document.createElement('div');
128
+ badge.className = `${ID}-badge`;
129
+ badge.textContent = `PI-${index}`;
130
+ badge.style.left = `${Math.max(6, rect.left + window.scrollX)}px`;
131
+ badge.style.top = `${Math.max(6, rect.top + window.scrollY - 20)}px`;
132
+ document.body.appendChild(badge);
133
+ }
134
+
135
+ function exportMarkdown() {
136
+ const lines = [`# Prompt Inspector`, ``, `Route: ${location.pathname}${location.hash || ''}`, ``];
137
+ state.bindings.forEach((binding, i) => {
138
+ lines.push(`## ${i + 1}. ${binding.mode === 'api' ? 'API Binding' : 'Comment'}`);
139
+ lines.push(`- Selector: \`${binding.selector}\``);
140
+ if (binding.api) lines.push(`- API: ${binding.api}`);
141
+ if (binding.comment) lines.push(`- Comment: ${binding.comment}`);
142
+ lines.push('');
143
+ });
144
+ const markdown = lines.join('\n');
145
+ navigator.clipboard?.writeText(markdown).catch(() => {});
146
+ console.log(markdown);
147
+ alert(`Prompt Inspector export copied/logged. Bindings: ${state.bindings.length}`);
148
+ }
149
+
150
+ document.addEventListener('mouseover', (event) => {
151
+ if (!state.selecting || bar.contains(event.target)) return;
152
+ positionHighlight(event.target);
153
+ }, true);
154
+
155
+ document.addEventListener('click', (event) => {
156
+ if (!state.selecting || bar.contains(event.target)) return;
157
+ event.preventDefault();
158
+ event.stopPropagation();
159
+ state.selecting = false;
160
+ state.target = event.target;
161
+ bar.querySelector('[data-action="select"]').textContent = 'Select';
162
+ document.getElementById(`${ID}-panel`)?.remove();
163
+ panelFor(event.target);
164
+ }, true);
165
+
166
+ bar.addEventListener('click', (event) => {
167
+ const action = event.target && event.target.getAttribute('data-action');
168
+ if (action === 'select') {
169
+ state.selecting = !state.selecting;
170
+ event.target.textContent = state.selecting ? 'Selecting...' : 'Select';
171
+ if (!state.selecting) positionHighlight(null);
172
+ }
173
+ if (action === 'export') exportMarkdown();
174
+ if (action === 'clear') {
175
+ state.bindings = [];
176
+ document.querySelectorAll(`.${ID}-badge`).forEach((el) => el.remove());
177
+ positionHighlight(null);
178
+ }
179
+ });
180
+ })();
@@ -0,0 +1,255 @@
1
+ # API Handler Templates
2
+
3
+ ## Success/Failure Handler Types
4
+
5
+ ### 1. Toast Messages
6
+
7
+ ```tsx
8
+ // Using react-hot-toast
9
+ import toast from 'react-hot-toast';
10
+
11
+ // Success
12
+ toast.success('${message}');
13
+
14
+ // Error
15
+ toast.error('${message}');
16
+ ```
17
+
18
+ ```tsx
19
+ // Using sonner
20
+ import { toast } from 'sonner';
21
+
22
+ // Success
23
+ toast.success('${message}');
24
+
25
+ // Error
26
+ toast.error('${message}');
27
+ ```
28
+
29
+ ```tsx
30
+ // Using react-toastify
31
+ import { toast } from 'react-toastify';
32
+
33
+ // Success
34
+ toast.success('${message}');
35
+
36
+ // Error
37
+ toast.error('${message}');
38
+ ```
39
+
40
+ ### 2. Alert/Popup Dialogs
41
+
42
+ ```tsx
43
+ // Native browser alert
44
+ alert('${message}');
45
+
46
+ // Using shadcn/ui AlertDialog
47
+ import {
48
+ AlertDialog,
49
+ AlertDialogAction,
50
+ AlertDialogContent,
51
+ AlertDialogDescription,
52
+ AlertDialogFooter,
53
+ AlertDialogHeader,
54
+ AlertDialogTitle,
55
+ } from "@/components/ui/alert-dialog";
56
+
57
+ <AlertDialog open={isOpen} onOpenChange={setIsOpen}>
58
+ <AlertDialogContent>
59
+ <AlertDialogHeader>
60
+ <AlertDialogTitle>${title}</AlertDialogTitle>
61
+ <AlertDialogDescription>${message}</AlertDialogDescription>
62
+ </AlertDialogHeader>
63
+ <AlertDialogFooter>
64
+ <AlertDialogAction onClick={() => setIsOpen(false)}>
65
+ 확인
66
+ </AlertDialogAction>
67
+ </AlertDialogFooter>
68
+ </AlertDialogContent>
69
+ </AlertDialog>
70
+ ```
71
+
72
+ ### 3. Page Navigation
73
+
74
+ ```tsx
75
+ // Using Next.js App Router
76
+ import { useRouter } from 'next/navigation';
77
+
78
+ const router = useRouter();
79
+
80
+ // Success redirect
81
+ router.push('${successPath}');
82
+
83
+ // With replace (no back button)
84
+ router.replace('${successPath}');
85
+ ```
86
+
87
+ ```tsx
88
+ // Using Next.js Pages Router
89
+ import { useRouter } from 'next/router';
90
+
91
+ const router = useRouter();
92
+ router.push('${successPath}');
93
+ ```
94
+
95
+ ### 4. State Update
96
+
97
+ ```tsx
98
+ // Update local state
99
+ setData(response.data);
100
+ setLoading(false);
101
+ setError(null);
102
+
103
+ // With React Query
104
+ queryClient.invalidateQueries({ queryKey: ['${queryKey}'] });
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Combined Handler Patterns
110
+
111
+ ### Pattern A: Toast + State Update
112
+
113
+ ```tsx
114
+ const handleSuccess = (data: ResponseType) => {
115
+ toast.success('${successMessage}');
116
+ setData(data);
117
+ setLoading(false);
118
+ };
119
+
120
+ const handleError = (error: Error) => {
121
+ toast.error('${errorMessage}');
122
+ setError(error.message);
123
+ setLoading(false);
124
+ };
125
+ ```
126
+
127
+ ### Pattern B: Toast + Navigation
128
+
129
+ ```tsx
130
+ const handleSuccess = () => {
131
+ toast.success('${successMessage}');
132
+ router.push('${successPath}');
133
+ };
134
+
135
+ const handleError = (error: Error) => {
136
+ toast.error(error.message || '${errorMessage}');
137
+ };
138
+ ```
139
+
140
+ ### Pattern C: Popup Dialog + Navigation
141
+
142
+ ```tsx
143
+ const handleSuccess = () => {
144
+ setDialogConfig({
145
+ open: true,
146
+ title: '${successTitle}',
147
+ message: '${successMessage}',
148
+ onConfirm: () => router.push('${successPath}'),
149
+ });
150
+ };
151
+
152
+ const handleError = (error: Error) => {
153
+ setDialogConfig({
154
+ open: true,
155
+ title: '${errorTitle}',
156
+ message: error.message || '${errorMessage}',
157
+ onConfirm: () => setDialogConfig({ open: false }),
158
+ });
159
+ };
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Trigger Patterns
165
+
166
+ ### onLoad (페이지 로딩 시)
167
+
168
+ ```tsx
169
+ // Using useEffect
170
+ useEffect(() => {
171
+ fetchData();
172
+ }, []);
173
+
174
+ // Using React Query
175
+ const { data, isLoading, error } = useQuery({
176
+ queryKey: ['${queryKey}'],
177
+ queryFn: () => fetch('${apiPath}').then(res => res.json()),
178
+ });
179
+
180
+ // Using SWR
181
+ const { data, error, isLoading } = useSWR('${apiPath}', fetcher);
182
+ ```
183
+
184
+ ### onClick (클릭 시)
185
+
186
+ ```tsx
187
+ <button onClick={async () => {
188
+ try {
189
+ setLoading(true);
190
+ const response = await axios.${method}('${apiPath}', ${hasBody ? 'payload' : ''});
191
+ handleSuccess(response.data);
192
+ } catch (error) {
193
+ handleError(error);
194
+ }
195
+ }}>
196
+ ${buttonText}
197
+ </button>
198
+ ```
199
+
200
+ ### onSubmit (폼 제출 시)
201
+
202
+ ```tsx
203
+ const handleSubmit = async (e: React.FormEvent) => {
204
+ e.preventDefault();
205
+ try {
206
+ setLoading(true);
207
+ const response = await axios.${method}('${apiPath}', formData);
208
+ handleSuccess(response.data);
209
+ } catch (error) {
210
+ handleError(error);
211
+ }
212
+ };
213
+
214
+ <form onSubmit={handleSubmit}>
215
+ {/* form fields */}
216
+ <button type="submit" disabled={loading}>
217
+ {loading ? '처리 중...' : '${submitText}'}
218
+ </button>
219
+ </form>
220
+ ```
221
+
222
+ ### onBlur (포커스 해제 시)
223
+
224
+ ```tsx
225
+ <input
226
+ onBlur={async (e) => {
227
+ const value = e.target.value;
228
+ if (value !== previousValue) {
229
+ try {
230
+ await axios.${method}('${apiPath}', { value });
231
+ handleSuccess();
232
+ } catch (error) {
233
+ handleError(error);
234
+ }
235
+ }
236
+ }}
237
+ />
238
+ ```
239
+
240
+ ### onChange with Debounce (입력 변경 시)
241
+
242
+ ```tsx
243
+ import { useDebouncedCallback } from 'use-debounce';
244
+
245
+ const debouncedSave = useDebouncedCallback(async (value: string) => {
246
+ try {
247
+ await axios.${method}('${apiPath}', { value });
248
+ handleSuccess();
249
+ } catch (error) {
250
+ handleError(error);
251
+ }
252
+ }, 500);
253
+
254
+ <input onChange={(e) => debouncedSave(e.target.value)} />
255
+ ```