mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-13 04:03:30 +00:00
44 lines
2.0 KiB
TypeScript
44 lines
2.0 KiB
TypeScript
/**
|
|
* Shared rendering helpers for the shell tools (`dsh-tool-bash`,
|
|
* `dsh-tool-pwsh`): the exit-status marker contract the tools' renderers emit,
|
|
* Host `presentResult` implementations parse here, and the Web terminal card
|
|
* model mirrors without importing Host code.
|
|
* @module @deepseek-ai/dsh-shell/render
|
|
*/
|
|
|
|
/**
|
|
* The exit status recovered from a rendered result, with the output body that
|
|
* status was split off from.
|
|
*/
|
|
export type ParsedExitStatus =
|
|
& { body: string }
|
|
& ({ exitCode: number } | { signal: string })
|
|
|
|
/**
|
|
* Split a rendered shell-tool result string into its output body and the
|
|
* structured exit status — the inverse of the `[exit code: N]` /
|
|
* `[killed by signal: X]` markers the shell tools' renderers append. A killed
|
|
* marker yields `signal`; otherwise a non-zero marker yields `exitCode`;
|
|
* absent both means a clean exit 0.
|
|
*
|
|
* The consumed marker is removed from `body` because a terminal presentation
|
|
* shows the exit status as its own pill: leaving the marker in the output
|
|
* would render the exit twice. Other markers (timeout, sandbox denial) carry
|
|
* facts no pill shows, so they stay in the body.
|
|
*
|
|
* Replay only retains the rendered content text, not the original
|
|
* `ShellRunResult`, so terminal presentation must recover the exit pill here.
|
|
* Requiring a leading newline and the end of the string keeps ordinary output
|
|
* that merely ends with marker-like text from matching unless the final line
|
|
* is indistinguishable from a real marker.
|
|
* @param text - rendered model-facing shell-tool result.
|
|
* @returns the marker-free body plus the recovered terminal exit code or signal.
|
|
*/
|
|
export function parseExitStatus(text: string): ParsedExitStatus {
|
|
const signal = /\n\[killed by signal: ([^\]\n]+)\]$/.exec(text)
|
|
if (signal?.[1] !== undefined) return { body: text.slice(0, signal.index), signal: signal[1] }
|
|
const exit = /\n\[exit code: (\d+)\]$/.exec(text)
|
|
if (exit?.[1] !== undefined) return { body: text.slice(0, exit.index), exitCode: Number(exit[1]) }
|
|
return { body: text, exitCode: 0 }
|
|
}
|