@maka/maka-cli 5.379.0 → 5.379.1

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.379.0",
3
+ "version": "5.379.1",
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.",
@@ -7,7 +7,8 @@ import { fuzzyPickName } from '../utilities/fuzzy-match.js';
7
7
  import { fileReach, planeTintItemName } from '../utilities/planes.js';
8
8
  import { hostLabel } from '../utilities/grid-names.js';
9
9
  import { editFileBlocked, rollEditFile } from '../utilities/edit-file-test.js';
10
- import { copyFile, deviceHas, fileOnto, findDataDevice, libraryDevice, receiveData } from '../utilities/data-library.js';
10
+ import { copyFile, deviceHas, fileOnto, findDataDevice, libraryDevice } from '../utilities/data-library.js';
11
+ import { NPC } from '../models/npc.js';
11
12
  /**
12
13
  * "download" -- COPY A FILE OFF THE GRID INTO YOUR DEVICE'S LIBRARY.
13
14
  *
@@ -41,8 +42,8 @@ import { copyFile, deviceHas, fileOnto, findDataDevice, libraryDevice, receiveDa
41
42
  * THE TIME: a Complex Action (p.239) wherever an action economy exists.
42
43
  *
43
44
  * "download <file> to <device>" picks the library; without it the file
44
- * lands on the persona's device. A runner with no data device at all
45
- * gets the old chip, because something has to hold it.
45
+ * lands on the persona's device. A runner with no data device at all is
46
+ * refused (p.250-251: a living persona has no storage) -- see pull().
46
47
  */
47
48
  export class DownloadCommand extends Command {
48
49
  static verb = 'download';
@@ -82,7 +83,7 @@ export class DownloadCommand extends Command {
82
83
  lines.push(` ${planeTintItemName(p.item, actor.plane)} -- ${where}`);
83
84
  }
84
85
  const home = libraryDevice(actor);
85
- lines.push(hint(`("download <file>" copies it ${home ? `onto your ${home.name}` : 'to a chip'}.)`));
86
+ lines.push(hint(home ? `("download <file>" copies it onto your ${home.name}.)` : `(You carry no device to copy onto -- a living persona has no storage, p.250-251.)`));
86
87
  return lines.join('\n');
87
88
  }
88
89
  const picked = fuzzyPickName(words, pullable.map(p => p.item.name));
@@ -205,6 +206,26 @@ export class DownloadCommand extends Command {
205
206
  if (device && deviceHas(device, item.name)) {
206
207
  return { ok: false, text: `Your ${device.name} already holds ${item.name}.` };
207
208
  }
209
+ // NO STORAGE, NO COPY (SR5 p.250-251, RAG-checked 2026-10-04): "your
210
+ // living persona is just a persona, not a device, you don't have any
211
+ // on-board storage; ... you can store files in nearby devices." A
212
+ // persona with no device to write to has nowhere for the copy to go
213
+ // -- and a datachip in the pack has no wireless for a mind on the grid
214
+ // to write through. In practice this is the technomancer with no
215
+ // commlink: every other runner needed a device to jack in at all.
216
+ // Before 1.191.1 this fell back to a chip, which canon never allowed.
217
+ //
218
+ // An NPC persona (a sprite, an agent) carries what it takes in its own
219
+ // hands -- the shelf download.ts already reads from a sprite.
220
+ const npcHands = !device && actor instanceof NPC;
221
+ if (!device && !npcHands) {
222
+ return {
223
+ ok: false,
224
+ text: actor.isTechnomancer()
225
+ ? `Your living persona is a persona, not a device -- it has no storage to copy ${item.name} into (p.250-251). ${hint(`Carry a commlink, deck or RCC and the copy lands there; reading files is not riding the hardware, so your Resonance stays yours.`)}`
226
+ : `You carry no commlink, deck or RCC to copy ${item.name} onto.`,
227
+ };
228
+ }
208
229
  // THE HOST'S GATE: cracked opens it (hack.ts); otherwise Edit File
209
230
  // wants a mark (p.239) before it can be tried at all.
210
231
  const host = source.kind === 'host' ? source.host : undefined;
@@ -251,17 +272,20 @@ export class DownloadCommand extends Command {
251
272
  onto = device;
252
273
  }
253
274
  else {
254
- onto = receiveData(actor, landed).device;
275
+ // An NPC persona's own hands (the refusal above covers everyone else).
276
+ landed.plane = 'matrix';
277
+ landed.atSpot = undefined;
278
+ actor.inventory.addItem(landed);
255
279
  }
256
- actor.performAction('copies a file', `${item.name}${onto ? ` onto ${onto.name}` : ' to a chip'}`, { quiet: this.scene.isHumanControlled(actor) });
257
- this.logger.write(`${actor.name} downloaded "${item.name}" (${source.kind}) ${onto ? `onto ${onto.name}` : 'to a chip'}.`);
280
+ actor.performAction('copies a file', `${item.name}${onto ? ` onto ${onto.name}` : ''}`, { quiet: this.scene.isHumanControlled(actor) });
281
+ this.logger.write(`${actor.name} downloaded "${item.name}" (${source.kind}) ${onto ? `onto ${onto.name}` : 'into its own hands'}.`);
258
282
  this.game?.requestSave('data');
259
283
  this.scene.updateStatus();
260
284
  const text = onto
261
285
  ? source.kind === 'sprite'
262
286
  ? `{light-blue-fg}${source.npc.name} opens its hands and the data pours out of them -- {bold}{underline}${item.name}{/underline}{/bold} is on your ${onto.name} now.{/light-blue-fg}`
263
287
  : `{light-blue-fg}You copy {bold}{underline}${item.name}{/underline}{/bold} onto your ${onto.name}${host ? ` -- ${hostLabel(host.over)} keeps its original` : ''}.{/light-blue-fg}${hint(` ("give" or "call" hands it over straight from the device; "transfer ${item.name} to chip" writes it to physical media.)`)}`
264
- : `{light-blue-fg}You pull {bold}{underline}${item.name}{/underline}{/bold} down onto a chip -- you carry no device with a library to hold it.{/light-blue-fg}`;
288
+ : `{light-blue-fg}You take hold of ${item.name}.{/light-blue-fg}`;
265
289
  // 'possess' objectives complete in the runner's hands; a device library
266
290
  // is the runner's hands for data (scene.ts checkWinCondition).
267
291
  if (this.scene.isHumanControlled(actor))
@@ -3248,5 +3248,10 @@
3248
3248
  // cargo onto the runner's device at the meet.
3249
3249
  // - The gear beat carries data (device libraries) and host (the found
3250
3250
  // archive of the host the persona is in).
3251
- export const ENGINE_VERSION = '1.191.0';
3251
+ // 1.191.1 (2026-10-04): A LIVING PERSONA HAS NO STORAGE (SR5 p.250-251).
3252
+ // - A download with no commlink, deck or RCC to land on is refused, not
3253
+ // written to a chip -- a persona is not a device, and a datachip has no
3254
+ // wireless to write through. Reaches only the deviceless technomancer;
3255
+ // one with a commlink copies onto it and keeps their Resonance.
3256
+ export const ENGINE_VERSION = '1.191.1';
3252
3257
  //# sourceMappingURL=engine-version.js.map
@@ -22,8 +22,8 @@ export function dataDevices(player) {
22
22
  * WHERE A DOWNLOAD LANDS: the device carrying the persona (p.239, the
23
23
  * copier owns the copy -- on the hardware they are running), else the
24
24
  * first data device on you. Undefined for a runner with none at all -- a
25
- * technomancer's living persona has no storage to write to (see
26
- * downloadTarget for what happens then).
25
+ * technomancer's living persona has no storage to write to (p.250-251),
26
+ * and download.ts refuses the copy rather than inventing a chip.
27
27
  */
28
28
  export function libraryDevice(player) {
29
29
  const persona = player.personaDevice();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.379.0",
3
+ "version": "5.379.1",
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.",