@maka/maka-cli 5.377.0 → 5.378.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.377.0",
3
+ "version": "5.378.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.",
@@ -1,6 +1,6 @@
1
1
  import { Command } from './command.js';
2
2
  import { sameSpot, spotOf, spotRefusal } from '../utilities/spots.js';
3
- import { TREAT_PRICE_PER_BOX, applyMedicineCare, isClinicRoom, isStreetDoc } from '../utilities/street-doc.js';
3
+ import { TREAT_PRICE_PER_BOX, applyMedicineCare, isClinicRoom, isStreetDoc, woundWords, DOCTOR_TALK } from '../utilities/street-doc.js';
4
4
  /**
5
5
  * Street-doc services (SR5e p.42, "Staying Healthy"): paid physical
6
6
  * healing at a clinic -- the certain, expensive alternative to burning
@@ -58,7 +58,7 @@ export class TreatCommand extends Command {
58
58
  this.logger.write(`TreatCommand: ${doc.name} healed ${healed} boxes for ${cost} (${actor.currency} left; ${actor.damageTaken}/${actor.maxConditionBoxes}).`);
59
59
  this.scene.addWorldEvent(`${actor.name} paid for treatment at ${room.name}.`);
60
60
  this.scene.updateStatus();
61
- void Promise.resolve(doc.hear(actor, `Patch me up. [System note: you just treated ${actor.name} for ${cost} nuyen, ${healed} boxes closed${actor.damageTaken > 0 ? ' -- more damage remains but they ran out of cred' : ''}. React briefly, in character.]`)).catch(err => {
61
+ void Promise.resolve(doc.hear(actor, `Patch me up. [System note: you just treated ${actor.name} for ${cost} nuyen. They are now ${woundWords(actor.damageTaken, actor.maxConditionBoxes)}${actor.damageTaken > 0 ? ' (they ran out of cred for the rest)' : ''}. React briefly, in character. ${DOCTOR_TALK}]`)).catch(err => {
62
62
  this.logger.error(`${doc.name} failed to hear the treatment: ${err}`);
63
63
  });
64
64
  const lines = [
@@ -69,7 +69,9 @@ export class TreatCommand extends Command {
69
69
  ` The doc doesn't ask for a name -- cash is its own paperwork down here.`,
70
70
  ];
71
71
  if (actor.damageTaken > 0) {
72
- lines.push(` "${actor.damageTaken} more when you can afford it. Try not to reopen my work."`);
72
+ // The count is on the receipt line above; the doc's own words carry
73
+ // none (7G2avXprhjrawdc7L -- a doc does not speak in boxes).
74
+ lines.push(` "I'll close the rest when you can afford it. Try not to reopen my work."`);
73
75
  // MEDICINE'S AFTERCARE (p.207-208; XpW98XthhN4biT4gM): the doc's
74
76
  // one Medicine + Logic test on this set of wounds rides the boxes
75
77
  // the patient could not pay for as bonus dice on their recovery
@@ -3228,5 +3228,12 @@
3228
3228
  // a 0-hit defence starts the tally but adds nothing (XR9xDyyxygCGzTLCz).
3229
3229
  // - A runner carrying a working deck or RCC no longer has a looted
3230
3230
  // commlink worn for them at session load (p.223, RsnjkLpgLcSmsrzKa).
3231
- export const ENGINE_VERSION = '1.189.0';
3231
+ // 1.190.0 (2026-10-04): VOICES, NOT TEMPLATES.
3232
+ // - The arc's Johnson picks up in their own AI voice, told the gist the
3233
+ // fixed quote used to print; the quote is the AI-off fallback
3234
+ // (mYocnosxLvj24CuWt: "this should be Mr. Halyard speaking").
3235
+ // - The street doc is told how the patient is in a body's words and is
3236
+ // barred from "boxes" and other screen terms, in the treat note and in
3237
+ // the brief (7G2avXprhjrawdc7L: "three boxes left ... breaks the fiction").
3238
+ export const ENGINE_VERSION = '1.190.0';
3232
3239
  //# sourceMappingURL=engine-version.js.map
@@ -4721,11 +4721,11 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4721
4721
  const knows = `"${pending.name}" -- ${pending.story} ${meetRoom ? `The meet is at ${meetRoom}; name that place and no other.` : 'You will find the runner when they arrive; never name a venue.'}`;
4722
4722
  if (this.pendingRunAccepted) {
4723
4723
  this.openJohnsonLine(`${knows} The runner has ALREADY ACCEPTED; the deal stands and the cab is on your account.`);
4724
- return `${j} picks up. "We've shaken on it. The cab's on my account -- get moving."${hint(` ("call taxi" when you're ready -- "end call" hangs up.)`)}`;
4724
+ return this.johnsonPicksUp(`We've shaken on it. The cab's on my account -- get moving.`, ` ("call taxi" when you're ready -- "end call" hangs up.)`);
4725
4725
  }
4726
- const where = meetRoom ? ` "Meet me at ${meetRoom}."` : ` "I'll find you when you arrive."`;
4726
+ const where = meetRoom ? ` Meet me at ${meetRoom}.` : ` I'll find you when you arrive.`;
4727
4727
  this.openJohnsonLine(`${knows} The runner has NOT accepted yet: they say they accept, or they pass -- and passing ends your operation.`);
4728
- return `${j} picks up. "${pending.story}"${where} "Same as last time -- the number we settle face to face."${hint(`\n(You're on the line with ${j}: "accept" locks it in, "decline" passes -- and passing ends the operation.)`)}`;
4728
+ return this.johnsonPicksUp(`${pending.story}${where} Same as last time -- the number we settle face to face.`, `\n(You're on the line with ${j}: "accept" locks it in, "decline" passes -- and passing ends the operation.)`);
4729
4729
  }
4730
4730
  // THE CHAPTER WAITS IN THE DRAWER (it landed while another job held
4731
4731
  // the table): calling the Johnson brings it onto the table and they
@@ -4735,7 +4735,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4735
4735
  const refused = this.takeFromDrawer(waiting);
4736
4736
  if (refused) {
4737
4737
  this.openJohnsonLine(`Your next chapter is ready, but the runner is committed to another job tonight. Yours keeps until they are back.`);
4738
- return `${j} picks up. "You're committed elsewhere tonight. Mine keeps -- call me when you're back."${hint(` ("end call" hangs up.)`)}`;
4738
+ return this.johnsonPicksUp(`You're committed elsewhere tonight. Mine keeps -- call me when you're back.`, ` ("end call" hangs up.)`);
4739
4739
  }
4740
4740
  return this.callOperationJohnson(said);
4741
4741
  }
@@ -4743,7 +4743,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4743
4743
  if (!gate.allowed) {
4744
4744
  const busy = gate.message ?? 'Working on it.';
4745
4745
  this.openJohnsonLine(`You have nothing new for the runner right now: "${busy}"`);
4746
- return `${j} picks up. "${busy}"${hint(` ("end call" hangs up.)`)}`;
4746
+ return this.johnsonPicksUp(busy, ` ("end call" hangs up.)`);
4747
4747
  }
4748
4748
  const beat = op.beats[op.nextBeat];
4749
4749
  // THE SIZE IS STILL THE PLAYER'S (job-order.ts): "call Veil, something
@@ -4752,7 +4752,27 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4752
4752
  // client does not deal in milk runs. The SHAPE is the beat's.
4753
4753
  this.draftNextSceneInBackground({ size: parseJobSize(said) ?? 'large', runType: beat.kind, chapter: true });
4754
4754
  this.openJohnsonLine(`Chapter ${op.nextBeat + 1} of "${op.title}": ${beat.brief} You are putting the details together and will message the runner the where and when shortly.`);
4755
- return `${j} picks up. "Chapter ${op.nextBeat + 1}: ${beat.brief} Give me a minute -- I'll send the where and when."${hint(` ("end call" hangs up -- the job comes as a message.)`)}`;
4755
+ return this.johnsonPicksUp(`Chapter ${op.nextBeat + 1}: ${beat.brief} Give me a minute -- I'll send the where and when.`, ` ("end call" hangs up -- the job comes as a message.)`);
4756
+ }
4757
+ /**
4758
+ * THE JOHNSON SPEAKS FOR THEMSELVES (mYocnosxLvj24CuWt, Maka: "I'm still
4759
+ * getting canned text, this should be Mr. Halyard speaking"). 1.180.0
4760
+ * opened a real line, but the pickup was still a fixed quote. Krow's
4761
+ * business call already works this way (fixerForBusiness, call.ts): with
4762
+ * AI on, the voice picks up off a note and says the GIST in its own words;
4763
+ * the fixed quote is only the AI-off fallback. The gist is the same
4764
+ * sentence the quote was, and the hint (the verbs) stays out of fiction.
4765
+ */
4766
+ johnsonPicksUp(gist, hintText) {
4767
+ const voice = this._johnsonVoice;
4768
+ const me = this.player;
4769
+ const j = voice?.name ?? this._operation?.johnson.name ?? 'The client';
4770
+ if (this.aiOn && voice && me && me.activeCallPartner === voice) {
4771
+ // hear() never rethrows (models/npc.ts), so fire-and-forget is safe.
4772
+ void voice.hear(me, `[System note: ${me.name} is calling you and you have picked up. Tell them this in your own voice and words, and nothing more: "${gist}" Add no new facts, places or numbers.]`, { viaLink: true });
4773
+ return `${j} picks up.${hint(hintText)}`;
4774
+ }
4775
+ return `${j} picks up. "${gist}"${hint(hintText)}`;
4756
4776
  }
4757
4777
  /**
4758
4778
  * The cab that answers "call taxi" varies per job (player request: not
@@ -44,7 +44,29 @@ export function treatHint(price = TREAT_PRICE_PER_BOX) {
44
44
  /** The doc's standing orders in the AI brief: treatment is the trade,
45
45
  * and the word for it is "treat". */
46
46
  export function streetDocBrief(price = TREAT_PRICE_PER_BOX) {
47
- return `You are this clinic's STREET DOC and treatment is your trade: you close physical wounds for ${price} nuyen a box, cash up front, no names asked. The player makes it happen by typing the command "treat" -- when anyone asks for help with wounds, tell them that word plainly and quote the price. Never say you cannot help a paying patient and never leave them with a diagnosis alone; if they are broke, name the price and mean it. Stun is not your department -- sleep is free.`;
47
+ return `You are this clinic's STREET DOC and treatment is your trade: you close physical wounds, ${price} nuyen for each one you close, cash up front, no names asked. The player makes it happen by typing the command "treat" -- when anyone asks for help with wounds, tell them that word plainly and quote the price. Never say you cannot help a paying patient and never leave them with a diagnosis alone; if they are broke, name the price and mean it. Stun is not your department -- sleep is free. ${DOCTOR_TALK}`;
48
+ }
49
+ /**
50
+ * A DOCTOR TALKS ABOUT BODIES, NOT BOOKKEEPING (7G2avXprhjrawdc7L, Maka:
51
+ * "You've got three boxes left ... this breaks the fiction"). The brief
52
+ * priced treatment "a box" and treat.ts told the doc how many "boxes
53
+ * closed", and the model said it back. Boxes are the player's screen;
54
+ * the doc sees cuts, bruising, broken ribs. Every note to the doc ends
55
+ * with this, and woundWords() is the fiction for how bad it still is.
56
+ */
57
+ export const DOCTOR_TALK = `Speak as a doctor about a body -- cuts, bleeding, bruising, ribs, stitches, rest. NEVER say "box", "boxes", "condition monitor", "damage", "dice" or any count of them; those are the player's screen, not words a person uses.`;
58
+ /** How bad the patient still is, in words a doctor would see. */
59
+ export function woundWords(taken, max) {
60
+ if (taken <= 0)
61
+ return 'patched up completely -- nothing left open';
62
+ const share = max > 0 ? taken / max : 1;
63
+ if (share <= 0.25)
64
+ return 'mostly mended -- a few shallow cuts and bruising left';
65
+ if (share <= 0.5)
66
+ return 'still carrying real wounds -- sore, stiff, nothing reopening if they take it easy';
67
+ if (share <= 0.75)
68
+ return 'still badly hurt -- deep wounds you could not get to';
69
+ return 'barely holding together -- most of the damage is still open';
48
70
  }
49
71
  /**
50
72
  * Medicine + Logic, once per set of wounds (p.208): the hits ride on the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.377.0",
3
+ "version": "5.378.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.",