@maka/maka-cli 5.194.0 → 5.196.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.194.0",
3
+ "version": "5.196.0",
4
4
  "type": "module",
5
5
  "summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
6
6
  "description": "A command line tool for scaffolding Meteor 3.x applications using React.",
@@ -15,7 +15,7 @@ export class EdgeCommand extends Command {
15
15
  return `Luck has left the building, and so have you.`;
16
16
  }
17
17
  if (actor.edgeBoostArmed) {
18
- return `Your edge is already burning -- land the strike. (${actor.edgeRemaining}/${actor.edge} left after this.)`;
18
+ return `Your edge is already burning -- land the strike. (${actor.edgeRemaining}/${actor.edgeMax} left after this.)`;
19
19
  }
20
20
  if (actor.edgeRemaining <= 0) {
21
21
  return `You're out of luck -- literally. Edge refreshes when the next job starts.`;
@@ -26,16 +26,16 @@ export class EdgeCommand extends Command {
26
26
  if (actor.hasQuality('bad-luck')) {
27
27
  const die = 1 + Math.floor(Math.random() * 6);
28
28
  if (die === 1) {
29
- this.logger.write(`${actor.name} burned an edge point and BAD LUCK ate it (${actor.edgeRemaining}/${actor.edge} left).`);
29
+ this.logger.write(`${actor.name} burned an edge point and BAD LUCK ate it (${actor.edgeRemaining}/${actor.edgeMax} left).`);
30
30
  this.scene.updateStatus();
31
- return `You reach for the luck that got you this far -- and it CURDLES. The point is spent; nothing comes. (Bad Luck. ${actor.edgeRemaining}/${actor.edge} edge left this job.)`;
31
+ return `You reach for the luck that got you this far -- and it CURDLES. The point is spent; nothing comes. (Bad Luck. ${actor.edgeRemaining}/${actor.edgeMax} edge left this job.)`;
32
32
  }
33
33
  }
34
34
  actor.edgeBoostArmed = true;
35
- this.logger.write(`${actor.name} burned an edge point (${actor.edgeRemaining}/${actor.edge} left).`);
35
+ this.logger.write(`${actor.name} burned an edge point (${actor.edgeRemaining}/${actor.edgeMax} left).`);
36
36
  this.actor.performAction('pushes the limit', '');
37
37
  this.scene.updateStatus();
38
- return `You reach for the luck that got you this far. The next strike you throw rolls +${actor.edge} dice. (${actor.edgeRemaining}/${actor.edge} edge left this job.)`;
38
+ return `You reach for the luck that got you this far. The next strike you throw rolls +${actor.edge} dice. (${actor.edgeRemaining}/${actor.edgeMax} edge left this job.)`;
39
39
  }
40
40
  }
41
41
  //# sourceMappingURL=edge.js.map
@@ -105,7 +105,7 @@ export class SheetCommand extends Command {
105
105
  //
106
106
  // The rule is canon and stays. What changes is that the number now
107
107
  // states its own ceiling and explains its own shortfall.
108
- const edgeMax = a.edge + a.lifestyleEdgeBonus;
108
+ const edgeMax = a.edgeMax;
109
109
  const edgeSource = a.lifestyleEdgeBonus > 0
110
110
  ? ` -- ${a.edge} base +${a.lifestyleEdgeBonus} from where you sleep`
111
111
  : '';
@@ -471,5 +471,16 @@
471
471
  // taxi, no pay. Left one full homecoming, the desk reviews the feeds:
472
472
  // +1 Public Awareness. New SaveReason 'cleanup'; new win condition
473
473
  // type 'erase'. The site reads Game.footageLeft() off the live handle.
474
- export const ENGINE_VERSION = '1.55.0';
474
+ // 1.55.1 (2026-09-15): THE EDGE CEILING IS ONE NUMBER. Player.edgeMax
475
+ // (attribute + lifestyle bonus) replaces the sum four readers were
476
+ // writing out by hand, three of them dropping the bonus -- the `edge`
477
+ // command's denominator and the condition report's published `max`,
478
+ // which the play page's HUD rendered as "edge 4/3" on a FULL pool.
479
+ // Underneath them, buildPlayerFromSave stood up a bare Player with no
480
+ // Game to set lifestyleEdgeBonus, so its refreshEdge filled the pool to
481
+ // the plain attribute: every headless boot -- shared runs, the browser
482
+ // hub, characterSheet.hydrate -- silently ATE the lifestyle point of a
483
+ // runner who left fed and slept. The tier is on the save; it is read
484
+ // there now (commerce.lifestyleTierFor, Squatter when unnamed).
485
+ export const ENGINE_VERSION = '1.55.1';
475
486
  //# sourceMappingURL=engine-version.js.map
@@ -27,7 +27,7 @@ import { heartbeatPresence, heartbeatPresenceNow } from './utilities/social.js';
27
27
  import { presenceBeatAllowed } from './utilities/presence-gate.js';
28
28
  import { pushSave, burnCloudSaveFor, enqueueBoundPush, flushPushQueue, writeSpill, takeLastMemorial, authToken, clearSpill, hasPendingPush, } from './utilities/cloud-saves.js';
29
29
  import { DOCWAGON_TIERS, RESUSC_FEE, DEATH_COMP } from './utilities/docwagon.js';
30
- import { isFence, LIFESTYLE_TIERS, LIFESTYLE_OPTIONS, canonicalLifestyleTier, canonicalLifestyleOption, lifestyleOptionAllowed } from './utilities/commerce.js';
30
+ import { isFence, LIFESTYLE_TIERS, LIFESTYLE_OPTIONS, canonicalLifestyleTier, canonicalLifestyleOption, lifestyleOptionAllowed, lifestyleTierFor } from './utilities/commerce.js';
31
31
  import { reconcileGarage } from './models/home-containers.js';
32
32
  import { ownedDrones } from './utilities/owned-drones.js';
33
33
  import { attachBrandMark, attachBrandMarkBottomRight } from './utilities/brand-mark.js';
@@ -2024,7 +2024,7 @@ export default class Game {
2024
2024
  rentDebt = 0;
2025
2025
  /** The active lifestyle tier's row (falls back to Squatter). */
2026
2026
  get lifestyle() {
2027
- return LIFESTYLE_TIERS.find(t => t.name === this.lifestyleTier) ?? LIFESTYLE_TIERS[1];
2027
+ return lifestyleTierFor(this.lifestyleTier);
2028
2028
  }
2029
2029
  hasLifestyleOption(key) {
2030
2030
  return this.lifestyleOptions.includes(key);
@@ -4776,7 +4776,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4776
4776
  if (fed && slept) {
4777
4777
  // Good-news status with a rules lesson inside -- hint-gated
4778
4778
  // (player request); the HUD's edge count carries the number anyway.
4779
- const note = hint(`Fed and slept -- you head out SHARP. (Edge ${p.edgeRemaining}/${p.edge + p.lifestyleEdgeBonus}.)`);
4779
+ const note = hint(`Fed and slept -- you head out SHARP. (Edge ${p.edgeRemaining}/${p.edgeMax}.)`);
4780
4780
  if (note)
4781
4781
  lines.push(note);
4782
4782
  }
@@ -22,6 +22,7 @@ import { hostileByStance, enemyInFight, renderRoomLayoutCompact, crewOfTable, ro
22
22
  import { serializeRoomGrid } from './utilities/room-grid.js';
23
23
  import { entrySpotFor, spotOf } from './utilities/spots.js';
24
24
  import { equipIntoEmptySlots } from './archetypes.js';
25
+ import { lifestyleTierFor } from './utilities/commerce.js';
25
26
  /**
26
27
  * The session's Logger: same shape the whole engine already talks to,
27
28
  * but every player-visible line becomes a GameEvent through `sink`.
@@ -186,6 +187,16 @@ export function buildPlayerFromSave(save) {
186
187
  // has no arrival beat to narrate into; porting it would apply locked
187
188
  // fatigue to a rider on someone else's schedule. Per-job flags are the
188
189
  // half that is unambiguously wrong to skip.
190
+ // THE LIFESTYLE POINT SURVIVES THE BOOT (mjmcee, 2026-09-15, seen as
191
+ // "edge 4/3" on the web sheet). A Middle+ hideout banks a bonus edge
192
+ // each job, and `lifestyleEdgeBonus` is set by Game from the active
193
+ // tier -- but this path builds a BARE Player, with no Game, so it
194
+ // stood at 0 and the refreshEdge below filled the pool to the plain
195
+ // attribute. Every headless boot -- shared runs, the browser hub, the
196
+ // site's characterSheet.hydrate -- therefore QUIETLY ATE the lifestyle
197
+ // point of a runner who left fed and slept, and published a ceiling one
198
+ // short for everyone else. The tier is on the save; read it.
199
+ player.lifestyleEdgeBonus = lifestyleTierFor(save.game?.lifestyleTier).edgeBonus;
189
200
  player.refreshEdge(player.ateThisCycle && player.sleptThisCycle);
190
201
  return player;
191
202
  }
@@ -3591,6 +3591,17 @@ export class Player extends AbstractPlayer {
3591
3591
  // A comfortable home sharpens the luck: Middle+ lifestyles bank a bonus
3592
3592
  // edge each job (set by Game from the active tier; 0 for NPCs).
3593
3593
  lifestyleEdgeBonus = 0;
3594
+ /**
3595
+ * THE EDGE CEILING -- the pool's real maximum, attribute plus whatever
3596
+ * the lifestyle banks. ONE getter because the sum was being written out
3597
+ * by hand at every call site and three of them dropped the bonus: the
3598
+ * sheet said 4, the `edge` command said /3, and the condition report
3599
+ * published max 3 to the web HUD, which rendered a full pool as "4/3"
3600
+ * (mjmcee, 2026-09-15). refreshEdge fills to THIS, so anything printing
3601
+ * a ceiling must read THIS -- `edge` alone is the attribute, which is
3602
+ * what the burn adds as dice and what karma raises, not the cap.
3603
+ */
3604
+ get edgeMax() { return this.edge + this.lifestyleEdgeBonus; }
3594
3605
  // ==================== Needs (SR5e p.56 / p.172) ====================
3595
3606
  // Edge comes back from "a fulfilling meal and a good night's sleep" --
3596
3607
  // so eating (use.ts) and sleeping (rest.ts, at a Residence) are tracked
@@ -3644,7 +3655,7 @@ export class Player extends AbstractPlayer {
3644
3655
  */
3645
3656
  refreshEdge(wellRested = true) {
3646
3657
  if (wellRested) {
3647
- this.edgeRemaining = this.edge + this.lifestyleEdgeBonus;
3658
+ this.edgeRemaining = this.edgeMax;
3648
3659
  }
3649
3660
  this.edgeBoostArmed = false;
3650
3661
  this.haggledThisJob = false;
@@ -199,6 +199,16 @@ export function canonicalLifestyleTier(raw) {
199
199
  return 'Middle';
200
200
  return LIFESTYLE_TIERS.find(t => t.name.toLowerCase() === wanted)?.name;
201
201
  }
202
+ /**
203
+ * The tier a stored name names, Squatter when it names nothing -- the
204
+ * same default Game.lifestyle has always used, lifted out of that getter
205
+ * so a BARE Player (buildPlayerFromSave, with no Game around it) can
206
+ * resolve its own lifestyle instead of silently reading a zero bonus.
207
+ */
208
+ export function lifestyleTierFor(raw) {
209
+ const name = canonicalLifestyleTier(raw) ?? raw;
210
+ return LIFESTYLE_TIERS.find(t => t.name === name) ?? LIFESTYLE_TIERS[1];
211
+ }
202
212
  /** One-line flavor note per consumable category, shown on shop shelves. */
203
213
  export function shelfNote(item) {
204
214
  switch (item.category) {
@@ -220,7 +220,7 @@ export function buildConditionReport(player, deps) {
220
220
  // fields, verbatim; edge is BOTH halves or neither on the web side.
221
221
  karma: player.karma,
222
222
  nuyen: player.currency,
223
- edge: { remaining: player.edgeRemaining, max: player.edge },
223
+ edge: { remaining: player.edgeRemaining, max: player.edgeMax },
224
224
  // THE ROOM'S OTHER DOTS (user: the map becomes a tactical
225
225
  // readout). Current room only, read at fire time; spot-seated
226
226
  // actors carry `spot` and the web places them on the grid it
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.194.0",
3
+ "version": "5.196.0",
4
4
  "type": "module",
5
5
  "summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
6
6
  "description": "A command line tool for scaffolding Meteor 3.x applications using React.",