@maka/maka-cli 5.202.0 → 5.204.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.202.0",
3
+ "version": "5.204.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.",
@@ -595,7 +595,9 @@ export class CallCommand extends Command {
595
595
  try {
596
596
  const sr = await import('../utilities/shared-run.js');
597
597
  await sr.HubLink.ready(this.game ?? undefined);
598
- const res = await sr.HubLink.call('sideQuest.partyPage', { text: greeting });
598
+ // `from` names the SPEAKER, not the account (t8qhbB3c3PRRkq5sP --
599
+ // see say.ts's party branch for the report this closes).
600
+ const res = await sr.HubLink.call('sideQuest.partyPage', { text: greeting, from: this.actor.name });
599
601
  if (this.actor.activeCallPartner) {
600
602
  this.actor.activeCallPartner.activeCallPartner = undefined;
601
603
  this.actor.activeCallPartner = undefined;
@@ -1,6 +1,7 @@
1
1
  import { Command } from './command.js';
2
2
  import { rollPool, formatRoll } from '../utilities/dice.js';
3
3
  import { hint } from '../utilities/hints.js';
4
+ import { spriteMatrix } from '../sprite-powers.js';
4
5
  import { fuzzyPickName } from '../utilities/fuzzy-match.js';
5
6
  /** Exported for game.ts: re-shelling a REGISTERED sprite after travel
6
7
  * or a resumed save needs the same stat builder. */
@@ -161,6 +162,12 @@ export class CompileCommand extends Command {
161
162
  // A sprite rides its compiler's persona: same grid, same host.
162
163
  if (shell)
163
164
  shell.matrixPosition = actor.matrixPosition;
165
+ // ...and carries its OWN Matrix array (p.254, p.259), which is what
166
+ // fills the [Sleaze]/[Attack] bracket on every roll it makes. It
167
+ // has no deck for the rig lookup to find, so without this its
168
+ // limits computed to 0 and rollPool refused them as "not a limit".
169
+ if (shell)
170
+ shell.spriteMatrixAttrs = spriteMatrix(typeKey, level);
164
171
  if (shell && this.game) {
165
172
  const entry = this.game.companions.find(c => c.npc === shell);
166
173
  if (entry)
@@ -13,6 +13,17 @@ export class EraseMarkCommand extends Command {
13
13
  static verb = 'unmark';
14
14
  static description = 'Erase Mark (Complex Action, SR5 p.239): "unmark me" scrubs the marks others hold on your persona; "unmark <icon>" needs three marks on that icon first. Computer + Logic [Attack] v. Willpower + Firewall. An Attack action -- GOD counts it. Also "erase mark on <icon>".';
15
15
  static npcPolicy = 'authorized';
16
+ /**
17
+ * A PLACER'S NAME STARTING A SENTENCE. `hostLabel` yields "the Approach
18
+ * host", lowercase and correct mid-clause -- and these lines open with
19
+ * it, so a bench read "the Approach host's key sloughs off...". The
20
+ * same class of blemish grid-names.ts records at length: cosmetic, and
21
+ * not harmless on a repro bench, where a reviewer meeting broken prose
22
+ * reasonably starts doubting the fixture.
23
+ */
24
+ static opening(name) {
25
+ return name.charAt(0).toUpperCase() + name.slice(1);
26
+ }
16
27
  /** p.239: two marks at -4, three at -10; one is unpenalised. */
17
28
  static penaltyFor(count) {
18
29
  if (count >= 3)
@@ -180,7 +191,7 @@ export class EraseMarkCommand extends Command {
180
191
  if (attempt.hits <= resist.hits) {
181
192
  this.logger.write(`${actor.name} failed Erase Mark on ${label} (${chosen.name}): ${attempt.hits} v ${resist.hits}.`);
182
193
  return [
183
- `The key holds. ${chosen.name}'s mark is still written into ${label} and your scrub slides off it.`,
194
+ `The key holds. ${EraseMarkCommand.opening(chosen.name)}'s mark is still written into ${label} and your scrub slides off it.`,
184
195
  hint(` (A Complex Action each try${take > 1 ? `; going for ${take} at once cost you ${penalty} dice` : ''}.)`),
185
196
  ...(god.length > 0 ? [`\n${god.join('\n')}`] : []),
186
197
  ].join('');
@@ -192,7 +203,7 @@ export class EraseMarkCommand extends Command {
192
203
  this.logger.write(`${actor.name} erased ${take} of ${chosen.name}'s mark(s) on ${label}: ${attempt.hits} v ${resist.hits}.`);
193
204
  const left = this.remainingOn(target, actor);
194
205
  return [
195
- `{light-blue-fg}${chosen.name}'s ${take > 1 ? `${take} keys slough` : 'key sloughs'} off ${label} -- the recognition pattern unwrites itself and ${target.kind === 'self' ? 'your icon stops answering to it' : 'the icon forgets it ever agreed'}.{/light-blue-fg}`,
206
+ `{light-blue-fg}${EraseMarkCommand.opening(chosen.name)}'s ${take > 1 ? `${take} keys slough` : 'key sloughs'} off ${label} -- the recognition pattern unwrites itself and ${target.kind === 'self' ? 'your icon stops answering to it' : 'the icon forgets it ever agreed'}.{/light-blue-fg}`,
196
207
  target.kind === 'self'
197
208
  ? (left > 0
198
209
  ? `\n${left} mark${left === 1 ? '' : 's'} still on you.`
@@ -90,7 +90,9 @@ export class MessageCommand extends Command {
90
90
  }
91
91
  const text = rest.join(' ');
92
92
  try {
93
- const res = await sr.HubLink.call('sideQuest.message', { handle: target.handle, text });
93
+ const res = await sr.HubLink.call(
94
+ // `from` names the SPEAKER (t8qhbB3c3PRRkq5sP) -- see say.ts.
95
+ 'sideQuest.message', { handle: target.handle, text, from: this.actor.name });
94
96
  const landed = res.reach === 'online'
95
97
  ? `They're on the street -- it lands now.`
96
98
  : `They're off the grid; it waits on their link until they jack in.`;
@@ -265,6 +265,16 @@ export class OrderCommand extends Command {
265
265
  // Result strings that mean the atomic tier bounced -- collected from
266
266
  // real refusals (go/attack/talk/take across sessions). The ’ variant
267
267
  // covers commands that answer with a smart quote.
268
- static ATOMIC_REFUSAL = /not a way to go|can['’]t go that way|isn['’]t here|don['’]t see|there is no item|too heavy|doesn['’]t know how|not valid|doesn['’]t seem to have/i;
268
+ //
269
+ // THE MATRIX REFUSALS WERE MISSING, and a repro bench found it the day
270
+ // sprites started being billed at all (wjFBY3zgyWzJP9adw). Order a
271
+ // sprite at a maglock slaved to a host you hold no mark on and `hack`
272
+ // answers "a host's devices answer nobody who holds no mark on the
273
+ // host itself" -- a refusal, nothing rolled, nothing changed. It
274
+ // matched none of the phrases below, so the atomic tier read it as
275
+ // obedience and charged a task for it. Free before this only because
276
+ // no sprite was ever charged for anything; a spirit ordered into the
277
+ // same wall has always paid a service for nothing.
278
+ static ATOMIC_REFUSAL = /not a way to go|can['’]t go that way|isn['’]t here|don['’]t see|there is no item|too heavy|doesn['’]t know how|not valid|doesn['’]t seem to have|answer nobody who holds no mark|no cyberdeck|needs a MARK|hold none on|is not here to|nothing here answers to|finds no persona|finds no device/i;
269
279
  }
270
280
  //# sourceMappingURL=order.js.map
@@ -208,8 +208,16 @@ export class SayCommand extends Command {
208
208
  try {
209
209
  if (channel.party) {
210
210
  // THE PARTY LINE: one say, every accepted seat hears it.
211
+ //
212
+ // `from` NAMES THE SPEAKER (t8qhbB3c3PRRkq5sP, live
213
+ // 2026-09-16: "Ted says Hi, who's Ted?" -- Ted being another
214
+ // character on the speaker's account). This call used to
215
+ // carry the text alone, so the server had nothing to sign it
216
+ // with but the account's presence row, which names whichever
217
+ // runner beat last and can be a day stale. The 1:1 branch
218
+ // below always sent `from`; the party line simply never did.
211
219
  const sr = await import('../utilities/shared-run.js');
212
- await sr.HubLink.call('sideQuest.partyPage', { text: message });
220
+ await sr.HubLink.call('sideQuest.partyPage', { text: message, from: currentPlayer.name });
213
221
  }
214
222
  else {
215
223
  const transport = await this.game?.streetTransport();
@@ -741,5 +741,44 @@
741
741
  // - PURGED: the dead `firearms` skill key from the NPC prompt, the
742
742
  // ganger constant and the seed doc; a seed still carrying it maps
743
743
  // onto pistols/automatics/longarms at the boundary.
744
- export const ENGINE_VERSION = '1.64.0';
744
+ // 1.65.0 (2026-09-16): THREE THINGS THE FIRST SPRITE BENCH FOUND. The
745
+ // repro bench for wjFBY3zgyWzJP9adw made an ordered sprite's dice
746
+ // visible for the first time, and visible dice are readable dice.
747
+ // - A SPRITE'S MATRIX ARRAY IS ITS OWN (p.254, p.259). It carries no
748
+ // deck, so baseMatrixAttribute's rig lookup returned 0 and every
749
+ // bracketed sprite roll computed a limit of zero -- which rollPool
750
+ // refuses as "not a limit" and said so, out loud, in the
751
+ // transcript. commands/compile.ts now stamps the book's per-type
752
+ // table (sprite-powers.spriteMatrix) onto the shell, so [Sleaze],
753
+ // [Attack] and [Data Processing] finally have numbers in them.
754
+ // Only Resonance equals Level; the four attributes do not.
755
+ // - A REFUSED ORDER MUST NOT COST A TASK. order.ts decides the atomic
756
+ // tier bounced by matching the result against a phrase list, and
757
+ // the Matrix refusals were never in it -- so a sprite ordered at a
758
+ // maglock slaved to a host it holds no mark on was told no AND
759
+ // charged for it. Free before only because sprites were charged for
760
+ // nothing; a spirit walked into the same wall and paid a service.
761
+ // - Erase Mark opened two lines with a host's lowercase label ("the
762
+ // Approach host's key sloughs off..."). Cosmetic, and the same
763
+ // class of blemish grid-names.ts records at length, because a
764
+ // reviewer meeting broken prose on a bench doubts the fixture.
765
+ // 1.66.0 (2026-09-16): THE CREW CHANNEL NAMES WHO SPOKE
766
+ // (t8qhbB3c3PRRkq5sP, live: "Ted says Hi, who's Ted?" -- Ted being
767
+ // another character on the speaker's account, who was playing Jynx).
768
+ // A page is signed server-side, and for the PARTY LINE the server had
769
+ // nothing to sign with but the account's presence row: ONE PER
770
+ // ACCOUNT, naming whichever runner heartbeated last, and never written
771
+ // at all by the browser or a hosted session. The reported row was a
772
+ // day stale, so every crew line that evening went out under a
773
+ // character nobody at the table was playing.
774
+ // - say.ts's party branch and call.ts's openPartyLine now send
775
+ // `from` -- the speaking actor -- exactly as the 1:1 branch beside
776
+ // them always has. `message` too.
777
+ // - game.ts's default street `send` stops DROPPING the `from` its own
778
+ // signature documents as "the sending ACTOR, which a multi-human
779
+ // server scene resolves to the right account".
780
+ // The name is still only a claim: the server verifies it against the
781
+ // account's seats and saves before stamping it, and an older client
782
+ // that sends none keeps the presence fallback.
783
+ export const ENGINE_VERSION = '1.66.0';
745
784
  //# sourceMappingURL=engine-version.js.map
@@ -2368,7 +2368,13 @@ export default class Game {
2368
2368
  const players = await fetchPlayers().catch(() => undefined);
2369
2369
  return (players ?? []).map(p => ({ playerName: p.playerName, handle: p.handle }));
2370
2370
  },
2371
- send: ({ handle, text }) => sr.HubLink.call('sideQuest.page', { handle, text }),
2371
+ // `from` IS PASSED ON, NOT DROPPED (t8qhbB3c3PRRkq5sP): the
2372
+ // signature has always named the sending actor so that a
2373
+ // multi-human scene resolves it to the right account -- this
2374
+ // default quietly threw it away, leaving the server to sign the
2375
+ // page from the account's presence row (one per ACCOUNT, naming
2376
+ // whichever runner heartbeated last).
2377
+ send: ({ from, handle, text }) => sr.HubLink.call('sideQuest.page', { handle, text, from }),
2372
2378
  };
2373
2379
  }
2374
2380
  /**
@@ -630,6 +630,14 @@ export class Player extends AbstractPlayer {
630
630
  * long as the sprite.
631
631
  */
632
632
  cookiedBy = new Map();
633
+ /**
634
+ * A SPRITE'S FOUR MATRIX ATTRIBUTES (SR5 p.254, p.259), stamped on the
635
+ * shell by commands/compile.ts. A sprite carries no deck, so without
636
+ * this every bracketed sprite roll computed a limit of 0 -- which
637
+ * rollPool rightly refuses as "not a limit" rather than honouring.
638
+ * Only Resonance equals Level; the four attributes are per TYPE.
639
+ */
640
+ spriteMatrixAttrs;
633
641
  /**
634
642
  * DIAGNOSTICS (p.257): the Teamwork bonus a machine sprite is holding
635
643
  * on ONE device -- "it takes the sprite's entire attention", so there
@@ -907,6 +915,16 @@ export class Player extends AbstractPlayer {
907
915
  baseMatrixAttribute(kind) {
908
916
  if (this.icHost)
909
917
  return this.icHost.attributes()[kind];
918
+ // A SPRITE'S ARRAY IS ITS OWN (SR5 p.254, p.259). It has no deck, so
919
+ // the rig lookup below returned 0 -- and a 0 reaching rollPool is
920
+ // refused as "not a limit", which is exactly what a repro bench
921
+ // caught the day an ordered sprite's dice first became visible
922
+ // (wjFBY3zgyWzJP9adw): the roll happened, unlimited, and said so.
923
+ // Set on the shell at compile time from sprite-powers.spriteMatrix,
924
+ // which carries the book's per-type table; only Resonance equals
925
+ // Level, the four attributes do not.
926
+ if (this.spriteMatrixAttrs)
927
+ return this.spriteMatrixAttrs[kind];
910
928
  if (this.isTechnomancer()) {
911
929
  switch (kind) {
912
930
  case 'attack': return this.charisma;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.202.0",
3
+ "version": "5.204.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.",