Files
reverse-engineering-anything/src/composition/javascriptAnalysisWorkerProcess.ts
T
morluto cb4e5cfbff feat(analysis): make resource budgets recoverable across CLI and MCP (#9706)
* refactor(analysis): centralize resource budgets and recovery facts

* feat(analysis): expose ASAR and Ghidra runtime admission controls

* feat(artifacts): expose reader admission and preserve limited recognition

* feat(javascript): expose recoverable semantic precision budgets

* feat(web): add recoverable source-map budgets and compact retained views

* feat(web): make historical capture decoding budgets recoverable

* fix(desktop): enforce selected view policies across capture and export

* feat(runtime): make Frida and LLDB retention budgets selectable

* feat(native): expose diagnostic budgets and preserve exhaustion causes

* feat(managed): expose recoverable snapshot and representation budgets

* feat(metadata): make Go and Rust inspection budgets recoverable

* feat(wasm): expose representation and producer admissions

* feat(evm): expose per-call worker resource budgets

* feat(android): make resource and string-pool omissions recoverable

* feat(producers): expose command and recorded-capture budgets

* docs(analysis): record recovery contracts and integrated validation

* fix(docs): link calibration oracle from published verification pages

* fix(docs): restore desktop task anchors and receipt links

* test(analysis): align fixtures with selectable budget contracts

* fix(analysis): remove source-location projector dependency cycle

* test(analysis): refresh budget recovery and verifier regressions

* test(analysis): preserve format and publication recovery expectations

* test(windows): align conformance with owned runtime admission

* fix(desktop): preserve selected alias kinds in exported state

* test(analysis): align provider fixtures with recoverable budgets

* test(desktop): validate emitted alias metadata structurally

* fix(ghidra): classify bounded Windows endpoint refusals

* test(cli): assert selectable artifact admission recovery

* fix(cli): preserve capture provenance in environment builds
2026-11-10 05:11:20 -05:00

117 lines
4.3 KiB
TypeScript

import { moduleResolutionModeForJavaScriptReference } from "../domain/javascript/javascriptModuleResolutionMode.js";
import { parseJavaScriptSource } from "../domain/javascript/javascriptSourceParser.js";
import { analyzeParsedJavaScriptStaticSourceSteps } from "../domain/javascript/javascriptStaticAnalysis.js";
import { analyzeParsedJavaScriptSemanticsSteps } from "../domain/javascript/javascriptSemanticAnalysis.js";
import { failedJavaScriptStaticAnalysis } from "../domain/javascript/javascriptStaticAnalysisHelpers.js";
import { projectJavaScriptModuleSemantics } from "../domain/javascript/javascriptModuleSemanticIr.js";
import {
javaScriptTransferByteBudget,
measureJavaScriptModuleTransfer,
} from "../javascript/analysis/JavaScriptAnalysisTransfer.js";
import { AnalysisResourceConstraintError } from "../domain/analysisErrorCore.js";
import { projectJavaScriptSemanticFileSteps } from "../application/javascript/JavaScriptSemanticGraphBuilder.js";
import { completeJavaScriptAnalysisSteps } from "../application/javascript/JavaScriptAnalysisControl.js";
import {
serveJavaScriptAnalysisWorker,
type JavaScriptSourceWorkerAnalyzer,
} from "../javascript/analysis/JavaScriptAnalysisWorkerServer.js";
const analyze: JavaScriptSourceWorkerAnalyzer = async (
file,
capacity,
callbacks,
packageType,
purpose,
precision,
) => {
if (!file.text.included)
throw new TypeError("JavaScript worker requires decoded source text");
await callbacks.phase("parse");
let parsed = parseJavaScriptSource(file.text.value, file.path, packageType);
if (parsed === null) {
await callbacks.checkpoint(failedJavaScriptStaticAnalysis());
return null;
}
await callbacks.phase("static");
const facts = await completeJavaScriptAnalysisSteps(
analyzeParsedJavaScriptStaticSourceSteps(
file.text.value,
parsed,
precision,
),
);
if (purpose === "preload-discovery") {
// Only declarations cross this preliminary pass. The normal pass owns
// full static/semantic facts and their result reservations.
const empty = failedJavaScriptStaticAnalysis();
await callbacks.checkpoint({
...empty,
parse_status: facts.parse_status,
parse_error_count: facts.parse_error_count,
...(facts.analysis_coverage === undefined
? {}
: { analysis_coverage: facts.analysis_coverage }),
visited_ast_nodes: facts.visited_ast_nodes,
limitations: facts.limitations,
electron: {
...empty.electron,
browser_windows: facts.electron.browser_windows,
},
});
return null;
}
const resultBudgetBytes = await callbacks.checkpoint(facts);
if (facts.parse_status === "failed") return null;
if (resultBudgetBytes === 0)
throw new AnalysisResourceConstraintError(
"analyze_javascript_application",
"memory",
`The parent reserved its remaining result capacity for static observations; semantic analysis of ${file.path} was not started`,
{ semantic_result_budget_bytes: 0 },
);
await callbacks.phase("semantic");
const ir = await completeJavaScriptAnalysisSteps(
analyzeParsedJavaScriptSemanticsSteps(
parsed,
moduleResolutionModeForJavaScriptReference(file.path, "static-import"),
capacity.nodes,
precision,
),
);
parsed = null;
const module = projectJavaScriptModuleSemantics(ir);
const measured = measureJavaScriptModuleTransfer(
module,
javaScriptTransferByteBudget(resultBudgetBytes),
);
if (measured.retentionBytes > resultBudgetBytes)
throw new AnalysisResourceConstraintError(
"analyze_javascript_application",
"memory",
`Completed module facts for ${file.path} exceed the parent's offered result budget; static facts were retained`,
{
semantic_result_budget_bytes: resultBudgetBytes,
module_transfer_bytes: measured.bytes,
},
);
await callbacks.phase("projection");
const projection = await completeJavaScriptAnalysisSteps(
projectJavaScriptSemanticFileSteps(
file,
ir,
capacity,
facts.electron.call_paths,
),
);
return { module, projection };
};
try {
await serveJavaScriptAnalysisWorker(analyze);
} catch (cause: unknown) {
process.stderr.write(
`${cause instanceof Error ? cause.message : String(cause)}\n`,
);
process.exitCode = 1;
}