@junctionpanel/server 0.1.35 → 0.1.37
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/server/client/daemon-client.d.ts +22 -6
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +42 -1
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +24 -1
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +23 -0
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +11 -0
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +20 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +4 -4
- package/dist/server/server/agent/pending-plan-review.d.ts +12 -0
- package/dist/server/server/agent/pending-plan-review.d.ts.map +1 -0
- package/dist/server/server/agent/pending-plan-review.js +85 -0
- package/dist/server/server/agent/pending-plan-review.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts +2 -3
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
- package/dist/server/server/agent-attention-policy.js +2 -2
- package/dist/server/server/agent-attention-policy.js.map +1 -1
- package/dist/server/server/notifications/relay-client.d.ts +9 -0
- package/dist/server/server/notifications/relay-client.d.ts.map +1 -0
- package/dist/server/server/notifications/relay-client.js +55 -0
- package/dist/server/server/notifications/relay-client.js.map +1 -0
- package/dist/server/server/notifications/relay-ownership.d.ts +5 -0
- package/dist/server/server/notifications/relay-ownership.d.ts.map +1 -0
- package/dist/server/server/notifications/relay-ownership.js +25 -0
- package/dist/server/server/notifications/relay-ownership.js.map +1 -0
- package/dist/server/server/notifications/relay-store.d.ts +22 -0
- package/dist/server/server/notifications/relay-store.d.ts.map +1 -0
- package/dist/server/server/notifications/relay-store.js +72 -0
- package/dist/server/server/notifications/relay-store.js.map +1 -0
- package/dist/server/server/session.d.ts +13 -7
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +135 -75
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +5 -0
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +81 -6
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/shared/agent-attention-notification.d.ts +2 -0
- package/dist/server/shared/agent-attention-notification.d.ts.map +1 -1
- package/dist/server/shared/agent-attention-notification.js +23 -5
- package/dist/server/shared/agent-attention-notification.js.map +1 -1
- package/dist/server/shared/messages.d.ts +1488 -1148
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +47 -12
- package/dist/server/shared/messages.js.map +1 -1
- package/package.json +2 -2
|
@@ -33,6 +33,8 @@ import { deriveProjectGroupingKey, deriveProjectGroupingName } from '../shared/p
|
|
|
33
33
|
import { DEFAULT_DAEMON_PACKAGE_NAME, resolveDaemonPackageVersion, } from './daemon-package-context.js';
|
|
34
34
|
import { runDaemonDoctor } from './daemon-doctor.js';
|
|
35
35
|
import { MANAGED_DAEMON_PROVIDERS, autoRouteProviderExecutable, loadDaemonProviderSettings, saveDaemonProviderExecutablePath, } from './daemon-provider-settings.js';
|
|
36
|
+
import { applyNotificationRelayOwnerLabel, preserveNotificationRelayOwnerLabel, } from './notifications/relay-ownership.js';
|
|
37
|
+
import { saveNotificationRelayConfig } from './notifications/relay-store.js';
|
|
36
38
|
import { resolvePackageUpdateInfo } from './package-update.js';
|
|
37
39
|
import { loadPersistedConfig } from './persisted-config.js';
|
|
38
40
|
const execAsync = promisify(exec);
|
|
@@ -42,6 +44,7 @@ const READ_ONLY_GIT_ENV = {
|
|
|
42
44
|
};
|
|
43
45
|
const DEFAULT_STORED_TIMELINE_FETCH_LIMIT = 200;
|
|
44
46
|
const pendingAgentInitializations = new Map();
|
|
47
|
+
const pendingAgentMessageExecutions = new Map();
|
|
45
48
|
const DEFAULT_AGENT_PROVIDER = AGENT_PROVIDER_IDS[0];
|
|
46
49
|
const CHECKOUT_DIFF_WATCH_DEBOUNCE_MS = 150;
|
|
47
50
|
const CHECKOUT_DIFF_FALLBACK_REFRESH_MS = 5000;
|
|
@@ -121,13 +124,14 @@ export class Session {
|
|
|
121
124
|
this.nextTerminalStreamId = 1;
|
|
122
125
|
this.checkoutDiffSubscriptions = new Map();
|
|
123
126
|
this.checkoutDiffTargets = new Map();
|
|
124
|
-
const { clientId, userId, onMessage, onBinaryMessage, onLifecycleIntent, logger, downloadTokenStore, junctionHome, agentManager, agentStorage, createAgentMcpTransport, terminalManager, agentProviderRuntimeSettings, } = options;
|
|
127
|
+
const { clientId, userId, onMessage, onBinaryMessage, onLifecycleIntent, onClientActivityChange, logger, downloadTokenStore, junctionHome, agentManager, agentStorage, createAgentMcpTransport, terminalManager, agentProviderRuntimeSettings, } = options;
|
|
125
128
|
this.clientId = clientId;
|
|
126
129
|
this.userId = userId;
|
|
127
130
|
this.sessionId = uuidv4();
|
|
128
131
|
this.onMessage = onMessage;
|
|
129
132
|
this.onBinaryMessage = onBinaryMessage ?? null;
|
|
130
133
|
this.onLifecycleIntent = onLifecycleIntent ?? null;
|
|
134
|
+
this.onClientActivityChange = onClientActivityChange ?? null;
|
|
131
135
|
this.downloadTokenStore = downloadTokenStore;
|
|
132
136
|
this.junctionHome = junctionHome;
|
|
133
137
|
this.agentManager = agentManager;
|
|
@@ -247,6 +251,61 @@ export class Session {
|
|
|
247
251
|
},
|
|
248
252
|
});
|
|
249
253
|
}
|
|
254
|
+
enqueueAcceptedAgentMessageExecution(input) {
|
|
255
|
+
const previous = pendingAgentMessageExecutions.get(input.agentId) ?? Promise.resolve();
|
|
256
|
+
const execution = previous
|
|
257
|
+
.catch(() => undefined)
|
|
258
|
+
.then(async () => {
|
|
259
|
+
const startedAt = Date.now();
|
|
260
|
+
const phaseTimings = {
|
|
261
|
+
performSendMs: 0,
|
|
262
|
+
waitForRunStartMs: 0,
|
|
263
|
+
};
|
|
264
|
+
const performSendStartedAt = Date.now();
|
|
265
|
+
await this.performAgentMessageSend(input);
|
|
266
|
+
phaseTimings.performSendMs = Date.now() - performSendStartedAt;
|
|
267
|
+
const waitForRunStartStartedAt = Date.now();
|
|
268
|
+
await this.agentManager.waitForAgentRunStart(input.agentId);
|
|
269
|
+
phaseTimings.waitForRunStartMs = Date.now() - waitForRunStartStartedAt;
|
|
270
|
+
this.sessionLogger.debug({
|
|
271
|
+
agentId: input.agentId,
|
|
272
|
+
durationMs: Date.now() - startedAt,
|
|
273
|
+
...phaseTimings,
|
|
274
|
+
}, 'Accepted send_agent_message_request execution started');
|
|
275
|
+
});
|
|
276
|
+
const trackedExecution = execution.finally(() => {
|
|
277
|
+
if (pendingAgentMessageExecutions.get(input.agentId) === trackedExecution) {
|
|
278
|
+
pendingAgentMessageExecutions.delete(input.agentId);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
pendingAgentMessageExecutions.set(input.agentId, trackedExecution);
|
|
282
|
+
return trackedExecution;
|
|
283
|
+
}
|
|
284
|
+
async performAgentMessageSend(input) {
|
|
285
|
+
await this.ensureAgentLoaded(input.agentId);
|
|
286
|
+
await this.interruptAgentIfRunning(input.agentId);
|
|
287
|
+
try {
|
|
288
|
+
this.agentManager.recordUserMessage(input.agentId, input.text, {
|
|
289
|
+
messageId: input.messageId,
|
|
290
|
+
emitState: false,
|
|
291
|
+
images: input.images?.map((image) => ({
|
|
292
|
+
data: image.preview?.data ?? image.data,
|
|
293
|
+
mimeType: image.preview?.mimeType ?? image.mimeType,
|
|
294
|
+
...(image.label ? { label: image.label } : {}),
|
|
295
|
+
...(image.preview?.width != null ? { width: image.preview.width } : {}),
|
|
296
|
+
...(image.preview?.height != null ? { height: image.preview.height } : {}),
|
|
297
|
+
})),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
this.sessionLogger.error({ err: error, agentId: input.agentId }, `Failed to record user message for agent ${input.agentId}`);
|
|
302
|
+
}
|
|
303
|
+
const prompt = this.buildAgentPrompt(input.text, input.images);
|
|
304
|
+
const started = this.startAgentStream(input.agentId, prompt, input.runOptions);
|
|
305
|
+
if (!started.ok) {
|
|
306
|
+
throw new Error(started.error);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
250
309
|
/**
|
|
251
310
|
* Initialize Agent MCP client for this session using in-memory transport
|
|
252
311
|
*/
|
|
@@ -889,6 +948,9 @@ export class Session {
|
|
|
889
948
|
case 'auto_route_provider_request':
|
|
890
949
|
await this.handleAutoRouteProviderRequest(msg);
|
|
891
950
|
break;
|
|
951
|
+
case 'update_notification_relay_config_request':
|
|
952
|
+
await this.handleUpdateNotificationRelayConfigRequest(msg);
|
|
953
|
+
break;
|
|
892
954
|
case 'clear_agent_attention':
|
|
893
955
|
await this.handleClearAgentAttention(msg.agentId);
|
|
894
956
|
break;
|
|
@@ -1357,7 +1419,7 @@ export class Session {
|
|
|
1357
1419
|
await this.agentManager.setTitle(agentId, normalizedName);
|
|
1358
1420
|
}
|
|
1359
1421
|
if (normalizedLabels) {
|
|
1360
|
-
await this.agentManager.setLabels(agentId, normalizedLabels);
|
|
1422
|
+
await this.agentManager.setLabels(agentId, preserveNotificationRelayOwnerLabel(liveAgent.labels, normalizedLabels));
|
|
1361
1423
|
}
|
|
1362
1424
|
}
|
|
1363
1425
|
else {
|
|
@@ -1368,7 +1430,11 @@ export class Session {
|
|
|
1368
1430
|
await this.agentStorage.upsert({
|
|
1369
1431
|
...existing,
|
|
1370
1432
|
...(normalizedName ? { title: normalizedName } : {}),
|
|
1371
|
-
...(normalizedLabels
|
|
1433
|
+
...(normalizedLabels
|
|
1434
|
+
? {
|
|
1435
|
+
labels: preserveNotificationRelayOwnerLabel(existing.labels, normalizedLabels),
|
|
1436
|
+
}
|
|
1437
|
+
: {}),
|
|
1372
1438
|
});
|
|
1373
1439
|
}
|
|
1374
1440
|
this.emit({
|
|
@@ -1409,30 +1475,17 @@ export class Session {
|
|
|
1409
1475
|
return;
|
|
1410
1476
|
}
|
|
1411
1477
|
try {
|
|
1412
|
-
await this.
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
this.handleAgentRunError(agentId, error, 'Failed to initialize agent before sending prompt');
|
|
1416
|
-
return;
|
|
1417
|
-
}
|
|
1418
|
-
try {
|
|
1419
|
-
await this.interruptAgentIfRunning(agentId);
|
|
1420
|
-
}
|
|
1421
|
-
catch (error) {
|
|
1422
|
-
this.handleAgentRunError(agentId, error, 'Failed to interrupt running agent before sending prompt');
|
|
1423
|
-
return;
|
|
1424
|
-
}
|
|
1425
|
-
const prompt = this.buildAgentPrompt(text, images);
|
|
1426
|
-
try {
|
|
1427
|
-
this.agentManager.recordUserMessage(agentId, text, {
|
|
1478
|
+
await this.performAgentMessageSend({
|
|
1479
|
+
agentId,
|
|
1480
|
+
text,
|
|
1428
1481
|
messageId,
|
|
1429
|
-
|
|
1482
|
+
images,
|
|
1483
|
+
runOptions,
|
|
1430
1484
|
});
|
|
1431
1485
|
}
|
|
1432
1486
|
catch (error) {
|
|
1433
|
-
this.
|
|
1487
|
+
this.handleAgentRunError(agentId, error, 'Failed to send prompt to agent');
|
|
1434
1488
|
}
|
|
1435
|
-
this.startAgentStream(agentId, prompt, runOptions);
|
|
1436
1489
|
}
|
|
1437
1490
|
/**
|
|
1438
1491
|
* Handle create agent request
|
|
@@ -1445,7 +1498,9 @@ export class Session {
|
|
|
1445
1498
|
const mergedLabels = autoWorkspaceName
|
|
1446
1499
|
? { ...labels, 'junction:workspace': autoWorkspaceName }
|
|
1447
1500
|
: labels;
|
|
1448
|
-
const snapshot = await this.agentManager.createAgent(sessionConfig, undefined, {
|
|
1501
|
+
const snapshot = await this.agentManager.createAgent(sessionConfig, undefined, {
|
|
1502
|
+
labels: applyNotificationRelayOwnerLabel(mergedLabels, this.userId),
|
|
1503
|
+
});
|
|
1449
1504
|
await this.forwardAgentUpdate(snapshot);
|
|
1450
1505
|
if (requestId) {
|
|
1451
1506
|
const agentPayload = await this.getAgentPayloadById(snapshot.id);
|
|
@@ -1941,6 +1996,46 @@ export class Session {
|
|
|
1941
1996
|
});
|
|
1942
1997
|
}
|
|
1943
1998
|
}
|
|
1999
|
+
async handleUpdateNotificationRelayConfigRequest(msg) {
|
|
2000
|
+
try {
|
|
2001
|
+
const relayUrl = msg.relayUrl?.trim();
|
|
2002
|
+
const token = msg.token?.trim();
|
|
2003
|
+
const expiresAt = msg.expiresAt?.trim();
|
|
2004
|
+
const providedCount = [msg.relayUrl, msg.token, msg.expiresAt].filter((value) => value !== undefined).length;
|
|
2005
|
+
if (providedCount === 0) {
|
|
2006
|
+
saveNotificationRelayConfig(this.junctionHome, this.userId, null);
|
|
2007
|
+
}
|
|
2008
|
+
else if (providedCount !== 3 || !relayUrl || !token || !expiresAt) {
|
|
2009
|
+
throw new SessionRequestError('invalid_notification_relay_config', 'relayUrl, token, and expiresAt must be provided together');
|
|
2010
|
+
}
|
|
2011
|
+
else {
|
|
2012
|
+
saveNotificationRelayConfig(this.junctionHome, this.userId, {
|
|
2013
|
+
relayUrl,
|
|
2014
|
+
token,
|
|
2015
|
+
expiresAt,
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
this.emit({
|
|
2019
|
+
type: 'update_notification_relay_config_response',
|
|
2020
|
+
payload: {
|
|
2021
|
+
success: true,
|
|
2022
|
+
error: null,
|
|
2023
|
+
requestId: msg.requestId,
|
|
2024
|
+
},
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
catch (error) {
|
|
2028
|
+
this.sessionLogger.error({ err: error }, 'Failed to update notification relay config');
|
|
2029
|
+
this.emit({
|
|
2030
|
+
type: 'update_notification_relay_config_response',
|
|
2031
|
+
payload: {
|
|
2032
|
+
success: false,
|
|
2033
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2034
|
+
requestId: msg.requestId,
|
|
2035
|
+
},
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
1944
2039
|
normalizeGitOptions(gitOptions, legacyWorktreeName) {
|
|
1945
2040
|
const fallbackOptions = legacyWorktreeName
|
|
1946
2041
|
? {
|
|
@@ -2301,6 +2396,14 @@ export class Session {
|
|
|
2301
2396
|
appVisible: msg.appVisible,
|
|
2302
2397
|
appVisibilityChangedAt,
|
|
2303
2398
|
};
|
|
2399
|
+
if (this.onClientActivityChange) {
|
|
2400
|
+
try {
|
|
2401
|
+
this.onClientActivityChange(this.clientActivity);
|
|
2402
|
+
}
|
|
2403
|
+
catch (error) {
|
|
2404
|
+
this.sessionLogger.warn({ err: error }, 'onClientActivityChange callback failed');
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2304
2407
|
}
|
|
2305
2408
|
/**
|
|
2306
2409
|
* Handle list commands request for an agent
|
|
@@ -4423,7 +4526,8 @@ export class Session {
|
|
|
4423
4526
|
}
|
|
4424
4527
|
try {
|
|
4425
4528
|
const agentId = resolved.agentId;
|
|
4426
|
-
const
|
|
4529
|
+
const storedRecord = await this.agentStorage.get(agentId);
|
|
4530
|
+
const archivedAt = storedRecord?.archivedAt ?? null;
|
|
4427
4531
|
if (archivedAt) {
|
|
4428
4532
|
this.emit({
|
|
4429
4533
|
type: 'send_agent_message_response',
|
|
@@ -4436,57 +4540,13 @@ export class Session {
|
|
|
4436
4540
|
});
|
|
4437
4541
|
return;
|
|
4438
4542
|
}
|
|
4439
|
-
await this.
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
}
|
|
4447
|
-
catch (error) {
|
|
4448
|
-
this.sessionLogger.error({ err: error, agentId }, 'Failed to record user message for send_agent_message_request');
|
|
4449
|
-
}
|
|
4450
|
-
const prompt = this.buildAgentPrompt(msg.text, msg.images);
|
|
4451
|
-
const started = this.startAgentStream(agentId, prompt, normalizeAgentRunOptions(msg.runOptions));
|
|
4452
|
-
if (!started.ok) {
|
|
4453
|
-
this.emit({
|
|
4454
|
-
type: 'send_agent_message_response',
|
|
4455
|
-
payload: {
|
|
4456
|
-
requestId: msg.requestId,
|
|
4457
|
-
agentId,
|
|
4458
|
-
accepted: false,
|
|
4459
|
-
error: started.error,
|
|
4460
|
-
},
|
|
4461
|
-
});
|
|
4462
|
-
return;
|
|
4463
|
-
}
|
|
4464
|
-
const startAbort = new AbortController();
|
|
4465
|
-
const startTimeoutMs = 15000;
|
|
4466
|
-
const startTimeout = setTimeout(() => startAbort.abort('timeout'), startTimeoutMs);
|
|
4467
|
-
try {
|
|
4468
|
-
await this.agentManager.waitForAgentRunStart(agentId, { signal: startAbort.signal });
|
|
4469
|
-
}
|
|
4470
|
-
catch (error) {
|
|
4471
|
-
const message = error instanceof Error
|
|
4472
|
-
? error.message
|
|
4473
|
-
: typeof error === 'string'
|
|
4474
|
-
? error
|
|
4475
|
-
: 'Unknown error';
|
|
4476
|
-
this.emit({
|
|
4477
|
-
type: 'send_agent_message_response',
|
|
4478
|
-
payload: {
|
|
4479
|
-
requestId: msg.requestId,
|
|
4480
|
-
agentId,
|
|
4481
|
-
accepted: false,
|
|
4482
|
-
error: message,
|
|
4483
|
-
},
|
|
4484
|
-
});
|
|
4485
|
-
return;
|
|
4486
|
-
}
|
|
4487
|
-
finally {
|
|
4488
|
-
clearTimeout(startTimeout);
|
|
4489
|
-
}
|
|
4543
|
+
await this.enqueueAcceptedAgentMessageExecution({
|
|
4544
|
+
agentId,
|
|
4545
|
+
text: msg.text,
|
|
4546
|
+
...(msg.messageId ? { messageId: msg.messageId } : {}),
|
|
4547
|
+
...(msg.images ? { images: msg.images } : {}),
|
|
4548
|
+
runOptions: normalizeAgentRunOptions(msg.runOptions),
|
|
4549
|
+
});
|
|
4490
4550
|
this.emit({
|
|
4491
4551
|
type: 'send_agent_message_response',
|
|
4492
4552
|
payload: {
|