create-harness-vibe-coding 0.8.18 → 0.8.19
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.
- package/CHANGELOG.md +13 -0
- package/README.md +1 -0
- package/package.json +5 -2
- package/src/index.js +383 -267
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js +17 -0
- package/src/ui/dist/assets/AgentsRoute-CuSKYmFu.js.map +1 -0
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js +7 -0
- package/src/ui/dist/assets/RolesRoute-DOzTYVRm.js.map +1 -0
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js +12 -0
- package/src/ui/dist/assets/SettingsRoute-DPU7jSQm.js.map +1 -0
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js +50 -0
- package/src/ui/dist/assets/TaskList-BN4r8s1i.js.map +1 -0
- package/src/ui/dist/assets/TerminalDrawer-6GBZ9nXN.css +32 -0
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js +74 -0
- package/src/ui/dist/assets/TerminalDrawer-Cej4PxsH.js.map +1 -0
- package/src/ui/dist/assets/WorkflowRoute-BnuhLJ6X.css +1 -0
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js +39 -0
- package/src/ui/dist/assets/WorkflowRoute-C-clKe-j.js.map +1 -0
- package/src/ui/dist/assets/index-BOVYWntB.js +117 -0
- package/src/ui/dist/assets/index-BOVYWntB.js.map +1 -0
- package/src/ui/dist/assets/index-DaUObq0H.css +1 -0
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js +7 -0
- package/src/ui/dist/assets/maximize-2-LNrr_rKr.js.map +1 -0
- package/src/ui/dist/assets/plus-QuTJyoT3.js +7 -0
- package/src/ui/dist/assets/plus-QuTJyoT3.js.map +1 -0
- package/src/ui/dist/assets/proxy-D0vUbds5.js +2 -0
- package/src/ui/dist/assets/proxy-D0vUbds5.js.map +1 -0
- package/src/ui/dist/assets/refresh-cw-JNmExijd.js +7 -0
- package/src/ui/dist/assets/refresh-cw-JNmExijd.js.map +1 -0
- package/src/ui/dist/assets/terminal-BBQvnOAK.js +7 -0
- package/src/ui/dist/assets/terminal-BBQvnOAK.js.map +1 -0
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js +7 -0
- package/src/ui/dist/assets/useReducedMotion-BqmH0Tf7.js.map +1 -0
- package/src/ui/dist/assets/x-DoIOGAJz.js +7 -0
- package/src/ui/dist/assets/x-DoIOGAJz.js.map +1 -0
- package/src/ui/dist/index.html +18 -0
- package/src/ui/index.html +17 -0
- package/src/ui/package.json +33 -0
- package/src/ui/pnpm-lock.yaml +1582 -0
- package/src/ui/pnpm-workspace.yaml +2 -0
- package/src/ui/src/App.tsx +86 -0
- package/src/ui/src/api.ts +93 -0
- package/src/ui/src/components/AgentsRoute.tsx +503 -0
- package/src/ui/src/components/Footer.tsx +69 -0
- package/src/ui/src/components/Header.tsx +175 -0
- package/src/ui/src/components/LoadingView.tsx +22 -0
- package/src/ui/src/components/RolesRoute.tsx +169 -0
- package/src/ui/src/components/SettingsRoute.tsx +166 -0
- package/src/ui/src/components/TaskList.tsx +388 -0
- package/src/ui/src/components/TerminalDrawer.tsx +611 -0
- package/src/ui/src/components/WorkflowRoute.tsx +670 -0
- package/src/ui/src/hooks/useReducedMotion.ts +17 -0
- package/src/ui/src/hooks/useServerConnection.ts +114 -0
- package/src/ui/src/index.css +281 -0
- package/src/ui/src/main.tsx +11 -0
- package/src/ui/src/types.ts +108 -0
- package/src/ui/tsconfig.json +21 -0
- package/src/ui/vite.config.ts +19 -0
- package/src/wf-ui-server/__tests__/a2a-store.test.mjs +79 -0
- package/src/wf-ui-server/__tests__/peer-capsule.test.mjs +268 -0
- package/src/wf-ui-server/__tests__/pty-adapter.test.mjs +70 -0
- package/src/wf-ui-server/__tests__/runtime-config.test.mjs +43 -0
- package/src/wf-ui-server/__tests__/runtime-detector.test.mjs +90 -0
- package/src/wf-ui-server/__tests__/security.test.mjs +59 -0
- package/src/wf-ui-server/__tests__/server.integration.test.mjs +150 -0
- package/src/wf-ui-server/__tests__/session-registry.test.mjs +238 -0
- package/src/wf-ui-server/__tests__/settings.test.mjs +135 -0
- package/src/wf-ui-server/__tests__/task-parser.test.mjs +200 -0
- package/src/wf-ui-server/__tests__/terminal-store.test.mjs +138 -0
- package/src/wf-ui-server/__tests__/token.test.mjs +48 -0
- package/src/wf-ui-server/__tests__/ws-events.integration.test.mjs +419 -0
- package/src/wf-ui-server/__tests__/ws-terminal.integration.test.mjs +383 -0
- package/src/wf-ui-server/a2a-store.mjs +296 -0
- package/src/wf-ui-server/peer-capsule.mjs +213 -0
- package/src/wf-ui-server/pty-adapter.mjs +155 -0
- package/src/wf-ui-server/runtime-config.mjs +153 -0
- package/src/wf-ui-server/runtime-detector.mjs +374 -0
- package/src/wf-ui-server/security.mjs +67 -0
- package/src/wf-ui-server/server.mjs +849 -0
- package/src/wf-ui-server/session-registry.mjs +204 -0
- package/src/wf-ui-server/settings.mjs +100 -0
- package/src/wf-ui-server/task-parser.mjs +133 -0
- package/src/wf-ui-server/terminal-store.mjs +225 -0
- package/src/wf-ui-server/token.mjs +41 -0
- package/src/wf-ui-server/ws-events.mjs +354 -0
- package/src/wf-ui-server/ws-terminal.mjs +473 -0
- package/templates/common/.claude/commands/wf-help.md +1 -0
- package/templates/common/.claude/commands/wf-task-list.md +2 -0
- package/templates/common/.claude/commands/wf-ui.md +26 -0
- package/templates/common/.claude/commands/wf-update.md +54 -9
- package/templates/common/.claude/rules/ecc/common.md +1 -1
- package/templates/common/.claude/skills/wf-auto/SKILL.md +3 -3
- package/templates/common/.claude/skills/wf-auto-spark/SKILL.md +2 -2
- package/templates/common/.claude/skills/wf-ui/SKILL.md +78 -0
- package/templates/common/.claude/skills/wf-update/SKILL.md +55 -58
- package/templates/common/.harness-version +63 -39
- package/templates/common/.opencode/commands/wf-help.md +1 -0
- package/templates/common/.opencode/commands/wf-task-list.md +2 -0
- package/templates/common/.opencode/commands/wf-ui.md +26 -0
- package/templates/common/.opencode/commands/wf-update.md +54 -9
- package/templates/common/CLAUDE.md +1 -1
- package/templates/common/Harness/MEMORY.md +2 -0
- package/templates/common/Harness/README.md +6 -4
- package/templates/common/Harness/a2a/role-graph.json +79 -0
- package/templates/common/Harness/a2a/runtime-registry.json +5 -0
- package/templates/common/Harness/a2a/skills/terminal-control.json +15 -0
- package/templates/common/Harness/ownership.manifest.json +57 -2
- package/templates/common/Harness/scripts/README.md +134 -0
- package/templates/common/Harness/scripts/a2a-terminal.mjs +191 -0
- package/templates/common/Harness/scripts/context-budget.mjs +1 -1
- package/templates/common/Harness/scripts/sync-host-global.mjs +278 -0
- package/templates/common/Harness/scripts/task-state.mjs +556 -23
- package/templates/common/Harness/scripts/validate-harness.mjs +229 -19
- package/templates/common/Harness/scripts/wf-remove.mjs +8 -3
- package/templates/common/Harness/scripts/wf-update-check.mjs +37 -9
- package/templates/common/Harness/scripts/wf-update-runner.mjs +325 -0
- package/templates/common/Harness/settings.json +35 -0
- package/templates/common/Harness/specs/protocols/TASK_ARCHIVE.md +7 -2
- package/templates/common/Harness/specs/runtime/command-surface.json +14 -0
- package/templates/common/Harness/specs/workflows/WF-AUTO-SPARK.md +8 -8
- package/templates/common/Harness/specs/workflows/WF-AUTO.md +12 -12
- package/templates/common/Harness/tasks/_template/NAMING.md +16 -16
- package/templates/common/Harness/tasks/_template/PLAN.md +17 -60
- package/templates/common/Harness/tasks/_template/PROBLEM.md +18 -0
- package/templates/common/Harness/tasks/_template/PROGRESS.md +9 -14
- package/templates/common/Harness/tasks/_template/REFERENCES.md +26 -0
- package/templates/common/Harness/tasks/_template/ARTIFACTS.md +0 -3
- package/templates/common/Harness/tasks/_template/NOTES.md +0 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { lazy, Suspense, useState, useEffect } from 'react';
|
|
2
|
+
import { Routes, Route, useLocation } from 'react-router-dom';
|
|
3
|
+
import Header from './components/Header';
|
|
4
|
+
import Footer from './components/Footer';
|
|
5
|
+
import LoadingView from './components/LoadingView';
|
|
6
|
+
import { useServerConnection } from './hooks/useServerConnection';
|
|
7
|
+
import { apiFetch } from './api';
|
|
8
|
+
|
|
9
|
+
const TaskList = lazy(() => import('./components/TaskList'));
|
|
10
|
+
const WorkflowRoute = lazy(() => import('./components/WorkflowRoute'));
|
|
11
|
+
const AgentsRoute = lazy(() => import('./components/AgentsRoute'));
|
|
12
|
+
const RolesRoute = lazy(() => import('./components/RolesRoute'));
|
|
13
|
+
const SettingsRoute = lazy(() => import('./components/SettingsRoute'));
|
|
14
|
+
const TerminalDrawer = lazy(() => import('./components/TerminalDrawer'));
|
|
15
|
+
|
|
16
|
+
function useDebugReporter(connState: string, errors: string[]) {
|
|
17
|
+
const location = useLocation();
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
apiFetch('/api/debug/report', {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
connected: connState === 'connected',
|
|
23
|
+
route: location.pathname,
|
|
24
|
+
url: window.location.href,
|
|
25
|
+
errors,
|
|
26
|
+
lastUpdate: new Date().toISOString(),
|
|
27
|
+
}),
|
|
28
|
+
}).catch(() => {});
|
|
29
|
+
}, [location.pathname, connState, errors]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadingLabel(pathname: string) {
|
|
33
|
+
if (pathname === '/workflow') return 'Loading workflow canvas';
|
|
34
|
+
if (pathname === '/agents') return 'Loading agent terminals';
|
|
35
|
+
if (pathname === '/roles') return 'Loading roles';
|
|
36
|
+
if (pathname === '/settings') return 'Loading settings';
|
|
37
|
+
return 'Loading tasks';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default function App() {
|
|
41
|
+
const location = useLocation();
|
|
42
|
+
const { connState, eventSeq, lastSync, lastError } = useServerConnection();
|
|
43
|
+
const [activeTerminalSession, setActiveTerminalSession] = useState<string | null>(null);
|
|
44
|
+
const [errors, setErrors] = useState<string[]>([]);
|
|
45
|
+
const [routePulse, setRoutePulse] = useState(false);
|
|
46
|
+
const fullCanvas = location.pathname === '/workflow';
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
const handler = (e: ErrorEvent) => setErrors(prev => [...prev, e.message].slice(-20));
|
|
50
|
+
window.addEventListener('error', handler);
|
|
51
|
+
return () => window.removeEventListener('error', handler);
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
setRoutePulse(true);
|
|
56
|
+
const timer = setTimeout(() => setRoutePulse(false), 520);
|
|
57
|
+
return () => clearTimeout(timer);
|
|
58
|
+
}, [location.pathname]);
|
|
59
|
+
|
|
60
|
+
useDebugReporter(connState, lastError ? [lastError, ...errors] : errors);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
|
|
64
|
+
<Header />
|
|
65
|
+
{routePulse && <div className="route-progress" aria-hidden="true" />}
|
|
66
|
+
<main style={{ flex: 1, overflow: fullCanvas ? 'hidden' : 'auto', padding: fullCanvas ? 0 : '16px 20px', minHeight: 0 }}>
|
|
67
|
+
<Suspense fallback={<LoadingView label={loadingLabel(location.pathname)} fullCanvas={fullCanvas} />}>
|
|
68
|
+
<Routes>
|
|
69
|
+
<Route path="/" element={<TaskList onSelectSession={setActiveTerminalSession} />} />
|
|
70
|
+
<Route path="/tasks" element={<TaskList onSelectSession={setActiveTerminalSession} />} />
|
|
71
|
+
<Route path="/workflow" element={<WorkflowRoute onSelectSession={setActiveTerminalSession} />} />
|
|
72
|
+
<Route path="/agents" element={<AgentsRoute onSelectSession={setActiveTerminalSession} />} />
|
|
73
|
+
<Route path="/roles" element={<RolesRoute />} />
|
|
74
|
+
<Route path="/settings" element={<SettingsRoute />} />
|
|
75
|
+
</Routes>
|
|
76
|
+
</Suspense>
|
|
77
|
+
</main>
|
|
78
|
+
{activeTerminalSession && (
|
|
79
|
+
<Suspense fallback={null}>
|
|
80
|
+
<TerminalDrawer sessionId={activeTerminalSession} onClose={() => setActiveTerminalSession(null)} />
|
|
81
|
+
</Suspense>
|
|
82
|
+
)}
|
|
83
|
+
{!fullCanvas && <Footer connState={connState} eventSeq={eventSeq} lastSync={lastSync} lastError={lastError} />}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export function getAuthToken() {
|
|
2
|
+
const current = new URL(window.location.href);
|
|
3
|
+
const fromUrl = current.searchParams.get('token');
|
|
4
|
+
if (fromUrl) {
|
|
5
|
+
window.sessionStorage.setItem('wf-ui-token', fromUrl);
|
|
6
|
+
return fromUrl;
|
|
7
|
+
}
|
|
8
|
+
return window.sessionStorage.getItem('wf-ui-token') || '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function apiFetch(path: string, init: RequestInit = {}) {
|
|
12
|
+
const token = getAuthToken();
|
|
13
|
+
const headers = new Headers(init.headers || {});
|
|
14
|
+
if (token) headers.set('Authorization', `Bearer ${token}`);
|
|
15
|
+
if (init.body && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json');
|
|
16
|
+
return fetch(path, { ...init, headers });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function apiJson<T = any>(path: string, init: RequestInit = {}): Promise<T> {
|
|
20
|
+
const res = await apiFetch(path, init);
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
let message = `${path}: ${res.status}`;
|
|
23
|
+
try {
|
|
24
|
+
const body = await res.json();
|
|
25
|
+
message = body?.error?.message || message;
|
|
26
|
+
} catch {
|
|
27
|
+
// keep status message
|
|
28
|
+
}
|
|
29
|
+
throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
return res.json();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const jsonCache = new Map<string, { ts: number; value?: unknown; promise?: Promise<unknown> }>();
|
|
35
|
+
|
|
36
|
+
export async function apiJsonCached<T = any>(
|
|
37
|
+
path: string,
|
|
38
|
+
{ ttlMs = 3000, refresh = false }: { ttlMs?: number; refresh?: boolean } = {},
|
|
39
|
+
): Promise<T> {
|
|
40
|
+
const key = path;
|
|
41
|
+
const now = Date.now();
|
|
42
|
+
const cached = jsonCache.get(key);
|
|
43
|
+
if (!refresh && cached) {
|
|
44
|
+
if (cached.value !== undefined && now - cached.ts < ttlMs) return cached.value as T;
|
|
45
|
+
if (cached.value !== undefined) {
|
|
46
|
+
if (!cached.promise) {
|
|
47
|
+
const promise = apiJson<T>(path)
|
|
48
|
+
.then((value) => {
|
|
49
|
+
jsonCache.set(key, { ts: Date.now(), value });
|
|
50
|
+
return value;
|
|
51
|
+
})
|
|
52
|
+
.catch((error) => {
|
|
53
|
+
jsonCache.set(key, { ts: cached.ts, value: cached.value });
|
|
54
|
+
console.debug?.('Background refresh failed', path, error);
|
|
55
|
+
return cached.value as T;
|
|
56
|
+
});
|
|
57
|
+
jsonCache.set(key, { ...cached, promise });
|
|
58
|
+
}
|
|
59
|
+
return cached.value as T;
|
|
60
|
+
}
|
|
61
|
+
if (cached.promise) return cached.promise as Promise<T>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const promise = apiJson<T>(path)
|
|
65
|
+
.then((value) => {
|
|
66
|
+
jsonCache.set(key, { ts: Date.now(), value });
|
|
67
|
+
return value;
|
|
68
|
+
})
|
|
69
|
+
.catch((error) => {
|
|
70
|
+
jsonCache.delete(key);
|
|
71
|
+
throw error;
|
|
72
|
+
});
|
|
73
|
+
jsonCache.set(key, { ts: now, promise });
|
|
74
|
+
return promise;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function invalidateApiCache(prefix?: string) {
|
|
78
|
+
if (!prefix) {
|
|
79
|
+
jsonCache.clear();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const key of [...jsonCache.keys()]) {
|
|
83
|
+
if (key.startsWith(prefix)) jsonCache.delete(key);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function wsUrl(path: string) {
|
|
88
|
+
const token = getAuthToken();
|
|
89
|
+
const url = new URL(path, window.location.href);
|
|
90
|
+
url.protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
91
|
+
url.searchParams.set('token', token);
|
|
92
|
+
return url.toString();
|
|
93
|
+
}
|