@maka/maka-cli 5.151.0 → 5.152.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.151.0",
3
+ "version": "5.152.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.",
@@ -552,6 +552,33 @@ export default class Game {
552
552
  return `{yellow-fg}🔥 Heat: ears up all over the block{/yellow-fg}`;
553
553
  return `{yellow-fg}🔥 Heat: somebody heard something{/yellow-fg}`;
554
554
  }
555
+ /**
556
+ * THE SAME BAND, FOR AN NPC'S MOUTH (YE9G3Q5P85y5xcP7n: "Mr. Ibis said
557
+ * 'Quiet as promised' however, there's a status of: 🔥 Heat: sirens
558
+ * circling closer"). heatBand() paints the player's own HUD; nothing
559
+ * fed the run's actual heat into NPC.respondTo's prompt at all, so an
560
+ * NPC narrating "the coast is clear" had no way to know it wasn't --
561
+ * the same shape as payoutSummary's fix for an invented payout, here
562
+ * for an invented all-clear.
563
+ *
564
+ * DELIBERATELY NOT ITS OWN THRESHOLDS. heat-band-honesty.test.ts pins
565
+ * the top band's heat check to the ONE line inside heatBand(), on
566
+ * purpose: the HUD's promise and checkpointOnRideHome's verifierDice
567
+ * escalation share that number so they cannot drift apart. A second
568
+ * copy of the same comparison here for the AI prompt would be exactly
569
+ * the drift that guard exists to catch. So this reads heatBand()'s OWN
570
+ * text -- strip the color codes and the HUD's "🔥 Heat: " lede, and
571
+ * what is left is plain enough for a prompt -- rather than re-deriving
572
+ * the bands.
573
+ */
574
+ heatSummaryForDialogue() {
575
+ if (!this.onRun)
576
+ return undefined;
577
+ const band = this.heatBand();
578
+ if (!band)
579
+ return undefined;
580
+ return band.replace(/\{[^}]*\}/g, '').replace(/^🔥\s*Heat:\s*/, '');
581
+ }
555
582
  // THE FOR-HIRE BOARD: archetype-built candidates, fresh faces each
556
583
  // homecoming (the gig-pool rotation school). Not saved -- the street's
557
584
  // talent pool churns; whoever you HIRED is the persistent part.
@@ -1660,6 +1660,15 @@ ${worldEventsSummary}
1660
1660
  const payoutSummary = payout
1661
1661
  ? `The agreed payout for the current job is EXACTLY ${payout} nuyen, paid as ONE LUMP SUM on delivery -- there is no advance and no half up front; never speak as if part has already been paid. Any time you mention payment, reward, or what the job is worth, use exactly this figure -- never invent a different one. Payment transfers automatically when the job completes; you never need to hand it over.`
1662
1662
  : '';
1663
+ // HEAT IS MECHANICALLY REAL TOO (YE9G3Q5P85y5xcP7n: an NPC said
1664
+ // "Quiet as promised" while the player's own HUD read "Heat: sirens
1665
+ // circling closer"). Same shape as payoutSummary above -- nothing
1666
+ // told the model the run's actual heat, so a reassuring line had
1667
+ // nothing to check itself against.
1668
+ const heat = this._scene?.ownerGame?.heatSummaryForDialogue?.();
1669
+ const heatSummary = heat
1670
+ ? `The district's current HEAT on this run is ${heat}. If you would naturally reassure them that things are quiet, clean, or under control, that claim has to be TRUE against this -- never tell them the coast is clear, that nobody noticed, or that things went quiet if heat says otherwise. Speak honestly about how hot it actually is instead.`
1671
+ : '';
1663
1672
  // If nothing else has happened to/around this NPC yet this scene, this
1664
1673
  // is the first time anyone's reached out -- nudge toward volunteering
1665
1674
  // the job rather than waiting to be asked, which real playtesting
@@ -2103,6 +2112,7 @@ Your objective is to drive the story line.`}
2103
2112
  ${eph ? '' : objectiveSummary}
2104
2113
  ${dialogueSummary}
2105
2114
  ${eph ? '' : payoutSummary}
2115
+ ${eph ? '' : heatSummary}
2106
2116
 
2107
2117
  ${roomDesc}${spotBlock}${combatSpatialBlock}
2108
2118
  ${formattedExitsStr}
@@ -652,7 +652,37 @@ export class Player extends AbstractPlayer {
652
652
  return true;
653
653
  if (this.arOffline)
654
654
  return false;
655
- return !!this.getPanMaster();
655
+ if (!this.getPanMaster())
656
+ return false;
657
+ return this.hasARDisplay();
658
+ }
659
+ /**
660
+ * THE MISSING HALF OF AR (canon p.53-54/221-222, RAG-checked
661
+ * 2026-09-10, acBi46ZKKJCPyBKXb: "it looks like I'm able to see AR
662
+ * with the Hermes Ikon, however, I don't have a method to interface
663
+ * to it -- no trode, or commlink jack. I think this is a gap"). It
664
+ * was: "a commlink alone does not automatically give you AR -- the
665
+ * commlink processes and sends the information, but you still need a
666
+ * display device to receive it." hasMatrixEyes gated ONLY on a
667
+ * PAN master existing, never on having any way to actually SEE what
668
+ * it sends -- so a runner with a commlink in their pocket and nothing
669
+ * on their face or in their skull got the full overlay regardless.
670
+ *
671
+ * Two independent roads in, matching what the rulebook actually lists:
672
+ * a DNI (trodes/datajack/technomancer -- Player.hasDirectNeuralInterface,
673
+ * "you can use all your senses to view AR without any extra devices"),
674
+ * or a worn visual display (cybereyes, glasses, goggles, contacts --
675
+ * same head.eyes slot and same two categories smartlink detection
676
+ * already reads, Category.Glasses / Category.EyeCyberwere). Audio-only
677
+ * and haptic-only AROs have their own separate gear (earbuds/cyberear,
678
+ * AR gloves, p.222/439) and are not modelled here -- this predicate is
679
+ * specifically the VISUAL overlay hasMatrixEyes has always been about.
680
+ */
681
+ hasARDisplay() {
682
+ if (this.hasDirectNeuralInterface())
683
+ return true;
684
+ const onFace = this._equipment.head?.eyes;
685
+ return !!onFace && (onFace.category === Category.Glasses || onFace.category === Category.EyeCyberwere);
656
686
  }
657
687
  /**
658
688
  * A DIRECT NEURAL INTERFACE -- what VR needs and AR does not (SR5 core
@@ -225,10 +225,17 @@ export function arStatusSlots(actor) {
225
225
  ? `{white-fg}◌ AR OFF{/white-fg}`
226
226
  : !actor.getPanMaster() && !actor.isTechnomancer()
227
227
  ? `{white-fg}◌ no AR rig{/white-fg}`
228
- // Off-plane, or any future state that puts the overlay down
229
- // without being one of the above. game.ts drops the slot
230
- // entirely while off-plane -- a persona has its own HUD line.
231
- : `{white-fg}◌ AR dark{/white-fg}`;
228
+ // A processor with nothing to paint it on (acBi46ZKKJCPyBKXb):
229
+ // a commlink sends the overlay, but nothing here receives it
230
+ // (Player.hasARDisplay -- no DNI, no worn glasses/goggles/
231
+ // cybereyes). Distinct from "no AR rig" -- the player HAS a
232
+ // rig, it just has nowhere to show up.
233
+ : !actor.hasARDisplay()
234
+ ? `{white-fg}◌ no display -- trodes or eyewear{/white-fg}`
235
+ // Off-plane, or any future state that puts the overlay down
236
+ // without being one of the above. game.ts drops the slot
237
+ // entirely while off-plane -- a persona has its own HUD line.
238
+ : `{white-fg}◌ AR dark{/white-fg}`;
232
239
  // The link slot asks for the LIVE LINK -- worn commlink or working
233
240
  // deck -- because that is what call.ts now asks for (p.223: a deck
234
241
  // performs all commlink functions). The old "AR ON | Link offline"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.151.0",
3
+ "version": "5.152.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.",