@maka/maka-cli 5.149.0 → 5.151.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.149.0",
3
+ "version": "5.151.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.",
@@ -51,6 +51,45 @@ export class LookCommand extends Command {
51
51
  return `${containerHit.description}\n Open. ${items.length === 0 ? 'Empty.'
52
52
  : `Inside: ${items.map(i => i.quantity > 1 ? `${i.name} ×${i.quantity}` : i.name).join(', ')}.`}`;
53
53
  }
54
+ // "look deck" (W7fzZRb6Asa7Qqjzg): a decker's cyberdeck is
55
+ // usually branded gear ("Sony CIY-720"), not literally named
56
+ // "deck" -- so the generic name-match below missed it entirely
57
+ // and "look deck" read "You cannot see deck" even carrying one.
58
+ // Resolved through the SAME lookup "deck" (deck.ts) already uses
59
+ // for the active/best-carried deck, then handed to the ordinary
60
+ // inspectItem by its real name so the two verbs describe one
61
+ // object identically.
62
+ if (target === 'deck') {
63
+ const carried = this.actor.getAnyCyberdeck();
64
+ if (carried) {
65
+ this.logger.write(`Looking at active deck '${carried.name}' in ${this.actor.name} inventory.`);
66
+ return this.inspectItem(carried.name, this.actor.inventory);
67
+ }
68
+ }
69
+ // AN EXACT NAME BEATS A FUZZY ITEM SUBSTRING (Sjjy52mjSqSdjFGdg:
70
+ // "look Jo" resolved to "Certified Credstick (job payments)" --
71
+ // Inventory.resolveKey does deliberately generous substring
72
+ // matching for item-name typos ("jo" sits inside "job payments"),
73
+ // and that ran before the room's actor list was ever consulted.
74
+ // A present person's EXACT name is a far stronger signal than an
75
+ // incidental item substring, so it wins first; an inexact query
76
+ // still falls through to the item/direction ladder below exactly
77
+ // as before.
78
+ // AN EXACT NAME BEATS A FUZZY ITEM SUBSTRING (Sjjy52mjSqSdjFGdg:
79
+ // "look Jo" resolved to "Certified Credstick (job payments)" --
80
+ // Inventory.resolveKey does deliberately generous substring
81
+ // matching for item-name typos ("jo" sits inside "job payments"),
82
+ // and that ran before the room's actor list was ever consulted.
83
+ // A present person's EXACT name is a far stronger signal than an
84
+ // incidental item substring, so it wins first; an inexact query
85
+ // still falls through to the item/direction ladder below exactly
86
+ // as before.
87
+ const exactActorMatch = this.scene
88
+ .getActorsInRoom(this.actor.currentLocation)
89
+ .find(a => a.name.toLowerCase() === target.toLowerCase() && this.actor.canPerceive(a));
90
+ if (exactActorMatch) {
91
+ return this.inspectActor(exactActorMatch.name);
92
+ }
54
93
  if (this.actor.inventory.hasItem(target)) {
55
94
  this.logger.write(`Looking at item '${target}' in ${this.actor.name} inventory.`);
56
95
  return this.inspectItem(target, this.actor.inventory);
@@ -64,14 +103,9 @@ export class LookCommand extends Command {
64
103
  return this.lookOutside(target);
65
104
  }
66
105
  else {
67
- // Check if it's another player or NPC in the room (that this
68
- // actor's plane can perceive -- see Player.canPerceive)
69
- const actorMatch = this.scene
70
- .getActorsInRoom(this.actor.currentLocation)
71
- .find(a => a.name.toLowerCase() === target.toLowerCase() && this.actor.canPerceive(a));
72
- if (actorMatch) {
73
- return this.inspectActor(actorMatch.name);
74
- }
106
+ // The exact-name actor check above already covers a present
107
+ // person; reaching here means the target is neither an item,
108
+ // a direction, nor anyone in the room by that exact name.
75
109
  return `You cannot see ${target}`;
76
110
  }
77
111
  }
@@ -88,6 +88,10 @@ export class TakeCommand extends Command {
88
88
  taken.push(item.name);
89
89
  }
90
90
  }
91
+ // Same durable-change rule as the loose-floor pickups below
92
+ // (RKLbzxQQRJk8eD8Az) -- only when something actually moved.
93
+ if (taken.length > 0)
94
+ this.game?.requestSave('take');
91
95
  const lines = [taken.length > 0 ? `${prefix}You take ${taken.join(', ')} from the ${container.name}.` : `${prefix}You take nothing from the ${container.name}.`, ...left];
92
96
  return lines.join('\n');
93
97
  }
@@ -100,6 +104,7 @@ export class TakeCommand extends Command {
100
104
  if (!container.inventory.transferItemTo(item.name.toLowerCase(), this.actor.inventory)) {
101
105
  return `${prefix}You can't lift the ${item.name} right now.`;
102
106
  }
107
+ this.game?.requestSave('take');
103
108
  this.actor.performAction('takes', `${item.name} from the ${container.name}`);
104
109
  return `${prefix}You take the ${item.name} from the ${container.name}.`;
105
110
  }
@@ -223,6 +228,14 @@ export class TakeCommand extends Command {
223
228
  }
224
229
  if (tookAnything) {
225
230
  this.scene.updateInventory(this.scene.getPlayer().inventory);
231
+ // A PICKUP IS A DURABLE CHANGE (RKLbzxQQRJk8eD8Az: "I picked up
232
+ // the 'Ferret's ledger Service Log', but I don't see it reflected
233
+ // in the character sheet"). buy.ts's own fix comment named this
234
+ // file as a sibling that never learned the lesson (vR8ajvm3wXdexxdF2)
235
+ // -- the web sheet reads the last SAVED snapshot, and nothing here
236
+ // ever asked for one, so a swept haul sat invisible until the next
237
+ // unrelated save beat (homecoming, rest, a trade).
238
+ this.game?.requestSave('take');
226
239
  }
227
240
  // Win-condition checks run AFTER the sweep summary renders: the check
228
241
  // logs the JOB COMPLETE banner itself, and running it per-item used to
@@ -363,6 +376,15 @@ export class TakeCommand extends Command {
363
376
  room.inventory.removeItem(itemName);
364
377
  room.plainSightItems.delete(item.name.toLowerCase());
365
378
  this.logger.write(`Successfully removed "${itemName}" from ${room.name} room's inventory during 'Take' command.`);
379
+ // A PICKUP IS A DURABLE CHANGE (RKLbzxQQRJk8eD8Az: "I picked up
380
+ // the 'Ferret's ledger Service Log', but I don't see it reflected
381
+ // in the character sheet"). buy.ts's own fix comment named this
382
+ // file as a sibling that never learned the lesson (vR8ajvm3wXdexxdF2)
383
+ // -- the web sheet reads the last SAVED snapshot, and nothing here
384
+ // ever asked for one. Placed after the item has actually changed
385
+ // hands (the try's own catch below handles a too-heavy rollback
386
+ // before this line is ever reached), same rule as buy.ts/unequip.ts.
387
+ this.game?.requestSave('take');
366
388
  // Possession-based win condition: if some OTHER actor ends up with
367
389
  // the item the win condition's target NPC wants, that counts just as
368
390
  // much as the player handing it over directly (emergent delivery).
@@ -185,6 +185,7 @@ import { clockTime, worldNow } from './utilities/world-clock.js';
185
185
  import { CommandFactory } from './factories/command-factory.js';
186
186
  import { SceneSynthesizer } from './factories/scene-factory.js';
187
187
  import { SceneSeedGenerator, FIXER_NAME, isFixerName } from './factories/scene-seed-generator.js';
188
+ import { draftFailureNote } from './utilities/draft-failure-note.js';
188
189
  import { CALL_ICON, CALL_COLOR, END_CALL_SENTINEL } from './utilities/comm-style.js';
189
190
  import { AI } from '../../../tools/ai/ai.class.js';
190
191
  import { BULLET } from './utilities/log-style.js';
@@ -4147,33 +4148,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4147
4148
  // caller but the ask-for-data-work door passes.
4148
4149
  const nextSeed = await SceneSeedGenerator.generate(this._logFilePath, nextTier, this.player, this.activeRumor, localCrew, undefined, runType);
4149
4150
  if (!nextSeed) {
4150
- // NAME the cause when it's the PROVIDER, not luck (real session:
4151
- // six Krow calls into an out-of-credits key, indistinguishable
4152
- // from flaky clients). Credit/auth failures are the player's to
4153
- // fix -- say so, out of character, once per ping.
4154
- const why = SceneSeedGenerator.lastFailure ?? '';
4155
- // TELL THE TRUTH ABOUT WHOSE FAULT IT IS (playtest 2026-08-26).
4156
- // The old test carried `invalid.*key`, meant for "invalid API
4157
- // key" -- but `.*` spans the whole message, so a skeleton
4158
- // validation error reading "Skeleton INVALID: ... locked doors
4159
- // and KEY placements" matched, and a map-generation bug was
4160
- // reported to the player as a billing problem. Sending someone to
4161
- // rotate a working key is worse than saying nothing.
4162
- //
4163
- // Every pattern here is now anchored to the phrase it actually
4164
- // means: a bare "invalid" or a stray "key" no longer counts, and
4165
- // the status codes need word boundaries so they can't match
4166
- // inside some other number.
4167
- const providerDown = /credit balance|billing|quota|insufficient (?:credit|fund|quota|balance)|invalid[\s_-]*api[\s_-]*key|api[\s_-]*key (?:is )?(?:invalid|expired|missing|not)|unauthorized|authentication|\b(?:401|403|429)\b|Plans & Billing/i.test(why);
4168
- // A structural failure is OURS, not the player's -- name it as
4169
- // the generator's problem so nobody goes hunting their billing
4170
- // page, and keep it short: the fiction already covers the beat.
4171
- const structural = !providerDown && /^Skeleton invalid|validation failed|isn't placed|unreachable from the start/i.test(why);
4172
- const opsNote = providerDown
4173
- ? `\n{yellow-fg}(Out of character: the AI provider refused -- "${why.slice(0, 120)}". Jobs can't generate until the API key/credits are fixed.){/yellow-fg}`
4174
- : structural
4175
- ? `\n{yellow-fg}(Out of character: the job generator couldn't lay out a solvable map this time -- nothing wrong with your key or credits. Call again; the next draft usually takes.){/yellow-fg}`
4176
- : '';
4151
+ const opsNote = draftFailureNote(SceneSeedGenerator.lastFailure ?? '');
4177
4152
  return `Incoming call -- ${FIXER_NAME}: "Job fell through, chummer. Client got cold feet before the ink dried. Give me another call in a bit -- I'll shake something loose."${opsNote}`;
4178
4153
  }
4179
4154
  // HUB sessions: the draft lands as a MESSAGE, never a teleport (real
@@ -0,0 +1,66 @@
1
+ /**
2
+ * THE OUT-OF-CHARACTER NOTE ON A FAILED JOB DRAFT (game.ts's
3
+ * draftNextScene). SceneSeedGenerator.generate() gives up after three
4
+ * pipeline attempts and hands back a bare error string; Krow's "Job
5
+ * fell through" callback fires either way, and this decides what --
6
+ * if anything -- rides after it, so the player can tell "you did
7
+ * something wrong" from "this is on us" from "pure bad luck, try
8
+ * again."
9
+ *
10
+ * Extracted to its own module (2026-09-10) so the classification --
11
+ * pure string matching against known provider/generator error prose --
12
+ * can be pinned directly, without standing up a Game instance or
13
+ * mocking SceneSeedGenerator to reach it.
14
+ *
15
+ * TELL THE TRUTH ABOUT WHOSE FAULT IT IS (playtest 2026-08-26). The old
16
+ * test carried `invalid.*key`, meant for "invalid API key" -- but `.*`
17
+ * spans the whole message, so a skeleton validation error reading
18
+ * "Skeleton INVALID: ... locked doors and KEY placements" matched, and
19
+ * a map-generation bug was reported to the player as a billing problem.
20
+ * Sending someone to rotate a working key is worse than saying nothing.
21
+ * Every pattern here is anchored to the phrase it actually means: a
22
+ * bare "invalid" or a stray "key" no longer counts, and the status
23
+ * codes need word boundaries so they can't match inside some other
24
+ * number.
25
+ */
26
+ export function draftFailureNote(why) {
27
+ // NAME THE CAUSE WHEN IT'S THE PROVIDER, NOT LUCK (real session: six
28
+ // Krow calls into an out-of-credits key, indistinguishable from flaky
29
+ // clients). Credit/auth failures are the player's to fix -- say so,
30
+ // out of character, once per ping.
31
+ // Widened 2026-09-10: the site's own current wording (ai-error-envelope.ts
32
+ // classifyUpstream's upstream_billing branch) reads "has run out of
33
+ // credit at its provider, or its key was rejected" -- neither phrase
34
+ // matched any pattern below, so the ORIGINAL motivating bug (the "six
35
+ // Krow calls into an out-of-credits key" session) would silently fall
36
+ // through to no note again today, on the site's real current message.
37
+ const providerDown = /credit balance|billing|quota|insufficient (?:credit|fund|quota|balance)|run out of credit|key was rejected|invalid[\s_-]*api[\s_-]*key|api[\s_-]*key (?:is )?(?:invalid|expired|missing|not)|unauthorized|authentication|\b(?:401|403|429)\b|Plans & Billing/i.test(why);
38
+ // TRANSIENT INFRASTRUCTURE, not billing and not a generation bug
39
+ // (real session, e8dLKM9j5P9yQn5yz's sibling report: a fresh
40
+ // character's very first homecoming draft, plus four manual "call
41
+ // Krow" retries, all failed in under half a second each against "The
42
+ // AI provider behind maka-cli.com is overloaded or down" --
43
+ // ai-error-envelope.ts's upstream_unavailable/rate_limited/
44
+ // upstream_timeout/upstream_error text, none of which this classifier
45
+ // recognized, so every one of those five calls read as the same
46
+ // unexplained "Job fell through" with nothing after it --
47
+ // indistinguishable from a broken loop rather than one outage. These
48
+ // are OURS and retryable, same tone as `structural` below, but a
49
+ // different truth: nothing was malformed, the provider just wasn't
50
+ // answering. Matched on the SITE'S OWN wording (ai-error-envelope.ts
51
+ // classifyUpstream/classifyTransportFailure) rather than status
52
+ // codes, since only the prose crosses the wire.
53
+ const providerOutage = !providerDown && /overloaded or down|rate-limited by its provider|took too long to answer|could not (?:complete that request|reach its ai provider)/i.test(why);
54
+ // A structural failure is OURS, not the player's -- name it as the
55
+ // generator's problem so nobody goes hunting their billing page, and
56
+ // keep it short: the fiction already covers the beat.
57
+ const structural = !providerDown && !providerOutage && /^Skeleton invalid|validation failed|isn't placed|unreachable from the start/i.test(why);
58
+ return providerDown
59
+ ? `\n{yellow-fg}(Out of character: the AI provider refused -- "${why.slice(0, 120)}". Jobs can't generate until the API key/credits are fixed.){/yellow-fg}`
60
+ : providerOutage
61
+ ? `\n{yellow-fg}(Out of character: the AI provider maka-cli.com talks to is overloaded, rate-limited, or unreachable right now -- nothing wrong with your account or your key. Give it a few minutes and call again.){/yellow-fg}`
62
+ : structural
63
+ ? `\n{yellow-fg}(Out of character: the job generator couldn't lay out a solvable map this time -- nothing wrong with your key or credits. Call again; the next draft usually takes.){/yellow-fg}`
64
+ : '';
65
+ }
66
+ //# sourceMappingURL=draft-failure-note.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.149.0",
3
+ "version": "5.151.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.",