@bitmagic/cli 0.1.33 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-gl.d.ts +12 -0
- package/dist/browser-gl.js +15 -0
- package/dist/browser-gl.js.map +1 -1
- package/dist/verify/browser.js +115 -1
- package/dist/verify/browser.js.map +1 -1
- package/dist/verify/classify.d.ts +28 -0
- package/dist/verify/classify.js +48 -0
- package/dist/verify/classify.js.map +1 -1
- package/package.json +3 -3
package/dist/browser-gl.d.ts
CHANGED
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
* detached agent run, an ssh session). The Vulkan backend needs no display at all and reaches the
|
|
17
17
|
* discrete GPU either way, so the result does not depend on how the CLI was invoked.
|
|
18
18
|
*
|
|
19
|
+
* `--disable-gpu-compositing` is load-bearing and must not be dropped as "an optimisation we do
|
|
20
|
+
* not need". Headless Chrome cannot composite a GPU-backed WebGL canvas: with GPU compositing on,
|
|
21
|
+
* ANGLE's Vulkan backend LOSES the context about 400ms into the page (measured: `webglcontextlost`
|
|
22
|
+
* at 373-420ms, in both `launch` and `launchPersistentContext`), and everything after that draws
|
|
23
|
+
* into nothing. It is nearly invisible — `requestAnimationFrame` keeps firing, the engine logs its
|
|
24
|
+
* usual start lines, the DOM HUD still paints, and the only symptom is that every screenshot comes
|
|
25
|
+
* back black. `bitmagic verify` reported PASSED like that, and since a project with no cover art
|
|
26
|
+
* publishes its verify screenshot as the game's thumbnail, a black frame would have shipped with
|
|
27
|
+
* nothing to flag it. Turning compositing off makes the compositor read the canvas back on the CPU
|
|
28
|
+
* — the GPU still does all the rendering, and the fill-rate win is intact (measured 0.29ms/frame
|
|
29
|
+
* against 97.8ms in software).
|
|
30
|
+
*
|
|
19
31
|
* `--enable-unsafe-swiftshader` stays on in BOTH modes. It does not force software rendering
|
|
20
32
|
* (`--use-angle=swiftshader` does that); it only permits the fallback, which Chrome otherwise
|
|
21
33
|
* deprecation-warns about and is on a path to refusing outright. Keeping it means a machine with
|
package/dist/browser-gl.js
CHANGED
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
* detached agent run, an ssh session). The Vulkan backend needs no display at all and reaches the
|
|
17
17
|
* discrete GPU either way, so the result does not depend on how the CLI was invoked.
|
|
18
18
|
*
|
|
19
|
+
* `--disable-gpu-compositing` is load-bearing and must not be dropped as "an optimisation we do
|
|
20
|
+
* not need". Headless Chrome cannot composite a GPU-backed WebGL canvas: with GPU compositing on,
|
|
21
|
+
* ANGLE's Vulkan backend LOSES the context about 400ms into the page (measured: `webglcontextlost`
|
|
22
|
+
* at 373-420ms, in both `launch` and `launchPersistentContext`), and everything after that draws
|
|
23
|
+
* into nothing. It is nearly invisible — `requestAnimationFrame` keeps firing, the engine logs its
|
|
24
|
+
* usual start lines, the DOM HUD still paints, and the only symptom is that every screenshot comes
|
|
25
|
+
* back black. `bitmagic verify` reported PASSED like that, and since a project with no cover art
|
|
26
|
+
* publishes its verify screenshot as the game's thumbnail, a black frame would have shipped with
|
|
27
|
+
* nothing to flag it. Turning compositing off makes the compositor read the canvas back on the CPU
|
|
28
|
+
* — the GPU still does all the rendering, and the fill-rate win is intact (measured 0.29ms/frame
|
|
29
|
+
* against 97.8ms in software).
|
|
30
|
+
*
|
|
19
31
|
* `--enable-unsafe-swiftshader` stays on in BOTH modes. It does not force software rendering
|
|
20
32
|
* (`--use-angle=swiftshader` does that); it only permits the fallback, which Chrome otherwise
|
|
21
33
|
* deprecation-warns about and is on a path to refusing outright. Keeping it means a machine with
|
|
@@ -47,6 +59,9 @@ export function browserGlArgs(env, platform = process.platform) {
|
|
|
47
59
|
// driver versions over bugs that do not touch a headless WebGL canvas.
|
|
48
60
|
'--ignore-gpu-blocklist',
|
|
49
61
|
'--enable-gpu',
|
|
62
|
+
// Not optional — without it the WebGL context dies ~400ms in and every frame is black. See
|
|
63
|
+
// the file header.
|
|
64
|
+
'--disable-gpu-compositing',
|
|
50
65
|
'--enable-unsafe-swiftshader',
|
|
51
66
|
];
|
|
52
67
|
}
|
package/dist/browser-gl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-gl.js","sourceRoot":"","sources":["../src/browser-gl.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"browser-gl.js","sourceRoot":"","sources":["../src/browser-gl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,oGAAoG;AACpG,MAAM,gBAAgB,GAAG,CAAC,6BAA6B,EAAE,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;AAEtG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAuC,EACvC,WAAqB,OAAO,CAAC,QAAQ;IAErC,IAAI,GAAG,CAAC,EAAE,KAAK,MAAM,IAAI,GAAG,CAAC,4BAA4B,KAAK,MAAM;QAAE,OAAO,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACnG,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACjE,OAAO;QACL,oBAAoB;QACpB,0BAA0B;QAC1B,6FAA6F;QAC7F,uEAAuE;QACvE,wBAAwB;QACxB,cAAc;QACd,2FAA2F;QAC3F,mBAAmB;QACnB,2BAA2B;QAC3B,6BAA6B;KAC9B,CAAC;AACJ,CAAC"}
|
package/dist/verify/browser.js
CHANGED
|
@@ -38,6 +38,7 @@ export async function runHeadlessCheck(options) {
|
|
|
38
38
|
try {
|
|
39
39
|
const context = await browser.newContext({ viewport: { width: 1280, height: 720 } });
|
|
40
40
|
const page = await context.newPage();
|
|
41
|
+
await armContextLossProbe(page);
|
|
41
42
|
page.on('console', (message) => consoleLines.push(`${message.type()}: ${message.text()}`));
|
|
42
43
|
page.on('pageerror', (error) => pageErrors.push(error.message));
|
|
43
44
|
page.on('requestfailed', (request) => consoleLines.push(`requestfailed: ${request.url()} ${request.failure()?.errorText ?? ''}`));
|
|
@@ -82,10 +83,20 @@ export async function runHeadlessCheck(options) {
|
|
|
82
83
|
// why this replaced a getContext() probe.
|
|
83
84
|
bufferWidth: element.width,
|
|
84
85
|
bufferHeight: element.height,
|
|
86
|
+
// Page coordinates of the rect, for sampling the captured frame below. Kept out of
|
|
87
|
+
// CanvasObservation, which is about whether a renderer claimed the canvas, not where.
|
|
88
|
+
left: Math.round(rect.left),
|
|
89
|
+
top: Math.round(rect.top),
|
|
85
90
|
};
|
|
86
91
|
});
|
|
87
92
|
const screenshotBuffer = await page.screenshot();
|
|
88
93
|
fs.writeFileSync(options.screenshotPath, screenshotBuffer);
|
|
94
|
+
const canvasFrame = canvas === null
|
|
95
|
+
? null
|
|
96
|
+
: await measureCanvasFrame(page, screenshotBuffer, canvas);
|
|
97
|
+
const webglContextLost = await page.evaluate(
|
|
98
|
+
// eslint-disable-next-line no-undef -- browser-side callback, see the canvas probe above.
|
|
99
|
+
(flag) => window[flag] === true, CONTEXT_LOST_FLAG);
|
|
89
100
|
let start;
|
|
90
101
|
if (options.startInteraction !== undefined && interaction !== null) {
|
|
91
102
|
start = {
|
|
@@ -96,7 +107,15 @@ export async function runHeadlessCheck(options) {
|
|
|
96
107
|
menuVisibleAfterSettle: await isMenuVisible(page),
|
|
97
108
|
};
|
|
98
109
|
}
|
|
99
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
consoleLines,
|
|
112
|
+
pageErrors,
|
|
113
|
+
canvas,
|
|
114
|
+
screenshotBytes: screenshotBuffer.length,
|
|
115
|
+
webglContextLost,
|
|
116
|
+
canvasFrame,
|
|
117
|
+
start,
|
|
118
|
+
};
|
|
100
119
|
}
|
|
101
120
|
finally {
|
|
102
121
|
// Written on success and failure alike, including when the try block above threw before
|
|
@@ -106,6 +125,101 @@ export async function runHeadlessCheck(options) {
|
|
|
106
125
|
await browser.close();
|
|
107
126
|
}
|
|
108
127
|
}
|
|
128
|
+
/** Window flag the init script below sets when the page loses its WebGL context. */
|
|
129
|
+
const CONTEXT_LOST_FLAG = '__bitmagicWebglContextLost';
|
|
130
|
+
/**
|
|
131
|
+
* Arm a `webglcontextlost` listener before any page script runs.
|
|
132
|
+
*
|
|
133
|
+
* Registered in the CAPTURE phase on `window`, because the event is dispatched at the canvas and
|
|
134
|
+
* does NOT bubble — a listener on the canvas itself would also have to wait for the canvas to
|
|
135
|
+
* exist, which is after the engine has already created it.
|
|
136
|
+
*
|
|
137
|
+
* Worth the plumbing because a lost context is otherwise undetectable from out here: the page
|
|
138
|
+
* keeps running its animation loop, the engine keeps logging, the HUD keeps painting, and the only
|
|
139
|
+
* difference is that nothing the renderer draws survives. That is exactly how a headless GPU run
|
|
140
|
+
* produced a passing verify whose screenshot was solid black (see `browser-gl.ts`).
|
|
141
|
+
*/
|
|
142
|
+
async function armContextLossProbe(page) {
|
|
143
|
+
await page.addInitScript((flag) => {
|
|
144
|
+
/* eslint-disable no-undef -- browser-side callback, see the canvas probe above. */
|
|
145
|
+
window.addEventListener('webglcontextlost', () => {
|
|
146
|
+
window[flag] = true;
|
|
147
|
+
}, true);
|
|
148
|
+
/* eslint-enable no-undef */
|
|
149
|
+
}, CONTEXT_LOST_FLAG);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* What the canvas rect of `screenshot` actually contains: how much of it is lit, and how many
|
|
153
|
+
* distinct colours it holds. The second is what catches a canvas that drew nothing on a page whose
|
|
154
|
+
* backdrop is not black — see `CanvasFrameObservation`.
|
|
155
|
+
*
|
|
156
|
+
* Decoded in the BROWSER rather than in Node: it needs a PNG decoder, the page already has one,
|
|
157
|
+
* and adding an image library to the CLI's dependencies for a single check is a poor trade for
|
|
158
|
+
* something every creator installs. The image goes back in as a data URL and is drawn to a 2D
|
|
159
|
+
* canvas, whose `getImageData` is a plain CPU readback of its own backing store — unaffected by
|
|
160
|
+
* whatever went wrong on the WebGL/compositing path that produced the frame.
|
|
161
|
+
*
|
|
162
|
+
* Returns null rather than throwing on any failure. A measurement that could not be taken must
|
|
163
|
+
* classify as "not observed"; failing a creator's game because a probe broke would be worse than
|
|
164
|
+
* the gap it closes.
|
|
165
|
+
*/
|
|
166
|
+
async function measureCanvasFrame(page, screenshot, rect) {
|
|
167
|
+
if (rect.width <= 0 || rect.height <= 0)
|
|
168
|
+
return null;
|
|
169
|
+
try {
|
|
170
|
+
return await page.evaluate(async (input) => {
|
|
171
|
+
/* eslint-disable no-undef -- browser-side callback, see the canvas probe above. */
|
|
172
|
+
const image = new Image();
|
|
173
|
+
image.src = input.dataUrl;
|
|
174
|
+
await image.decode();
|
|
175
|
+
// The screenshot is a viewport capture at deviceScaleFactor 1, so its pixels are the
|
|
176
|
+
// page's CSS pixels; clamp to the image in case the canvas overhangs the viewport.
|
|
177
|
+
const left = Math.max(0, input.left);
|
|
178
|
+
const top = Math.max(0, input.top);
|
|
179
|
+
const width = Math.min(input.width, image.naturalWidth - left);
|
|
180
|
+
const height = Math.min(input.height, image.naturalHeight - top);
|
|
181
|
+
if (width <= 0 || height <= 0)
|
|
182
|
+
return null;
|
|
183
|
+
const surface = document.createElement('canvas');
|
|
184
|
+
surface.width = width;
|
|
185
|
+
surface.height = height;
|
|
186
|
+
const ctx = surface.getContext('2d');
|
|
187
|
+
if (!ctx)
|
|
188
|
+
return null;
|
|
189
|
+
ctx.drawImage(image, left, top, width, height, 0, 0, width, height);
|
|
190
|
+
const { data } = ctx.getImageData(0, 0, width, height);
|
|
191
|
+
let lit = 0;
|
|
192
|
+
let sampled = 0;
|
|
193
|
+
const colors = new Set();
|
|
194
|
+
// Every 4th pixel per axis: ~16x less work than a full scan, and a frame that is empty
|
|
195
|
+
// only in the 15 pixels between samples is not a frame anyone needs warning about.
|
|
196
|
+
for (let y = 0; y < height; y += 4) {
|
|
197
|
+
for (let x = 0; x < width; x += 4) {
|
|
198
|
+
const i = (y * width + x) << 2;
|
|
199
|
+
// Threshold, not `> 0`: PNG capture of a near-black frame is not bit-exact.
|
|
200
|
+
if (data[i] > 4 || data[i + 1] > 4 || data[i + 2] > 4)
|
|
201
|
+
lit++;
|
|
202
|
+
// 5 bits per channel, so capture rounding and dithering do not read as detail.
|
|
203
|
+
colors.add(((data[i] >> 3) << 10) | ((data[i + 1] >> 3) << 5) | (data[i + 2] >> 3));
|
|
204
|
+
sampled++;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return sampled === 0 ? null : { litFraction: lit / sampled, distinctColors: colors.size };
|
|
208
|
+
/* eslint-enable no-undef */
|
|
209
|
+
}, {
|
|
210
|
+
dataUrl: `data:image/png;base64,${screenshot.toString('base64')}`,
|
|
211
|
+
left: rect.left,
|
|
212
|
+
top: rect.top,
|
|
213
|
+
width: rect.width,
|
|
214
|
+
height: rect.height,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// A page that is already unusable (crashed renderer, closed context) cannot be measured, and
|
|
219
|
+
// the run has more useful things to report about that than a missing pixel statistic.
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
109
223
|
const START_POLL_MS = 250;
|
|
110
224
|
function hasStartMarker(consoleLines, marker) {
|
|
111
225
|
return consoleLines.some((line) => line.includes(marker));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/verify/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAa,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/verify/browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,20 @@ export interface CanvasObservation {
|
|
|
13
13
|
bufferWidth: number;
|
|
14
14
|
bufferHeight: number;
|
|
15
15
|
}
|
|
16
|
+
/** What the canvas area of the captured screenshot contains. */
|
|
17
|
+
export interface CanvasFrameObservation {
|
|
18
|
+
/** Fraction of sampled pixels that are not black. */
|
|
19
|
+
litFraction: number;
|
|
20
|
+
/**
|
|
21
|
+
* How many distinct colours the sampled pixels fall into, quantised to 5 bits per channel.
|
|
22
|
+
*
|
|
23
|
+
* The load-bearing number, and the reason this is not just a brightness check: a canvas that
|
|
24
|
+
* rendered nothing composites as a FLAT area — black on a black page, but whatever the page's
|
|
25
|
+
* background happens to be otherwise. Flatness catches that in every case; darkness only catches
|
|
26
|
+
* it when the backdrop is black. A real rendered frame from a 3D scene has thousands.
|
|
27
|
+
*/
|
|
28
|
+
distinctColors: number;
|
|
29
|
+
}
|
|
16
30
|
/** What the start interaction (waiting for and clicking the engine Play button) observed. */
|
|
17
31
|
export interface StartObservations {
|
|
18
32
|
playButtonSeen: boolean;
|
|
@@ -29,6 +43,20 @@ export interface VerifyObservations {
|
|
|
29
43
|
canvas: CanvasObservation | null;
|
|
30
44
|
/** Byte length of the PNG screenshot taken after settling. */
|
|
31
45
|
screenshotBytes: number;
|
|
46
|
+
/**
|
|
47
|
+
* The page fired `webglcontextlost`. The renderer is dead from that moment: rAF keeps firing,
|
|
48
|
+
* the engine logs its usual lines, the DOM HUD still paints, and nothing else gives it away.
|
|
49
|
+
*/
|
|
50
|
+
webglContextLost: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* What the captured screenshot actually contains INSIDE the canvas rect, or null when it could
|
|
53
|
+
* not be measured (no canvas, decode failed).
|
|
54
|
+
*
|
|
55
|
+
* Neither the console nor the page can answer "did a frame actually come out": what matters is
|
|
56
|
+
* what the COMPOSITOR captured, because that image is also the game's published thumbnail when
|
|
57
|
+
* the project has no cover art. See `BLACK_FRAME_MAX_LIT_FRACTION` and `MIN_DISTINCT_COLORS`.
|
|
58
|
+
*/
|
|
59
|
+
canvasFrame: CanvasFrameObservation | null;
|
|
32
60
|
/** Only present when the run was asked to perform the start interaction (`bitmagic verify`);
|
|
33
61
|
* `publish`'s smoke check never sets it and classifies exactly as before. */
|
|
34
62
|
start?: StartObservations;
|
package/dist/verify/classify.js
CHANGED
|
@@ -26,6 +26,33 @@ const UNTOUCHED_CANVAS_HEIGHT = 150;
|
|
|
26
26
|
* real frame — a smoke signal, not a pixel assertion.
|
|
27
27
|
*/
|
|
28
28
|
const MIN_SCREENSHOT_BYTES = 20_000;
|
|
29
|
+
/**
|
|
30
|
+
* Below this fraction of non-black pixels in the canvas rect, the frame is treated as black.
|
|
31
|
+
*
|
|
32
|
+
* The byte-size check above does not catch this case: the black frame that prompted this still
|
|
33
|
+
* carried the DOM HUD, which compresses to far more than 20KB, so verify reported PASSED on an
|
|
34
|
+
* image that was solid black behind the panel. The measured cause was a lost WebGL context under
|
|
35
|
+
* headless GPU compositing (see `browser-gl.ts`), but the check is deliberately about the PIXELS
|
|
36
|
+
* rather than that cause: this screenshot becomes the game's published thumbnail when the project
|
|
37
|
+
* has no cover art, so whatever makes it black — a dead context, a renderer that drew nothing, a
|
|
38
|
+
* capture path that lost the layer — is worth failing over.
|
|
39
|
+
*
|
|
40
|
+
* 0.5% rather than zero because PNG capture of a nearly-black frame is not bit-exact, and a real
|
|
41
|
+
* frame clears this by orders of magnitude: a healthy voxel game measures upwards of 99% lit. A
|
|
42
|
+
* genuine full-black render (a fade-out caught at the settle instant) would fail here; that is the
|
|
43
|
+
* intended trade, because it is indistinguishable from the broken case in the artifact that ships.
|
|
44
|
+
*/
|
|
45
|
+
const BLACK_FRAME_MAX_LIT_FRACTION = 0.005;
|
|
46
|
+
/**
|
|
47
|
+
* Fewer distinct colours than this in the canvas area means nothing was drawn there.
|
|
48
|
+
*
|
|
49
|
+
* This is the check that does the work, because "black" is only how the failure looked on a black
|
|
50
|
+
* page: a canvas whose context died composites as a flat area of WHATEVER is behind it, and on a
|
|
51
|
+
* page with a dark-grey backdrop the brightness check above sails straight past it. Two rather than
|
|
52
|
+
* one leaves room for the capture's own rounding and a single antialiased edge; a rendered 3D frame
|
|
53
|
+
* measures in the thousands.
|
|
54
|
+
*/
|
|
55
|
+
const MIN_DISTINCT_COLORS = 3;
|
|
29
56
|
/**
|
|
30
57
|
* The engine's line when the player has fallen out of the world and is being put back.
|
|
31
58
|
*
|
|
@@ -92,6 +119,27 @@ export function classifyVerifyRun(observations) {
|
|
|
92
119
|
failures.push(`The screenshot is implausibly small (${observations.screenshotBytes} bytes) — the frame ` +
|
|
93
120
|
'looks blank.');
|
|
94
121
|
}
|
|
122
|
+
if (observations.webglContextLost) {
|
|
123
|
+
failures.push('The WebGL context was lost during the run, so the game rendered nothing after that point '
|
|
124
|
+
+ '(the page keeps running and the HUD keeps painting, which is why nothing else shows it). '
|
|
125
|
+
+ 'If this machine drives a GPU, re-run with BITMAGIC_BROWSER_SOFTWARE_GL=true to confirm.');
|
|
126
|
+
}
|
|
127
|
+
// Only when a canvas was found and measured: `null` means "not observed", never "empty".
|
|
128
|
+
const frame = observations.canvasFrame;
|
|
129
|
+
if (frame !== null) {
|
|
130
|
+
// Both land on the same remedy, so only the more specific one is reported.
|
|
131
|
+
const shipped = 'This image is also what publish uses as the game\'s thumbnail when the '
|
|
132
|
+
+ 'project has no cover art, so it cannot be shipped as-is.';
|
|
133
|
+
if (frame.litFraction <= BLACK_FRAME_MAX_LIT_FRACTION) {
|
|
134
|
+
failures.push('The screenshot is black where the game should be — nothing the renderer drew reached '
|
|
135
|
+
+ `the captured frame. ${shipped}`);
|
|
136
|
+
}
|
|
137
|
+
else if (frame.distinctColors < MIN_DISTINCT_COLORS) {
|
|
138
|
+
failures.push(`The screenshot shows a flat, featureless area where the game should be `
|
|
139
|
+
+ `(${frame.distinctColors} distinct colour${frame.distinctColors === 1 ? '' : 's'} across `
|
|
140
|
+
+ `the whole canvas) — the renderer's output never reached the captured frame. ${shipped}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
95
143
|
for (const line of observations.consoleLines) {
|
|
96
144
|
const fatal = FATAL_CONSOLE.find((f) => line.includes(f));
|
|
97
145
|
if (fatal)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/verify/classify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/verify/classify.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitmagic/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"description": "Build Bitmagic games from your own agent tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"citty": "^0.2.2",
|
|
20
20
|
"playwright-core": "^1.59.1",
|
|
21
21
|
"tar": "^7.4.3",
|
|
22
|
-
"@bitmagic/
|
|
23
|
-
"@bitmagic/
|
|
22
|
+
"@bitmagic/asset-core": "0.1.1",
|
|
23
|
+
"@bitmagic/world-forger": "0.1.3"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@eslint/js": "^9.38.0",
|