maqcli 0.2.0 → 0.4.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/capabilities.d.ts +57 -0
- package/dist/core/capabilities.js +106 -0
- package/dist/core/command-catalog.js +6 -0
- package/dist/core/config-store.d.ts +8 -0
- package/dist/core/config-store.js +4 -0
- package/dist/core/init-wizard.js +7 -5
- package/dist/core/launcher.d.ts +71 -0
- package/dist/core/launcher.js +340 -0
- package/dist/core/onboarding.d.ts +76 -0
- package/dist/core/onboarding.js +88 -0
- package/dist/core/orchestrator.d.ts +85 -0
- package/dist/core/orchestrator.js +220 -0
- package/dist/core/providers-catalog.d.ts +67 -0
- package/dist/core/providers-catalog.js +188 -0
- package/dist/core/session.d.ts +10 -0
- package/dist/core/session.js +47 -23
- package/dist/index.js +62 -1
- package/dist/server/daemon.js +13 -1
- package/dist/server/relay-bridge.js +4 -0
- package/dist/server/webui.d.ts +19 -0
- package/dist/server/webui.js +319 -0
- package/package.json +1 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* webui.ts — the self-contained "god-level" control UI the daemon serves at
|
|
3
|
+
* `/app` (and `/`). Zero build step, zero dependencies: one HTML document with
|
|
4
|
+
* inline CSS + vanilla JS. It renders the SAME normalized event stream the
|
|
5
|
+
* mobile app consumes, so there is no second source of truth.
|
|
6
|
+
*
|
|
7
|
+
* Layout (Cursor-style, megalodon theme — deep black + electric blue + white):
|
|
8
|
+
* ┌ left ────────────┬ center ───────────────────────┬ right (collapsible) ┐
|
|
9
|
+
* │ sessions/agents/ │ goal input + mode toggle │ preview: session │
|
|
10
|
+
* │ history │ (parallel|loop|safe) + send │ detail / result │
|
|
11
|
+
* │ │ phase chips + live SSE console │ JSON │
|
|
12
|
+
* └──────────────────┴────────────────────────────────┴──────────────────────┘
|
|
13
|
+
* A feature switcher (top bar) runs detect / doctor / connectivity / models.
|
|
14
|
+
*
|
|
15
|
+
* Auth: the daemon requires a Bearer token for /v1/* . The page reads it from
|
|
16
|
+
* ?token=… or a prompt, keeps it in memory only, and streams SSE via fetch +
|
|
17
|
+
* ReadableStream (so the token rides in the Authorization header, never the URL).
|
|
18
|
+
*/
|
|
19
|
+
export function webuiHtml(version) {
|
|
20
|
+
// NB: the client script uses only single/double quotes and string
|
|
21
|
+
// concatenation — no backticks / ${} — so it lives safely inside this
|
|
22
|
+
// template literal.
|
|
23
|
+
return `<!doctype html>
|
|
24
|
+
<html lang="en"><head>
|
|
25
|
+
<meta charset="utf-8">
|
|
26
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
27
|
+
<title>MAQ · megalodon</title>
|
|
28
|
+
<style>
|
|
29
|
+
:root{
|
|
30
|
+
--bg:#04060c; --bg2:#080c16; --panel:#0b1120; --panel2:#0e1526; --edge:#182339;
|
|
31
|
+
--ink:#eaf1ff; --mut:#8695b3; --blue:#2f81f7; --blue2:#5aa2ff; --white:#ffffff;
|
|
32
|
+
--red:#ff4d5e; --ok:#3ad29f; --warn:#f5b44a;
|
|
33
|
+
}
|
|
34
|
+
*{box-sizing:border-box} html,body{height:100%}
|
|
35
|
+
body{margin:0;background:
|
|
36
|
+
radial-gradient(1200px 500px at 70% -10%, #0b1c38 0%, transparent 60%),
|
|
37
|
+
radial-gradient(900px 500px at 0% 110%, #0a1730 0%, transparent 55%), var(--bg);
|
|
38
|
+
color:var(--ink); font:14px/1.5 ui-sans-serif,-apple-system,Segoe UI,Roboto,sans-serif}
|
|
39
|
+
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
|
|
40
|
+
header{display:flex;align-items:center;gap:14px;padding:10px 16px;border-bottom:1px solid var(--edge);
|
|
41
|
+
background:linear-gradient(180deg,#0a1224,#070b15)}
|
|
42
|
+
.brand{font-weight:800;letter-spacing:3px;font-size:16px}
|
|
43
|
+
.brand .fin{color:var(--red)} .brand .m{color:var(--blue2)}
|
|
44
|
+
.dot{width:9px;height:9px;border-radius:50%;background:var(--mut);box-shadow:0 0 0 3px #ffffff10}
|
|
45
|
+
.dot.on{background:var(--ok);box-shadow:0 0 10px var(--ok)}
|
|
46
|
+
.grow{flex:1}
|
|
47
|
+
.switch{display:flex;gap:6px;flex-wrap:wrap}
|
|
48
|
+
.switch button, .ghost{background:var(--panel2);color:var(--mut);border:1px solid var(--edge);
|
|
49
|
+
border-radius:8px;padding:6px 10px;cursor:pointer;font-size:12px}
|
|
50
|
+
.switch button:hover,.ghost:hover{color:var(--ink);border-color:var(--blue)}
|
|
51
|
+
main{display:grid;grid-template-columns:250px 1fr 0px;height:calc(100vh - 53px);transition:grid-template-columns .18s}
|
|
52
|
+
main.preview{grid-template-columns:250px 1fr 360px}
|
|
53
|
+
.col{overflow:auto;min-width:0}
|
|
54
|
+
.left{border-right:1px solid var(--edge);background:var(--bg2)}
|
|
55
|
+
.right{border-left:1px solid var(--edge);background:var(--bg2)}
|
|
56
|
+
.sec{padding:10px 12px;border-bottom:1px solid var(--edge);color:var(--mut);
|
|
57
|
+
text-transform:uppercase;font-size:10px;letter-spacing:1.5px}
|
|
58
|
+
.item{padding:9px 12px;border-bottom:1px solid #0f1626;cursor:pointer}
|
|
59
|
+
.item:hover{background:#0f1830}
|
|
60
|
+
.item.active{background:#101c38;box-shadow:inset 3px 0 0 var(--blue)}
|
|
61
|
+
.item .t{color:var(--ink);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
62
|
+
.item .s{color:var(--mut);font-size:11px;margin-top:2px}
|
|
63
|
+
.badge{display:inline-block;padding:1px 7px;border-radius:999px;border:1px solid var(--edge);font-size:10px}
|
|
64
|
+
.b-running{color:var(--blue2);border-color:var(--blue)} .b-done{color:var(--ok);border-color:var(--ok)}
|
|
65
|
+
.b-error,.b-cancelled{color:var(--red);border-color:var(--red)} .b-paused{color:var(--warn);border-color:var(--warn)}
|
|
66
|
+
.center{display:flex;flex-direction:column}
|
|
67
|
+
.composer{padding:14px 16px;border-bottom:1px solid var(--edge)}
|
|
68
|
+
.modes{display:flex;gap:8px;margin-bottom:10px}
|
|
69
|
+
.mode{flex:1;background:var(--panel);border:1px solid var(--edge);border-radius:10px;padding:9px 10px;cursor:pointer}
|
|
70
|
+
.mode.sel{border-color:var(--blue);background:#0f1c3a;box-shadow:0 0 0 1px var(--blue) inset}
|
|
71
|
+
.mode h4{margin:0;font-size:13px;color:var(--ink)} .mode p{margin:2px 0 0;font-size:11px;color:var(--mut)}
|
|
72
|
+
.composerRow{display:flex;gap:8px;align-items:flex-end}
|
|
73
|
+
textarea{flex:1;resize:vertical;min-height:44px;max-height:160px;background:var(--panel2);color:var(--ink);
|
|
74
|
+
border:1px solid var(--edge);border-radius:10px;padding:10px 12px;font:14px/1.4 inherit}
|
|
75
|
+
textarea:focus{outline:none;border-color:var(--blue)}
|
|
76
|
+
.send{background:linear-gradient(180deg,var(--blue2),var(--blue));color:#00122e;font-weight:700;border:none;
|
|
77
|
+
border-radius:10px;padding:11px 16px;cursor:pointer}
|
|
78
|
+
.send:disabled{opacity:.5;cursor:not-allowed}
|
|
79
|
+
.opts{display:flex;gap:14px;align-items:center;margin-top:8px;color:var(--mut);font-size:12px}
|
|
80
|
+
.opts select,.opts input{background:var(--panel2);color:var(--ink);border:1px solid var(--edge);border-radius:7px;padding:4px 7px}
|
|
81
|
+
.chips{display:flex;gap:8px;padding:10px 16px;flex-wrap:wrap;border-bottom:1px solid var(--edge)}
|
|
82
|
+
.chip{display:flex;align-items:center;gap:6px;padding:5px 11px;border-radius:999px;border:1px solid var(--edge);
|
|
83
|
+
color:var(--mut);font-size:12px}
|
|
84
|
+
.chip.on{color:var(--blue2);border-color:var(--blue)} .chip.done{color:var(--ok);border-color:var(--ok)}
|
|
85
|
+
.console{flex:1;overflow:auto;padding:12px 16px}
|
|
86
|
+
.ev{display:flex;gap:9px;padding:2px 0;font-size:12.5px}
|
|
87
|
+
.ev .ic{width:14px;text-align:center} .ev .tx{white-space:pre-wrap;word-break:break-word}
|
|
88
|
+
.e-blue{color:var(--blue2)} .e-mut{color:var(--mut)} .e-ok{color:var(--ok)} .e-red{color:var(--red)} .e-warn{color:var(--warn)}
|
|
89
|
+
.empty{color:var(--mut);text-align:center;padding:40px 20px}
|
|
90
|
+
pre{white-space:pre-wrap;word-break:break-word;font-size:12px;color:var(--ink)}
|
|
91
|
+
.rhead{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--edge)}
|
|
92
|
+
a{color:var(--blue2)}
|
|
93
|
+
</style></head>
|
|
94
|
+
<body>
|
|
95
|
+
<header>
|
|
96
|
+
<span class="dot" id="dot"></span>
|
|
97
|
+
<span class="brand"><span class="m">M A</span> <span class="fin">Q</span> ▲</span>
|
|
98
|
+
<span class="e-mut" style="font-size:12px">megalodon · v${version}</span>
|
|
99
|
+
<span class="grow"></span>
|
|
100
|
+
<div class="switch">
|
|
101
|
+
<button onclick="feat('agents')">Agents</button>
|
|
102
|
+
<button onclick="feat('connectivity')">Connectivity</button>
|
|
103
|
+
<button onclick="feat('doctor')">Doctor</button>
|
|
104
|
+
<button onclick="feat('models')">Models</button>
|
|
105
|
+
<button class="ghost" onclick="togglePreview()">Preview</button>
|
|
106
|
+
</div>
|
|
107
|
+
</header>
|
|
108
|
+
<main id="main">
|
|
109
|
+
<div class="col left">
|
|
110
|
+
<div class="sec">Sessions & history</div>
|
|
111
|
+
<div id="sessions"><div class="empty">No sessions yet.</div></div>
|
|
112
|
+
<div class="sec">Agents</div>
|
|
113
|
+
<div id="agents"><div class="empty">—</div></div>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="col center">
|
|
116
|
+
<div class="composer">
|
|
117
|
+
<div class="modes" id="modes"></div>
|
|
118
|
+
<div class="composerRow">
|
|
119
|
+
<textarea id="goal" placeholder="Describe a goal — e.g. add pagination to the users endpoint and add tests"></textarea>
|
|
120
|
+
<button class="send" id="send" onclick="startTask()">Send ▶</button>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="opts">
|
|
123
|
+
<label>target
|
|
124
|
+
<select id="target">
|
|
125
|
+
<option value="none">none (raw)</option><option value="auto">auto</option>
|
|
126
|
+
<option value="claude-code">claude-code</option><option value="codex">codex</option>
|
|
127
|
+
<option value="gemini">gemini</option>
|
|
128
|
+
</select>
|
|
129
|
+
</label>
|
|
130
|
+
<label><input type="checkbox" id="dry"> dry-run</label>
|
|
131
|
+
<label>concurrency <input type="number" id="conc" value="4" min="1" max="16" style="width:52px"></label>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="chips" id="chips"></div>
|
|
135
|
+
<div class="console" id="console"><div class="empty">Pick a mode, type a goal, and press Send. The live Scout→Plan→Execute→Verify stream shows here.</div></div>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="col right">
|
|
138
|
+
<div class="rhead"><b>Preview</b><button class="ghost" onclick="togglePreview()">Close</button></div>
|
|
139
|
+
<div id="preview" style="padding:12px"><div class="empty">Select a session to inspect its result.</div></div>
|
|
140
|
+
</div>
|
|
141
|
+
</main>
|
|
142
|
+
<script>
|
|
143
|
+
"use strict";
|
|
144
|
+
var base = location.origin;
|
|
145
|
+
var token = new URLSearchParams(location.search).get('token') || sessionStorage.getItem('maqToken') || '';
|
|
146
|
+
if(!token){ token = prompt('Daemon auth token (printed by: maq serve — or the launcher):') || ''; }
|
|
147
|
+
sessionStorage.setItem('maqToken', token);
|
|
148
|
+
|
|
149
|
+
var MODES = [
|
|
150
|
+
{id:'', h:'Single', p:'one Scout→Plan→Execute→Verify pass'},
|
|
151
|
+
{id:'parallel',h:'Parallel', p:'split, run at once, join & repeat'},
|
|
152
|
+
{id:'loop', h:'Loop', p:'refine & retry until it verifies'},
|
|
153
|
+
{id:'safe', h:'Safe', p:'light split → merge → validate'}
|
|
154
|
+
];
|
|
155
|
+
var mode = 'parallel';
|
|
156
|
+
var activeId = null;
|
|
157
|
+
|
|
158
|
+
function h(tag,cls,txt){ var e=document.createElement(tag); if(cls)e.className=cls; if(txt!=null)e.textContent=txt; return e; }
|
|
159
|
+
function headers(){ return {authorization:'Bearer '+token,'content-type':'application/json'}; }
|
|
160
|
+
function api(path,opts){ opts=opts||{}; opts.headers=headers(); return fetch(base+path,opts); }
|
|
161
|
+
|
|
162
|
+
function renderModes(){
|
|
163
|
+
var c=document.getElementById('modes'); c.innerHTML='';
|
|
164
|
+
MODES.forEach(function(m){
|
|
165
|
+
var d=h('div','mode'+(m.id===mode?' sel':''));
|
|
166
|
+
d.innerHTML='<h4>'+m.h+'</h4><p>'+m.p+'</p>';
|
|
167
|
+
d.onclick=function(){ mode=m.id; renderModes(); };
|
|
168
|
+
c.appendChild(d);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
var PHASES=['scout','plan','execute','verify'];
|
|
173
|
+
function renderChips(events){
|
|
174
|
+
var done={}, active=null, orch=[];
|
|
175
|
+
events.forEach(function(e){
|
|
176
|
+
var p=e.data&&e.data.phase;
|
|
177
|
+
if(!p)return;
|
|
178
|
+
if(/^(parallel-round|loop-iteration|safe-)/.test(p)){ if(e.type==='phase.started')orch.push(p); return; }
|
|
179
|
+
if(e.type==='phase.started')active=p;
|
|
180
|
+
if(e.type==='phase.done'){done[p]=true; if(active===p)active=null;}
|
|
181
|
+
});
|
|
182
|
+
var c=document.getElementById('chips'); c.innerHTML='';
|
|
183
|
+
PHASES.forEach(function(p){
|
|
184
|
+
var cls='chip'+(done[p]?' done':(active===p?' on':''));
|
|
185
|
+
var chip=h('div',cls); chip.innerHTML=(done[p]?'✓ ':(active===p?'● ':'○ '))+p; c.appendChild(chip);
|
|
186
|
+
});
|
|
187
|
+
var last=orch[orch.length-1];
|
|
188
|
+
if(last){ var oc=h('div','chip on'); oc.textContent='◆ '+last; oc.innerHTML='◆ '+last; c.appendChild(oc); }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function iconFor(e){
|
|
192
|
+
switch(e.type){
|
|
193
|
+
case 'task.started': return ['▶','e-blue', (e.data.goal||e.data.task||'')+(e.data.mode?' ['+e.data.mode+']':'')];
|
|
194
|
+
case 'phase.started': return ['›','e-blue', (e.data.phase||'')+' …'];
|
|
195
|
+
case 'phase.done': return ['•','e-mut', (e.data.phase||'')+(e.data.reason?' '+e.data.reason:'')];
|
|
196
|
+
case 'agent.event': return ['·','e-mut', e.data.note||JSON.stringify(e.data)];
|
|
197
|
+
case 'agent.stdout': return ['|','e-mut', e.data.text||''];
|
|
198
|
+
case 'agent.stderr': return ['!','e-warn', e.data.text||''];
|
|
199
|
+
case 'tool.call': return ['⚙','e-blue','tool: '+(e.data.tool||JSON.stringify(e.data.command||e.data.raw||{}))];
|
|
200
|
+
case 'task.done': return [e.data.verified?'✓':'⚑', e.data.verified?'e-ok':'e-warn', 'done · verified='+e.data.verified+(e.data.mode?' · '+e.data.mode:'')+(e.data.summary?' · '+e.data.summary:'')];
|
|
201
|
+
case 'task.error': return ['✗','e-red','error: '+(e.data.message||'')];
|
|
202
|
+
case 'task.cancelled': return ['✗','e-red','cancelled'];
|
|
203
|
+
default: return ['○','e-mut', e.type];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function pushEvent(e){
|
|
207
|
+
var c=document.getElementById('console');
|
|
208
|
+
if(c.firstChild&&c.firstChild.className==='empty')c.innerHTML='';
|
|
209
|
+
var parts=iconFor(e);
|
|
210
|
+
var row=h('div','ev');
|
|
211
|
+
var ic=h('span','ic '+parts[1]); ic.innerHTML=parts[0];
|
|
212
|
+
var tx=h('span','tx '+parts[1]); tx.textContent=parts[2];
|
|
213
|
+
row.appendChild(ic); row.appendChild(tx); c.appendChild(row);
|
|
214
|
+
c.scrollTop=c.scrollHeight;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
var evList=[];
|
|
218
|
+
async function streamEvents(id){
|
|
219
|
+
evList=[];
|
|
220
|
+
document.getElementById('console').innerHTML='';
|
|
221
|
+
var res=await fetch(base+'/v1/sessions/'+id+'/events',{headers:{authorization:'Bearer '+token}});
|
|
222
|
+
if(!res.ok||!res.body){ pushEvent({type:'task.error',data:{message:'stream failed '+res.status}}); return; }
|
|
223
|
+
var reader=res.body.getReader(), dec=new TextDecoder(), buf='';
|
|
224
|
+
while(true){
|
|
225
|
+
var r=await reader.read(); if(r.done)break;
|
|
226
|
+
buf+=dec.decode(r.value,{stream:true});
|
|
227
|
+
var blocks=buf.split('\\n\\n'); buf=blocks.pop();
|
|
228
|
+
for(var i=0;i<blocks.length;i++){
|
|
229
|
+
var lines=blocks[i].split('\\n');
|
|
230
|
+
for(var j=0;j<lines.length;j++){
|
|
231
|
+
var ln=lines[j];
|
|
232
|
+
if(ln.indexOf('data:')===0){
|
|
233
|
+
var payload=ln.slice(5).trim(); if(!payload)continue;
|
|
234
|
+
try{ var ev=JSON.parse(payload); if(ev.type==='stream.end'){continue;} evList.push(ev); pushEvent(ev); renderChips(evList); }catch(err){}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if(id!==activeId)break;
|
|
239
|
+
}
|
|
240
|
+
refreshSessions();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function startTask(){
|
|
244
|
+
var goal=document.getElementById('goal').value.trim(); if(!goal)return;
|
|
245
|
+
var btn=document.getElementById('send'); btn.disabled=true;
|
|
246
|
+
var body={task:goal, target:document.getElementById('target').value, dryRun:document.getElementById('dry').checked,
|
|
247
|
+
maxConcurrency:Number(document.getElementById('conc').value)||4};
|
|
248
|
+
if(mode)body.mode=mode;
|
|
249
|
+
try{
|
|
250
|
+
var res=await api('/v1/sessions',{method:'POST',body:JSON.stringify(body)});
|
|
251
|
+
var s=await res.json();
|
|
252
|
+
if(!res.ok){ pushEvent({type:'task.error',data:{message:s.error||('HTTP '+res.status)}}); return; }
|
|
253
|
+
activeId=s.id; document.getElementById('goal').value='';
|
|
254
|
+
await refreshSessions();
|
|
255
|
+
streamEvents(s.id);
|
|
256
|
+
}catch(e){ pushEvent({type:'task.error',data:{message:String(e)}}); }
|
|
257
|
+
finally{ btn.disabled=false; }
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function refreshSessions(){
|
|
261
|
+
try{
|
|
262
|
+
var res=await api('/v1/sessions'); var d=await res.json();
|
|
263
|
+
var box=document.getElementById('sessions'); box.innerHTML='';
|
|
264
|
+
var list=(d.sessions||[]);
|
|
265
|
+
document.getElementById('dot').className='dot on';
|
|
266
|
+
if(!list.length){ box.innerHTML='<div class="empty">No sessions yet.</div>'; return; }
|
|
267
|
+
list.slice().reverse().forEach(function(s){
|
|
268
|
+
var it=h('div','item'+(s.id===activeId?' active':''));
|
|
269
|
+
var t=h('div','t'); t.textContent=s.task;
|
|
270
|
+
var meta=h('div','s');
|
|
271
|
+
meta.innerHTML='<span class="badge b-'+s.status+'">'+s.status+'</span> '+
|
|
272
|
+
(s.mode?('· '+s.mode+' '):'')+'· '+(s.target||'auto')+' · '+s.eventCount+' ev'+
|
|
273
|
+
(s.verified===true?' · ✓':(s.verified===false?' · ✗':''));
|
|
274
|
+
it.appendChild(t); it.appendChild(meta);
|
|
275
|
+
it.onclick=function(){ activeId=s.id; refreshSessions(); openPreview(s.id); streamEvents(s.id); };
|
|
276
|
+
box.appendChild(it);
|
|
277
|
+
});
|
|
278
|
+
}catch(e){ document.getElementById('dot').className='dot'; }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function openPreview(id){
|
|
282
|
+
document.getElementById('main').classList.add('preview');
|
|
283
|
+
var box=document.getElementById('preview'); box.innerHTML='loading…';
|
|
284
|
+
try{
|
|
285
|
+
var res=await api('/v1/sessions/'+id); var d=await res.json();
|
|
286
|
+
box.innerHTML='';
|
|
287
|
+
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);
|
|
288
|
+
box.appendChild(pre);
|
|
289
|
+
}catch(e){ box.textContent=String(e); }
|
|
290
|
+
}
|
|
291
|
+
function togglePreview(){ document.getElementById('main').classList.toggle('preview'); }
|
|
292
|
+
|
|
293
|
+
async function feat(kind){
|
|
294
|
+
document.getElementById('main').classList.add('preview');
|
|
295
|
+
var box=document.getElementById('preview'); box.innerHTML='running '+kind+'…';
|
|
296
|
+
try{
|
|
297
|
+
var out;
|
|
298
|
+
if(kind==='agents'){ out=await (await api('/v1/agents')).json(); renderAgents(out.agents||[]); }
|
|
299
|
+
else if(kind==='connectivity'){ out=await (await api('/v1/connectivity')).json(); }
|
|
300
|
+
else { out=await (await api('/v1/exec',{method:'POST',body:JSON.stringify({argv:[kind]})})).json(); }
|
|
301
|
+
var pre=h('pre'); pre.textContent=(out.stdout!=null?out.stdout:'')+(out.stderr?('\\n'+out.stderr):'')||JSON.stringify(out,null,2);
|
|
302
|
+
box.innerHTML=''; box.appendChild(pre);
|
|
303
|
+
}catch(e){ box.textContent=String(e); }
|
|
304
|
+
}
|
|
305
|
+
function renderAgents(agents){
|
|
306
|
+
var box=document.getElementById('agents'); box.innerHTML='';
|
|
307
|
+
if(!agents.length){ box.innerHTML='<div class="empty">none detected</div>'; return; }
|
|
308
|
+
agents.forEach(function(a){
|
|
309
|
+
var it=h('div','item'); var t=h('div','t'); t.textContent=a.name;
|
|
310
|
+
var s=h('div','s'); s.textContent=a.installed?(a.authenticated?'authenticated':'installed'):'not found';
|
|
311
|
+
it.appendChild(t); it.appendChild(s); box.appendChild(it);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
renderModes(); refreshSessions(); feat('agents'); setInterval(refreshSessions, 5000);
|
|
316
|
+
document.getElementById('goal').addEventListener('keydown', function(e){ if((e.metaKey||e.ctrlKey)&&e.key==='Enter')startTask(); });
|
|
317
|
+
</script>
|
|
318
|
+
</body></html>`;
|
|
319
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maqcli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MAQ master orchestrator — a token-efficient, agent-agnostic supervisor CLI that sits on top of any worker CLI (AI or not) via a Scout -> Plan -> Execute -> Verify pipeline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|