@agent-link/server 0.1.90 → 0.1.92
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/context.d.ts +4 -0
- package/dist/context.js +3 -0
- package/dist/context.js.map +1 -1
- package/dist/ws-agent.js +5 -1
- package/dist/ws-agent.js.map +1 -1
- package/dist/ws-client.js +11 -7
- package/dist/ws-client.js.map +1 -1
- package/package.json +1 -1
- package/web/app.js +27 -16
- package/web/modules/connection.js +8 -1
- package/web/style.css +45 -19
package/dist/context.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ export interface AuthAttemptState {
|
|
|
30
30
|
}
|
|
31
31
|
export declare const authAttempts: Map<string, AuthAttemptState>;
|
|
32
32
|
export declare const pendingAuth: Map<string, string>;
|
|
33
|
+
export declare const sessionAuth: Map<string, {
|
|
34
|
+
passwordHash: string;
|
|
35
|
+
passwordSalt: string;
|
|
36
|
+
}>;
|
|
33
37
|
export declare const serverSecret: NonSharedBuffer;
|
|
34
38
|
/**
|
|
35
39
|
* Generate a short, URL-safe session ID
|
package/dist/context.js
CHANGED
|
@@ -8,6 +8,9 @@ export const webClients = new Map();
|
|
|
8
8
|
export const authAttempts = new Map();
|
|
9
9
|
// Pending auth: clientId → sessionId (web clients awaiting password verification)
|
|
10
10
|
export const pendingAuth = new Map();
|
|
11
|
+
// Session auth: sessionId → { passwordHash, passwordSalt }
|
|
12
|
+
// Persists across agent disconnects so web clients can still be required to authenticate
|
|
13
|
+
export const sessionAuth = new Map();
|
|
11
14
|
// Server secret for HMAC auth tokens (generated fresh on each server start)
|
|
12
15
|
export const serverSecret = randomBytes(32);
|
|
13
16
|
/**
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AA0BrC,yCAAyC;AACzC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEtD,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExD,oCAAoC;AACpC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;AAOvD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEhE,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;AAErD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA4D;IAE5D,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC;YACzD,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;YACrB,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE5B,kDAAkD;YAClD,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBACpC,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;oBACzC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;YACtB,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC5B,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AA0BrC,yCAAyC;AACzC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEtD,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExD,oCAAoC;AACpC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAqB,CAAC;AAOvD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEhE,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;AAErD,2DAA2D;AAC3D,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,GAAG,EAA0D,CAAC;AAE7F,4EAA4E;AAC5E,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA4D;IAE5D,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC;YACzD,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;YACrB,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE5B,kDAAkD;YAClD,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBACpC,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;oBACzC,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IAClB,CAAC;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;YACtB,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC5B,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC"}
|
package/dist/ws-agent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WebSocket } from 'ws';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
|
-
import { agents, sessionToAgent, webClients, generateSessionId, } from './context.js';
|
|
3
|
+
import { agents, sessionToAgent, webClients, generateSessionId, sessionAuth, } from './context.js';
|
|
4
4
|
import { generateSessionKey, encodeKey, parseMessage, encryptAndSend } from './encryption.js';
|
|
5
5
|
import { hashPassword } from './auth.js';
|
|
6
6
|
export function handleAgentConnection(ws, req) {
|
|
@@ -39,6 +39,10 @@ export function handleAgentConnection(ws, req) {
|
|
|
39
39
|
};
|
|
40
40
|
agents.set(agentId, agent);
|
|
41
41
|
sessionToAgent.set(sessionId, agentId);
|
|
42
|
+
// Persist password auth per session so it survives agent disconnects
|
|
43
|
+
if (passwordHash && passwordSalt) {
|
|
44
|
+
sessionAuth.set(sessionId, { passwordHash, passwordSalt });
|
|
45
|
+
}
|
|
42
46
|
console.log(`[Agent] Registered: ${name} (${agentId}), session: ${sessionId}${requestedSessionId ? ' (reconnect)' : ''}${passwordHash ? ' (password protected)' : ''}`);
|
|
43
47
|
// Send registration with session key (this initial message is plain text)
|
|
44
48
|
ws.send(JSON.stringify({
|
package/dist/ws-agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EACL,MAAM,EACN,cAAc,EACd,UAAU,EACV,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/ws-client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WebSocket } from 'ws';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import { createRequire } from 'module';
|
|
4
|
-
import { agents, sessionToAgent, webClients, pendingAuth, } from './context.js';
|
|
4
|
+
import { agents, sessionToAgent, webClients, pendingAuth, sessionAuth, } from './context.js';
|
|
5
5
|
import { generateSessionKey, encodeKey, parseMessage, encryptAndSend } from './encryption.js';
|
|
6
6
|
import { isSessionLocked, recordFailure, clearFailures, verifyPassword, generateAuthToken, verifyAuthToken, } from './auth.js';
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
@@ -19,12 +19,15 @@ export function handleWebConnection(ws, req) {
|
|
|
19
19
|
// Check if agent exists for this session
|
|
20
20
|
const agentId = sessionToAgent.get(sessionId);
|
|
21
21
|
const agent = agentId ? agents.get(agentId) : undefined;
|
|
22
|
-
// Password-protected session?
|
|
23
|
-
const
|
|
22
|
+
// Password-protected session? Check persistent sessionAuth (survives agent disconnects)
|
|
23
|
+
const auth = sessionAuth.get(sessionId);
|
|
24
|
+
const requiresAuth = !!(auth?.passwordHash && auth?.passwordSalt);
|
|
24
25
|
if (requiresAuth) {
|
|
25
26
|
// Check saved auth token first
|
|
26
27
|
if (authToken && verifyAuthToken(authToken, sessionId)) {
|
|
27
|
-
|
|
28
|
+
// Refresh the token so it doesn't expire during long sessions
|
|
29
|
+
const refreshedToken = generateAuthToken(sessionId);
|
|
30
|
+
completeConnection(ws, clientId, sessionId, agent, refreshedToken);
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
33
|
// Check lockout
|
|
@@ -65,8 +68,9 @@ function handlePendingAuthMessage(clientId, ws, raw) {
|
|
|
65
68
|
return;
|
|
66
69
|
const agentId = sessionToAgent.get(sessionId);
|
|
67
70
|
const agent = agentId ? agents.get(agentId) : undefined;
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
const auth = sessionAuth.get(sessionId);
|
|
72
|
+
if (!auth?.passwordHash || !auth?.passwordSalt) {
|
|
73
|
+
// Password removed while authenticating
|
|
70
74
|
ws.send(JSON.stringify({ type: 'error', message: 'Session no longer available.' }));
|
|
71
75
|
pendingAuth.delete(clientId);
|
|
72
76
|
ws.close();
|
|
@@ -82,7 +86,7 @@ function handlePendingAuthMessage(clientId, ws, raw) {
|
|
|
82
86
|
ws.close();
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
|
-
const valid = verifyPassword(msg.password,
|
|
89
|
+
const valid = verifyPassword(msg.password, auth.passwordHash, auth.passwordSalt);
|
|
86
90
|
if (!valid) {
|
|
87
91
|
const { locked, remaining } = recordFailure(sessionId);
|
|
88
92
|
if (locked) {
|
package/dist/ws-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EACL,MAAM,EACN,cAAc,EACd,UAAU,EACV,WAAW,GAGZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,GAChB,MAAM,WAAW,CAAC;AAEnB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE7C,MAAM,UAAU,mBAAmB,CAAC,EAAa,EAAE,GAAoB;IACrE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAE9B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;QACzE,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IAED,yCAAyC;IACzC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAExD,
|
|
1
|
+
{"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../src/ws-client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -47,6 +47,7 @@ const App = {
|
|
|
47
47
|
const inputText = ref('');
|
|
48
48
|
const isProcessing = ref(false);
|
|
49
49
|
const isCompacting = ref(false);
|
|
50
|
+
const queuedMessages = ref([]);
|
|
50
51
|
const inputRef = ref(null);
|
|
51
52
|
|
|
52
53
|
// Sidebar state
|
|
@@ -157,7 +158,7 @@ const App = {
|
|
|
157
158
|
const { connect, wsSend, closeWs, submitPassword, setDequeueNext } = createConnection({
|
|
158
159
|
status, agentName, hostname, workDir, sessionId, error,
|
|
159
160
|
serverVersion, agentVersion,
|
|
160
|
-
messages, isProcessing, isCompacting, visibleLimit,
|
|
161
|
+
messages, isProcessing, isCompacting, visibleLimit, queuedMessages,
|
|
161
162
|
historySessions, currentClaudeSessionId, loadingSessions, loadingHistory,
|
|
162
163
|
folderPickerLoading, folderPickerEntries, folderPickerPath,
|
|
163
164
|
authRequired, authPassword, authError, authAttempts, authLocked,
|
|
@@ -216,9 +217,7 @@ const App = {
|
|
|
216
217
|
};
|
|
217
218
|
|
|
218
219
|
if (isProcessing.value) {
|
|
219
|
-
userMsg.
|
|
220
|
-
userMsg._queuedPayload = payload;
|
|
221
|
-
messages.value.push(userMsg);
|
|
220
|
+
queuedMessages.value.push({ id: streaming.nextId(), content: userMsg.content, attachments: userMsg.attachments, payload });
|
|
222
221
|
} else {
|
|
223
222
|
userMsg.status = 'sent';
|
|
224
223
|
messages.value.push(userMsg);
|
|
@@ -235,19 +234,22 @@ const App = {
|
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
function dequeueNext() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
|
|
237
|
+
if (queuedMessages.value.length === 0) return;
|
|
238
|
+
const queued = queuedMessages.value.shift();
|
|
239
|
+
const userMsg = {
|
|
240
|
+
id: queued.id, role: 'user', status: 'sent',
|
|
241
|
+
content: queued.content, attachments: queued.attachments,
|
|
242
|
+
timestamp: new Date(),
|
|
243
|
+
};
|
|
244
|
+
messages.value.push(userMsg);
|
|
242
245
|
isProcessing.value = true;
|
|
243
|
-
wsSend(
|
|
244
|
-
delete msg._queuedPayload;
|
|
246
|
+
wsSend(queued.payload);
|
|
245
247
|
scrollToBottom(true);
|
|
246
248
|
}
|
|
247
249
|
|
|
248
250
|
function removeQueuedMessage(msgId) {
|
|
249
|
-
const idx =
|
|
250
|
-
if (idx !== -1)
|
|
251
|
+
const idx = queuedMessages.value.findIndex(m => m.id === msgId);
|
|
252
|
+
if (idx !== -1) queuedMessages.value.splice(idx, 1);
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
function handleKeydown(e) {
|
|
@@ -283,7 +285,7 @@ const App = {
|
|
|
283
285
|
status, agentName, hostname, workDir, sessionId, error,
|
|
284
286
|
serverVersion, agentVersion,
|
|
285
287
|
messages, visibleMessages, hasMoreMessages, loadMoreMessages,
|
|
286
|
-
inputText, isProcessing, isCompacting, canSend, hasInput, inputRef,
|
|
288
|
+
inputText, isProcessing, isCompacting, canSend, hasInput, inputRef, queuedMessages,
|
|
287
289
|
sendMessage, handleKeydown, cancelExecution, removeQueuedMessage, onMessageListScroll,
|
|
288
290
|
getRenderedContent, copyMessage, toggleTool,
|
|
289
291
|
isPrevAssistant: _isPrevAssistant,
|
|
@@ -484,8 +486,7 @@ const App = {
|
|
|
484
486
|
<!-- User message -->
|
|
485
487
|
<template v-if="msg.role === 'user'">
|
|
486
488
|
<div class="message-role-label user-label">You</div>
|
|
487
|
-
<div
|
|
488
|
-
<button v-if="msg.status === 'queued'" class="queue-remove-btn" @click="removeQueuedMessage(msg.id)" title="Remove from queue">×</button>
|
|
489
|
+
<div class="message-bubble user-bubble" :title="formatTimestamp(msg.timestamp)">
|
|
489
490
|
<div class="message-content">{{ msg.content }}</div>
|
|
490
491
|
<div v-if="msg.attachments && msg.attachments.length" class="message-attachments">
|
|
491
492
|
<div v-for="(att, ai) in msg.attachments" :key="ai" class="message-attachment-chip">
|
|
@@ -496,7 +497,6 @@ const App = {
|
|
|
496
497
|
<span>{{ att.name }}</span>
|
|
497
498
|
</div>
|
|
498
499
|
</div>
|
|
499
|
-
<div v-if="msg.status === 'queued'" class="queue-badge">queued</div>
|
|
500
500
|
</div>
|
|
501
501
|
</template>
|
|
502
502
|
|
|
@@ -616,6 +616,17 @@ const App = {
|
|
|
616
616
|
@change="handleFileSelect"
|
|
617
617
|
accept="image/*,text/*,.pdf,.json,.md,.py,.js,.ts,.tsx,.jsx,.css,.html,.xml,.yaml,.yml,.toml,.sh,.sql,.csv"
|
|
618
618
|
/>
|
|
619
|
+
<div v-if="queuedMessages.length > 0" class="queue-bar">
|
|
620
|
+
<div v-for="(qm, qi) in queuedMessages" :key="qm.id" class="queue-item">
|
|
621
|
+
<span class="queue-item-num">{{ qi + 1 }}.</span>
|
|
622
|
+
<span class="queue-item-text">{{ qm.content }}</span>
|
|
623
|
+
<span v-if="qm.attachments && qm.attachments.length" class="queue-item-attach" :title="qm.attachments.map(a => a.name).join(', ')">
|
|
624
|
+
<svg viewBox="0 0 24 24" width="11" height="11"><path fill="currentColor" d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5a2.5 2.5 0 0 1 5 0v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5a2.5 2.5 0 0 0 5 0V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"/></svg>
|
|
625
|
+
{{ qm.attachments.length }}
|
|
626
|
+
</span>
|
|
627
|
+
<button class="queue-item-remove" @click="removeQueuedMessage(qm.id)" title="Remove from queue">×</button>
|
|
628
|
+
</div>
|
|
629
|
+
</div>
|
|
619
630
|
<div
|
|
620
631
|
:class="['input-card', { 'drag-over': dragOver }]"
|
|
621
632
|
@dragover="handleDragOver"
|
|
@@ -14,7 +14,7 @@ export function createConnection(deps) {
|
|
|
14
14
|
const {
|
|
15
15
|
status, agentName, hostname, workDir, sessionId, error,
|
|
16
16
|
serverVersion, agentVersion,
|
|
17
|
-
messages, isProcessing, isCompacting, visibleLimit,
|
|
17
|
+
messages, isProcessing, isCompacting, visibleLimit, queuedMessages,
|
|
18
18
|
historySessions, currentClaudeSessionId, loadingSessions, loadingHistory,
|
|
19
19
|
folderPickerLoading, folderPickerEntries, folderPickerPath,
|
|
20
20
|
authRequired, authPassword, authError, authAttempts, authLocked,
|
|
@@ -207,6 +207,8 @@ export function createConnection(deps) {
|
|
|
207
207
|
error.value = 'Agent disconnected. Waiting for reconnect...';
|
|
208
208
|
isProcessing.value = false;
|
|
209
209
|
isCompacting.value = false;
|
|
210
|
+
queuedMessages.value = [];
|
|
211
|
+
loadingSessions.value = false;
|
|
210
212
|
} else if (msg.type === 'agent_reconnected') {
|
|
211
213
|
status.value = 'Connected';
|
|
212
214
|
error.value = '';
|
|
@@ -230,6 +232,7 @@ export function createConnection(deps) {
|
|
|
230
232
|
scrollToBottom();
|
|
231
233
|
isProcessing.value = false;
|
|
232
234
|
isCompacting.value = false;
|
|
235
|
+
loadingSessions.value = false;
|
|
233
236
|
_dequeueNext();
|
|
234
237
|
} else if (msg.type === 'claude_output') {
|
|
235
238
|
handleClaudeOutput(msg, scheduleHighlight);
|
|
@@ -393,6 +396,7 @@ export function createConnection(deps) {
|
|
|
393
396
|
localStorage.setItem(`agentlink-workdir-${sessionId.value}`, msg.workDir);
|
|
394
397
|
sidebar.addToWorkdirHistory(msg.workDir);
|
|
395
398
|
messages.value = [];
|
|
399
|
+
queuedMessages.value = [];
|
|
396
400
|
toolMsgMap.clear();
|
|
397
401
|
visibleLimit.value = 50;
|
|
398
402
|
streaming.setMessageIdCounter(0);
|
|
@@ -414,6 +418,9 @@ export function createConnection(deps) {
|
|
|
414
418
|
const wasConnected = status.value === 'Connected' || status.value === 'Connecting...';
|
|
415
419
|
isProcessing.value = false;
|
|
416
420
|
isCompacting.value = false;
|
|
421
|
+
queuedMessages.value = [];
|
|
422
|
+
loadingSessions.value = false;
|
|
423
|
+
loadingHistory.value = false;
|
|
417
424
|
|
|
418
425
|
// Don't auto-reconnect if auth-locked or still in auth prompt
|
|
419
426
|
if (authLocked.value || authRequired.value) return;
|
package/web/style.css
CHANGED
|
@@ -787,27 +787,56 @@ body {
|
|
|
787
787
|
color: var(--text-primary);
|
|
788
788
|
}
|
|
789
789
|
|
|
790
|
-
/* ──
|
|
791
|
-
.
|
|
792
|
-
|
|
790
|
+
/* ── Queue bar (pending messages above input) ── */
|
|
791
|
+
.queue-bar {
|
|
792
|
+
max-width: 768px;
|
|
793
|
+
margin: 0 auto 6px;
|
|
794
|
+
display: flex;
|
|
795
|
+
flex-direction: column;
|
|
796
|
+
gap: 3px;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.queue-item {
|
|
800
|
+
display: flex;
|
|
801
|
+
align-items: center;
|
|
802
|
+
gap: 6px;
|
|
803
|
+
background: var(--bg-secondary);
|
|
793
804
|
border: 1px dashed var(--border);
|
|
794
|
-
|
|
805
|
+
border-radius: 8px;
|
|
806
|
+
padding: 4px 8px;
|
|
807
|
+
font-size: 0.8rem;
|
|
808
|
+
line-height: 1.3;
|
|
809
|
+
color: var(--text-secondary);
|
|
810
|
+
opacity: 0.85;
|
|
795
811
|
}
|
|
796
812
|
|
|
797
|
-
.queue-
|
|
798
|
-
|
|
813
|
+
.queue-item-num {
|
|
814
|
+
flex-shrink: 0;
|
|
799
815
|
font-weight: 600;
|
|
800
|
-
text-transform: uppercase;
|
|
801
|
-
letter-spacing: 0.05em;
|
|
802
816
|
color: var(--text-secondary);
|
|
803
|
-
|
|
804
|
-
|
|
817
|
+
font-size: 0.7rem;
|
|
818
|
+
opacity: 0.6;
|
|
805
819
|
}
|
|
806
820
|
|
|
807
|
-
.queue-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
821
|
+
.queue-item-text {
|
|
822
|
+
flex: 1;
|
|
823
|
+
min-width: 0;
|
|
824
|
+
overflow: hidden;
|
|
825
|
+
text-overflow: ellipsis;
|
|
826
|
+
white-space: nowrap;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
.queue-item-attach {
|
|
830
|
+
flex-shrink: 0;
|
|
831
|
+
display: flex;
|
|
832
|
+
align-items: center;
|
|
833
|
+
gap: 2px;
|
|
834
|
+
font-size: 0.7rem;
|
|
835
|
+
opacity: 0.6;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.queue-item-remove {
|
|
839
|
+
flex-shrink: 0;
|
|
811
840
|
background: none;
|
|
812
841
|
border: none;
|
|
813
842
|
color: var(--text-secondary);
|
|
@@ -815,15 +844,12 @@ body {
|
|
|
815
844
|
line-height: 1;
|
|
816
845
|
cursor: pointer;
|
|
817
846
|
padding: 0 2px;
|
|
818
|
-
opacity: 0;
|
|
847
|
+
opacity: 0.5;
|
|
819
848
|
transition: color 0.15s, opacity 0.15s;
|
|
820
849
|
}
|
|
821
850
|
|
|
822
|
-
.
|
|
851
|
+
.queue-item-remove:hover {
|
|
823
852
|
opacity: 1;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
.queue-remove-btn:hover {
|
|
827
853
|
color: var(--error);
|
|
828
854
|
}
|
|
829
855
|
|