Files
reverse-engineering-anything/src/domain/commandObservation.ts
T
gensokyo-devandClaude Opus 5.5 6ce708cfde fix(rizin): report shell refusals instead of complete empty results
Rizin exits 0 when its shell refuses a statement, so execute_rizin_command
reported completion_status complete with exit code 0 and an empty stdout
that read as a genuine empty result.

Rizin 0.6 through 0.9.1 log exactly four refusal lines from
librz/core/cmd/cmd.c: an unknown command, a wrong argument count, an
invalid statement (RZ_CMD_STATUS_INVALID, which also stops the remaining
statements) and a parse error. The Rizin command profile now classifies a
completed process's stderr against those lines; the shared one-shot
service reports completion_status "rejected" and a limitation that names
the refusal and says stdout holds only earlier statements' output. Other
ERROR lines come from commands that ran and stay diagnostics.

Fixes #10364

Co-Authored-By: gensokyo-dev <gensokyo-dev@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 04:42:35 +01:00

63 lines
2.5 KiB
TypeScript

import { z } from "zod";
/** Opaque producer text and the command capture's explicit completion facts. */
export const commandObservationSchema = z.strictObject({
stdout: z.string(),
stderr: z.string(),
exit_code: z.union([z.string(), z.number(), z.null()]),
signal: z.string().nullable(),
output_budget_bytes: z.int().positive().exactOptional(),
output_budget_source: z.enum(["default", "request"]).exactOptional(),
output_truncated: z.boolean(),
completion_status: z
.enum(["complete", "rejected", "unknown"])
.describe(
"complete: the provider process completed. rejected: it completed, but the provider reported that it refused the command; limitations say what ran. unknown: the capture or process ended early.",
),
artifact_sha256_after: z
.string()
.regex(/^[a-f0-9]{64}$/u)
.nullable(),
artifact_changed: z.boolean().nullable(),
});
/** Exact producer admission that omitted command output; kinds define the unit. */
export const gdbOutputLimitSchema = z.strictObject({
kind: z.enum(["command_bytes", "command_records", "mi_line_bytes"]),
maximum: z.int().positive(),
});
export type GdbOutputLimit = z.infer<typeof gdbOutputLimitSchema>;
/** The GDB owner retains ordered records and derives its stream groupings. */
export const gdbCommandResultSchema = z.strictObject({
command: z.string(),
mi: z
.string()
.describe(
"The console command's independently framed MI result record; empty when a separate read-only query proves completion but raw stdout prevents identifying the original result class.",
),
records: z.array(z.string()),
console: z.string(),
target: z.string(),
log: z.string(),
process_exit_observed: z.boolean().exactOptional(),
process_exit_code: z.number().int().nullable().exactOptional(),
process_exit_signal: z.string().nullable().exactOptional(),
output_truncated: z.boolean(),
output_limits: z.array(gdbOutputLimitSchema).min(1).exactOptional(),
output_invalid_utf8: z.literal(true).exactOptional(),
completion_status: z.enum(["complete", "unknown"]),
});
/** Read-only capture facts; protocol interpretation stays with the provider. */
export type GdbCommandResult = Readonly<
Omit<z.infer<typeof gdbCommandResultSchema>, "records">
> & { readonly records: readonly string[] };
export const commandEvidenceDetailSchema = z
.enum(["complete", "summary"])
.default("complete")
.describe(
"complete returns the original Evidence; summary retains that complete parent and returns command output once with completion and source context.",
);