mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
e20994a8ea
* fix(ghidra): keep JVM warnings out of LaunchSupport output Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ghidra): retain LaunchSupport warnings in session diagnostics * fix(ghidra): select helper logging flags by observed JVM identity * fix(ghidra): preserve diagnostics through typed failure projection --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
import type { AnalysisError } from "./analysisErrorBase.js";
|
|
import {
|
|
AnalysisAccessDeniedError,
|
|
AnalysisArtifactChangedError,
|
|
AnalysisInputError,
|
|
AnalysisOutputError,
|
|
AnalysisCapabilityUnavailableError,
|
|
AnalysisResourceConstraintError,
|
|
AnalysisCancelledError,
|
|
AnalysisTimeoutError,
|
|
} from "./analysisErrorCore.js";
|
|
import { redactExplicitText } from "./explicitSensitiveValues.js";
|
|
import type { JsonValue } from "./jsonValue.js";
|
|
import { ProviderAdapterError } from "./providerAdapterError.js";
|
|
import { ProviderCleanupError } from "./providerCleanupError.js";
|
|
|
|
/** Keep a real JSON-pointer ancestor when a property identity is explicitly excluded. */
|
|
export const redactExplicitPointer = (
|
|
pointer: string,
|
|
values: readonly string[],
|
|
): string => {
|
|
let parent = "";
|
|
for (const segment of pointer.split("/").slice(1)) {
|
|
const decoded = segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
const child = `${parent}/${segment}`;
|
|
if (
|
|
values.some(
|
|
(literal) => decoded.includes(literal) || child.includes(literal),
|
|
)
|
|
)
|
|
return parent;
|
|
parent = child;
|
|
}
|
|
return parent;
|
|
};
|
|
|
|
/** Exclude explicit literals from common acquisition/decoder failures, preserving typed diagnostics. */
|
|
export const redactExplicitFailure = (
|
|
error: AnalysisError,
|
|
values: readonly string[],
|
|
): AnalysisError => {
|
|
if (values.length === 0) return error;
|
|
const text = (value: string): string => redactExplicitText(value, values);
|
|
const path = (
|
|
parts: readonly (string | number)[],
|
|
ordinaryNames: boolean,
|
|
): (string | number)[] => {
|
|
const retained: (string | number)[] = [];
|
|
for (const part of parts) {
|
|
if (typeof part !== "string") {
|
|
retained.push(part);
|
|
} else if (!ordinaryNames && part.startsWith("/")) {
|
|
const pointer = redactExplicitPointer(part, values);
|
|
retained.push(pointer);
|
|
if (pointer !== part) break;
|
|
} else {
|
|
if (values.some((literal) => part.includes(literal))) break;
|
|
retained.push(part);
|
|
}
|
|
}
|
|
return retained;
|
|
};
|
|
const diagnostics = (
|
|
value: Readonly<Record<string, JsonValue>>,
|
|
): Record<string, JsonValue> =>
|
|
Object.fromEntries(
|
|
Object.entries(value)
|
|
.filter(([key]) => !values.some((literal) => key.includes(literal)))
|
|
.map(([key, item]) => [key, visit(item)]),
|
|
);
|
|
const visit = (value: JsonValue): JsonValue => {
|
|
if (typeof value === "string") return text(value);
|
|
if (Array.isArray(value)) return value.map(visit);
|
|
if (typeof value === "object" && value !== null) return diagnostics(value);
|
|
return value;
|
|
};
|
|
const context = {
|
|
cause: error,
|
|
...(error.diagnostics === undefined
|
|
? {}
|
|
: { diagnostics: diagnostics(error.diagnostics) }),
|
|
...(error.capturedOutput === undefined
|
|
? {}
|
|
: {
|
|
capturedOutput: {
|
|
...error.capturedOutput,
|
|
stdout: text(error.capturedOutput.stdout),
|
|
stderr: text(error.capturedOutput.stderr),
|
|
},
|
|
}),
|
|
...(error.cleanup === undefined
|
|
? {}
|
|
: {
|
|
cleanup: {
|
|
reason: text(error.cleanup.reason),
|
|
resources: error.cleanup.resources.map(text),
|
|
},
|
|
}),
|
|
};
|
|
if (error instanceof AnalysisCancelledError)
|
|
return new AnalysisCancelledError(error.operation, {
|
|
...context,
|
|
partialObservation: error.partialObservation,
|
|
});
|
|
if (error instanceof AnalysisTimeoutError)
|
|
return new AnalysisTimeoutError(error.operation, error.timeoutMs, {
|
|
...context,
|
|
partialObservation: error.partialObservation,
|
|
});
|
|
if (error instanceof AnalysisAccessDeniedError)
|
|
return new AnalysisAccessDeniedError(
|
|
error.operation,
|
|
text(error.path),
|
|
error.systemCode,
|
|
context,
|
|
);
|
|
if (error instanceof AnalysisArtifactChangedError)
|
|
return new AnalysisArtifactChangedError(
|
|
error.operation,
|
|
text(error.path),
|
|
text(error.reason),
|
|
context,
|
|
);
|
|
if (error instanceof AnalysisInputError)
|
|
return new AnalysisInputError(
|
|
error.operation,
|
|
context,
|
|
error.issues.map((issue) => ({
|
|
...issue,
|
|
// Unknown-argument paths contain literal field names, including names
|
|
// beginning with '/'; they are not producer JSON-pointer coordinates.
|
|
path: path(issue.path, issue.reason === "unknown_argument"),
|
|
...(issue.message === undefined
|
|
? {}
|
|
: { message: text(issue.message) }),
|
|
...(issue.expected === undefined
|
|
? {}
|
|
: { expected: visit(issue.expected) }),
|
|
})),
|
|
);
|
|
if (error instanceof AnalysisOutputError)
|
|
return new AnalysisOutputError(
|
|
error.operation,
|
|
text(error.reason),
|
|
context,
|
|
);
|
|
if (error instanceof AnalysisCapabilityUnavailableError)
|
|
return new AnalysisCapabilityUnavailableError(
|
|
error.providerId,
|
|
error.operation,
|
|
text(error.reason),
|
|
{
|
|
...context,
|
|
...(error.userMessage === undefined
|
|
? {}
|
|
: { userMessage: text(error.userMessage) }),
|
|
},
|
|
);
|
|
if (error instanceof AnalysisResourceConstraintError)
|
|
return new AnalysisResourceConstraintError(
|
|
error.operation,
|
|
error.resource,
|
|
text(error.reason),
|
|
error.reportedLimits === null ? null : diagnostics(error.reportedLimits),
|
|
{
|
|
...context,
|
|
...(error.remediationAction === undefined
|
|
? {}
|
|
: { remediationAction: text(error.remediationAction) }),
|
|
},
|
|
);
|
|
if (error instanceof ProviderCleanupError)
|
|
return new ProviderCleanupError(
|
|
error.providerId,
|
|
error.cleanupResources.map(text),
|
|
diagnostics(error.diagnostics ?? {}),
|
|
{ operation: error.operation, cause: error },
|
|
);
|
|
if (error instanceof ProviderAdapterError)
|
|
return new ProviderAdapterError(error.providerId, error.operation, context);
|
|
return error;
|
|
};
|