fix(core): stream shell progress tail
This commit is contained in:
parent
ac1b802820
commit
4778e6e031
2 changed files with 30 additions and 9 deletions
|
|
@ -17,6 +17,7 @@ export const name = "shell"
|
|||
export const DEFAULT_TIMEOUT_MS = 2 * 60 * 1_000
|
||||
export const MAX_TIMEOUT_MS = 10 * 60 * 1_000
|
||||
export const MAX_CAPTURE_BYTES = 1024 * 1024
|
||||
export const PROGRESS_LINES = 25
|
||||
|
||||
const BACKGROUND_STARTED = "The command was moved to the background."
|
||||
const BACKGROUND_INSTRUCTION =
|
||||
|
|
@ -210,6 +211,23 @@ export const Plugin = {
|
|||
}
|
||||
})
|
||||
|
||||
const captureProgress = Effect.fn("ShellTool.captureProgress")(function* () {
|
||||
const latest = yield* shell.output(info.id, { cursor: Number.MAX_SAFE_INTEGER })
|
||||
const start = Math.max(0, latest.size - MAX_CAPTURE_BYTES)
|
||||
const page = yield* shell.output(info.id, { cursor: start, limit: MAX_CAPTURE_BYTES })
|
||||
const trailingNewline = page.output.endsWith("\n")
|
||||
const lines = trailingNewline ? page.output.split("\n").slice(0, -1) : page.output.split("\n")
|
||||
const truncated = start > 0 || lines.length > PROGRESS_LINES
|
||||
const output = lines.slice(-PROGRESS_LINES).join("\n") + (trailingNewline ? "\n" : "")
|
||||
const notice = truncated
|
||||
? `[output truncated; showing last ${PROGRESS_LINES} lines. Full output saved to: ${info.file}]\n\n`
|
||||
: ""
|
||||
return {
|
||||
output: `${notice}${output || "(no output)"}`,
|
||||
truncated,
|
||||
}
|
||||
})
|
||||
|
||||
const settleShell = Effect.fn("ShellTool.settleShell")(function* () {
|
||||
const final = yield* shell.wait(info.id)
|
||||
|
||||
|
|
@ -258,7 +276,7 @@ export const Plugin = {
|
|||
|
||||
const progress = yield* Effect.sleep("1 second").pipe(
|
||||
Effect.andThen(
|
||||
captureShell().pipe(
|
||||
captureProgress().pipe(
|
||||
Effect.flatMap((capture) =>
|
||||
context.progress({
|
||||
structured: { truncated: capture.truncated },
|
||||
|
|
|
|||
|
|
@ -166,10 +166,10 @@ const overflowCommand = (bytes: number) =>
|
|||
isWindows
|
||||
? `[Console]::Out.Write(('x' * ${bytes})); Start-Sleep -Milliseconds 100`
|
||||
: `head -c ${bytes} /dev/zero | tr '\\0' 'x'`
|
||||
const progressOverflowCommand = (bytes: number) =>
|
||||
const progressLinesCommand = (lines: number) =>
|
||||
isWindows
|
||||
? `[Console]::Out.Write(('x' * ${bytes})); Start-Sleep -Milliseconds 1500`
|
||||
: `head -c ${bytes} /dev/zero | tr '\\0' 'x'; sleep 1.5`
|
||||
? `1..${lines} | ForEach-Object { [Console]::Out.WriteLine(('line {0:d2}' -f $_)) }; Start-Sleep -Milliseconds 1500`
|
||||
: `i=1; while [ $i -le ${lines} ]; do printf 'line %02d\\n' "$i"; i=$((i+1)); done; sleep 1.5`
|
||||
|
||||
const withSession = <A, E, R>(directory: string, body: (registry: ToolRegistry.Interface) => Effect.Effect<A, E, R>) =>
|
||||
Effect.gen(function* () {
|
||||
|
|
@ -417,17 +417,17 @@ describe("ShellTool", () => {
|
|||
),
|
||||
)
|
||||
|
||||
it.live("reports bounded output progress for a running command", () =>
|
||||
it.live("reports the latest output lines for a running command", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) => {
|
||||
reset()
|
||||
const bytes = ShellTool.MAX_CAPTURE_BYTES + 1024
|
||||
const lines = ShellTool.PROGRESS_LINES + 10
|
||||
return withSession(tmp.path, (registry) =>
|
||||
Effect.gen(function* () {
|
||||
const progress: ToolRegistry.Progress[] = []
|
||||
yield* settleTool(registry, {
|
||||
...call({ command: progressOverflowCommand(bytes) }, "call-progress"),
|
||||
...call({ command: progressLinesCommand(lines) }, "call-progress"),
|
||||
progress: (update) => Effect.sync(() => progress.push(update)),
|
||||
})
|
||||
|
||||
|
|
@ -436,9 +436,12 @@ describe("ShellTool", () => {
|
|||
const content = progress[0]?.content[0]
|
||||
expect(content?.type).toBe("text")
|
||||
if (content?.type !== "text") return
|
||||
expect(content.text.indexOf("\n\n[output truncated; full output saved to:")).toBe(
|
||||
ShellTool.MAX_CAPTURE_BYTES,
|
||||
expect(content.text).toStartWith(
|
||||
`[output truncated; showing last ${ShellTool.PROGRESS_LINES} lines. Full output saved to:`,
|
||||
)
|
||||
expect(content.text).not.toContain("line 10\n")
|
||||
expect(content.text).toContain("line 11\n")
|
||||
expect(content.text).toContain(`line ${lines}\n`)
|
||||
}),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue