mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 09:27:29 +00:00
worker-start and task-create take --spec-file <path> (or - for stdin). worker-start --keep-open keeps a worker open after it finishes in one step, and worker-keep-open replaces worker-retain (kept as a hidden alias). Concise text output escapes terminal control characters in worker-written values.
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { readFile } from 'node:fs/promises'
|
|
import { isAbsolute, join } from 'node:path'
|
|
import { getRequiredStringFlag, getRequiredStringFlagAllowingEmpty } from './flags'
|
|
import { RuntimeClientError } from './runtime-client'
|
|
|
|
type BodyOptions = {
|
|
required: boolean
|
|
maximumCharacters: number
|
|
tooLargeCode: string
|
|
label: string
|
|
}
|
|
|
|
export function readCommandBody(
|
|
flags: Map<string, string | boolean>,
|
|
cwd: string,
|
|
options: BodyOptions & { required: true }
|
|
): Promise<string>
|
|
export function readCommandBody(
|
|
flags: Map<string, string | boolean>,
|
|
cwd: string,
|
|
options: BodyOptions
|
|
): Promise<string | undefined>
|
|
export async function readCommandBody(
|
|
flags: Map<string, string | boolean>,
|
|
cwd: string,
|
|
options: BodyOptions
|
|
): Promise<string | undefined> {
|
|
const body = await readTextOrFileFlag(flags, cwd, 'body', options.required)
|
|
if (body !== undefined && body.length > options.maximumCharacters) {
|
|
throw new RuntimeClientError(
|
|
options.tooLargeCode,
|
|
`${options.label} must be at most ${options.maximumCharacters} characters`
|
|
)
|
|
}
|
|
return body
|
|
}
|
|
|
|
/** Reads `--<flag> <text>` or `--<flag>-file <path|->`, refusing both. */
|
|
export async function readTextOrFileFlag(
|
|
flags: Map<string, string | boolean>,
|
|
cwd: string,
|
|
flag: string,
|
|
required: boolean
|
|
): Promise<string | undefined> {
|
|
const fileFlag = `${flag}-file`
|
|
const hasText = flags.has(flag)
|
|
const hasFile = flags.has(fileFlag)
|
|
if (hasText && hasFile) {
|
|
throw new RuntimeClientError(
|
|
'invalid_argument',
|
|
`Use either --${flag} or --${fileFlag}, not both`
|
|
)
|
|
}
|
|
if (!hasText && !hasFile) {
|
|
if (required) {
|
|
throw new RuntimeClientError('invalid_argument', `Missing --${flag} or --${fileFlag}`)
|
|
}
|
|
return undefined
|
|
}
|
|
return hasText
|
|
? getRequiredStringFlagAllowingEmpty(flags, flag)
|
|
: readBodyFile(getRequiredStringFlag(flags, fileFlag), cwd)
|
|
}
|
|
|
|
async function readBodyFile(path: string, cwd: string): Promise<string> {
|
|
if (path !== '-') {
|
|
return readFile(isAbsolute(path) ? path : join(cwd, path), 'utf8')
|
|
}
|
|
if (process.stdin.isTTY) {
|
|
throw new RuntimeClientError('invalid_argument', 'stdin body requested but stdin is a TTY')
|
|
}
|
|
const chunks: Buffer[] = []
|
|
for await (const chunk of process.stdin) {
|
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)))
|
|
}
|
|
return Buffer.concat(chunks).toString('utf8')
|
|
}
|