maqcli 0.7.0 → 0.9.0
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/dist/core/launcher.js +1 -1
- package/dist/index.js +1 -1
- package/dist/server/daemon.js +1 -1
- package/dist/server/webui.d.ts +22 -13
- package/dist/server/webui.js +568 -397
- package/package.json +1 -1
package/dist/server/webui.js
CHANGED
|
@@ -1,462 +1,633 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* webui.ts — the self-contained "
|
|
3
|
-
* `/app` (and `/`). Zero build step, zero dependencies: one HTML document
|
|
4
|
-
* inline CSS + vanilla JS. It renders the SAME normalized event stream the
|
|
2
|
+
* webui.ts — the self-contained "Megalodon" control surface the daemon serves
|
|
3
|
+
* at `/app` (and `/`). Zero build step, zero dependencies: one HTML document
|
|
4
|
+
* with inline CSS + vanilla JS. It renders the SAME normalized event stream the
|
|
5
5
|
* mobile app consumes, so there is no second source of truth.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* This is a from-spec rebuild (maq_cli_ui_spec Phases 4-6). The recommended
|
|
8
|
+
* SPA stack (React + Monaco + Framer + react-resizable-panels) is deliberately
|
|
9
|
+
* NOT used: the daemon ships one static asset with no build pipeline, so the
|
|
10
|
+
* same UX is delivered dependency-free —
|
|
11
|
+
* - real drag-resizable 3-panel shell (custom pointer-drag splitters)
|
|
12
|
+
* - universal preview: JSON tree / code+line-numbers / markdown / sandboxed
|
|
13
|
+
* HTML / images (replaces Monaco + react-markdown + react-json-view)
|
|
14
|
+
* - send button with a toggle-up mode picker popover (Single/Parallel/Loop/
|
|
15
|
+
* Safe), mode icon on the button face, selection persisted
|
|
16
|
+
* - orchestration visualizations derived from the event stream (parallel
|
|
17
|
+
* round dashboard / loop progress / safe split→merge→validate rail)
|
|
18
|
+
* - custom animated cursor follower + micro-interactions (CSS, not Framer)
|
|
14
19
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
20
|
+
* Theme (Megalodon): deep matte black base, controlled blue-white accents (not
|
|
21
|
+
* neon), sparse red for status/danger, white primary text, no gradients except
|
|
22
|
+
* intentional depth cues. Everything references CSS custom-property tokens.
|
|
23
|
+
*
|
|
24
|
+
* Auth: the daemon requires a Bearer token for /v1/*. The page reads it from
|
|
25
|
+
* ?key= / ?token= or a prompt, keeps it in memory only, and streams SSE via
|
|
26
|
+
* fetch + ReadableStream (token in the Authorization header, never the URL).
|
|
18
27
|
*/
|
|
19
28
|
export function webuiHtml(version) {
|
|
20
|
-
// NB:
|
|
21
|
-
//
|
|
22
|
-
// template literal.
|
|
29
|
+
// NB: client script uses only single/double quotes + string concatenation —
|
|
30
|
+
// no backticks / ${} — so it lives safely inside this template literal.
|
|
23
31
|
return `<!doctype html>
|
|
24
32
|
<html lang="en"><head>
|
|
25
33
|
<meta charset="utf-8">
|
|
26
34
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
27
|
-
<title>MAQ ·
|
|
35
|
+
<title>MAQ · Megalodon</title>
|
|
28
36
|
<style>
|
|
37
|
+
@media (prefers-reduced-motion: no-preference){ :root{ --dur-1:140ms; --dur-2:240ms; --ease:cubic-bezier(.2,.8,.2,1) } }
|
|
38
|
+
@media (prefers-reduced-motion: reduce){ :root{ --dur-1:0ms; --dur-2:0ms; --ease:linear } *{animation-duration:0ms !important;transition-duration:0ms !important} }
|
|
29
39
|
:root{
|
|
30
|
-
|
|
31
|
-
--
|
|
32
|
-
--
|
|
40
|
+
/* Megalodon: deep matte black + blue-white + sparse red */
|
|
41
|
+
--bg:#04070d; --surface:#090d16; --surface-2:#0e131f; --surface-3:#141a29;
|
|
42
|
+
--border:#1a2233; --border-strong:#28324a; --edge-soft:#131926;
|
|
43
|
+
--ink:#eef2fb; --ink-dim:#8a94ab; --ink-faint:#565f76;
|
|
44
|
+
--accent:#4d8dff; --accent-2:#93b8ff; --accent-ink:#04122e;
|
|
45
|
+
--accent-soft:rgba(77,141,255,.13); --accent-line:rgba(77,141,255,.42); --accent-glow:rgba(77,141,255,.28);
|
|
46
|
+
--danger:#ff4d5e; --danger-soft:rgba(255,77,94,.13);
|
|
47
|
+
--ok:#37d9a0; --ok-soft:rgba(55,217,160,.13);
|
|
48
|
+
--warn:#f5b544; --warn-soft:rgba(245,181,68,.13);
|
|
49
|
+
--fs-11:.6875rem; --fs-12:.75rem; --fs-13:.8125rem; --fs-15:.9375rem; --fs-19:1.1875rem; --fs-24:1.5rem;
|
|
50
|
+
--font-display:'Space Grotesk',ui-sans-serif,system-ui,sans-serif;
|
|
51
|
+
--font-body:'Inter',ui-sans-serif,-apple-system,'Segoe UI',Roboto,sans-serif;
|
|
52
|
+
--font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
|
|
53
|
+
--sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;
|
|
54
|
+
--r:10px; --r-sm:7px; --r-lg:14px;
|
|
55
|
+
--wl:266px; --wr:0px; --shadow:0 16px 48px rgba(0,0,0,.5);
|
|
33
56
|
}
|
|
34
57
|
*{box-sizing:border-box} html,body{height:100%}
|
|
35
|
-
body{margin:0;background:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
body{margin:0;background:var(--bg);color:var(--ink);font:var(--fs-13)/1.55 var(--font-body);-webkit-font-smoothing:antialiased}
|
|
59
|
+
@media (pointer:fine) and (prefers-reduced-motion: no-preference){ body{cursor:none} a,button,[role=button],input,textarea,select,.resize{cursor:none} }
|
|
60
|
+
h1,h2,h3,h4{font-family:var(--font-display);font-weight:600;margin:0;letter-spacing:-.01em}
|
|
61
|
+
a{color:var(--accent-2)}
|
|
62
|
+
button,input,select,textarea{font-family:inherit;color:inherit}
|
|
63
|
+
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:5px}
|
|
64
|
+
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
65
|
+
.eyebrow{font-size:var(--fs-11);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-faint);font-weight:600}
|
|
66
|
+
::-webkit-scrollbar{width:9px;height:9px} ::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:9px} ::-webkit-scrollbar-track{background:transparent}
|
|
67
|
+
|
|
68
|
+
/* custom cursor */
|
|
69
|
+
#cur,#curDot{position:fixed;top:0;left:0;pointer-events:none;z-index:9999;border-radius:50%;translate:-50% -50%}
|
|
70
|
+
#cur{width:26px;height:26px;border:1.5px solid var(--accent-line);transition:width var(--dur-1) var(--ease),height var(--dur-1) var(--ease),background var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease)}
|
|
71
|
+
#cur.hot{width:40px;height:40px;background:var(--accent-soft);border-color:var(--accent)}
|
|
72
|
+
#cur.press{width:20px;height:20px}
|
|
73
|
+
#curDot{width:5px;height:5px;background:var(--accent)}
|
|
74
|
+
@media (pointer:coarse),(prefers-reduced-motion: reduce){ #cur,#curDot{display:none !important} }
|
|
75
|
+
|
|
76
|
+
/* app shell */
|
|
77
|
+
#app{display:grid;height:100vh;grid-template-rows:54px 1fr;
|
|
78
|
+
grid-template-columns:var(--wl) 5px 1fr 5px var(--wr);
|
|
79
|
+
grid-template-areas:"top top top top top" "side rl main rr prev"}
|
|
80
|
+
#app.no-prev{grid-template-columns:var(--wl) 5px 1fr 0px 0px}
|
|
81
|
+
@media (max-width:900px){
|
|
82
|
+
#app{grid-template-columns:1fr;grid-template-areas:"top" "main"}
|
|
83
|
+
#side{position:fixed;inset:54px auto 0 0;width:284px;z-index:60;transform:translateX(-100%);transition:transform var(--dur-2) var(--ease)}
|
|
84
|
+
#side.open{transform:none} #rl,#rr,#prev{display:none}
|
|
85
|
+
#scrim{position:fixed;inset:54px 0 0 0;background:#000b;z-index:55;display:none} #scrim.on{display:block}
|
|
86
|
+
#app.prev-sheet #prev{display:flex;position:fixed;inset:54px 0 0 0;z-index:58;width:100%}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* topbar */
|
|
90
|
+
#top{grid-area:top;display:flex;align-items:center;gap:var(--sp-3);padding:0 var(--sp-4);
|
|
91
|
+
border-bottom:1px solid var(--border);background:linear-gradient(180deg,var(--surface-2),var(--surface))}
|
|
92
|
+
.menu-b{display:none} @media(max-width:900px){.menu-b{display:inline-flex}}
|
|
93
|
+
.brand{display:flex;align-items:center;gap:9px}
|
|
94
|
+
.fin{width:26px;height:26px;color:var(--accent)} .fin svg{width:100%;height:100%}
|
|
95
|
+
.brand h1{font-size:var(--fs-15);letter-spacing:.14em}
|
|
96
|
+
.brand .q{color:var(--danger)}
|
|
97
|
+
.live{display:flex;align-items:center;gap:6px;font-size:var(--fs-11);color:var(--ink-faint)}
|
|
98
|
+
.dot{width:7px;height:7px;border-radius:50%;background:var(--ink-faint)}
|
|
99
|
+
.dot.on{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}
|
|
46
100
|
.grow{flex:1}
|
|
47
|
-
.
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.
|
|
63
|
-
.
|
|
64
|
-
.
|
|
65
|
-
.
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.
|
|
71
|
-
.
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.
|
|
94
|
-
.
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
.
|
|
104
|
-
.
|
|
105
|
-
.
|
|
106
|
-
.
|
|
107
|
-
.
|
|
108
|
-
.
|
|
109
|
-
.
|
|
110
|
-
.
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
101
|
+
.tnav{display:flex;gap:3px;overflow-x:auto;scrollbar-width:none} .tnav::-webkit-scrollbar{display:none}
|
|
102
|
+
.tb{background:transparent;color:var(--ink-dim);border:1px solid transparent;border-radius:var(--r-sm);
|
|
103
|
+
padding:6px 11px;font-size:var(--fs-12);font-weight:500;white-space:nowrap;display:inline-flex;align-items:center;gap:6px;
|
|
104
|
+
transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease),transform var(--dur-1) var(--ease)}
|
|
105
|
+
.tb:hover{background:var(--surface-3);color:var(--ink)} .tb:active{transform:scale(.96)}
|
|
106
|
+
.tb.accent{color:var(--accent-2)} .tb svg{width:14px;height:14px;flex:none}
|
|
107
|
+
.kbd{border:1px solid var(--border-strong);border-radius:4px;padding:0 5px;font:10px var(--font-mono);color:var(--ink-faint)}
|
|
108
|
+
|
|
109
|
+
/* resize handles */
|
|
110
|
+
.resize{background:transparent;position:relative} .resize::after{content:'';position:absolute;inset:0 2px;border-radius:3px;transition:background var(--dur-1) var(--ease)}
|
|
111
|
+
.resize:hover::after,.resize.drag::after{background:var(--accent-line)}
|
|
112
|
+
@media(max-width:900px){.resize{display:none}}
|
|
113
|
+
|
|
114
|
+
/* sidebar */
|
|
115
|
+
#side{grid-area:side;background:var(--surface);border-right:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column}
|
|
116
|
+
.s-sec{padding:var(--sp-3) var(--sp-4) var(--sp-2)} .s-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
117
|
+
.cbadge{background:var(--surface-3);border:1px solid var(--border);border-radius:999px;color:var(--ink-dim);font-size:10px;padding:1px 7px;font-weight:600}
|
|
118
|
+
.cbadge.alert{background:var(--warn-soft);border-color:var(--warn);color:var(--warn)}
|
|
119
|
+
.grp-label{font-size:10px;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.08em;padding:8px var(--sp-4) 3px}
|
|
120
|
+
.row{padding:9px var(--sp-4);border-bottom:1px solid var(--edge-soft);display:flex;flex-direction:column;gap:3px;
|
|
121
|
+
transition:background var(--dur-1) var(--ease)}
|
|
122
|
+
.row[tabindex]{cursor:pointer} .row:hover{background:var(--surface-2)} .row.active{background:var(--surface-3);box-shadow:inset 3px 0 0 var(--accent)}
|
|
123
|
+
.row-t{font-size:var(--fs-13);color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
124
|
+
.row-m{font-size:var(--fs-11);color:var(--ink-faint);display:flex;align-items:center;gap:7px;flex-wrap:wrap}
|
|
125
|
+
.tag{border:1px solid var(--border);border-radius:999px;padding:0 7px;font-size:10px;font-weight:600}
|
|
126
|
+
.tag.running{color:var(--accent-2);border-color:var(--accent-line)} .tag.done{color:var(--ok);border-color:var(--ok)}
|
|
127
|
+
.tag.error,.tag.cancelled{color:var(--danger);border-color:var(--danger)} .tag.paused{color:var(--warn);border-color:var(--warn)}
|
|
128
|
+
.empty{padding:var(--sp-6) var(--sp-4);text-align:center;color:var(--ink-faint);font-size:var(--fs-12)}
|
|
129
|
+
.empty svg{width:26px;height:26px;opacity:.5;margin-bottom:6px}
|
|
130
|
+
.skel{background:linear-gradient(90deg,var(--surface-2) 25%,var(--surface-3) 37%,var(--surface-2) 63%);background-size:400% 100%;
|
|
131
|
+
animation:sh 1.4s ease infinite;border-radius:6px;height:12px;margin:6px var(--sp-4)}
|
|
132
|
+
@keyframes sh{0%{background-position:100% 0}100%{background-position:0 0}}
|
|
133
|
+
@media(prefers-reduced-motion:reduce){.skel{animation:none;opacity:.5}}
|
|
134
|
+
|
|
135
|
+
/* main */
|
|
136
|
+
#main{grid-area:main;display:flex;flex-direction:column;min-width:0;background:var(--bg)}
|
|
137
|
+
#composer{padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--border)}
|
|
138
|
+
.comp-row{display:flex;gap:var(--sp-2);align-items:flex-end}
|
|
139
|
+
#goal{flex:1;resize:none;height:48px;max-height:190px;background:var(--surface);color:var(--ink);border:1px solid var(--border);
|
|
140
|
+
border-radius:var(--r);padding:12px 14px;font:var(--fs-13)/1.5 var(--font-body);transition:border-color var(--dur-1) var(--ease)}
|
|
141
|
+
#goal::placeholder{color:var(--ink-faint)} #goal:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
142
|
+
/* split send button + toggle-up mode picker */
|
|
143
|
+
.send-wrap{position:relative;display:flex;flex:none}
|
|
144
|
+
.send{background:var(--accent);color:var(--accent-ink);font-weight:700;border:none;border-radius:var(--r) 0 0 var(--r);
|
|
145
|
+
padding:12px 15px 12px 16px;font-size:var(--fs-13);display:inline-flex;align-items:center;gap:8px;
|
|
146
|
+
transition:filter var(--dur-1) var(--ease),transform var(--dur-1) var(--ease)}
|
|
147
|
+
.send:hover{filter:brightness(1.09)} .send:active{transform:scale(.97)} .send:disabled{opacity:.45;filter:none}
|
|
148
|
+
.send .mi{width:15px;height:15px}
|
|
149
|
+
.mode-toggle{background:var(--accent);color:var(--accent-ink);border:none;border-left:1px solid rgba(4,18,46,.25);
|
|
150
|
+
border-radius:0 var(--r) var(--r) 0;padding:0 9px;display:inline-flex;align-items:center;transition:filter var(--dur-1) var(--ease)}
|
|
151
|
+
.mode-toggle:hover{filter:brightness(1.09)} .mode-toggle svg{width:14px;height:14px;transition:transform var(--dur-1) var(--ease)}
|
|
152
|
+
.mode-toggle.open svg{transform:rotate(180deg)}
|
|
153
|
+
.mode-pop{position:absolute;bottom:calc(100% + 8px);right:0;width:288px;background:var(--surface-2);border:1px solid var(--border-strong);
|
|
154
|
+
border-radius:var(--r-lg);box-shadow:var(--shadow);padding:6px;display:none;z-index:40;animation:pop var(--dur-2) var(--ease)}
|
|
155
|
+
.mode-pop.open{display:block}
|
|
156
|
+
@keyframes pop{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
|
|
157
|
+
.mopt{display:flex;gap:10px;padding:9px 10px;border-radius:9px;cursor:pointer;align-items:flex-start}
|
|
158
|
+
.mopt:hover,.mopt.sel{background:var(--surface-3)} .mopt.sel{box-shadow:inset 0 0 0 1px var(--accent-line)}
|
|
159
|
+
.mopt .ic{width:17px;height:17px;color:var(--ink-dim);flex:none;margin-top:1px} .mopt.sel .ic{color:var(--accent)}
|
|
160
|
+
.mopt h4{font-size:var(--fs-12);font-family:var(--font-body);color:var(--ink)} .mopt p{margin:2px 0 0;font-size:var(--fs-11);color:var(--ink-faint);line-height:1.4}
|
|
161
|
+
.opts{display:flex;gap:var(--sp-4);align-items:center;margin-top:var(--sp-3);flex-wrap:wrap;color:var(--ink-dim);font-size:var(--fs-12)}
|
|
162
|
+
.opts label{display:flex;align-items:center;gap:6px}
|
|
163
|
+
.opts select,.opts input[type=number]{background:var(--surface);color:var(--ink);border:1px solid var(--border);border-radius:6px;padding:3px 7px;font-size:var(--fs-12)}
|
|
164
|
+
.opts input[type=checkbox]{accent-color:var(--accent);width:14px;height:14px}
|
|
165
|
+
.hint{margin-left:auto;color:var(--ink-faint);font-size:var(--fs-11)}
|
|
166
|
+
|
|
167
|
+
/* timeline (signature) + orchestration viz */
|
|
168
|
+
#timeline{padding:var(--sp-3) var(--sp-5);border-bottom:1px solid var(--border);overflow-x:auto}
|
|
169
|
+
.track{display:flex;align-items:center;min-height:32px}
|
|
170
|
+
.node{display:flex;align-items:center;flex:none}
|
|
171
|
+
.node-dot{width:20px;height:20px;border-radius:50%;border:2px solid var(--border-strong);background:var(--surface);display:flex;align-items:center;justify-content:center;flex:none;
|
|
172
|
+
transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease)}
|
|
173
|
+
.node-dot svg{width:11px;height:11px;opacity:0} .node.done .node-dot{border-color:var(--ok);background:var(--ok-soft)} .node.done .node-dot svg{opacity:1;color:var(--ok)}
|
|
174
|
+
.node.active .node-dot{border-color:var(--accent);background:var(--accent-soft);animation:pulse 1.6s ease-in-out infinite}
|
|
175
|
+
@keyframes pulse{0%,100%{box-shadow:0 0 0 3px var(--accent-soft)}50%{box-shadow:0 0 0 8px transparent}}
|
|
176
|
+
.node-label{font-size:var(--fs-12);color:var(--ink-faint);margin-left:7px;white-space:nowrap}
|
|
177
|
+
.node.done .node-label{color:var(--ok)} .node.active .node-label{color:var(--accent-2);font-weight:600}
|
|
178
|
+
.node-line{width:26px;height:1px;background:var(--border-strong);margin:0 4px} .node.done + .node-line{background:var(--ok)}
|
|
179
|
+
.sub-rail{display:flex;align-items:center;gap:6px;margin-top:8px;flex-wrap:wrap}
|
|
180
|
+
.sub-chip{font-size:10px;color:var(--accent-2);background:var(--accent-soft);border:1px solid var(--accent-line);border-radius:999px;padding:2px 9px;font-weight:600}
|
|
181
|
+
.sub-chip.merge{color:var(--warn);background:var(--warn-soft);border-color:var(--warn)}
|
|
182
|
+
|
|
183
|
+
/* console */
|
|
184
|
+
#console{flex:1;overflow-y:auto;padding:var(--sp-3) var(--sp-5);display:flex;flex-direction:column;gap:5px}
|
|
185
|
+
.ev{display:flex;gap:9px;padding:6px 9px;border-radius:8px;border-left:2px solid transparent;animation:fade var(--dur-2) var(--ease)}
|
|
186
|
+
@keyframes fade{from{opacity:0;transform:translateY(2px)}to{opacity:1;transform:none}}
|
|
187
|
+
@media(prefers-reduced-motion:reduce){.ev{animation:none}}
|
|
188
|
+
.ev .ic{width:15px;height:15px;flex:none;margin-top:1px} .ev .ic svg{width:100%;height:100%}
|
|
189
|
+
.ev .tx{white-space:pre-wrap;word-break:break-word;font:11.5px/1.55 var(--font-mono);flex:1}
|
|
190
|
+
.ev .t{color:var(--ink-faint);font-size:10px;margin-left:7px}
|
|
191
|
+
.c-accent{color:var(--accent-2)} .c-dim{color:var(--ink-dim)} .c-ok{color:var(--ok)} .c-danger{color:var(--danger)} .c-warn{color:var(--warn)}
|
|
192
|
+
.ev.bg-danger{background:var(--danger-soft);border-left-color:var(--danger)} .ev.bg-warn{background:var(--warn-soft);border-left-color:var(--warn)}
|
|
193
|
+
|
|
194
|
+
/* preview */
|
|
195
|
+
#prev{grid-area:prev;background:var(--surface);border-left:1px solid var(--border);overflow:hidden;min-width:0;display:flex;flex-direction:column}
|
|
196
|
+
.p-head{display:flex;align-items:center;gap:8px;padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--border)}
|
|
197
|
+
.p-head h3{font-size:var(--fs-13);flex:1} .p-type{font-size:10px;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.06em}
|
|
198
|
+
.ibtn{background:transparent;border:1px solid var(--border);border-radius:7px;color:var(--ink-dim);padding:5px 9px;font-size:var(--fs-12);display:inline-flex;align-items:center;gap:5px;transition:border-color var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
|
|
199
|
+
.ibtn:hover{color:var(--ink);border-color:var(--accent-line)}
|
|
200
|
+
#prevBody{flex:1;overflow:auto}
|
|
201
|
+
pre.code{margin:0;padding:0;font:11.5px/1.6 var(--font-mono);display:flex}
|
|
202
|
+
.gutter{color:var(--ink-faint);text-align:right;padding:var(--sp-3) 8px;user-select:none;border-right:1px solid var(--border);background:var(--surface-2)}
|
|
203
|
+
.codelines{padding:var(--sp-3) var(--sp-4);white-space:pre;overflow-x:auto;color:var(--ink);flex:1}
|
|
204
|
+
.md{padding:var(--sp-4);line-height:1.65} .md h1,.md h2,.md h3{margin:.8em 0 .3em} .md code{background:var(--surface-3);padding:1px 5px;border-radius:4px;font:12px var(--font-mono)}
|
|
205
|
+
.md pre{background:var(--surface-2);border:1px solid var(--border);border-radius:8px;padding:10px;overflow-x:auto;font:12px var(--font-mono)}
|
|
206
|
+
.md ul{padding-left:1.2em} .md a{color:var(--accent-2)}
|
|
207
|
+
.jt{padding:var(--sp-4);font:12px/1.6 var(--font-mono)} .jt .k{color:var(--accent-2)} .jt .s{color:var(--ok)} .jt .n{color:var(--warn)} .jt .b{color:var(--danger)}
|
|
208
|
+
.jt .tog{cursor:pointer;color:var(--ink-faint);user-select:none} .jt .nest{padding-left:16px;border-left:1px solid var(--edge-soft)}
|
|
209
|
+
.jt .col{display:none} .jt.open>.col{display:block}
|
|
210
|
+
iframe.htmlprev{width:100%;height:100%;border:none;background:#fff}
|
|
211
|
+
|
|
212
|
+
/* overlays */
|
|
213
|
+
.ov{position:fixed;inset:0;background:var(--bg);z-index:100;display:none;flex-direction:column}
|
|
214
|
+
.ov.show{display:flex}
|
|
215
|
+
.ov-head{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-5);border-bottom:1px solid var(--border);background:var(--surface)}
|
|
216
|
+
.back{background:var(--surface-3);border:1px solid var(--border);color:var(--ink);border-radius:var(--r-sm);padding:7px 12px;font-size:var(--fs-12);font-weight:500;display:inline-flex;align-items:center;gap:6px;transition:border-color var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
|
|
217
|
+
.back:hover{border-color:var(--accent);color:var(--accent-2)}
|
|
218
|
+
.ov-body{flex:1;overflow-y:auto;padding:var(--sp-5)}
|
|
219
|
+
.fgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:var(--sp-3)}
|
|
220
|
+
.fcard{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:var(--sp-4);text-align:left;
|
|
221
|
+
transition:border-color var(--dur-1) var(--ease),transform var(--dur-1) var(--ease)}
|
|
222
|
+
.fcard:hover{border-color:var(--accent-line);transform:translateY(-2px)} .fcard:active{transform:none}
|
|
223
|
+
.fcard .eyebrow{color:var(--accent-2)} .fcard h4{font-size:var(--fs-13);margin:5px 0 4px;font-family:var(--font-body)} .fcard p{margin:0;font-size:var(--fs-12);color:var(--ink-dim);line-height:1.5}
|
|
224
|
+
.req{padding:10px var(--sp-4);border-bottom:1px solid var(--edge-soft);border-left:3px solid transparent}
|
|
225
|
+
.req.destructive{border-left-color:var(--danger);background:var(--danger-soft)} .req.major{border-left-color:var(--warn);background:var(--warn-soft)}
|
|
226
|
+
.req .a{font-size:var(--fs-12);color:var(--ink)} .req .r{font-size:var(--fs-11);color:var(--ink-faint);margin:3px 0 8px}
|
|
227
|
+
.req .btns{display:flex;gap:6px} .bs{border:none;border-radius:6px;padding:5px 12px;font-size:11px;font-weight:600} .ok-b{background:var(--ok);color:#04231a} .no-b{background:var(--danger);color:#2e0507}
|
|
228
|
+
.sec-blk{margin-bottom:var(--sp-6)} .sec-h{display:flex;align-items:center;gap:8px;margin-bottom:8px} .sec-h h4{font-size:var(--fs-13);font-family:var(--font-body)}
|
|
229
|
+
.sec-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:6px;margin-bottom:8px}
|
|
230
|
+
.sec-i{background:var(--surface-2);border:1px solid var(--border);border-radius:7px;padding:7px 10px;font:11.5px var(--font-mono);color:var(--ink);word-break:break-all}
|
|
231
|
+
.sec-note{color:var(--ink-faint);font-size:var(--fs-11);line-height:1.5}
|
|
232
|
+
.posture{display:flex;gap:var(--sp-2);margin-bottom:var(--sp-5);flex-wrap:wrap}
|
|
233
|
+
.pill{display:inline-flex;align-items:center;gap:6px;background:var(--ok-soft);border:1px solid var(--ok);color:var(--ok);border-radius:999px;padding:5px 12px;font-size:var(--fs-12);font-weight:600}
|
|
234
|
+
.pill svg{width:12px;height:12px}
|
|
235
|
+
/* command palette */
|
|
236
|
+
.cmdk-bd{position:fixed;inset:0;background:rgba(2,4,9,.62);z-index:200;display:none;justify-content:center;padding-top:12vh}
|
|
237
|
+
.cmdk-bd.show{display:flex}
|
|
238
|
+
.cmdk{width:min(560px,92vw);height:max-content;background:var(--surface-2);border:1px solid var(--border-strong);border-radius:var(--r-lg);box-shadow:var(--shadow);overflow:hidden;animation:pop var(--dur-2) var(--ease)}
|
|
239
|
+
.cmdk-in{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--border)} .cmdk-in svg{width:16px;height:16px;color:var(--ink-faint)}
|
|
240
|
+
#cmdkInput{flex:1;background:transparent;border:none;outline:none;color:var(--ink);font-size:var(--fs-15)} #cmdkInput::placeholder{color:var(--ink-faint)}
|
|
241
|
+
.cmdk-list{max-height:52vh;overflow-y:auto;padding:6px}
|
|
242
|
+
.cmdk-it{display:flex;align-items:center;gap:11px;padding:9px 10px;border-radius:8px;cursor:pointer} .cmdk-it.sel,.cmdk-it:hover{background:var(--surface-3)}
|
|
243
|
+
.cmdk-it .ic{width:15px;height:15px;color:var(--ink-faint);flex:none} .cmdk-it.sel .ic{color:var(--accent)}
|
|
244
|
+
.cmdk-it .m{flex:1;min-width:0} .cmdk-it .tt{font-size:var(--fs-13);color:var(--ink)} .cmdk-it .ss{font-size:var(--fs-11);color:var(--ink-faint)}
|
|
245
|
+
.cmdk-it .cat{font-size:10px;color:var(--ink-faint);text-transform:uppercase}
|
|
115
246
|
</style></head>
|
|
116
247
|
<body>
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
<
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
</
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<div class="sec">
|
|
139
|
-
<div
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
248
|
+
<div id="cur"></div><div id="curDot"></div>
|
|
249
|
+
<div id="app">
|
|
250
|
+
<header id="top">
|
|
251
|
+
<button class="menu-b ibtn" aria-label="Toggle sidebar" onclick="toggleSide()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M3 6h18M3 12h18M3 18h18"/></svg></button>
|
|
252
|
+
<div class="brand">
|
|
253
|
+
<span class="fin" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M2 15c5 1 8-1 11-6 1 3 1 5 0 7 2 0 4-1 5-3 0 4-3 7-8 7-4 0-8-2-8-5zm11-7c-3 2-6 3-9 2 2-3 6-4 9-2z"/></svg></span>
|
|
254
|
+
<h1>MAQ<span class="q"> ▴</span></h1>
|
|
255
|
+
<span class="sr-only">version ${version}</span>
|
|
256
|
+
<span class="live"><span class="dot" id="dot"></span><span id="liveTxt">connecting</span></span>
|
|
257
|
+
</div>
|
|
258
|
+
<span class="grow"></span>
|
|
259
|
+
<nav class="tnav" aria-label="Tools">
|
|
260
|
+
<button class="tb" onclick="openPalette()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>Search<span class="kbd">⌘K</span></button>
|
|
261
|
+
<button class="tb accent" onclick="openFeatures()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>Features</button>
|
|
262
|
+
<button class="tb" onclick="openSecurity()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2 4 5v6c0 5 3.5 8.5 8 11 4.5-2.5 8-6 8-11V5l-8-3z"/></svg>Security</button>
|
|
263
|
+
<button class="tb" id="prevToggle" onclick="togglePreview()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16"/></svg>Preview</button>
|
|
264
|
+
</nav>
|
|
265
|
+
</header>
|
|
266
|
+
<div id="scrim" onclick="toggleSide()"></div>
|
|
267
|
+
|
|
268
|
+
<aside id="side" aria-label="History">
|
|
269
|
+
<div class="s-sec"><div class="s-head"><span class="eyebrow">Request box</span><span class="cbadge" id="reqCount">0</span></div><div id="requests" role="region" aria-label="Pending requests"></div></div>
|
|
270
|
+
<div class="s-sec"><div class="s-head"><span class="eyebrow">History</span></div></div>
|
|
271
|
+
<div id="sessions" role="region" aria-label="Session history"></div>
|
|
272
|
+
<div class="s-sec"><div class="s-head"><span class="eyebrow">Agents</span></div><div id="agents" role="region" aria-label="Agents"></div></div>
|
|
273
|
+
</aside>
|
|
274
|
+
|
|
275
|
+
<div class="resize" id="rl" role="separator" aria-label="Resize sidebar" aria-orientation="vertical"></div>
|
|
276
|
+
|
|
277
|
+
<main id="main">
|
|
278
|
+
<div id="composer">
|
|
279
|
+
<div class="comp-row">
|
|
280
|
+
<label class="sr-only" for="goal">Goal</label>
|
|
281
|
+
<textarea id="goal" placeholder="Describe a goal — the Headroom master decomposes and dispatches it"></textarea>
|
|
282
|
+
<div class="send-wrap">
|
|
283
|
+
<button class="send" id="send" onclick="startTask()"><span class="mi" id="sendIcon"></span><span id="sendLabel">Send</span></button>
|
|
284
|
+
<button class="mode-toggle" id="modeToggle" aria-haspopup="menu" aria-expanded="false" aria-label="Choose execution mode" onclick="togglePop(event)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 15l6-6 6 6"/></svg></button>
|
|
285
|
+
<div class="mode-pop" id="modePop" role="menu" aria-label="Execution mode"></div>
|
|
286
|
+
</div>
|
|
147
287
|
</div>
|
|
148
288
|
<div class="opts">
|
|
149
|
-
<label>target
|
|
150
|
-
<select id="target">
|
|
151
|
-
<option value="none">none (raw)</option><option value="auto">auto</option>
|
|
152
|
-
<option value="claude-code">claude-code</option><option value="codex">codex</option>
|
|
153
|
-
<option value="gemini">gemini</option>
|
|
154
|
-
</select>
|
|
155
|
-
</label>
|
|
289
|
+
<label>target <select id="target"><option value="none">none (raw)</option><option value="auto">auto</option><option value="claude-code">claude-code</option><option value="codex">codex</option><option value="gemini">gemini</option></select></label>
|
|
156
290
|
<label><input type="checkbox" id="dry"> dry-run</label>
|
|
157
291
|
<label>concurrency <input type="number" id="conc" value="4" min="1" max="16" style="width:52px"></label>
|
|
292
|
+
<span class="hint"><span class="kbd">⌘↵</span> to send</span>
|
|
158
293
|
</div>
|
|
159
294
|
</div>
|
|
160
|
-
<div class="
|
|
161
|
-
<div
|
|
162
|
-
</
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
</
|
|
168
|
-
<div
|
|
169
|
-
|
|
170
|
-
<button class="ghost" onclick="closeFeatures()">← Back to home</button>
|
|
171
|
-
<b style="margin-left:12px">All features</b>
|
|
172
|
-
<span class="grow"></span>
|
|
173
|
-
<span class="e-mut" style="font-size:12px">everything MAQ can do — click to run</span>
|
|
174
|
-
</div>
|
|
175
|
-
<div class="grid" id="featureGrid"><div class="empty">loading…</div></div>
|
|
295
|
+
<div id="timeline" aria-label="Progress"><div class="track" id="track"></div><div id="subrail"></div></div>
|
|
296
|
+
<div id="console" role="log" aria-live="polite" aria-label="Live activity"></div>
|
|
297
|
+
</main>
|
|
298
|
+
|
|
299
|
+
<div class="resize" id="rr" role="separator" aria-label="Resize preview" aria-orientation="vertical"></div>
|
|
300
|
+
|
|
301
|
+
<aside id="prev" aria-label="Preview">
|
|
302
|
+
<div class="p-head"><h3>Preview</h3><span class="p-type" id="prevType"></span><button class="ibtn" onclick="togglePreview()">Close</button></div>
|
|
303
|
+
<div id="prevBody"></div>
|
|
304
|
+
</aside>
|
|
176
305
|
</div>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
<span class="grow"></span>
|
|
182
|
-
<span class="e-mut" style="font-size:12px">enforced at the code level — same rules the terminal ('maq security') shows and enforces</span>
|
|
183
|
-
</div>
|
|
184
|
-
<div id="securityBody" style="overflow:auto;padding:16px"><div class="empty">loading…</div></div>
|
|
306
|
+
|
|
307
|
+
<div class="ov" id="features" role="dialog" aria-label="All features">
|
|
308
|
+
<div class="ov-head"><button class="back" onclick="closeFeatures()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>Back to home</button><h3 style="margin-left:4px">All features</h3><span class="grow"></span><span class="eyebrow" style="text-transform:none;letter-spacing:0">everything MAQ can do — click to run</span></div>
|
|
309
|
+
<div class="ov-body"><div class="fgrid" id="featureGrid"></div></div>
|
|
185
310
|
</div>
|
|
186
|
-
<
|
|
311
|
+
<div class="ov" id="security" role="dialog" aria-label="Security rules">
|
|
312
|
+
<div class="ov-head"><button class="back" onclick="closeSecurity()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>Back to home</button><h3 style="margin-left:4px">Security rules</h3><span class="grow"></span><span class="eyebrow" style="text-transform:none;letter-spacing:0">enforced at the code level — same rules the terminal ('maq security') shows</span></div>
|
|
313
|
+
<div class="ov-body" id="securityBody"></div>
|
|
314
|
+
</div>
|
|
315
|
+
<div class="cmdk-bd" id="cmdk" role="dialog" aria-label="Command palette">
|
|
316
|
+
<div class="cmdk"><div class="cmdk-in"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg><input id="cmdkInput" placeholder="Search features and sessions…" autocomplete="off"><span class="kbd">esc</span></div><div class="cmdk-list" id="cmdkList"></div></div>
|
|
317
|
+
</div>
|
|
318
|
+
<script>${CLIENT_JS}</script>
|
|
319
|
+
</body></html>`;
|
|
320
|
+
}
|
|
321
|
+
const CLIENT_JS = String.raw `
|
|
187
322
|
"use strict";
|
|
188
|
-
var base
|
|
189
|
-
var
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
323
|
+
var base=location.origin;
|
|
324
|
+
var qp=new URLSearchParams(location.search);
|
|
325
|
+
var token=qp.get('key')||qp.get('token')||sessionStorage.getItem('maqToken')||'';
|
|
326
|
+
if(!token){ token=prompt('Session auth key (the 9-digit key printed by: maq serve):')||''; }
|
|
327
|
+
sessionStorage.setItem('maqToken',token);
|
|
328
|
+
|
|
329
|
+
var I={
|
|
330
|
+
play:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>',
|
|
331
|
+
single:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>',
|
|
332
|
+
parallel:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h6M4 12h6M4 17h6M14 12h6M10 7c4 0 0 5 4 5M10 17c4 0 0-5 4-5"/></svg>',
|
|
333
|
+
loop:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12a8 8 0 0 1 14-5M20 12a8 8 0 0 1-14 5"/><path d="M18 3v4h-4M6 21v-4h4"/></svg>',
|
|
334
|
+
safe:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v4M6 21v-6M18 21v-6M12 15v-4M6 15a3 3 0 0 1 0-6M18 15a3 3 0 0 0 0-6M6 9h12"/></svg>',
|
|
335
|
+
chev:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>',
|
|
336
|
+
dot:'<svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="4"/></svg>',
|
|
337
|
+
check:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M5 13l4 4L19 7"/></svg>',
|
|
338
|
+
warn:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 9v4M12 17h.01M10.3 3.9L2.7 17a2 2 0 0 0 1.7 3h15.2a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>',
|
|
339
|
+
x:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18 6L6 18M6 6l12 12"/></svg>',
|
|
340
|
+
tool:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.8-3.8a6 6 0 0 1-7.9 7.9l-6.9 6.9a2.1 2.1 0 0 1-3-3l6.9-6.9a6 6 0 0 1 7.9-7.9z"/></svg>',
|
|
341
|
+
flag:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 22V4M4 4h11l-1.5 4L15 12H4"/></svg>',
|
|
342
|
+
verified:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l3 1.5 3.3-.3 1 3.1 2.7 2-1.3 3 1.3 3-2.7 2-1 3.1-3.3-.3L12 22l-3-1.5-3.3.3-1-3.1-2.7-2 1.3-3-1.3-3 2.7-2 1-3.1 3.3.3z"/><path d="M9 12l2 2 4-4"/></svg>',
|
|
343
|
+
circle:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/></svg>',
|
|
344
|
+
box:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M3 7l3-4h12l3 4"/></svg>'
|
|
345
|
+
};
|
|
346
|
+
var MODES=[
|
|
347
|
+
{id:'',h:'Single',ic:I.single,p:'one Scout→Plan→Execute→Verify pass'},
|
|
348
|
+
{id:'parallel',h:'Parallel',ic:I.parallel,p:'split, run at once, join by summary, repeat'},
|
|
349
|
+
{id:'loop',h:'Loop',ic:I.loop,p:'refine & retry until it verifies'},
|
|
350
|
+
{id:'safe',h:'Safe',ic:I.safe,p:'light split → merge → validate, isolated'}
|
|
198
351
|
];
|
|
199
|
-
var mode
|
|
200
|
-
var activeId =
|
|
352
|
+
var mode=sessionStorage.getItem('maqMode')||'parallel';
|
|
353
|
+
var activeId=null, connected=false, evList=[];
|
|
354
|
+
|
|
355
|
+
function h(t,c,html){var e=document.createElement(t);if(c)e.className=c;if(html!=null)e.innerHTML=html;return e;}
|
|
356
|
+
function esc(s){var d=document.createElement('div');d.textContent=String(s==null?'':s);return d.innerHTML;}
|
|
357
|
+
function hd(){return {authorization:'Bearer '+token,'content-type':'application/json'};}
|
|
358
|
+
function api(p,o){o=o||{};o.headers=hd();return fetch(base+p,o);}
|
|
359
|
+
function setLive(v){connected=v;document.getElementById('dot').className='dot'+(v?' on':'');document.getElementById('liveTxt').textContent=v?'connected':'offline';}
|
|
360
|
+
function empty(ic,t,hint){return '<div class="empty">'+(I[ic]||I.circle)+'<div>'+t+'</div>'+(hint?'<div style="margin-top:2px;opacity:.8">'+hint+'</div>':'')+'</div>';}
|
|
361
|
+
function skel(n){var s='';for(var i=0;i<n;i++)s+='<div class="skel" style="width:'+(58+((i*19)%36))+'%"></div>';return s;}
|
|
362
|
+
function ago(ts){try{var d=(Date.now()-new Date(ts).getTime())/1000;if(d<60)return Math.max(1,d|0)+'s ago';if(d<3600)return (d/60|0)+'m ago';if(d<86400)return (d/3600|0)+'h ago';return (d/86400|0)+'d ago';}catch(e){return '';}}
|
|
363
|
+
function fmtT(ts){try{return new Date(ts).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit'});}catch(e){return '';}}
|
|
364
|
+
function toggleSide(){document.getElementById('side').classList.toggle('open');document.getElementById('scrim').classList.toggle('on');}
|
|
365
|
+
|
|
366
|
+
/* ---- custom cursor follower ---- */
|
|
367
|
+
(function(){
|
|
368
|
+
var cur=document.getElementById('cur'),dot=document.getElementById('curDot');
|
|
369
|
+
if(!cur)return; var tx=0,ty=0,cx=0,cy=0;
|
|
370
|
+
addEventListener('mousemove',function(e){tx=e.clientX;ty=e.clientY;dot.style.transform='translate('+tx+'px,'+ty+'px) translate(-50%,-50%)';
|
|
371
|
+
var t=e.target; cur.classList.toggle('hot', !!(t.closest && t.closest('button,a,[role=button],.row[tabindex],.fcard,.mopt,.cmdk-it')));});
|
|
372
|
+
addEventListener('mousedown',function(){cur.classList.add('press');});
|
|
373
|
+
addEventListener('mouseup',function(){cur.classList.remove('press');});
|
|
374
|
+
(function loop(){cx+=(tx-cx)*.18;cy+=(ty-cy)*.18;cur.style.transform='translate('+cx+'px,'+cy+'px) translate(-50%,-50%)';requestAnimationFrame(loop);})();
|
|
375
|
+
})();
|
|
201
376
|
|
|
202
|
-
|
|
203
|
-
function
|
|
204
|
-
|
|
377
|
+
/* ---- resizable panels ---- */
|
|
378
|
+
(function(){
|
|
379
|
+
var app=document.getElementById('app');
|
|
380
|
+
var wl=sessionStorage.getItem('maqWL'); if(wl)app.style.setProperty('--wl',wl);
|
|
381
|
+
function drag(handle,varName,fromLeft){
|
|
382
|
+
var el=document.getElementById(handle); if(!el)return;
|
|
383
|
+
el.addEventListener('pointerdown',function(e){
|
|
384
|
+
e.preventDefault();el.classList.add('drag');el.setPointerCapture(e.pointerId);
|
|
385
|
+
function mv(ev){
|
|
386
|
+
var v = fromLeft ? ev.clientX : (innerWidth-ev.clientX);
|
|
387
|
+
v=Math.max(180,Math.min(520,v));
|
|
388
|
+
app.style.setProperty(varName, v+'px');
|
|
389
|
+
sessionStorage.setItem(varName==='--wl'?'maqWL':'maqWR', v+'px');
|
|
390
|
+
}
|
|
391
|
+
function up(){el.classList.remove('drag');removeEventListener('pointermove',mv);removeEventListener('pointerup',up);}
|
|
392
|
+
addEventListener('pointermove',mv);addEventListener('pointerup',up);
|
|
393
|
+
});
|
|
394
|
+
el.addEventListener('dblclick',function(){app.style.removeProperty(varName);sessionStorage.removeItem(varName==='--wl'?'maqWL':'maqWR');});
|
|
395
|
+
}
|
|
396
|
+
drag('rl','--wl',true); drag('rr','--wr',false);
|
|
397
|
+
})();
|
|
205
398
|
|
|
206
|
-
|
|
207
|
-
|
|
399
|
+
/* ---- mode picker (toggle-up popover) ---- */
|
|
400
|
+
function renderModePop(){
|
|
401
|
+
var pop=document.getElementById('modePop');pop.innerHTML='';
|
|
208
402
|
MODES.forEach(function(m){
|
|
209
|
-
var d=h('div','
|
|
210
|
-
d.
|
|
211
|
-
d.onclick=function(){
|
|
212
|
-
|
|
403
|
+
var d=h('div','mopt'+(m.id===mode?' sel':''),'<span class="ic">'+m.ic+'</span><div><h4>'+m.h+'</h4><p>'+m.p+'</p></div>');
|
|
404
|
+
d.setAttribute('role','menuitemradio');d.setAttribute('aria-checked',m.id===mode?'true':'false');
|
|
405
|
+
d.onclick=function(){mode=m.id;sessionStorage.setItem('maqMode',mode);renderModePop();syncSendFace();closePop();};
|
|
406
|
+
pop.appendChild(d);
|
|
213
407
|
});
|
|
214
408
|
}
|
|
409
|
+
function syncSendFace(){
|
|
410
|
+
var m=MODES.filter(function(x){return x.id===mode;})[0]||MODES[0];
|
|
411
|
+
document.getElementById('sendIcon').innerHTML=m.ic;
|
|
412
|
+
document.getElementById('sendLabel').textContent='Send · '+m.h;
|
|
413
|
+
}
|
|
414
|
+
function togglePop(e){e.stopPropagation();var p=document.getElementById('modePop'),t=document.getElementById('modeToggle');
|
|
415
|
+
var open=p.classList.toggle('open');t.classList.toggle('open',open);t.setAttribute('aria-expanded',open?'true':'false');}
|
|
416
|
+
function closePop(){var p=document.getElementById('modePop'),t=document.getElementById('modeToggle');p.classList.remove('open');t.classList.remove('open');t.setAttribute('aria-expanded','false');}
|
|
417
|
+
document.addEventListener('click',function(e){ if(!e.target.closest('.send-wrap'))closePop(); });
|
|
215
418
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
419
|
+
/* ---- timeline + orchestration viz ---- */
|
|
420
|
+
var PH=[{id:'scout',l:'Scout'},{id:'plan',l:'Plan'},{id:'execute',l:'Execute'},{id:'verify',l:'Verify'}];
|
|
421
|
+
function renderTimeline(events){
|
|
422
|
+
var done={},active=null,orchRounds=[],parallel=0,loopN=0,safe={};
|
|
219
423
|
events.forEach(function(e){
|
|
220
|
-
var p=e.data&&e.data.phase;
|
|
221
|
-
if(
|
|
222
|
-
if(/^
|
|
223
|
-
if(e.type==='phase.
|
|
224
|
-
if(e.type==='phase.done'){done[p]=true;
|
|
424
|
+
var p=e.data&&e.data.phase; if(!p)return;
|
|
425
|
+
if(/^parallel-round/.test(p)){ if(e.type==='phase.started'){parallel++;if(orchRounds.indexOf(p)<0)orchRounds.push(p);} return; }
|
|
426
|
+
if(/^loop-iteration/.test(p)){ if(e.type==='phase.started'){loopN++;if(orchRounds.indexOf(p)<0)orchRounds.push(p);} return; }
|
|
427
|
+
if(/^safe-/.test(p)){ if(e.type==='phase.done')safe[p.replace('safe-','')]=true; if(orchRounds.indexOf(p)<0)orchRounds.push(p); return; }
|
|
428
|
+
if(e.type==='phase.started')active=p; if(e.type==='phase.done'){done[p]=true;if(active===p)active=null;}
|
|
225
429
|
});
|
|
226
|
-
var
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if(
|
|
430
|
+
var tr=document.getElementById('track');tr.innerHTML='';
|
|
431
|
+
PH.forEach(function(ph,i){var st=done[ph.id]?'done':(active===ph.id?'active':'');var n=h('div','node'+(st?' '+st:''),'<span class="node-dot">'+I.check+'</span><span class="node-label">'+ph.l+'</span>');tr.appendChild(n);if(i<PH.length-1)tr.appendChild(h('div','node-line'));});
|
|
432
|
+
var sr=document.getElementById('subrail');
|
|
433
|
+
if(mode==='safe'&&orchRounds.length){
|
|
434
|
+
var stages=['split','merge','validate'];sr.innerHTML='<div class="sub-rail">'+stages.map(function(s){return '<span class="sub-chip'+(s==='merge'?' merge':'')+'">'+(safe[s]?'✓ ':'')+s+'</span>';}).join('')+'</div>';
|
|
435
|
+
} else if(parallel&&mode==='parallel'){ sr.innerHTML='<div class="sub-rail"><span class="sub-chip">parallel · round '+parallel+'</span></div>'; }
|
|
436
|
+
else if(loopN&&mode==='loop'){ sr.innerHTML='<div class="sub-rail"><span class="sub-chip">loop · iteration '+loopN+'</span></div>'; }
|
|
437
|
+
else if(orchRounds.length){ sr.innerHTML='<div class="sub-rail">'+orchRounds.slice(-4).map(function(r){return '<span class="sub-chip">'+r+'</span>';}).join('')+'</div>'; }
|
|
438
|
+
else sr.innerHTML='';
|
|
233
439
|
}
|
|
234
440
|
|
|
235
|
-
function
|
|
441
|
+
function evView(e){
|
|
236
442
|
switch(e.type){
|
|
237
|
-
case 'task.started':
|
|
238
|
-
case 'phase.started':
|
|
239
|
-
case 'phase.done':
|
|
240
|
-
case 'agent.event':
|
|
241
|
-
case 'agent.stdout':
|
|
242
|
-
case 'agent.stderr':
|
|
243
|
-
case 'tool.call':
|
|
244
|
-
case 'task.done':
|
|
245
|
-
case 'task.error':
|
|
246
|
-
case 'task.cancelled':
|
|
247
|
-
default:
|
|
443
|
+
case 'task.started':return [I.play,'c-accent',(e.data.goal||e.data.task||'')+(e.data.mode?' ['+e.data.mode+']':''),0];
|
|
444
|
+
case 'phase.started':return [I.chev,'c-accent',(e.data.phase||'')+' …',0];
|
|
445
|
+
case 'phase.done':return [I.dot,'c-dim',(e.data.phase||'')+(e.data.reason?' '+e.data.reason:''),0];
|
|
446
|
+
case 'agent.event':return [I.dot,'c-dim',e.data.note||JSON.stringify(e.data),0];
|
|
447
|
+
case 'agent.stdout':return [I.dot,'c-dim',e.data.text||'',0];
|
|
448
|
+
case 'agent.stderr':return [I.warn,'c-warn',e.data.text||'',1];
|
|
449
|
+
case 'tool.call':return [I.tool,'c-accent','tool: '+(e.data.tool||JSON.stringify(e.data.command||e.data.raw||{})),0];
|
|
450
|
+
case 'task.done':return [e.data.verified?I.verified:I.flag,e.data.verified?'c-ok':'c-warn','done · verified='+e.data.verified+(e.data.mode?' · '+e.data.mode:'')+(e.data.summary?' · '+e.data.summary:''),e.data.verified?0:1];
|
|
451
|
+
case 'task.error':return [I.x,'c-danger','error: '+(e.data.message||''),2];
|
|
452
|
+
case 'task.cancelled':return [I.x,'c-danger','cancelled',2];
|
|
453
|
+
default:return [I.circle,'c-dim',e.type,0];
|
|
248
454
|
}
|
|
249
455
|
}
|
|
250
456
|
function pushEvent(e){
|
|
251
|
-
var c=document.getElementById('console');
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
var ic=h('span','ic '+parts[1]); ic.innerHTML=parts[0];
|
|
256
|
-
var tx=h('span','tx '+parts[1]); tx.textContent=parts[2];
|
|
257
|
-
row.appendChild(ic); row.appendChild(tx); c.appendChild(row);
|
|
258
|
-
c.scrollTop=c.scrollHeight;
|
|
457
|
+
var c=document.getElementById('console');var f=c.firstElementChild;if(f&&f.classList&&f.classList.contains('emptywrap'))c.innerHTML='';
|
|
458
|
+
var p=evView(e);var card=h('div','ev'+(p[3]===2?' bg-danger':(p[3]===1?' bg-warn':'')));
|
|
459
|
+
card.innerHTML='<span class="ic '+p[1]+'">'+p[0]+'</span><span class="tx '+p[1]+'"></span><span class="t">'+fmtT(e.ts)+'</span>';
|
|
460
|
+
card.querySelector('.tx').textContent=p[2];c.appendChild(card);c.scrollTop=c.scrollHeight;
|
|
259
461
|
}
|
|
462
|
+
function clearConsole(){document.getElementById('console').innerHTML='<div class="emptywrap">'+empty('box','Pick a mode, describe a goal, and Send.','The live Scout→Plan→Execute→Verify stream renders here.')+'</div>';}
|
|
260
463
|
|
|
261
|
-
var evList=[];
|
|
262
464
|
async function streamEvents(id){
|
|
263
|
-
evList=[];
|
|
264
|
-
document.getElementById('console').innerHTML='';
|
|
465
|
+
evList=[];document.getElementById('console').innerHTML='';renderTimeline([]);
|
|
265
466
|
var res=await fetch(base+'/v1/sessions/'+id+'/events',{headers:{authorization:'Bearer '+token}});
|
|
266
|
-
if(!res.ok||!res.body){
|
|
267
|
-
var
|
|
268
|
-
while(true){
|
|
269
|
-
var
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
var lines=blocks[i].split('\\n');
|
|
274
|
-
for(var j=0;j<lines.length;j++){
|
|
275
|
-
var ln=lines[j];
|
|
276
|
-
if(ln.indexOf('data:')===0){
|
|
277
|
-
var payload=ln.slice(5).trim(); if(!payload)continue;
|
|
278
|
-
try{ var ev=JSON.parse(payload); if(ev.type==='stream.end'){continue;} evList.push(ev); pushEvent(ev); renderChips(evList); }catch(err){}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if(id!==activeId)break;
|
|
283
|
-
}
|
|
467
|
+
if(!res.ok||!res.body){pushEvent({type:'task.error',ts:new Date().toISOString(),data:{message:'stream '+res.status}});return;}
|
|
468
|
+
var rd=res.body.getReader(),dec=new TextDecoder(),buf='';
|
|
469
|
+
while(true){var r=await rd.read();if(r.done)break;buf+=dec.decode(r.value,{stream:true});
|
|
470
|
+
var bl=buf.split('\n\n');buf=bl.pop();
|
|
471
|
+
for(var i=0;i<bl.length;i++){var ls=bl[i].split('\n');for(var j=0;j<ls.length;j++){var ln=ls[j];
|
|
472
|
+
if(ln.indexOf('data:')===0){var pl=ln.slice(5).trim();if(!pl)continue;try{var ev=JSON.parse(pl);if(ev.type==='stream.end')continue;evList.push(ev);pushEvent(ev);renderTimeline(evList);}catch(x){}}}}
|
|
473
|
+
if(id!==activeId)break;}
|
|
284
474
|
refreshSessions();
|
|
285
475
|
}
|
|
286
476
|
|
|
287
477
|
async function startTask(){
|
|
288
|
-
var
|
|
289
|
-
var btn=document.getElementById('send');
|
|
290
|
-
var body={task:goal,
|
|
291
|
-
maxConcurrency:Number(document.getElementById('conc').value)||4};
|
|
478
|
+
var g=document.getElementById('goal');var goal=g.value.trim();if(!goal)return;
|
|
479
|
+
var btn=document.getElementById('send');btn.disabled=true;
|
|
480
|
+
var body={task:goal,target:document.getElementById('target').value,dryRun:document.getElementById('dry').checked,maxConcurrency:Number(document.getElementById('conc').value)||4};
|
|
292
481
|
if(mode)body.mode=mode;
|
|
293
|
-
try{
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
await refreshSessions();
|
|
299
|
-
streamEvents(s.id);
|
|
300
|
-
}catch(e){ pushEvent({type:'task.error',data:{message:String(e)}}); }
|
|
301
|
-
finally{ btn.disabled=false; }
|
|
482
|
+
try{var res=await api('/v1/sessions',{method:'POST',body:JSON.stringify(body)});var s=await res.json();
|
|
483
|
+
if(!res.ok){pushEvent({type:'task.error',ts:new Date().toISOString(),data:{message:s.error||('HTTP '+res.status)}});return;}
|
|
484
|
+
activeId=s.id;g.value='';await refreshSessions();streamEvents(s.id);
|
|
485
|
+
}catch(e){pushEvent({type:'task.error',ts:new Date().toISOString(),data:{message:String(e)}});}
|
|
486
|
+
finally{btn.disabled=false;}
|
|
302
487
|
}
|
|
303
488
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
var meta=h('div','s');
|
|
315
|
-
meta.innerHTML='<span class="badge b-'+s.status+'">'+s.status+'</span> '+
|
|
316
|
-
(s.mode?('· '+s.mode+' '):'')+'· '+(s.target||'auto')+' · '+s.eventCount+' ev'+
|
|
317
|
-
(s.verified===true?' · ✓':(s.verified===false?' · ✗':''));
|
|
318
|
-
it.appendChild(t); it.appendChild(meta);
|
|
319
|
-
it.onclick=function(){ activeId=s.id; refreshSessions(); openPreview(s.id); streamEvents(s.id); };
|
|
320
|
-
box.appendChild(it);
|
|
321
|
-
});
|
|
322
|
-
}catch(e){ document.getElementById('dot').className='dot'; }
|
|
489
|
+
/* ---- sessions (history grouped by day, timestamps, click-to-restore) ---- */
|
|
490
|
+
var sLoaded=false;
|
|
491
|
+
function groupKey(ts){try{var d=new Date(ts);var t=new Date();if(d.toDateString()===t.toDateString())return 'Today';var y=new Date(t-864e5);if(d.toDateString()===y.toDateString())return 'Yesterday';return d.toLocaleDateString([], {month:'short',day:'numeric'});}catch(e){return 'Earlier';}}
|
|
492
|
+
function sessionRow(s){
|
|
493
|
+
var it=h('div','row'+(s.id===activeId?' active':''));it.setAttribute('tabindex','0');it.setAttribute('role','button');it.setAttribute('aria-label','Open session '+s.task);
|
|
494
|
+
var vm=s.verified===true?' · ✓':(s.verified===false?' · ✗':'');
|
|
495
|
+
it.innerHTML='<div class="row-t">'+esc(s.task)+'</div><div class="row-m"><span class="tag '+s.status+'">'+s.status+'</span>'+(s.mode?'<span>'+s.mode+'</span>':'')+'<span>'+(s.target||'auto')+'</span><span>'+ago(s.updatedAt||s.createdAt)+'</span>'+vm+'</div>';
|
|
496
|
+
it.onclick=function(){activeId=s.id;refreshSessions();openPreview(s.id);streamEvents(s.id);if(innerWidth<=900)toggleSide();};
|
|
497
|
+
it.onkeydown=function(ev){if(ev.key==='Enter')it.click();};
|
|
498
|
+
return it;
|
|
323
499
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
var pre=h('pre'); pre.textContent=JSON.stringify({id:d.id,task:d.task,status:d.status,mode:d.mode,verified:d.verified,error:d.error},null,2);
|
|
332
|
-
box.appendChild(pre);
|
|
333
|
-
}catch(e){ box.textContent=String(e); }
|
|
500
|
+
async function refreshSessions(){
|
|
501
|
+
var box=document.getElementById('sessions');if(!sLoaded)box.innerHTML=skel(3);
|
|
502
|
+
try{var d=await (await api('/v1/sessions')).json();setLive(true);var list=(d.sessions||[]);sLoaded=true;box.innerHTML='';
|
|
503
|
+
if(!list.length){box.innerHTML=empty('box','No sessions yet','Send a goal to start one.');return;}
|
|
504
|
+
var groups={},order=[];list.slice().reverse().forEach(function(s){var k=groupKey(s.updatedAt||s.createdAt);if(!groups[k]){groups[k]=[];order.push(k);}groups[k].push(s);});
|
|
505
|
+
order.forEach(function(k){box.appendChild(h('div','grp-label',k));groups[k].forEach(function(s){box.appendChild(sessionRow(s));});});
|
|
506
|
+
}catch(e){setLive(false);if(!sLoaded)box.innerHTML=empty('warn','Can\'t reach the daemon','');}
|
|
334
507
|
}
|
|
335
|
-
function togglePreview(){ document.getElementById('main').classList.toggle('preview'); }
|
|
336
508
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
509
|
+
/* ---- universal preview ---- */
|
|
510
|
+
function detectType(text){var t=(text||'').trim();if(!t)return 'empty';if((t[0]==='{'||t[0]==='[')){try{JSON.parse(t);return 'json';}catch(e){}}if(/^<!doctype|^<html|^<div|^<body/i.test(t))return 'html';if(/^#\s|\n#\s|\*\*|^- |\n- /.test(t))return 'markdown';return 'code';}
|
|
511
|
+
function jsonTree(v,key){
|
|
512
|
+
var wrap=h('div','jt open');var isObj=v&&typeof v==='object';
|
|
513
|
+
if(isObj){var isArr=Array.isArray(v);var keys=isArr?v.map(function(_,i){return i;}):Object.keys(v);
|
|
514
|
+
var head=h('div',null,'<span class="tog">▾</span> '+(key!=null?'<span class="k">'+esc(key)+'</span>: ':'')+(isArr?'[':'{')+'<span class="c-dim"> '+keys.length+' </span>'+(isArr?']':'}'));
|
|
515
|
+
head.querySelector('.tog').onclick=function(){wrap.classList.toggle('open');this.textContent=wrap.classList.contains('open')?'▾':'▸';};
|
|
516
|
+
wrap.appendChild(head);var col=h('div','col nest');keys.forEach(function(k){col.appendChild(jsonTree(v[k],k));});wrap.appendChild(col);
|
|
517
|
+
} else {
|
|
518
|
+
var cls=typeof v==='number'?'n':(typeof v==='boolean'?'b':'s');var val=typeof v==='string'?'"'+v+'"':String(v);
|
|
519
|
+
wrap.innerHTML=(key!=null?'<span class="k">'+esc(key)+'</span>: ':'')+'<span class="'+cls+'">'+esc(val)+'</span>';wrap.className='jt';
|
|
520
|
+
}
|
|
521
|
+
return wrap;
|
|
348
522
|
}
|
|
349
|
-
function
|
|
350
|
-
var
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
523
|
+
function mdToHtml(t){
|
|
524
|
+
var FE=String.fromCharCode(96,96,96);var parts=t.split(FE);var out='';
|
|
525
|
+
for(var i=0;i<parts.length;i++){ if(i%2){out+='<pre>'+esc(parts[i].replace(/^\w*\n/,''))+'</pre>';continue;}
|
|
526
|
+
var s=esc(parts[i]);
|
|
527
|
+
s=s.replace(/^### (.*)$/gm,'<h3>$1</h3>').replace(/^## (.*)$/gm,'<h2>$1</h2>').replace(/^# (.*)$/gm,'<h1>$1</h1>');
|
|
528
|
+
s=s.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>').replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener">$1</a>');
|
|
529
|
+
s=s.replace(/^- (.*)$/gm,'<li>$1</li>').replace(/(<li>[\s\S]*?<\/li>)/g,'<ul>$1</ul>');
|
|
530
|
+
var C=String.fromCharCode(96);s=s.replace(new RegExp(C+'([^'+C+']+)'+C,'g'),'<code>$1</code>');
|
|
531
|
+
s=s.replace(/\n{2,}/g,'</p><p>');out+='<p>'+s+'</p>';
|
|
532
|
+
}
|
|
533
|
+
return out;
|
|
357
534
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
var
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
card.onclick=function(){ runFeature(c); };
|
|
369
|
-
grid.appendChild(card);
|
|
370
|
-
});
|
|
371
|
-
}catch(e){ grid.innerHTML='<div class="empty">'+e+'</div>'; }
|
|
535
|
+
function renderPreview(content,forceType){
|
|
536
|
+
var box=document.getElementById('prevBody');var ty=forceType||detectType(content);document.getElementById('prevType').textContent=ty;
|
|
537
|
+
box.innerHTML='';
|
|
538
|
+
if(ty==='json'){try{var v=JSON.parse(content);box.appendChild(jsonTree(v));return;}catch(e){ty='code';}}
|
|
539
|
+
if(ty==='markdown'){var m=h('div','md');m.innerHTML=mdToHtml(content);box.appendChild(m);return;}
|
|
540
|
+
if(ty==='html'){var f=document.createElement('iframe');f.className='htmlprev';f.setAttribute('sandbox','');f.srcdoc=content;box.appendChild(f);return;}
|
|
541
|
+
if(ty==='image'){var img=document.createElement('img');img.src=content;img.style.maxWidth='100%';box.appendChild(img);return;}
|
|
542
|
+
if(ty==='empty'){box.innerHTML=empty('box','Nothing to preview','Select a session or run a feature.');return;}
|
|
543
|
+
var lines=String(content).split('\n');var pre=h('pre','code');var g=h('div','gutter');var cl=h('div','codelines');
|
|
544
|
+
g.textContent=lines.map(function(_,i){return i+1;}).join('\n');cl.textContent=content;pre.appendChild(g);pre.appendChild(cl);box.appendChild(pre);
|
|
372
545
|
}
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
var d=await (await api('/v1/security')).json();
|
|
380
|
-
var r=d.rules, evs=(d.events||[]);
|
|
381
|
-
var html='';
|
|
382
|
-
html+='<div style="margin-bottom:14px">';
|
|
383
|
-
html+='<span class="pill2 on">permission posture: '+r.permissionMode+'</span>';
|
|
384
|
-
html+='<span class="pill2 on">secret env scrubbing: on</span>';
|
|
385
|
-
html+='<span class="pill2 on">prompt-injection scanning: on</span>';
|
|
386
|
-
html+='</div>';
|
|
387
|
-
|
|
388
|
-
html+=sec('Protected paths (never writable — cannot be overridden by config)', r.protectedPaths.length);
|
|
389
|
-
html+='<div class="seclist">'+r.protectedPaths.map(function(p){return '<div class="secitem">'+esc(p)+'</div>';}).join('')+'</div>';
|
|
390
|
-
html+='<div class="secnote">Enforced in sandbox.ts checkWrite(), unconditionally, before any tier logic — a compromised agent cannot argue past this with a clever prompt.</div>';
|
|
391
|
-
|
|
392
|
-
html+=sec('Protected file patterns (matched by name, anywhere in the project)', r.protectedNamePatterns.length);
|
|
393
|
-
html+='<div class="seclist">'+r.protectedNamePatterns.map(function(p){return '<div class="secitem">'+esc(p)+'</div>';}).join('')+'</div>';
|
|
394
|
-
|
|
395
|
-
if(r.extraProtectedPaths && r.extraProtectedPaths.length){
|
|
396
|
-
html+=sec('Project-added protected paths', r.extraProtectedPaths.length);
|
|
397
|
-
html+='<div class="seclist">'+r.extraProtectedPaths.map(function(p){return '<div class="secitem">'+esc(p)+'</div>';}).join('')+'</div>';
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
html+=sec('Network egress allowlist (default-deny everything else)', r.netAllowlist.length);
|
|
401
|
-
html+='<div class="seclist">'+r.netAllowlist.map(function(p){return '<div class="secitem">'+esc(p)+'</div>';}).join('')+'</div>';
|
|
402
|
-
html+='<div class="secnote">Enforced in tools.ts http_get and available to any outbound call site via security.ts checkEgress(). Not just a suggestion in a prompt.</div>';
|
|
403
|
-
|
|
404
|
-
html+=sec('Prompt-injection scanning', r.promptInjectionScanning.length);
|
|
405
|
-
html+='<div class="seclist">'+r.promptInjectionScanning.map(function(p){return '<div class="secitem">'+esc(p)+'</div>';}).join('')+'</div>';
|
|
406
|
-
html+='<div class="secnote">README, manifest, git commits, AGENTS.md and skill files are scanned for override/exfiltration/jailbreak patterns before they reach a model. Findings are surfaced loudly, never silently dropped.</div>';
|
|
407
|
-
|
|
408
|
-
html+=sec('Recent findings (this session)', evs.length);
|
|
409
|
-
if(!evs.length){ html+='<div class="secnote">None recorded yet — findings appear here as tasks run.</div>'; }
|
|
410
|
-
else {
|
|
411
|
-
html+='<div>'+evs.slice().reverse().map(function(e){
|
|
412
|
-
var cls=e.severity==='high'?'e-red':'e-warn';
|
|
413
|
-
return '<div class="ev"><span class="ic '+cls+'">⚠</span><span class="tx '+cls+'">'+esc(e.kind)+': '+esc(e.detail)+'</span></div>';
|
|
414
|
-
}).join('')+'</div>';
|
|
415
|
-
}
|
|
416
|
-
}catch(e){ box.innerHTML='<div class="empty">'+e+'</div>'; return; }
|
|
417
|
-
box.innerHTML = html;
|
|
546
|
+
function openPreview(id){
|
|
547
|
+
document.getElementById('app').classList.remove('no-prev');document.getElementById('app').classList.add('prev-sheet');
|
|
548
|
+
var box=document.getElementById('prevBody');box.innerHTML=skel(5);document.getElementById('prevType').textContent='';
|
|
549
|
+
api('/v1/sessions/'+id).then(function(r){return r.json();}).then(function(d){
|
|
550
|
+
renderPreview(JSON.stringify({id:d.id,task:d.task,status:d.status,mode:d.mode,verified:d.verified,error:d.error,events:(d.events||[]).length},null,2),'json');
|
|
551
|
+
}).catch(function(e){box.innerHTML=empty('warn','Could not load session',String(e));});
|
|
418
552
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
function
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
553
|
+
function togglePreview(){var a=document.getElementById('app');a.classList.toggle('no-prev');a.classList.toggle('prev-sheet');
|
|
554
|
+
if(!a.classList.contains('no-prev')&&!document.getElementById('prevBody').innerHTML.trim())renderPreview('','empty');}
|
|
555
|
+
|
|
556
|
+
/* ---- feature explorer / exec ---- */
|
|
557
|
+
async function feat(kind){
|
|
558
|
+
document.getElementById('app').classList.remove('no-prev');document.getElementById('app').classList.add('prev-sheet');
|
|
559
|
+
var box=document.getElementById('prevBody');box.innerHTML=skel(5);document.getElementById('prevType').textContent='';
|
|
560
|
+
try{var out;
|
|
561
|
+
if(kind==='agents'){out=await (await api('/v1/agents')).json();renderAgents(out.agents||[]);renderPreview(JSON.stringify(out,null,2),'json');return;}
|
|
562
|
+
if(kind==='connectivity'){out=await (await api('/v1/connectivity')).json();renderPreview(JSON.stringify(out,null,2),'json');return;}
|
|
563
|
+
out=await (await api('/v1/exec',{method:'POST',body:JSON.stringify({argv:[kind]})})).json();
|
|
564
|
+
var txt=(out.stdout!=null?out.stdout:'')+(out.stderr?('\n'+out.stderr):'');renderPreview(txt||JSON.stringify(out,null,2));
|
|
565
|
+
}catch(e){box.innerHTML=empty('warn','Could not run '+kind,String(e));}
|
|
432
566
|
}
|
|
567
|
+
function renderAgents(agents){var box=document.getElementById('agents');if(!agents.length){box.innerHTML=empty('box','No agents','Log in to an AI CLI.');return;}box.innerHTML='';
|
|
568
|
+
agents.forEach(function(a){var st=a.installed?(a.authenticated?'authenticated':'logged out'):'not found';var tg=a.installed?(a.authenticated?'done':'paused'):'cancelled';
|
|
569
|
+
box.appendChild(h('div','row','<div class="row-t">'+esc(a.name)+'</div><div class="row-m"><span class="tag '+tg+'">'+st+'</span></div>'));});}
|
|
433
570
|
|
|
571
|
+
async function openFeatures(){document.getElementById('features').classList.add('show');var g=document.getElementById('featureGrid');g.innerHTML=skel(6);
|
|
572
|
+
try{var cat=await (await api('/v1/commands')).json();var cmds=(cat.maq||[]);g.innerHTML='';
|
|
573
|
+
cmds.forEach(function(c){var card=h('button','fcard','<div class="eyebrow">'+esc(c.category)+'</div><h4>'+esc(c.name)+'</h4><p>'+esc(c.summary)+'</p>');card.onclick=function(){runFeature(c);};g.appendChild(card);});
|
|
574
|
+
}catch(e){g.innerHTML=empty('warn','Could not load features',String(e));}}
|
|
575
|
+
function closeFeatures(){document.getElementById('features').classList.remove('show');}
|
|
576
|
+
function runFeature(c){closeFeatures();if(c.needsInput==='task'||c.needsInput==='query'){var g=document.getElementById('goal');g.focus();if(c.name==='orchestrate'){mode='parallel';renderModePop();syncSendFace();}g.placeholder='['+c.name+'] '+c.summary;}else feat(c.name);}
|
|
577
|
+
|
|
578
|
+
async function openSecurity(){document.getElementById('security').classList.add('show');var box=document.getElementById('securityBody');box.innerHTML=skel(8);
|
|
579
|
+
try{var d=await (await api('/v1/security')).json();var r=d.rules,evs=(d.events||[]);var html='';
|
|
580
|
+
html+='<div class="posture"><span class="pill">'+I.check+' posture: '+r.permissionMode+'</span><span class="pill">'+I.check+' secret scrubbing: on</span><span class="pill">'+I.check+' injection scanning: on</span></div>';
|
|
581
|
+
html+=secBlk('Protected paths','never writable — cannot be overridden by config',r.protectedPaths,'Enforced in sandbox.ts checkWrite(), unconditionally, before any tier logic.');
|
|
582
|
+
html+=secBlk('Protected file patterns','matched by name anywhere',r.protectedNamePatterns,'');
|
|
583
|
+
if(r.extraProtectedPaths&&r.extraProtectedPaths.length)html+=secBlk('Project-added protected paths','',r.extraProtectedPaths,'');
|
|
584
|
+
html+=secBlk('Network egress allowlist','default-deny everything else',r.netAllowlist,'Enforced in tools.ts http_get via security.ts checkEgress().');
|
|
585
|
+
html+=secBlk('Prompt-injection scanning','',r.promptInjectionScanning,'README, manifest, git commits, AGENTS.md and skill files scanned before reaching a model.');
|
|
586
|
+
html+='<div class="sec-blk"><div class="sec-h"><h4>Recent findings</h4><span class="cbadge'+(evs.length?' alert':'')+'">'+evs.length+'</span></div>';
|
|
587
|
+
html+=evs.length?('<div>'+evs.slice().reverse().map(function(e){var cl=e.severity==='high'?'c-danger':'c-warn';return '<div class="ev"><span class="ic '+cl+'">'+I.warn+'</span><span class="tx '+cl+'">'+esc(e.kind)+': '+esc(e.detail)+'</span></div>';}).join('')+'</div>'):'<div class="sec-note">None recorded yet.</div>';
|
|
588
|
+
html+='</div>';box.innerHTML=html;
|
|
589
|
+
}catch(e){box.innerHTML=empty('warn','Could not load security rules',String(e));}}
|
|
590
|
+
function secBlk(t,note,items,foot){var html='<div class="sec-blk"><div class="sec-h"><h4>'+t+'</h4><span class="cbadge">'+(items?items.length:0)+'</span>'+(note?'<span class="sec-note">'+note+'</span>':'')+'</div>';
|
|
591
|
+
html+='<div class="sec-list">'+(items||[]).map(function(p){return '<div class="sec-i">'+esc(p)+'</div>';}).join('')+'</div>';if(foot)html+='<div class="sec-note">'+foot+'</div>';return html+'</div>';}
|
|
592
|
+
function closeSecurity(){document.getElementById('security').classList.remove('show');}
|
|
593
|
+
|
|
594
|
+
/* ---- request box ---- */
|
|
434
595
|
async function loadRequests(){
|
|
435
|
-
try{
|
|
436
|
-
var
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
box.innerHTML='';
|
|
441
|
-
pend.forEach(function(r){
|
|
442
|
-
var it=h('div','req '+r.risk);
|
|
443
|
-
var a=h('div','a'); a.textContent=r.action+' — '+(r.detail||'');
|
|
444
|
-
var reason=h('div','r'); reason.textContent=r.risk+' · '+(r.reason||'');
|
|
445
|
-
var btns=h('div','btns');
|
|
446
|
-
var ok=h('button','ok-btn','Approve'); ok.onclick=function(){ decideReq(r.id,'approve'); };
|
|
447
|
-
var no=h('button','no-btn','Deny'); no.onclick=function(){ decideReq(r.id,'deny'); };
|
|
448
|
-
btns.appendChild(ok); btns.appendChild(no);
|
|
449
|
-
it.appendChild(a); it.appendChild(reason); it.appendChild(btns); box.appendChild(it);
|
|
450
|
-
});
|
|
596
|
+
try{var d=await (await api('/v1/requests')).json();var box=document.getElementById('requests');var pend=(d.pending||[]);
|
|
597
|
+
var b=document.getElementById('reqCount');b.textContent=String(pend.length);b.className='cbadge'+(pend.length?' alert':'');
|
|
598
|
+
if(!pend.length){box.innerHTML=empty('box','No pending requests','');return;}box.innerHTML='';
|
|
599
|
+
pend.forEach(function(r){var it=h('div','req '+r.risk,'<div class="a">'+esc(r.action)+' — '+esc(r.detail||'')+'</div><div class="r">'+esc(r.risk)+' · '+esc(r.reason||'')+'</div><div class="btns"><button class="bs ok-b">Approve</button><button class="bs no-b">Deny</button></div>');
|
|
600
|
+
it.querySelector('.ok-b').onclick=function(){decideReq(r.id,'approve');};it.querySelector('.no-b').onclick=function(){decideReq(r.id,'deny');};box.appendChild(it);});
|
|
451
601
|
}catch(e){}
|
|
452
602
|
}
|
|
453
|
-
async function decideReq(id,action){
|
|
454
|
-
try{ await api('/v1/requests/'+id,{method:'POST',body:JSON.stringify({action:action})}); loadRequests(); }catch(e){}
|
|
455
|
-
}
|
|
603
|
+
async function decideReq(id,a){try{await api('/v1/requests/'+id,{method:'POST',body:JSON.stringify({action:a})});loadRequests();}catch(e){}}
|
|
456
604
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
document.getElementById('
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
}
|
|
605
|
+
/* ---- command palette ---- */
|
|
606
|
+
var cmdkItems=[],cmdkSel=0;
|
|
607
|
+
async function openPalette(){var bd=document.getElementById('cmdk');bd.classList.add('show');var inp=document.getElementById('cmdkInput');inp.value='';inp.focus();
|
|
608
|
+
cmdkItems=[];try{var cat=await (await api('/v1/commands')).json();(cat.maq||[]).forEach(function(c){cmdkItems.push({t:c.name,s:c.summary,cat:c.category,run:function(){closePalette();runFeature(c);}});});}catch(e){}
|
|
609
|
+
try{var d=await (await api('/v1/sessions')).json();(d.sessions||[]).slice().reverse().slice(0,8).forEach(function(s){cmdkItems.push({t:s.task,s:s.status+' · '+(s.mode||'single'),cat:'session',run:function(){closePalette();activeId=s.id;refreshSessions();openPreview(s.id);streamEvents(s.id);}});});}catch(e){}
|
|
610
|
+
paletteFilter('');}
|
|
611
|
+
function closePalette(){document.getElementById('cmdk').classList.remove('show');}
|
|
612
|
+
function paletteFilter(q){q=q.toLowerCase();var list=document.getElementById('cmdkList');var m=cmdkItems.filter(function(it){return (it.t+' '+it.s+' '+it.cat).toLowerCase().indexOf(q)>=0;});cmdkSel=0;
|
|
613
|
+
if(!m.length){list.innerHTML='<div class="empty" style="padding:26px">No matches</div>';return;}list.innerHTML='';
|
|
614
|
+
m.forEach(function(it,i){var el=h('div','cmdk-it'+(i===0?' sel':''),'<span class="ic">'+I.chev+'</span><div class="m"><div class="tt">'+esc(it.t)+'</div><div class="ss">'+esc(it.s)+'</div></div><span class="cat">'+esc(it.cat)+'</span>');el.onclick=it.run;el.dataset.i=i;list.appendChild(el);});
|
|
615
|
+
list._m=m;}
|
|
616
|
+
document.getElementById('cmdkInput').addEventListener('input',function(e){paletteFilter(e.target.value);});
|
|
617
|
+
document.getElementById('cmdkInput').addEventListener('keydown',function(e){var list=document.getElementById('cmdkList');var m=list._m||[];
|
|
618
|
+
if(e.key==='ArrowDown'){e.preventDefault();cmdkSel=Math.min(m.length-1,cmdkSel+1);}
|
|
619
|
+
else if(e.key==='ArrowUp'){e.preventDefault();cmdkSel=Math.max(0,cmdkSel-1);}
|
|
620
|
+
else if(e.key==='Enter'){if(m[cmdkSel])m[cmdkSel].run();return;}
|
|
621
|
+
else return;
|
|
622
|
+
[].forEach.call(list.children,function(c,i){c.classList.toggle('sel',i===cmdkSel);});});
|
|
623
|
+
|
|
624
|
+
/* ---- init ---- */
|
|
625
|
+
clearConsole();renderModePop();syncSendFace();renderTimeline([]);refreshSessions();feat('agents');loadRequests();
|
|
626
|
+
document.getElementById('app').classList.add('no-prev');
|
|
627
|
+
setInterval(refreshSessions,5000);setInterval(loadRequests,3000);
|
|
628
|
+
document.getElementById('goal').addEventListener('keydown',function(e){if((e.metaKey||e.ctrlKey)&&e.key==='Enter')startTask();});
|
|
629
|
+
document.addEventListener('keydown',function(e){
|
|
630
|
+
if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k'){e.preventDefault();openPalette();}
|
|
631
|
+
if(e.key==='Escape'){closeFeatures();closeSecurity();closePalette();closePop();}
|
|
632
|
+
});
|
|
633
|
+
`;
|