@bitmagic/cli 0.1.17 → 0.1.19
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 +47 -2
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/edit.d.ts +10 -0
- package/dist/commands/edit.js +142 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/upgrade.d.ts +10 -0
- package/dist/commands/upgrade.js +43 -0
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/editor/save.d.ts +57 -0
- package/dist/editor/save.js +144 -0
- package/dist/editor/save.js.map +1 -0
- package/dist/editor/server.d.ts +17 -0
- package/dist/editor/server.js +185 -0
- package/dist/editor/server.js.map +1 -0
- package/dist/editor/shell-page.d.ts +38 -0
- package/dist/editor/shell-page.js +339 -0
- package/dist/editor/shell-page.js.map +1 -0
- package/dist/project/context.d.ts +2 -0
- package/dist/project/context.js.map +1 -1
- package/dist/scaffold/agents-md.d.ts +51 -0
- package/dist/scaffold/agents-md.js +102 -0
- package/dist/scaffold/agents-md.js.map +1 -0
- package/dist/scaffold/project-files.d.ts +8 -0
- package/dist/scaffold/project-files.js +19 -2
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +6 -2
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/upgrade-project.d.ts +9 -2
- package/dist/scaffold/upgrade-project.js +16 -3
- package/dist/scaffold/upgrade-project.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ bitmagic publish # verify-gate, build, and ship — private by defa
|
|
|
35
35
|
| `bitmagic init [dir] [--template <id>] [--name <name>] [--idea "<pitch>"] [--env <env>] [--force]` | Scaffold a new project: mints a game, downloads the vendored engine, writes `AGENTS.md`, `GAME-DESIGN.md` and templates. `--idea` seeds the design doc's pitch. |
|
|
36
36
|
| `bitmagic check` | Typecheck (`tsc --noEmit`) against the vendored engine. Fast; does not prove the game runs. |
|
|
37
37
|
| `bitmagic dev [--port <port>]` | Build, then serve with `tsc --watch` + `vite`, default port 3010. |
|
|
38
|
+
| `bitmagic edit [--port <port>] [--editor-port <port>]` | Everything `dev` does, plus a visual scene editor at `http://localhost:3011/`: click an object, drag the gizmo, and the new transform is written to `src/work/world.json`. See **Editing the scene visually** below. |
|
|
38
39
|
| `bitmagic verify [--timeout <ms>]` | Build, boot the game in a headless browser, click the engine's Play button like a player would, and report what broke. A game without the button passes as long as gameplay starts by itself (auto-starting genres, custom start UIs); a run where gameplay never starts fails. `--timeout` is settle time in ms measured after gameplay starts, so the screenshot captures gameplay. Writes the artifacts the publish gate reads (see below). |
|
|
39
40
|
| `bitmagic build` | Bundle the game into one self-contained `.bitmagic/build/index.html`. Rarely needs to be run by hand — `publish` builds automatically when the project changed. |
|
|
40
41
|
| `bitmagic publish [--visibility public\|private] [--name <name>] [--description <desc>] [--force]` | Verify-gate, build if needed, and upload straight to GCS. **Private unless `--visibility public` is passed.** |
|
|
@@ -62,6 +63,7 @@ my-game/
|
|
|
62
63
|
.bitmagic/
|
|
63
64
|
cover.webp # bitmagic cover's artwork — the publish thumbnail when present
|
|
64
65
|
cover.json # its URL and the design hash it was generated from
|
|
66
|
+
AGENTS.md.latest # the current AGENTS.md template, when upgrade kept your edited one
|
|
65
67
|
build/
|
|
66
68
|
index.html # bitmagic build's output bundle
|
|
67
69
|
manifest.json # engineVersion, fingerprint, bytes, sha256, builtAt
|
|
@@ -87,6 +89,37 @@ Re-running on an unchanged design generates nothing and costs nothing — it rep
|
|
|
87
89
|
cover. Edit the design and run again, or pass `--force`, to replace it. Because it writes
|
|
88
90
|
`world.json`, it invalidates a passing verify: run it before `bitmagic verify`, not after.
|
|
89
91
|
|
|
92
|
+
## Editing the scene visually
|
|
93
|
+
|
|
94
|
+
Some things are faster with a mouse. `bitmagic edit` runs everything `bitmagic dev` runs and adds a
|
|
95
|
+
local editor on a second port:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
bitmagic edit
|
|
99
|
+
# Serving the game at http://localhost:3010/
|
|
100
|
+
# Editor ready at http://localhost:3011/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Open the editor URL in your normal browser. The game loads paused, with a free-flying camera, the
|
|
104
|
+
scene hierarchy and the transform gizmo — the same editor the web Creator uses, which already ships
|
|
105
|
+
inside `engine/`. Click an object to select it, then move, rotate, scale, snap it to the ground,
|
|
106
|
+
edit its numbers in the inspector, delete it, or right-click to add one from the project's assets.
|
|
107
|
+
|
|
108
|
+
**Every change is saved to `src/work/world.json` as you make it.** There is no Save button and no
|
|
109
|
+
unsaved state: your agent reads the same file, and `git diff` is the record of what you moved.
|
|
110
|
+
Saves are surgical — one entry per object touched, nothing else in the file is rewritten.
|
|
111
|
+
|
|
112
|
+
If your agent edits `world.json` while the editor is open, the editor says so and offers a reload
|
|
113
|
+
rather than silently reloading over work in progress.
|
|
114
|
+
|
|
115
|
+
Both ports must fall between 3000 and 3199. That is the window the asset CDN allows as an origin;
|
|
116
|
+
outside it the game loads with no terrain and no error.
|
|
117
|
+
|
|
118
|
+
What it does **not** do yet: terrain and voxel sculpting. Clicking the ground still opens the
|
|
119
|
+
engine's terrain tools, but saving them needs an asset upload this command does not perform, so the
|
|
120
|
+
editor warns you as soon as you change a voxel and offers to discard it. Use the web Creator for
|
|
121
|
+
terrain work.
|
|
122
|
+
|
|
90
123
|
## Publishing
|
|
91
124
|
|
|
92
125
|
`bitmagic publish` is two gated steps in one command:
|
|
@@ -142,8 +175,20 @@ invalidate the verify you just checked.
|
|
|
142
175
|
refuses to run against a dirty git working tree unless `--force`, so the upgrade always shows up as
|
|
143
176
|
its own reviewable diff.
|
|
144
177
|
|
|
145
|
-
What is yours and never touched: `src/`, `world.json`, `game.json`, `package.json`, `
|
|
146
|
-
`
|
|
178
|
+
What is yours and never touched: `src/`, `world.json`, `game.json`, `package.json`, `CLAUDE.md`,
|
|
179
|
+
`GAME-DESIGN.md`, `.gitignore`, and any skill you wrote yourself.
|
|
180
|
+
|
|
181
|
+
`AGENTS.md` is the one conditional case, and it can never lose your work. The CLI records a hash of
|
|
182
|
+
the `AGENTS.md` it writes. On a later upgrade:
|
|
183
|
+
|
|
184
|
+
- **Still byte-identical to what we wrote** — you never edited it, so refreshing it only replaces
|
|
185
|
+
our words with our newer ones. It is refreshed, and the output says so.
|
|
186
|
+
- **Edited by you (or scaffolded before this existed)** — it is left exactly as it is. The output
|
|
187
|
+
names the sections the current template has that yours does not, and writes the current template
|
|
188
|
+
to `.bitmagic/AGENTS.md.latest` so you (or your agent) can diff and merge the parts you want.
|
|
189
|
+
|
|
190
|
+
That is why `bitmagic cover` could ship and stay invisible: an agent only knows what its `AGENTS.md`
|
|
191
|
+
tells it, and nothing was updating that file.
|
|
147
192
|
|
|
148
193
|
The shipped skills are on the refreshed side deliberately. They describe what the **CLI** can do,
|
|
149
194
|
not what your game is, so a project holding the version that came with its scaffold has an agent
|
package/dist/cli.d.ts
CHANGED
|
@@ -95,6 +95,16 @@ declare const rawCommands: {
|
|
|
95
95
|
readonly description: "Port to serve on (default 3010).";
|
|
96
96
|
};
|
|
97
97
|
}>;
|
|
98
|
+
edit: CommandDef<{
|
|
99
|
+
readonly port: {
|
|
100
|
+
readonly type: "string";
|
|
101
|
+
readonly description: "Port to serve the game on (default 3010).";
|
|
102
|
+
};
|
|
103
|
+
readonly 'editor-port': {
|
|
104
|
+
readonly type: "string";
|
|
105
|
+
readonly description: "Port to serve the editor on (default 3011).";
|
|
106
|
+
};
|
|
107
|
+
}>;
|
|
98
108
|
verify: CommandDef<{
|
|
99
109
|
readonly timeout: {
|
|
100
110
|
readonly type: "string";
|
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ import { initCommand } from './commands/init.js';
|
|
|
8
8
|
import { upgradeCommand } from './commands/upgrade.js';
|
|
9
9
|
import { checkCommand } from './commands/check.js';
|
|
10
10
|
import { devCommand } from './commands/dev.js';
|
|
11
|
+
import { editCommand } from './commands/edit.js';
|
|
11
12
|
import { verifyCommand } from './commands/verify.js';
|
|
12
13
|
import { buildCommand } from './commands/build.js';
|
|
13
14
|
import { generateCommand } from './commands/generate.js';
|
|
@@ -102,6 +103,7 @@ const rawCommands = {
|
|
|
102
103
|
upgrade: upgradeCommand,
|
|
103
104
|
check: checkCommand,
|
|
104
105
|
dev: devCommand,
|
|
106
|
+
edit: editCommand,
|
|
105
107
|
verify: verifyCommand,
|
|
106
108
|
build: buildCommand,
|
|
107
109
|
generate: generateCommand,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const editCommand: import("citty").CommandDef<{
|
|
2
|
+
readonly port: {
|
|
3
|
+
readonly type: "string";
|
|
4
|
+
readonly description: "Port to serve the game on (default 3010).";
|
|
5
|
+
};
|
|
6
|
+
readonly 'editor-port': {
|
|
7
|
+
readonly type: "string";
|
|
8
|
+
readonly description: "Port to serve the editor on (default 3011).";
|
|
9
|
+
};
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bitmagic edit` — `dev` plus a visual scene editor.
|
|
3
|
+
*
|
|
4
|
+
* Everything `dev` does (build, `tsc --watch`, vite) plus a loopback sidecar that serves the editor
|
|
5
|
+
* shell and writes scene edits into `src/work/world.json`. Deliberately a superset rather than a
|
|
6
|
+
* flag on `dev`: `dev` is the plain run-the-game loop and must stay offline, minimal and boring,
|
|
7
|
+
* while `edit` opens a second port and a write path into the creator's project.
|
|
8
|
+
*/
|
|
9
|
+
import { defineCommand } from 'citty';
|
|
10
|
+
import { spawn, spawnSync } from 'child_process';
|
|
11
|
+
import { CliError } from '../errors.js';
|
|
12
|
+
import { loadProjectContext, projectBin } from '../project/context.js';
|
|
13
|
+
import { startEditorServer } from '../editor/server.js';
|
|
14
|
+
import { CORS_ALLOWED_PORT_MAX, CORS_ALLOWED_PORT_MIN } from '../local-port.js';
|
|
15
|
+
import { waitForServer } from '../verify/wait-for-server.js';
|
|
16
|
+
const DEFAULT_GAME_PORT = 3010;
|
|
17
|
+
const DEFAULT_EDITOR_PORT = 3011;
|
|
18
|
+
/**
|
|
19
|
+
* Both ports must sit inside the CDN's CORS window.
|
|
20
|
+
*
|
|
21
|
+
* The game port for the reason `local-port.ts` documents at length: a project fetches its forged
|
|
22
|
+
* level and its GLBs cross-origin from the portal CDN, which allowlists `localhost:3000`-`3199`
|
|
23
|
+
* and nothing else. Outside it the fetch is blocked, the world loads with no terrain, and the
|
|
24
|
+
* symptom reads as a broken game rather than a blocked request.
|
|
25
|
+
*
|
|
26
|
+
* The editor port is checked too, even though the shell itself fetches nothing from the CDN,
|
|
27
|
+
* because the two are adjacent by default and a creator who moves one will move the other — being
|
|
28
|
+
* told the rule once, at the point of the mistake, beats discovering it as a terrain-less world.
|
|
29
|
+
*/
|
|
30
|
+
function parsePort(value, fallback, flag) {
|
|
31
|
+
if (value === undefined)
|
|
32
|
+
return fallback;
|
|
33
|
+
const port = Number(value);
|
|
34
|
+
if (!Number.isInteger(port)) {
|
|
35
|
+
throw new CliError(`\`${flag}\` must be a whole number, got "${value}".`);
|
|
36
|
+
}
|
|
37
|
+
if (port < CORS_ALLOWED_PORT_MIN || port > CORS_ALLOWED_PORT_MAX) {
|
|
38
|
+
throw new CliError(`\`${flag}\` must be between ${CORS_ALLOWED_PORT_MIN} and ${CORS_ALLOWED_PORT_MAX}. `
|
|
39
|
+
+ 'The asset CDN only allows those origins; outside that window the game loads with no terrain.');
|
|
40
|
+
}
|
|
41
|
+
return port;
|
|
42
|
+
}
|
|
43
|
+
export const editCommand = defineCommand({
|
|
44
|
+
meta: {
|
|
45
|
+
name: 'edit',
|
|
46
|
+
description: 'Serve the game with a visual scene editor, saving edits to world.json.',
|
|
47
|
+
},
|
|
48
|
+
args: {
|
|
49
|
+
port: { type: 'string', description: `Port to serve the game on (default ${DEFAULT_GAME_PORT}).` },
|
|
50
|
+
'editor-port': { type: 'string', description: `Port to serve the editor on (default ${DEFAULT_EDITOR_PORT}).` },
|
|
51
|
+
},
|
|
52
|
+
async run({ args }) {
|
|
53
|
+
const context = loadProjectContext();
|
|
54
|
+
const tsc = projectBin(context.root, 'tsc');
|
|
55
|
+
const vite = projectBin(context.root, 'vite');
|
|
56
|
+
const gamePort = parsePort(args.port, DEFAULT_GAME_PORT, '--port');
|
|
57
|
+
const editorPort = parsePort(args['editor-port'], DEFAULT_EDITOR_PORT, '--editor-port');
|
|
58
|
+
if (gamePort === editorPort) {
|
|
59
|
+
throw new CliError('`--port` and `--editor-port` must differ — the game and the editor are two servers.');
|
|
60
|
+
}
|
|
61
|
+
// Build to completion first, exactly as `dev` does: every alias resolves into dist/, so serving
|
|
62
|
+
// before the first emit 404s every module.
|
|
63
|
+
console.log('Building…');
|
|
64
|
+
const build = spawnSync(tsc, [], { cwd: context.root, stdio: 'inherit' });
|
|
65
|
+
if (build.error) {
|
|
66
|
+
throw new CliError(`Could not run the TypeScript compiler: ${build.error.message}`);
|
|
67
|
+
}
|
|
68
|
+
if (build.status !== 0) {
|
|
69
|
+
throw new CliError('Build failed. Fix the errors above, then run `bitmagic edit` again.', build.status ?? 1);
|
|
70
|
+
}
|
|
71
|
+
// Before the children, so a port clash fails fast rather than after vite has claimed its port.
|
|
72
|
+
const editor = await startEditorServer({
|
|
73
|
+
root: context.root,
|
|
74
|
+
gameId: context.metadata.gameId,
|
|
75
|
+
gamePort,
|
|
76
|
+
port: editorPort,
|
|
77
|
+
log: (message) => console.log(message),
|
|
78
|
+
});
|
|
79
|
+
const children = [
|
|
80
|
+
{
|
|
81
|
+
name: 'tsc --watch',
|
|
82
|
+
process: spawn(tsc, ['--watch', '--preserveWatchOutput'], { cwd: context.root, stdio: 'inherit' }),
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'vite',
|
|
86
|
+
process: spawn(vite, ['--port', String(gamePort), '--strictPort'], { cwd: context.root, stdio: 'inherit' }),
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
let shuttingDown = false;
|
|
90
|
+
let requestedByUser = false;
|
|
91
|
+
const shutdown = () => {
|
|
92
|
+
if (shuttingDown)
|
|
93
|
+
return;
|
|
94
|
+
shuttingDown = true;
|
|
95
|
+
for (const child of children)
|
|
96
|
+
child.process.kill('SIGTERM');
|
|
97
|
+
void editor.close();
|
|
98
|
+
};
|
|
99
|
+
process.on('SIGINT', () => {
|
|
100
|
+
requestedByUser = true;
|
|
101
|
+
shutdown();
|
|
102
|
+
});
|
|
103
|
+
process.on('SIGTERM', () => {
|
|
104
|
+
requestedByUser = true;
|
|
105
|
+
shutdown();
|
|
106
|
+
});
|
|
107
|
+
void waitForServer(gamePort, 30_000)
|
|
108
|
+
.then(() => {
|
|
109
|
+
console.log(`\nServing the game at ${`http://localhost:${gamePort}/`}`);
|
|
110
|
+
console.log(`Editor ready at ${editor.url}`);
|
|
111
|
+
console.log('\nOpen the editor URL, click an object and drag the gizmo.');
|
|
112
|
+
console.log('Every change is saved to src/work/world.json.');
|
|
113
|
+
})
|
|
114
|
+
.catch(() => {
|
|
115
|
+
// The child-exit watcher below reports a vite that never comes up.
|
|
116
|
+
});
|
|
117
|
+
const failure = await new Promise((resolve) => {
|
|
118
|
+
let exitedCount = 0;
|
|
119
|
+
for (const child of children) {
|
|
120
|
+
child.process.on('error', (error) => {
|
|
121
|
+
shutdown();
|
|
122
|
+
resolve({ name: child.name, detail: `could not start: ${error.message}` });
|
|
123
|
+
});
|
|
124
|
+
child.process.on('exit', (code, signal) => {
|
|
125
|
+
exitedCount += 1;
|
|
126
|
+
if (!requestedByUser && !shuttingDown) {
|
|
127
|
+
shutdown();
|
|
128
|
+
resolve({ name: child.name, detail: `exited with code ${code}${signal ? ` (signal ${signal})` : ''}` });
|
|
129
|
+
}
|
|
130
|
+
else if (exitedCount === children.length) {
|
|
131
|
+
resolve(undefined);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
await editor.close();
|
|
137
|
+
if (failure) {
|
|
138
|
+
throw new CliError(`${failure.name} ${failure.detail}. \`bitmagic edit\` stopped.`);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/commands/edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Output } from '../output.js';
|
|
2
|
+
import type { AgentsMdOutcome } from '../scaffold/agents-md.js';
|
|
2
3
|
import { type DependencyMismatch } from '../scaffold/dependency-diff.js';
|
|
3
4
|
export interface GitStatus {
|
|
4
5
|
dirty: boolean;
|
|
@@ -26,6 +27,15 @@ export declare function assertCleanTree(status: GitStatus, force: boolean): void
|
|
|
26
27
|
* calling this proves the printed line actually uses them.
|
|
27
28
|
*/
|
|
28
29
|
export declare function printDependencyReport(output: Output, root: string): DependencyMismatch[];
|
|
30
|
+
/**
|
|
31
|
+
* Say what became of AGENTS.md, and — when it was kept — what the current template has that it
|
|
32
|
+
* does not.
|
|
33
|
+
*
|
|
34
|
+
* Only `kept` is worth more than a line. `current` says nothing at all: reporting "unchanged" on
|
|
35
|
+
* every upgrade of every project is the kind of output people stop reading, which costs the
|
|
36
|
+
* messages that do matter.
|
|
37
|
+
*/
|
|
38
|
+
export declare function reportAgentsMd(output: Output, outcome: AgentsMdOutcome): void;
|
|
29
39
|
/**
|
|
30
40
|
* Tell a project scaffolded before GAME-DESIGN.md existed that it is missing one, and return
|
|
31
41
|
* whether it was.
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -109,6 +109,41 @@ export function printDependencyReport(output, root) {
|
|
|
109
109
|
}
|
|
110
110
|
return mismatches;
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Say what became of AGENTS.md, and — when it was kept — what the current template has that it
|
|
114
|
+
* does not.
|
|
115
|
+
*
|
|
116
|
+
* Only `kept` is worth more than a line. `current` says nothing at all: reporting "unchanged" on
|
|
117
|
+
* every upgrade of every project is the kind of output people stop reading, which costs the
|
|
118
|
+
* messages that do matter.
|
|
119
|
+
*/
|
|
120
|
+
export function reportAgentsMd(output, outcome) {
|
|
121
|
+
if (outcome.action === 'current')
|
|
122
|
+
return;
|
|
123
|
+
output.info('');
|
|
124
|
+
if (outcome.action === 'rewritten') {
|
|
125
|
+
output.info('Refreshed AGENTS.md — it was still exactly as the CLI last wrote it, so nothing was lost.');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (outcome.action === 'created') {
|
|
129
|
+
output.info('Wrote AGENTS.md — this project had none.');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
output.info('AGENTS.md has your edits, so it was left alone.');
|
|
133
|
+
if (outcome.missingSections.length > 0) {
|
|
134
|
+
output.info(` It is missing ${outcome.missingSections.length} section${outcome.missingSections.length === 1 ? '' : 's'} the current template has:`);
|
|
135
|
+
for (const heading of outcome.missingSections) {
|
|
136
|
+
output.info(` - ${heading}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
output.info(' It has every section the current template has, but the wording has moved on.');
|
|
141
|
+
}
|
|
142
|
+
if (outcome.templatePath !== undefined) {
|
|
143
|
+
output.info(` Current template: ${outcome.templatePath}`);
|
|
144
|
+
output.info(' Diff it against your AGENTS.md and merge what you want to keep.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
112
147
|
/**
|
|
113
148
|
* Tell a project scaffolded before GAME-DESIGN.md existed that it is missing one, and return
|
|
114
149
|
* whether it was.
|
|
@@ -197,6 +232,7 @@ export const upgradeCommand = defineCommand({
|
|
|
197
232
|
output.info(` ${file}`);
|
|
198
233
|
}
|
|
199
234
|
const mismatches = printDependencyReport(output, context.root);
|
|
235
|
+
reportAgentsMd(output, result.agentsMd);
|
|
200
236
|
const needsDesignDoc = reportMissingDesignDoc(output, context.root);
|
|
201
237
|
output.result({
|
|
202
238
|
ok: true,
|
|
@@ -209,6 +245,13 @@ export const upgradeCommand = defineCommand({
|
|
|
209
245
|
// True for projects scaffolded before GAME-DESIGN.md existed: `bitmagic cover` has nothing
|
|
210
246
|
// to read until one is written.
|
|
211
247
|
missingDesignDoc: needsDesignDoc,
|
|
248
|
+
// Enough for an agent to act without parsing prose: whether its own guidance was refreshed,
|
|
249
|
+
// which sections it is behind on, and the file to diff against.
|
|
250
|
+
agentsMd: {
|
|
251
|
+
action: result.agentsMd.action,
|
|
252
|
+
missingSections: result.agentsMd.missingSections,
|
|
253
|
+
templatePath: result.agentsMd.templatePath ?? null,
|
|
254
|
+
},
|
|
212
255
|
});
|
|
213
256
|
}
|
|
214
257
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,YAAY,EAAe,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACvG,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn the game engine's own scene-editing replies into a `WorldJsonModification[]`.
|
|
3
|
+
*
|
|
4
|
+
* This is the CLI lane's counterpart to the Creator's `useSave.ts saveSceneModifications` and the
|
|
5
|
+
* spawn-point/world-config half of `useTabSwitching.ts deactivateScene`. The web lane posts its
|
|
6
|
+
* modifications to `POST /api/edit-world-config`, which rebuilds `predicateField`/`predicateValue`
|
|
7
|
+
* into real predicates server-side because functions cannot cross HTTP. Here there is no server:
|
|
8
|
+
* the shell page posts the engine's replies VERBATIM to the local sidecar, and this module — which
|
|
9
|
+
* runs in Node, in the same process that writes the file — builds the predicates directly.
|
|
10
|
+
*
|
|
11
|
+
* That split is deliberate. Everything that knows what world.json means lives on this side, so it
|
|
12
|
+
* is plain, synchronous, dependency-free code that can be unit-tested without a browser; the shell
|
|
13
|
+
* stays a dumb relay of `SCENE_HAS_CHANGES` and `SCENE_EDITING_STATUS`.
|
|
14
|
+
*/
|
|
15
|
+
import type { WorldJsonModification, WorldJsonShape } from '@bitmagic/world-forger/pipeline/index.js';
|
|
16
|
+
/** The engine's `SCENE_HAS_CHANGES` reply (`CreatorMessageHandler.ts`, `CHECK_SCENE_CHANGES`). */
|
|
17
|
+
export interface SceneChangeReport {
|
|
18
|
+
hasChanges?: boolean;
|
|
19
|
+
modifiedObjectIds?: string[];
|
|
20
|
+
deletedObjectIds?: string[];
|
|
21
|
+
fullSaveNeeded?: boolean;
|
|
22
|
+
pendingWorldConfig?: {
|
|
23
|
+
settings: unknown;
|
|
24
|
+
path: string[];
|
|
25
|
+
title?: string;
|
|
26
|
+
} | null;
|
|
27
|
+
pendingSpawnPoints?: Array<Record<string, unknown>> | null;
|
|
28
|
+
}
|
|
29
|
+
/** The engine's `SCENE_EDITING_STATUS` reply (`CreatorMessageHandler.ts`, line ~1463). */
|
|
30
|
+
export interface SceneEditingStatus {
|
|
31
|
+
unlocked?: boolean;
|
|
32
|
+
environmentObjects?: Array<Record<string, unknown>>;
|
|
33
|
+
/**
|
|
34
|
+
* WHICH level `environmentObjects` covers. `serializeEnvironmentObjects()` walks the LIVE scene
|
|
35
|
+
* and a multi-level game only instantiates one level, so a non-null id means the array is this
|
|
36
|
+
* level plus untagged globals — never the whole world. `null` (single-level or legacy) means it
|
|
37
|
+
* genuinely is the whole world.
|
|
38
|
+
*/
|
|
39
|
+
activeLevelId?: string | null;
|
|
40
|
+
markers?: Array<Record<string, unknown>>;
|
|
41
|
+
}
|
|
42
|
+
/** What the shell POSTs to `/api/scene/save`. Just the two engine replies, plus one flag. */
|
|
43
|
+
export interface ScenePayload {
|
|
44
|
+
changes: SceneChangeReport;
|
|
45
|
+
status: SceneEditingStatus;
|
|
46
|
+
/** Set by the shell when the engine posted `ADD_MARKER` / `UPDATE_MARKER` since the last save. */
|
|
47
|
+
markersDirty?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build the write for one scene-editing flush. Returns `[]` when there is nothing to persist, so
|
|
51
|
+
* the caller can skip the file write entirely.
|
|
52
|
+
*
|
|
53
|
+
* `world` is the CURRENT parsed world.json, needed only to resolve the levels registry. Everything
|
|
54
|
+
* else comes from the engine, which is the source of truth for scene state — this never invents a
|
|
55
|
+
* position, rotation or scale.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildSceneModifications(payload: ScenePayload, world: WorldJsonShape): WorldJsonModification[];
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `EditorManager.markFullSaveNeeded()` pushes this sentinel into the same `Set` that holds real
|
|
3
|
+
* object ids, so it arrives in `modifiedObjectIds` and must be filtered out before any id is
|
|
4
|
+
* matched against an object. `fullSaveNeeded` carries the actual signal.
|
|
5
|
+
*/
|
|
6
|
+
const FULL_SAVE_SENTINEL = '__FULL_SAVE__';
|
|
7
|
+
/** Spawn markers are tracked in the same modified-id set but persist through `pendingSpawnPoints`. */
|
|
8
|
+
const SPAWN_ID_PREFIX = 'spawn_';
|
|
9
|
+
function isRecord(value) {
|
|
10
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
/** Match an array item by its `id`, the predicate every environmentObjects write uses. */
|
|
13
|
+
function byId(id) {
|
|
14
|
+
return (item) => isRecord(item) && item.id === id;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The spawn-point half, mirroring `useTabSwitching.ts deactivateScene` lines 234-303.
|
|
18
|
+
*
|
|
19
|
+
* The rule that matters: in a levels game the spawns belong to the ACTIVE level's entry, and the
|
|
20
|
+
* flat `spawnPoints` / `playerSpawn*` fields are only mirrored when that level is the start level.
|
|
21
|
+
* Published games carry frozen template code that reads only the flat fields, so the mirror cannot
|
|
22
|
+
* be dropped — but writing it from a non-start level would make the wrong level's spawn the one
|
|
23
|
+
* every published build uses.
|
|
24
|
+
*/
|
|
25
|
+
function spawnPointModifications(spawnPoints, activeLevelId, world) {
|
|
26
|
+
const player = spawnPoints.find((point) => point.type === 'player');
|
|
27
|
+
const globals = [
|
|
28
|
+
{ type: 'set', path: ['spawnPoints'], value: spawnPoints },
|
|
29
|
+
];
|
|
30
|
+
if (player?.position !== undefined) {
|
|
31
|
+
globals.push({ type: 'set', path: ['playerSpawnPosition'], value: player.position });
|
|
32
|
+
}
|
|
33
|
+
// Only when present: writing `undefined` would drop the key on stringify for a game that had a
|
|
34
|
+
// rotation before, silently resetting the player's facing.
|
|
35
|
+
if (player?.rotationY !== undefined) {
|
|
36
|
+
globals.push({ type: 'set', path: ['playerSpawnRotationY'], value: player.rotationY });
|
|
37
|
+
}
|
|
38
|
+
const levels = world.worldProfileData?.levels ?? [];
|
|
39
|
+
if (levels.length === 0)
|
|
40
|
+
return globals;
|
|
41
|
+
const firstLevel = levels[0];
|
|
42
|
+
if (firstLevel === undefined)
|
|
43
|
+
return globals;
|
|
44
|
+
const startLevelId = world.worldProfileData?.startLevelId ?? firstLevel.id;
|
|
45
|
+
const targetId = activeLevelId ?? startLevelId;
|
|
46
|
+
const level = levels.find((entry) => entry.id === targetId);
|
|
47
|
+
// No matching entry means the engine reported a level this world.json does not know about.
|
|
48
|
+
// Falling back to the globals keeps the edit rather than dropping it on the floor.
|
|
49
|
+
if (level === undefined)
|
|
50
|
+
return globals;
|
|
51
|
+
const levelModification = {
|
|
52
|
+
type: 'update',
|
|
53
|
+
path: ['levels'],
|
|
54
|
+
predicate: (item) => isRecord(item) && item.id === level.id,
|
|
55
|
+
// An updater rather than a `{ ...level, spawnPoints }` snapshot (which is what the Creator
|
|
56
|
+
// builds): the snapshot was read before the write and would silently revert any other field
|
|
57
|
+
// the agent changed on this level in between.
|
|
58
|
+
value: (item) => ({ ...(isRecord(item) ? item : {}), spawnPoints }),
|
|
59
|
+
};
|
|
60
|
+
return level.id === startLevelId ? [levelModification, ...globals] : [levelModification];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the write for one scene-editing flush. Returns `[]` when there is nothing to persist, so
|
|
64
|
+
* the caller can skip the file write entirely.
|
|
65
|
+
*
|
|
66
|
+
* `world` is the CURRENT parsed world.json, needed only to resolve the levels registry. Everything
|
|
67
|
+
* else comes from the engine, which is the source of truth for scene state — this never invents a
|
|
68
|
+
* position, rotation or scale.
|
|
69
|
+
*/
|
|
70
|
+
export function buildSceneModifications(payload, world) {
|
|
71
|
+
const { changes, status } = payload;
|
|
72
|
+
const environmentObjects = status.environmentObjects ?? [];
|
|
73
|
+
const activeLevelId = status.activeLevelId ?? null;
|
|
74
|
+
const deletedObjectIds = changes.deletedObjectIds ?? [];
|
|
75
|
+
const modifiedObjectIds = (changes.modifiedObjectIds ?? []).filter((id) => id !== FULL_SAVE_SENTINEL && !id.startsWith(SPAWN_ID_PREFIX));
|
|
76
|
+
const modifications = [];
|
|
77
|
+
// Deletions first: order is the contract for `applyModificationsToWorld`, and an id that is both
|
|
78
|
+
// deleted and re-added in the same flush must end up added.
|
|
79
|
+
for (const id of deletedObjectIds) {
|
|
80
|
+
modifications.push({
|
|
81
|
+
type: 'removeRoot',
|
|
82
|
+
path: ['environmentObjects'],
|
|
83
|
+
predicate: byId(id),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (changes.fullSaveNeeded === true) {
|
|
87
|
+
if (activeLevelId === null) {
|
|
88
|
+
// The array genuinely is the whole world, so replacing it wholesale is safe — and it is the
|
|
89
|
+
// only form that can DROP an object the engine no longer has but never reported deleting.
|
|
90
|
+
modifications.push({
|
|
91
|
+
type: 'setRoot',
|
|
92
|
+
path: ['environmentObjects'],
|
|
93
|
+
value: environmentObjects,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Deliberate divergence from the Creator, which issues a `setRoot` here. In a levels game the
|
|
98
|
+
// array holds only the active level plus globals, so a `setRoot` deletes every other level's
|
|
99
|
+
// scenery. Upserting each object writes exactly what the engine reported and touches nothing
|
|
100
|
+
// else.
|
|
101
|
+
for (const object of environmentObjects) {
|
|
102
|
+
const id = object.id;
|
|
103
|
+
if (typeof id !== 'string')
|
|
104
|
+
continue;
|
|
105
|
+
modifications.push({
|
|
106
|
+
type: 'upsertRoot',
|
|
107
|
+
path: ['environmentObjects'],
|
|
108
|
+
predicate: byId(id),
|
|
109
|
+
value: object,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const modifiedIds = new Set(modifiedObjectIds);
|
|
116
|
+
for (const object of environmentObjects) {
|
|
117
|
+
const id = object.id;
|
|
118
|
+
if (typeof id !== 'string' || !modifiedIds.has(id))
|
|
119
|
+
continue;
|
|
120
|
+
modifications.push({
|
|
121
|
+
type: 'upsertRoot',
|
|
122
|
+
path: ['environmentObjects'],
|
|
123
|
+
predicate: byId(id),
|
|
124
|
+
value: object,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (changes.pendingWorldConfig) {
|
|
129
|
+
const { path, settings } = changes.pendingWorldConfig;
|
|
130
|
+
if (Array.isArray(path) && path.length > 0) {
|
|
131
|
+
modifications.push({ type: 'set', path, value: settings });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (changes.pendingSpawnPoints && changes.pendingSpawnPoints.length > 0) {
|
|
135
|
+
modifications.push(...spawnPointModifications(changes.pendingSpawnPoints, activeLevelId, world));
|
|
136
|
+
}
|
|
137
|
+
if (payload.markersDirty === true) {
|
|
138
|
+
// Whole-array `set` rather than push/update: `SCENE_EDITING_STATUS` returns the live
|
|
139
|
+
// `markerSystem.serializeMarkers()` output, which already reflects adds, edits and removals.
|
|
140
|
+
modifications.push({ type: 'set', path: ['markers'], value: status.markers ?? [] });
|
|
141
|
+
}
|
|
142
|
+
return modifications;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=save.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../src/editor/save.ts"],"names":[],"mappings":"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"}
|