@maka/maka-cli 5.193.0 → 5.194.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.193.0",
3
+ "version": "5.194.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.",
@@ -91,6 +91,14 @@ export class LookCommand extends Command {
91
91
  .getActorsInRoom(this.actor.currentLocation)
92
92
  .find(a => a.name.toLowerCase() === target.toLowerCase() && this.actor.canPerceive(a));
93
93
  if (exactActorMatch) {
94
+ // THE FACE IS WRITTEN WHEN SOMEBODY ACTUALLY LOOKS (2026-09-14).
95
+ // Authored appearances (the hub's regulars) are already set and
96
+ // return immediately; a generated run's stranger gets theirs
97
+ // here, once, instead of every NPC in the scene being written up
98
+ // at boot for text most of them never show.
99
+ if (exactActorMatch instanceof NPC) {
100
+ await exactActorMatch.ensureAIAppearance(this.scene.story ?? '');
101
+ }
94
102
  return this.inspectActor(exactActorMatch.name);
95
103
  }
96
104
  if (this.actor.inventory.hasItem(target)) {
@@ -19,6 +19,13 @@ export class NPCFactory {
19
19
  // Native off-plane residents: ice lives on the Matrix, spirits on the
20
20
  // astral. They have no body to leave behind -- the plane IS their home.
21
21
  npc.plane = json.plane ?? 'meat';
22
+ // AN AUTHORED FACE IS FINAL (2026-09-14). Seeding the appearance also
23
+ // closes the door on the generator: setAuthoredAppearance marks it
24
+ // written, so ensureAIAppearance returns early and the district's
25
+ // regulars keep the same face every visit instead of being re-invented
26
+ // on each hub entry.
27
+ if (json.appearance)
28
+ npc.setAuthoredAppearance(json.appearance);
22
29
  return npc;
23
30
  }
24
31
  convertPlayerSeedToConstructorConfig(seed) {
@@ -2538,28 +2538,6 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
2538
2538
  get pendingRide() {
2539
2539
  return this._pendingRide;
2540
2540
  }
2541
- /**
2542
- * Generates NPC first-impression appearances ("look at <npc>") in the
2543
- * background, one at a time -- the only AI dressing still worth doing
2544
- * now that every scene arrives with real prose. Fire-and-forget: until
2545
- * an appearance lands, look-at just shows a bit less flavor.
2546
- */
2547
- warmNpcAppearancesInBackground() {
2548
- if (!this._useAi)
2549
- return;
2550
- const npcs = this.scene.allActors.filter((a) => a instanceof NPC);
2551
- const context = `${this.sceneSeed?.name ?? ''} -- ${this.scene.story}`;
2552
- void (async () => {
2553
- for (const npc of npcs) {
2554
- try {
2555
- await npc.ensureAIAppearance(context);
2556
- }
2557
- catch {
2558
- // Non-fatal: the next look-at simply has less flavor.
2559
- }
2560
- }
2561
- })();
2562
- }
2563
2541
  // A single fixed room, created once and never torn down across job
2564
2542
  // transitions -- the player's own place, unlike every job's generated
2565
2543
  // rooms which get discarded wholesale when the next job replaces them.
@@ -3271,7 +3249,6 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
3271
3249
  // (player request). Occupied slots (archetype signature gear) are
3272
3250
  // never swapped out.
3273
3251
  equipIntoEmptySlots(this.player);
3274
- this.warmNpcAppearancesInBackground();
3275
3252
  this.startPursuitHeartbeat();
3276
3253
  this.startClockTicker();
3277
3254
  this.startMapHeartbeat();
@@ -4753,7 +4730,6 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4753
4730
  const arrivalLines = this.unfoldCompanionsOnArrival();
4754
4731
  // The crew meets you at the jobsite (commands/crew.ts, lead.ts).
4755
4732
  const allyLines = this.spawnCrew();
4756
- this.warmNpcAppearancesInBackground();
4757
4733
  this.refreshLogLabel();
4758
4734
  // THE MEET opens the job (canon p.28): the seed's client is this
4759
4735
  // run's Johnson -- track them, and point the arrival at the meet.
@@ -913,10 +913,38 @@ Available in-game commands (use with [COMMAND] prefix):
913
913
  return this._appearance;
914
914
  }
915
915
  /**
916
- * Generates a spoiler-free, player-facing first impression once per scene
917
- * load. Deliberately kept separate from `_description`, which holds
918
- * GM-only behavior notes (e.g. "will kill on sight") that would ruin the
919
- * game if surfaced through `look at <npc>`.
916
+ * THE SEED WROTE THIS FACE, so nothing may write it again
917
+ * (2026-09-14). Setting `hasAIAppearance` is the whole point: it is
918
+ * the same latch ensureAIAppearance sets after generating, so an
919
+ * authored appearance and a generated one are indistinguishable to
920
+ * every reader, and neither is ever overwritten.
921
+ *
922
+ * Used by the NPC factory for a seed carrying `appearance` -- the hub's
923
+ * twelve regulars, who are authored content and must keep their faces
924
+ * between visits.
925
+ */
926
+ setAuthoredAppearance(appearance) {
927
+ this._appearance = appearance;
928
+ this.hasAIAppearance = true;
929
+ }
930
+ /**
931
+ * Generates a spoiler-free, player-facing first impression. Deliberately
932
+ * kept separate from `_description`, which holds GM-only behavior notes
933
+ * (e.g. "will kill on sight") that would ruin the game if surfaced
934
+ * through `look at <npc>`.
935
+ *
936
+ * CALLED ON FIRST LOOK, NOT ON SCENE BOOT (2026-09-14, mjmcee: "why are
937
+ * they being regnerated?"). This used to be warmed for EVERY NPC in the
938
+ * scene the moment it loaded -- twelve calls per hub entry, measured in
939
+ * production, for text that is read only if the player looks at that
940
+ * particular person, and most of them are never looked at.
941
+ *
942
+ * The cost of waiting until the look is one short call in front of one
943
+ * reply the player explicitly asked for. The cost of warming was twelve
944
+ * calls per visit whether or not anyone ever looked, and it did not even
945
+ * buy stability: every visit rebuilt the NPCs and re-invented all of
946
+ * them. Authored appearances (setAuthoredAppearance) answer the second
947
+ * half; this answers the first.
920
948
  */
921
949
  async ensureAIAppearance(sceneContext) {
922
950
  if (this.hasAIAppearance)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.193.0",
3
+ "version": "5.194.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.",