@junctionpanel/server 0.1.35 → 0.1.36

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.
Files changed (53) hide show
  1. package/dist/server/client/daemon-client.d.ts +9 -6
  2. package/dist/server/client/daemon-client.d.ts.map +1 -1
  3. package/dist/server/client/daemon-client.js +15 -1
  4. package/dist/server/client/daemon-client.js.map +1 -1
  5. package/dist/server/server/agent/agent-manager.d.ts +24 -1
  6. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  7. package/dist/server/server/agent/agent-manager.js +23 -0
  8. package/dist/server/server/agent/agent-manager.js.map +1 -1
  9. package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
  10. package/dist/server/server/agent/agent-projections.js +11 -0
  11. package/dist/server/server/agent/agent-projections.js.map +1 -1
  12. package/dist/server/server/agent/agent-sdk-types.d.ts +20 -0
  13. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  14. package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
  15. package/dist/server/server/agent/agent-storage.d.ts +4 -4
  16. package/dist/server/server/agent/pending-plan-review.d.ts +12 -0
  17. package/dist/server/server/agent/pending-plan-review.d.ts.map +1 -0
  18. package/dist/server/server/agent/pending-plan-review.js +85 -0
  19. package/dist/server/server/agent/pending-plan-review.js.map +1 -0
  20. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
  21. package/dist/server/server/agent-attention-policy.d.ts +2 -3
  22. package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
  23. package/dist/server/server/agent-attention-policy.js +2 -2
  24. package/dist/server/server/agent-attention-policy.js.map +1 -1
  25. package/dist/server/server/notifications/relay-client.d.ts +9 -0
  26. package/dist/server/server/notifications/relay-client.d.ts.map +1 -0
  27. package/dist/server/server/notifications/relay-client.js +55 -0
  28. package/dist/server/server/notifications/relay-client.js.map +1 -0
  29. package/dist/server/server/notifications/relay-ownership.d.ts +5 -0
  30. package/dist/server/server/notifications/relay-ownership.d.ts.map +1 -0
  31. package/dist/server/server/notifications/relay-ownership.js +25 -0
  32. package/dist/server/server/notifications/relay-ownership.js.map +1 -0
  33. package/dist/server/server/notifications/relay-store.d.ts +22 -0
  34. package/dist/server/server/notifications/relay-store.d.ts.map +1 -0
  35. package/dist/server/server/notifications/relay-store.js +72 -0
  36. package/dist/server/server/notifications/relay-store.js.map +1 -0
  37. package/dist/server/server/session.d.ts +3 -0
  38. package/dist/server/server/session.d.ts.map +1 -1
  39. package/dist/server/server/session.js +125 -74
  40. package/dist/server/server/session.js.map +1 -1
  41. package/dist/server/server/websocket-server.d.ts +1 -0
  42. package/dist/server/server/websocket-server.d.ts.map +1 -1
  43. package/dist/server/server/websocket-server.js +31 -5
  44. package/dist/server/server/websocket-server.js.map +1 -1
  45. package/dist/server/shared/agent-attention-notification.d.ts +2 -0
  46. package/dist/server/shared/agent-attention-notification.d.ts.map +1 -1
  47. package/dist/server/shared/agent-attention-notification.js +23 -5
  48. package/dist/server/shared/agent-attention-notification.js.map +1 -1
  49. package/dist/server/shared/messages.d.ts +1488 -1148
  50. package/dist/server/shared/messages.d.ts.map +1 -1
  51. package/dist/server/shared/messages.js +47 -12
  52. package/dist/server/shared/messages.js.map +1 -1
  53. 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;
@@ -247,6 +250,61 @@ export class Session {
247
250
  },
248
251
  });
249
252
  }
253
+ enqueueAcceptedAgentMessageExecution(input) {
254
+ const previous = pendingAgentMessageExecutions.get(input.agentId) ?? Promise.resolve();
255
+ const execution = previous
256
+ .catch(() => undefined)
257
+ .then(async () => {
258
+ const startedAt = Date.now();
259
+ const phaseTimings = {
260
+ performSendMs: 0,
261
+ waitForRunStartMs: 0,
262
+ };
263
+ const performSendStartedAt = Date.now();
264
+ await this.performAgentMessageSend(input);
265
+ phaseTimings.performSendMs = Date.now() - performSendStartedAt;
266
+ const waitForRunStartStartedAt = Date.now();
267
+ await this.agentManager.waitForAgentRunStart(input.agentId);
268
+ phaseTimings.waitForRunStartMs = Date.now() - waitForRunStartStartedAt;
269
+ this.sessionLogger.debug({
270
+ agentId: input.agentId,
271
+ durationMs: Date.now() - startedAt,
272
+ ...phaseTimings,
273
+ }, 'Accepted send_agent_message_request execution started');
274
+ });
275
+ const trackedExecution = execution.finally(() => {
276
+ if (pendingAgentMessageExecutions.get(input.agentId) === trackedExecution) {
277
+ pendingAgentMessageExecutions.delete(input.agentId);
278
+ }
279
+ });
280
+ pendingAgentMessageExecutions.set(input.agentId, trackedExecution);
281
+ return trackedExecution;
282
+ }
283
+ async performAgentMessageSend(input) {
284
+ await this.ensureAgentLoaded(input.agentId);
285
+ await this.interruptAgentIfRunning(input.agentId);
286
+ try {
287
+ this.agentManager.recordUserMessage(input.agentId, input.text, {
288
+ messageId: input.messageId,
289
+ emitState: false,
290
+ images: input.images?.map((image) => ({
291
+ data: image.preview?.data ?? image.data,
292
+ mimeType: image.preview?.mimeType ?? image.mimeType,
293
+ ...(image.label ? { label: image.label } : {}),
294
+ ...(image.preview?.width != null ? { width: image.preview.width } : {}),
295
+ ...(image.preview?.height != null ? { height: image.preview.height } : {}),
296
+ })),
297
+ });
298
+ }
299
+ catch (error) {
300
+ this.sessionLogger.error({ err: error, agentId: input.agentId }, `Failed to record user message for agent ${input.agentId}`);
301
+ }
302
+ const prompt = this.buildAgentPrompt(input.text, input.images);
303
+ const started = this.startAgentStream(input.agentId, prompt, input.runOptions);
304
+ if (!started.ok) {
305
+ throw new Error(started.error);
306
+ }
307
+ }
250
308
  /**
251
309
  * Initialize Agent MCP client for this session using in-memory transport
252
310
  */
@@ -889,6 +947,9 @@ export class Session {
889
947
  case 'auto_route_provider_request':
890
948
  await this.handleAutoRouteProviderRequest(msg);
891
949
  break;
950
+ case 'update_notification_relay_config_request':
951
+ await this.handleUpdateNotificationRelayConfigRequest(msg);
952
+ break;
892
953
  case 'clear_agent_attention':
893
954
  await this.handleClearAgentAttention(msg.agentId);
894
955
  break;
@@ -1357,7 +1418,7 @@ export class Session {
1357
1418
  await this.agentManager.setTitle(agentId, normalizedName);
1358
1419
  }
1359
1420
  if (normalizedLabels) {
1360
- await this.agentManager.setLabels(agentId, normalizedLabels);
1421
+ await this.agentManager.setLabels(agentId, preserveNotificationRelayOwnerLabel(liveAgent.labels, normalizedLabels));
1361
1422
  }
1362
1423
  }
1363
1424
  else {
@@ -1368,7 +1429,11 @@ export class Session {
1368
1429
  await this.agentStorage.upsert({
1369
1430
  ...existing,
1370
1431
  ...(normalizedName ? { title: normalizedName } : {}),
1371
- ...(normalizedLabels ? { labels: { ...existing.labels, ...normalizedLabels } } : {}),
1432
+ ...(normalizedLabels
1433
+ ? {
1434
+ labels: preserveNotificationRelayOwnerLabel(existing.labels, normalizedLabels),
1435
+ }
1436
+ : {}),
1372
1437
  });
1373
1438
  }
1374
1439
  this.emit({
@@ -1409,30 +1474,17 @@ export class Session {
1409
1474
  return;
1410
1475
  }
1411
1476
  try {
1412
- await this.ensureAgentLoaded(agentId);
1413
- }
1414
- catch (error) {
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, {
1477
+ await this.performAgentMessageSend({
1478
+ agentId,
1479
+ text,
1428
1480
  messageId,
1429
- emitState: false,
1481
+ images,
1482
+ runOptions,
1430
1483
  });
1431
1484
  }
1432
1485
  catch (error) {
1433
- this.sessionLogger.error({ err: error, agentId }, `Failed to record user message for agent ${agentId}`);
1486
+ this.handleAgentRunError(agentId, error, 'Failed to send prompt to agent');
1434
1487
  }
1435
- this.startAgentStream(agentId, prompt, runOptions);
1436
1488
  }
1437
1489
  /**
1438
1490
  * Handle create agent request
@@ -1445,7 +1497,9 @@ export class Session {
1445
1497
  const mergedLabels = autoWorkspaceName
1446
1498
  ? { ...labels, 'junction:workspace': autoWorkspaceName }
1447
1499
  : labels;
1448
- const snapshot = await this.agentManager.createAgent(sessionConfig, undefined, { labels: mergedLabels });
1500
+ const snapshot = await this.agentManager.createAgent(sessionConfig, undefined, {
1501
+ labels: applyNotificationRelayOwnerLabel(mergedLabels, this.userId),
1502
+ });
1449
1503
  await this.forwardAgentUpdate(snapshot);
1450
1504
  if (requestId) {
1451
1505
  const agentPayload = await this.getAgentPayloadById(snapshot.id);
@@ -1941,6 +1995,46 @@ export class Session {
1941
1995
  });
1942
1996
  }
1943
1997
  }
1998
+ async handleUpdateNotificationRelayConfigRequest(msg) {
1999
+ try {
2000
+ const relayUrl = msg.relayUrl?.trim();
2001
+ const token = msg.token?.trim();
2002
+ const expiresAt = msg.expiresAt?.trim();
2003
+ const providedCount = [msg.relayUrl, msg.token, msg.expiresAt].filter((value) => value !== undefined).length;
2004
+ if (providedCount === 0) {
2005
+ saveNotificationRelayConfig(this.junctionHome, this.userId, null);
2006
+ }
2007
+ else if (providedCount !== 3 || !relayUrl || !token || !expiresAt) {
2008
+ throw new SessionRequestError('invalid_notification_relay_config', 'relayUrl, token, and expiresAt must be provided together');
2009
+ }
2010
+ else {
2011
+ saveNotificationRelayConfig(this.junctionHome, this.userId, {
2012
+ relayUrl,
2013
+ token,
2014
+ expiresAt,
2015
+ });
2016
+ }
2017
+ this.emit({
2018
+ type: 'update_notification_relay_config_response',
2019
+ payload: {
2020
+ success: true,
2021
+ error: null,
2022
+ requestId: msg.requestId,
2023
+ },
2024
+ });
2025
+ }
2026
+ catch (error) {
2027
+ this.sessionLogger.error({ err: error }, 'Failed to update notification relay config');
2028
+ this.emit({
2029
+ type: 'update_notification_relay_config_response',
2030
+ payload: {
2031
+ success: false,
2032
+ error: error instanceof Error ? error.message : String(error),
2033
+ requestId: msg.requestId,
2034
+ },
2035
+ });
2036
+ }
2037
+ }
1944
2038
  normalizeGitOptions(gitOptions, legacyWorktreeName) {
1945
2039
  const fallbackOptions = legacyWorktreeName
1946
2040
  ? {
@@ -4423,7 +4517,8 @@ export class Session {
4423
4517
  }
4424
4518
  try {
4425
4519
  const agentId = resolved.agentId;
4426
- const archivedAt = await this.getArchivedAt(agentId);
4520
+ const storedRecord = await this.agentStorage.get(agentId);
4521
+ const archivedAt = storedRecord?.archivedAt ?? null;
4427
4522
  if (archivedAt) {
4428
4523
  this.emit({
4429
4524
  type: 'send_agent_message_response',
@@ -4436,57 +4531,13 @@ export class Session {
4436
4531
  });
4437
4532
  return;
4438
4533
  }
4439
- await this.ensureAgentLoaded(agentId);
4440
- await this.interruptAgentIfRunning(agentId);
4441
- try {
4442
- this.agentManager.recordUserMessage(agentId, msg.text, {
4443
- messageId: msg.messageId,
4444
- emitState: false,
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
- }
4534
+ await this.enqueueAcceptedAgentMessageExecution({
4535
+ agentId,
4536
+ text: msg.text,
4537
+ ...(msg.messageId ? { messageId: msg.messageId } : {}),
4538
+ ...(msg.images ? { images: msg.images } : {}),
4539
+ runOptions: normalizeAgentRunOptions(msg.runOptions),
4540
+ });
4490
4541
  this.emit({
4491
4542
  type: 'send_agent_message_response',
4492
4543
  payload: {