@junctionpanel/server 0.1.32 → 0.1.34

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 (75) hide show
  1. package/dist/server/client/daemon-client.d.ts +6 -1
  2. package/dist/server/client/daemon-client.d.ts.map +1 -1
  3. package/dist/server/client/daemon-client.js +17 -0
  4. package/dist/server/client/daemon-client.js.map +1 -1
  5. package/dist/server/server/agent/agent-management-mcp.d.ts.map +1 -1
  6. package/dist/server/server/agent/agent-management-mcp.js +44 -7
  7. package/dist/server/server/agent/agent-management-mcp.js.map +1 -1
  8. package/dist/server/server/agent/agent-manager.d.ts +6 -0
  9. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  10. package/dist/server/server/agent/agent-manager.js +88 -10
  11. package/dist/server/server/agent/agent-manager.js.map +1 -1
  12. package/dist/server/server/agent/agent-permission-fingerprint.d.ts +6 -0
  13. package/dist/server/server/agent/agent-permission-fingerprint.d.ts.map +1 -0
  14. package/dist/server/server/agent/agent-permission-fingerprint.js +28 -0
  15. package/dist/server/server/agent/agent-permission-fingerprint.js.map +1 -0
  16. package/dist/server/server/agent/agent-projections.d.ts +1 -0
  17. package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
  18. package/dist/server/server/agent/agent-projections.js +61 -3
  19. package/dist/server/server/agent/agent-projections.js.map +1 -1
  20. package/dist/server/server/agent/agent-sdk-types.d.ts +10 -1
  21. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  22. package/dist/server/server/agent/agent-storage.d.ts +13 -0
  23. package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
  24. package/dist/server/server/agent/agent-storage.js +4 -2
  25. package/dist/server/server/agent/agent-storage.js.map +1 -1
  26. package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
  27. package/dist/server/server/agent/mcp-server.js +44 -7
  28. package/dist/server/server/agent/mcp-server.js.map +1 -1
  29. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  30. package/dist/server/server/agent/providers/codex-app-server-agent.js +4 -0
  31. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  32. package/dist/server/server/bootstrap.d.ts.map +1 -1
  33. package/dist/server/server/bootstrap.js +2 -1
  34. package/dist/server/server/bootstrap.js.map +1 -1
  35. package/dist/server/server/cli-runtime-exports.d.ts +2 -0
  36. package/dist/server/server/cli-runtime-exports.d.ts.map +1 -1
  37. package/dist/server/server/cli-runtime-exports.js +2 -0
  38. package/dist/server/server/cli-runtime-exports.js.map +1 -1
  39. package/dist/server/server/daemon-doctor.d.ts +4 -0
  40. package/dist/server/server/daemon-doctor.d.ts.map +1 -1
  41. package/dist/server/server/daemon-doctor.js +33 -12
  42. package/dist/server/server/daemon-doctor.js.map +1 -1
  43. package/dist/server/server/daemon-package-context.d.ts +10 -0
  44. package/dist/server/server/daemon-package-context.d.ts.map +1 -0
  45. package/dist/server/server/daemon-package-context.js +31 -0
  46. package/dist/server/server/daemon-package-context.js.map +1 -0
  47. package/dist/server/server/package-update.d.ts +32 -0
  48. package/dist/server/server/package-update.d.ts.map +1 -0
  49. package/dist/server/server/package-update.js +196 -0
  50. package/dist/server/server/package-update.js.map +1 -0
  51. package/dist/server/server/session.d.ts +1 -0
  52. package/dist/server/server/session.d.ts.map +1 -1
  53. package/dist/server/server/session.js +91 -85
  54. package/dist/server/server/session.js.map +1 -1
  55. package/dist/server/server/worktree-bootstrap.d.ts +2 -1
  56. package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
  57. package/dist/server/server/worktree-bootstrap.js +1 -0
  58. package/dist/server/server/worktree-bootstrap.js.map +1 -1
  59. package/dist/server/shared/messages.d.ts +617 -446
  60. package/dist/server/shared/messages.d.ts.map +1 -1
  61. package/dist/server/shared/messages.js +22 -1
  62. package/dist/server/shared/messages.js.map +1 -1
  63. package/dist/server/utils/checkout-git.d.ts +14 -0
  64. package/dist/server/utils/checkout-git.d.ts.map +1 -1
  65. package/dist/server/utils/checkout-git.js +73 -44
  66. package/dist/server/utils/checkout-git.js.map +1 -1
  67. package/dist/server/utils/worktree-metadata.d.ts +30 -0
  68. package/dist/server/utils/worktree-metadata.d.ts.map +1 -1
  69. package/dist/server/utils/worktree-metadata.js +38 -9
  70. package/dist/server/utils/worktree-metadata.js.map +1 -1
  71. package/dist/server/utils/worktree.d.ts +7 -3
  72. package/dist/server/utils/worktree.d.ts.map +1 -1
  73. package/dist/server/utils/worktree.js +91 -47
  74. package/dist/server/utils/worktree.js.map +1 -1
  75. package/package.json +2 -2
@@ -11,8 +11,9 @@ import { buildConfigOverrides, buildSessionConfig, extractTimestamps, extractTim
11
11
  import { experimental_createMCPClient } from 'ai';
12
12
  import { buildProviderRegistry } from './agent/provider-registry.js';
13
13
  import { applyProviderEnv, } from './agent/provider-launch-config.js';
14
+ import { buildPermissionRecoveryFingerprint } from './agent/agent-permission-fingerprint.js';
14
15
  import { scheduleAgentMetadataGeneration } from './agent/agent-metadata-generator.js';
15
- import { resolveEffectiveThinkingOptionId, toAgentPayload } from './agent/agent-projections.js';
16
+ import { toAgentPayload, resolveEffectiveThinkingOptionId, toStoredAgentPayload, } from './agent/agent-projections.js';
16
17
  import { appendTimelineItemIfAgentKnown, emitLiveTimelineItemIfAgentKnown, } from './agent/timeline-append.js';
17
18
  import { projectTimelineRows, selectTimelineWindowByProjectedLimit, } from './agent/timeline-projection.js';
18
19
  import { DEFAULT_STRUCTURED_GENERATION_PROVIDERS, StructuredAgentFallbackError, StructuredAgentResponseError, generateStructuredAgentResponseWithFallback, } from './agent/agent-response-loop.js';
@@ -21,7 +22,7 @@ import { listDirectoryEntries, readExplorerFile, getDownloadableFileInfo, } from
21
22
  import { slugify, validateBranchSlug, listJunctionWorktrees, deleteJunctionWorktree, isJunctionOwnedWorktreeCwd, resolveJunctionWorktreeRootForCwd, createInRepoWorktree, restoreInRepoWorktree, } from '../utils/worktree.js';
22
23
  import { readJunctionWorktreeMetadata } from '../utils/worktree-metadata.js';
23
24
  import { runAsyncWorktreeBootstrap } from './worktree-bootstrap.js';
24
- import { getCheckoutDiff, getCheckoutStatus, getCheckoutStatusLite, listBranchSuggestions, NotGitRepoError, MergeConflictError, MergeFromBaseConflictError, commitChanges, mergeToBase, mergeFromBase, pushCurrentBranch, createPullRequest, getPullRequestFailureLogs, getPullRequestStatus, listGitRemotes, mergePullRequest, resolveBaseRef, } from '../utils/checkout-git.js';
25
+ import { getCheckoutDiff, getCheckoutStatus, getCheckoutStatusLite, listBranchSuggestions, NotGitRepoError, MergeConflictError, MergeFromBaseConflictError, commitChanges, mergeToBase, mergeFromBase, pushCurrentBranch, createPullRequest, getPullRequestFailureLogs, getPullRequestStatus, listGitRemotes, mergePullRequest, resolveBaseRefWithSource, } from '../utils/checkout-git.js';
25
26
  import { getProjectIcon } from '../utils/project-icon.js';
26
27
  import { expandTilde } from '../utils/path.js';
27
28
  import { searchHomeDirectories, searchWorkspaceEntries, searchWorkspaceEntriesAtGitRef, searchGitRepositories, checkIsGitRepo, } from '../utils/directory-suggestions.js';
@@ -29,9 +30,10 @@ import { cloneRepository } from '../utils/git-clone.js';
29
30
  import { initRepository } from '../utils/git-init.js';
30
31
  import { resolveClientMessageId } from './client-message-id.js';
31
32
  import { deriveProjectGroupingKey, deriveProjectGroupingName } from '../shared/project-grouping.js';
32
- import { resolveDaemonVersion } from './daemon-version.js';
33
+ import { DEFAULT_DAEMON_PACKAGE_NAME, resolveDaemonPackageVersion, } from './daemon-package-context.js';
33
34
  import { runDaemonDoctor } from './daemon-doctor.js';
34
35
  import { MANAGED_DAEMON_PROVIDERS, autoRouteProviderExecutable, loadDaemonProviderSettings, saveDaemonProviderExecutablePath, } from './daemon-provider-settings.js';
36
+ import { resolvePackageUpdateInfo } from './package-update.js';
35
37
  import { loadPersistedConfig } from './persisted-config.js';
36
38
  const execAsync = promisify(exec);
37
39
  const READ_ONLY_GIT_ENV = {
@@ -338,63 +340,7 @@ export class Session {
338
340
  return payload;
339
341
  }
340
342
  buildStoredAgentPayload(record) {
341
- const defaultCapabilities = {
342
- supportsStreaming: false,
343
- supportsSessionPersistence: true,
344
- supportsDynamicModes: false,
345
- supportsMcpServers: false,
346
- supportsReasoningStream: false,
347
- supportsToolInvocations: true,
348
- };
349
- const createdAt = new Date(record.createdAt);
350
- const updatedAt = new Date(record.lastActivityAt ?? record.updatedAt);
351
- const lastUserMessageAt = record.lastUserMessageAt ? new Date(record.lastUserMessageAt) : null;
352
- const provider = coerceAgentProvider(this.sessionLogger, record.provider, record.id);
353
- const runtimeInfo = record.runtimeInfo
354
- ? {
355
- provider: coerceAgentProvider(this.sessionLogger, record.runtimeInfo.provider, record.id),
356
- sessionId: record.runtimeInfo.sessionId,
357
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'model')
358
- ? { model: record.runtimeInfo.model ?? null }
359
- : {}),
360
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'thinkingOptionId')
361
- ? { thinkingOptionId: record.runtimeInfo.thinkingOptionId ?? null }
362
- : {}),
363
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'modeId')
364
- ? { modeId: record.runtimeInfo.modeId ?? null }
365
- : {}),
366
- ...(record.runtimeInfo.extra ? { extra: record.runtimeInfo.extra } : {}),
367
- }
368
- : undefined;
369
- return {
370
- id: record.id,
371
- provider,
372
- cwd: record.cwd,
373
- model: record.config?.model ?? null,
374
- thinkingOptionId: record.config?.thinkingOptionId ?? null,
375
- effectiveThinkingOptionId: resolveEffectiveThinkingOptionId({
376
- runtimeInfo,
377
- configuredThinkingOptionId: record.config?.thinkingOptionId ?? null,
378
- }),
379
- ...(runtimeInfo ? { runtimeInfo } : {}),
380
- createdAt: createdAt.toISOString(),
381
- updatedAt: updatedAt.toISOString(),
382
- lastUserMessageAt: lastUserMessageAt ? lastUserMessageAt.toISOString() : null,
383
- status: record.lastStatus,
384
- capabilities: defaultCapabilities,
385
- currentModeId: record.lastModeId ?? null,
386
- availableModes: [],
387
- pendingPermissions: [],
388
- persistence: toAgentPersistenceHandle(this.sessionLogger, record.persistence),
389
- lastUsage: undefined,
390
- lastError: undefined,
391
- title: record.title ?? null,
392
- requiresAttention: record.requiresAttention ?? false,
393
- attentionReason: record.attentionReason ?? null,
394
- attentionTimestamp: record.attentionTimestamp ?? null,
395
- archivedAt: record.archivedAt ?? null,
396
- labels: record.labels,
397
- };
343
+ return toStoredAgentPayload(record);
398
344
  }
399
345
  fetchStoredTimeline(record, options) {
400
346
  const rows = (record.timelineRows ?? []).map((row) => ({ ...row }));
@@ -542,6 +488,7 @@ export class Session {
542
488
  this.sessionLogger.info({ agentId, provider: record.provider }, 'Agent created from stored config');
543
489
  }
544
490
  await this.agentManager.hydrateTimelineFromProvider(agentId);
491
+ await this.reconcilePersistedPendingPermissions(record, agentId);
545
492
  return this.agentManager.getAgent(agentId) ?? snapshot;
546
493
  })();
547
494
  pendingAgentInitializations.set(agentId, initPromise);
@@ -555,6 +502,45 @@ export class Session {
555
502
  }
556
503
  }
557
504
  }
505
+ async reconcilePersistedPendingPermissions(record, agentId) {
506
+ const persistedPending = record.pendingPermissions ?? [];
507
+ if (persistedPending.length === 0) {
508
+ return;
509
+ }
510
+ const liveAgent = this.agentManager.getAgent(agentId);
511
+ const sessionPending = liveAgent && liveAgent.lifecycle !== 'closed'
512
+ ? liveAgent.session.getPendingPermissions()
513
+ : [];
514
+ const recoveredIds = new Set(sessionPending.map((request) => request.id));
515
+ const recoveredFingerprints = new Set(sessionPending.map((request) => buildPermissionRecoveryFingerprint(request)));
516
+ const expiredRequests = persistedPending.filter((request) => {
517
+ if (recoveredIds.has(request.id)) {
518
+ return false;
519
+ }
520
+ return !recoveredFingerprints.has(buildPermissionRecoveryFingerprint(request));
521
+ });
522
+ if (expiredRequests.length === 0) {
523
+ return;
524
+ }
525
+ if (liveAgent && liveAgent.lifecycle !== 'closed') {
526
+ const expiredIds = new Set(expiredRequests.map((request) => request.id));
527
+ const expiredFingerprints = new Set(expiredRequests.map((request) => buildPermissionRecoveryFingerprint(request)));
528
+ this.agentManager.prunePendingPermissions(agentId, {
529
+ requestIds: expiredIds,
530
+ requestFingerprints: expiredFingerprints,
531
+ settleLifecycleIfInactive: sessionPending.length === 0,
532
+ });
533
+ }
534
+ if (sessionPending.length === 0) {
535
+ await this.agentManager.clearAgentAttention(agentId);
536
+ }
537
+ const requestLabel = expiredRequests.length === 1 ? 'approval request' : `${expiredRequests.length} approval requests`;
538
+ await this.agentManager.appendTimelineItem(agentId, {
539
+ type: 'error',
540
+ message: `${requestLabel} expired while the daemon was offline. Re-run the request if you still want to continue.`,
541
+ });
542
+ this.agentManager.notifyAgentState(agentId);
543
+ }
558
544
  matchesAgentFilter(options) {
559
545
  const { agent, project, filter } = options;
560
546
  if (filter?.labels) {
@@ -1209,6 +1195,8 @@ export class Session {
1209
1195
  restoredWorktree = await restoreInRepoWorktree({
1210
1196
  repoRoot: record.archivedWorktree.repoRoot,
1211
1197
  baseBranch: record.archivedWorktree.baseBranch,
1198
+ baseBranchSource: record.archivedWorktree.baseBranchSource ?? 'remote',
1199
+ remoteName: record.archivedWorktree.remoteName ?? undefined,
1212
1200
  branchName: record.archivedWorktree.branchName,
1213
1201
  worktreeSlug: record.archivedWorktree.worktreeSlug,
1214
1202
  runSetup: false,
@@ -1322,6 +1310,8 @@ export class Session {
1322
1310
  return {
1323
1311
  repoRoot: ownership.repoRoot,
1324
1312
  baseBranch: metadata.baseRefName,
1313
+ baseBranchSource: metadata.version === 3 ? metadata.baseBranchSource : 'remote',
1314
+ remoteName: metadata.version === 3 ? metadata.remoteName ?? null : null,
1325
1315
  branchName,
1326
1316
  worktreeSlug: basename(resolvedWorktree.worktreePath),
1327
1317
  originalCwd: resolvedWorktree.worktreePath,
@@ -1719,15 +1709,26 @@ export class Session {
1719
1709
  };
1720
1710
  }
1721
1711
  }
1722
- const baseBranch = normalized?.baseBranch ?? (await resolveBaseRef(repoRoot, { remoteName: normalized?.remoteName }));
1712
+ const resolvedBase = normalized?.baseBranch
1713
+ ? {
1714
+ ref: normalized.baseBranch,
1715
+ source: normalized.baseBranchSource ?? 'remote',
1716
+ remoteName: normalized?.remoteName ?? null,
1717
+ }
1718
+ : await resolveBaseRefWithSource(repoRoot, {
1719
+ remoteName: normalized?.remoteName,
1720
+ source: normalized?.baseBranchSource ?? 'remote',
1721
+ });
1722
+ const baseBranch = resolvedBase.ref;
1723
1723
  if (!baseBranch) {
1724
1724
  throw new Error('Unable to determine a base branch for worktree creation');
1725
1725
  }
1726
- this.sessionLogger.info({ repoRoot, baseBranch }, 'Creating in-repo worktree for new agent');
1726
+ this.sessionLogger.info({ repoRoot, baseBranch, baseBranchSource: resolvedBase.source }, 'Creating in-repo worktree for new agent');
1727
1727
  const createdWorktree = await createInRepoWorktree({
1728
1728
  repoRoot,
1729
1729
  baseBranch,
1730
- remoteName: normalized?.remoteName,
1730
+ baseBranchSource: resolvedBase.source,
1731
+ remoteName: resolvedBase.remoteName ?? normalized?.remoteName,
1731
1732
  runSetup: false,
1732
1733
  });
1733
1734
  return {
@@ -1797,12 +1798,7 @@ export class Session {
1797
1798
  }
1798
1799
  }
1799
1800
  resolveDaemonVersionSafe() {
1800
- try {
1801
- return resolveDaemonVersion(import.meta.url);
1802
- }
1803
- catch {
1804
- return null;
1805
- }
1801
+ return resolveDaemonPackageVersion(import.meta.url);
1806
1802
  }
1807
1803
  toDaemonMetadata(input) {
1808
1804
  const homeDir = input?.homeDir ?? homedir();
@@ -1822,6 +1818,7 @@ export class Session {
1822
1818
  type: 'run_daemon_doctor_response',
1823
1819
  payload: {
1824
1820
  daemon: result.daemon,
1821
+ update: result.update,
1825
1822
  summary: result.summary,
1826
1823
  checks: result.checks,
1827
1824
  ranAt: result.ranAt,
@@ -1837,6 +1834,11 @@ export class Session {
1837
1834
  type: 'run_daemon_doctor_response',
1838
1835
  payload: {
1839
1836
  daemon: this.toDaemonMetadata(snapshot),
1837
+ update: resolvePackageUpdateInfo({
1838
+ npmInvocation: null,
1839
+ packageName: DEFAULT_DAEMON_PACKAGE_NAME,
1840
+ currentVersion: this.resolveDaemonVersionSafe(),
1841
+ }),
1840
1842
  summary: 'fail',
1841
1843
  checks: [],
1842
1844
  ranAt: new Date().toISOString(),
@@ -1914,21 +1916,16 @@ export class Session {
1914
1916
  if (!executablePath) {
1915
1917
  throw new SessionRequestError('provider_not_found', `Could not automatically locate ${msg.provider} on this daemon.`);
1916
1918
  }
1917
- const snapshot = saveDaemonProviderExecutablePath({
1918
- junctionHome: this.junctionHome,
1919
- provider: msg.provider,
1920
- executablePath,
1921
- });
1922
1919
  this.emit({
1923
1920
  type: 'auto_route_provider_response',
1924
1921
  payload: {
1925
- daemon: this.toDaemonMetadata(snapshot),
1926
- provider: snapshot.providers[msg.provider],
1922
+ daemon: this.toDaemonMetadata(),
1923
+ provider: msg.provider,
1924
+ executablePath,
1927
1925
  error: null,
1928
1926
  requestId: msg.requestId,
1929
1927
  },
1930
1928
  });
1931
- await this.handleRestartServerRequest(msg.requestId, 'settings_update');
1932
1929
  }
1933
1930
  catch (error) {
1934
1931
  this.sessionLogger.error({ err: error, provider: msg.provider }, 'Failed to auto-route provider executable');
@@ -1936,7 +1933,8 @@ export class Session {
1936
1933
  type: 'auto_route_provider_response',
1937
1934
  payload: {
1938
1935
  daemon: this.toDaemonMetadata(),
1939
- provider: null,
1936
+ provider: msg.provider,
1937
+ executablePath: null,
1940
1938
  error: error instanceof Error ? error.message : String(error),
1941
1939
  requestId: msg.requestId,
1942
1940
  },
@@ -1957,6 +1955,7 @@ export class Session {
1957
1955
  return null;
1958
1956
  }
1959
1957
  const baseBranch = merged.baseBranch?.trim() || undefined;
1958
+ const baseBranchSource = merged.baseBranchSource ?? 'remote';
1960
1959
  const remoteName = merged.remoteName?.trim() || undefined;
1961
1960
  const createWorktree = Boolean(merged.createWorktree);
1962
1961
  const createNewBranch = Boolean(merged.createNewBranch);
@@ -1973,12 +1972,6 @@ export class Session {
1973
1972
  if (remoteName) {
1974
1973
  this.assertSafeRemoteName(remoteName);
1975
1974
  }
1976
- if (createWorktree && !baseBranch) {
1977
- throw new Error('Base branch is required when creating a worktree');
1978
- }
1979
- if (createNewBranch && !baseBranch) {
1980
- throw new Error('Base branch is required when creating a new branch');
1981
- }
1982
1975
  if (createNewBranch) {
1983
1976
  if (!normalizedBranchName) {
1984
1977
  throw new Error('New branch name is required');
@@ -1996,6 +1989,7 @@ export class Session {
1996
1989
  }
1997
1990
  return {
1998
1991
  baseBranch,
1992
+ baseBranchSource,
1999
1993
  remoteName,
2000
1994
  createNewBranch,
2001
1995
  newBranchName: normalizedBranchName,
@@ -2599,6 +2593,8 @@ export class Session {
2599
2593
  const branches = await listBranchSuggestions(resolvedCwd, {
2600
2594
  query,
2601
2595
  limit,
2596
+ preferredBranches: msg.preferredBranches,
2597
+ source: msg.source,
2602
2598
  remoteName: msg.remoteName,
2603
2599
  });
2604
2600
  this.emit({
@@ -4219,6 +4215,15 @@ export class Session {
4219
4215
  });
4220
4216
  return;
4221
4217
  }
4218
+ const existing = this.agentManager.getAgent(resolved.agentId);
4219
+ if (!existing) {
4220
+ const record = await this.agentStorage.get(resolved.agentId);
4221
+ if (record && !record.internal && !record.archivedAt) {
4222
+ await this.ensureAgentLoaded(resolved.agentId).catch((error) => {
4223
+ this.sessionLogger.warn({ err: error, agentId: resolved.agentId }, 'Failed to lazily load agent before fetch_agent_response; falling back to stored state');
4224
+ });
4225
+ }
4226
+ }
4222
4227
  const agent = await this.getAgentPayloadById(resolved.agentId);
4223
4228
  if (!agent) {
4224
4229
  this.emit({
@@ -4535,7 +4540,8 @@ export class Session {
4535
4540
  return;
4536
4541
  }
4537
4542
  const final = this.buildStoredAgentPayload(record);
4538
- const status = record.attentionReason === 'permission'
4543
+ const hasPendingPermission = final.pendingPermissions.length > 0;
4544
+ const status = hasPendingPermission
4539
4545
  ? 'permission'
4540
4546
  : record.lastStatus === 'error'
4541
4547
  ? 'error'