-- Offline development entry point. Uses the same analyzer as the Studio adapter. local fs = require("@lune/fs") local luau = require("@lune/luau") local process = require("@lune/process") local serde = require("@lune/serde") local capturePath, libraryPath = process.args[1], process.args[2] assert( capturePath and libraryPath, "Usage: lune run scripts/analyze-profile.luau [maxFrames]" ) local maxFrames = tonumber(process.args[3] or "64") assert(maxFrames and maxFrames % 1 == 0 and maxFrames >= 1 and maxFrames <= 256, "maxFrames must be 1–256") local librarySource = fs.readFile(libraryPath) assert( serde.hash("sha256", librarySource) == "ab9579e592e8751386a01537152f2b739cc7942ce565d3c11337cddaa250d231", "LibMP checksum differs from the reviewed release" ) local library = luau.load(librarySource, { environment = { -- This path uses only OpenFromBuffer. Never expose LibMP's optional file or -- process providers; Lune reads the explicit input below instead. require = function(name) if name == "@std/fs" then return {} end if name == "@lute/process" then return { args = {} } end error("Unexpected LibMP dependency: " .. tostring(name)) end, }, })() assert(library.IsCliMode, "Expected an offline LibMP runtime") local raw = fs.readFile(capturePath) assert(#raw > 0 and #raw <= 32 * 1024 * 1024, "Capture must contain 1 byte to 32 MiB") local analyzer = luau.load(fs.readFile(process.args[4] or "plugin/src/Profiler.lua"))() local session local ok, report = pcall(function() session = library.Session.OpenFromBuffer(buffer.fromstring(raw)) assert(session and session:IsValid(), "LibMP rejected the capture; expected a compatible binary .gprx file") local result = analyzer.analyzeSession(session, maxFrames) result.source = "microprofiler-file" result.captureBytes = #raw result.libraryVersion = library.Versions.Library return result end) local cleaned, cleanupError = true, nil if session then cleaned, cleanupError = pcall(function() session:Dispose() end) end assert(ok, report) report.cleanupRequired = not cleaned or (report.scopes and report.scopes.cleanupRequired == true) or (report.counterTrends and report.counterTrends.cleanupRequired == true) if not cleaned then report.cleanupError = tostring(cleanupError) end print(serde.encode("json", report))