@maka/maka-cli 5.187.0 → 5.188.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.187.0",
3
+ "version": "5.188.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.",
@@ -13,6 +13,7 @@ import { Logger } from '../utilities/logger.js';
13
13
  import { migrateLegacySeed } from './seed-migration.js';
14
14
  import { Device } from '../models/device.js';
15
15
  import { fuzzyPickName } from '../utilities/fuzzy-match.js';
16
+ import { adoptSeededIce } from '../utilities/ic-actors.js';
16
17
  /**
17
18
  * How many AI enrichment calls may be in flight at once.
18
19
  *
@@ -252,6 +253,17 @@ Key Locations: ${json.rooms.map(r => r.name).join(', ')}
252
253
  // architecture nobody wrote.
253
254
  if (isIce && npc.currentLocation?.hasNode) {
254
255
  npc.insideHost = npc.currentLocation;
256
+ // ...AND THE HOST HAS TO KNOW IT IS RUNNING IT (mPCh2FJykPsyJKmcc's
257
+ // bench, 2026-09-14). Standing inside the node was only half the
258
+ // adoption: nothing registered the construct with the Host, so it
259
+ // was ice by every reading except the one the host itself uses.
260
+ // The host then launched its own twin on the first Combat Turn
261
+ // (p.247 forbids two of a type), the construct swung with an
262
+ // Attack of 0 because "IC uses the Matrix attributes of its host"
263
+ // is read off icHost, and the grid view listed it twice. See
264
+ // adoptSeededIce for the three-for-one.
265
+ if (npc.currentLocation.host)
266
+ adoptSeededIce(npc, npc.currentLocation.host);
255
267
  }
256
268
  npc.scene = scene;
257
269
  builtNpcs.push(npc);
@@ -299,8 +299,23 @@ function hostInteriorIcons(scene, actor, room) {
299
299
  // and that would put the wrong noun on a person.
300
300
  // Inside a host, the roster is who is INSIDE it (matrix-roster.ts) -- a
301
301
  // persona's body is never in this room.
302
+ // THE HOST'S OWN PROGRAMS ARE LISTED ONCE, BELOW, NOT TWICE, HERE AND
303
+ // BELOW (mPCh2FJykPsyJKmcc's bench, 2026-09-14). A running IC is an
304
+ // actor inside the host AND a name in room.runningIC, and both loops
305
+ // printed it -- in different words, with only the second offering the
306
+ // verbs, so one program read as two and the reader had to guess which
307
+ // line was real:
308
+ //
309
+ // ▲ Patrol IC #2 -- intrusion countermeasures, and you are inside its host.
310
+ // ▲ Patrol IC #2 -- hunting, and it has your icon. (0/10) ("attack ..." crash it)
311
+ //
312
+ // hostInteriorPanel already resolved this the right way round -- it
313
+ // skips `a.icHost === host` in its persona list -- so this matches it
314
+ // rather than inventing a third rule. Everything else inside the host
315
+ // still comes through here: a rival decker's persona, a companion, a
316
+ // construct nothing registered as the host's.
302
317
  for (const a of (room.host ? personasInside(scene, room.host) : [])) {
303
- if (a === actor)
318
+ if (a === actor || a.icHost === room.host)
304
319
  continue;
305
320
  if (a.plane === 'matrix' && sameHostSide(actor, a) && actor.canPerceive(a)) {
306
321
  const companion = scene.ownerGame?.companions.find(c => c.npc === a);
@@ -350,11 +365,16 @@ function hostInteriorIcons(scene, actor, room) {
350
365
  // game will not name, and a room that contradicts the damage log reads
351
366
  // as broken rules rather than thin prose.
352
367
  //
353
- // NO VERB IS OFFERED, deliberately, because none exists yet: IC live
354
- // in room.runningIC as names, not as actors, so nothing in this engine
355
- // can target them -- `thread Resonance Spike` says "no hostile icon in
356
- // reach" while they attack. Naming them here does not pretend
357
- // otherwise; advertising a verb that refuses would be the worse lie.
368
+ // A VERB IS OFFERED NOW, where there is an actor to point it at. When
369
+ // this loop was written IC lived in room.runningIC as names only and
370
+ // nothing could target them, so it deliberately advertised nothing;
371
+ // ic-actors.ts made each running program an actor, and the line grew
372
+ // the monitor and the verbs to match. A kind with no actor behind it
373
+ // (a scene that cannot host actors at all) still gets named and still
374
+ // offers nothing, for the original reason.
375
+ //
376
+ // THIS IS THE ONE PLACE THE HOST'S OWN PROGRAMS ARE LISTED -- see the
377
+ // skip in the persona loop above.
358
378
  for (const name of room.runningIC) {
359
379
  const ice = room.host?.iceActors.get(name);
360
380
  icons.push(`▲ ${ice?.name ?? name} -- hunting, and it has your icon.${ice ? ` (${ice.conditionSummary()}) ("thread resonance-spike ${ice.name}" / "attack ${ice.name}" crash it)` : ''}`);
@@ -1,6 +1,7 @@
1
1
  import { NPC } from '../models/npc.js';
2
2
  import { CommandRegistry } from '../commands/command-registry.js';
3
3
  import { Logger } from './logger.js';
4
+ import { IC_TYPES } from './ic.js';
4
5
  /**
5
6
  * IC AS ICONS (increment 5 of the Matrix position model, 2026-09-02).
6
7
  * SR5 p.247: "Each IC program has a persona with its own Condition
@@ -95,4 +96,51 @@ export function crashedIC(host) {
95
96
  }
96
97
  return out;
97
98
  }
99
+ /**
100
+ * ADOPT A SEEDED CONSTRUCT AS ONE OF ITS HOST'S PROGRAMS
101
+ * (mPCh2FJykPsyJKmcc's bench, 2026-09-14).
102
+ *
103
+ * scene-factory already settles what a matrix-plane NPC IS -- "a
104
+ * matrix-plane NPC in this engine IS intrusion countermeasures" -- and
105
+ * already stands it inside the node it guards. What it never did was
106
+ * tell the HOST. So a seeded construct was ice by every reading except
107
+ * the one the host itself uses, and three things went wrong at once,
108
+ * all of them visible in one bench transcript:
109
+ *
110
+ * 1. THE HOST LAUNCHED ITS TWIN. hostLaunchStep picks the first
111
+ * IC_TYPE not in `runningIC`, and a seeded "Patrol IC" was not in
112
+ * it -- so the host launched a second Patrol on the first Combat
113
+ * Turn and the player fought "Patrol IC" and "Patrol IC #2" at
114
+ * once. Straight against p.247: a host "can't launch more than one
115
+ * of each type of IC program at once."
116
+ * 2. IT ATTACKED WITH NO LIMIT. "IC uses the Matrix attributes of its
117
+ * host" (p.247) is read off `icHost` (Player.baseMatrixAttribute).
118
+ * Unset, a construct's Attack was 0, so every swing it took
119
+ * printed dice.ts's caller-bug diagnostic to the player:
120
+ * `[LIMIT IGNORED -- a caller computed one that is not a limit]`.
121
+ * 3. IT WAS LISTED TWICE, once as an icon inside the host and again
122
+ * off `runningIC` (grid-view.ts), with different words each time.
123
+ *
124
+ * One registration, three symptoms -- which is the argument for fixing
125
+ * it here at the seam rather than three times downstream.
126
+ *
127
+ * THE KIND IS THE CANON NAME WHEN THE SEED USED ONE. A construct called
128
+ * "Patrol IC" IS the host's Patrol, and registering it under its own
129
+ * name would leave the launch step free to add the real one beside it --
130
+ * the bug. A construct with a name of its own ("Sentinel", "the
131
+ * Gatekeeper") registers under that name: it counts against the host's
132
+ * Rating cap because it is a program the host is running, and it blocks
133
+ * no canon type, because it is not one.
134
+ */
135
+ export function adoptSeededIce(npc, host) {
136
+ const canon = IC_TYPES.find(t => t.name.toLowerCase() === npc.name.trim().toLowerCase());
137
+ const kind = canon?.name ?? npc.name;
138
+ npc.icHost = host;
139
+ npc.icKind = kind;
140
+ npc.matrixPosition = { kind: 'host', host };
141
+ if (!host.iceActors.has(kind))
142
+ host.iceActors.set(kind, npc);
143
+ if (!host.runningIC.includes(kind))
144
+ host.runningIC.push(kind);
145
+ }
98
146
  //# sourceMappingURL=ic-actors.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.187.0",
3
+ "version": "5.188.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.",