create-byan-agent 2.9.0 → 2.9.2
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/package.json +1 -1
- package/src/webui/chat/claude-adapter.js +4 -3
- package/src/webui/chat/cli-detector.js +2 -0
- package/src/webui/chat/codex-adapter.js +4 -1
- package/src/webui/chat/copilot-adapter.js +4 -1
- package/src/webui/public/chat.css +37 -0
- package/src/webui/public/chat.html +5 -0
- package/src/webui/public/chat.js +60 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-byan-agent",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2",
|
|
4
4
|
"description": "BYAN v2.2.2 - Intelligent AI agent installer with multi-platform native support (GitHub Copilot CLI, Claude Code, Codex/OpenCode)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-byan-agent": "bin/create-byan-agent-v2.js"
|
|
@@ -99,9 +99,10 @@ class ClaudeAdapter extends Bridge {
|
|
|
99
99
|
|
|
100
100
|
_handleStderr(data) {
|
|
101
101
|
const text = data.toString().trim();
|
|
102
|
-
if (text)
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
if (!text) return;
|
|
103
|
+
// Claude dumps progress/status info to stderr — not errors
|
|
104
|
+
if (/^(Initializing|Loading|Connected|Session|Warming|Cost:|Token)/m.test(text)) return;
|
|
105
|
+
this.onError(new Error(`claude stderr: ${text}`));
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
_parseLine(line) {
|
|
@@ -50,6 +50,7 @@ async function detectCLIs() {
|
|
|
50
50
|
const cmdPath = whichSync(def.command);
|
|
51
51
|
if (!cmdPath) {
|
|
52
52
|
results.push({
|
|
53
|
+
id: def.name,
|
|
53
54
|
name: def.name,
|
|
54
55
|
path: null,
|
|
55
56
|
version: null,
|
|
@@ -63,6 +64,7 @@ async function detectCLIs() {
|
|
|
63
64
|
const version = versionResult.ok ? parseVersion(versionResult.output) : null;
|
|
64
65
|
|
|
65
66
|
results.push({
|
|
67
|
+
id: def.name,
|
|
66
68
|
name: def.name,
|
|
67
69
|
path: cmdPath,
|
|
68
70
|
version,
|
|
@@ -32,7 +32,10 @@ class CodexAdapter extends Bridge {
|
|
|
32
32
|
|
|
33
33
|
this.process.stderr.on('data', (data) => {
|
|
34
34
|
const text = data.toString().trim();
|
|
35
|
-
if (text)
|
|
35
|
+
if (!text) return;
|
|
36
|
+
// Codex dumps progress/usage info to stderr
|
|
37
|
+
if (/^(Running|Executing|Model:|Tokens|Cost)/m.test(text)) return;
|
|
38
|
+
this.onError(new Error(`codex stderr: ${text}`));
|
|
36
39
|
});
|
|
37
40
|
|
|
38
41
|
this.process.on('error', (err) => {
|
|
@@ -42,7 +42,10 @@ class CopilotAdapter extends Bridge {
|
|
|
42
42
|
|
|
43
43
|
this.process.stderr.on('data', (data) => {
|
|
44
44
|
const text = data.toString().trim();
|
|
45
|
-
if (text)
|
|
45
|
+
if (!text) return;
|
|
46
|
+
// Copilot dumps usage stats to stderr — not errors
|
|
47
|
+
if (/^(Total usage|API time|Total session|Total code|Breakdown by|claude-|gpt-|o[1-4]|Est\.|Premium request)/m.test(text)) return;
|
|
48
|
+
this.onError(new Error(`copilot stderr: ${text}`));
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
this.process.on('error', (err) => {
|
|
@@ -195,6 +195,34 @@ body {
|
|
|
195
195
|
border-color: var(--accent);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
.cli-select {
|
|
199
|
+
background: var(--surface);
|
|
200
|
+
color: var(--text);
|
|
201
|
+
border: 1px solid var(--border);
|
|
202
|
+
border-radius: var(--radius);
|
|
203
|
+
padding: 6px 12px;
|
|
204
|
+
font-size: 0.8rem;
|
|
205
|
+
font-family: var(--font-sans);
|
|
206
|
+
cursor: pointer;
|
|
207
|
+
outline: none;
|
|
208
|
+
transition: border-color var(--transition);
|
|
209
|
+
appearance: none;
|
|
210
|
+
-webkit-appearance: none;
|
|
211
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M3 4.5L6 8l3-3.5H3z'/%3E%3C/svg%3E");
|
|
212
|
+
background-repeat: no-repeat;
|
|
213
|
+
background-position: right 8px center;
|
|
214
|
+
padding-right: 28px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.cli-select:hover,
|
|
218
|
+
.cli-select:focus {
|
|
219
|
+
border-color: var(--accent);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.cli-select option:disabled {
|
|
223
|
+
color: var(--text-dim);
|
|
224
|
+
}
|
|
225
|
+
|
|
198
226
|
.topbar-right {
|
|
199
227
|
display: flex;
|
|
200
228
|
align-items: center;
|
|
@@ -1522,6 +1550,11 @@ body {
|
|
|
1522
1550
|
border-left-color: var(--success);
|
|
1523
1551
|
}
|
|
1524
1552
|
|
|
1553
|
+
.toast.error {
|
|
1554
|
+
border-left-color: var(--error);
|
|
1555
|
+
background: rgba(239, 68, 68, 0.1);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1525
1558
|
.toast.warning {
|
|
1526
1559
|
border-left-color: var(--warning);
|
|
1527
1560
|
}
|
|
@@ -1566,6 +1599,10 @@ body {
|
|
|
1566
1599
|
display: none;
|
|
1567
1600
|
}
|
|
1568
1601
|
|
|
1602
|
+
.cli-select {
|
|
1603
|
+
display: none;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1569
1606
|
.export-options {
|
|
1570
1607
|
grid-template-columns: 1fr;
|
|
1571
1608
|
}
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
<span class="agent-icon" id="active-agent-icon"></span>
|
|
20
20
|
<span class="agent-name" id="active-agent-name">No agent</span>
|
|
21
21
|
</div>
|
|
22
|
+
<select id="cli-select" class="cli-select" aria-label="Select CLI backend">
|
|
23
|
+
<option value="claude">Claude Code</option>
|
|
24
|
+
<option value="copilot">GitHub Copilot</option>
|
|
25
|
+
<option value="codex">Codex</option>
|
|
26
|
+
</select>
|
|
22
27
|
<select id="model-select" class="model-select" aria-label="Select model">
|
|
23
28
|
<option value="">Default model</option>
|
|
24
29
|
<option value="sonnet">Claude Sonnet</option>
|
package/src/webui/public/chat.js
CHANGED
|
@@ -62,6 +62,7 @@ class ByanChat {
|
|
|
62
62
|
agentList: document.getElementById('agent-list'),
|
|
63
63
|
sessionList: document.getElementById('session-list'),
|
|
64
64
|
cliStatus: document.getElementById('cli-status'),
|
|
65
|
+
cliSelect: document.getElementById('cli-select'),
|
|
65
66
|
modelSelect: document.getElementById('model-select'),
|
|
66
67
|
agentIndicator: document.getElementById('agent-indicator'),
|
|
67
68
|
activeAgentIcon: document.getElementById('active-agent-icon'),
|
|
@@ -136,9 +137,12 @@ class ByanChat {
|
|
|
136
137
|
case 'tool-approval':
|
|
137
138
|
this.showToolApproval(data.tool, data.command);
|
|
138
139
|
break;
|
|
140
|
+
case 'chat-error':
|
|
139
141
|
case 'error':
|
|
140
|
-
this.
|
|
141
|
-
|
|
142
|
+
this.handleChatError(data);
|
|
143
|
+
break;
|
|
144
|
+
case 'chat-tool':
|
|
145
|
+
this.showToolUsage(data.tool);
|
|
142
146
|
break;
|
|
143
147
|
case 'raw-output':
|
|
144
148
|
this.appendRawOutput(data.content);
|
|
@@ -148,6 +152,19 @@ class ByanChat {
|
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
|
|
155
|
+
handleChatError(data) {
|
|
156
|
+
const errorMsg = data.error || data.message || 'An error occurred';
|
|
157
|
+
this.showToast(errorMsg, 'error');
|
|
158
|
+
this.addMessage('system', `Error: ${errorMsg}`, { agent: 'System' });
|
|
159
|
+
this.finishStreaming(this.streamingContent);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
showToolUsage(tool) {
|
|
163
|
+
if (!tool) return;
|
|
164
|
+
const name = typeof tool === 'string' ? tool : tool.name || 'unknown tool';
|
|
165
|
+
this.appendChunk(`\n> Using tool: **${name}**\n`);
|
|
166
|
+
}
|
|
167
|
+
|
|
151
168
|
// ============================================================
|
|
152
169
|
// CLI Detection
|
|
153
170
|
// ============================================================
|
|
@@ -155,7 +172,7 @@ class ByanChat {
|
|
|
155
172
|
async detectCLIs() {
|
|
156
173
|
const knownCLIs = [
|
|
157
174
|
{ id: 'claude', name: 'Claude Code', cmd: 'claude' },
|
|
158
|
-
{ id: 'copilot', name: 'GitHub Copilot', cmd: '
|
|
175
|
+
{ id: 'copilot', name: 'GitHub Copilot', cmd: 'copilot' },
|
|
159
176
|
{ id: 'codex', name: 'OpenCode', cmd: 'codex' }
|
|
160
177
|
];
|
|
161
178
|
|
|
@@ -184,31 +201,48 @@ class ByanChat {
|
|
|
184
201
|
renderCLIStatus() {
|
|
185
202
|
this.dom.cliStatus.innerHTML = '';
|
|
186
203
|
for (const cli of this.clis) {
|
|
204
|
+
const cliId = cli.id || cli.name;
|
|
187
205
|
const el = document.createElement('div');
|
|
188
|
-
el.className = 'cli-item' + (cli.available ? ' available' : '') + (this.currentCLI ===
|
|
206
|
+
el.className = 'cli-item' + (cli.available ? ' available' : '') + (this.currentCLI === cliId ? ' active' : '');
|
|
189
207
|
el.setAttribute('role', 'button');
|
|
190
208
|
el.setAttribute('tabindex', '0');
|
|
191
209
|
el.setAttribute('aria-label', `${cli.name}: ${cli.available ? 'available' : 'not detected'}`);
|
|
192
210
|
el.innerHTML = `<span class="cli-dot"></span>${this.escapeHtml(cli.name)}`;
|
|
193
|
-
el.addEventListener('click', () => this.selectCLI(
|
|
194
|
-
el.addEventListener('keydown', (e) => { if (e.key === 'Enter') this.selectCLI(
|
|
211
|
+
el.addEventListener('click', () => this.selectCLI(cliId));
|
|
212
|
+
el.addEventListener('keydown', (e) => { if (e.key === 'Enter') this.selectCLI(cliId); });
|
|
195
213
|
this.dom.cliStatus.appendChild(el);
|
|
196
214
|
}
|
|
215
|
+
this.renderCLISelect();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
renderCLISelect() {
|
|
219
|
+
if (!this.dom.cliSelect) return;
|
|
220
|
+
this.dom.cliSelect.innerHTML = '';
|
|
221
|
+
for (const cli of this.clis) {
|
|
222
|
+
const cliId = cli.id || cli.name;
|
|
223
|
+
const opt = document.createElement('option');
|
|
224
|
+
opt.value = cliId;
|
|
225
|
+
opt.textContent = cli.name + (cli.available ? '' : ' (not detected)');
|
|
226
|
+
opt.disabled = !cli.available;
|
|
227
|
+
this.dom.cliSelect.appendChild(opt);
|
|
228
|
+
}
|
|
229
|
+
if (this.currentCLI) this.dom.cliSelect.value = this.currentCLI;
|
|
197
230
|
}
|
|
198
231
|
|
|
199
232
|
pickDefaultCLI() {
|
|
200
233
|
const available = this.clis.filter(c => c.available);
|
|
201
234
|
if (available.length > 0) {
|
|
202
|
-
this.selectCLI(available[0].id);
|
|
235
|
+
this.selectCLI(available[0].id || available[0].name);
|
|
203
236
|
} else if (this.clis.length > 0) {
|
|
204
|
-
this.selectCLI(this.clis[0].id);
|
|
237
|
+
this.selectCLI(this.clis[0].id || this.clis[0].name);
|
|
205
238
|
}
|
|
206
239
|
}
|
|
207
240
|
|
|
208
241
|
selectCLI(id) {
|
|
209
242
|
this.currentCLI = id;
|
|
210
|
-
const cli = this.clis.find(c => c.id === id);
|
|
211
|
-
this.dom.cliLabel.textContent = cli ? cli.name : id;
|
|
243
|
+
const cli = this.clis.find(c => (c.id || c.name) === id);
|
|
244
|
+
if (this.dom.cliLabel) this.dom.cliLabel.textContent = cli ? cli.name : id;
|
|
245
|
+
if (this.dom.cliSelect) this.dom.cliSelect.value = id;
|
|
212
246
|
this.renderCLIStatus();
|
|
213
247
|
this.saveState();
|
|
214
248
|
}
|
|
@@ -417,6 +451,7 @@ class ByanChat {
|
|
|
417
451
|
|
|
418
452
|
async startSession() {
|
|
419
453
|
const agentName = this.currentAgent ? this.currentAgent.name : null;
|
|
454
|
+
let bridgeOk = false;
|
|
420
455
|
|
|
421
456
|
try {
|
|
422
457
|
const res = await fetch('/api/chat/start', {
|
|
@@ -427,10 +462,15 @@ class ByanChat {
|
|
|
427
462
|
if (res.ok) {
|
|
428
463
|
const data = await res.json();
|
|
429
464
|
this.sessionId = data.sessionId || data.id || this.generateId();
|
|
465
|
+
bridgeOk = true;
|
|
430
466
|
} else {
|
|
467
|
+
const err = await res.json().catch(() => ({}));
|
|
468
|
+
const errMsg = err.error || `CLI bridge failed (${this.currentCLI || 'unknown'})`;
|
|
469
|
+
this.showToast(errMsg, 'error');
|
|
431
470
|
this.sessionId = this.generateId();
|
|
432
471
|
}
|
|
433
|
-
} catch {
|
|
472
|
+
} catch (e) {
|
|
473
|
+
this.showToast(`Cannot reach server: ${e.message || 'network error'}`, 'error');
|
|
434
474
|
this.sessionId = this.generateId();
|
|
435
475
|
}
|
|
436
476
|
|
|
@@ -450,7 +490,10 @@ class ByanChat {
|
|
|
450
490
|
this.renderSessions();
|
|
451
491
|
|
|
452
492
|
if (this.currentAgent) {
|
|
453
|
-
this.addMessage('system', `Session started with ${this.currentAgent.title || this.currentAgent.name}`
|
|
493
|
+
this.addMessage('system', `Session started with ${this.currentAgent.title || this.currentAgent.name}` +
|
|
494
|
+
(bridgeOk ? ` via ${this.currentCLI || 'default CLI'}` : ' (offline mode — CLI bridge unavailable)'));
|
|
495
|
+
} else if (!bridgeOk) {
|
|
496
|
+
this.addMessage('system', 'Session started in offline mode — CLI bridge could not be initialized');
|
|
454
497
|
}
|
|
455
498
|
|
|
456
499
|
this.wsSend({ type: 'join', sessionId: this.sessionId });
|
|
@@ -1324,6 +1367,11 @@ class ByanChat {
|
|
|
1324
1367
|
// Model select
|
|
1325
1368
|
this.dom.modelSelect.addEventListener('change', (e) => this.switchModel(e.target.value));
|
|
1326
1369
|
|
|
1370
|
+
// CLI select
|
|
1371
|
+
if (this.dom.cliSelect) {
|
|
1372
|
+
this.dom.cliSelect.addEventListener('change', (e) => this.selectCLI(e.target.value));
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1327
1375
|
// Sidebar overlay (close on click)
|
|
1328
1376
|
this.dom.sidebarOverlay.addEventListener('click', () => this.closeSidebar());
|
|
1329
1377
|
|