@maka/maka-cli 5.87.0 → 5.89.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 (39) hide show
  1. package/bundle/typescript/package.json +1 -4
  2. package/bundle/typescript/src/commands/game/sideQuest/commands/move.d.ts +76 -5
  3. package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +162 -11
  4. package/bundle/typescript/src/commands/game/sideQuest/commands/move.js.map +1 -1
  5. package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +71 -1
  6. package/bundle/typescript/src/commands/game/sideQuest/game.js +106 -17
  7. package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
  8. package/bundle/typescript/src/commands/game/sideQuest/headless.js +34 -0
  9. package/bundle/typescript/src/commands/game/sideQuest/headless.js.map +1 -1
  10. package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +46 -0
  11. package/bundle/typescript/src/commands/game/sideQuest/models/player.js +81 -1
  12. package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
  13. package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js +8 -0
  14. package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js.map +1 -1
  15. package/bundle/typescript/src/commands/game/sideQuest/utilities/bystander.js +2 -12
  16. package/bundle/typescript/src/commands/game/sideQuest/utilities/bystander.js.map +1 -1
  17. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +13 -0
  18. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
  19. package/bundle/typescript/src/commands/game/sideQuest/utilities/ephemeral.d.ts +73 -0
  20. package/bundle/typescript/src/commands/game/sideQuest/utilities/ephemeral.js +210 -1
  21. package/bundle/typescript/src/commands/game/sideQuest/utilities/ephemeral.js.map +1 -1
  22. package/bundle/typescript/src/commands/game/sideQuest/utilities/room-view.d.ts +0 -31
  23. package/bundle/typescript/src/commands/game/sideQuest/utilities/room-view.js +21 -75
  24. package/bundle/typescript/src/commands/game/sideQuest/utilities/room-view.js.map +1 -1
  25. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.d.ts +22 -0
  26. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.js +69 -2
  27. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.js.map +1 -1
  28. package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.d.ts +19 -2
  29. package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js +29 -6
  30. package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js.map +1 -1
  31. package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.d.ts +47 -3
  32. package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +121 -17
  33. package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js.map +1 -1
  34. package/bundle/typescript/src/commands/game/sideQuest/utilities/street-gang.js +2 -14
  35. package/bundle/typescript/src/commands/game/sideQuest/utilities/street-gang.js.map +1 -1
  36. package/bundle/typescript/src/tools/sdk-loader/relocate.d.ts +19 -0
  37. package/bundle/typescript/src/tools/sdk-loader/relocate.js +23 -9
  38. package/bundle/typescript/src/tools/sdk-loader/relocate.js.map +1 -1
  39. package/package.json +1 -4
@@ -14,6 +14,7 @@ import { pushSave, burnCloudSaveFor } from './utilities/cloud-saves.js';
14
14
  import { DOCWAGON_TIERS, RESUSC_FEE, DEATH_COMP } from './utilities/docwagon.js';
15
15
  import { isFence, LIFESTYLE_TIERS } from './utilities/commerce.js';
16
16
  import { bestFakeSin, wandRead, processArrest } from './utilities/sin.js';
17
+ import { tickEphemerals } from './utilities/ephemeral.js';
17
18
  import { renderMapViewport, mapCaption } from './utilities/map-view.js';
18
19
  import { tallestRoomRows } from './utilities/room-grid.js';
19
20
  import { renderRoomLayoutCompact, crewOfTable, roomCaption } from './utilities/room-view.js';
@@ -825,6 +826,35 @@ export default class Game {
825
826
  * off the job). The hosting server writes their snapshot back and
826
827
  * marks them 'left'. */
827
828
  onPlayerExtracted;
829
+ /**
830
+ * Shared-run hook: THE SCENE UNDERNEATH EVERYONE JUST CHANGED.
831
+ *
832
+ * `repaintForScene` is how this Game tells its own UI that the world
833
+ * moved. On a hosted table there IS no UI here -- `_mapBox` is
834
+ * undefined on the server, so `updateExits` (and with it both map
835
+ * panels) is a NO-OP, measured rather than assumed: a real headless
836
+ * boot emits map/room/status 1,1,1 and calling updateExits +
837
+ * updateStatus by hand leaves it at 1,1,1, while one `command` takes
838
+ * it to 2,2,2.
839
+ *
840
+ * So every rider's panels move only when headless.ts's pushMap /
841
+ * pushStatus run, and those run from `command`, `addPlayer` and boot
842
+ * -- nowhere else. A scene swap that does not happen inside somebody's
843
+ * command therefore changes the server's truth and sends NOTHING, and
844
+ * `draftNextSceneInBackground` is exactly that shape: fire-and-forget
845
+ * over 20-40 seconds, long after the command that started it returned
846
+ * and pushed the OLD scene.
847
+ *
848
+ * This hook is the missing wire, same shape as onPlayerDeath /
849
+ * onPlayerExtracted above and installed in the same place.
850
+ *
851
+ * HARDENING, NOT A BUG FIX. The inert joint is proven; the swap
852
+ * arriving outside a command is READ IN THE SOURCE AND NOT EXECUTED
853
+ * (continueToNextScene is gated on job completion, so the harness
854
+ * cannot drive it end to end). Nothing here is offered as the cause of
855
+ * a live report.
856
+ */
857
+ onSceneChanged;
828
858
  /**
829
859
  * The per-player band (shared runs -- scene.players.length > 1):
830
860
  * resolves the FALLEN player's own contract, bills THAT player
@@ -1017,6 +1047,13 @@ export default class Game {
1017
1047
  * already answered upstream.
1018
1048
  */
1019
1049
  ephemerals = new Map();
1050
+ /**
1051
+ * Every ephemeral name this session has ever issued. Session-only like
1052
+ * the registry above, but CUMULATIVE where that one is a census -- see
1053
+ * IEphemeralHost.spentNames for why a name outliving its body is the
1054
+ * whole point.
1055
+ */
1056
+ spentNames = new Set();
1020
1057
  /** Corners that have already had their encounter -- once each, and
1021
1058
  * never saved, on the same session-only model as sweptRooms. */
1022
1059
  gangedRooms = new Set();
@@ -2831,10 +2868,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
2831
2868
  this.pendingRunAccepted = save.game.pendingRun.accepted ?? false;
2832
2869
  }
2833
2870
  this.player.currentLocation = this._homeRoom;
2834
- this.updateEquipment(this.player.equipment);
2835
- this.updateInventory(this.player.inventory, capitalCase(this.scene.getCurrencyType()));
2836
- this.updateExits(this.player.currentLocation);
2837
- this.updateStatus();
2871
+ this.repaintForScene();
2838
2872
  this.refreshLogLabel();
2839
2873
  Logger.getInstance().write(`Resumed save for ${save.playerName} (saved ${save.savedAt}, reason ${save.reason}).`);
2840
2874
  }
@@ -3109,7 +3143,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3109
3143
  this.player.currentLocation = this._homeRoom;
3110
3144
  this.player.cameFrom = undefined;
3111
3145
  const arrivalLines = this.unfoldCompanionsOnArrival();
3112
- this.refreshHubUi();
3146
+ this.repaintForScene();
3113
3147
  return [...foldLines, ...arrivalLines].join('\n');
3114
3148
  }
3115
3149
  /** Back to the job you left standing. */
@@ -3128,7 +3162,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3128
3162
  this.player.cameFrom = undefined;
3129
3163
  this._openRun = undefined;
3130
3164
  const arrivalLines = this.unfoldCompanionsOnArrival();
3131
- this.refreshHubUi();
3165
+ this.repaintForScene();
3132
3166
  return [...foldLines, ...arrivalLines].join('\n');
3133
3167
  }
3134
3168
  /** Cross-plane and combat state that must not ride in a cab, shared
@@ -3158,11 +3192,34 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3158
3192
  this.autoFight.cancelPending();
3159
3193
  }
3160
3194
  /** The panel refresh both errand legs need. */
3161
- refreshHubUi() {
3195
+ /**
3196
+ * REPAINT EVERYTHING FOR THE SCENE YOU ARE NOW STANDING IN.
3197
+ *
3198
+ * These same four calls, in this same order, were written out three
3199
+ * times -- here (as refreshHubUi), at the end of returnToHub, and at
3200
+ * the end of activateRunScene. Three copies of one rule is how a
3201
+ * fourth arrival gets two of them and reads as done, and it is the
3202
+ * shape that has already cost this file twice.
3203
+ *
3204
+ * Public because a shared run's homecoming has to reach it: the ride
3205
+ * home used to repaint the STATUS box alone, so a runner arrived back
3206
+ * at the hub with the RUN's map still drawn beside the log -- the
3207
+ * exact mirror of the hub's map surviving into a run, which is the bug
3208
+ * blankRunPanels was added to end (575fc700). One boundary, repainted
3209
+ * in one direction only, is a half-swept family.
3210
+ *
3211
+ * ORDER IS LOAD-BEARING at the shared-run call sites: updateExits
3212
+ * early-returns while `remoteSession` is set, so this must be called
3213
+ * AFTER SharedRunSession.finish() clears it, never before.
3214
+ */
3215
+ repaintForScene() {
3162
3216
  this.updateEquipment(this.player.equipment);
3163
3217
  this.updateInventory(this.player.inventory, capitalCase(this.scene.getCurrencyType()));
3164
3218
  this.updateExits(this.player.currentLocation);
3165
3219
  this.updateStatus();
3220
+ // Local UI is repainted above; a hosted table has none, and learns
3221
+ // the scene moved from here. See onSceneChanged.
3222
+ this.onSceneChanged?.();
3166
3223
  }
3167
3224
  returnToHub() {
3168
3225
  const hub = this._hubScene;
@@ -3278,10 +3335,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3278
3335
  const restocked = this.restockVendorShelves();
3279
3336
  const restockLine = restocked > 0 ? `\nThe district has restocked around you -- the wok steams, the bar's shelf is full, the market stalls are loud again.` : '';
3280
3337
  this.advanceGig();
3281
- this.updateEquipment(this.player.equipment);
3282
- this.updateInventory(this.player.inventory, capitalCase(this.scene.getCurrencyType()));
3283
- this.updateExits(this.player.currentLocation);
3284
- this.updateStatus();
3338
+ this.repaintForScene();
3285
3339
  this.refreshLogLabel();
3286
3340
  Logger.getInstance().write(`Returned to hub "${this._hubName}". Lifestyle ${this.lifestyleTier}: ${paid} paid, ${this.rentDebt} owed. Restocked ${restocked}. Rumor: ${this.activeRumor ?? '(none)'}`);
3287
3341
  // Drones spin back up beside the cot.
@@ -3657,10 +3711,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3657
3711
  this.player.currentLocation = this._homeRoom;
3658
3712
  }
3659
3713
  }
3660
- this.updateEquipment(this.player.equipment);
3661
- this.updateInventory(this.player.inventory, capitalCase(this.scene.getCurrencyType()));
3662
- this.updateExits(this.player.currentLocation);
3663
- this.updateStatus();
3714
+ this.repaintForScene();
3664
3715
  // Fresh streets, no trail yet (see Player.cameFrom / the HUD crumb).
3665
3716
  this.player.cameFrom = undefined;
3666
3717
  // Deployed drones spin back up at the curb -- BEFORE appearance
@@ -4425,7 +4476,24 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4425
4476
  armedLine(player) {
4426
4477
  const weapon = player.getWeaponProfile();
4427
4478
  const weaponItem = player.getCarriedWeapon();
4428
- const ammoNote = weaponItem?.isFirearm()
4479
+ // THE AMMO BELONGS TO THE GUN, AND THE GUN IS ON THE BODY YOU LEFT
4480
+ // (Dt2zDhMk87eHjCL3a: "I see '[10 rd]' next to the attack program").
4481
+ //
4482
+ // getWeaponProfile() correctly returns "attack programs" in the
4483
+ // Matrix, "astral strike" on the astral, a mount on a drone -- but
4484
+ // the ammo note was read from getCarriedWeapon() on every plane and
4485
+ // appended to whatever that profile said. So a decker whose slumped
4486
+ // body was carrying a loaded pistol read "Armed: attack programs
4487
+ // (DV 4) [10 rds]", counting the rounds of a weapon their persona
4488
+ // cannot touch, on a thing that does not fire.
4489
+ //
4490
+ // Canon has no consumable for programs at all, asked directly: they
4491
+ // are files that provide a benefit while running, with no charges,
4492
+ // no per-use cost, and nothing to spend (p.243 PROGRAMS). The only
4493
+ // limit is whether the program is loaded. So there is no Matrix
4494
+ // number that belongs in this slot -- the fix is to print nothing,
4495
+ // not to find a different count.
4496
+ const ammoNote = player.plane === 'meat' && weaponItem?.isFirearm()
4429
4497
  ? (weaponItem.jammed
4430
4498
  ? ` {red-fg}[JAMMED -- reboot]{/red-fg}`
4431
4499
  : weaponItem.ammo === 0 ? ` {red-fg}[DRY]{/red-fg}` : ` [${weaponItem.ammo} rds]`)
@@ -4930,7 +4998,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4930
4998
  const command = CommandFactory.createCommand(verb, context);
4931
4999
  if (command) {
4932
5000
  const result = await command.execute(args);
4933
- return out(this.withICTurn(actor, result));
5001
+ return out(this.withEphemeralTurn(actor, this.withICTurn(actor, result)));
4934
5002
  }
4935
5003
  // Typo tolerance: two straight sessions bounced on slips like "searh"
4936
5004
  // and "maop". Reuse the same fuzzy matcher item/NPC names go through
@@ -4976,6 +5044,27 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4976
5044
  * utilities/ic.ts decides whether anything happens at all
4977
5045
  * (hostIsHunting); this only carries the result to the panes.
4978
5046
  */
5047
+ /**
5048
+ * THE EPHEMERAL TURN, appended the same way the host's is.
5049
+ *
5050
+ * One player action is one beat for every passing face in the room --
5051
+ * the same engine mapping withICTurn makes below, and hung off the
5052
+ * same single dispatch for the same reason: a mob closes on you while
5053
+ * you look, talk, or check your gear, not only while you walk. Hooking
5054
+ * one verb is the "fixed one verb, left its siblings" shape CLAUDE.md
5055
+ * warns about.
5056
+ *
5057
+ * utilities/ephemeral.ts decides what each kind does with its beat;
5058
+ * this only carries the narration back. Only a mob ever produces any.
5059
+ */
5060
+ withEphemeralTurn(actor, result) {
5061
+ if (result === null)
5062
+ return null;
5063
+ if (actor !== this.player || this.ephemerals.size === 0)
5064
+ return result;
5065
+ const lines = tickEphemerals(this, actor);
5066
+ return lines.length === 0 ? result : `${result}\n\n${lines.join('\n')}`;
5067
+ }
4979
5068
  withICTurn(actor, result) {
4980
5069
  if (result === null)
4981
5070
  return null;