Add an offline Ix initializer through the real setup pipeline, supporting Basic and Advanced play, base factions, Ixians and Tleilaxu with the full 47-card deck and 22-card spice deck. Preserve all normal start and publication gates. Add a reusable local prototype starter: back up the named fresh ready lobby, initialize it once by exact version/state comparison and preserve seat/recovery tables and other rooms. Update the existing checklist with a separate prototype stage and document functional scope, source interpretations and later refinement. Six new tests cover all-profile private setup, exact typed starting forces, Face Dancer/treachery custody, JSON continuation, two fixed-seed complete games and local SQLite write/rejection boundaries. Independent review caught a missing JSON version update, now fixed and covered; focused checking fixed one test typing error before the stable broad check. No new rule interpretation was introduced. Validation: types, lint and 4,211 offline tests passed (123.237s); production build passed (6.543s); all 40 HTTP tests passed (23.578s). Source-bound report: 20260913-ix-prototype-final/report.json, fingerprint 3b8f295593bcb314bb72308d81739006b11d949d1e5906dbf6ce0704b15ebd72. Browser W5LE6VFB: human Ixian + Medium Tleilaxu + Hard Atreides from genuine setup, private starting-card refresh, Weather Control, mobile stronghold placement, then owned Brutal autopilot. Atreides won on turn 1; this short complete journey is not proof of every card or faction interaction. Finished private hand restored at phone width; expanded Poison Tooth was readable. Fixed-seed offline games 2026091301 (Basic) and 2026091302 (Advanced) both completed with both Ix factions. All 64 opening room versions/hashes are unchanged. One browser room and 30 HTTP rooms were added, totaling 95. Reused the running server; no restart or automation. Aggregate goal counters: 59,524,858 to 59,976,567 at completed verification, 451,709 tokens before final Git overhead. Two bounded workhorse helpers handled inventory/tests and independent review; one stable full check/build/HTTP run. Full game scope remains active and unfinished; future work prioritizes missing functional prototypes before exhaustive refinement and final acceptance.
75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
import { DatabaseSync } from 'node:sqlite';
|
|
import { writeFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { parseArgs } from 'node:util';
|
|
import { captureSavedGames } from './saved-game-verification';
|
|
import { startIxPrototypeRoom } from './prototype-room';
|
|
import { sourceSnapshot } from './verification';
|
|
|
|
async function main() {
|
|
const { values } = parseArgs({
|
|
options: {
|
|
db: { type: 'string' },
|
|
room: { type: 'string' },
|
|
version: { type: 'string' },
|
|
out: { type: 'string' },
|
|
help: { type: 'boolean' },
|
|
},
|
|
});
|
|
if (values.help) {
|
|
console.log(
|
|
'Usage: node --import tsx tools/start-prototype.ts --db PATH --room CODE --version NUMBER --out /private/new-directory\nStarts only a fresh ready Ix expansion lobby for local prototyping. Backs up all rooms first, preserves sessions and existing games, and rejects stale versions. Normal game-start and publication gates remain closed.',
|
|
);
|
|
return;
|
|
}
|
|
if (
|
|
!values.db ||
|
|
!values.room ||
|
|
!values.out ||
|
|
!/^\d+$/.test(values.version ?? '')
|
|
)
|
|
throw new Error(
|
|
'Provide --db, --room, --version and a new private --out directory.',
|
|
);
|
|
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
const version = Number(values.version),
|
|
source = sourceSnapshot(root);
|
|
const snapshot = await captureSavedGames(root, values.db, values.out, true);
|
|
if (
|
|
!snapshot.rooms.some(
|
|
(room) => room.code === values.room && room.version === version,
|
|
)
|
|
)
|
|
throw new Error('The requested lobby version is absent from the backup.');
|
|
const db = new DatabaseSync(values.db);
|
|
try {
|
|
const result = startIxPrototypeRoom(db, values.room, version);
|
|
writeFileSync(
|
|
resolve(values.out, 'prototype.json'),
|
|
JSON.stringify(
|
|
{
|
|
format: 1,
|
|
startedAt: new Date().toISOString(),
|
|
profile: 'ix',
|
|
source,
|
|
beforeVersion: version,
|
|
...result,
|
|
},
|
|
null,
|
|
2,
|
|
) + '\n',
|
|
{ flag: 'wx', mode: 0o600 },
|
|
);
|
|
console.log(JSON.stringify(result));
|
|
} finally {
|
|
db.close();
|
|
}
|
|
}
|
|
main().catch((error: unknown) => {
|
|
console.error(
|
|
error instanceof Error ? error.message : 'Prototype start failed.',
|
|
);
|
|
process.exitCode = 1;
|
|
});
|