@agent-relay/sandbox 0.0.0 → 0.1.0

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.
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Shell snippets for running the `relayfile-mount` daemon inside a sandbox.
3
+ *
4
+ * Callers that drive the mount — a command-at-a-time executor, a runner that
5
+ * submits one multi-line script, and a generator that emits sandbox-resident
6
+ * bootstrap JS — would otherwise each hand-roll near-identical bash. This
7
+ * module is the single builder for all of them, and owns the command
8
+ * templates the bootstrap generator embeds.
9
+ *
10
+ * The contract: helpers take primitives, do their own shell quoting, and
11
+ * return ready-to-run bash. Callers must not re-quote.
12
+ */
13
+ export type RelayfileMountShellOptions = {
14
+ /** Relayfile base URL, e.g. `https://your-relayfile-host.example`. */
15
+ baseUrl: string;
16
+ /** Workspace id the path-scoped token is bound to. */
17
+ workspaceId: string;
18
+ /** Local mirror root inside the sandbox, e.g. `/home/<user>/workspace`. */
19
+ localDir: string;
20
+ /**
21
+ * Private relayfile-mount state directory. Required: it is sandbox-image
22
+ * specific, and it must sit OUTSIDE the mounted workspace so sync metadata
23
+ * never appears in the Relayfile tree.
24
+ */
25
+ stateDir: string;
26
+ /** Path-scoped relayfile token (`relay_pa_*`). */
27
+ token: string;
28
+ /**
29
+ * Optional logical path scopes. The daemon accepts repeated
30
+ * `--remote-path` args; callers pass the scopes they care about here so the
31
+ * continuous sync never pulls a full workspace export.
32
+ */
33
+ paths?: readonly string[];
34
+ /**
35
+ * Whether relayfile-mount should use the WebSocket event stream. Omit to use
36
+ * the CLI default. Set false to fall back to bounded `/fs/events` polling,
37
+ * which suits hosts that cannot hold a long-lived WebSocket request open.
38
+ */
39
+ websocket?: boolean;
40
+ /**
41
+ * Lazily materialize GitHub repo subtrees on first access instead of eagerly
42
+ * hydrating every repo file during bootstrap.
43
+ */
44
+ lazyRepos?: boolean;
45
+ /**
46
+ * Path to a JSON creds file (`{"token": "relay_pa_…", "mintedAt"?, "expiresAt"?}`)
47
+ * the daemon re-reads on 401 so a refreshed token heals the mount without a
48
+ * restart. Passed as the RELAYFILE_MOUNT_CREDS_FILE env var rather than a
49
+ * `--creds-file` flag for the same version-skew reason as
50
+ * RELAYFILE_MOUNT_LOCAL_LAYOUT above: pre-creds binaries reject an unknown
51
+ * flag but ignore the env var, so one spelling works across every binary a
52
+ * snapshot may carry. `--token` stays as the launch credential either way.
53
+ */
54
+ credsFilePath?: string;
55
+ };
56
+ export type RelayfileMountInitialSyncOptions = RelayfileMountShellOptions & {
57
+ /**
58
+ * Optional timeout for a pre-handler sync. When set, the command uses
59
+ * coreutils `timeout`; if it is unavailable, the sync fails so callers can
60
+ * gracefully continue without risking an unbounded pre-handler sync.
61
+ */
62
+ timeoutSeconds?: number;
63
+ /**
64
+ * Optional idle timeout for pre-handler sync. Unlike timeoutSeconds, this
65
+ * cancels only when mount state stops progressing for N seconds.
66
+ */
67
+ idleTimeoutSeconds?: number;
68
+ };
69
+ export type RelayfileMountDaemonOptions = RelayfileMountShellOptions & {
70
+ /** Daemon sync interval. Defaults to `1s` for near-real-time writeback. */
71
+ interval?: string;
72
+ /** Path the daemon redirects stdout/stderr to. Defaults to `/tmp/relayfile-mount.log`. */
73
+ logPath?: string;
74
+ };
75
+ export type RelayfileMountShellTemplate = {
76
+ startShellTemplate: string;
77
+ flushShellTemplate: string;
78
+ pathArgsPlaceholderArg: string;
79
+ pathArgTemplate: string;
80
+ placeholders: {
81
+ baseUrl: string;
82
+ workspaceId: string;
83
+ localDir: string;
84
+ token: string;
85
+ pathArgs: string;
86
+ path: string;
87
+ };
88
+ };
89
+ /**
90
+ * Bash command that starts a `relayfile-mount` daemon in the background and
91
+ * echoes the daemon PID on stdout (so callers can capture it and kill the
92
+ * process later). The daemon redirects all output to `logPath` so it does
93
+ * not pollute the caller's stdout/stderr.
94
+ *
95
+ * Mirrors the inline command originally in
96
+ * `executor.ts:startRelayfileMount` (#???) — see the file-level comment for
97
+ * the migration story.
98
+ */
99
+ export declare function buildRelayfileMountStartShell(opts: RelayfileMountDaemonOptions): string;
100
+ /**
101
+ * Bash command that runs a one-time relayfile-mount sync (`--once`). Pushes
102
+ * any pending local writes upstream and exits. Use this:
103
+ * - As an explicit pre-handler sync so the mount mirror is populated
104
+ * before the handler reads from it (executor's initial-sync pattern).
105
+ * - As a post-handler flush before sandbox teardown so writeback drafts
106
+ * the handler created (e.g. `ctx.github.comment` files) reach
107
+ * relayfile cloud before the sandbox stops.
108
+ */
109
+ export declare function buildRelayfileMountFlushShell(opts: RelayfileMountShellOptions): string;
110
+ /**
111
+ * Post-handler CLEANUP flush command — the durable cure for cleanup flushes
112
+ * that time out on large mirrors. Identical to
113
+ * {@link buildRelayfileMountFlushShell} EXCEPT the mode flag is the shell
114
+ * variable `$relayfile_mount_flush_mode`, which the lifecycle shell probes
115
+ * once into `--flush-outbox-once` (O(durable outbox); flushes only
116
+ * `.relay/outbox/pending` and exits WITHOUT a full-tree reconcile —
117
+ * scanLocalFiles/pushLocal/pullRemote — so a large mirror can't blow the
118
+ * cleanup `timeout`) on daemons that support it, else `--once` on older ones,
119
+ * whose behavior is unchanged. Emitted as a SINGLE command (the flag is one
120
+ * expanded token) so it stays valid inside the cleanup's `timeout Ns ...`
121
+ * wrapper — an inline `if/fi` would break `timeout`. The flag choice does not
122
+ * change the exit-code/`.relay/state.json` contract the cleanup gate reads: a
123
+ * real outbox-flush failure still exits nonzero and leaves pending, so the
124
+ * loud-fail stays load-bearing.
125
+ */
126
+ export declare function buildRelayfileMountCleanupFlushShell(opts: RelayfileMountShellOptions): string;
127
+ export declare function buildRelayfileMountInitialSyncShell(opts: RelayfileMountInitialSyncOptions): string;
128
+ export declare const RELAYFILE_INITIAL_SYNC_SCRIPT_PATH = "/tmp/relayfile-initial-sync.sh";
129
+ export declare const RELAYFILE_INITIAL_SYNC_EXIT_PATH = "/tmp/relayfile-initial-sync.exit";
130
+ export declare const RELAYFILE_INITIAL_SYNC_LOG_PATH = "/tmp/relayfile-initial-sync.log";
131
+ export declare const RELAYFILE_INITIAL_SYNC_PID_PATH = "/tmp/relayfile-initial-sync.pid";
132
+ export type RelayfileMountInitialSyncRunOptions = {
133
+ runId?: string;
134
+ };
135
+ /**
136
+ * Bash that launches the (idle-watched) initial sync in the background and
137
+ * returns immediately, echoing the launcher PID. Daytona's exec path cannot
138
+ * host a single long-running command: the proxy read-times-out around 120s
139
+ * (a gateway timeout) and callers add their own client-side fail-fast, so a
140
+ * first materialization with real data (a populated /github tree, a cold
141
+ * workspace export) gets killed mid-sync. Instead the sync runs detached in
142
+ * the sandbox — preserving the in-sandbox idle watchdog — and callers poll
143
+ * `buildRelayfileMountInitialSyncStatusShell` with short execs until the
144
+ * exit sentinel appears.
145
+ */
146
+ export declare function buildRelayfileMountInitialSyncBackgroundShell(opts: RelayfileMountInitialSyncOptions, runOptions?: RelayfileMountInitialSyncRunOptions): string;
147
+ /** Short, idempotent status probe for the backgrounded initial sync. */
148
+ export declare function buildRelayfileMountInitialSyncStatusShell(runOptions?: RelayfileMountInitialSyncRunOptions): string;
149
+ export declare function buildRelayfileMountInitialSyncKillShell(runOptions?: RelayfileMountInitialSyncRunOptions): string;
150
+ export declare function buildRelayfileMountInitialSyncLogTailShell(lines?: number, runOptions?: RelayfileMountInitialSyncRunOptions): string;
151
+ export type RelayfileMountInitialSyncStatus = {
152
+ state: "running";
153
+ } | {
154
+ state: "exited";
155
+ exitCode: number;
156
+ } | {
157
+ state: "unknown";
158
+ };
159
+ export declare function parseRelayfileMountInitialSyncStatus(output: string): RelayfileMountInitialSyncStatus;
160
+ export declare function buildRelayfileMountPathArgsShell(paths: readonly string[]): string;
161
+ export declare function buildRelayfileMountShellTemplate(placeholders: Partial<RelayfileMountShellTemplate["placeholders"]> | undefined, options: Pick<RelayfileMountDaemonOptions, "stateDir"> & Partial<Pick<RelayfileMountDaemonOptions, "interval" | "websocket">>): RelayfileMountShellTemplate;
162
+ //# sourceMappingURL=mount-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-script.d.ts","sourceRoot":"","sources":["../src/mount-script.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,461 @@
1
+ /**
2
+ * Shell snippets for running the `relayfile-mount` daemon inside a sandbox.
3
+ *
4
+ * Callers that drive the mount — a command-at-a-time executor, a runner that
5
+ * submits one multi-line script, and a generator that emits sandbox-resident
6
+ * bootstrap JS — would otherwise each hand-roll near-identical bash. This
7
+ * module is the single builder for all of them, and owns the command
8
+ * templates the bootstrap generator embeds.
9
+ *
10
+ * The contract: helpers take primitives, do their own shell quoting, and
11
+ * return ready-to-run bash. Callers must not re-quote.
12
+ */
13
+ /**
14
+ * Pin the daemon's local layout to `scoped` (remote path appended under
15
+ * --local-dir) on every invocation.
16
+ *
17
+ * Newer daemon releases made the layout explicit: they default to `exact`
18
+ * (--local-dir IS the mirror root) and hard-error on multiple --remote-path
19
+ * values unless `--local-layout=scoped`. All builders in this module
20
+ * pre-compute an UNSCOPED local dir (see `unscopedLocalDir`) and rely on the
21
+ * daemon appending the remote path, which is what older binaries did
22
+ * implicitly. Without this pin, a newer binary breaks two ways: multi-path
23
+ * mounts fail at startup, and single-path mounts silently mirror at the wrong
24
+ * depth.
25
+ *
26
+ * Pinned via env var rather than the `--local-layout` flag on purpose: older
27
+ * binaries reject the unknown flag but ignore the env var, while newer ones
28
+ * read RELAYFILE_MOUNT_LOCAL_LAYOUT as the flag default. One spelling
29
+ * therefore yields an identical on-disk layout across every binary version a
30
+ * sandbox image may carry — which matters because the image and this code are
31
+ * versioned independently. The pathless case is safe: scoped layout with
32
+ * remote path "/" is a no-op join (normalizeMountRemotePath("/") → localDir).
33
+ *
34
+ * Spelled `env VAR=… relayfile-mount` (not the bare `VAR=… relayfile-mount`
35
+ * shell form) because initial-sync commands get wrapped by coreutils
36
+ * `timeout`, which execs its argument instead of shell-parsing it — a bare
37
+ * assignment prefix would make `timeout '20s' VAR=… relayfile-mount` fail
38
+ * with "failed to run command". `env` is a real executable, so the same
39
+ * prefix composes under `timeout`, `nohup`, and direct execution alike.
40
+ */
41
+ const SCOPED_LOCAL_LAYOUT_ENV = "env RELAYFILE_MOUNT_LOCAL_LAYOUT=scoped ";
42
+ /**
43
+ * `env`-prefix for every relayfile-mount invocation: always pins the scoped
44
+ * local layout, and when the caller provides a creds file, also points the
45
+ * daemon at it via RELAYFILE_MOUNT_CREDS_FILE (see `credsFilePath` docs for
46
+ * the version-skew rationale).
47
+ */
48
+ function mountEnvPrefix(opts) {
49
+ if (!opts.credsFilePath) {
50
+ return SCOPED_LOCAL_LAYOUT_ENV;
51
+ }
52
+ return `env RELAYFILE_MOUNT_LOCAL_LAYOUT=scoped RELAYFILE_MOUNT_CREDS_FILE=${shellQuote(opts.credsFilePath)} `;
53
+ }
54
+ const DEFAULT_TEMPLATE_PLACEHOLDERS = {
55
+ baseUrl: "__relayfile_base_url__",
56
+ workspaceId: "__relayfile_workspace_id__",
57
+ localDir: "__relayfile_local_dir__",
58
+ token: "__relayfile_token__",
59
+ pathArgs: "__relayfile_path_args__",
60
+ path: "__relayfile_path__",
61
+ };
62
+ /**
63
+ * Bash command that starts a `relayfile-mount` daemon in the background and
64
+ * echoes the daemon PID on stdout (so callers can capture it and kill the
65
+ * process later). The daemon redirects all output to `logPath` so it does
66
+ * not pollute the caller's stdout/stderr.
67
+ *
68
+ * Mirrors the inline command originally in
69
+ * `executor.ts:startRelayfileMount` (#???) — see the file-level comment for
70
+ * the migration story.
71
+ */
72
+ export function buildRelayfileMountStartShell(opts) {
73
+ const scopedRoots = scopedRemoteRoots(opts.paths ?? [], { allowProviderRoot: true });
74
+ const localDir = unscopedLocalDir(opts.localDir, scopedRoots);
75
+ const args = buildMountArgs({ ...opts, localDir, paths: scopedRoots });
76
+ const interval = opts.interval ?? "1s";
77
+ const logPath = opts.logPath ?? "/tmp/relayfile-mount.log";
78
+ const startShell = [
79
+ `${mountEnvPrefix(opts)}nohup relayfile-mount`,
80
+ ...args,
81
+ `--interval ${shellQuote(interval)}`,
82
+ `> ${shellQuote(logPath)} 2>&1 & echo $!`,
83
+ ].join(" ");
84
+ if (scopedRoots.length <= 1) {
85
+ return startShell;
86
+ }
87
+ // `paths-file` is the new-daemon sentinel: the release that added it also
88
+ // added repeated `--remote-path` support. The Go flag package prints
89
+ // `-paths-file` in help while the command accepts `--paths-file`, so probe
90
+ // for the flag name without assuming dash style.
91
+ return [
92
+ "if relayfile-mount --help 2>&1 | grep -q -- 'paths-file'; then",
93
+ `${startShell};`,
94
+ "else",
95
+ "echo 'relayfile-mount multi-path filters unsupported; starting one daemon per remote path' >&2;",
96
+ `${buildRelayfileMountFallbackStartShell({ ...opts, paths: scopedRoots })};`,
97
+ "fi",
98
+ ].join(" ");
99
+ }
100
+ /**
101
+ * Bash command that runs a one-time relayfile-mount sync (`--once`). Pushes
102
+ * any pending local writes upstream and exits. Use this:
103
+ * - As an explicit pre-handler sync so the mount mirror is populated
104
+ * before the handler reads from it (executor's initial-sync pattern).
105
+ * - As a post-handler flush before sandbox teardown so writeback drafts
106
+ * the handler created (e.g. `ctx.github.comment` files) reach
107
+ * relayfile cloud before the sandbox stops.
108
+ */
109
+ export function buildRelayfileMountFlushShell(opts) {
110
+ const scopedRoots = scopedRemoteRoots(opts.paths ?? [], { allowProviderRoot: true });
111
+ const localDir = unscopedLocalDir(opts.localDir, scopedRoots);
112
+ const args = buildMountArgs({ ...opts, localDir, paths: scopedRoots });
113
+ return [`${mountEnvPrefix(opts)}relayfile-mount --once`, ...args].join(" ");
114
+ }
115
+ /**
116
+ * Post-handler CLEANUP flush command — the durable cure for cleanup flushes
117
+ * that time out on large mirrors. Identical to
118
+ * {@link buildRelayfileMountFlushShell} EXCEPT the mode flag is the shell
119
+ * variable `$relayfile_mount_flush_mode`, which the lifecycle shell probes
120
+ * once into `--flush-outbox-once` (O(durable outbox); flushes only
121
+ * `.relay/outbox/pending` and exits WITHOUT a full-tree reconcile —
122
+ * scanLocalFiles/pushLocal/pullRemote — so a large mirror can't blow the
123
+ * cleanup `timeout`) on daemons that support it, else `--once` on older ones,
124
+ * whose behavior is unchanged. Emitted as a SINGLE command (the flag is one
125
+ * expanded token) so it stays valid inside the cleanup's `timeout Ns ...`
126
+ * wrapper — an inline `if/fi` would break `timeout`. The flag choice does not
127
+ * change the exit-code/`.relay/state.json` contract the cleanup gate reads: a
128
+ * real outbox-flush failure still exits nonzero and leaves pending, so the
129
+ * loud-fail stays load-bearing.
130
+ */
131
+ export function buildRelayfileMountCleanupFlushShell(opts) {
132
+ const scopedRoots = scopedRemoteRoots(opts.paths ?? [], { allowProviderRoot: true });
133
+ const localDir = unscopedLocalDir(opts.localDir, scopedRoots);
134
+ const args = buildMountArgs({ ...opts, localDir, paths: scopedRoots });
135
+ return [
136
+ `${mountEnvPrefix(opts)}relayfile-mount "$relayfile_mount_flush_mode"`,
137
+ ...args,
138
+ ].join(" ");
139
+ }
140
+ export function buildRelayfileMountInitialSyncShell(opts) {
141
+ const commands = buildInitialSyncCommands(opts);
142
+ const command = commands.join(" && ");
143
+ if (opts.idleTimeoutSeconds && opts.idleTimeoutSeconds > 0) {
144
+ return buildIdleWatchedCommand(command, initialSyncProgressFiles(opts), opts.idleTimeoutSeconds);
145
+ }
146
+ if (!opts.timeoutSeconds || opts.timeoutSeconds <= 0) {
147
+ return command;
148
+ }
149
+ const timeout = `${Math.ceil(opts.timeoutSeconds)}s`;
150
+ const timedCommand = commands
151
+ .map((entry) => `timeout ${shellQuote(timeout)} ${entry}`)
152
+ .join(" && ");
153
+ return [
154
+ "{",
155
+ "if command -v timeout >/dev/null 2>&1; then",
156
+ `${timedCommand};`,
157
+ "else",
158
+ "echo 'timeout command unavailable for relayfile initial sync' >&2;",
159
+ "false;",
160
+ "fi;",
161
+ "}",
162
+ ].join(" ");
163
+ }
164
+ export const RELAYFILE_INITIAL_SYNC_SCRIPT_PATH = "/tmp/relayfile-initial-sync.sh";
165
+ export const RELAYFILE_INITIAL_SYNC_EXIT_PATH = "/tmp/relayfile-initial-sync.exit";
166
+ export const RELAYFILE_INITIAL_SYNC_LOG_PATH = "/tmp/relayfile-initial-sync.log";
167
+ export const RELAYFILE_INITIAL_SYNC_PID_PATH = "/tmp/relayfile-initial-sync.pid";
168
+ function relayfileInitialSyncPath(path, runId) {
169
+ if (!runId) {
170
+ return path;
171
+ }
172
+ const safeRunId = runId.replace(/[^A-Za-z0-9_.-]/g, "_");
173
+ return `${path}.${safeRunId}`;
174
+ }
175
+ /**
176
+ * Bash that launches the (idle-watched) initial sync in the background and
177
+ * returns immediately, echoing the launcher PID. Daytona's exec path cannot
178
+ * host a single long-running command: the proxy read-times-out around 120s
179
+ * (a gateway timeout) and callers add their own client-side fail-fast, so a
180
+ * first materialization with real data (a populated /github tree, a cold
181
+ * workspace export) gets killed mid-sync. Instead the sync runs detached in
182
+ * the sandbox — preserving the in-sandbox idle watchdog — and callers poll
183
+ * `buildRelayfileMountInitialSyncStatusShell` with short execs until the
184
+ * exit sentinel appears.
185
+ */
186
+ export function buildRelayfileMountInitialSyncBackgroundShell(opts, runOptions = {}) {
187
+ const scriptPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_SCRIPT_PATH, runOptions.runId);
188
+ const exitPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_EXIT_PATH, runOptions.runId);
189
+ const logPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_LOG_PATH, runOptions.runId);
190
+ const pidPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_PID_PATH, runOptions.runId);
191
+ const syncShell = buildRelayfileMountInitialSyncShell(opts);
192
+ const runner = [
193
+ "if command -v setsid >/dev/null 2>&1; then",
194
+ ` setsid sh ${shellQuote(scriptPath)} > ${shellQuote(logPath)} 2>&1 &`,
195
+ "else",
196
+ ` sh ${shellQuote(scriptPath)} > ${shellQuote(logPath)} 2>&1 &`,
197
+ "fi;",
198
+ "relayfile_initial_sync_pid=$!;",
199
+ `echo "$relayfile_initial_sync_pid" > ${shellQuote(pidPath)};`,
200
+ 'wait "$relayfile_initial_sync_pid";',
201
+ `echo $? > ${shellQuote(exitPath)}`,
202
+ ].join(" ");
203
+ return [
204
+ "set -e",
205
+ `rm -f ${shellQuote(scriptPath)} ${shellQuote(exitPath)} ${shellQuote(logPath)} ${shellQuote(pidPath)} &&`,
206
+ // Quoted heredoc delimiter: the sync shell lands in the script file
207
+ // verbatim, with no re-quoting hazards from nesting it in `sh -c`.
208
+ `cat > ${shellQuote(scriptPath)} <<'RELAYFILE_INITIAL_SYNC_EOF'
209
+ ${syncShell}
210
+ RELAYFILE_INITIAL_SYNC_EOF
211
+ `,
212
+ `nohup sh -c ${shellQuote(runner)} >/dev/null 2>&1 & echo $!`,
213
+ ].join("\n");
214
+ }
215
+ const RELAYFILE_INITIAL_SYNC_EXIT_MARKER = "relayfile-initial-sync-exit:";
216
+ const RELAYFILE_INITIAL_SYNC_RUNNING_MARKER = "relayfile-initial-sync-running";
217
+ /** Short, idempotent status probe for the backgrounded initial sync. */
218
+ export function buildRelayfileMountInitialSyncStatusShell(runOptions = {}) {
219
+ const exitPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_EXIT_PATH, runOptions.runId);
220
+ const pidPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_PID_PATH, runOptions.runId);
221
+ return [
222
+ `if [ -f ${shellQuote(exitPath)} ]; then`,
223
+ `echo "${RELAYFILE_INITIAL_SYNC_EXIT_MARKER}$(cat ${shellQuote(exitPath)})";`,
224
+ `elif [ -f ${shellQuote(pidPath)} ]; then`,
225
+ `relayfile_initial_sync_pid=$(cat ${shellQuote(pidPath)} 2>/dev/null || true);`,
226
+ 'case "$relayfile_initial_sync_pid" in',
227
+ ` ''|*[!0-9]*) echo ${RELAYFILE_INITIAL_SYNC_RUNNING_MARKER} ;;`,
228
+ ' *)',
229
+ ' if kill -0 "$relayfile_initial_sync_pid" 2>/dev/null; then',
230
+ ` echo ${RELAYFILE_INITIAL_SYNC_RUNNING_MARKER};`,
231
+ " else",
232
+ ` echo "${RELAYFILE_INITIAL_SYNC_EXIT_MARKER}127";`,
233
+ " fi",
234
+ " ;;",
235
+ "esac",
236
+ "else",
237
+ `echo ${RELAYFILE_INITIAL_SYNC_RUNNING_MARKER};`,
238
+ "fi",
239
+ ].join(" ");
240
+ }
241
+ export function buildRelayfileMountInitialSyncKillShell(runOptions = {}) {
242
+ const pidPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_PID_PATH, runOptions.runId);
243
+ return [
244
+ `if [ -f ${shellQuote(pidPath)} ]; then`,
245
+ `relayfile_initial_sync_pid=$(cat ${shellQuote(pidPath)} 2>/dev/null || true);`,
246
+ 'case "$relayfile_initial_sync_pid" in',
247
+ " ''|*[!0-9]*) ;;",
248
+ ' *)',
249
+ ' kill -TERM -- "-$relayfile_initial_sync_pid" 2>/dev/null || true;',
250
+ ' kill "$relayfile_initial_sync_pid" 2>/dev/null || true',
251
+ " ;;",
252
+ "esac",
253
+ "fi",
254
+ ].join(" ");
255
+ }
256
+ export function buildRelayfileMountInitialSyncLogTailShell(lines = 40, runOptions = {}) {
257
+ const logPath = relayfileInitialSyncPath(RELAYFILE_INITIAL_SYNC_LOG_PATH, runOptions.runId);
258
+ return `tail -n ${Math.max(1, Math.floor(lines))} ${shellQuote(logPath)} 2>/dev/null || true`;
259
+ }
260
+ export function parseRelayfileMountInitialSyncStatus(output) {
261
+ const match = output.match(new RegExp(`${RELAYFILE_INITIAL_SYNC_EXIT_MARKER}(-?\\d+)`));
262
+ const exitCode = match?.[1];
263
+ if (exitCode !== undefined) {
264
+ return { state: "exited", exitCode: Number.parseInt(exitCode, 10) };
265
+ }
266
+ if (output.includes(RELAYFILE_INITIAL_SYNC_RUNNING_MARKER)) {
267
+ return { state: "running" };
268
+ }
269
+ return { state: "unknown" };
270
+ }
271
+ export function buildRelayfileMountPathArgsShell(paths) {
272
+ return scopedRemoteRoots(paths, { allowProviderRoot: true })
273
+ .map(buildMountPathArg)
274
+ .join("");
275
+ }
276
+ export function buildRelayfileMountShellTemplate(placeholders = {},
277
+ // `stateDir` is required (sandbox-image specific); `interval` / `websocket`
278
+ // stay optional.
279
+ options) {
280
+ const resolved = { ...DEFAULT_TEMPLATE_PLACEHOLDERS, ...placeholders };
281
+ const baseOpts = {
282
+ baseUrl: resolved.baseUrl,
283
+ workspaceId: resolved.workspaceId,
284
+ localDir: resolved.localDir,
285
+ token: resolved.token,
286
+ ...options,
287
+ };
288
+ const pathArgsPlaceholderArg = buildMountPathArg(resolved.pathArgs);
289
+ const pathArgTemplate = buildMountPathArg(resolved.path);
290
+ const startShellWithoutPaths = buildRelayfileMountStartShell(baseOpts);
291
+ const flushShellWithoutPaths = buildRelayfileMountFlushShell(baseOpts);
292
+ return {
293
+ startShellTemplate: insertStartTemplatePathArgs(startShellWithoutPaths, pathArgsPlaceholderArg),
294
+ flushShellTemplate: `${flushShellWithoutPaths}${pathArgsPlaceholderArg}`,
295
+ pathArgsPlaceholderArg,
296
+ pathArgTemplate,
297
+ placeholders: resolved,
298
+ };
299
+ }
300
+ function buildMountArgs(opts) {
301
+ return [
302
+ `--base-url ${shellQuote(opts.baseUrl)}`,
303
+ `--workspace ${shellQuote(opts.workspaceId)}`,
304
+ `--local-dir ${shellQuote(opts.localDir)}`,
305
+ `--state-dir ${shellQuote(opts.stateDir)}`,
306
+ `--token ${shellQuote(opts.token)}`,
307
+ ...(opts.websocket === false ? ["--websocket=false"] : []),
308
+ ...(opts.lazyRepos ? ["--lazy-repos"] : []),
309
+ ...scopedRemoteRoots(opts.paths ?? [], { allowProviderRoot: true })
310
+ .map((path) => `--remote-path ${shellQuote(path)}`),
311
+ ];
312
+ }
313
+ function buildInitialSyncCommands(opts) {
314
+ const roots = scopedRemoteRoots(opts.paths ?? []);
315
+ if (roots.length === 0) {
316
+ return [buildRelayfileMountFlushShell(opts)];
317
+ }
318
+ const localDir = unscopedLocalDir(opts.localDir, roots);
319
+ return roots
320
+ .map((remoteRoot, index) => {
321
+ const args = [
322
+ ...buildMountArgs({ ...opts, localDir, paths: [] }),
323
+ `--remote-path ${shellQuote(remoteRoot)}`,
324
+ `--state-file ${shellQuote(`/tmp/relayfile-mount-initial-sync-${index}.json`)}`,
325
+ ];
326
+ return [`${mountEnvPrefix(opts)}relayfile-mount --once`, ...args].join(" ");
327
+ });
328
+ }
329
+ function initialSyncProgressFiles(opts) {
330
+ const roots = scopedRemoteRoots(opts.paths ?? []);
331
+ if (roots.length === 0) {
332
+ const stateDir = opts.stateDir;
333
+ return [
334
+ `${stateDir.replace(/\/+$/u, "")}/.relayfile-mount-state.json`,
335
+ ];
336
+ }
337
+ return roots.map((_remoteRoot, index) => `/tmp/relayfile-mount-initial-sync-${index}.json`);
338
+ }
339
+ function buildIdleWatchedCommand(command, progressFiles, idleTimeoutSeconds) {
340
+ const idle = Math.max(1, Math.ceil(idleTimeoutSeconds));
341
+ const poll = Math.max(1, Math.min(5, Math.floor(idle / 3) || 1));
342
+ const progressArgs = progressFiles.map(shellQuote).join(" ");
343
+ return [
344
+ "(",
345
+ `set -- ${progressArgs};`,
346
+ "relayfile_mount_marker=$(mktemp /tmp/relayfile-mount-progress.XXXXXX) || exit 1;",
347
+ 'touch "$relayfile_mount_marker";',
348
+ `(${command}) &`,
349
+ "relayfile_mount_sync_pid=$!;",
350
+ "relayfile_mount_status=0;",
351
+ 'while kill -0 "$relayfile_mount_sync_pid" 2>/dev/null; do',
352
+ ' for relayfile_mount_progress_file in "$@"; do',
353
+ ' if [ -f "$relayfile_mount_progress_file" ] && [ "$relayfile_mount_progress_file" -nt "$relayfile_mount_marker" ]; then',
354
+ ' touch "$relayfile_mount_marker";',
355
+ " fi;",
356
+ " done;",
357
+ " relayfile_mount_now=$(date +%s);",
358
+ ' relayfile_mount_marker_mtime=$(date -r "$relayfile_mount_marker" +%s 2>/dev/null || stat -c %Y "$relayfile_mount_marker" 2>/dev/null || echo "$relayfile_mount_now");',
359
+ ` if [ $((relayfile_mount_now - relayfile_mount_marker_mtime)) -ge ${idle} ]; then`,
360
+ ` echo 'relayfile initial sync made no progress for ${idle}s; canceling' >&2;`,
361
+ ' kill "$relayfile_mount_sync_pid" 2>/dev/null || true;',
362
+ ' wait "$relayfile_mount_sync_pid" 2>/dev/null || true;',
363
+ ' rm -f "$relayfile_mount_marker";',
364
+ " exit 124;",
365
+ " fi;",
366
+ ` sleep ${poll};`,
367
+ "done;",
368
+ 'wait "$relayfile_mount_sync_pid" || relayfile_mount_status=$?;',
369
+ 'rm -f "$relayfile_mount_marker";',
370
+ 'exit "$relayfile_mount_status";',
371
+ ")",
372
+ ].join(" ");
373
+ }
374
+ function scopedRemoteRoots(paths, options = {}) {
375
+ const roots = new Set();
376
+ for (const path of paths) {
377
+ const root = scopedRemoteRoot(path, options);
378
+ if (root) {
379
+ roots.add(root);
380
+ }
381
+ }
382
+ return [...roots].sort();
383
+ }
384
+ function scopedRemoteRoot(path, options = {}) {
385
+ const trimmed = path.trim();
386
+ if (!trimmed.startsWith("/")) {
387
+ return null;
388
+ }
389
+ const withoutGlob = trimmed.endsWith("/**") ? trimmed.slice(0, -3) : trimmed;
390
+ const normalized = withoutGlob.replace(/\/{2,}/g, "/").replace(/\/$/u, "");
391
+ if (!normalized || normalized === "/" || normalized.includes("*")) {
392
+ return null;
393
+ }
394
+ if (!options.allowProviderRoot && normalized.slice(1).split("/").length < 2) {
395
+ return null;
396
+ }
397
+ return normalized;
398
+ }
399
+ function unscopedLocalDir(localRoot, remoteRoots) {
400
+ let normalizedRoot = localRoot.replace(/\/+$/u, "");
401
+ const suffixes = remoteRoots
402
+ .map((remoteRoot) => remoteRoot.replace(/^\/+/u, "").replace(/\/+$/u, ""))
403
+ .filter(Boolean)
404
+ .sort((left, right) => right.length - left.length);
405
+ for (const suffix of suffixes) {
406
+ if (!suffix) {
407
+ continue;
408
+ }
409
+ if (normalizedRoot === suffix) {
410
+ normalizedRoot = "";
411
+ continue;
412
+ }
413
+ if (normalizedRoot.endsWith(`/${suffix}`)) {
414
+ normalizedRoot = normalizedRoot.slice(0, -suffix.length).replace(/\/+$/u, "");
415
+ continue;
416
+ }
417
+ const nestedSuffix = `/${suffix}/`;
418
+ const nestedIndex = normalizedRoot.indexOf(nestedSuffix);
419
+ if (nestedIndex !== -1) {
420
+ normalizedRoot = normalizedRoot.slice(0, nestedIndex).replace(/\/+$/u, "");
421
+ }
422
+ }
423
+ return normalizedRoot || "/";
424
+ }
425
+ function buildMountPathArg(path) {
426
+ return ` --remote-path ${shellQuote(path)}`;
427
+ }
428
+ function insertStartTemplatePathArgs(shell, pathArgsPlaceholderArg) {
429
+ return shell.replace(" --interval ", `${pathArgsPlaceholderArg} --interval `);
430
+ }
431
+ function buildRelayfileMountFallbackStartShell(opts) {
432
+ const roots = scopedRemoteRoots(opts.paths ?? [], { allowProviderRoot: true });
433
+ const localDir = unscopedLocalDir(opts.localDir, roots);
434
+ const interval = opts.interval ?? "1s";
435
+ const logPath = opts.logPath ?? "/tmp/relayfile-mount.log";
436
+ const starts = roots.map((root) => [
437
+ `${mountEnvPrefix(opts)}relayfile-mount`,
438
+ ...buildMountArgs({ ...opts, localDir, paths: [root] }),
439
+ `--interval ${shellQuote(interval)}`,
440
+ `>> ${shellQuote(logPath)} 2>&1 &`,
441
+ "relayfile_mount_pids=\"$relayfile_mount_pids $!\";",
442
+ ].join(" "));
443
+ return [
444
+ "(",
445
+ "relayfile_mount_pids='';",
446
+ ...starts,
447
+ "trap 'kill $relayfile_mount_pids 2>/dev/null || true; wait' INT TERM EXIT;",
448
+ "wait",
449
+ ") >/dev/null 2>&1 & echo $!",
450
+ ].join(" ");
451
+ }
452
+ /**
453
+ * POSIX-safe single-quote escape. `foo` → `'foo'`, `foo's` → `'foo'\''s'`.
454
+ * Conservative — quotes every value, even ones that don't strictly need it,
455
+ * so callers never have to think about characters that would otherwise be
456
+ * shell-interpreted (spaces, `$`, etc.).
457
+ */
458
+ function shellQuote(value) {
459
+ return `'${value.replace(/'/g, "'\\''")}'`;
460
+ }
461
+ //# sourceMappingURL=mount-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-script.js","sourceRoot":"","sources":["../src/mount-script.ts"],"names":[],"mappings":"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"}