@vgai/cli 0.5.11 → 0.5.12
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/README.md +1 -1
- package/dist/index.js +308 -379
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ vgai upgrade [--report] report engine drift vs. the project's engine pin
|
|
|
74
74
|
present reports "not a scaffolded project" instead of
|
|
75
75
|
dumping the whole template — see `vgai validate` instead)
|
|
76
76
|
vgai validate [folder] in-process: validate vgai.project.json, check every declared
|
|
77
|
-
entry/
|
|
77
|
+
entry/contractShim file exists, print the engine
|
|
78
78
|
pin (default: cwd) — no monorepo Vite/editor stack required
|
|
79
79
|
Exit codes: 0 valid, 1 invalid manifest or missing file, 2 usage
|
|
80
80
|
npm run vgai -- add deploy-vercel add project-owned Vercel scripts/config
|
package/dist/index.js
CHANGED
|
@@ -413,6 +413,51 @@ var init_client = __esm({
|
|
|
413
413
|
const data = await this.command({ type: "inspect" });
|
|
414
414
|
return data.subject;
|
|
415
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* The HIERARCHY PANEL's actual rendered row tree, as data.
|
|
418
|
+
*
|
|
419
|
+
* The same rows a human is looking at: the adapter's tree after the component
|
|
420
|
+
* marks fold implementation subtrees, after the internals reveal, after the
|
|
421
|
+
* document promotion, the child cap, the collapse state, the search filter
|
|
422
|
+
* and the selection scope. Works in play mode and edit mode alike — the
|
|
423
|
+
* answer reports which (`playState`, `activeViewportTab`), because a
|
|
424
|
+
* play-mode tree and an edit-mode tree come from different adapters.
|
|
425
|
+
*
|
|
426
|
+
* Deliberately NOT `status().entities`, which walks the raw adapter tree and
|
|
427
|
+
* therefore answers a different question: a panel defect is invisible in it.
|
|
428
|
+
*
|
|
429
|
+
* Each row carries `childCount` (what its caret opens), `internalChildCount`
|
|
430
|
+
* (what is folded behind "Reveal Internals") and `expandable` (whether the
|
|
431
|
+
* panel draws a caret at all) — so "this subtree exists but the UI offers no
|
|
432
|
+
* way to open it" is a readable fact rather than something only a human
|
|
433
|
+
* squinting at the panel can notice.
|
|
434
|
+
*
|
|
435
|
+
* Rejects, naming the panel, when no hierarchy panel is mounted: an empty
|
|
436
|
+
* tree would be a fabricated answer about a surface nobody is being shown.
|
|
437
|
+
*/
|
|
438
|
+
async hierarchy() {
|
|
439
|
+
const data = await this.command({ type: "hierarchy" });
|
|
440
|
+
return data.hierarchy;
|
|
441
|
+
}
|
|
442
|
+
/** Write one editable path through the active Inspector's own IO. */
|
|
443
|
+
async setInspectionField(path, value) {
|
|
444
|
+
const data = await this.command({
|
|
445
|
+
type: "set-inspection-field",
|
|
446
|
+
path,
|
|
447
|
+
value
|
|
448
|
+
});
|
|
449
|
+
return data.subject;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Undo / redo one project transaction — the same queue the keyboard shortcut
|
|
453
|
+
* drives. `moved` is false when there was nothing left in that direction.
|
|
454
|
+
*/
|
|
455
|
+
async undo() {
|
|
456
|
+
return this.command({ type: "undo" });
|
|
457
|
+
}
|
|
458
|
+
async redo() {
|
|
459
|
+
return this.command({ type: "redo" });
|
|
460
|
+
}
|
|
416
461
|
/** Read the editor's actual current durable projection. */
|
|
417
462
|
async currentView() {
|
|
418
463
|
const data = await this.command({ type: "current-view" });
|
|
@@ -425,7 +470,30 @@ var init_client = __esm({
|
|
|
425
470
|
...size === void 0 ? {} : { size }
|
|
426
471
|
});
|
|
427
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* Read or drive the ACTIVE center document's own DOM — the scoped
|
|
475
|
+
* editor-chrome door, and the read/gesture half of the same subject
|
|
476
|
+
* {@link captureActiveDocument} photographs. NOT play-mode gated, and NOT
|
|
477
|
+
* page automation: a target outside the active document's container is
|
|
478
|
+
* refused by name. Design and scope contract:
|
|
479
|
+
* `packages/editor/src/editor-document-probe.ts`.
|
|
480
|
+
*/
|
|
481
|
+
async documentProbe(step) {
|
|
482
|
+
return this.command({ type: "document-probe", step });
|
|
483
|
+
}
|
|
428
484
|
// --- Display (set semantics) ---
|
|
485
|
+
/**
|
|
486
|
+
* The Game document's "Persist to game source" consent, over the relay —
|
|
487
|
+
* the same session-scoped switch the checkbox flips, refused for the same
|
|
488
|
+
* reasons (it answers with the server's own words when the base cannot be
|
|
489
|
+
* written). `recorder` names who accounts for the diff a write produces.
|
|
490
|
+
*/
|
|
491
|
+
async setSourcePersistConsent(enabled) {
|
|
492
|
+
return this.command({
|
|
493
|
+
type: "set-source-persist-consent",
|
|
494
|
+
enabled
|
|
495
|
+
});
|
|
496
|
+
}
|
|
429
497
|
async setGrid(enabled) {
|
|
430
498
|
await this.command({ type: "set-grid", enabled });
|
|
431
499
|
}
|
|
@@ -18296,6 +18364,9 @@ var init_inspection_operations = __esm({
|
|
|
18296
18364
|
id: external_exports.string(),
|
|
18297
18365
|
title: external_exports.string(),
|
|
18298
18366
|
kindLabel: external_exports.string().optional(),
|
|
18367
|
+
note: external_exports.string().optional().describe(
|
|
18368
|
+
"The identity row\u2019s own line \u2014 for an ingest mount, where the object was CONSTRUCTED (`Source \xB7 game.js:271`), or the reason it has no such line."
|
|
18369
|
+
),
|
|
18299
18370
|
hint: external_exports.string().optional().describe("The quiet line a subject with nothing to edit carries."),
|
|
18300
18371
|
presentation: external_exports.object({
|
|
18301
18372
|
preferred: external_exports.string().describe("The surface\u2019s presentation affinity: card|column."),
|
|
@@ -18311,6 +18382,7 @@ var init_inspection_operations = __esm({
|
|
|
18311
18382
|
disabled: external_exports.boolean().optional()
|
|
18312
18383
|
})
|
|
18313
18384
|
),
|
|
18385
|
+
related: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string() })).describe("Agent-visible counterparts of the inspector\u2019s related-document buttons."),
|
|
18314
18386
|
sections: external_exports.array(InspectedSectionSchema)
|
|
18315
18387
|
});
|
|
18316
18388
|
NothingInspectedSchema = external_exports.object({ none: external_exports.literal(true).describe("There is no inspector showing.") }).describe("Nothing is being inspected.");
|
|
@@ -39603,36 +39675,12 @@ function rejectRemovedRootAdapterSpelling(value, ctx) {
|
|
|
39603
39675
|
function rootMedium(root) {
|
|
39604
39676
|
return typeof root.adapter === "string" ? root.adapter : root.adapter.surface;
|
|
39605
39677
|
}
|
|
39606
|
-
var GAME_MANIFEST_VERSION,
|
|
39678
|
+
var GAME_MANIFEST_VERSION, REMOVED_SURFACE_SPELLING, REMOVED_BARE_ADAPTER_SPELLING, RootAdapterSchema, AdapterRootSchema, LearnKindSchema, LearnDifficultySchema, LearnMetadataSchema, GameManifestSchema;
|
|
39607
39679
|
var init_schema = __esm({
|
|
39608
39680
|
"../engine/src/manifest/schema.ts"() {
|
|
39609
39681
|
"use strict";
|
|
39610
39682
|
init_zod();
|
|
39611
39683
|
GAME_MANIFEST_VERSION = 2;
|
|
39612
|
-
IngestStrategySchema = external_exports.enum([
|
|
39613
|
-
"shared",
|
|
39614
|
-
// game imports host-served ESM three — full in-realm capture
|
|
39615
|
-
"deduped",
|
|
39616
|
-
// game source built by OUR pipeline, bundler dedupe — full capture
|
|
39617
|
-
"iframe-reachable",
|
|
39618
|
-
// prebuilt bundle in iframe, three reachable — cross-realm capture
|
|
39619
|
-
"opaque-embed"
|
|
39620
|
-
// prebuilt bundle, nothing reachable — host lifecycle only
|
|
39621
|
-
]);
|
|
39622
|
-
TierSchema = external_exports.enum([
|
|
39623
|
-
"first-party",
|
|
39624
|
-
// vgai-native root: full editor, full loop control
|
|
39625
|
-
"shared",
|
|
39626
|
-
// = IngestStrategy 'shared' rung
|
|
39627
|
-
"deduped",
|
|
39628
|
-
// = IngestStrategy 'deduped' rung
|
|
39629
|
-
"iframe-reachable",
|
|
39630
|
-
// = IngestStrategy 'iframe-reachable' rung
|
|
39631
|
-
"opaque-embed",
|
|
39632
|
-
// = IngestStrategy 'opaque-embed' rung
|
|
39633
|
-
"unsupported"
|
|
39634
|
-
// this root does not function in this delivery context
|
|
39635
|
-
]);
|
|
39636
39684
|
REMOVED_SURFACE_SPELLING = {
|
|
39637
39685
|
threejs: "three",
|
|
39638
39686
|
pixijs: "canvas",
|
|
@@ -39654,14 +39702,11 @@ var init_schema = __esm({
|
|
|
39654
39702
|
external_exports.object({
|
|
39655
39703
|
surface: external_exports.enum(["three", "canvas", "dom"]).describe("Native surface captured from the unmodified game"),
|
|
39656
39704
|
ingest: external_exports.object({
|
|
39657
|
-
strategy: IngestStrategySchema.describe(
|
|
39658
|
-
"Capture mechanics rung this ingested root uses (\xA74) \u2014 also the root`s natural local capability tier"
|
|
39659
|
-
),
|
|
39660
|
-
entryHtml: external_exports.string().optional().describe(
|
|
39661
|
-
"Entry HTML path, project-relative. WIRED for opaque-embed (D-W2): the file`s bytes are read verbatim through the project-static route and hosted in a sandboxed iframe (embed-only, no scene introspection), for both canvas and three roots. Legal but NOT wired to a mount for iframe-reachable (a named error at resolve names this \u2014 use `bundleUrl` instead, the wired reachable route)."
|
|
39662
|
-
),
|
|
39663
39705
|
contractShim: external_exports.string().optional().describe(
|
|
39664
|
-
|
|
39706
|
+
"Project-relative path to a HOST-ADDED ES module that declares this game's `window.vgaiGame` contract (adapter/ingest/game-contract.ts) WITHOUT editing a vendored byte \u2014 the pristine-copy door. The host imports it immediately BEFORE the game's own entry module, in the editor's realm. TIMING CONTRACT, which a shim author must obey: because it runs before the game`s entry, it MUST assign `window.vgaiGame` SYNCHRONOUSLY at top level. Anything that needs the game`s own modules must be LAZY: a dynamic `import()` INSIDE each verb/provider closure, resolved at call time. Importing a game module eagerly from the shim would evaluate it ahead of the game`s own entry and reorder its module side effects. Every such `import()` MUST take a STRING LITERAL, never a variable/table lookup. A variable specifier is not statically analyzable, so the dev server leaves it alone and it resolves at runtime against the shim`s own `/@fs/` url \u2014 while the game`s entry has had ITS relative imports rewritten to whatever url the server considers canonical for those files. Module identity is per-url, so the shim silently binds a SECOND, freshly-evaluated copy of the whole game and every provider reports a game that never started. Measured on three-descent: 285 segments through the game`s graph, 0 through the shim`s, and no error anywhere."
|
|
39707
|
+
),
|
|
39708
|
+
dataWriter: external_exports.string().optional().describe(
|
|
39709
|
+
"Project-relative path to a HOST-ADDED ES module that writes this game's own DATA file back \u2014 the sibling of a source write for a game whose authorable truth is not source. Descent places its robots, powerups and hostages in binary records inside `descent.hog`, reaching no source literal, so an authored move of one is an edit to that file and nothing else can write it. The module declares two exports and the host knows nothing else about it: `dataFile` (a project-relative string \u2014 the ONE file this writer edits) and `planDataEdit(bytes, {record, property, baseline, next})`, which returns `{changed: true, bytes}` or `{changed: false, reason}` and may be async. It is loaded in the editor realm beside the game, so it may `import()` the game's own modules to resolve what only a running game knows (Descent's writer asks the game`s own `find_point_seg` which segment a moved object landed in, and refuses \"outside the mine\" rather than writing data the game would read back wrong). It NEVER fabricates: a record it cannot address, or a property it does not model, is a named refusal. An object is anchored to a record by carrying `userData.vgaiRecordIndex` \u2014 the game declares that identity itself (a recorded patch or a shim); the host never infers one."
|
|
39665
39710
|
),
|
|
39666
39711
|
assets: external_exports.record(external_exports.string(), external_exports.string()).optional().describe(
|
|
39667
39712
|
"Path-substring -> served-URL rewrites for this ingested game (IngestGame.assets today)"
|
|
@@ -39670,72 +39715,11 @@ var init_schema = __esm({
|
|
|
39670
39715
|
"DOM API stub ids this ingested game requires to run headlessly/in-realm"
|
|
39671
39716
|
),
|
|
39672
39717
|
captureTimeoutMs: external_exports.number().optional().describe(
|
|
39673
|
-
"How long
|
|
39674
|
-
),
|
|
39675
|
-
// The six iframe-reachable-multi mount fields
|
|
39676
|
-
// (`ingest-iframe-2d.ts`'s `IframeReachableMultiOpts`), legal
|
|
39677
|
-
// ONLY when `strategy` is 'iframe-reachable' (enforced by the
|
|
39678
|
-
// `.superRefine` below).
|
|
39679
|
-
bundleUrl: external_exports.string().optional().describe(
|
|
39680
|
-
"Absolute URL of the externalized built game bundle \u2014 the WIRED iframe-reachable mount route (iframe-reachable only), for BOTH canvas (Track P, ingest-iframe-2d.ts's mountIngestGame2DIframeReachableMulti) and three (D-W1, ingest-iframe-reachable-adapter.ts's mountIngestGameIframeReachableBundle). PRECONDITION: the bundle must externalize its root`s own runtime as a bare, un-rewritten import (`pixi.js` for canvas, `three` for three \u2014 `vgai bundle` does this for you) so it resolves through the iframe importmap to the HOST instance the capture trap is installed on; a bundle with an inlined runtime is unreachable and degrades to the embed-only floor. Exactly one of bundleUrl/entryHtml is required when strategy is iframe-reachable."
|
|
39681
|
-
),
|
|
39682
|
-
baseHref: external_exports.string().optional().describe(
|
|
39683
|
-
"Iframe <base href> so the game's relative asset URLs resolve (iframe-reachable only)."
|
|
39684
|
-
),
|
|
39685
|
-
assetBaseUrl: external_exports.string().optional().describe(
|
|
39686
|
-
"Host-side basePath forced onto the trapped runtime's own asset resolution \u2014 pixi's `Assets.init` for a canvas root, three's `DefaultLoadingManager.setURLModifier` for a three root (D-W1) \u2014 absolute, or root-relative (resolved against the editor page's own origin at mount time, ingest-mode.ts, so a static manifest never has to know the dev-server port) (iframe-reachable only \u2014 a document.write iframe keeps the parent window.location)."
|
|
39687
|
-
),
|
|
39688
|
-
extraDeps: external_exports.array(external_exports.string()).optional().describe(
|
|
39689
|
-
"Bare specifiers of this root's externalized deps beyond its own runtime (pixi.js/three \u2014 e.g. '@pixi/sound', 'gsap'). Resolved by the editor's host-namespace registry into module namespaces when known (D-P1 \u2014 the manifest carries data, not code); an unregistered specifier falls back to the open project's own node_modules (D-Z3), served as a verbatim iframe importmap URL. Throws a named error if neither resolves it (iframe-reachable only)."
|
|
39690
|
-
),
|
|
39691
|
-
pixiModuleUrl: external_exports.string().optional().describe(
|
|
39692
|
-
'PIXI-ONLY: standalone matching-major pixi ESM URL to trap instead of the host pixi, for version-skewed games (e.g. a v6 game on a v8 host); this field\'s PRESENCE is how the skew is expressed (D-P2 \u2014 no separate strategy/tier for version skew) (iframe-reachable only). Declaring this on a `kind: "three"` root is schema-legal (this field is kind-agnostic here) but throws a NAMED not-supported error at resolve \u2014 three has no version-skew mount this wave (D-W7: a hypothetical `threeModuleUrl` is explicitly parked, no consumer exists).'
|
|
39693
|
-
),
|
|
39694
|
-
bodyHtml: external_exports.string().optional().describe(
|
|
39695
|
-
'HTML injected into the iframe body before the game script boots (e.g. a `<div id="game-root">` the game expects to find) (iframe-reachable only).'
|
|
39718
|
+
"How long the host waits for this game's first captured frame before the mount FAILS by name. A game that needs a long boot (streamed world assets, a menu the player must clear) raises it; the default is 10s."
|
|
39696
39719
|
)
|
|
39697
|
-
}).describe(
|
|
39720
|
+
}).strict().describe(
|
|
39698
39721
|
"Ingest adapter configuration for an unmodified game (a repo-vendored game or your own external folder)"
|
|
39699
|
-
)
|
|
39700
|
-
if (ingest.contractShim === void 0 || ingest.strategy === "iframe-reachable" && ingest.entryHtml !== void 0) {
|
|
39701
|
-
return;
|
|
39702
|
-
}
|
|
39703
|
-
ctx.addIssue({
|
|
39704
|
-
code: external_exports.ZodIssueCode.custom,
|
|
39705
|
-
message: `\`contractShim\` is read ONLY by the self-hosted entry-document route, so it requires strategy 'iframe-reachable' together with \`entryHtml\` (got strategy "${ingest.strategy}"${ingest.entryHtml === void 0 ? " and no `entryHtml`" : ""}) \u2014 the host injects the shim module into the GAME'S OWN entry HTML (ingest-self-hosted-three-adapter.ts), and no other mount has such a document.`,
|
|
39706
|
-
path: ["contractShim"]
|
|
39707
|
-
});
|
|
39708
|
-
}).superRefine((ingest, ctx) => {
|
|
39709
|
-
const iframeOnlyFields = [
|
|
39710
|
-
["bundleUrl", ingest.bundleUrl !== void 0],
|
|
39711
|
-
["baseHref", ingest.baseHref !== void 0],
|
|
39712
|
-
["assetBaseUrl", ingest.assetBaseUrl !== void 0],
|
|
39713
|
-
["extraDeps", ingest.extraDeps !== void 0],
|
|
39714
|
-
["pixiModuleUrl", ingest.pixiModuleUrl !== void 0],
|
|
39715
|
-
["bodyHtml", ingest.bodyHtml !== void 0]
|
|
39716
|
-
];
|
|
39717
|
-
if (ingest.strategy !== "iframe-reachable") {
|
|
39718
|
-
for (const [key, present] of iframeOnlyFields) {
|
|
39719
|
-
if (present) {
|
|
39720
|
-
ctx.addIssue({
|
|
39721
|
-
code: external_exports.ZodIssueCode.custom,
|
|
39722
|
-
message: `\`${key}\` is only legal when strategy is 'iframe-reachable' (got "${ingest.strategy}") \u2014 bundleUrl/baseHref/assetBaseUrl/extraDeps/pixiModuleUrl/bodyHtml are the iframe-reachable-multi mount's options (canvas: ingest-iframe-2d.ts IframeReachableMultiOpts; three, D-W1: ingest-iframe-reachable-adapter.ts IframeReachableBundleOpts) and have no meaning under any other strategy.`,
|
|
39723
|
-
path: [key]
|
|
39724
|
-
});
|
|
39725
|
-
}
|
|
39726
|
-
}
|
|
39727
|
-
return;
|
|
39728
|
-
}
|
|
39729
|
-
const hasBundleUrl = ingest.bundleUrl !== void 0;
|
|
39730
|
-
const hasEntryHtml = ingest.entryHtml !== void 0;
|
|
39731
|
-
if (hasBundleUrl === hasEntryHtml) {
|
|
39732
|
-
ctx.addIssue({
|
|
39733
|
-
code: external_exports.ZodIssueCode.custom,
|
|
39734
|
-
message: `strategy 'iframe-reachable' requires EXACTLY ONE of \`bundleUrl\` (externalized multi-file bundle, the iframe-reachable-multi mount) or \`entryHtml\` (single-file/legacy iframe entry) \u2014 ${hasBundleUrl ? "both are present" : "neither is present"}.`,
|
|
39735
|
-
path: hasBundleUrl ? ["bundleUrl"] : ["entryHtml"]
|
|
39736
|
-
});
|
|
39737
|
-
}
|
|
39738
|
-
})
|
|
39722
|
+
)
|
|
39739
39723
|
}).strict()
|
|
39740
39724
|
])
|
|
39741
39725
|
).describe(
|
|
@@ -39760,17 +39744,7 @@ var init_schema = __esm({
|
|
|
39760
39744
|
"Marks this root as a DEV LAYER: the game's own dev GUI, not shipped game content. Four readers act on it. `mountManifestRoots` mounts it only when dev layers are enabled (`devLayersEnabled`, runtime/dev-layers.ts), so a production build carries no dev GUI; the host stacks every dev root ABOVE every non-dev root (a dev layer sits topmost, and as a DOM layer it steals no input from the game while closed); the play compositor EXCLUDES dev layers from a capture unless the capture asks for them; and the editor mounts a dev root as edit-time CHROME rather than authorable content (no hierarchy entry, no OID stamping, no JSX write-back, not selectable)."
|
|
39761
39745
|
),
|
|
39762
39746
|
loop: external_exports.enum(["gated", "self-driven"]).default("gated").describe(
|
|
39763
|
-
|
|
39764
|
-
),
|
|
39765
|
-
capabilities: external_exports.object({
|
|
39766
|
-
local: TierSchema.optional().describe(
|
|
39767
|
-
"Declared capability tier when served via the local CLI (Vite pipeline); omitted -> derived (\xA74)"
|
|
39768
|
-
),
|
|
39769
|
-
hosted: TierSchema.optional().describe(
|
|
39770
|
-
"Declared capability tier when served hosted (no bundler: esbuild-wasm + externals only); omitted -> derived (\xA74)"
|
|
39771
|
-
)
|
|
39772
|
-
}).optional().describe(
|
|
39773
|
-
"Per-delivery-context capability tier declarations (\xA74). Declaring above the adapter's ceiling for that context is an error; declaring at or below it (including `unsupported`) is legal."
|
|
39747
|
+
"gated: host-driven loop (default). self-driven: this root drives its own loop (composited, unsynchronized)"
|
|
39774
39748
|
)
|
|
39775
39749
|
}).strict();
|
|
39776
39750
|
LearnKindSchema = external_exports.enum(["starter", "feature", "sample-game", "lesson-companion"]).describe(
|
|
@@ -39869,6 +39843,13 @@ var init_schema = __esm({
|
|
|
39869
39843
|
width: external_exports.number().describe("Canvas width in pixels"),
|
|
39870
39844
|
height: external_exports.number().describe("Canvas height in pixels")
|
|
39871
39845
|
}).optional().describe("Canvas resolution"),
|
|
39846
|
+
rendering: external_exports.object({
|
|
39847
|
+
antialias: external_exports.boolean().describe(
|
|
39848
|
+
"Whether every three root is built with a multisampled drawing buffer. This is the ONE render property a world cannot declare for itself (world3d-react/renderer-config.ts): a WebGL context fixes its sample count at CREATION from this boolean, long before a world mounts, so it belongs to the PROJECT. The runtime reader is mount-manifest.ts, which threads it into createHostRenderer for each three root. WebGL exposes no sample COUNT \u2014 the implementation picks one (4x on every desktop browser measured), so a source engine that authored 8x/16x gets multisampling but not its exact count."
|
|
39849
|
+
)
|
|
39850
|
+
}).strict().optional().describe(
|
|
39851
|
+
"Construction-time renderer properties, which no world can declare after the fact. Everything a world CAN declare (tone mapping, output colour space, clear colour, shadow filter) lives on the world's own renderer config instead."
|
|
39852
|
+
),
|
|
39872
39853
|
debug: external_exports.object({
|
|
39873
39854
|
allowInProduction: external_exports.boolean().describe(
|
|
39874
39855
|
"Allow the ?vgai-debug=1 introspection bridge and debug-command invocation in production builds. Default false: the bridge only installs in dev builds. The runtime reader is the debug-bridge installer (D18)."
|
|
@@ -39925,6 +39906,11 @@ function checkAdapterEntryRules(root) {
|
|
|
39925
39906
|
`Game manifest: root "${root.id}" uses the '${adapter}' adapter but declares no \`entry\` \u2014 a built-in adapter root is authored as an entry module.`
|
|
39926
39907
|
);
|
|
39927
39908
|
}
|
|
39909
|
+
if (typeof adapter === "object" && "ingest" in adapter && !root.entry) {
|
|
39910
|
+
throw new Error(
|
|
39911
|
+
`Game manifest: root "${root.id}" is an { ingest } root but declares no \`entry\` \u2014 the game's own entry module is what the host imports.`
|
|
39912
|
+
);
|
|
39913
|
+
}
|
|
39928
39914
|
}
|
|
39929
39915
|
function resolveAdapter(root) {
|
|
39930
39916
|
const { adapter } = root;
|
|
@@ -39945,52 +39931,13 @@ function resolveAdapter(root) {
|
|
|
39945
39931
|
type: "ingest",
|
|
39946
39932
|
identity,
|
|
39947
39933
|
surface: adapter.surface,
|
|
39948
|
-
strategy: ingest.strategy,
|
|
39949
|
-
entryHtml: ingest.entryHtml,
|
|
39950
39934
|
contractShim: ingest.contractShim,
|
|
39935
|
+
dataWriter: ingest.dataWriter,
|
|
39951
39936
|
assets: ingest.assets,
|
|
39952
39937
|
domStubs: ingest.domStubs,
|
|
39953
|
-
captureTimeoutMs: ingest.captureTimeoutMs
|
|
39954
|
-
bundleUrl: ingest.bundleUrl,
|
|
39955
|
-
baseHref: ingest.baseHref,
|
|
39956
|
-
assetBaseUrl: ingest.assetBaseUrl,
|
|
39957
|
-
extraDeps: ingest.extraDeps,
|
|
39958
|
-
pixiModuleUrl: ingest.pixiModuleUrl,
|
|
39959
|
-
bodyHtml: ingest.bodyHtml
|
|
39938
|
+
captureTimeoutMs: ingest.captureTimeoutMs
|
|
39960
39939
|
};
|
|
39961
39940
|
}
|
|
39962
|
-
function ceilingFor(adapter, context) {
|
|
39963
|
-
if (typeof adapter === "string") return CAPABILITY_CEILINGS.builtin[context];
|
|
39964
|
-
if (isModuleAdapter(adapter)) return CAPABILITY_CEILINGS.module[context];
|
|
39965
|
-
return CAPABILITY_CEILINGS.ingest[adapter.ingest.strategy][context];
|
|
39966
|
-
}
|
|
39967
|
-
function resolveCapabilities(root) {
|
|
39968
|
-
const contexts = ["local", "hosted"];
|
|
39969
|
-
const result = {};
|
|
39970
|
-
for (const context of contexts) {
|
|
39971
|
-
const declared = root.capabilities?.[context];
|
|
39972
|
-
if (declared !== void 0) {
|
|
39973
|
-
const ceiling = ceilingFor(root.adapter, context);
|
|
39974
|
-
if (TIER_RANK[declared] > TIER_RANK[ceiling]) {
|
|
39975
|
-
throw new Error(
|
|
39976
|
-
`Game manifest: root "${root.id}": declared capabilities.${context} tier "${declared}" exceeds the "${ceiling}" ceiling for this adapter in the ${context} context (\xA74). Under-claiming (including \`unsupported\`) is legal; over-claiming is not.`
|
|
39977
|
-
);
|
|
39978
|
-
}
|
|
39979
|
-
result[context] = declared;
|
|
39980
|
-
continue;
|
|
39981
|
-
}
|
|
39982
|
-
if (typeof root.adapter === "string") {
|
|
39983
|
-
result[context] = "first-party";
|
|
39984
|
-
} else if (isModuleAdapter(root.adapter)) {
|
|
39985
|
-
throw new Error(
|
|
39986
|
-
`Game manifest: root "${root.id}": { module } adapter requires an explicit capabilities.${context} declaration \u2014 a custom adapter's reach is not derivable (\xA74).`
|
|
39987
|
-
);
|
|
39988
|
-
} else {
|
|
39989
|
-
result[context] = CAPABILITY_CEILINGS.ingest[root.adapter.ingest.strategy][context];
|
|
39990
|
-
}
|
|
39991
|
-
}
|
|
39992
|
-
return result;
|
|
39993
|
-
}
|
|
39994
39941
|
function checkEngineVersionPin(version2) {
|
|
39995
39942
|
if (!SEMVER_RE.test(version2)) {
|
|
39996
39943
|
throw new Error(
|
|
@@ -40010,8 +39957,7 @@ function resolveRoot2(root) {
|
|
|
40010
39957
|
zOrder: root.zOrder,
|
|
40011
39958
|
pausable: root.pausable,
|
|
40012
39959
|
dev: root.dev,
|
|
40013
|
-
loop: root.loop
|
|
40014
|
-
capabilities: resolveCapabilities(root)
|
|
39960
|
+
loop: root.loop
|
|
40015
39961
|
};
|
|
40016
39962
|
}
|
|
40017
39963
|
function loadGameManifest(raw) {
|
|
@@ -40044,6 +39990,7 @@ function loadGameManifest(raw) {
|
|
|
40044
39990
|
roots,
|
|
40045
39991
|
server: server2,
|
|
40046
39992
|
resolution: manifest.resolution,
|
|
39993
|
+
rendering: manifest.rendering,
|
|
40047
39994
|
authoring: manifest.authoring,
|
|
40048
39995
|
debug: manifest.debug,
|
|
40049
39996
|
determinism: manifest.determinism,
|
|
@@ -40051,29 +39998,11 @@ function loadGameManifest(raw) {
|
|
|
40051
39998
|
learn: manifest.learn
|
|
40052
39999
|
};
|
|
40053
40000
|
}
|
|
40054
|
-
var
|
|
40001
|
+
var DEFAULT_SERVER_MODULE, SEMVER_RE;
|
|
40055
40002
|
var init_load = __esm({
|
|
40056
40003
|
"../engine/src/manifest/load.ts"() {
|
|
40057
40004
|
"use strict";
|
|
40058
40005
|
init_schema();
|
|
40059
|
-
CAPABILITY_CEILINGS = {
|
|
40060
|
-
builtin: { local: "first-party", hosted: "first-party" },
|
|
40061
|
-
ingest: {
|
|
40062
|
-
shared: { local: "shared", hosted: "shared" },
|
|
40063
|
-
deduped: { local: "deduped", hosted: "unsupported" },
|
|
40064
|
-
"iframe-reachable": { local: "iframe-reachable", hosted: "iframe-reachable" },
|
|
40065
|
-
"opaque-embed": { local: "opaque-embed", hosted: "opaque-embed" }
|
|
40066
|
-
},
|
|
40067
|
-
module: { local: "first-party", hosted: "first-party" }
|
|
40068
|
-
};
|
|
40069
|
-
TIER_RANK = {
|
|
40070
|
-
"first-party": 5,
|
|
40071
|
-
shared: 4,
|
|
40072
|
-
deduped: 4,
|
|
40073
|
-
"iframe-reachable": 3,
|
|
40074
|
-
"opaque-embed": 2,
|
|
40075
|
-
unsupported: 1
|
|
40076
|
-
};
|
|
40077
40006
|
DEFAULT_SERVER_MODULE = "server/colyseus-setup.ts";
|
|
40078
40007
|
SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?$/;
|
|
40079
40008
|
}
|
|
@@ -42664,7 +42593,7 @@ function createIngestManifest(inspection, options) {
|
|
|
42664
42593
|
roots: [
|
|
42665
42594
|
{
|
|
42666
42595
|
id: "game",
|
|
42667
|
-
adapter: { surface, ingest: {
|
|
42596
|
+
adapter: { surface, ingest: {} },
|
|
42668
42597
|
entry
|
|
42669
42598
|
}
|
|
42670
42599
|
]
|
|
@@ -304450,12 +304379,54 @@ var require_lib = __commonJS({
|
|
|
304450
304379
|
}
|
|
304451
304380
|
});
|
|
304452
304381
|
|
|
304382
|
+
// ../vgai-live/dist/editor-document.js
|
|
304383
|
+
var LiveEditorDocument;
|
|
304384
|
+
var init_editor_document = __esm({
|
|
304385
|
+
"../vgai-live/dist/editor-document.js"() {
|
|
304386
|
+
"use strict";
|
|
304387
|
+
LiveEditorDocument = class {
|
|
304388
|
+
#client;
|
|
304389
|
+
constructor(client) {
|
|
304390
|
+
this.#client = client;
|
|
304391
|
+
}
|
|
304392
|
+
/** Read matching elements inside the active document: tag, text, attributes,
|
|
304393
|
+
* value/checked/disabled and rect. `matched` is the total before `limit`. */
|
|
304394
|
+
async query(selector, options) {
|
|
304395
|
+
return this.#probe({
|
|
304396
|
+
action: "query",
|
|
304397
|
+
selector,
|
|
304398
|
+
...options?.limit === void 0 ? {} : { limit: options.limit }
|
|
304399
|
+
});
|
|
304400
|
+
}
|
|
304401
|
+
/** A REAL pointer gesture (pointerdown/mousedown/focus/pointerup/mouseup/click)
|
|
304402
|
+
* — not `element.click()`, which a `pointerdown` listener never sees. */
|
|
304403
|
+
async click(selector, options) {
|
|
304404
|
+
return this.#probe({
|
|
304405
|
+
action: "click",
|
|
304406
|
+
selector,
|
|
304407
|
+
...options?.index === void 0 ? {} : { index: options.index }
|
|
304408
|
+
});
|
|
304409
|
+
}
|
|
304410
|
+
/** A real keydown/keyup on the target, or on whatever inside the document has focus. */
|
|
304411
|
+
async key(key, options) {
|
|
304412
|
+
return this.#probe({ action: "key", key, ...options ?? {} });
|
|
304413
|
+
}
|
|
304414
|
+
/** A real `ClipboardEvent` carrying `text/plain` — the gesture nothing else
|
|
304415
|
+
* in the product can produce. */
|
|
304416
|
+
async paste(text, options) {
|
|
304417
|
+
return this.#probe({ action: "paste", text, ...options ?? {} });
|
|
304418
|
+
}
|
|
304419
|
+
#probe(step) {
|
|
304420
|
+
return this.#client.documentProbe(step);
|
|
304421
|
+
}
|
|
304422
|
+
};
|
|
304423
|
+
}
|
|
304424
|
+
});
|
|
304425
|
+
|
|
304453
304426
|
// ../vgai-live/dist/editor.js
|
|
304454
304427
|
function inferAssetKind(path) {
|
|
304455
304428
|
if (path.endsWith(".prefab.json"))
|
|
304456
304429
|
return "prefab";
|
|
304457
|
-
if (path.endsWith(".mat.json"))
|
|
304458
|
-
return "material";
|
|
304459
304430
|
const dot = path.lastIndexOf(".");
|
|
304460
304431
|
const ext = dot >= 0 ? path.slice(dot).toLowerCase() : "";
|
|
304461
304432
|
return EXTENSION_KIND[ext] ?? "json";
|
|
@@ -304464,6 +304435,7 @@ var EXTENSION_KIND, LiveEditor;
|
|
|
304464
304435
|
var init_editor2 = __esm({
|
|
304465
304436
|
"../vgai-live/dist/editor.js"() {
|
|
304466
304437
|
"use strict";
|
|
304438
|
+
init_editor_document();
|
|
304467
304439
|
EXTENSION_KIND = {
|
|
304468
304440
|
".glb": "model",
|
|
304469
304441
|
".gltf": "model",
|
|
@@ -304473,10 +304445,15 @@ var init_editor2 = __esm({
|
|
|
304473
304445
|
".webp": "image",
|
|
304474
304446
|
".gif": "image",
|
|
304475
304447
|
".svg": "image",
|
|
304448
|
+
".hdr": "image",
|
|
304449
|
+
".exr": "image",
|
|
304476
304450
|
".mp3": "audio",
|
|
304477
304451
|
".ogg": "audio",
|
|
304478
304452
|
".wav": "audio",
|
|
304479
|
-
".flac": "audio"
|
|
304453
|
+
".flac": "audio",
|
|
304454
|
+
".glsl": "source",
|
|
304455
|
+
".vert": "source",
|
|
304456
|
+
".frag": "source"
|
|
304480
304457
|
};
|
|
304481
304458
|
LiveEditor = class {
|
|
304482
304459
|
/** `#`-private, not `private`: `vgai eval --list` enumerates this object's
|
|
@@ -304484,8 +304461,18 @@ var init_editor2 = __esm({
|
|
|
304484
304461
|
* raw `EditorClient` advertised beside them. See `./game-client/`'s
|
|
304485
304462
|
* `client.ts` (GameClient's field block) for the full reasoning. */
|
|
304486
304463
|
#client;
|
|
304464
|
+
/**
|
|
304465
|
+
* The ACTIVE center document's own DOM: read it, click it, key it, paste
|
|
304466
|
+
* into it. The one door onto editor chrome that is not play-mode gated, and
|
|
304467
|
+
* deliberately scoped to that document alone —
|
|
304468
|
+
* `packages/editor/src/editor-document-probe.ts` carries the design and the
|
|
304469
|
+
* refusal contract. Screenshotting the same subject is
|
|
304470
|
+
* {@link LiveEditor.captureActiveDocument}, not a fifth verb here.
|
|
304471
|
+
*/
|
|
304472
|
+
document;
|
|
304487
304473
|
constructor(client) {
|
|
304488
304474
|
this.#client = client;
|
|
304475
|
+
this.document = new LiveEditorDocument(client);
|
|
304489
304476
|
}
|
|
304490
304477
|
/**
|
|
304491
304478
|
* The active authoring adapter's persistence destination — where a save would
|
|
@@ -304637,6 +304624,23 @@ var init_editor2 = __esm({
|
|
|
304637
304624
|
async shading(mode) {
|
|
304638
304625
|
await this.#client.setShadingMode(mode);
|
|
304639
304626
|
}
|
|
304627
|
+
/**
|
|
304628
|
+
* CONSENT to edits being written into the game's own source files, for this
|
|
304629
|
+
* session — the Game document's "Persist to game source" checkbox, reachable
|
|
304630
|
+
* from a script.
|
|
304631
|
+
*
|
|
304632
|
+
* Off by default every session, on purpose: it is a statement about what you
|
|
304633
|
+
* are doing right now, never a property of the game. With it off, an edit
|
|
304634
|
+
* lives on the running object and says so; with it on, an edit that can be
|
|
304635
|
+
* honestly anchored to the line that CREATED the object is written there,
|
|
304636
|
+
* and one that cannot still says so. Answers with the server's own phrase for
|
|
304637
|
+
* who records the resulting diff — your version control, or a vendored
|
|
304638
|
+
* game's own lock — and refuses, with the reason, where the checkbox is
|
|
304639
|
+
* disabled.
|
|
304640
|
+
*/
|
|
304641
|
+
async persistToGameSource(on) {
|
|
304642
|
+
return this.#client.setSourcePersistConsent(on);
|
|
304643
|
+
}
|
|
304640
304644
|
/**
|
|
304641
304645
|
* READ the inspector, as data — the serialized inspection subject
|
|
304642
304646
|
* (`editor.inspect()`; design: `docs/ARCHITECTURE-CORE.md` §Editor chrome,
|
|
@@ -304667,6 +304671,51 @@ var init_editor2 = __esm({
|
|
|
304667
304671
|
async inspect() {
|
|
304668
304672
|
return this.#client.inspect();
|
|
304669
304673
|
}
|
|
304674
|
+
/**
|
|
304675
|
+
* READ the hierarchy panel, as data — the rows a human is looking at right
|
|
304676
|
+
* now, nested exactly as the panel nests them.
|
|
304677
|
+
*
|
|
304678
|
+
* The companion to {@link inspect}: that one answers "what IS the selected
|
|
304679
|
+
* thing", this one answers "what does the tree LOOK LIKE". It is the panel's
|
|
304680
|
+
* own output, not a fresh walk of the scene — the adapter's tree after the
|
|
304681
|
+
* component marks fold implementation subtrees (bones, particle renderers,
|
|
304682
|
+
* instanced pools), after the internals reveal, the document promotion, the
|
|
304683
|
+
* child cap, the collapse state, the search filter and the selection scope.
|
|
304684
|
+
*
|
|
304685
|
+
* Works in play mode and edit mode; the answer says which (`playState`,
|
|
304686
|
+
* `activeViewportTab`), because the two are different adapters and a tree
|
|
304687
|
+
* that looks wrong is very often the wrong adapter's tree.
|
|
304688
|
+
*
|
|
304689
|
+
* Prefer this over `status().entities`, which is deliberately a different
|
|
304690
|
+
* question — the RAW adapter tree, unprojected. A panel that renders the
|
|
304691
|
+
* wrong rows looks perfectly healthy in that facet.
|
|
304692
|
+
*
|
|
304693
|
+
* Each row carries `childCount` (what its caret opens), `internalChildCount`
|
|
304694
|
+
* (what is folded behind "Reveal Internals") and `expandable` (whether the
|
|
304695
|
+
* panel draws a caret at all), so "this subtree exists but nothing in the UI
|
|
304696
|
+
* opens it" is a fact you can read rather than one you have to notice.
|
|
304697
|
+
*
|
|
304698
|
+
* Rejects, naming the panel, when no hierarchy panel is mounted — an empty
|
|
304699
|
+
* tree would be a fabricated answer about a surface nobody is being shown.
|
|
304700
|
+
*/
|
|
304701
|
+
async hierarchy() {
|
|
304702
|
+
return this.#client.hierarchy();
|
|
304703
|
+
}
|
|
304704
|
+
/**
|
|
304705
|
+
* Write one editable field from `inspect()` by its stable path, through the
|
|
304706
|
+
* same Inspector IO and persistence boundary the human control uses.
|
|
304707
|
+
*/
|
|
304708
|
+
async setField(path, value) {
|
|
304709
|
+
return this.#client.setInspectionField(path, value);
|
|
304710
|
+
}
|
|
304711
|
+
/** Undo / redo one project transaction, through the session's own history
|
|
304712
|
+
* queue — the same one the keyboard shortcut drives. */
|
|
304713
|
+
async undo() {
|
|
304714
|
+
return this.#client.undo();
|
|
304715
|
+
}
|
|
304716
|
+
async redo() {
|
|
304717
|
+
return this.#client.redo();
|
|
304718
|
+
}
|
|
304670
304719
|
/** Mirrors `vgai status` — the full live editor state as JSON. */
|
|
304671
304720
|
async status() {
|
|
304672
304721
|
return this.#client.getState();
|
|
@@ -306335,6 +306384,7 @@ __export(dist_exports, {
|
|
|
306335
306384
|
HIDDEN_RECOVERY_STALL_POLLS: () => HIDDEN_RECOVERY_STALL_POLLS,
|
|
306336
306385
|
HiddenRecoveryDriver: () => HiddenRecoveryDriver,
|
|
306337
306386
|
LiveEditor: () => LiveEditor,
|
|
306387
|
+
LiveEditorDocument: () => LiveEditorDocument,
|
|
306338
306388
|
LiveTools: () => LiveTools,
|
|
306339
306389
|
PageTransport: () => PageTransport,
|
|
306340
306390
|
RelayTransport: () => RelayTransport,
|
|
@@ -306408,6 +306458,7 @@ var init_dist = __esm({
|
|
|
306408
306458
|
init_singleton();
|
|
306409
306459
|
init_tools();
|
|
306410
306460
|
init_editor2();
|
|
306461
|
+
init_editor_document();
|
|
306411
306462
|
init_game();
|
|
306412
306463
|
init_game_client();
|
|
306413
306464
|
init_session();
|
|
@@ -307551,7 +307602,6 @@ function rewritePackageJson(targetDir, slug, engineDir, monoRoot) {
|
|
|
307551
307602
|
function resolvePackageRoots() {
|
|
307552
307603
|
return {
|
|
307553
307604
|
engineRelPath: "node_modules/@vgai/engine",
|
|
307554
|
-
p2pRelPath: "node_modules/@vgai/p2p-colyseus/",
|
|
307555
307605
|
editorRelPath: "node_modules/@vgai/editor",
|
|
307556
307606
|
liveRelPath: "node_modules/@vgai/live",
|
|
307557
307607
|
sdkRelPath: "node_modules/@vgai/sdk",
|
|
@@ -307612,6 +307662,32 @@ function rewriteGameManifest(targetDir, name, slug, template, monoRoot) {
|
|
|
307612
307662
|
writeJson(manifestPath, manifest);
|
|
307613
307663
|
return manifest;
|
|
307614
307664
|
}
|
|
307665
|
+
function repinEngineAfterInstall(targetDir) {
|
|
307666
|
+
const installed = readInstalledVersion(targetDir, "@vgai/engine");
|
|
307667
|
+
if (!installed) return null;
|
|
307668
|
+
const manifestPath = resolveManifestPath(targetDir);
|
|
307669
|
+
let manifest;
|
|
307670
|
+
try {
|
|
307671
|
+
manifest = JSON.parse(readFileSync12(manifestPath, "utf-8"));
|
|
307672
|
+
} catch {
|
|
307673
|
+
return null;
|
|
307674
|
+
}
|
|
307675
|
+
const engine = manifest["engine"] ?? {};
|
|
307676
|
+
const from = typeof engine["version"] === "string" ? engine["version"] : "";
|
|
307677
|
+
if (from === installed) return null;
|
|
307678
|
+
manifest["engine"] = { ...engine, version: installed };
|
|
307679
|
+
writeJson(manifestPath, manifest);
|
|
307680
|
+
const baselinePath = join14(targetDir, SCAFFOLD_BASELINE_RELATIVE_PATH);
|
|
307681
|
+
try {
|
|
307682
|
+
const baseline = JSON.parse(readFileSync12(baselinePath, "utf-8"));
|
|
307683
|
+
baseline.engineVersion = installed;
|
|
307684
|
+
baseline.files["vgai.project.json"] = hashFile(manifestPath);
|
|
307685
|
+
writeFileSync4(baselinePath, `${JSON.stringify(baseline, null, 2)}
|
|
307686
|
+
`, "utf-8");
|
|
307687
|
+
} catch {
|
|
307688
|
+
}
|
|
307689
|
+
return { from, to: installed };
|
|
307690
|
+
}
|
|
307615
307691
|
var REACT_ONLY_PAGE_SOURCE = `export interface ReactGamePageProps {
|
|
307616
307692
|
readonly lastInput: string;
|
|
307617
307693
|
readonly title?: string;
|
|
@@ -307758,26 +307834,13 @@ function rewriteTsconfig(targetDir, engineRelPath, editorRelPath) {
|
|
|
307758
307834
|
}
|
|
307759
307835
|
writeJson(tsconfigPath, tsconfig);
|
|
307760
307836
|
}
|
|
307761
|
-
function rewriteViteConfig(targetDir
|
|
307837
|
+
function rewriteViteConfig(targetDir) {
|
|
307762
307838
|
const vitePath = join14(targetDir, "vite.config.ts");
|
|
307763
307839
|
if (!existsSync11(vitePath)) return;
|
|
307764
|
-
writeFileSync4(
|
|
307765
|
-
vitePath,
|
|
307766
|
-
rewriteViteConfigContent(readFileSync12(vitePath, "utf-8"), engineRelPath, p2pRelPath),
|
|
307767
|
-
"utf-8"
|
|
307768
|
-
);
|
|
307840
|
+
writeFileSync4(vitePath, rewriteViteConfigContent(readFileSync12(vitePath, "utf-8")), "utf-8");
|
|
307769
307841
|
}
|
|
307770
|
-
function rewriteViteConfigContent(content
|
|
307771
|
-
|
|
307772
|
-
return ensureReactDedupe(
|
|
307773
|
-
content.replace(
|
|
307774
|
-
/'@engine':\s*path\.resolve\(__dirname,\s*['"][^'"]+['"]\)/,
|
|
307775
|
-
`'@engine': path.resolve(__dirname, '${engineRelPath}/src')`
|
|
307776
|
-
).replace(/\.\.\/\.\.\/(?:packages\/)?p2p-colyseus\//g, p2pRelPath).replace(
|
|
307777
|
-
/(['"])\.\.\/\.\.\/(?:packages\/)?engine\/src\/data\/vite-plugin-data\1/g,
|
|
307778
|
-
`$1${enginePluginRoot}/src/data/vite-plugin-data$1`
|
|
307779
|
-
)
|
|
307780
|
-
);
|
|
307842
|
+
function rewriteViteConfigContent(content) {
|
|
307843
|
+
return ensureReactDedupe(content);
|
|
307781
307844
|
}
|
|
307782
307845
|
function ensureReactDedupe(content) {
|
|
307783
307846
|
const REQUIRED = ["react", "react-dom"];
|
|
@@ -307797,32 +307860,6 @@ function ensureReactDedupe(content) {
|
|
|
307797
307860
|
"resolve: {\n // react/react-dom dedupe (GH #123): see packages/editor/template/vite.config.ts's\n // matching comment for the dual-React-instance root cause this avoids.\n dedupe: ['react', 'react-dom'],"
|
|
307798
307861
|
);
|
|
307799
307862
|
}
|
|
307800
|
-
function rewriteDataRefModule(targetDir, engineRelPath) {
|
|
307801
|
-
const dataRefPath = join14(targetDir, "src", "data", "data-ref.ts");
|
|
307802
|
-
if (!existsSync11(dataRefPath)) return;
|
|
307803
|
-
writeFileSync4(
|
|
307804
|
-
dataRefPath,
|
|
307805
|
-
rewriteDataRefModuleContent(readFileSync12(dataRefPath, "utf-8"), engineRelPath),
|
|
307806
|
-
"utf-8"
|
|
307807
|
-
);
|
|
307808
|
-
}
|
|
307809
|
-
function rewriteDataRefModuleContent(content, engineRelPath) {
|
|
307810
|
-
return content.replace(
|
|
307811
|
-
// Match BOTH in-repo spellings, exactly like the sibling p2p-colyseus and
|
|
307812
|
-
// vite-plugin-data rewrites above (`(?:packages\/)?`): the STARTER template
|
|
307813
|
-
// (packages/editor/template/) spells this `../../../../engine/src/data/…`
|
|
307814
|
-
// (already inside `packages/`), but an `examples/<id>/` project spells the
|
|
307815
|
-
// identical on-disk target `../../../../packages/engine/src/data/…` (WITH
|
|
307816
|
-
// the `packages/` segment). Without the optional `packages/` here a bare
|
|
307817
|
-
// literal match no-oped on every data-trio EXAMPLE scaffold, leaving its
|
|
307818
|
-
// data-ref.ts pointed at the in-checkout depth — which fails `tsc`/`vite
|
|
307819
|
-
// build` the moment it's scaffolded into any external directory (E4
|
|
307820
|
-
// AC-TPL-002; no prior CI externally-scaffolds a data-trio example, so it
|
|
307821
|
-
// stayed latent). The p2p/vite-plugin rewrites already carried this guard.
|
|
307822
|
-
/(['"])(?:\.\.\/)+(?:packages\/)?engine\/src\/data\/data-ref\1/,
|
|
307823
|
-
`$1../../${engineRelPath}/src/data/data-ref$1`
|
|
307824
|
-
);
|
|
307825
|
-
}
|
|
307826
307863
|
function rewriteIndexHtml(targetDir, name) {
|
|
307827
307864
|
const htmlPath = join14(targetDir, "index.html");
|
|
307828
307865
|
if (!existsSync11(htmlPath)) return;
|
|
@@ -307859,13 +307896,12 @@ function scaffoldProject(opts) {
|
|
|
307859
307896
|
writeExampleReadme(targetDir, name, opts.exampleId);
|
|
307860
307897
|
}
|
|
307861
307898
|
if (opts.presentation) applyPresentation(targetDir, opts.presentation);
|
|
307862
|
-
const { engineRelPath,
|
|
307899
|
+
const { engineRelPath, editorRelPath } = resolvePackageRoots();
|
|
307863
307900
|
rewritePackageJson(targetDir, slug, engineDir, monoRoot);
|
|
307864
307901
|
const manifest = rewriteGameManifest(targetDir, name, slug, template, monoRoot);
|
|
307865
307902
|
rewriteTemplateVariantFiles(targetDir, template);
|
|
307866
307903
|
rewriteTsconfig(targetDir, engineRelPath, editorRelPath);
|
|
307867
|
-
rewriteViteConfig(targetDir
|
|
307868
|
-
rewriteDataRefModule(targetDir, engineRelPath);
|
|
307904
|
+
rewriteViteConfig(targetDir);
|
|
307869
307905
|
rewriteIndexHtml(targetDir, name);
|
|
307870
307906
|
rewriteRoadmap(targetDir, name);
|
|
307871
307907
|
if (hasCapabilityDistribution) initializeProjectCatalog(targetDir, catalogDir);
|
|
@@ -308058,15 +308094,6 @@ function checkAdapterWall(manifest) {
|
|
|
308058
308094
|
}
|
|
308059
308095
|
}
|
|
308060
308096
|
}
|
|
308061
|
-
function checkHostedTierWall(manifest) {
|
|
308062
|
-
for (const world of manifest.roots) {
|
|
308063
|
-
if (world.capabilities.hosted !== "first-party") {
|
|
308064
|
-
throw new DeployError(
|
|
308065
|
-
`vgai deploy: world "${world.id}" declares capabilities.hosted = "${world.capabilities.hosted}", below the required "first-party" tier \u2014 a static host IS a hosted delivery context (\xA71.B), and only first-party roots can ship there.`
|
|
308066
|
-
);
|
|
308067
|
-
}
|
|
308068
|
-
}
|
|
308069
|
-
}
|
|
308070
308097
|
function runProjectBuild(projectDir, extraViteArgs) {
|
|
308071
308098
|
const cmd = extraViteArgs ? `npm run build -- ${extraViteArgs}` : "npm run build";
|
|
308072
308099
|
try {
|
|
@@ -308154,7 +308181,6 @@ async function deployProject(opts) {
|
|
|
308154
308181
|
const { projectDir, reportOnly = false, wrangler } = opts;
|
|
308155
308182
|
const manifest = loadManifestOrThrow(projectDir);
|
|
308156
308183
|
checkAdapterWall(manifest);
|
|
308157
|
-
checkHostedTierWall(manifest);
|
|
308158
308184
|
const projectName = opts.projectName ?? defaultProjectName(manifest.name);
|
|
308159
308185
|
const targetUrlShape = `${projectName}.pages.dev`;
|
|
308160
308186
|
if (!reportOnly) {
|
|
@@ -309238,7 +309264,6 @@ async function packageItchZip(opts) {
|
|
|
309238
309264
|
const { projectDir, reportOnly = false } = opts;
|
|
309239
309265
|
const manifest = loadManifestOrThrow(projectDir);
|
|
309240
309266
|
checkAdapterWall(manifest);
|
|
309241
|
-
checkHostedTierWall(manifest);
|
|
309242
309267
|
runProjectBuild(projectDir, "--base ./");
|
|
309243
309268
|
const manifestPath = resolveManifestPath(projectDir);
|
|
309244
309269
|
const staging = stageBuildOutput(projectDir, manifestPath);
|
|
@@ -309689,7 +309714,7 @@ function projectHasThreeRoot(projectDir) {
|
|
|
309689
309714
|
}
|
|
309690
309715
|
function reapplyScaffoldRewrites(scratchDir, projectDir, monoRoot, name, currentEngineVersion, targetPackageVersions) {
|
|
309691
309716
|
const engineDir = resolveScaffoldPackageDir(monoRoot, join18("packages", "engine"), "@vgai/engine");
|
|
309692
|
-
const { engineRelPath,
|
|
309717
|
+
const { engineRelPath, editorRelPath, liveRelPath, sdkRelPath, editorSdkRelPath } = resolvePackageRoots();
|
|
309693
309718
|
const targetEditorVersion = targetPackageVersions["@vgai/editor"] ?? readInstalledVersion(monoRoot, "@vgai/editor");
|
|
309694
309719
|
const satelliteRelPaths = {
|
|
309695
309720
|
"@vgai/live": liveRelPath,
|
|
@@ -309774,21 +309799,9 @@ function reapplyScaffoldRewrites(scratchDir, projectDir, monoRoot, name, current
|
|
|
309774
309799
|
}
|
|
309775
309800
|
const vitePath = join18(scratchDir, "vite.config.ts");
|
|
309776
309801
|
if (existsSync14(vitePath)) {
|
|
309777
|
-
const content = rewriteViteConfigContent(
|
|
309778
|
-
readFileSync16(vitePath, "utf-8"),
|
|
309779
|
-
engineRelPath,
|
|
309780
|
-
p2pRelPath
|
|
309781
|
-
);
|
|
309802
|
+
const content = rewriteViteConfigContent(readFileSync16(vitePath, "utf-8"));
|
|
309782
309803
|
writeFileSync7(vitePath, content, "utf-8");
|
|
309783
309804
|
}
|
|
309784
|
-
const dataRefPath = join18(scratchDir, "src", "data", "data-ref.ts");
|
|
309785
|
-
if (existsSync14(dataRefPath)) {
|
|
309786
|
-
writeFileSync7(
|
|
309787
|
-
dataRefPath,
|
|
309788
|
-
rewriteDataRefModuleContent(readFileSync16(dataRefPath, "utf-8"), engineRelPath),
|
|
309789
|
-
"utf-8"
|
|
309790
|
-
);
|
|
309791
|
-
}
|
|
309792
309805
|
const htmlPath = join18(scratchDir, "index.html");
|
|
309793
309806
|
if (existsSync14(htmlPath)) {
|
|
309794
309807
|
const html = readFileSync16(htmlPath, "utf-8").replace(
|
|
@@ -310347,6 +310360,7 @@ function formatTabCensus(census) {
|
|
|
310347
310360
|
census.heapUsedMB === null ? "heap n/a" : `heap ${census.heapUsedMB}MB${census.heapLimitMB === null ? "" : `/${census.heapLimitMB}MB`}`,
|
|
310348
310361
|
`canvas ${census.canvasMB}MB in ${census.canvases}`
|
|
310349
310362
|
];
|
|
310363
|
+
if (census.mountEpochs !== void 0) parts.splice(1, 0, `mount epochs ${census.mountEpochs}`);
|
|
310350
310364
|
if (census.textures !== void 0) parts.push(`tex ${census.textures}`);
|
|
310351
310365
|
if (census.geometries !== void 0) parts.push(`geo ${census.geometries}`);
|
|
310352
310366
|
if (census.programs !== void 0) parts.push(`prog ${census.programs}`);
|
|
@@ -321178,7 +321192,14 @@ function shipRoutesLine(projectRoot) {
|
|
|
321178
321192
|
}
|
|
321179
321193
|
return text.includes(STARTER_SENTINEL) ? "ship routes: not yet implemented (fine while the game is forming \u2014 see AGENTS.md)" : "ship routes: implemented";
|
|
321180
321194
|
}
|
|
321181
|
-
var GAMEPLAY_PATHS = [
|
|
321195
|
+
var GAMEPLAY_PATHS = [
|
|
321196
|
+
"src/components",
|
|
321197
|
+
"src/scenes",
|
|
321198
|
+
"src/prefabs",
|
|
321199
|
+
"src/lib",
|
|
321200
|
+
"src/world.tsx",
|
|
321201
|
+
"src/hooks"
|
|
321202
|
+
];
|
|
321182
321203
|
var STALE_AUTOPLAY_COMMIT_THRESHOLD = 5;
|
|
321183
321204
|
function git2(cwd2, args2) {
|
|
321184
321205
|
const result = spawnSync8("git", args2, { cwd: cwd2, encoding: "utf-8" });
|
|
@@ -321212,13 +321233,7 @@ function livePlaneLine(shape) {
|
|
|
321212
321233
|
}
|
|
321213
321234
|
|
|
321214
321235
|
// src/integrations.ts
|
|
321215
|
-
import {
|
|
321216
|
-
existsSync as existsSync22,
|
|
321217
|
-
mkdirSync as mkdirSync11,
|
|
321218
|
-
readFileSync as readFileSync25,
|
|
321219
|
-
renameSync as renameSync3,
|
|
321220
|
-
writeFileSync as writeFileSync9
|
|
321221
|
-
} from "node:fs";
|
|
321236
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync25, renameSync as renameSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
321222
321237
|
import { homedir as homedir6 } from "node:os";
|
|
321223
321238
|
import { dirname as dirname13, join as join29 } from "node:path";
|
|
321224
321239
|
|
|
@@ -321285,9 +321300,7 @@ function parseHookStdin(raw) {
|
|
|
321285
321300
|
return {};
|
|
321286
321301
|
}
|
|
321287
321302
|
function buildCallerSessionContext(opts) {
|
|
321288
|
-
const lines = [
|
|
321289
|
-
"vgai caller-session bridge (advisory, not a gate):"
|
|
321290
|
-
];
|
|
321303
|
+
const lines = ["vgai caller-session bridge (advisory, not a gate):"];
|
|
321291
321304
|
if (opts.projectRoot) {
|
|
321292
321305
|
lines.push(` project root: ${opts.projectRoot}`);
|
|
321293
321306
|
} else {
|
|
@@ -321304,19 +321317,13 @@ function buildCallerSessionContext(opts) {
|
|
|
321304
321317
|
}
|
|
321305
321318
|
if (opts.projectRoot) {
|
|
321306
321319
|
const canon = canonicalPath(opts.projectRoot);
|
|
321307
|
-
const match = editors.find(
|
|
321308
|
-
(s) => s.project !== null && canonicalPath(s.project) === canon
|
|
321309
|
-
);
|
|
321320
|
+
const match = editors.find((s) => s.project !== null && canonicalPath(s.project) === canon);
|
|
321310
321321
|
if (match) {
|
|
321311
|
-
lines.push(
|
|
321312
|
-
` prefer this session for control commands: http://127.0.0.1:${match.port}`
|
|
321313
|
-
);
|
|
321322
|
+
lines.push(` prefer this session for control commands: http://127.0.0.1:${match.port}`);
|
|
321314
321323
|
}
|
|
321315
321324
|
}
|
|
321316
321325
|
}
|
|
321317
|
-
lines.push(
|
|
321318
|
-
" drive the game with `vgai eval`, never synthetic keys / wall-clock sleeps."
|
|
321319
|
-
);
|
|
321326
|
+
lines.push(" drive the game with `vgai eval`, never synthetic keys / wall-clock sleeps.");
|
|
321320
321327
|
return lines.join("\n");
|
|
321321
321328
|
}
|
|
321322
321329
|
function gatherLiveSessionNotes() {
|
|
@@ -321441,9 +321448,7 @@ function readIntegrationStatus(paths) {
|
|
|
321441
321448
|
if (codex) {
|
|
321442
321449
|
const hooks = codex["hooks"];
|
|
321443
321450
|
if (typeof hooks === "object" && hooks !== null) {
|
|
321444
|
-
codexSessionStartInstalled = hasVgaiCommandInHookList(
|
|
321445
|
-
hooks["SessionStart"]
|
|
321446
|
-
);
|
|
321451
|
+
codexSessionStartInstalled = hasVgaiCommandInHookList(hooks["SessionStart"]);
|
|
321447
321452
|
legacyCodexPreToolUseBashGate = hasLegacyCodexPreToolUseBashGate(codex);
|
|
321448
321453
|
}
|
|
321449
321454
|
} else if (existsSync22(paths.codexHooksJson)) {
|
|
@@ -321453,14 +321458,10 @@ function readIntegrationStatus(paths) {
|
|
|
321453
321458
|
if (claude) {
|
|
321454
321459
|
const hooks = claude["hooks"];
|
|
321455
321460
|
if (typeof hooks === "object" && hooks !== null) {
|
|
321456
|
-
claudeSessionStartInstalled = hasVgaiCommandInHookList(
|
|
321457
|
-
hooks["SessionStart"]
|
|
321458
|
-
);
|
|
321461
|
+
claudeSessionStartInstalled = hasVgaiCommandInHookList(hooks["SessionStart"]);
|
|
321459
321462
|
}
|
|
321460
321463
|
} else if (existsSync22(paths.claudeSettingsJson)) {
|
|
321461
|
-
notes.push(
|
|
321462
|
-
`claude settings file exists but is not valid JSON: ${paths.claudeSettingsJson}`
|
|
321463
|
-
);
|
|
321464
|
+
notes.push(`claude settings file exists but is not valid JSON: ${paths.claudeSettingsJson}`);
|
|
321464
321465
|
}
|
|
321465
321466
|
if (legacyCodexPreToolUseBashGate) {
|
|
321466
321467
|
notes.push(
|
|
@@ -324162,9 +324163,6 @@ function detectUnmanagedReactRoots(source, file2) {
|
|
|
324162
324163
|
}
|
|
324163
324164
|
|
|
324164
324165
|
// src/validate.ts
|
|
324165
|
-
function isServedRouteOrAbsoluteUrl(value) {
|
|
324166
|
-
return /^[a-z][a-z0-9+.-]*:\/\//i.test(value) || value.startsWith("//") || value.startsWith("/project-game-static/");
|
|
324167
|
-
}
|
|
324168
324166
|
function checkFile(worldId, field, declaredPath, resolvedPath) {
|
|
324169
324167
|
return { worldId, field, declaredPath, resolvedPath, exists: existsSync25(resolvedPath) };
|
|
324170
324168
|
}
|
|
@@ -324175,16 +324173,9 @@ function collectFileChecks(folder, manifest) {
|
|
|
324175
324173
|
checks.push(checkFile(world.id, "entry", world.entry, join35(folder, world.entry)));
|
|
324176
324174
|
}
|
|
324177
324175
|
if (world.adapter.type === "ingest") {
|
|
324178
|
-
const
|
|
324179
|
-
if (
|
|
324180
|
-
checks.push(
|
|
324181
|
-
checkFile(world.id, "adapter.ingest.entryHtml", entryHtml, join35(folder, entryHtml))
|
|
324182
|
-
);
|
|
324183
|
-
}
|
|
324184
|
-
if (bundleUrl !== void 0 && !isServedRouteOrAbsoluteUrl(bundleUrl)) {
|
|
324185
|
-
checks.push(
|
|
324186
|
-
checkFile(world.id, "adapter.ingest.bundleUrl", bundleUrl, join35(folder, bundleUrl))
|
|
324187
|
-
);
|
|
324176
|
+
const shim = world.adapter.contractShim;
|
|
324177
|
+
if (shim !== void 0) {
|
|
324178
|
+
checks.push(checkFile(world.id, "adapter.ingest.contractShim", shim, join35(folder, shim)));
|
|
324188
324179
|
}
|
|
324189
324180
|
}
|
|
324190
324181
|
}
|
|
@@ -324698,8 +324689,8 @@ function catalogDistributionDir() {
|
|
|
324698
324689
|
);
|
|
324699
324690
|
}
|
|
324700
324691
|
function cliVersion() {
|
|
324701
|
-
if ("0.5.
|
|
324702
|
-
return "0.5.
|
|
324692
|
+
if ("0.5.12") {
|
|
324693
|
+
return "0.5.12";
|
|
324703
324694
|
}
|
|
324704
324695
|
try {
|
|
324705
324696
|
const pkg = JSON.parse(readFileSync32(join39(__dirname4, "..", "package.json"), "utf8"));
|
|
@@ -324718,7 +324709,7 @@ function bakedTargetVersions() {
|
|
|
324718
324709
|
if (false)
|
|
324719
324710
|
return void 0;
|
|
324720
324711
|
try {
|
|
324721
|
-
return JSON.parse('{"@vgai/engine":"0.5.
|
|
324712
|
+
return JSON.parse('{"@vgai/engine":"0.5.12","@vgai/editor":"0.5.12","@vgai/p2p-colyseus":"0.5.12","@vgai/live":"0.5.12","@vgai/sdk":"0.5.12","@vgai/editor-sdk":"0.5.12","@vgai/cli":"0.5.12"}');
|
|
324722
324713
|
} catch {
|
|
324723
324714
|
return void 0;
|
|
324724
324715
|
}
|
|
@@ -324821,7 +324812,6 @@ Verify it:
|
|
|
324821
324812
|
Ship it:
|
|
324822
324813
|
npm run deploy The project's provider-native deployment script
|
|
324823
324814
|
deploy [folder] Legacy Cloudflare/itch compatibility for existing projects
|
|
324824
|
-
bundle <folder> Sidecar ESM bundle for an external pixi game
|
|
324825
324815
|
render-cinematic Deterministic frame-addressed video export
|
|
324826
324816
|
|
|
324827
324817
|
Bring in an existing web game:
|
|
@@ -324987,7 +324977,7 @@ Project:
|
|
|
324987
324977
|
--to (that package, if named) > this CLI build's baked-in version
|
|
324988
324978
|
> (in-repo only) this checkout's installed version.
|
|
324989
324979
|
validate [folder] In-process: validate vgai.project.json, check every declared
|
|
324990
|
-
entry/
|
|
324980
|
+
entry/contractShim file exists, print the engine pin
|
|
324991
324981
|
(default: cwd) \u2014 no monorepo/editor/Vite needed beyond this checkout
|
|
324992
324982
|
Exit codes: 0 valid, 1 invalid manifest/files/React roots/design states, 2 usage
|
|
324993
324983
|
Deployment is project-owned: add deploy-vercel or deploy-cloudflare, then
|
|
@@ -324996,15 +324986,6 @@ Project:
|
|
|
324996
324986
|
--json Print a single machine-readable JSON report instead of text
|
|
324997
324987
|
Exit codes: 0 pass, 1 conformance failure, 2 usage/environment error
|
|
324998
324988
|
Requires a monorepo checkout (same precondition as \`edit\`)
|
|
324999
|
-
bundle <folder> Build an external pixi game's iframe-reachable world as a sidecar
|
|
325000
|
-
ESM bundle (pixi.js + declared extraDeps externalized), never
|
|
325001
|
-
touching game source. Prints the vgai.project.json fields to add.
|
|
325002
|
-
--write Patch vgai.project.json's bundleUrl in place instead of printing it
|
|
325003
|
-
--entry <path> Build entry, folder-relative (default: probed from package.json)
|
|
325004
|
-
--world <id> Which world to build (default: the manifest's one iframe-reachable
|
|
325005
|
-
canvas world \u2014 an error if there are zero or several)
|
|
325006
|
-
Exit codes: 0 built, 1 build failure, 2 usage error
|
|
325007
|
-
Requires a monorepo checkout (same precondition as \`edit\`)
|
|
325008
324989
|
doctor <folder> Headless mount of every declared world: static validation
|
|
325009
324990
|
(manifest + declared files + engine pin), then a REAL headless
|
|
325010
324991
|
editor session. Exactly one verdict per world \u2014
|
|
@@ -326042,11 +326023,7 @@ function renderValidateReport(report) {
|
|
|
326042
326023
|
`${manifestPath}: OK \u2014 "${manifest.name}" v${manifest.version} (engine ${manifest.engine.version})`
|
|
326043
326024
|
);
|
|
326044
326025
|
for (const world of manifest.roots) {
|
|
326045
|
-
|
|
326046
|
-
const adapterLabel = adapter.type === "ingest" ? `${adapter.identity} (${adapter.strategy})` : adapter.identity;
|
|
326047
|
-
lines.push(
|
|
326048
|
-
` root "${world.id}" surface=${world.surface} adapter=${adapterLabel} tiers={local: ${world.capabilities.local}, hosted: ${world.capabilities.hosted}}`
|
|
326049
|
-
);
|
|
326026
|
+
lines.push(` root "${world.id}" surface=${world.surface} adapter=${world.adapter.identity}`);
|
|
326050
326027
|
}
|
|
326051
326028
|
lines.push("");
|
|
326052
326029
|
const missing = fileChecks.filter((f) => !f.exists);
|
|
@@ -326448,6 +326425,24 @@ function describeEditorProvenance(packagedEntry, engineRoot) {
|
|
|
326448
326425
|
}
|
|
326449
326426
|
return `Editor: packaged @vgai/editor@${version2} (${editorPkgDir})`;
|
|
326450
326427
|
}
|
|
326428
|
+
function assertEditorProjectInstalled(absProject, engineRoot = ENGINE_ROOT) {
|
|
326429
|
+
let realEngineRoot;
|
|
326430
|
+
try {
|
|
326431
|
+
realEngineRoot = realpathSync8(engineRoot);
|
|
326432
|
+
} catch {
|
|
326433
|
+
realEngineRoot = engineRoot;
|
|
326434
|
+
}
|
|
326435
|
+
const engineRootIsCheckout = existsSync28(
|
|
326436
|
+
join39(realEngineRoot, "packages", "editor", "package.json")
|
|
326437
|
+
);
|
|
326438
|
+
const projectIsInCheckout = absProject === realEngineRoot || absProject.startsWith(realEngineRoot + sep6);
|
|
326439
|
+
if (engineRootIsCheckout && projectIsInCheckout) return;
|
|
326440
|
+
if (existsSync28(join39(absProject, "node_modules"))) return;
|
|
326441
|
+
throw new Error(
|
|
326442
|
+
`Project dependencies are not installed in ${absProject}.
|
|
326443
|
+
Run \`npm install\` in that project, then run \`vgai edit\` again. vgai will not borrow React or editor packages from another checkout.`
|
|
326444
|
+
);
|
|
326445
|
+
}
|
|
326451
326446
|
async function launchEditor(projectPath, opts = {}) {
|
|
326452
326447
|
if (opts.noOpen === void 0 && process.env["VGAI_NO_OPEN"]) {
|
|
326453
326448
|
opts = { ...opts, noOpen: true };
|
|
@@ -326457,6 +326452,7 @@ async function launchEditor(projectPath, opts = {}) {
|
|
|
326457
326452
|
}
|
|
326458
326453
|
const absProject = canonicalPath(resolve20(projectPath));
|
|
326459
326454
|
discoverProject(absProject);
|
|
326455
|
+
assertEditorProjectInstalled(absProject);
|
|
326460
326456
|
const portRequest = resolveEditorPortRequest(
|
|
326461
326457
|
absProject,
|
|
326462
326458
|
opts.portOverride,
|
|
@@ -326795,50 +326791,6 @@ No vgai.project.json in ${absFolder}`
|
|
|
326795
326791
|
});
|
|
326796
326792
|
process.exit(code);
|
|
326797
326793
|
}
|
|
326798
|
-
async function runBundle(folderArg, opts) {
|
|
326799
|
-
const absFolder = resolve20(folderArg);
|
|
326800
|
-
if (!existsSync28(absFolder) || !statSync12(absFolder).isDirectory()) {
|
|
326801
|
-
console.error(
|
|
326802
|
-
`Usage: vgai bundle <folder> [--write] [--entry <path>] [--world <id>]
|
|
326803
|
-
Folder not found: ${absFolder}`
|
|
326804
|
-
);
|
|
326805
|
-
process.exit(2);
|
|
326806
|
-
}
|
|
326807
|
-
if (!hasManifest(absFolder)) {
|
|
326808
|
-
console.error(
|
|
326809
|
-
`Usage: vgai bundle <folder> [--write] [--entry <path>] [--world <id>]
|
|
326810
|
-
No vgai.project.json in ${absFolder}`
|
|
326811
|
-
);
|
|
326812
|
-
process.exit(2);
|
|
326813
|
-
}
|
|
326814
|
-
const runnerScript = join39(ENGINE_ROOT, "packages/editor/scripts/run-bundle.ts");
|
|
326815
|
-
if (!existsSync28(runnerScript)) {
|
|
326816
|
-
throw new Error(`Bundle runner not found at ${runnerScript}. Is the engine installed?`);
|
|
326817
|
-
}
|
|
326818
|
-
const childArgs = [
|
|
326819
|
-
"tsx",
|
|
326820
|
-
runnerScript,
|
|
326821
|
-
absFolder,
|
|
326822
|
-
...opts.write ? ["--write"] : [],
|
|
326823
|
-
...opts.entry !== void 0 ? ["--entry", opts.entry] : [],
|
|
326824
|
-
...opts.world !== void 0 ? ["--world", opts.world] : []
|
|
326825
|
-
];
|
|
326826
|
-
const code = await new Promise((resolvePromise) => {
|
|
326827
|
-
const child = spawn4("npx", childArgs, {
|
|
326828
|
-
cwd: ENGINE_ROOT,
|
|
326829
|
-
stdio: "inherit",
|
|
326830
|
-
shell: true
|
|
326831
|
-
});
|
|
326832
|
-
child.on("error", (err2) => {
|
|
326833
|
-
console.error(`Failed to start bundle runner: ${err2.message}`);
|
|
326834
|
-
resolvePromise(1);
|
|
326835
|
-
});
|
|
326836
|
-
child.on("close", (exitCode) => {
|
|
326837
|
-
resolvePromise(exitCode ?? 1);
|
|
326838
|
-
});
|
|
326839
|
-
});
|
|
326840
|
-
process.exit(code);
|
|
326841
|
-
}
|
|
326842
326794
|
var DOCTOR_USAGE = "Usage: vgai doctor <folder> [--json] [--port <n>] [--timeout <ms>]";
|
|
326843
326795
|
async function runDoctor(folderArg, opts) {
|
|
326844
326796
|
const absFolder = resolve20(folderArg);
|
|
@@ -327714,7 +327666,6 @@ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
327714
327666
|
"screenshot",
|
|
327715
327667
|
"eval",
|
|
327716
327668
|
"conformance",
|
|
327717
|
-
"bundle",
|
|
327718
327669
|
"doctor",
|
|
327719
327670
|
"render-cinematic",
|
|
327720
327671
|
"perf",
|
|
@@ -328212,6 +328163,10 @@ Unrecognized option or invalid project name: ${name}`);
|
|
|
328212
328163
|
throw new Error(`npm install exited with code ${exitCode ?? "unknown"}`);
|
|
328213
328164
|
cacheDependencies(targetDir);
|
|
328214
328165
|
}
|
|
328166
|
+
const repin = repinEngineAfterInstall(targetDir);
|
|
328167
|
+
if (repin) {
|
|
328168
|
+
console.log(`Engine pin updated ${repin.from} -> ${repin.to} (the project's installed @vgai/engine).`);
|
|
328169
|
+
}
|
|
328215
328170
|
} catch {
|
|
328216
328171
|
console.error("npm install failed. The editor was not started; fix the install and retry.");
|
|
328217
328172
|
process.exitCode = 1;
|
|
@@ -328324,7 +328279,7 @@ ${subcommand === "list" ? `Unknown option: ${unknown2[0]}` : `Unknown subcommand
|
|
|
328324
328279
|
console.log(`Usage: vgai validate [folder]
|
|
328325
328280
|
|
|
328326
328281
|
In-process: validate vgai.project.json, check every declared
|
|
328327
|
-
entry/
|
|
328282
|
+
entry/contractShim file exists, print the engine pin (default: cwd)
|
|
328328
328283
|
\u2014 no monorepo/editor/Vite needed beyond this checkout.
|
|
328329
328284
|
|
|
328330
328285
|
Exit codes: 0 valid, 1 invalid manifest/files/React roots/design states, 2 usage`);
|
|
@@ -328911,33 +328866,6 @@ Choose exactly one target: project, --port/--url, --all, or --everywhere.`
|
|
|
328911
328866
|
await runConformance(positional[0], jsonMode);
|
|
328912
328867
|
break;
|
|
328913
328868
|
}
|
|
328914
|
-
case "bundle": {
|
|
328915
|
-
if (hasHelpFlag(args)) {
|
|
328916
|
-
console.log("Usage: vgai bundle <folder> [--write] [--entry <path>] [--world <id>]");
|
|
328917
|
-
break;
|
|
328918
|
-
}
|
|
328919
|
-
const write = args.includes("--write");
|
|
328920
|
-
const entryIdx = args.indexOf("--entry");
|
|
328921
|
-
const entry = entryIdx >= 0 ? args[entryIdx + 1] : void 0;
|
|
328922
|
-
const worldIdx = args.indexOf("--world");
|
|
328923
|
-
const worldId = worldIdx >= 0 ? args[worldIdx + 1] : void 0;
|
|
328924
|
-
const positional = [];
|
|
328925
|
-
for (let i = 1; i < args.length; i++) {
|
|
328926
|
-
const a = args[i];
|
|
328927
|
-
if (a === "--write") continue;
|
|
328928
|
-
if (a === "--entry" || a === "--world") {
|
|
328929
|
-
i++;
|
|
328930
|
-
continue;
|
|
328931
|
-
}
|
|
328932
|
-
positional.push(a);
|
|
328933
|
-
}
|
|
328934
|
-
if (!positional[0]) {
|
|
328935
|
-
console.error("Usage: vgai bundle <folder> [--write] [--entry <path>] [--world <id>]");
|
|
328936
|
-
process.exit(2);
|
|
328937
|
-
}
|
|
328938
|
-
await runBundle(positional[0], { write, entry, world: worldId });
|
|
328939
|
-
break;
|
|
328940
|
-
}
|
|
328941
328869
|
case "doctor": {
|
|
328942
328870
|
if (hasHelpFlag(args)) {
|
|
328943
328871
|
console.log(DOCTOR_USAGE);
|
|
@@ -329435,6 +329363,7 @@ if (process.argv[1] && import.meta.url === pathToFileURL2(realpathOrSelf(process
|
|
|
329435
329363
|
export {
|
|
329436
329364
|
BRIDGE_SCREENSHOT_STALE,
|
|
329437
329365
|
HIDDEN_FRAME_NOTICE,
|
|
329366
|
+
assertEditorProjectInstalled,
|
|
329438
329367
|
authoringWarningsWarning,
|
|
329439
329368
|
autoAddCapabilityForTool,
|
|
329440
329369
|
autoLaunchEditorAfterCreate,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/cli",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.12",
|
|
6
6
|
"description": "Create, open, control, validate, and playtest VGAI game projects.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"game-engine",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@oclif/core": "^4.11.14",
|
|
42
|
-
"@vgai/editor": "0.5.
|
|
43
|
-
"@vgai/editor-sdk": "0.5.
|
|
44
|
-
"@vgai/engine": "0.5.
|
|
45
|
-
"@vgai/live": "0.5.
|
|
46
|
-
"@vgai/p2p-colyseus": "0.5.
|
|
47
|
-
"@vgai/sdk": "0.5.
|
|
42
|
+
"@vgai/editor": "0.5.12",
|
|
43
|
+
"@vgai/editor-sdk": "0.5.12",
|
|
44
|
+
"@vgai/engine": "0.5.12",
|
|
45
|
+
"@vgai/live": "0.5.12",
|
|
46
|
+
"@vgai/p2p-colyseus": "0.5.12",
|
|
47
|
+
"@vgai/sdk": "0.5.12",
|
|
48
48
|
"ink": "^7.1.0",
|
|
49
49
|
"playwright": "^1.58.2",
|
|
50
50
|
"react": "^19.2.4",
|