@penclipai/adapter-utils 2026.608.0 → 2026.702.0-canary.1

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 (68) hide show
  1. package/dist/command-managed-runtime.d.ts +10 -0
  2. package/dist/command-managed-runtime.d.ts.map +1 -1
  3. package/dist/command-managed-runtime.js +87 -12
  4. package/dist/command-managed-runtime.js.map +1 -1
  5. package/dist/command-managed-runtime.test.js +227 -134
  6. package/dist/command-managed-runtime.test.js.map +1 -1
  7. package/dist/exclude-patterns.d.ts +4 -0
  8. package/dist/exclude-patterns.d.ts.map +1 -0
  9. package/dist/exclude-patterns.js +26 -0
  10. package/dist/exclude-patterns.js.map +1 -0
  11. package/dist/execution-target-sandbox.test.js +118 -1
  12. package/dist/execution-target-sandbox.test.js.map +1 -1
  13. package/dist/execution-target.d.ts +6 -1
  14. package/dist/execution-target.d.ts.map +1 -1
  15. package/dist/execution-target.js +7 -0
  16. package/dist/execution-target.js.map +1 -1
  17. package/dist/git-workspace-sync.d.ts +52 -0
  18. package/dist/git-workspace-sync.d.ts.map +1 -0
  19. package/dist/git-workspace-sync.js +294 -0
  20. package/dist/git-workspace-sync.js.map +1 -0
  21. package/dist/git-workspace-sync.test.d.ts +2 -0
  22. package/dist/git-workspace-sync.test.d.ts.map +1 -0
  23. package/dist/git-workspace-sync.test.js +147 -0
  24. package/dist/git-workspace-sync.test.js.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +1 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/remote-managed-runtime.d.ts +3 -1
  30. package/dist/remote-managed-runtime.d.ts.map +1 -1
  31. package/dist/remote-managed-runtime.js +8 -2
  32. package/dist/remote-managed-runtime.js.map +1 -1
  33. package/dist/runtime-progress.d.ts +45 -0
  34. package/dist/runtime-progress.d.ts.map +1 -0
  35. package/dist/runtime-progress.js +95 -0
  36. package/dist/runtime-progress.js.map +1 -0
  37. package/dist/runtime-progress.test.d.ts +2 -0
  38. package/dist/runtime-progress.test.d.ts.map +1 -0
  39. package/dist/runtime-progress.test.js +240 -0
  40. package/dist/runtime-progress.test.js.map +1 -0
  41. package/dist/sandbox-callback-bridge.d.ts.map +1 -1
  42. package/dist/sandbox-callback-bridge.js +8 -4
  43. package/dist/sandbox-callback-bridge.js.map +1 -1
  44. package/dist/sandbox-managed-runtime.d.ts +15 -3
  45. package/dist/sandbox-managed-runtime.d.ts.map +1 -1
  46. package/dist/sandbox-managed-runtime.js +262 -74
  47. package/dist/sandbox-managed-runtime.js.map +1 -1
  48. package/dist/sandbox-managed-runtime.test.js +656 -1
  49. package/dist/sandbox-managed-runtime.test.js.map +1 -1
  50. package/dist/server-utils.d.ts +143 -3
  51. package/dist/server-utils.d.ts.map +1 -1
  52. package/dist/server-utils.js +586 -41
  53. package/dist/server-utils.js.map +1 -1
  54. package/dist/server-utils.test.js +502 -6
  55. package/dist/server-utils.test.js.map +1 -1
  56. package/dist/ssh-fixture.test.js +140 -1
  57. package/dist/ssh-fixture.test.js.map +1 -1
  58. package/dist/ssh.d.ts +7 -0
  59. package/dist/ssh.d.ts.map +1 -1
  60. package/dist/ssh.js +382 -128
  61. package/dist/ssh.js.map +1 -1
  62. package/dist/types.d.ts +23 -1
  63. package/dist/types.d.ts.map +1 -1
  64. package/dist/workspace-restore-merge.d.ts +1 -0
  65. package/dist/workspace-restore-merge.d.ts.map +1 -1
  66. package/dist/workspace-restore-merge.js +3 -7
  67. package/dist/workspace-restore-merge.js.map +1 -1
  68. package/package.json +2 -2
@@ -1,6 +1,14 @@
1
1
  import { type PreparedSandboxManagedRuntime, type SandboxManagedRuntimeAsset, type SandboxManagedRuntimeClient } from "./sandbox-managed-runtime.js";
2
2
  import type { RunProcessResult } from "./server-utils.js";
3
+ import type { RuntimeProgressSink, RuntimeStatusSink } from "./runtime-progress.js";
3
4
  export interface CommandManagedRuntimeRunner {
5
+ /**
6
+ * True only when `execute({ stdin })` can surface useful in-flight progress
7
+ * for a single stdin-backed command. Provider-backed sandbox runners usually
8
+ * complete the entire RPC before returning, so they should leave this false
9
+ * and let the caller choose a chunked upload path when progress is requested.
10
+ */
11
+ supportsSingleStreamStdinProgress?: boolean;
4
12
  execute(input: {
5
13
  command: string;
6
14
  args?: string[];
@@ -41,5 +49,7 @@ export declare function prepareCommandManagedRuntime(input: {
41
49
  installCommand?: string | null;
42
50
  /** When provided alongside `installCommand`, skip the install if `command -v <detectCommand>` succeeds. */
43
51
  detectCommand?: string | null;
52
+ onProgress?: RuntimeProgressSink;
53
+ onRuntimeProgress?: RuntimeStatusSink;
44
54
  }): Promise<PreparedSandboxManagedRuntime>;
45
55
  //# sourceMappingURL=command-managed-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-managed-runtime.d.ts","sourceRoot":"","sources":["../src/command-managed-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAEjC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACtE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACvE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AAyBpE,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACvD,MAAM,EAAE,2BAA2B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACrC,GAAG,2BAA2B,CAwE9B;AAED,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,MAAM,EAAE,2BAA2B,CAAC;IACpC,IAAI,EAAE,yBAAyB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2GAA2G;IAC3G,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAkFzC"}
1
+ {"version":3,"file":"command-managed-runtime.d.ts","sourceRoot":"","sources":["../src/command-managed-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAEjC,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEpF,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,iCAAiC,CAAC,EAAE,OAAO,CAAC;IAC5C,OAAO,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACtE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACvE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AAsCpE,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACvD,MAAM,EAAE,2BAA2B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACrC,GAAG,2BAA2B,CAgJ9B;AAED,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,MAAM,EAAE,2BAA2B,CAAC;IACpC,IAAI,EAAE,yBAAyB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2GAA2G;IAC3G,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAsFzC"}
@@ -7,7 +7,19 @@ function shellQuote(value) {
7
7
  function mergeRuntimeExcludes(entries) {
8
8
  return [...new Set([".paperclip-runtime", ...(entries ?? [])])];
9
9
  }
10
- const REMOTE_WRITE_BASE64_CHUNK_SIZE = 32 * 1024;
10
+ // Largest base64 body we hand to the runner as a single stdin string. Normal
11
+ // multi-MB workspace/asset tarballs stay well under this and upload in one
12
+ // round-trip; anything larger uses the bounded chunked-append fallback so a
13
+ // runaway stdin string can't blow the runner/provider RPC limits.
14
+ const REMOTE_WRITE_SINGLE_STREAM_MAX_BASE64_BYTES = 96 * 1024 * 1024;
15
+ // Fallback chunk size (base64 bytes). Kept a multiple of 4 so each chunk is a
16
+ // self-contained base64 unit that decodes cleanly on its own.
17
+ const REMOTE_WRITE_FALLBACK_BASE64_CHUNK_SIZE = 4 * 1024 * 1024;
18
+ const REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE = (REMOTE_WRITE_FALLBACK_BASE64_CHUNK_SIZE / 4) * 3;
19
+ const REMOTE_READ_CHUNK_BYTES = REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE;
20
+ function base64EncodedLength(byteLength) {
21
+ return Math.ceil(byteLength / 3) * 4;
22
+ }
11
23
  function toBuffer(bytes) {
12
24
  if (Buffer.isBuffer(bytes))
13
25
  return bytes;
@@ -31,6 +43,7 @@ export function createCommandManagedRuntimeClient(input) {
31
43
  cwd: input.commandCwd,
32
44
  stdin: opts.stdin,
33
45
  timeoutMs: opts.timeoutMs ?? input.timeoutMs,
46
+ onLog: opts.onLog,
34
47
  });
35
48
  requireSuccessfulResult(result, script);
36
49
  return result;
@@ -39,20 +52,78 @@ export function createCommandManagedRuntimeClient(input) {
39
52
  makeDir: async (remotePath) => {
40
53
  await runShell(`mkdir -p ${shellQuote(remotePath)}`);
41
54
  },
42
- writeFile: async (remotePath, bytes) => {
43
- const body = toBuffer(bytes).toString("base64");
55
+ writeFile: async (remotePath, bytes, options) => {
56
+ const buffer = toBuffer(bytes);
57
+ const total = buffer.byteLength;
58
+ const encodedLength = base64EncodedLength(total);
44
59
  const remoteDir = path.posix.dirname(remotePath);
45
- const remoteTempPath = `${remotePath}.paperclip-upload.b64`;
46
- await runShell(`mkdir -p ${shellQuote(remoteDir)} && rm -f ${shellQuote(remoteTempPath)} && : > ${shellQuote(remoteTempPath)}`);
47
- for (let offset = 0; offset < body.length; offset += REMOTE_WRITE_BASE64_CHUNK_SIZE) {
48
- const chunk = body.slice(offset, offset + REMOTE_WRITE_BASE64_CHUNK_SIZE);
49
- await runShell(`cat >> ${shellQuote(remoteTempPath)}`, { stdin: chunk });
60
+ const remoteTempPath = `${remotePath}.paperclip-upload`;
61
+ const canUseSingleStreamProgressPath = input.runner.supportsSingleStreamStdinProgress === true;
62
+ // Primary path: a single round-trip. Stream the entire base64 body to one
63
+ // `base64 -d` process via stdin, decode straight into a temp file, then
64
+ // atomically rename into place. This replaces the previous loop that did
65
+ // one `printf >> tmpfile` shell round-trip per 32 KB — thousands of serial
66
+ // processes for a large workspace — with exactly one process.
67
+ if (encodedLength <= REMOTE_WRITE_SINGLE_STREAM_MAX_BASE64_BYTES &&
68
+ canUseSingleStreamProgressPath) {
69
+ const body = buffer.toString("base64");
70
+ await options?.onProgress?.(0, total);
71
+ await runShell(`mkdir -p ${shellQuote(remoteDir)} && ` +
72
+ `base64 -d > ${shellQuote(remoteTempPath)} && ` +
73
+ `mv -f ${shellQuote(remoteTempPath)} ${shellQuote(remotePath)}`, { stdin: body });
74
+ await options?.onProgress?.(total, total);
75
+ return;
76
+ }
77
+ // Bounded fallback for payloads too large to hand the runner as one stdin
78
+ // string: append the base64 body to a remote temp file in large chunks
79
+ // (orders of magnitude fewer round-trips than the old 32 KB loop), decoding
80
+ // each self-contained chunk on arrival and emitting progress per write,
81
+ // then atomically rename into place.
82
+ await runShell(`mkdir -p ${shellQuote(remoteDir)} && ` +
83
+ `rm -f ${shellQuote(remoteTempPath)} && : > ${shellQuote(remoteTempPath)}`);
84
+ for (let offset = 0; offset < total; offset += REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE) {
85
+ const end = Math.min(total, offset + REMOTE_WRITE_FALLBACK_DECODED_CHUNK_SIZE);
86
+ const chunk = buffer.subarray(offset, end).toString("base64");
87
+ await runShell(`base64 -d >> ${shellQuote(remoteTempPath)}`, { stdin: chunk });
88
+ await options?.onProgress?.(end, total);
50
89
  }
51
- await runShell(`base64 -d < ${shellQuote(remoteTempPath)} > ${shellQuote(remotePath)} && rm -f ${shellQuote(remoteTempPath)}`);
90
+ await runShell(`mv -f ${shellQuote(remoteTempPath)} ${shellQuote(remotePath)}`);
91
+ await options?.onProgress?.(total, total);
52
92
  },
53
- readFile: async (remotePath) => {
54
- const result = await runShell(`base64 < ${shellQuote(remotePath)}`);
55
- return Buffer.from(result.stdout.replace(/\s+/g, ""), "base64");
93
+ readFile: async (remotePath, options) => {
94
+ // Chunked reads intentionally query the remote size first, even without
95
+ // a progress sink, so each sandbox RPC stays bounded and truncation is
96
+ // detected without materializing the whole file as one stdout string.
97
+ const sizeResult = await runShell(`wc -c < ${shellQuote(remotePath)}`);
98
+ const totalBytes = Number.parseInt(sizeResult.stdout.trim(), 10);
99
+ if (!Number.isFinite(totalBytes) || totalBytes < 0) {
100
+ throw new Error(`Could not determine remote file size for ${remotePath}`);
101
+ }
102
+ // Read in bounded remote chunks so the runner never has to materialize a
103
+ // single base64 stdout string for the whole archive. The client API still
104
+ // returns the decoded file as a Buffer, but every command result stays
105
+ // small enough for provider-backed sandbox RPCs.
106
+ const decodedChunks = [];
107
+ let decodedSoFar = 0;
108
+ if (totalBytes === 0) {
109
+ await options?.onProgress?.(0, 0);
110
+ return Buffer.alloc(0);
111
+ }
112
+ for (let chunkIndex = 0; decodedSoFar < totalBytes; chunkIndex++) {
113
+ const result = await runShell(`dd if=${shellQuote(remotePath)} bs=${REMOTE_READ_CHUNK_BYTES} skip=${chunkIndex} count=1 2>/dev/null | base64`);
114
+ const chunk = Buffer.from(result.stdout.replace(/\s+/g, ""), "base64");
115
+ if (chunk.byteLength === 0)
116
+ break;
117
+ decodedChunks.push(chunk);
118
+ decodedSoFar += chunk.byteLength;
119
+ await options?.onProgress?.(Math.min(decodedSoFar, totalBytes), totalBytes);
120
+ }
121
+ const out = Buffer.concat(decodedChunks);
122
+ if (out.byteLength !== totalBytes) {
123
+ throw new Error(`Remote file read was truncated for ${remotePath}: ${out.byteLength}/${totalBytes} bytes`);
124
+ }
125
+ await options?.onProgress?.(out.byteLength, totalBytes);
126
+ return out;
56
127
  },
57
128
  listFiles: async (remotePath) => {
58
129
  const result = await runShell(`if [ -d ${shellQuote(remotePath)} ]; then ` +
@@ -133,6 +204,8 @@ export async function prepareCommandManagedRuntime(input) {
133
204
  workspaceExclude: mergeRuntimeExcludes(input.workspaceExclude),
134
205
  preserveAbsentOnRestore: input.preserveAbsentOnRestore,
135
206
  assets: input.assets,
207
+ onProgress: input.onProgress,
208
+ onRuntimeProgress: input.onRuntimeProgress,
136
209
  });
137
210
  }
138
211
  }
@@ -163,6 +236,8 @@ export async function prepareCommandManagedRuntime(input) {
163
236
  workspaceExclude: mergeRuntimeExcludes(input.workspaceExclude),
164
237
  preserveAbsentOnRestore: input.preserveAbsentOnRestore,
165
238
  assets: input.assets,
239
+ onProgress: input.onProgress,
240
+ onRuntimeProgress: input.onRuntimeProgress,
166
241
  });
167
242
  }
168
243
  //# sourceMappingURL=command-managed-runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-managed-runtime.js","sourceRoot":"","sources":["../src/command-managed-runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-managed-runtime.js","sourceRoot":"","sources":["../src/command-managed-runtime.ts"],"names":[],"mappings":"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"}
@@ -5,79 +5,15 @@ import path from "node:path";
5
5
  import { execFile as execFileCallback, spawn } from "node:child_process";
6
6
  import { promisify } from "node:util";
7
7
  import { afterEach, describe, expect, it } from "vitest";
8
- import { prepareCommandManagedRuntime } from "./command-managed-runtime.js";
8
+ import { createCommandManagedRuntimeClient, prepareCommandManagedRuntime, } from "./command-managed-runtime.js";
9
9
  const execFile = promisify(execFileCallback);
10
- function createChildProcessEnv(overrides) {
11
- const env = {};
12
- for (const [key, value] of Object.entries(process.env)) {
13
- if (value !== undefined)
14
- env[key] = value;
15
- }
16
- return { ...env, ...overrides };
17
- }
18
- function execFileWithInput(command, args, options) {
19
- if (options.input == null) {
20
- return execFile(command, args, {
21
- cwd: options.cwd,
22
- env: options.env,
23
- maxBuffer: options.maxBuffer,
24
- timeout: options.timeout,
25
- });
26
- }
27
- return new Promise((resolve, reject) => {
28
- let stdout = "";
29
- let stderr = "";
30
- let timedOut = false;
31
- const child = spawn(command, args, {
32
- cwd: options.cwd,
33
- env: options.env,
34
- windowsHide: true,
35
- stdio: ["pipe", "pipe", "pipe"],
36
- });
37
- const timer = options.timeout
38
- ? setTimeout(() => {
39
- timedOut = true;
40
- child.kill();
41
- }, options.timeout)
42
- : null;
43
- child.stdout.setEncoding("utf8");
44
- child.stderr.setEncoding("utf8");
45
- child.stdout.on("data", (chunk) => {
46
- stdout += chunk;
47
- if (options.maxBuffer && stdout.length > options.maxBuffer)
48
- child.kill();
49
- });
50
- child.stderr.on("data", (chunk) => {
51
- stderr += chunk;
52
- if (options.maxBuffer && stderr.length > options.maxBuffer)
53
- child.kill();
54
- });
55
- child.on("error", reject);
56
- child.on("close", (code, signal) => {
57
- if (timer)
58
- clearTimeout(timer);
59
- if (code === 0 && !timedOut) {
60
- resolve({ stdout, stderr });
61
- return;
62
- }
63
- const error = new Error(`${command} exited with code ${code ?? "null"}`);
64
- error.stdout = stdout;
65
- error.stderr = stderr;
66
- error.code = code;
67
- error.signal = signal;
68
- error.killed = timedOut;
69
- reject(error);
70
- });
71
- child.stdin.end(options.input);
72
- });
73
- }
74
10
  function resolveTestPosixShellCommand(command) {
75
11
  if (process.platform !== "win32")
76
12
  return command === "bash" ? "/bin/bash" : "/bin/sh";
77
13
  const candidates = command === "bash"
78
14
  ? ["C:\\Program Files\\Git\\bin\\bash.exe", "C:\\Program Files\\Git\\usr\\bin\\bash.exe"]
79
15
  : ["C:\\Program Files\\Git\\usr\\bin\\sh.exe", "C:\\Program Files\\Git\\bin\\bash.exe"];
80
- return candidates.find((candidate) => existsSync(candidate)) ?? "sh";
16
+ return candidates.find((candidate) => existsSync(candidate)) ?? command;
81
17
  }
82
18
  function augmentTestPosixPath(env) {
83
19
  if (process.platform !== "win32")
@@ -93,7 +29,109 @@ function augmentTestPosixPath(env) {
93
29
  function rewriteWindowsPathsForGitShell(script) {
94
30
  if (process.platform !== "win32")
95
31
  return script;
96
- return script.replace(/([A-Za-z]):\\([^'"\s]*)/g, (_match, drive, rest) => `/${drive.toLowerCase()}/${rest.replace(/\\/g, "/")}`);
32
+ const toGitShellPath = (drive, rest) => `/${drive.toLowerCase()}/${rest.replace(/\\/g, "/")}`;
33
+ const rewritten = script
34
+ .replace(/'([A-Za-z]):\\([^']*)'/g, (_match, drive, rest) => `'${toGitShellPath(drive, rest)}'`)
35
+ .replace(/"([A-Za-z]):\\([^"]*)"/g, (_match, drive, rest) => `"${toGitShellPath(drive, rest)}"`)
36
+ .replace(/([A-Za-z]):\\([^'"\s]*)/g, (_match, drive, rest) => toGitShellPath(drive, rest));
37
+ return rewritten.replace(/mkdir -p '\.' && (?=(?:base64 -d >|rm -f|: >)\s+'([^']+)')/g, (_match, targetPath) => `mkdir -p '${path.posix.dirname(targetPath)}' && `);
38
+ }
39
+ function resolveRunnerShell(input) {
40
+ const env = { ...process.env, ...input.env };
41
+ const command = input.command === "sh" || input.command === "bash"
42
+ ? resolveTestPosixShellCommand(input.command)
43
+ : input.command;
44
+ const args = [...(input.args ?? [])];
45
+ if (input.command === "sh" || input.command === "bash") {
46
+ augmentTestPosixPath(env);
47
+ }
48
+ if ((input.command === "sh" || input.command === "bash") &&
49
+ (args[0] === "-c" || args[0] === "-lc") &&
50
+ typeof args[1] === "string") {
51
+ args[1] = rewriteWindowsPathsForGitShell(args[1]);
52
+ }
53
+ return { command, args, env };
54
+ }
55
+ // A runner that actually executes the shell scripts (piping stdin through a real
56
+ // pipe so multi-MB payloads work) and replays stdout through onLog in several
57
+ // chunks so the streaming readFile byte-counter is exercised.
58
+ function makeSpawnRunner(options = {}) {
59
+ const calls = [];
60
+ const runner = {
61
+ supportsSingleStreamStdinProgress: options.supportsSingleStreamStdinProgress,
62
+ execute: async (input) => await new Promise((resolve) => {
63
+ calls.push({ command: input.command, args: input.args, cwd: input.cwd, stdin: input.stdin });
64
+ const startedAt = new Date().toISOString();
65
+ const { command, args, env } = resolveRunnerShell(input);
66
+ const child = spawn(command, args, {
67
+ cwd: input.cwd,
68
+ env,
69
+ });
70
+ let stdout = "";
71
+ let stderr = "";
72
+ child.stdout.on("data", (chunk) => {
73
+ stdout += chunk.toString("utf8");
74
+ });
75
+ child.stderr.on("data", (chunk) => {
76
+ stderr += chunk.toString("utf8");
77
+ });
78
+ child.on("error", () => {
79
+ resolve({ exitCode: 127, signal: null, timedOut: false, stdout, stderr, pid: null, startedAt });
80
+ });
81
+ child.on("close", async (code) => {
82
+ if (options.maxStdoutBytes != null &&
83
+ Buffer.byteLength(stdout, "utf8") > options.maxStdoutBytes) {
84
+ resolve({
85
+ exitCode: 1,
86
+ signal: null,
87
+ timedOut: false,
88
+ stdout,
89
+ stderr: `stdout exceeded ${options.maxStdoutBytes} bytes`,
90
+ pid: child.pid ?? null,
91
+ startedAt,
92
+ });
93
+ return;
94
+ }
95
+ if (input.onLog && stdout.length > 0) {
96
+ const chunkSize = Math.max(1, Math.ceil(stdout.length / 4));
97
+ for (let offset = 0; offset < stdout.length; offset += chunkSize) {
98
+ await input.onLog("stdout", stdout.slice(offset, offset + chunkSize));
99
+ }
100
+ }
101
+ resolve({
102
+ exitCode: code ?? 0,
103
+ signal: null,
104
+ timedOut: false,
105
+ stdout,
106
+ stderr,
107
+ pid: child.pid ?? null,
108
+ startedAt,
109
+ });
110
+ });
111
+ if (input.stdin != null)
112
+ child.stdin.write(input.stdin);
113
+ child.stdin.end();
114
+ }),
115
+ };
116
+ return { runner, calls };
117
+ }
118
+ function toArrayBuffer(buffer) {
119
+ return Uint8Array.from(buffer).buffer;
120
+ }
121
+ async function withBase64StringByteLimit(limitBytes, fn) {
122
+ const originalToString = Buffer.prototype.toString;
123
+ Buffer.prototype.toString = function patchedToString(encoding, start, end) {
124
+ if (encoding === "base64" && this.byteLength > limitBytes) {
125
+ throw new Error(`test guard: attempted to base64-encode ${this.byteLength} bytes at once`);
126
+ }
127
+ return originalToString.call(this, encoding, start, end);
128
+ };
129
+ try {
130
+ return await fn();
131
+ }
132
+ finally {
133
+ Buffer.prototype.toString = originalToString;
134
+ }
97
135
  }
98
136
  describe("command managed runtime", () => {
99
137
  const cleanupDirs = [];
@@ -119,24 +157,18 @@ describe("command managed runtime", () => {
119
157
  execute: async (input) => {
120
158
  calls.push({ ...input });
121
159
  const startedAt = new Date().toISOString();
122
- const env = createChildProcessEnv(input.env);
123
- const command = input.command === "sh" || input.command === "bash"
124
- ? resolveTestPosixShellCommand(input.command)
125
- : input.command;
126
- const args = [...(input.args ?? [])];
127
- if (input.command === "sh" || input.command === "bash") {
128
- augmentTestPosixPath(env);
129
- }
130
- if ((input.command === "sh" || input.command === "bash") &&
160
+ const { command, args, env } = resolveRunnerShell(input);
161
+ if (input.stdin != null &&
162
+ (input.command === "sh" || input.command === "bash") &&
131
163
  (args[0] === "-c" || args[0] === "-lc") &&
132
164
  typeof args[1] === "string") {
133
- args[1] = rewriteWindowsPathsForGitShell(args[1]);
165
+ env.PAPERCLIP_TEST_STDIN = input.stdin;
166
+ args[1] = `printf '%s' \"$PAPERCLIP_TEST_STDIN\" | (${args[1]})`;
134
167
  }
135
168
  try {
136
- const result = await execFileWithInput(command, args, {
169
+ const result = await execFile(command, args, {
137
170
  cwd: input.cwd,
138
171
  env,
139
- input: input.stdin,
140
172
  maxBuffer: 32 * 1024 * 1024,
141
173
  timeout: input.timeoutMs,
142
174
  });
@@ -176,9 +208,9 @@ describe("command managed runtime", () => {
176
208
  await expect(readFile(path.join(remoteWorkspaceDir, "README.md"), "utf8")).resolves.toBe("local workspace\n");
177
209
  await expect(readFile(path.join(remoteWorkspaceDir, ".paperclip-runtime", "state.json"), "utf8")).rejects
178
210
  .toMatchObject({ code: "ENOENT" });
179
- const uploadCalls = calls.filter((call) => call.args?.[1]?.includes("cat >>"));
180
- expect(uploadCalls.length).toBeGreaterThan(0);
181
- expect(uploadCalls.every((call) => typeof call.stdin === "string" && call.stdin.length <= 32 * 1024)).toBe(true);
211
+ // The single-stream upload pipes the tarball through exactly one stdin-backed
212
+ // process (the speed fix); nothing else streams stdin.
213
+ expect(calls.filter((call) => call.stdin != null).length).toBe(1);
182
214
  await mkdir(path.join(remoteWorkspaceDir, ".paperclip-runtime"), { recursive: true });
183
215
  await writeFile(path.join(remoteWorkspaceDir, "README.md"), "remote workspace\n", "utf8");
184
216
  await writeFile(path.join(remoteWorkspaceDir, ".paperclip-runtime", "remote-state.json"), "{\"remote\":true}\n", "utf8");
@@ -188,7 +220,10 @@ describe("command managed runtime", () => {
188
220
  .toBe("{\"keep\":true}\n");
189
221
  await expect(readFile(path.join(localWorkspaceDir, ".paperclip-runtime", "remote-state.json"), "utf8")).rejects
190
222
  .toMatchObject({ code: "ENOENT" });
191
- }, 30_000);
223
+ // Restore streams the download through `base64`/onLog (no stdin), so the only
224
+ // stdin-backed call remains the single upload from prepare.
225
+ expect(calls.filter((call) => call.stdin != null).length).toBe(1);
226
+ });
192
227
  it("runs setup commands from a stable root cwd when staging into a nested remote workspace dir", async () => {
193
228
  const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-runtime-nested-"));
194
229
  cleanupDirs.push(rootDir);
@@ -198,56 +233,7 @@ describe("command managed runtime", () => {
198
233
  await mkdir(localWorkspaceDir, { recursive: true });
199
234
  await mkdir(remoteBaseDir, { recursive: true });
200
235
  await writeFile(path.join(localWorkspaceDir, "README.md"), "local workspace\n", "utf8");
201
- const calls = [];
202
- const runner = {
203
- execute: async (input) => {
204
- calls.push({ ...input });
205
- const startedAt = new Date().toISOString();
206
- const env = createChildProcessEnv(input.env);
207
- const command = input.command === "sh" || input.command === "bash"
208
- ? resolveTestPosixShellCommand(input.command)
209
- : input.command;
210
- const args = [...(input.args ?? [])];
211
- if (input.command === "sh" || input.command === "bash") {
212
- augmentTestPosixPath(env);
213
- }
214
- if ((input.command === "sh" || input.command === "bash") &&
215
- (args[0] === "-c" || args[0] === "-lc") &&
216
- typeof args[1] === "string") {
217
- args[1] = rewriteWindowsPathsForGitShell(args[1]);
218
- }
219
- try {
220
- const result = await execFileWithInput(command, args, {
221
- cwd: input.cwd,
222
- env,
223
- input: input.stdin,
224
- maxBuffer: 32 * 1024 * 1024,
225
- timeout: input.timeoutMs,
226
- });
227
- return {
228
- exitCode: 0,
229
- signal: null,
230
- timedOut: false,
231
- stdout: result.stdout,
232
- stderr: result.stderr,
233
- pid: null,
234
- startedAt,
235
- };
236
- }
237
- catch (error) {
238
- const err = error;
239
- return {
240
- exitCode: typeof err.code === "number" ? err.code : null,
241
- signal: err.signal ?? null,
242
- timedOut: Boolean(err.killed && input.timeoutMs),
243
- stdout: err.stdout ?? "",
244
- stderr: err.stderr ?? "",
245
- pid: null,
246
- startedAt,
247
- };
248
- }
249
- },
250
- };
236
+ const { runner, calls } = makeSpawnRunner();
251
237
  await prepareCommandManagedRuntime({
252
238
  runner,
253
239
  spec: {
@@ -261,6 +247,113 @@ describe("command managed runtime", () => {
261
247
  expect(calls.length).toBeGreaterThan(0);
262
248
  expect(calls.every((call) => call.cwd === "/")).toBe(true);
263
249
  await expect(readFile(path.join(remoteWorkspaceDir, "README.md"), "utf8")).resolves.toBe("local workspace\n");
264
- }, 30_000);
250
+ });
251
+ it("uploads a multi-MB payload in a single process and preserves exact bytes", async () => {
252
+ const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-write-"));
253
+ cleanupDirs.push(rootDir);
254
+ const remotePath = path.join(rootDir, "nested", "payload.bin");
255
+ // ~3 MB of every byte value so the test catches any non-binary-safe handling.
256
+ const payload = Buffer.alloc(3 * 1024 * 1024);
257
+ for (let i = 0; i < payload.length; i++)
258
+ payload[i] = i % 256;
259
+ const { runner, calls } = makeSpawnRunner({ supportsSingleStreamStdinProgress: true });
260
+ const client = createCommandManagedRuntimeClient({ runner, commandCwd: "/", timeoutMs: 30_000 });
261
+ const progress = [];
262
+ await withBase64StringByteLimit(4 * 1024 * 1024, async () => {
263
+ await client.writeFile(remotePath, toArrayBuffer(payload), {
264
+ onProgress: (done, total) => {
265
+ progress.push({ done, total });
266
+ },
267
+ });
268
+ });
269
+ // Exactly one upload process: O(1) round-trips regardless of payload size.
270
+ expect(calls.length).toBe(1);
271
+ expect(calls[0].stdin).toBeTypeOf("string");
272
+ const written = await readFile(remotePath);
273
+ expect(written.equals(payload)).toBe(true);
274
+ // Progress is monotonically non-decreasing and reaches the total.
275
+ expect(progress.length).toBeGreaterThan(0);
276
+ for (let i = 1; i < progress.length; i++) {
277
+ expect(progress[i].done).toBeGreaterThanOrEqual(progress[i - 1].done);
278
+ }
279
+ expect(progress.at(-1)).toEqual({ done: payload.length, total: payload.length });
280
+ });
281
+ it("falls back to chunked upload progress when the runner cannot report mid-stream stdin progress", async () => {
282
+ const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-write-fallback-"));
283
+ cleanupDirs.push(rootDir);
284
+ const remotePath = path.join(rootDir, "nested", "payload.bin");
285
+ const payload = Buffer.alloc(12 * 1024 * 1024);
286
+ for (let i = 0; i < payload.length; i++)
287
+ payload[i] = i % 256;
288
+ const { runner, calls } = makeSpawnRunner({ supportsSingleStreamStdinProgress: false });
289
+ const client = createCommandManagedRuntimeClient({ runner, commandCwd: "/", timeoutMs: 30_000 });
290
+ const progress = [];
291
+ await client.writeFile(remotePath, toArrayBuffer(payload), {
292
+ onProgress: (done, total) => {
293
+ progress.push({ done, total });
294
+ },
295
+ });
296
+ const written = await readFile(remotePath);
297
+ expect(written.equals(payload)).toBe(true);
298
+ // Provider-backed sandbox runners cannot surface mid-flight progress for a
299
+ // single stdin RPC, so we intentionally use several large append commands.
300
+ expect(calls.length).toBeGreaterThan(2);
301
+ const stdinCalls = calls.filter((call) => call.stdin != null);
302
+ expect(stdinCalls.length).toBeGreaterThan(2);
303
+ expect(stdinCalls.every((call) => Buffer.byteLength(call.stdin ?? "", "utf8") <= 4.1 * 1024 * 1024)).toBe(true);
304
+ expect(progress.length).toBeGreaterThan(2);
305
+ for (let i = 1; i < progress.length; i++) {
306
+ expect(progress[i].done).toBeGreaterThanOrEqual(progress[i - 1].done);
307
+ }
308
+ expect(progress.at(-1)).toEqual({ done: payload.length, total: payload.length });
309
+ });
310
+ it("falls back to bounded chunks when the runner does not explicitly opt in", async () => {
311
+ const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-write-fallback-no-progress-"));
312
+ cleanupDirs.push(rootDir);
313
+ const remotePath = path.join(rootDir, "nested", "payload.bin");
314
+ const payload = Buffer.alloc(12 * 1024 * 1024);
315
+ for (let i = 0; i < payload.length; i++)
316
+ payload[i] = i % 256;
317
+ const { runner, calls } = makeSpawnRunner();
318
+ const client = createCommandManagedRuntimeClient({ runner, commandCwd: "/", timeoutMs: 30_000 });
319
+ await withBase64StringByteLimit(4 * 1024 * 1024, async () => {
320
+ await client.writeFile(remotePath, toArrayBuffer(payload));
321
+ });
322
+ const written = await readFile(remotePath);
323
+ expect(written.equals(payload)).toBe(true);
324
+ // A runner that doesn't mark single-stream stdin support must avoid passing
325
+ // the whole base64 archive as one string, so we expect multiple append calls.
326
+ const stdinCalls = calls.filter((call) => call.stdin != null);
327
+ expect(stdinCalls.length).toBeGreaterThan(1);
328
+ expect(stdinCalls.every((call) => Buffer.byteLength(call.stdin ?? "", "utf8") <= 4.1 * 1024 * 1024)).toBe(true);
329
+ });
330
+ it("downloads in bounded stdout chunks and reports monotonic byte progress to the total", async () => {
331
+ const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-command-read-"));
332
+ cleanupDirs.push(rootDir);
333
+ const remotePath = path.join(rootDir, "download.bin");
334
+ const payload = Buffer.alloc(7 * 1024 * 1024);
335
+ for (let i = 0; i < payload.length; i++)
336
+ payload[i] = (i * 7) % 256;
337
+ await writeFile(remotePath, payload);
338
+ const { runner, calls } = makeSpawnRunner({ maxStdoutBytes: 5 * 1024 * 1024 });
339
+ const client = createCommandManagedRuntimeClient({ runner, commandCwd: "/", timeoutMs: 30_000 });
340
+ const progress = [];
341
+ const bytes = await client.readFile(remotePath, {
342
+ onProgress: (done, total) => {
343
+ progress.push({ done, total });
344
+ },
345
+ });
346
+ expect(Buffer.from(bytes).equals(payload)).toBe(true);
347
+ // The old single `base64 < file` path would exceed the runner's stdout cap.
348
+ // The bounded path reads with several small `dd | base64` commands instead.
349
+ expect(calls.some((call) => call.args?.join(" ").includes("base64 <"))).toBe(false);
350
+ expect(calls.filter((call) => call.args?.join(" ").includes("dd if=")).length).toBeGreaterThan(1);
351
+ expect(progress.length).toBeGreaterThan(1);
352
+ for (let i = 1; i < progress.length; i++) {
353
+ expect(progress[i].done).toBeGreaterThanOrEqual(progress[i - 1].done);
354
+ }
355
+ expect(progress.every((entry) => entry.total === payload.length)).toBe(true);
356
+ expect(progress.at(-1)?.done).toBe(payload.length);
357
+ });
265
358
  });
266
359
  //# sourceMappingURL=command-managed-runtime.test.js.map