@junctionpanel/server 0.1.33 → 0.1.35

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 +2 -0
  2. package/dist/server/client/daemon-client.d.ts.map +1 -1
  3. package/dist/server/client/daemon-client.js +2 -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 +5 -0
  9. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  10. package/dist/server/server/agent/agent-manager.js +66 -12
  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 +5 -0
  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/claude-agent.d.ts.map +1 -1
  30. package/dist/server/server/agent/providers/claude-agent.js +38 -90
  31. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  32. package/dist/server/server/agent/providers/claude-cli-capabilities.d.ts +50 -0
  33. package/dist/server/server/agent/providers/claude-cli-capabilities.d.ts.map +1 -0
  34. package/dist/server/server/agent/providers/claude-cli-capabilities.js +247 -0
  35. package/dist/server/server/agent/providers/claude-cli-capabilities.js.map +1 -0
  36. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  37. package/dist/server/server/agent/providers/codex-app-server-agent.js +4 -0
  38. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  39. package/dist/server/server/agent/providers/gemini-agent.d.ts +287 -1
  40. package/dist/server/server/agent/providers/gemini-agent.d.ts.map +1 -1
  41. package/dist/server/server/agent/providers/gemini-agent.js +255 -16
  42. package/dist/server/server/agent/providers/gemini-agent.js.map +1 -1
  43. package/dist/server/server/daemon-doctor.d.ts +5 -0
  44. package/dist/server/server/daemon-doctor.d.ts.map +1 -1
  45. package/dist/server/server/daemon-doctor.js +26 -0
  46. package/dist/server/server/daemon-doctor.js.map +1 -1
  47. package/dist/server/server/file-explorer/service.d.ts +1 -0
  48. package/dist/server/server/file-explorer/service.d.ts.map +1 -1
  49. package/dist/server/server/file-explorer/service.js +36 -0
  50. package/dist/server/server/file-explorer/service.js.map +1 -1
  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 +82 -71
  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 +424 -218
  60. package/dist/server/shared/messages.d.ts.map +1 -1
  61. package/dist/server/shared/messages.js +9 -0
  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,17 +11,18 @@ 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';
19
20
  import { isValidAgentProvider, AGENT_PROVIDER_IDS } from './agent/provider-manifest.js';
20
- import { listDirectoryEntries, readExplorerFile, getDownloadableFileInfo, } from './file-explorer/service.js';
21
+ import { listDirectoryEntries, readExplorerFile, getDownloadableFileInfo, isWorkspaceExplorerMissingPathError, } from './file-explorer/service.js';
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';
@@ -339,63 +340,7 @@ export class Session {
339
340
  return payload;
340
341
  }
341
342
  buildStoredAgentPayload(record) {
342
- const defaultCapabilities = {
343
- supportsStreaming: false,
344
- supportsSessionPersistence: true,
345
- supportsDynamicModes: false,
346
- supportsMcpServers: false,
347
- supportsReasoningStream: false,
348
- supportsToolInvocations: true,
349
- };
350
- const createdAt = new Date(record.createdAt);
351
- const updatedAt = new Date(record.lastActivityAt ?? record.updatedAt);
352
- const lastUserMessageAt = record.lastUserMessageAt ? new Date(record.lastUserMessageAt) : null;
353
- const provider = coerceAgentProvider(this.sessionLogger, record.provider, record.id);
354
- const runtimeInfo = record.runtimeInfo
355
- ? {
356
- provider: coerceAgentProvider(this.sessionLogger, record.runtimeInfo.provider, record.id),
357
- sessionId: record.runtimeInfo.sessionId,
358
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'model')
359
- ? { model: record.runtimeInfo.model ?? null }
360
- : {}),
361
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'thinkingOptionId')
362
- ? { thinkingOptionId: record.runtimeInfo.thinkingOptionId ?? null }
363
- : {}),
364
- ...(Object.prototype.hasOwnProperty.call(record.runtimeInfo, 'modeId')
365
- ? { modeId: record.runtimeInfo.modeId ?? null }
366
- : {}),
367
- ...(record.runtimeInfo.extra ? { extra: record.runtimeInfo.extra } : {}),
368
- }
369
- : undefined;
370
- return {
371
- id: record.id,
372
- provider,
373
- cwd: record.cwd,
374
- model: record.config?.model ?? null,
375
- thinkingOptionId: record.config?.thinkingOptionId ?? null,
376
- effectiveThinkingOptionId: resolveEffectiveThinkingOptionId({
377
- runtimeInfo,
378
- configuredThinkingOptionId: record.config?.thinkingOptionId ?? null,
379
- }),
380
- ...(runtimeInfo ? { runtimeInfo } : {}),
381
- createdAt: createdAt.toISOString(),
382
- updatedAt: updatedAt.toISOString(),
383
- lastUserMessageAt: lastUserMessageAt ? lastUserMessageAt.toISOString() : null,
384
- status: record.lastStatus,
385
- capabilities: defaultCapabilities,
386
- currentModeId: record.lastModeId ?? null,
387
- availableModes: [],
388
- pendingPermissions: [],
389
- persistence: toAgentPersistenceHandle(this.sessionLogger, record.persistence),
390
- lastUsage: undefined,
391
- lastError: undefined,
392
- title: record.title ?? null,
393
- requiresAttention: record.requiresAttention ?? false,
394
- attentionReason: record.attentionReason ?? null,
395
- attentionTimestamp: record.attentionTimestamp ?? null,
396
- archivedAt: record.archivedAt ?? null,
397
- labels: record.labels,
398
- };
343
+ return toStoredAgentPayload(record);
399
344
  }
400
345
  fetchStoredTimeline(record, options) {
401
346
  const rows = (record.timelineRows ?? []).map((row) => ({ ...row }));
@@ -543,6 +488,7 @@ export class Session {
543
488
  this.sessionLogger.info({ agentId, provider: record.provider }, 'Agent created from stored config');
544
489
  }
545
490
  await this.agentManager.hydrateTimelineFromProvider(agentId);
491
+ await this.reconcilePersistedPendingPermissions(record, agentId);
546
492
  return this.agentManager.getAgent(agentId) ?? snapshot;
547
493
  })();
548
494
  pendingAgentInitializations.set(agentId, initPromise);
@@ -556,6 +502,45 @@ export class Session {
556
502
  }
557
503
  }
558
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
+ }
559
544
  matchesAgentFilter(options) {
560
545
  const { agent, project, filter } = options;
561
546
  if (filter?.labels) {
@@ -1210,6 +1195,8 @@ export class Session {
1210
1195
  restoredWorktree = await restoreInRepoWorktree({
1211
1196
  repoRoot: record.archivedWorktree.repoRoot,
1212
1197
  baseBranch: record.archivedWorktree.baseBranch,
1198
+ baseBranchSource: record.archivedWorktree.baseBranchSource ?? 'remote',
1199
+ remoteName: record.archivedWorktree.remoteName ?? undefined,
1213
1200
  branchName: record.archivedWorktree.branchName,
1214
1201
  worktreeSlug: record.archivedWorktree.worktreeSlug,
1215
1202
  runSetup: false,
@@ -1323,6 +1310,8 @@ export class Session {
1323
1310
  return {
1324
1311
  repoRoot: ownership.repoRoot,
1325
1312
  baseBranch: metadata.baseRefName,
1313
+ baseBranchSource: metadata.version === 3 ? metadata.baseBranchSource : 'remote',
1314
+ remoteName: metadata.version === 3 ? metadata.remoteName ?? null : null,
1326
1315
  branchName,
1327
1316
  worktreeSlug: basename(resolvedWorktree.worktreePath),
1328
1317
  originalCwd: resolvedWorktree.worktreePath,
@@ -1720,15 +1709,26 @@ export class Session {
1720
1709
  };
1721
1710
  }
1722
1711
  }
1723
- 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;
1724
1723
  if (!baseBranch) {
1725
1724
  throw new Error('Unable to determine a base branch for worktree creation');
1726
1725
  }
1727
- 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');
1728
1727
  const createdWorktree = await createInRepoWorktree({
1729
1728
  repoRoot,
1730
1729
  baseBranch,
1731
- remoteName: normalized?.remoteName,
1730
+ baseBranchSource: resolvedBase.source,
1731
+ remoteName: resolvedBase.remoteName ?? normalized?.remoteName,
1732
1732
  runSetup: false,
1733
1733
  });
1734
1734
  return {
@@ -1955,6 +1955,7 @@ export class Session {
1955
1955
  return null;
1956
1956
  }
1957
1957
  const baseBranch = merged.baseBranch?.trim() || undefined;
1958
+ const baseBranchSource = merged.baseBranchSource ?? 'remote';
1958
1959
  const remoteName = merged.remoteName?.trim() || undefined;
1959
1960
  const createWorktree = Boolean(merged.createWorktree);
1960
1961
  const createNewBranch = Boolean(merged.createNewBranch);
@@ -1971,12 +1972,6 @@ export class Session {
1971
1972
  if (remoteName) {
1972
1973
  this.assertSafeRemoteName(remoteName);
1973
1974
  }
1974
- if (createWorktree && !baseBranch) {
1975
- throw new Error('Base branch is required when creating a worktree');
1976
- }
1977
- if (createNewBranch && !baseBranch) {
1978
- throw new Error('Base branch is required when creating a new branch');
1979
- }
1980
1975
  if (createNewBranch) {
1981
1976
  if (!normalizedBranchName) {
1982
1977
  throw new Error('New branch name is required');
@@ -1994,6 +1989,7 @@ export class Session {
1994
1989
  }
1995
1990
  return {
1996
1991
  baseBranch,
1992
+ baseBranchSource,
1997
1993
  remoteName,
1998
1994
  createNewBranch,
1999
1995
  newBranchName: normalizedBranchName,
@@ -2597,6 +2593,8 @@ export class Session {
2597
2593
  const branches = await listBranchSuggestions(resolvedCwd, {
2598
2594
  query,
2599
2595
  limit,
2596
+ preferredBranches: msg.preferredBranches,
2597
+ source: msg.source,
2600
2598
  remoteName: msg.remoteName,
2601
2599
  });
2602
2600
  this.emit({
@@ -3745,7 +3743,10 @@ export class Session {
3745
3743
  }
3746
3744
  }
3747
3745
  catch (error) {
3748
- this.sessionLogger.error({ err: error, cwd, path: requestedPath }, `Failed to fulfill workspace file explorer request for cwd ${cwd}`);
3746
+ const log = isWorkspaceExplorerMissingPathError(error)
3747
+ ? this.sessionLogger.debug.bind(this.sessionLogger)
3748
+ : this.sessionLogger.error.bind(this.sessionLogger);
3749
+ log({ err: error, cwd, path: requestedPath }, `Failed to fulfill workspace file explorer request for cwd ${cwd}`);
3749
3750
  this.emit({
3750
3751
  type: 'workspace_file_explorer_response',
3751
3752
  payload: {
@@ -4217,6 +4218,15 @@ export class Session {
4217
4218
  });
4218
4219
  return;
4219
4220
  }
4221
+ const existing = this.agentManager.getAgent(resolved.agentId);
4222
+ if (!existing) {
4223
+ const record = await this.agentStorage.get(resolved.agentId);
4224
+ if (record && !record.internal && !record.archivedAt) {
4225
+ await this.ensureAgentLoaded(resolved.agentId).catch((error) => {
4226
+ this.sessionLogger.warn({ err: error, agentId: resolved.agentId }, 'Failed to lazily load agent before fetch_agent_response; falling back to stored state');
4227
+ });
4228
+ }
4229
+ }
4220
4230
  const agent = await this.getAgentPayloadById(resolved.agentId);
4221
4231
  if (!agent) {
4222
4232
  this.emit({
@@ -4533,7 +4543,8 @@ export class Session {
4533
4543
  return;
4534
4544
  }
4535
4545
  const final = this.buildStoredAgentPayload(record);
4536
- const status = record.attentionReason === 'permission'
4546
+ const hasPendingPermission = final.pendingPermissions.length > 0;
4547
+ const status = hasPendingPermission
4537
4548
  ? 'permission'
4538
4549
  : record.lastStatus === 'error'
4539
4550
  ? 'error'