@lelouchhe/webagent 0.1.5 → 0.1.7
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/index.html +3 -2
- package/dist/js/{app.mmlj0xfy.js → app.mmmmfxhu.js} +8 -8
- package/dist/js/{commands.mmlj0xfy.js → commands.mmmmfxhu.js} +3 -3
- package/dist/js/{connection.mmlj0xfy.js → connection.mmmmfxhu.js} +3 -3
- package/dist/js/{events.mmlj0xfy.js → events.mmmmfxhu.js} +24 -4
- package/dist/js/{images.mmlj0xfy.js → images.mmmmfxhu.js} +1 -1
- package/dist/js/{input.mmlj0xfy.js → input.mmmmfxhu.js} +4 -4
- package/dist/js/{render.mmlj0xfy.js → render.mmmmfxhu.js} +1 -1
- package/dist/js/{state.mmlj0xfy.js → state.mmmmfxhu.js} +25 -0
- package/dist/{styles.mmlj0xfy.css → styles.mmmmfxhu.css} +20 -1
- package/package.json +1 -1
package/dist/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
14
14
|
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.3.2/dist/purify.min.js"></script>
|
|
15
15
|
<script>document.documentElement.setAttribute('data-theme', localStorage.getItem('theme') || 'auto');</script>
|
|
16
|
-
<link rel="stylesheet" href="/styles.
|
|
16
|
+
<link rel="stylesheet" href="/styles.mmmmfxhu.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
<button id="send-btn" class="input-btn" title="Send (Enter)">↵</button>
|
|
41
41
|
<input type="file" id="file-input" accept="image/*" multiple hidden>
|
|
42
42
|
</div>
|
|
43
|
+
<div id="status-bar"></div>
|
|
43
44
|
|
|
44
|
-
<script type="module" src="/js/app.
|
|
45
|
+
<script type="module" src="/js/app.mmmmfxhu.js"></script>
|
|
45
46
|
</body>
|
|
46
47
|
</html>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Boot entry point — imports all modules and starts the app
|
|
2
2
|
|
|
3
|
-
import './render.
|
|
4
|
-
import './commands.
|
|
5
|
-
import './images.
|
|
6
|
-
import './input.
|
|
7
|
-
import { connect } from './connection.
|
|
8
|
-
import { state, setHashSessionId, resetSessionUI, updateSessionInfo } from './state.
|
|
9
|
-
import { loadHistory } from './events.
|
|
10
|
-
import { addSystem, scrollToBottom } from './render.
|
|
3
|
+
import './render.mmmmfxhu.js'; // theme, click-to-collapse listeners
|
|
4
|
+
import './commands.mmmmfxhu.js'; // slash menu listeners
|
|
5
|
+
import './images.mmmmfxhu.js'; // attach/paste listeners
|
|
6
|
+
import './input.mmmmfxhu.js'; // keyboard/send listeners
|
|
7
|
+
import { connect } from './connection.mmmmfxhu.js';
|
|
8
|
+
import { state, setHashSessionId, resetSessionUI, updateSessionInfo } from './state.mmmmfxhu.js';
|
|
9
|
+
import { loadHistory } from './events.mmmmfxhu.js';
|
|
10
|
+
import { addSystem, scrollToBottom } from './render.mmmmfxhu.js';
|
|
11
11
|
|
|
12
12
|
connect();
|
|
13
13
|
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
state, dom, setBusy, resetSessionUI, requestNewSession, sendCancel,
|
|
5
5
|
getConfigOption, getConfigValue, setHashSessionId, updateSessionInfo,
|
|
6
6
|
updateNewBtnVisibility,
|
|
7
|
-
} from './state.
|
|
8
|
-
import { addSystem, addMessage, scrollToBottom, escHtml, formatLocalTime } from './render.
|
|
9
|
-
import { loadHistory } from './events.
|
|
7
|
+
} from './state.mmmmfxhu.js';
|
|
8
|
+
import { addSystem, addMessage, scrollToBottom, escHtml, formatLocalTime } from './render.mmmmfxhu.js';
|
|
9
|
+
import { loadHistory } from './events.mmmmfxhu.js';
|
|
10
10
|
|
|
11
11
|
// --- Push notification helpers ---
|
|
12
12
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// WebSocket connection lifecycle
|
|
2
2
|
|
|
3
|
-
import { state, setBusy, getHashSessionId, requestNewSession, resetSessionUI, setConnectionStatus, clearCancelTimer } from './state.
|
|
4
|
-
import { addSystem, finishThinking, finishAssistant, finishBash, scrollToBottom } from './render.
|
|
5
|
-
import { handleEvent, loadHistory, loadNewEvents, retryUnconfirmedPermissions } from './events.
|
|
3
|
+
import { state, setBusy, getHashSessionId, requestNewSession, resetSessionUI, setConnectionStatus, clearCancelTimer } from './state.mmmmfxhu.js';
|
|
4
|
+
import { addSystem, finishThinking, finishAssistant, finishBash, scrollToBottom } from './render.mmmmfxhu.js';
|
|
5
|
+
import { handleEvent, loadHistory, loadNewEvents, retryUnconfirmedPermissions } from './events.mmmmfxhu.js';
|
|
6
6
|
|
|
7
7
|
export function connect() {
|
|
8
8
|
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
state, dom, setBusy, setConfigValue, getConfigOption, updateConfigOptions,
|
|
5
|
-
updateModeUI, resetSessionUI, requestNewSession, setHashSessionId, updateSessionInfo,
|
|
5
|
+
updateModeUI, updateStatusBar, resetSessionUI, requestNewSession, setHashSessionId, updateSessionInfo,
|
|
6
6
|
setConnectionStatus, clearCancelTimer,
|
|
7
|
-
} from './state.
|
|
7
|
+
} from './state.mmmmfxhu.js';
|
|
8
8
|
import {
|
|
9
9
|
addMessage, addSystem, finishAssistant, finishThinking, hideWaiting,
|
|
10
10
|
scrollToBottom, renderMd, escHtml, renderPatchDiff, addBashBlock, finishBash, appendMessageElement,
|
|
11
11
|
formatLocalTime,
|
|
12
|
-
} from './render.
|
|
12
|
+
} from './render.mmmmfxhu.js';
|
|
13
13
|
|
|
14
14
|
const NOTIFY_TIP_KEY = 'webagent_notify_tip_shown';
|
|
15
15
|
const NOTIFY_TIP_DENIED_KEY = 'webagent_notify_tip_denied_shown';
|
|
@@ -377,6 +377,7 @@ export function handleEvent(msg) {
|
|
|
377
377
|
dom.sendBtn.disabled = false;
|
|
378
378
|
dom.input.placeholder = '';
|
|
379
379
|
setBusy(Boolean(msg.busyKind));
|
|
380
|
+
state.newTurnStarted = false;
|
|
380
381
|
if (msg.busyKind === 'bash') {
|
|
381
382
|
const pendingBashEl = document.getElementById('bash-replay-pending');
|
|
382
383
|
if (pendingBashEl) {
|
|
@@ -390,9 +391,16 @@ export function handleEvent(msg) {
|
|
|
390
391
|
if (dom.messages.children.length === 0) {
|
|
391
392
|
addSystem(`Session created: ${state.sessionTitle || msg.sessionId.slice(0, 8) + '…'}`);
|
|
392
393
|
}
|
|
394
|
+
updateStatusBar();
|
|
393
395
|
break;
|
|
394
396
|
|
|
395
397
|
case 'user_message': {
|
|
398
|
+
// A new turn is starting (from another client's broadcast).
|
|
399
|
+
// Finalise any in-progress streaming from the previous turn so
|
|
400
|
+
// subsequent message_chunks create a fresh element BELOW this bubble.
|
|
401
|
+
finishThinking();
|
|
402
|
+
finishAssistant();
|
|
403
|
+
state.newTurnStarted = true;
|
|
396
404
|
state.turnEnded = false;
|
|
397
405
|
if (msg.sessionId === state.sessionId) {
|
|
398
406
|
const el = addMessage('user', msg.text);
|
|
@@ -613,8 +621,18 @@ export function handleEvent(msg) {
|
|
|
613
621
|
break;
|
|
614
622
|
}
|
|
615
623
|
|
|
616
|
-
case 'prompt_done':
|
|
624
|
+
case 'prompt_done': {
|
|
617
625
|
clearCancelTimer();
|
|
626
|
+
if (msg.stopReason === 'cancelled' && state.newTurnStarted) {
|
|
627
|
+
// This prompt_done belongs to a previous turn — a new turn has already
|
|
628
|
+
// started (signaled by user_message from another client). Don't clobber
|
|
629
|
+
// the current turn's pending state; just tidy up leftover streaming elements.
|
|
630
|
+
state.newTurnStarted = false;
|
|
631
|
+
finishThinking();
|
|
632
|
+
finishAssistant();
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
state.newTurnStarted = false;
|
|
618
636
|
if (msg.stopReason === 'cancelled') {
|
|
619
637
|
cancelPendingTurnUI();
|
|
620
638
|
}
|
|
@@ -622,6 +640,7 @@ export function handleEvent(msg) {
|
|
|
622
640
|
state.pendingPromptDone = true;
|
|
623
641
|
finishPromptIfIdle();
|
|
624
642
|
break;
|
|
643
|
+
}
|
|
625
644
|
|
|
626
645
|
case 'session_deleted':
|
|
627
646
|
if (msg.sessionId === state.sessionId) {
|
|
@@ -645,6 +664,7 @@ export function handleEvent(msg) {
|
|
|
645
664
|
const valueName = opt?.options.find(o => o.value === msg.value)?.name || msg.value;
|
|
646
665
|
addSystem(`ok: ${label}: ${valueName}`);
|
|
647
666
|
if (msg.configId === 'mode') updateModeUI();
|
|
667
|
+
updateStatusBar();
|
|
648
668
|
break;
|
|
649
669
|
}
|
|
650
670
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
import {
|
|
4
4
|
state, dom, setBusy, sendCancel,
|
|
5
5
|
getConfigOption, getConfigValue, updateNewBtnVisibility,
|
|
6
|
-
} from './state.
|
|
7
|
-
import { addMessage, addSystem, addBashBlock, showWaiting } from './render.
|
|
8
|
-
import { handleSlashCommand, hideSlashMenu, handleSlashMenuKey, updateSlashMenu } from './commands.
|
|
9
|
-
import { renderAttachPreview } from './images.
|
|
6
|
+
} from './state.mmmmfxhu.js';
|
|
7
|
+
import { addMessage, addSystem, addBashBlock, showWaiting } from './render.mmmmfxhu.js';
|
|
8
|
+
import { handleSlashCommand, hideSlashMenu, handleSlashMenuKey, updateSlashMenu } from './commands.mmmmfxhu.js';
|
|
9
|
+
import { renderAttachPreview } from './images.mmmmfxhu.js';
|
|
10
10
|
|
|
11
11
|
function wsReady() {
|
|
12
12
|
return state.ws && state.ws.readyState === 1;
|
|
@@ -16,6 +16,7 @@ export const dom = {
|
|
|
16
16
|
themeBtn: $('#theme-btn'),
|
|
17
17
|
slashMenu: $('#slash-menu'),
|
|
18
18
|
inputArea: $('#input-area'),
|
|
19
|
+
statusBar: $('#status-bar'),
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export const state = {
|
|
@@ -37,6 +38,7 @@ export const state = {
|
|
|
37
38
|
pendingPermissionRequestIds: new Set(),
|
|
38
39
|
pendingPromptDone: false,
|
|
39
40
|
turnEnded: false,
|
|
41
|
+
newTurnStarted: false,
|
|
40
42
|
cancelTimeout: 10_000,
|
|
41
43
|
_cancelTimerId: null,
|
|
42
44
|
_onCancelTimeout: null,
|
|
@@ -71,6 +73,7 @@ export function setConfigValue(id, value) {
|
|
|
71
73
|
export function updateConfigOptions(newOptions) {
|
|
72
74
|
state.configOptions = newOptions;
|
|
73
75
|
updateModeUI();
|
|
76
|
+
updateStatusBar();
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
export function updateModeUI() {
|
|
@@ -80,6 +83,26 @@ export function updateModeUI() {
|
|
|
80
83
|
else if (modeValue.includes('#autopilot')) dom.inputArea.classList.add('autopilot-mode');
|
|
81
84
|
}
|
|
82
85
|
|
|
86
|
+
export function updateStatusBar() {
|
|
87
|
+
if (!dom.statusBar) return;
|
|
88
|
+
const model = getConfigValue('model');
|
|
89
|
+
const cwd = state.sessionCwd || '';
|
|
90
|
+
dom.statusBar.textContent = '';
|
|
91
|
+
const parts = [];
|
|
92
|
+
if (model) parts.push(model);
|
|
93
|
+
if (cwd) {
|
|
94
|
+
if (model) {
|
|
95
|
+
dom.statusBar.appendChild(document.createTextNode(model + ' \u00b7 '));
|
|
96
|
+
}
|
|
97
|
+
const cwdSpan = document.createElement('span');
|
|
98
|
+
cwdSpan.className = 'status-cwd';
|
|
99
|
+
cwdSpan.textContent = cwd;
|
|
100
|
+
dom.statusBar.appendChild(cwdSpan);
|
|
101
|
+
} else if (model) {
|
|
102
|
+
dom.statusBar.textContent = model;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
83
106
|
export function setBusy(on) {
|
|
84
107
|
state.busy = on;
|
|
85
108
|
if (on) {
|
|
@@ -116,6 +139,7 @@ export function resetSessionUI() {
|
|
|
116
139
|
state.unconfirmedPermissions.clear();
|
|
117
140
|
state.pendingPromptDone = false;
|
|
118
141
|
state.turnEnded = false;
|
|
142
|
+
state.newTurnStarted = false;
|
|
119
143
|
state._cancelTimerId = null;
|
|
120
144
|
state.lastEventSeq = 0;
|
|
121
145
|
state.replayInProgress = false;
|
|
@@ -126,6 +150,7 @@ export function resetSessionUI() {
|
|
|
126
150
|
dom.sendBtn.disabled = false;
|
|
127
151
|
dom.input.placeholder = '';
|
|
128
152
|
setBusy(false);
|
|
153
|
+
if (dom.statusBar) dom.statusBar.textContent = '';
|
|
129
154
|
}
|
|
130
155
|
|
|
131
156
|
export function updateNewBtnVisibility() {
|
|
@@ -355,7 +355,7 @@ body {
|
|
|
355
355
|
/* Input */
|
|
356
356
|
#input-area {
|
|
357
357
|
position: relative;
|
|
358
|
-
padding: 8px 16px
|
|
358
|
+
padding: 8px 16px 4px;
|
|
359
359
|
background: var(--bg);
|
|
360
360
|
border-top: 1px solid var(--border);
|
|
361
361
|
display: flex;
|
|
@@ -410,6 +410,25 @@ body {
|
|
|
410
410
|
#input-area.autopilot-mode #input-prompt {
|
|
411
411
|
color: var(--red);
|
|
412
412
|
}
|
|
413
|
+
#status-bar {
|
|
414
|
+
display: flex;
|
|
415
|
+
padding: 0 16px 10px;
|
|
416
|
+
background: var(--bg);
|
|
417
|
+
color: var(--text-dim);
|
|
418
|
+
font-size: 11px;
|
|
419
|
+
line-height: 1.4;
|
|
420
|
+
white-space: nowrap;
|
|
421
|
+
user-select: none;
|
|
422
|
+
}
|
|
423
|
+
#status-bar::before {
|
|
424
|
+
content: '\200b';
|
|
425
|
+
}
|
|
426
|
+
#status-bar .status-cwd {
|
|
427
|
+
overflow: hidden;
|
|
428
|
+
text-overflow: ellipsis;
|
|
429
|
+
direction: rtl;
|
|
430
|
+
text-align: left;
|
|
431
|
+
}
|
|
413
432
|
#input-prompt {
|
|
414
433
|
color: var(--text);
|
|
415
434
|
font-weight: bold;
|