@maka/maka-cli 5.9.0 → 5.10.0

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.
Files changed (33) hide show
  1. package/bundle/typescript/package.json +1 -1
  2. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +5 -0
  3. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
  4. package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +23 -1
  5. package/bundle/typescript/src/commands/game/sideQuest/game.js +160 -3
  6. package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
  7. package/bundle/typescript/src/commands/game/sideQuest/models/npc.d.ts +2 -0
  8. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +8 -0
  9. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
  10. package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +2 -0
  11. package/bundle/typescript/src/commands/game/sideQuest/models/player.js +8 -0
  12. package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
  13. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.d.ts +10 -0
  14. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js +10 -0
  15. package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js.map +1 -1
  16. package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +17 -0
  17. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +32 -0
  18. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
  19. package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +208 -0
  20. package/bundle/typescript/src/commands/game/sideQuest/types/save-file.js +14 -0
  21. package/bundle/typescript/src/commands/game/sideQuest/types/save-file.js.map +1 -0
  22. package/bundle/typescript/src/commands/game/sideQuest/ui.d.ts +6 -0
  23. package/bundle/typescript/src/commands/game/sideQuest/ui.js +48 -4
  24. package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
  25. package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.d.ts +50 -0
  26. package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js +232 -0
  27. package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js.map +1 -0
  28. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.d.ts +71 -0
  29. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +447 -0
  30. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -0
  31. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +174 -18
  32. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
  33. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.9.0",
3
+ "version": "5.10.0",
4
4
  "type": "module",
5
5
  "summary": "A command line tool for scaffolding Meteor 2.x applications using either React.",
6
6
  "description": "A command line tool for scaffolding Meteor 2.x applications using React.",
@@ -102,6 +102,11 @@ export class RestCommand extends Command {
102
102
  : hint(` (Rest again to keep recovering.)`));
103
103
  this.actor.performAction('rests', '');
104
104
  this.scene.updateStatus();
105
+ // A rest is a safe beat -- autosave (player ruling). requestSave's
106
+ // own guards keep mid-run and NPC rests from writing anything.
107
+ if (this.game && this.actor === this.scene.getPlayer()) {
108
+ this.game.requestSave('rest');
109
+ }
105
110
  return lines.join('\n');
106
111
  }
107
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rest.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/commands/rest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rest.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/commands/rest.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import blessed from 'blessed';
2
2
  import { ISceneSeedJson } from './types/seed/scene-seed.js';
3
3
  import { Item } from './models/item.js';
4
4
  import { Player, Inventory, Room, Scene } from './models/_index.js';
5
+ import { ISaveFileV1, SaveReason } from './types/save-file.js';
5
6
  import { ILifestyleTier } from './utilities/commerce.js';
6
7
  import { NPC } from './models/npc.js';
7
8
  import { AutoFight } from './utilities/auto-fight.js';
@@ -60,6 +61,10 @@ export default class Game {
60
61
  boundDevice?: Item;
61
62
  }[];
62
63
  private _pendingRedeploys;
64
+ private _saveFilePath?;
65
+ private _dead;
66
+ private _resume?;
67
+ private _hubSeed?;
63
68
  /**
64
69
  * The one correct runtime NPC spawn (mirrors scene-factory's seed
65
70
  * path): construct with a scene-bound registry, add to the scene
@@ -230,6 +235,23 @@ export default class Game {
230
235
  get metaBox(): blessed.Widgets.BoxElement;
231
236
  get inputBox(): blessed.Widgets.TextboxElement;
232
237
  init(options: IMainGameConfig, screen: blessed.Widgets.Screen): Promise<string>;
238
+ /**
239
+ * Everything a save restores beyond the seed synthesis: the player,
240
+ * the hub world overlay, and the Game-level ledgers. Ordering inside
241
+ * matters less than its POSITION in init(): after seedHomeTurfContacts
242
+ * and snapshotVendorStock (both deliberately pre-overlay).
243
+ */
244
+ private applyResumeState;
245
+ /**
246
+ * THE single save routine -- every safe beat funnels here. Guards make
247
+ * it a silent no-op anywhere a save would lie: mid-run (the "runs are
248
+ * disposable" ruling lives in the scene === _hubScene check), downed
249
+ * or KO'd, mid-exchange, dead, or before init finishes. Synchronous by
250
+ * design so the process-exit quit hook can use it; failures log and
251
+ * never crash a turn.
252
+ */
253
+ requestSave(reason: SaveReason): void;
254
+ private buildSaveFile;
233
255
  /**
234
256
  * Synchronous readiness check for continueToNextScene() -- lets callers
235
257
  * give instant feedback for the "not ready yet" cases (job not done, no
@@ -352,7 +374,7 @@ export default class Game {
352
374
  updateEquipment(_playerEquipment: PlayerEquipment): void;
353
375
  updateExits(_room: Room): void;
354
376
  updateInventory(_playerInventory: Inventory, _currencyName?: string): void;
355
- static getInstance(player: Player, sceneSeed: ISceneSeedJson): Promise<Game>;
377
+ static getInstance(player: Player, sceneSeed: ISceneSeedJson, resume?: ISaveFileV1): Promise<Game>;
356
378
  handleInput(input: string): Promise<string | null>;
357
379
  /**
358
380
  * The help taxonomy: every entry is [primary, ...aliases], grouped the
@@ -4,6 +4,9 @@ import { Category } from './types/shared/item-enum.js';
4
4
  import { Item } from './models/item.js';
5
5
  import { Room } from './models/_index.js';
6
6
  import { Door } from './models/door.js';
7
+ import { SAVE_VERSION } from './types/save-file.js';
8
+ import { serializePlayer, restorePlayer, captureHubOverlay, applyHubOverlay, writeSaveAtomic, deleteSave, } from './utilities/persistence.js';
9
+ import { pushSave, burnCloudSaveFor } from './utilities/cloud-saves.js';
7
10
  import { isFence, LIFESTYLE_TIERS } from './utilities/commerce.js';
8
11
  import { rollPool, formatRoll } from './utilities/dice.js';
9
12
  import { Direction } from './types/shared/direction-enum.js';
@@ -198,6 +201,13 @@ export default class Game {
198
201
  // Drones deployed at travel time re-shell on arrival ("the rotors spin
199
202
  // back up at the curb") -- tracked as their items across the swap.
200
203
  _pendingRedeploys = [];
204
+ // ---------------- PERSISTENCE (see utilities/persistence.ts) ----------
205
+ // Character + hub world survive the process (player rulings): autosave
206
+ // at safe beats only, one slot per character, PERMADEATH on real death.
207
+ _saveFilePath; // from options.saveFilePath; unset = never save
208
+ _dead = false; // set in close(); suppresses any later save
209
+ _resume; // present when this session continues a save
210
+ _hubSeed; // the seed embedded into every save
201
211
  /**
202
212
  * The one correct runtime NPC spawn (mirrors scene-factory's seed
203
213
  * path): construct with a scene-bound registry, add to the scene
@@ -849,6 +859,7 @@ export default class Game {
849
859
  async init(options, screen) {
850
860
  this._useAi = options.useAi;
851
861
  this._logFilePath = options.logFilePath;
862
+ this._saveFilePath = options.saveFilePath;
852
863
  this.initInputBox(screen);
853
864
  this.initLogBox(screen);
854
865
  this.initMetaBox(screen);
@@ -891,16 +902,24 @@ export default class Game {
891
902
  if (this.scene.isHub) {
892
903
  this._hubScene = this.scene;
893
904
  this._hubName = this.sceneSeed?.name ?? 'home';
905
+ // Every save embeds this seed -- resume never depends on the
906
+ // original scene file still existing or matching.
907
+ this._hubSeed = this.sceneSeed;
894
908
  // The street starts talking from minute one.
895
909
  this._rumorPool = this.sceneSeed?.rumors ?? [];
896
910
  this.advanceRumor();
897
911
  // The economy wakes up with it: shelf blueprints for restocking,
898
912
  // the first odd job on offer, and the lifestyle's edge perk.
913
+ // snapshotVendorStock deliberately runs BEFORE any resume overlay:
914
+ // the restock blueprint is the seed's PRISTINE shelves (config
915
+ // copies), and restockVendorShelves only refills what the overlay
916
+ // leaves empty.
899
917
  this.snapshotVendorStock();
900
918
  this._gigPool = this.sceneSeed?.gigs ?? [];
901
919
  this.advanceGig();
902
920
  this.player.lifestyleEdgeBonus = this.lifestyle.edgeBonus;
903
- // Home turf knows its own (see seedHomeTurfContacts).
921
+ // Home turf knows its own (see seedHomeTurfContacts). On resume the
922
+ // saved contacts overwrite these loyalty-1 seeds a few lines down.
904
923
  this.seedHomeTurfContacts();
905
924
  // The next run starts cooking the moment you're home (player
906
925
  // request): generation takes 20-40s, and waiting for the player
@@ -908,7 +927,9 @@ export default class Game {
908
927
  // Mr. Johnson's "1 new message" ping lands mid-session, and the
909
928
  // call finds work already waiting. The gate keeps this a no-op
910
929
  // with AI off or a draft/pending seed somehow already in flight.
911
- if (this.canDraftNextScene().allowed) {
930
+ // GATED on resume: a restored pendingRun must not be clobbered by
931
+ // a fresh background draft landing 20-40s into the session.
932
+ if (!this._resume && this.canDraftNextScene().allowed) {
912
933
  this.draftNextSceneInBackground();
913
934
  }
914
935
  }
@@ -922,7 +943,20 @@ export default class Game {
922
943
  // The banner learns where we are only after the hub/scene bookkeeping
923
944
  // above settles.
924
945
  this.refreshLogLabel();
946
+ // RESUME (see utilities/persistence.ts): lay the save over the
947
+ // freshly-synthesized hub -- player sheet/gear, hub world diffs,
948
+ // and the Game-level ledgers -- AFTER all the fresh-start seeding
949
+ // above, so the save is authoritative everywhere they overlap.
950
+ if (this._resume && this._hubScene) {
951
+ this.applyResumeState(this._resume);
952
+ }
925
953
  this.initialized = true;
954
+ if (this._resume) {
955
+ const pendingNote = this._pendingRunSeed
956
+ ? hint(`\n\n${FIXER_NAME}'s job is still on offer: "${this._pendingRunSeed.name}". "call taxi" when you're ready, or "call ${FIXER_NAME}" to hear it again.`)
957
+ : '';
958
+ return `Welcome back, ${this.player.name}. The cot remembers your shape.\n ${this.scene.story}${pendingNote}`;
959
+ }
926
960
  // Nudge the player toward "call" up front -- the fixer convention means
927
961
  // the story deliberately doesn't narrate a completed briefing, so
928
962
  // without this hint there'd be no in-game indication that "call" is how
@@ -933,6 +967,106 @@ export default class Game {
933
967
  : '';
934
968
  return `Welcome, ${this.player.name}\n ${this.scene.story}${callHint}`;
935
969
  }
970
+ /**
971
+ * Everything a save restores beyond the seed synthesis: the player,
972
+ * the hub world overlay, and the Game-level ledgers. Ordering inside
973
+ * matters less than its POSITION in init(): after seedHomeTurfContacts
974
+ * and snapshotVendorStock (both deliberately pre-overlay).
975
+ */
976
+ applyResumeState(save) {
977
+ restorePlayer(this.player, save.player);
978
+ applyHubOverlay(this.scene, save.hub, this.player, this._homeRoom);
979
+ this.lifestyleTier = save.game.lifestyleTier;
980
+ this.rentDebt = save.game.rentDebt;
981
+ this.syncHomeToLifestyle();
982
+ this.player.lifestyleEdgeBonus = this.lifestyle.edgeBonus;
983
+ this._tier = save.game.tier;
984
+ this.contacts = new Map(save.game.contacts);
985
+ this.fencedCategories = new Set(save.game.fencedCategories);
986
+ this._rumorIndex = save.game.rumorIndex;
987
+ this.activeRumor = save.game.activeRumor;
988
+ this._gigPool = [...save.game.gigPool];
989
+ this._gigIndex = save.game.gigIndex;
990
+ this.gigAvailable = save.game.gigAvailable;
991
+ this.activeGig = save.game.activeGig;
992
+ if (save.game.pendingRun) {
993
+ this._pendingRunSeed = save.game.pendingRun.seed;
994
+ this._pendingRunTier = save.game.pendingRun.tier;
995
+ this._pendingRide = save.game.pendingRun.ride;
996
+ }
997
+ this.player.currentLocation = this._homeRoom;
998
+ this.updateEquipment(this.player.equipment);
999
+ this.updateInventory(this.player.inventory, capitalCase(this.scene.getCurrencyType()));
1000
+ this.updateExits(this.player.currentLocation);
1001
+ this.updateStatus();
1002
+ this.refreshLogLabel();
1003
+ Logger.getInstance().write(`Resumed save for ${save.playerName} (saved ${save.savedAt}, reason ${save.reason}).`);
1004
+ }
1005
+ /**
1006
+ * THE single save routine -- every safe beat funnels here. Guards make
1007
+ * it a silent no-op anywhere a save would lie: mid-run (the "runs are
1008
+ * disposable" ruling lives in the scene === _hubScene check), downed
1009
+ * or KO'd, mid-exchange, dead, or before init finishes. Synchronous by
1010
+ * design so the process-exit quit hook can use it; failures log and
1011
+ * never crash a turn.
1012
+ */
1013
+ requestSave(reason) {
1014
+ const logger = Logger.getInstance();
1015
+ if (!this.initialized || this._dead || !this._saveFilePath)
1016
+ return;
1017
+ if (!this.hasHub || this.scene !== this._hubScene || !this._hubSeed)
1018
+ return;
1019
+ if (this.player.isDown() || this.player.isUnconscious())
1020
+ return;
1021
+ if (this.scene.isPlayerExchangeActive())
1022
+ return;
1023
+ try {
1024
+ const save = this.buildSaveFile(reason);
1025
+ writeSaveAtomic(this._saveFilePath, save);
1026
+ logger.write(`Saved (${reason}) -> ${this._saveFilePath}`);
1027
+ // Local-first: the beat is DONE the moment the file lands. The
1028
+ // cloud mirror rides behind, fire-and-forget (see cloud-saves.ts
1029
+ // -- logged-out/offline/expired all degrade to a silent no-op).
1030
+ void pushSave(this._saveFilePath, save);
1031
+ }
1032
+ catch (err) {
1033
+ logger.error(`requestSave(${reason}) failed: ${err}`);
1034
+ }
1035
+ }
1036
+ buildSaveFile(reason) {
1037
+ return {
1038
+ version: SAVE_VERSION,
1039
+ savedAt: new Date().toISOString(),
1040
+ reason,
1041
+ playerName: this.player.name,
1042
+ summary: {
1043
+ archetypeName: this.player.archetypeName,
1044
+ karma: this.player.karma,
1045
+ currency: this.player.currency,
1046
+ lifestyleTier: this.lifestyleTier,
1047
+ hubName: this._hubName,
1048
+ },
1049
+ hubSeed: this._hubSeed,
1050
+ player: serializePlayer(this.player),
1051
+ game: {
1052
+ lifestyleTier: this.lifestyleTier,
1053
+ rentDebt: this.rentDebt,
1054
+ tier: this._tier,
1055
+ contacts: [...this.contacts.entries()],
1056
+ fencedCategories: [...this.fencedCategories],
1057
+ rumorIndex: this._rumorIndex,
1058
+ activeRumor: this.activeRumor,
1059
+ gigPool: [...this._gigPool],
1060
+ gigIndex: this._gigIndex,
1061
+ gigAvailable: this.gigAvailable,
1062
+ activeGig: this.activeGig,
1063
+ pendingRun: this._pendingRunSeed && this._pendingRunTier !== undefined
1064
+ ? { seed: this._pendingRunSeed, tier: this._pendingRunTier, ride: this._pendingRide }
1065
+ : undefined,
1066
+ },
1067
+ hub: captureHubOverlay(this._hubScene, this._hubSeed, this.player, this._homeRoom),
1068
+ };
1069
+ }
936
1070
  /**
937
1071
  * Synchronous readiness check for continueToNextScene() -- lets callers
938
1072
  * give instant feedback for the "not ready yet" cases (job not done, no
@@ -1096,6 +1230,10 @@ export default class Game {
1096
1230
  // Drones spin back up beside the cot.
1097
1231
  const companionArrivalLines = this.unfoldCompanionsOnArrival();
1098
1232
  const companionBlock = [...companionFoldLines, ...companionArrivalLines];
1233
+ // The homecoming save: everything above (payout, rent, restock,
1234
+ // contacts reset) settled first, so the save reflects the hub as
1235
+ // the player will find it.
1236
+ this.requestSave('homecoming');
1099
1237
  const fateLine = wrappedRun
1100
1238
  ? `The run's wrapped and the street swallows you back up.`
1101
1239
  : `The run's behind you -- unfinished, unpaid, already someone else's problem. The street doesn't ask.`;
@@ -1282,6 +1420,9 @@ export default class Game {
1282
1420
  if (!seed || tier === undefined) {
1283
1421
  return `There's no job waiting. "call ${FIXER_NAME}" to drum one up.`;
1284
1422
  }
1423
+ // The departure save: hub state with the job still on offer -- what
1424
+ // a mid-run quit resumes to (the "runs are disposable" ruling).
1425
+ this.requestSave('job-accept');
1285
1426
  const haggledAtOffer = this.player.haggledThisJob;
1286
1427
  try {
1287
1428
  const banner = await this.activateRunScene(seed, tier, { startInHideout: false });
@@ -1300,6 +1441,21 @@ export default class Game {
1300
1441
  }
1301
1442
  }
1302
1443
  async close() {
1444
+ // PERMADEATH (player ruling): close() is reachable ONLY via
1445
+ // Scene.endGame(), and endGame fires ONLY on real death (combat
1446
+ // resolveDeath, street-decides knockout, drain burnout, ward
1447
+ // backlash, stim crash) -- so this IS the one death choke point.
1448
+ // The save burns with the body; _dead also suppresses the quit
1449
+ // hook's save on the way out. Keep that invariant: any future
1450
+ // non-death caller of close() must set a flag before this line.
1451
+ this._dead = true;
1452
+ if (this._saveFilePath) {
1453
+ deleteSave(this._saveFilePath);
1454
+ // The cloud copy burns too -- tombstone-first, so an offline death
1455
+ // can't be resurrected from the mirror (see cloud-saves.ts).
1456
+ burnCloudSaveFor(this._saveFilePath, this.player.name);
1457
+ Logger.getInstance().write(`Permadeath: save deleted (${this._saveFilePath}).`);
1458
+ }
1303
1459
  this.stopPursuitHeartbeat();
1304
1460
  this._inputBox.removeAllListeners(); // removes all event listeners
1305
1461
  this._inputBox.cancel(); // cancels any active input session
@@ -1691,9 +1847,10 @@ export default class Game {
1691
1847
  this.updateStatus();
1692
1848
  }
1693
1849
  // Public method to get the instance of the Game class
1694
- static async getInstance(player, sceneSeed) {
1850
+ static async getInstance(player, sceneSeed, resume) {
1695
1851
  if (!Game.instance) {
1696
1852
  Game.instance = new Game(player, sceneSeed);
1853
+ Game.instance._resume = resume;
1697
1854
  }
1698
1855
  return Game.instance;
1699
1856
  }