@maka/maka-cli 5.221.0 → 5.223.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.221.0",
3
+ "version": "5.223.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.",
@@ -150,22 +150,49 @@ export class JackCommand extends Command {
150
150
  // price is paid on the other side: every point of Matrix damage
151
151
  // lands on their REAL stun track (see combat-exchange routing).
152
152
  if (!actor.isTechnomancer()) {
153
- const deck = actor.getCyberdeck();
154
- if (!deck) {
153
+ // A COMMLINK IS A WAY ONTO THE MATRIX (9d9kJJW3WANoA2MvA, Maka:
154
+ // "check the rules on page 222 -- anyone with a commlink should
155
+ // be able to enter the matrix"). He is right and the line he
156
+ // quoted -- "No cyberdeck, no Matrix" -- was flatly wrong.
157
+ // p.221: "the majority of people interact with the Matrix in
158
+ // augmented reality, using their commlink", and p.222 gives a
159
+ // commlink user their own Matrix attributes and their own five
160
+ // actions. The Matrix is where everyone already lives.
161
+ //
162
+ // WHAT A DECK ACTUALLY BUYS is the hacking half, and the model
163
+ // already said so without anyone having to write a rule here:
164
+ // Item.matrixAttribute gives a non-deck device Data Processing
165
+ // and Firewall equal to its rating and ATTACK AND SLEAZE OF
166
+ // ZERO -- exactly p.222's "both of these attributes are equal to
167
+ // your commlink's rating", and exactly p.221's reason ("unlike a
168
+ // cyberdeck it has no space for cyberprograms or other hacking
169
+ // tools"). So a commlink persona can ride the grid, look, talk
170
+ // and carry files, and cannot hack. The refusal for that lives
171
+ // where the hacking happens (Player.deckOnlyRefusal), not here.
172
+ const rig = actor.getCyberdeck() ?? actor.getPanMaster();
173
+ if (!rig) {
155
174
  const bricked = actor.getAnyCyberdeck();
156
175
  return bricked
157
176
  ? `Your ${bricked.name} is BRICKED (${bricked.deckSummary()}) -- dead boards don't jack in. Rest somewhere safe to repair it.`
158
- : `No cyberdeck, no Matrix. A commlink gets you calls and AR -- riding the grid takes a real deck.`;
159
- }
160
- if (actor.runningSilent) {
161
- return `You're running silent -- no broadcast, no Matrix. Go loud first ("silent").`;
177
+ : `Nothing to jack in ON. A commlink or a cyberdeck puts you on the grid (p.222) -- you are carrying neither.`;
162
178
  }
179
+ // RUNNING SILENT IS A MATRIX STATE, NOT A DOOR (oJELzTwkTJE63bvXr,
180
+ // Maka: "I should be able to jack in, even running silent"). The
181
+ // refusal here had it exactly backwards. p.235-236: "you can
182
+ // switch your commlink, deck, other device, or persona ... to
183
+ // silent running" -- it is a mode you run WHILE on the Matrix,
184
+ // and going quiet is the first thing a runner does on the way
185
+ // in, not a reason to be kept out. The cost is already modelled
186
+ // where canon puts it: -2 on every Matrix action
187
+ // (Player.matrixActionPenalty), and an icon nobody can see
188
+ // without beating you in an opposed test (silent-icons.ts).
189
+ //
163
190
  // VR NEEDS A DIRECT NEURAL INTERFACE (p.222-223): a datajack or
164
- // a trode net. The deck's own screen still gives you AR -- calls,
191
+ // a trode net. The rig's own screen still gives you AR -- calls,
165
192
  // the overlay, the sheet -- but riding the grid means plugging
166
193
  // your nervous system in. Names the two cures and their prices.
167
194
  if (!actor.hasDirectNeuralInterface()) {
168
- return `Jacking in is VR, and VR needs a direct neural interface -- a trode net (70 nuyen on any electronics shelf) or a datajack at the clinic. Without one your ${deck.name} is AR only.`;
195
+ return `Jacking in is VR, and VR needs a direct neural interface -- a trode net (70 nuyen on any electronics shelf) or a datajack at the clinic. Without one your ${rig.name} is AR only.`;
169
196
  }
170
197
  }
171
198
  let mode = (sub === 'hot' || args[1]?.toLowerCase() === 'hot') ? 'hot' : 'cold';
@@ -1279,5 +1279,51 @@
1279
1279
  // it DOES (p.235-236, already charged to players through
1280
1280
  // matrixActionPenalty) rather than added to its hide roll. Spending it
1281
1281
  // twice would be a house rule wearing a citation.
1282
- export const ENGINE_VERSION = '1.80.0';
1282
+ // 1.80.1 (2026-09-16): the camera-hide fix in 5.222.0 -- a camera hides
1283
+ // behind its OWN rating, not its master host's. Recorded here late and
1284
+ // deliberately: that commit said "engine 1.80.1" in its subject and did
1285
+ // not move this constant, so 5.222.0 shipped reporting 1.80.0. The fix
1286
+ // itself is in utilities/silent-icons.ts with its reasoning; this entry
1287
+ // exists so the changelog does not have a hole where a version was
1288
+ // announced. p.233's slaving rule is about DEFENDING AN ATTACK, not
1289
+ // hiding, and borrowing the host's rating made a camera on a rating-8
1290
+ // host unfindable -- measured at zero finds in twelve looks.
1291
+ // 1.81.0 (2026-09-16): A COMMLINK IS A WAY ONTO THE MATRIX, AND SILENCE
1292
+ // IS NOT A LOCKED DOOR. Two reports, two refusals, seven lines apart in
1293
+ // the same guard, both wrong.
1294
+ // - 9d9kJJW3WANoA2MvA (Maka): "check the rules on page 222 -- anyone
1295
+ // with a commlink should be able to enter the matrix". The line he
1296
+ // quoted, "No cyberdeck, no Matrix. A commlink gets you calls and AR
1297
+ // -- riding the grid takes a real deck", was flatly wrong. p.221:
1298
+ // "the majority of people interact with the Matrix in augmented
1299
+ // reality, using their commlink." p.222 gives a commlink user their
1300
+ // own Matrix attributes and their own five actions.
1301
+ // - oJELzTwkTJE63bvXr (Maka): "I should be able to jack in, even
1302
+ // running silent". Backwards. p.235-236: "you can switch your
1303
+ // commlink, deck, other device, or persona ... to silent running" --
1304
+ // a mode you run WHILE on the Matrix, and the first thing a runner
1305
+ // does on the way in. The cost is already modelled where canon puts
1306
+ // it: -2 on every Matrix action, and an icon nobody sees without
1307
+ // beating you in an opposed test (1.80.0).
1308
+ // WHAT A DECK ACTUALLY BUYS is the hacking half, and the item model
1309
+ // already said so without anyone writing a rule: a non-deck device has
1310
+ // Data Processing and Firewall equal to its rating and ATTACK AND
1311
+ // SLEAZE OF ZERO -- p.222's "both of these attributes are equal to your
1312
+ // commlink's rating", p.221's "no space for cyberprograms or other
1313
+ // hacking tools". So a commlink persona rides the grid, looks, talks
1314
+ // and carries data, and cannot crack an icon.
1315
+ // AND THAT HALF IS LOAD-BEARING, not a nicety. Attack 0 does not fail
1316
+ // safe: a limit of 0 is NOT a cap of zero hits in rollPool, it is no
1317
+ // cap at all (`limit > 0` is what makes a cap a cap). Opening the door
1318
+ // without closing the hacking half would not have made a commlink user
1319
+ // bad at hacking -- it would have made them roll UNLIMITED and out-hit
1320
+ // the decker beside them. burnedAttributeRefusal answers for the
1321
+ // no-gear case too now (deckOnlyRefusal), naming the gear instead of
1322
+ // blaming an IC that was never there, and never sending somebody to
1323
+ // reboot a deck they do not own.
1324
+ // SEVEN TEST FIXTURES WERE HACKING WITH NO DECK, which is how long that
1325
+ // hole had been open: they leaned on the old "no gear, stay quiet"
1326
+ // branch and have been rolling unlimited all along. They carry decks
1327
+ // now. The VR gate (a direct neural interface, p.222-223) is untouched.
1328
+ export const ENGINE_VERSION = '1.81.0';
1283
1329
  //# sourceMappingURL=engine-version.js.map
@@ -858,10 +858,48 @@ export class Player extends AbstractPlayer {
858
858
  burnedAttributeRefusal(kind) {
859
859
  if (this.matrixAttribute(kind) > 0)
860
860
  return undefined;
861
+ // NO GEAR IS ITS OWN REFUSAL, and it used to be nobody's
862
+ // (9d9kJJW3WANoA2MvA). This returned undefined here on the grounds
863
+ // that "its callers already gate on the gear" -- and the gate they
864
+ // meant was jack-in's "No cyberdeck, no Matrix", which was itself
865
+ // the canon violation being fixed. Once a commlink can reach the
866
+ // grid (p.222), a persona with Attack 0 and Sleaze 0 is an ordinary
867
+ // thing to be, and the hacking verbs had nothing left standing
868
+ // between them and a roll.
869
+ //
870
+ // THE FAILURE MODE IS WORSE THAN IT LOOKS, which is why it is
871
+ // refused rather than left to the dice: a limit of 0 is not a limit
872
+ // of zero hits in rollPool, it is NO LIMIT (`limit > 0` is what
873
+ // makes a cap a cap). So a commlink user who reached a hacking roll
874
+ // would not fail -- they would roll UNLIMITED, out-hitting the
875
+ // decker standing next to them.
861
876
  if (this.baseMatrixAttribute(kind) <= 0)
862
- return undefined; // no gear, not a burn
877
+ return this.deckOnlyRefusal(kind);
863
878
  return `${Player.ATTR_EATER[kind]} ate your ${Player.ATTR_NAME[kind]} -- there is nothing left to work with. It comes back when you reboot ("jack out", then jack back in).`;
864
879
  }
880
+ /**
881
+ * WHY A COMMLINK CANNOT DO THIS, in the book's own terms.
882
+ *
883
+ * p.221: a commlink "has all of the necessary software already loaded,
884
+ * but unlike a cyberdeck it has no space for cyberprograms or other
885
+ * hacking tools." p.222 gives it Data Processing and Firewall equal to
886
+ * its rating and names no Attack or Sleaze at all. That is not an
887
+ * oversight in the engine's item model -- it is the whole difference
888
+ * between riding the Matrix and hacking it.
889
+ *
890
+ * Data Processing and Firewall can never be 0 on a working rig, so in
891
+ * practice this only ever answers for attack and sleaze; the other two
892
+ * are handled so the method cannot lie if a future device rates 0.
893
+ */
894
+ deckOnlyRefusal(kind) {
895
+ if (kind !== 'attack' && kind !== 'sleaze')
896
+ return undefined;
897
+ const rig = this.activeDeck ?? this.getCyberdeck() ?? this.getPanMaster();
898
+ const what = kind === 'attack' ? 'Attack' : 'Sleaze';
899
+ return rig
900
+ ? `Your ${rig.name} has no ${what} rating -- it is a commlink, not a cyberdeck, and "no space for cyberprograms or other hacking tools" (p.221). You are ON the grid and you can look, talk and carry data; cracking an icon takes a deck.`
901
+ : `Nothing you are carrying has an ${what} rating -- that takes a cyberdeck (p.221).`;
902
+ }
865
903
  /** Which IC eats which attribute (p.248), for naming the culprit. */
866
904
  static ATTR_EATER = {
867
905
  attack: 'Jammer IC', sleaze: 'Marker IC',
@@ -1,6 +1,6 @@
1
1
  import { rollPool, formatRoll } from './dice.js';
2
2
  import { deviceDefensePool } from './matrix-intrusion.js';
3
- import { isWatched, cameraMasterHost } from './surveillance.js';
3
+ import { isWatched } from './surveillance.js';
4
4
  import { DEFAULT_DEVICE_RATING } from '../models/device.js';
5
5
  function hiddenDevice(device) {
6
6
  return {
@@ -34,17 +34,25 @@ export function hiddenIconsIn(scene, room, viewer) {
34
34
  .map(hiddenDevice);
35
35
  // THE CAMERAS, which p.217 names FIRST. They are not a Device -- the
36
36
  // cluster is derived from the room (surveillance.ts isWatched) -- so
37
- // they hide on the room's own set and resist with their master host's
38
- // rating where there is one: a site's lenses are as quiet as the
39
- // security that runs them, and a slave borrows its master's numbers
40
- // (p.233). Without a host they fall back to the door-lock rating
41
- // canon prices ordinary fixtures at (p.356).
37
+ // they hide on the room's own set, and they hide behind their OWN
38
+ // rating: an ordinary fixture, which canon prices at 2 (p.356).
39
+ //
40
+ // THE FIRST CUT GAVE THEM THEIR MASTER HOST'S RATING and that was
41
+ // wrong twice over. Canon first: p.233's slaving rule is about what a
42
+ // slave DEFENDS AN ATTACK with -- "whenever a slaved device is called
43
+ // on to make a defense test" -- and hiding is not an attack being
44
+ // defended. Borrowing the host's numbers here was an extrapolation
45
+ // with nothing under it, which is exactly what this project's rule
46
+ // against inventing canon is for. And then arithmetic: a rating-8
47
+ // host gave its lenses 16 dice against a sweep the Data Processing
48
+ // limit caps near 5, so a camera on any corporate host was not hard
49
+ // to find, it was impossible. Measured before shipping the fix --
50
+ // zero finds in twelve looks.
42
51
  if (isWatched(room) && !room.camerasSpottedBy.has(viewer.name)) {
43
- const master = scene ? cameraMasterHost(scene.getRooms(), room) : undefined;
44
- const rating = master?.hostRating ?? DEFAULT_DEVICE_RATING.lock ?? 2;
52
+ const rating = DEFAULT_DEVICE_RATING.lock ?? 2;
45
53
  out.push({
46
54
  name: 'Camera cluster',
47
- hide: { pool: Math.max(0, rating * 2), label: master ? 'its host\'s rating' : 'Device Rating' },
55
+ hide: { pool: Math.max(0, rating * 2), label: 'Device Rating' },
48
56
  reveal: (v) => { room.camerasSpottedBy.add(v); },
49
57
  });
50
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.221.0",
3
+ "version": "5.223.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.",