@getpaseo/server 0.1.88 → 0.1.90

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 (94) hide show
  1. package/dist/server/server/agent/agent-manager.js +4 -1
  2. package/dist/server/server/agent/agent-prompt.js +4 -1
  3. package/dist/server/server/agent/agent-sdk-types.d.ts +1 -0
  4. package/dist/server/server/agent/agent-storage.d.ts +22 -22
  5. package/dist/server/server/agent/agent-storage.js +2 -9
  6. package/dist/server/server/agent/create-agent/create.d.ts +2 -0
  7. package/dist/server/server/agent/create-agent/create.js +26 -7
  8. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +1 -0
  9. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +4 -0
  10. package/dist/server/server/agent/create-agent-mode.d.ts +3 -8
  11. package/dist/server/server/agent/create-agent-mode.js +16 -2
  12. package/dist/server/server/agent/import-sessions.js +1 -1
  13. package/dist/server/server/agent/mcp-server.d.ts +1 -0
  14. package/dist/server/server/agent/mcp-server.js +113 -70
  15. package/dist/server/server/agent/provider-snapshot-manager.d.ts +2 -1
  16. package/dist/server/server/agent/provider-snapshot-manager.js +18 -2
  17. package/dist/server/server/agent/providers/acp-agent.d.ts +3 -3
  18. package/dist/server/server/agent/providers/acp-agent.js +18 -13
  19. package/dist/server/server/agent/providers/codex-app-server-agent.js +16 -22
  20. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -0
  21. package/dist/server/server/agent/providers/mock-load-test-agent.js +69 -2
  22. package/dist/server/server/agent/providers/opencode-agent.js +19 -8
  23. package/dist/server/server/agent/providers/pi/agent.js +13 -0
  24. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +3 -0
  25. package/dist/server/server/agent/timeline-projection.js +30 -1
  26. package/dist/server/server/atomic-file.d.ts +3 -0
  27. package/dist/server/server/atomic-file.js +19 -0
  28. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +1 -0
  29. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +10 -2
  30. package/dist/server/server/bootstrap.d.ts +7 -2
  31. package/dist/server/server/bootstrap.js +154 -115
  32. package/dist/server/server/chat/chat-service.js +2 -4
  33. package/dist/server/server/config.js +41 -0
  34. package/dist/server/server/daemon-keypair.js +2 -2
  35. package/dist/server/server/loop-service.d.ts +26 -22
  36. package/dist/server/server/loop-service.js +27 -9
  37. package/dist/server/server/package-version.d.ts +2 -2
  38. package/dist/server/server/paseo-worktree-archive-service.d.ts +2 -0
  39. package/dist/server/server/paseo-worktree-archive-service.js +28 -9
  40. package/dist/server/server/persisted-config.d.ts +84 -28
  41. package/dist/server/server/persisted-config.js +20 -3
  42. package/dist/server/server/pid-lock.d.ts +2 -2
  43. package/dist/server/server/private-files.d.ts +0 -1
  44. package/dist/server/server/private-files.js +0 -5
  45. package/dist/server/server/schedule/service.d.ts +6 -0
  46. package/dist/server/server/schedule/service.js +41 -18
  47. package/dist/server/server/schedule/store.js +3 -2
  48. package/dist/server/server/script-health-monitor.d.ts +4 -4
  49. package/dist/server/server/script-health-monitor.js +6 -6
  50. package/dist/server/server/script-proxy.d.ts +2 -39
  51. package/dist/server/server/script-proxy.js +1 -244
  52. package/dist/server/server/script-route-branch-handler.d.ts +2 -2
  53. package/dist/server/server/script-route-branch-handler.js +3 -37
  54. package/dist/server/server/script-status-projection.d.ts +6 -4
  55. package/dist/server/server/script-status-projection.js +85 -37
  56. package/dist/server/server/server-id.js +3 -3
  57. package/dist/server/server/service-proxy.d.ts +237 -0
  58. package/dist/server/server/service-proxy.js +714 -0
  59. package/dist/server/server/session.d.ts +12 -18
  60. package/dist/server/server/session.js +206 -117
  61. package/dist/server/server/speech/providers/local/worker-client.js +1 -11
  62. package/dist/server/server/websocket-server.d.ts +7 -4
  63. package/dist/server/server/websocket-server.js +9 -4
  64. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  65. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  66. package/dist/server/server/workspace-directory.d.ts +8 -0
  67. package/dist/server/server/workspace-directory.js +141 -11
  68. package/dist/server/server/workspace-git-service.d.ts +3 -0
  69. package/dist/server/server/workspace-git-service.js +53 -12
  70. package/dist/server/server/workspace-registry.d.ts +2 -2
  71. package/dist/server/server/workspace-registry.js +2 -6
  72. package/dist/server/server/workspace-service-env.d.ts +1 -0
  73. package/dist/server/server/workspace-service-env.js +23 -18
  74. package/dist/server/server/worktree/commands.d.ts +2 -0
  75. package/dist/server/server/worktree/commands.js +4 -1
  76. package/dist/server/server/worktree-bootstrap.d.ts +4 -3
  77. package/dist/server/server/worktree-bootstrap.js +14 -13
  78. package/dist/server/server/worktree-core.d.ts +1 -0
  79. package/dist/server/server/worktree-core.js +2 -0
  80. package/dist/server/server/worktree-session.d.ts +6 -2
  81. package/dist/server/server/worktree-session.js +3 -0
  82. package/dist/server/services/github-service.d.ts +1 -0
  83. package/dist/server/services/github-service.js +7 -1
  84. package/dist/server/utils/checkout-git.d.ts +6 -3
  85. package/dist/server/utils/checkout-git.js +40 -38
  86. package/dist/server/utils/worktree.d.ts +17 -12
  87. package/dist/server/utils/worktree.js +39 -22
  88. package/dist/src/server/persisted-config.js +20 -3
  89. package/dist/src/server/private-files.js +0 -5
  90. package/package.json +9 -7
  91. package/dist/server/server/editor-targets.d.ts +0 -18
  92. package/dist/server/server/editor-targets.js +0 -109
  93. package/dist/server/utils/script-hostname.d.ts +0 -8
  94. package/dist/server/utils/script-hostname.js +0 -14
@@ -17,6 +17,7 @@ export async function createPaseoWorktreeCommand(dependencies, input) {
17
17
  ...input,
18
18
  runSetup: false,
19
19
  paseoHome: input.paseoHome ?? dependencies.paseoHome,
20
+ worktreesRoot: input.worktreesRoot ?? dependencies.worktreesRoot,
20
21
  });
21
22
  return { ok: true, createdWorktree };
22
23
  }
@@ -32,6 +33,7 @@ export async function archivePaseoWorktreeCommand(dependencies, input) {
32
33
  const resolvedTarget = await resolveArchiveTarget(dependencies, input);
33
34
  const ownership = await isPaseoOwnedWorktreeCwd(resolvedTarget.targetPath, {
34
35
  paseoHome: dependencies.paseoHome,
36
+ worktreesRoot: dependencies.worktreesRoot,
35
37
  });
36
38
  if (!ownership.allowed) {
37
39
  return {
@@ -46,6 +48,7 @@ export async function archivePaseoWorktreeCommand(dependencies, input) {
46
48
  targetPath: resolvedTarget.targetPath,
47
49
  repoRoot,
48
50
  worktreesRoot: ownership.worktreeRoot,
51
+ worktreesBaseRoot: dependencies.worktreesRoot,
49
52
  requestId: input.requestId,
50
53
  });
51
54
  return {
@@ -78,7 +81,7 @@ async function resolveArchiveTarget(dependencies, input) {
78
81
  throw new Error("worktreePath, worktreeSlug, or repoRoot+branchName is required");
79
82
  }
80
83
  async function resolveWorktreeSlugPath(dependencies, repoRoot, worktreeSlug) {
81
- const worktreesRoot = await getPaseoWorktreesRoot(repoRoot, dependencies.paseoHome);
84
+ const worktreesRoot = await getPaseoWorktreesRoot(repoRoot, dependencies.paseoHome, dependencies.worktreesRoot);
82
85
  return join(worktreesRoot, worktreeSlug);
83
86
  }
84
87
  //# sourceMappingURL=commands.js.map
@@ -1,7 +1,7 @@
1
1
  import type { Logger } from "pino";
2
2
  import type { TerminalManager } from "../terminal/terminal-manager.js";
3
3
  import { runWorktreeSetupCommands, type WorktreeConfig, type WorktreeSetupCommandResult } from "../utils/worktree.js";
4
- import { type ScriptRouteStore } from "./script-proxy.js";
4
+ import { type ServiceProxySubsystem } from "./service-proxy.js";
5
5
  import type { WorkspaceScriptRuntimeStore } from "./workspace-script-runtime-store.js";
6
6
  import type { AgentTimelineItem, ToolCallDetail } from "./agent/agent-sdk-types.js";
7
7
  export interface WorktreeBootstrapTerminalResult {
@@ -58,7 +58,8 @@ interface SpawnWorkspaceScriptOptions {
58
58
  scriptName: string;
59
59
  daemonPort?: number | null;
60
60
  daemonListenHost?: string | null;
61
- routeStore: ScriptRouteStore;
61
+ serviceProxyPublicBaseUrl?: string | null;
62
+ serviceProxy: ServiceProxySubsystem;
62
63
  runtimeStore: WorkspaceScriptRuntimeStore;
63
64
  terminalManager: TerminalManager;
64
65
  logger?: Logger;
@@ -67,7 +68,7 @@ interface SpawnWorkspaceScriptOptions {
67
68
  export declare function spawnWorkspaceScript(options: SpawnWorkspaceScriptOptions): Promise<WorktreeScriptResult>;
68
69
  export declare function teardownWorktreeScripts(options: {
69
70
  hostnames: string[];
70
- routeStore: ScriptRouteStore;
71
+ serviceProxy: Pick<ServiceProxySubsystem, "removeServiceRoutesByHostnames">;
71
72
  logger: Logger;
72
73
  }): void;
73
74
  export {};
@@ -1,7 +1,6 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- import { buildScriptHostname } from "../utils/script-hostname.js";
3
2
  import { getScriptConfigs, getWorktreeTerminalSpecs, isServiceScript, paseoConfigParseError, processCarriageReturns, readPaseoConfig, resolveWorktreeRuntimeEnv, runWorktreeSetupCommands, WorktreeSetupError, } from "../utils/worktree.js";
4
- import { findFreePort } from "./script-proxy.js";
3
+ import { findFreePort } from "./service-proxy.js";
5
4
  import { assertNoServiceEnvNameCollisions, buildWorkspaceServiceEnv, } from "./workspace-service-env.js";
6
5
  import { ensureWorkspaceServicePortPlan, requirePlannedWorkspaceServicePort, refreshWorkspaceServicePort, } from "./workspace-service-port-registry.js";
7
6
  const MAX_WORKTREE_SETUP_COMMAND_OUTPUT_BYTES = 64 * 1024;
@@ -501,8 +500,7 @@ export async function runAsyncWorktreeBootstrap(options) {
501
500
  await runWorktreeTerminalBootstrap(options, runtimeEnv);
502
501
  }
503
502
  async function setupServiceScriptRoute(params) {
504
- const { scriptConfigs, config, scriptName, projectSlug, branchName, workspaceId, daemonPort, daemonListenHost, existingRuntimeEntry, routeStore, } = params;
505
- const hostname = buildScriptHostname({ projectSlug, branchName, scriptName });
503
+ const { scriptConfigs, config, scriptName, projectSlug, branchName, workspaceId, daemonPort, daemonListenHost, serviceProxyPublicBaseUrl, existingRuntimeEntry, serviceProxy, } = params;
506
504
  const serviceDeclarations = [];
507
505
  for (const [configuredScriptName, scriptConfig] of scriptConfigs) {
508
506
  if (isServiceScript(scriptConfig)) {
@@ -538,16 +536,18 @@ async function setupServiceScriptRoute(params) {
538
536
  branchName,
539
537
  daemonPort,
540
538
  daemonListenHost,
539
+ serviceProxyPublicBaseUrl,
541
540
  peers,
542
541
  });
543
- routeStore.registerRoute({
544
- hostname,
542
+ const registeredRoute = serviceProxy.registerWorkspaceService({
545
543
  port,
546
544
  workspaceId,
547
545
  projectSlug,
546
+ branchName,
548
547
  scriptName,
548
+ publicBaseUrl: serviceProxyPublicBaseUrl ?? null,
549
549
  });
550
- return { hostname, port, env };
550
+ return { hostname: registeredRoute.hostname, port, env };
551
551
  }
552
552
  async function acquireWorkspaceScriptTerminal(params) {
553
553
  const { serviceScript, existingRuntimeEntry, terminalManager, repoRoot, scriptName, env } = params;
@@ -565,7 +565,7 @@ async function acquireWorkspaceScriptTerminal(params) {
565
565
  return { terminal, reusableTerminal };
566
566
  }
567
567
  export async function spawnWorkspaceScript(options) {
568
- const { repoRoot, workspaceId, projectSlug, branchName, scriptName, daemonPort, daemonListenHost, routeStore, runtimeStore, terminalManager, logger, onLifecycleChanged, } = options;
568
+ const { repoRoot, workspaceId, projectSlug, branchName, scriptName, daemonPort, daemonListenHost, serviceProxyPublicBaseUrl, serviceProxy, runtimeStore, terminalManager, logger, onLifecycleChanged, } = options;
569
569
  const configResult = readPaseoConfig(repoRoot);
570
570
  if (!configResult.ok) {
571
571
  throw paseoConfigParseError(configResult);
@@ -598,8 +598,9 @@ export async function spawnWorkspaceScript(options) {
598
598
  workspaceId,
599
599
  daemonPort,
600
600
  daemonListenHost,
601
+ serviceProxyPublicBaseUrl,
601
602
  existingRuntimeEntry,
602
- routeStore,
603
+ serviceProxy,
603
604
  });
604
605
  hostname = serviceSetup.hostname;
605
606
  port = serviceSetup.port;
@@ -631,7 +632,7 @@ export async function spawnWorkspaceScript(options) {
631
632
  disposeLifecycleListeners?.();
632
633
  disposeLifecycleListeners = null;
633
634
  if (input.removeRoute && hostname) {
634
- routeStore.removeRouteForWorkspaceScript({ workspaceId, scriptName });
635
+ serviceProxy.removeWorkspaceService({ workspaceId, scriptName });
635
636
  }
636
637
  runtimeStore.set({
637
638
  workspaceId,
@@ -689,7 +690,7 @@ export async function spawnWorkspaceScript(options) {
689
690
  catch (error) {
690
691
  disposeLifecycleListeners?.();
691
692
  if (routeRegistered && hostname) {
692
- routeStore.removeRoute(hostname);
693
+ serviceProxy.removeServiceRoutesByHostnames([hostname]);
693
694
  }
694
695
  if (runtimeRegistered) {
695
696
  runtimeStore.remove({ workspaceId, scriptName });
@@ -707,9 +708,9 @@ export async function spawnWorkspaceScript(options) {
707
708
  }
708
709
  }
709
710
  export function teardownWorktreeScripts(options) {
710
- const { hostnames, routeStore, logger } = options;
711
+ const { hostnames, serviceProxy, logger } = options;
712
+ serviceProxy.removeServiceRoutesByHostnames(hostnames);
711
713
  for (const hostname of hostnames) {
712
- routeStore.removeRoute(hostname);
713
714
  logger.info({ hostname }, "Removed script proxy route");
714
715
  }
715
716
  }
@@ -11,6 +11,7 @@ export interface CreateWorktreeCoreInput {
11
11
  githubPrNumber?: number;
12
12
  firstAgentContext?: FirstAgentContext;
13
13
  paseoHome?: string;
14
+ worktreesRoot?: string;
14
15
  runSetup?: boolean;
15
16
  }
16
17
  export interface CreateWorktreeCoreDeps {
@@ -54,6 +54,7 @@ export async function createWorktreeCore(input, deps) {
54
54
  slug: normalizedSlug,
55
55
  repoRoot,
56
56
  paseoHome: input.paseoHome,
57
+ worktreesRoot: input.worktreesRoot,
57
58
  });
58
59
  if (existingWorktree) {
59
60
  return { worktree: existingWorktree, intent, repoRoot, created: false };
@@ -65,6 +66,7 @@ export async function createWorktreeCore(input, deps) {
65
66
  source: intent,
66
67
  runSetup: input.runSetup ?? true,
67
68
  paseoHome: input.paseoHome,
69
+ worktreesRoot: input.worktreesRoot,
68
70
  }),
69
71
  intent,
70
72
  repoRoot,
@@ -5,7 +5,7 @@ import type { PersistedWorkspaceRecord } from "./workspace-registry.js";
5
5
  import type { WorkspaceGitService } from "./workspace-git-service.js";
6
6
  import { runAsyncWorktreeBootstrap } from "./worktree-bootstrap.js";
7
7
  import type { TerminalManager } from "../terminal/terminal-manager.js";
8
- import type { ScriptRouteStore } from "./script-proxy.js";
8
+ import type { ServiceProxySubsystem } from "./service-proxy.js";
9
9
  import type { WorkspaceScriptRuntimeStore } from "./workspace-script-runtime-store.js";
10
10
  import type { GitHubService } from "../services/github-service.js";
11
11
  import type { CheckoutExistingBranchResult } from "../utils/checkout-git.js";
@@ -31,6 +31,7 @@ type AgentWorktreeSetupTimelineWriter = (input: {
31
31
  }) => Promise<boolean>;
32
32
  interface BuildAgentSessionConfigDependencies {
33
33
  paseoHome?: string;
34
+ worktreesRoot?: string;
34
35
  sessionLogger: Logger;
35
36
  workspaceGitService?: WorkspaceGitService;
36
37
  createPaseoWorktree: (input: CreatePaseoWorktreeInput, options?: {
@@ -47,6 +48,7 @@ interface BuildAgentSessionConfigDependencies {
47
48
  }
48
49
  interface CreatePaseoWorktreeInBackgroundDependencies {
49
50
  paseoHome?: string;
51
+ worktreesRoot?: string;
50
52
  emitWorkspaceUpdateForCwd: (cwd: string, options?: {
51
53
  dedupeGitState?: boolean;
52
54
  }) => Promise<void>;
@@ -55,10 +57,11 @@ interface CreatePaseoWorktreeInBackgroundDependencies {
55
57
  sessionLogger: Logger;
56
58
  terminalManager: TerminalManager | null;
57
59
  archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
58
- scriptRouteStore: ScriptRouteStore | null;
60
+ serviceProxy: ServiceProxySubsystem | null;
59
61
  scriptRuntimeStore: WorkspaceScriptRuntimeStore | null;
60
62
  getDaemonTcpPort: (() => number | null) | null;
61
63
  getDaemonTcpHost: (() => string | null) | null;
64
+ serviceProxyPublicBaseUrl?: string | null;
62
65
  onScriptsChanged: ((workspaceId: string, workspaceDirectory: string) => void) | null;
63
66
  }
64
67
  interface CreatePaseoWorktreeWorkflowDependencies extends CreatePaseoWorktreeInBackgroundDependencies {
@@ -100,6 +103,7 @@ interface HandleWorkspaceSetupStatusRequestDependencies {
100
103
  }
101
104
  interface HandleCreatePaseoWorktreeRequestDependencies {
102
105
  paseoHome?: string;
106
+ worktreesRoot?: string;
103
107
  describeWorkspaceRecord: (result: CreatePaseoWorktreeResult) => Promise<WorkspaceDescriptorPayload>;
104
108
  emit: EmitSessionMessage;
105
109
  sessionLogger: Logger;
@@ -41,6 +41,7 @@ export async function buildAgentSessionConfig(dependencies, config, gitOptions,
41
41
  firstAgentContext,
42
42
  runSetup: false,
43
43
  paseoHome: dependencies.paseoHome,
44
+ worktreesRoot: dependencies.worktreesRoot,
44
45
  }, {
45
46
  resolveDefaultBranch: normalized.baseBranch
46
47
  ? async () => normalized.baseBranch
@@ -241,6 +242,7 @@ export async function handleCreatePaseoWorktreeRequest(dependencies, request) {
241
242
  try {
242
243
  const commandResult = await createPaseoWorktreeCommand({
243
244
  paseoHome: dependencies.paseoHome,
245
+ worktreesRoot: dependencies.worktreesRoot,
244
246
  createPaseoWorktreeWorkflow: dependencies.createPaseoWorktreeWorkflow,
245
247
  }, {
246
248
  cwd: request.cwd,
@@ -304,6 +306,7 @@ export async function createPaseoWorktreeWorkflow(dependencies, input, options)
304
306
  ...input,
305
307
  runSetup: false,
306
308
  paseoHome: input.paseoHome ?? dependencies.paseoHome,
309
+ worktreesRoot: input.worktreesRoot ?? dependencies.worktreesRoot,
307
310
  }, options?.resolveDefaultBranch
308
311
  ? { resolveDefaultBranch: options.resolveDefaultBranch }
309
312
  : undefined);
@@ -228,6 +228,7 @@ export interface GitHubService {
228
228
  retainCurrentPullRequestStatusPoll?(options: {
229
229
  cwd: string;
230
230
  headRef: string;
231
+ headRepositoryOwner?: string;
231
232
  onStatus?: (status: GitHubCurrentPullRequestStatus | null) => void;
232
233
  onError?: (error: unknown) => void;
233
234
  }): {
@@ -425,7 +425,10 @@ export function createGitHubService(options = {}) {
425
425
  return buildCacheKey({
426
426
  cwd: target.cwd,
427
427
  method: "getCurrentPullRequestStatus",
428
- args: { headRef: target.headRef },
428
+ args: {
429
+ headRef: target.headRef,
430
+ headRepositoryOwner: target.headRepositoryOwner,
431
+ },
429
432
  });
430
433
  }
431
434
  function updatePollTargetAfterSuccess(update) {
@@ -465,6 +468,7 @@ export function createGitHubService(options = {}) {
465
468
  await api.getCurrentPullRequestStatus({
466
469
  cwd: target.cwd,
467
470
  headRef: target.headRef,
471
+ headRepositoryOwner: target.headRepositoryOwner,
468
472
  reason: "self-heal-github",
469
473
  });
470
474
  }
@@ -601,6 +605,7 @@ export function createGitHubService(options = {}) {
601
605
  updatePollTargetAfterSuccess({
602
606
  cwd: input.cwd,
603
607
  headRef: input.headRef,
608
+ headRepositoryOwner: input.headRepositoryOwner,
604
609
  status,
605
610
  notify: input.reason === "self-heal-github",
606
611
  });
@@ -795,6 +800,7 @@ export function createGitHubService(options = {}) {
795
800
  target = {
796
801
  cwd: input.cwd,
797
802
  headRef: input.headRef,
803
+ headRepositoryOwner: input.headRepositoryOwner,
798
804
  retainCount: 0,
799
805
  timer: null,
800
806
  latestStatus: null,
@@ -130,6 +130,7 @@ export interface MergeFromBaseOptions {
130
130
  }
131
131
  export interface CheckoutContext {
132
132
  paseoHome?: string;
133
+ worktreesRoot?: string;
133
134
  logger?: Pick<Logger, "trace">;
134
135
  facts?: CheckoutSnapshotFacts | null;
135
136
  }
@@ -149,7 +150,6 @@ export type CheckoutSnapshotFacts = {
149
150
  comparisonBaseRef: string | null;
150
151
  branchRemoteName: string | null;
151
152
  branchMergeRef: string | null;
152
- trackedOriginBranch: string | null;
153
153
  pullRequestLookupTarget: PullRequestStatusLookupTarget | null;
154
154
  };
155
155
  export declare function getCurrentBranch(cwd: string): Promise<string | null>;
@@ -159,8 +159,11 @@ export interface GitWorktreeEntry {
159
159
  branchRef?: string;
160
160
  isBare?: boolean;
161
161
  }
162
- /** Check whether a path contains a `.paseo/worktrees/` segment (both `/` and `\`). */
163
- export declare function isPaseoWorktreePath(p: string): boolean;
162
+ /** Check whether a path is under Paseo's worktree root. */
163
+ export declare function isPaseoWorktreePath(p: string, options?: {
164
+ paseoHome?: string;
165
+ worktreesRoot?: string;
166
+ }): boolean;
164
167
  /** True when `child` is strictly inside `parent` (handles both `/` and `\`). */
165
168
  export declare function isDescendantPath(child: string, parent: string): boolean;
166
169
  export declare function parseWorktreeList(output: string): GitWorktreeEntry[];
@@ -7,7 +7,7 @@ import { parseGitHubRepoFromRemote } from "../server/workspace-git-metadata.js";
7
7
  import { GitHubAuthenticationError, GitHubCliMissingError, GitHubCommandError, createGitHubService, resolveGitHubRepo, } from "../services/github-service.js";
8
8
  import { parseGitRevParsePath, resolveGitRevParsePath } from "./git-rev-parse-path.js";
9
9
  import { runGitCommand } from "./run-git-command.js";
10
- import { isPaseoOwnedWorktreeCwd } from "./worktree.js";
10
+ import { isPaseoOwnedWorktreeCwd, resolvePaseoWorktreesBaseRoot } from "./worktree.js";
11
11
  import { readPaseoWorktreeMetadata } from "./worktree-metadata.js";
12
12
  const READ_ONLY_GIT_ENV = {
13
13
  GIT_OPTIONAL_LOCKS: "0",
@@ -570,7 +570,7 @@ export async function getMainRepoRoot(cwd) {
570
570
  });
571
571
  return getMainRepoRootFromCommonDir(cwd, resolveGitRevParsePath(cwd, commonDirOut));
572
572
  }
573
- async function getMainRepoRootFromCommonDir(cwd, commonDir) {
573
+ async function getMainRepoRootFromCommonDir(cwd, commonDir, context) {
574
574
  if (!commonDir) {
575
575
  throw new Error("Not in a git repository");
576
576
  }
@@ -583,13 +583,20 @@ async function getMainRepoRootFromCommonDir(cwd, commonDir) {
583
583
  envOverlay: READ_ONLY_GIT_ENV,
584
584
  });
585
585
  const worktrees = parseWorktreeList(worktreeOut);
586
- const nonBareNonPaseo = worktrees.filter((wt) => !wt.isBare && !isPaseoWorktreePath(wt.path));
586
+ const nonBareNonPaseo = worktrees.filter((wt) => !wt.isBare &&
587
+ !isPaseoWorktreePath(wt.path, {
588
+ paseoHome: context?.paseoHome,
589
+ worktreesRoot: context?.worktreesRoot,
590
+ }));
587
591
  const childrenOfBareRepo = nonBareNonPaseo.filter((wt) => isDescendantPath(wt.path, normalized));
588
592
  const mainChild = childrenOfBareRepo.find((wt) => basename(wt.path) === "main");
589
593
  return mainChild?.path ?? childrenOfBareRepo[0]?.path ?? nonBareNonPaseo[0]?.path ?? normalized;
590
594
  }
591
- /** Check whether a path contains a `.paseo/worktrees/` segment (both `/` and `\`). */
592
- export function isPaseoWorktreePath(p) {
595
+ /** Check whether a path is under Paseo's worktree root. */
596
+ export function isPaseoWorktreePath(p, options) {
597
+ if (options?.worktreesRoot || options?.paseoHome) {
598
+ return isDescendantPath(p, resolvePaseoWorktreesBaseRoot(options));
599
+ }
593
600
  return /[/\\]\.paseo[/\\]worktrees[/\\]/.test(p);
594
601
  }
595
602
  /** True when `child` is strictly inside `parent` (handles both `/` and `\`). */
@@ -669,7 +676,10 @@ async function getPaseoWorktreeForCwd(cwd, context, knownWorktreeRoot) {
669
676
  if (!/[\\/]worktrees[\\/]/.test(cwd)) {
670
677
  return { isPaseoOwnedWorktree: false };
671
678
  }
672
- const ownership = await isPaseoOwnedWorktreeCwd(cwd, { paseoHome: context?.paseoHome });
679
+ const ownership = await isPaseoOwnedWorktreeCwd(cwd, {
680
+ paseoHome: context?.paseoHome,
681
+ worktreesRoot: context?.worktreesRoot,
682
+ });
673
683
  if (!ownership.allowed) {
674
684
  return { isPaseoOwnedWorktree: false };
675
685
  }
@@ -965,52 +975,46 @@ async function getAheadBehind(cwd, baseRef, currentBranch, context) {
965
975
  }
966
976
  return { ahead, behind };
967
977
  }
968
- async function getAheadOfOrigin(cwd, currentBranch, baseRef, context) {
978
+ async function getAheadOfOrigin(cwd, currentBranch, context) {
969
979
  if (!currentBranch) {
970
980
  return null;
971
981
  }
972
- const trackedOriginBranch = await getTrackedOriginBranch(cwd, currentBranch, context);
973
- const originBranch = trackedOriginBranch ?? currentBranch;
982
+ const upstreamRef = await getConfiguredUpstreamRef(cwd, currentBranch, context);
983
+ if (!upstreamRef) {
984
+ return null;
985
+ }
974
986
  try {
975
- const { stdout } = await runGitCommand(["rev-list", "--count", `origin/${originBranch}..${currentBranch}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
987
+ const { stdout } = await runGitCommand(["rev-list", "--count", `${upstreamRef}..${currentBranch}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
976
988
  const count = Number.parseInt(stdout.trim(), 10);
977
989
  return Number.isNaN(count) ? null : count;
978
990
  }
979
991
  catch {
980
- if (trackedOriginBranch) {
981
- return null;
982
- }
983
- if (!baseRef || normalizeLocalBranchRefName(baseRef) === currentBranch) {
984
- return null;
985
- }
986
- try {
987
- const comparisonBaseRef = await resolveBestComparisonBaseRef(cwd, baseRef, context);
988
- const { stdout } = await runGitCommand(["rev-list", "--count", `${comparisonBaseRef}..${currentBranch}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
989
- const count = Number.parseInt(stdout.trim(), 10);
990
- return Number.isNaN(count) ? null : count;
991
- }
992
- catch {
993
- return null;
994
- }
992
+ return null;
995
993
  }
996
994
  }
997
- async function getTrackedOriginBranch(cwd, currentBranch, context) {
998
- if (context?.facts?.isGit && context.facts.currentBranch === currentBranch) {
999
- return context.facts.trackedOriginBranch;
1000
- }
1001
- const remoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`, context);
1002
- if (remoteName !== "origin") {
995
+ async function getConfiguredUpstreamRef(cwd, currentBranch, context) {
996
+ const remoteName = context?.facts?.isGit && context.facts.currentBranch === currentBranch
997
+ ? context.facts.branchRemoteName
998
+ : await getGitConfigValue(cwd, `branch.${currentBranch}.remote`, context);
999
+ if (!remoteName) {
1003
1000
  return null;
1004
1001
  }
1005
- const mergeRef = await getGitConfigValue(cwd, `branch.${currentBranch}.merge`, context);
1006
- return parseBranchMergeHeadRef(mergeRef);
1002
+ const mergeRef = context?.facts?.isGit && context.facts.currentBranch === currentBranch
1003
+ ? context.facts.branchMergeRef
1004
+ : await getGitConfigValue(cwd, `branch.${currentBranch}.merge`, context);
1005
+ const upstreamBranch = parseBranchMergeHeadRef(mergeRef);
1006
+ return upstreamBranch ? `${remoteName}/${upstreamBranch}` : null;
1007
1007
  }
1008
1008
  async function getBehindOfOrigin(cwd, currentBranch, context) {
1009
1009
  if (!currentBranch) {
1010
1010
  return null;
1011
1011
  }
1012
+ const upstreamRef = await getConfiguredUpstreamRef(cwd, currentBranch, context);
1013
+ if (!upstreamRef) {
1014
+ return null;
1015
+ }
1012
1016
  try {
1013
- const { stdout } = await runGitCommand(["rev-list", "--count", `${currentBranch}..origin/${currentBranch}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
1017
+ const { stdout } = await runGitCommand(["rev-list", "--count", `${currentBranch}..${upstreamRef}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
1014
1018
  const count = Number.parseInt(stdout.trim(), 10);
1015
1019
  return Number.isNaN(count) ? null : count;
1016
1020
  }
@@ -1076,7 +1080,7 @@ export async function getCheckoutSnapshotFacts(cwd, context) {
1076
1080
  ? readPaseoWorktreeBaseRef(inspected.paseoWorktree.worktreeRoot)
1077
1081
  : null;
1078
1082
  const resolvedBaseRef = storedBaseRef ?? (await resolveBaseRef(cwd));
1079
- const mainRepoRoot = await getMainRepoRootFromCommonDir(cwd, inspected.gitCommonDir).catch(() => null);
1083
+ const mainRepoRoot = await getMainRepoRootFromCommonDir(cwd, inspected.gitCommonDir, context).catch(() => null);
1080
1084
  let comparisonBaseRef = null;
1081
1085
  if (resolvedBaseRef &&
1082
1086
  inspected.currentBranch &&
@@ -1095,7 +1099,6 @@ export async function getCheckoutSnapshotFacts(cwd, context) {
1095
1099
  }
1096
1100
  }
1097
1101
  }
1098
- const trackedOriginBranch = branchRemoteName === "origin" ? parseBranchMergeHeadRef(branchMergeRef) : null;
1099
1102
  const pullRequestLookupTarget = inspected.currentBranch
1100
1103
  ? buildPullRequestLookupTargetFromBranchConfig({
1101
1104
  currentBranch: inspected.currentBranch,
@@ -1118,7 +1121,6 @@ export async function getCheckoutSnapshotFacts(cwd, context) {
1118
1121
  comparisonBaseRef,
1119
1122
  branchRemoteName,
1120
1123
  branchMergeRef,
1121
- trackedOriginBranch,
1122
1124
  pullRequestLookupTarget,
1123
1125
  };
1124
1126
  }
@@ -1228,7 +1230,7 @@ export async function getCheckoutStatus(cwd, context) {
1228
1230
  ? getAheadBehind(cwd, baseRef, currentBranch, factsContext)
1229
1231
  : Promise.resolve(null),
1230
1232
  hasRemote && currentBranch
1231
- ? getAheadOfOrigin(cwd, currentBranch, baseRef, factsContext)
1233
+ ? getAheadOfOrigin(cwd, currentBranch, factsContext)
1232
1234
  : Promise.resolve(null),
1233
1235
  hasRemote && currentBranch
1234
1236
  ? getBehindOfOrigin(cwd, currentBranch, factsContext)
@@ -83,6 +83,10 @@ export interface PaseoWorktreeOwnership {
83
83
  worktreeRoot?: string;
84
84
  worktreePath?: string;
85
85
  }
86
+ export interface WorktreeRootOptions {
87
+ paseoHome?: string;
88
+ worktreesRoot?: string;
89
+ }
86
90
  export type WorktreeSource = {
87
91
  kind: "branch-off";
88
92
  baseBranch: string;
@@ -104,11 +108,13 @@ export interface CreateWorktreeOptions {
104
108
  source: WorktreeSource;
105
109
  runSetup: boolean;
106
110
  paseoHome?: string;
111
+ worktreesRoot?: string;
107
112
  }
108
113
  interface ResolveExistingWorktreeForSlugOptions {
109
114
  slug: string;
110
115
  repoRoot: string;
111
116
  paseoHome?: string;
117
+ worktreesRoot?: string;
112
118
  }
113
119
  export declare class BranchAlreadyCheckedOutError extends Error {
114
120
  readonly branchName: string;
@@ -164,32 +170,31 @@ export declare function runWorktreeTeardownCommands(options: {
164
170
  */
165
171
  export declare function getGitCommonDir(cwd: string): Promise<string>;
166
172
  export declare function deriveWorktreeProjectHash(cwd: string): Promise<string>;
167
- export declare function getPaseoWorktreesRoot(cwd: string, paseoHome?: string): Promise<string>;
168
- export declare function computeWorktreePath(cwd: string, slug: string, paseoHome?: string): Promise<string>;
169
- export declare function isPaseoOwnedWorktreeCwd(cwd: string, options?: {
170
- paseoHome?: string;
171
- }): Promise<PaseoWorktreeOwnership>;
172
- export declare function listPaseoWorktrees({ cwd, paseoHome, }: {
173
+ export declare function resolvePaseoWorktreesBaseRoot(options?: WorktreeRootOptions): string;
174
+ export declare function getPaseoWorktreesRoot(cwd: string, paseoHome?: string, worktreesRoot?: string): Promise<string>;
175
+ export declare function computeWorktreePath(cwd: string, slug: string, paseoHome?: string, worktreesRoot?: string): Promise<string>;
176
+ export declare function isPaseoOwnedWorktreeCwd(cwd: string, options?: WorktreeRootOptions): Promise<PaseoWorktreeOwnership>;
177
+ export declare function listPaseoWorktrees({ cwd, paseoHome, worktreesRoot, }: {
173
178
  cwd: string;
174
179
  paseoHome?: string;
180
+ worktreesRoot?: string;
175
181
  }): Promise<PaseoWorktreeInfo[]>;
176
- export declare function resolveExistingWorktreeForSlug({ slug, repoRoot, paseoHome, }: ResolveExistingWorktreeForSlugOptions): Promise<WorktreeConfig | null>;
177
- export declare function resolvePaseoWorktreeRootForCwd(cwd: string, options?: {
178
- paseoHome?: string;
179
- }): Promise<{
182
+ export declare function resolveExistingWorktreeForSlug({ slug, repoRoot, paseoHome, worktreesRoot, }: ResolveExistingWorktreeForSlugOptions): Promise<WorktreeConfig | null>;
183
+ export declare function resolvePaseoWorktreeRootForCwd(cwd: string, options?: WorktreeRootOptions): Promise<{
180
184
  repoRoot: string;
181
185
  worktreeRoot: string;
182
186
  worktreePath: string;
183
187
  } | null>;
184
- export declare function deletePaseoWorktree({ cwd, worktreePath, worktreeSlug, worktreesRoot, paseoHome, }: {
188
+ export declare function deletePaseoWorktree({ cwd, worktreePath, worktreeSlug, worktreesRoot, paseoHome, worktreesBaseRoot, }: {
185
189
  cwd: string | null;
186
190
  worktreePath?: string;
187
191
  worktreeSlug?: string;
188
192
  worktreesRoot?: string;
189
193
  paseoHome?: string;
194
+ worktreesBaseRoot?: string;
190
195
  }): Promise<void>;
191
196
  /**
192
197
  * Create a git worktree with proper naming conventions
193
198
  */
194
- export declare const createWorktree: ({ cwd, source, worktreeSlug, runSetup, paseoHome, }: CreateWorktreeOptions) => Promise<WorktreeConfig>;
199
+ export declare const createWorktree: ({ cwd, source, worktreeSlug, runSetup, paseoHome, worktreesRoot, }: CreateWorktreeOptions) => Promise<WorktreeConfig>;
195
200
  //# sourceMappingURL=worktree.d.ts.map