@smthrs/std 1.0.0-rc.6 → 1.0.0-rc.8
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.
- package/CHANGELOG.md +4 -0
- package/README.md +39 -37
- package/dist/cjs/Bash.d.ts +10 -0
- package/dist/cjs/Bash.d.ts.map +1 -1
- package/dist/cjs/Bash.js +13 -12
- package/dist/cjs/Bash.js.map +3 -3
- package/dist/cjs/Checkpoints.d.ts +37 -0
- package/dist/cjs/Checkpoints.d.ts.map +1 -1
- package/dist/cjs/Checkpoints.js +75 -0
- package/dist/cjs/Checkpoints.js.map +2 -2
- package/dist/cjs/internal/EnvelopePrecheck.d.ts +2 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -1
- package/dist/cjs/internal/EnvelopePrecheck.js +217 -34
- package/dist/cjs/internal/EnvelopePrecheck.js.map +3 -3
- package/dist/cjs/internal/Exec.d.ts +26 -14
- package/dist/cjs/internal/Exec.d.ts.map +1 -1
- package/dist/cjs/internal/Exec.js +73 -31
- package/dist/cjs/internal/Exec.js.map +2 -2
- package/dist/cjs/internal/Text.d.ts +11 -0
- package/dist/cjs/internal/Text.d.ts.map +1 -1
- package/dist/cjs/internal/Text.js +3 -0
- package/dist/cjs/internal/Text.js.map +2 -2
- package/dist/esm/Bash.d.ts +10 -0
- package/dist/esm/Bash.d.ts.map +1 -1
- package/dist/esm/Bash.js +22 -13
- package/dist/esm/Bash.js.map +1 -1
- package/dist/esm/Checkpoints.d.ts +37 -0
- package/dist/esm/Checkpoints.d.ts.map +1 -1
- package/dist/esm/Checkpoints.js +85 -0
- package/dist/esm/Checkpoints.js.map +1 -1
- package/dist/esm/internal/EnvelopePrecheck.d.ts +2 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -1
- package/dist/esm/internal/EnvelopePrecheck.js +295 -60
- package/dist/esm/internal/EnvelopePrecheck.js.map +1 -1
- package/dist/esm/internal/Exec.d.ts +26 -14
- package/dist/esm/internal/Exec.d.ts.map +1 -1
- package/dist/esm/internal/Exec.js +116 -30
- package/dist/esm/internal/Exec.js.map +1 -1
- package/dist/esm/internal/Text.d.ts +11 -0
- package/dist/esm/internal/Text.d.ts.map +1 -1
- package/dist/esm/internal/Text.js +11 -0
- package/dist/esm/internal/Text.js.map +1 -1
- package/docs/README.md +3 -1
- package/docs/api.md +21 -18
- package/docs/concepts/limits-and-disclosure.md +8 -5
- package/docs/guides/pin-a-checkpoint.md +20 -0
- package/docs/guides/run-a-shell-command.md +16 -6
- package/docs/installation.md +13 -9
- package/docs/quickstart.md +1 -1
- package/docs/reference/flows.md +2 -2
- package/docs/troubleshooting.md +15 -3
- package/package.json +6 -6
- package/src/Bash.ts +25 -13
- package/src/Checkpoints.ts +137 -0
- package/src/internal/EnvelopePrecheck.ts +295 -63
- package/src/internal/Exec.ts +157 -51
- package/src/internal/Text.ts +15 -0
package/docs/reference/flows.md
CHANGED
|
@@ -241,9 +241,9 @@ envelope `bash` declares for every call.
|
|
|
241
241
|
| Output | Type | Meaning |
|
|
242
242
|
| ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------------------- |
|
|
243
243
|
| `exitCode` | number | The command's exit code, including non-zero. |
|
|
244
|
-
| `stdout`, `stderr` | string | Captured streams
|
|
244
|
+
| `stdout`, `stderr` | string | Captured streams; start and end kept when truncated. |
|
|
245
245
|
| `stdoutTruncated`, `stderrTruncated` | boolean | Whether that stream is a fragment. |
|
|
246
|
-
| `stdoutDroppedBytes`, `stderrDroppedBytes` | number | Bytes omitted from the
|
|
246
|
+
| `stdoutDroppedBytes`, `stderrDroppedBytes` | number | Bytes omitted from the middle. |
|
|
247
247
|
| `invalidProbe` | `Probe.InvalidProbe`, optional | Reserved for independently confirmed launch failures; not inferred from exit code. |
|
|
248
248
|
|
|
249
249
|
`Bash.Input` and `Bash.Output` are also exported as TypeScript types alongside
|
package/docs/troubleshooting.md
CHANGED
|
@@ -160,6 +160,18 @@ The same rule refuses a hermetic `script` whose `interpreter` is not a shell:
|
|
|
160
160
|
the pre-check reads shell text, and Python is not shell text. Run it
|
|
161
161
|
unhermetically, or express it as shell.
|
|
162
162
|
|
|
163
|
+
## invalid_input: Command not started: its arguments exceed the operating system's size limit (E2BIG)
|
|
164
|
+
|
|
165
|
+
**What happened.** The operating system refused to start the command because
|
|
166
|
+
its arguments are too large: one argument over 128 KiB on Linux, or all of them
|
|
167
|
+
over 1 MiB on macOS. A long heredoc in `command`, or a file's text passed in
|
|
168
|
+
`args`, is one such argument. For a `container` call the host's `docker exec`
|
|
169
|
+
carries the same arguments, so the same limit applies.
|
|
170
|
+
|
|
171
|
+
**What to change.** Send the text on standard input, which has no size limit.
|
|
172
|
+
Put a program and its data in `script`, or keep `command` short and pass the
|
|
173
|
+
data in `stdin`. Never put long text in `command` or `args`.
|
|
174
|
+
|
|
163
175
|
## provider_unavailable: this host has no container transport
|
|
164
176
|
|
|
165
177
|
**What happened.** A call named a `container` and no `Container` service was
|
|
@@ -260,11 +272,11 @@ runs. The server would have run workspace-written code on the host.
|
|
|
260
272
|
absolute path, not a launcher. For typescript-language-server, also pin
|
|
261
273
|
`initializationOptions: { tsserver: { path } }` to a host copy.
|
|
262
274
|
|
|
263
|
-
## A write of captured output replaced a file with a
|
|
275
|
+
## A write of captured output replaced a file with a fragment
|
|
264
276
|
|
|
265
277
|
**What happened.** A truncated `stdout`, `stderr`, or `tail` was written to a
|
|
266
|
-
file. Those fields are fragments: the
|
|
267
|
-
printed,
|
|
278
|
+
file. Those fields are fragments: `bash` keeps the start and the end of what the
|
|
279
|
+
process printed and `test` keeps the tail, never the whole of it.
|
|
268
280
|
|
|
269
281
|
**What to change.** Check `stdoutTruncated`, `stderrTruncated`, or
|
|
270
282
|
`tailTruncated` before writing captured output anywhere.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smthrs/std",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.8",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"smthrs": {
|
|
7
7
|
"group": "agent"
|
|
@@ -401,11 +401,11 @@
|
|
|
401
401
|
"tag": "next"
|
|
402
402
|
},
|
|
403
403
|
"dependencies": {
|
|
404
|
-
"@smthrs/capability": "1.0.0-rc.
|
|
405
|
-
"@smthrs/control": "1.0.0-rc.
|
|
406
|
-
"@smthrs/core": "1.0.0-rc.
|
|
407
|
-
"@smthrs/kernel": "1.0.0-rc.
|
|
408
|
-
"@smthrs/model": "1.0.0-rc.
|
|
404
|
+
"@smthrs/capability": "1.0.0-rc.8",
|
|
405
|
+
"@smthrs/control": "1.0.0-rc.8",
|
|
406
|
+
"@smthrs/core": "1.0.0-rc.8",
|
|
407
|
+
"@smthrs/kernel": "1.0.0-rc.8",
|
|
408
|
+
"@smthrs/model": "1.0.0-rc.8"
|
|
409
409
|
},
|
|
410
410
|
"devDependencies": {
|
|
411
411
|
"@effect/language-service": "0.87.2",
|
package/src/Bash.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { capability, envelope } from "./internal/Declaration.ts"
|
|
|
27
27
|
import * as Diagnostics from "./internal/Diagnostics.ts"
|
|
28
28
|
import { outsideEnvelope } from "./internal/EnvelopePrecheck.ts"
|
|
29
29
|
import * as Exec from "./internal/Exec.ts"
|
|
30
|
-
import {
|
|
30
|
+
import { elideMiddle as elide, MAX_SHELL_OUTPUT_BYTES } from "./internal/Text.ts"
|
|
31
31
|
import * as Probe from "./Probe.ts"
|
|
32
32
|
import * as StdError from "./StdError.ts"
|
|
33
33
|
import * as TreeFingerprint from "./TreeFingerprint.ts"
|
|
@@ -173,10 +173,12 @@ export type Input = typeof Input.Type
|
|
|
173
173
|
export const Output = Schema.Struct({
|
|
174
174
|
exitCode: Schema.Number.annotate({ description: "Command exit code, including non-zero codes" }),
|
|
175
175
|
stdout: Schema.String.annotate({
|
|
176
|
-
description:
|
|
176
|
+
description:
|
|
177
|
+
"Captured stdout; when stdoutTruncated is true, only its start and end, with one line naming the bytes omitted between them"
|
|
177
178
|
}),
|
|
178
179
|
stderr: Schema.String.annotate({
|
|
179
|
-
description:
|
|
180
|
+
description:
|
|
181
|
+
"Captured stderr; when stderrTruncated is true, only its start and end, with one line naming the bytes omitted between them"
|
|
180
182
|
}),
|
|
181
183
|
stdoutTruncated: Schema.Boolean.annotate({
|
|
182
184
|
description:
|
|
@@ -186,8 +188,8 @@ export const Output = Schema.Struct({
|
|
|
186
188
|
description:
|
|
187
189
|
"Whether stderr exceeded the capture limit, leaving stderr a fragment that must not be written to a file"
|
|
188
190
|
}),
|
|
189
|
-
stdoutDroppedBytes: Schema.Number.annotate({ description: "UTF-8 bytes omitted from the
|
|
190
|
-
stderrDroppedBytes: Schema.Number.annotate({ description: "UTF-8 bytes omitted from the
|
|
191
|
+
stdoutDroppedBytes: Schema.Number.annotate({ description: "UTF-8 bytes omitted from the middle of stdout" }),
|
|
192
|
+
stderrDroppedBytes: Schema.Number.annotate({ description: "UTF-8 bytes omitted from the middle of stderr" }),
|
|
191
193
|
invalidProbe: Schema.optional(
|
|
192
194
|
Probe.InvalidProbe.annotate({
|
|
193
195
|
description: "Reserved for a confirmed launch failure; an exit code alone does not establish one"
|
|
@@ -209,6 +211,17 @@ export const Output = Schema.Struct({
|
|
|
209
211
|
*/
|
|
210
212
|
export type Output = typeof Output.Type
|
|
211
213
|
|
|
214
|
+
/**
|
|
215
|
+
* The text of a stream cut to its start and end: the start, one line naming
|
|
216
|
+
* the bytes omitted between them, and the end. A host that captures output
|
|
217
|
+
* itself, such as a terminal behind {@link inTerminal}, cuts with this so every
|
|
218
|
+
* {@link Output} reads the same.
|
|
219
|
+
*
|
|
220
|
+
* @category rendering
|
|
221
|
+
* @since 1.0.0-rc.5
|
|
222
|
+
*/
|
|
223
|
+
export const elideMiddle: (start: string, droppedBytes: number, end: string) => string = elide
|
|
224
|
+
|
|
212
225
|
/**
|
|
213
226
|
* Static conservative effect envelope for the bash flow.
|
|
214
227
|
*
|
|
@@ -500,6 +513,7 @@ export const run = Effect.fn("Bash.run")(function*(
|
|
|
500
513
|
...(spawned.env === undefined ? {} : { env: spawned.env }),
|
|
501
514
|
timeoutMs: input.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
502
515
|
maxCaptureBytes: MAX_SHELL_OUTPUT_BYTES,
|
|
516
|
+
overflow: "ends",
|
|
503
517
|
...(spawned.args === undefined ? {} : { args: spawned.args }),
|
|
504
518
|
...(spawned.stdin === undefined ? {} : { stdin: spawned.stdin })
|
|
505
519
|
}).pipe(Effect.mapError((error) => Exec.toStdError(spawned.quoted, error)))
|
|
@@ -507,18 +521,16 @@ export const run = Effect.fn("Bash.run")(function*(
|
|
|
507
521
|
// A command on this host may have changed files a language server holds
|
|
508
522
|
// open; a container's files are not the ones it was sent.
|
|
509
523
|
if (!contained) yield* Diagnostics.refresh
|
|
510
|
-
const stdout = truncateBytes(result.stdout, MAX_SHELL_OUTPUT_BYTES, { keep: "tail" })
|
|
511
|
-
const stderr = truncateBytes(result.stderr, MAX_SHELL_OUTPUT_BYTES, { keep: "tail" })
|
|
512
524
|
// Exit codes alone cannot establish whether the shell refused to launch a
|
|
513
525
|
// command or a launched runner chose that status after executing tests.
|
|
514
526
|
return {
|
|
515
527
|
exitCode: result.exitCode,
|
|
516
|
-
stdout: stdout
|
|
517
|
-
stderr: stderr
|
|
518
|
-
stdoutTruncated: result.stdoutDroppedBytes > 0
|
|
519
|
-
stderrTruncated: result.stderrDroppedBytes > 0
|
|
520
|
-
stdoutDroppedBytes: result.stdoutDroppedBytes
|
|
521
|
-
stderrDroppedBytes: result.stderrDroppedBytes
|
|
528
|
+
stdout: result.stdout,
|
|
529
|
+
stderr: result.stderr,
|
|
530
|
+
stdoutTruncated: result.stdoutDroppedBytes > 0,
|
|
531
|
+
stderrTruncated: result.stderrDroppedBytes > 0,
|
|
532
|
+
stdoutDroppedBytes: result.stdoutDroppedBytes,
|
|
533
|
+
stderrDroppedBytes: result.stderrDroppedBytes,
|
|
522
534
|
...(mutated === undefined ? {} : { mutated })
|
|
523
535
|
}
|
|
524
536
|
})
|
package/src/Checkpoints.ts
CHANGED
|
@@ -72,6 +72,8 @@
|
|
|
72
72
|
|
|
73
73
|
import { ChildProcessSpawner } from "@smthrs/kernel/ChildProcessSpawner"
|
|
74
74
|
import { Context, Effect, Layer, Schema } from "effect"
|
|
75
|
+
import * as Container from "./Container.ts"
|
|
76
|
+
import * as Exec from "./internal/Exec.ts"
|
|
75
77
|
import { GitWorktree } from "./internal/GitWorktree.ts"
|
|
76
78
|
import { withoutTrailingSlash } from "./internal/Paths.ts"
|
|
77
79
|
import * as Prune from "./internal/Prune.ts"
|
|
@@ -409,6 +411,141 @@ const gitStore = (options: GitOptions, spawner: ChildProcessSpawner["Service"]):
|
|
|
409
411
|
*/
|
|
410
412
|
export const layerGit = (options: GitOptions): Layer.Layer<Checkpoints, never, ChildProcessSpawner> =>
|
|
411
413
|
Layer.effect(Checkpoints)(makeGit(options))
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* What {@link makeContainer} needs to know about the container it pins in.
|
|
417
|
+
*
|
|
418
|
+
* @category models
|
|
419
|
+
* @since 1.0.0-rc.8
|
|
420
|
+
*/
|
|
421
|
+
export interface ContainerOptions {
|
|
422
|
+
/** The container `bash` runs in. */
|
|
423
|
+
readonly container: string
|
|
424
|
+
/** A directory of the repository inside it; absent is the container's own working directory. */
|
|
425
|
+
readonly cwd?: string | undefined
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* `$1` is the id. Records the working tree with `stash create` over a copy of
|
|
430
|
+
* the index, names the commit in config as {@link makeGit} does, and prints it.
|
|
431
|
+
*/
|
|
432
|
+
const pinScript = [
|
|
433
|
+
"set -e",
|
|
434
|
+
"cd \"$(git rev-parse --show-toplevel)\"",
|
|
435
|
+
"copy=$(mktemp -d)",
|
|
436
|
+
"trap 'rm -rf -- \"$copy\"' EXIT",
|
|
437
|
+
"index=$(git rev-parse --git-path index)",
|
|
438
|
+
"if [ -e \"$index\" ]; then cp -p -- \"$index\" \"$copy/index\"; fi",
|
|
439
|
+
"commit=$(GIT_INDEX_FILE=\"$copy/index\" git -c user.name=flows -c user.email=flows@localhost stash create \"flows checkpoint $1\")",
|
|
440
|
+
"[ -n \"$commit\" ] || commit=$(git rev-parse --verify 'HEAD^{commit}')",
|
|
441
|
+
`git config "${configSection}.$1" "$commit"`,
|
|
442
|
+
"printf '%s\\n' \"$commit\""
|
|
443
|
+
].join("\n")
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* `$1` is the id, `$2` the lease. Checks the tree out at
|
|
447
|
+
* `<top>/.flows-checkpoints/<id>-<lease>` in a repository of its own whose
|
|
448
|
+
* objects are the workspace's, and prints the top and the checkout.
|
|
449
|
+
*/
|
|
450
|
+
const checkoutScript = [
|
|
451
|
+
"set -e",
|
|
452
|
+
"top=$(git rev-parse --show-toplevel)",
|
|
453
|
+
"cd \"$top\"",
|
|
454
|
+
"common=$(cd \"$(git rev-parse --git-common-dir)\" && pwd -P)",
|
|
455
|
+
`if [ "$1" = ${baseId} ]; then`,
|
|
456
|
+
` commit=$(git rev-parse --verify --quiet '${TestRunner.captureBase}^{commit}' || git rev-parse --verify --quiet 'HEAD^{commit}') || { echo "No commit resolves from ${TestRunner.captureBase} or HEAD in $top." >&2; exit 1; }`,
|
|
457
|
+
"else",
|
|
458
|
+
` commit=$(git config --get "${configSection}.$1") || { echo "No checkpoint is stored under $1 in $top. Take the reading on the live tree instead." >&2; exit 1; }`,
|
|
459
|
+
"fi",
|
|
460
|
+
`dir="$top/${scratchDirectory}/$1-$2"`,
|
|
461
|
+
"trap 'rm -rf -- \"$dir\"' EXIT",
|
|
462
|
+
`mkdir -p -- "$top/${scratchDirectory}"`,
|
|
463
|
+
"git init --quiet \"$dir\"",
|
|
464
|
+
"printf '%s/objects\\n' \"$common\" > \"$dir/.git/objects/info/alternates\"",
|
|
465
|
+
"git -C \"$dir\" checkout --quiet --detach \"$commit\"",
|
|
466
|
+
"trap - EXIT",
|
|
467
|
+
"printf '%s\\n%s\\n' \"$top\" \"$dir\""
|
|
468
|
+
].join("\n")
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Builds the store for a host whose `bash` runs in one container.
|
|
472
|
+
*
|
|
473
|
+
* The repository is the container's, so every git command runs there, through
|
|
474
|
+
* the same {@link Container.Container} transport `bash` takes. The host store
|
|
475
|
+
* looked in the CLI's own directory instead and refused every `at` in 112 of
|
|
476
|
+
* 123 trials of the 2026-10-14 SWE-bench Pro run. This keeps that store's
|
|
477
|
+
* shape: a checkpoint is a `stash create` commit named in config, and a tree
|
|
478
|
+
* is checked out under the repository for one call, so a relocated `bash`
|
|
479
|
+
* call keeps its subdirectory and still finds what the workspace installs
|
|
480
|
+
* beside it. That git may run what the repository configures, but only inside
|
|
481
|
+
* the container the agent already commands.
|
|
482
|
+
*
|
|
483
|
+
* @category constructors
|
|
484
|
+
* @since 1.0.0-rc.8
|
|
485
|
+
*/
|
|
486
|
+
export const makeContainer = (
|
|
487
|
+
options: ContainerOptions
|
|
488
|
+
): Effect.Effect<Checkpoints, never, ChildProcessSpawner | Container.Container> =>
|
|
489
|
+
Effect.gen(function*() {
|
|
490
|
+
const spawner = yield* ChildProcessSpawner
|
|
491
|
+
const transport = yield* Container.Container
|
|
492
|
+
const sh = (script: string, args: ReadonlyArray<string>) =>
|
|
493
|
+
transport.exec({
|
|
494
|
+
container: options.container,
|
|
495
|
+
file: "sh",
|
|
496
|
+
args: ["-c", script, "sh", ...args],
|
|
497
|
+
cwd: options.cwd,
|
|
498
|
+
stdin: false
|
|
499
|
+
}).pipe(
|
|
500
|
+
Effect.flatMap((plan) =>
|
|
501
|
+
Exec.exec(plan.file, { args: plan.args, env: plan.env }).pipe(
|
|
502
|
+
Effect.mapError((error) => Exec.toStdError(plan.file, error))
|
|
503
|
+
)
|
|
504
|
+
),
|
|
505
|
+
Effect.flatMap((result) =>
|
|
506
|
+
result.exitCode === 0
|
|
507
|
+
? Effect.succeed(result.stdout.trim().split("\n"))
|
|
508
|
+
: Effect.fail(failed(`git in container ${options.container} failed: ${result.stderr.trim()}`))
|
|
509
|
+
),
|
|
510
|
+
Effect.provideService(ChildProcessSpawner, spawner)
|
|
511
|
+
)
|
|
512
|
+
const named = (id: string) =>
|
|
513
|
+
namable.test(id)
|
|
514
|
+
? Effect.void
|
|
515
|
+
: Effect.fail(failed(`A checkpoint id must match ${namable.source}; ${id} does not.`, "invalid_input"))
|
|
516
|
+
return make({
|
|
517
|
+
capture: (id) =>
|
|
518
|
+
named(id).pipe(
|
|
519
|
+
Effect.andThen(sh(pinScript, [id])),
|
|
520
|
+
Effect.map(([commit]) => new Snapshot({ id, ref: commit! }))
|
|
521
|
+
),
|
|
522
|
+
materialize: (id, use) =>
|
|
523
|
+
named(id).pipe(Effect.andThen(Effect.acquireUseRelease(
|
|
524
|
+
sh(checkoutScript, [id, globalThis.crypto.randomUUID()]),
|
|
525
|
+
([root, checkout]) => use({ id, host: checkout!, guest: checkout!, root: root!, guestRoot: root! }),
|
|
526
|
+
([, checkout]) =>
|
|
527
|
+
sh("rm -rf -- \"$1\"", [checkout!]).pipe(
|
|
528
|
+
Effect.catch((error) =>
|
|
529
|
+
Effect.logWarning("could not remove a scratch checkout").pipe(
|
|
530
|
+
Effect.annotateLogs({ path: checkout, reason: error.message })
|
|
531
|
+
)
|
|
532
|
+
)
|
|
533
|
+
)
|
|
534
|
+
)))
|
|
535
|
+
})
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Provides {@link makeContainer}.
|
|
540
|
+
*
|
|
541
|
+
* @category layers
|
|
542
|
+
* @since 1.0.0-rc.8
|
|
543
|
+
*/
|
|
544
|
+
export const layerContainer = (
|
|
545
|
+
options: ContainerOptions
|
|
546
|
+
): Layer.Layer<Checkpoints, never, ChildProcessSpawner | Container.Container> =>
|
|
547
|
+
Layer.effect(Checkpoints)(makeContainer(options))
|
|
548
|
+
|
|
412
549
|
/**
|
|
413
550
|
* Rewrites one call's input so the call runs against a materialized checkpoint.
|
|
414
551
|
*
|