@maka/maka-cli 5.184.0 → 5.186.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.
- package/bundle/typescript/package.json +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/disable.js +4 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/download.js +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/edit-file.js +132 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hide.js +110 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.js +23 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/jobs.js +15 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/journal.js +17 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/search.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/tap.js +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +23 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/cleanup-seed.js +89 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +220 -6
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js +21 -0
- package/bundle/typescript/src/commands/game/sideQuest/headless.js +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/host.js +24 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +43 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grids.js +22 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/host-combat.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic-brain.js +35 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic.js +107 -34
- package/bundle/typescript/src/commands/game/sideQuest/utilities/marks.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/surveillance.js +34 -0
- package/package.json +1 -1
|
@@ -140,6 +140,21 @@ const empty = () => ({ lines: [], meta: [], world: [] });
|
|
|
140
140
|
* maglocks fall, the vault unseals -- but it stops being an immunity.
|
|
141
141
|
*/
|
|
142
142
|
export function hostIsHunting(room, actor) {
|
|
143
|
+
return hostSuspectsOrHunts(room, actor)
|
|
144
|
+
// ...AND IT CAN SEE YOU (2026-09-14, "constantly in combat, even
|
|
145
|
+
// running silent"). Alert used to be the whole test, so a host woken
|
|
146
|
+
// by a successful Brute Force -- which canon says leaves it "aware
|
|
147
|
+
// that it is under attack ... but it doesn't automatically spot you"
|
|
148
|
+
// (p.236) -- opened the fight on the next keystroke and the silent
|
|
149
|
+
// test in ambientPatrol was never rolled (it bailed on alert). Ice
|
|
150
|
+
// hunts what the host has SPOTTED (Host.spotted, shared with every
|
|
151
|
+
// program, p.247); an alerted host that has not spotted you sweeps
|
|
152
|
+
// for you every action instead (ambientPatrol, focused).
|
|
153
|
+
&& isSpotted(room, actor);
|
|
154
|
+
}
|
|
155
|
+
/** Alert, inside, unsanctioned -- the host is looking, whether or not it
|
|
156
|
+
* has found this persona yet. The two halves below split on that. */
|
|
157
|
+
function hostSuspectsOrHunts(room, actor) {
|
|
143
158
|
return actor.plane === 'matrix'
|
|
144
159
|
&& room.hasNode
|
|
145
160
|
// IC RUNS INSIDE THE HOST, AND NOWHERE ELSE (p.246-247; Deditri,
|
|
@@ -161,6 +176,27 @@ export function hostIsHunting(room, actor) {
|
|
|
161
176
|
&& !room.hostSanctioned
|
|
162
177
|
&& room.hostAlert;
|
|
163
178
|
}
|
|
179
|
+
/** An alerted host that has NOT found this persona: its Patrol is
|
|
180
|
+
* running Matrix Perception every action (Data Trails p.86). */
|
|
181
|
+
export function hostSuspects(room, actor) {
|
|
182
|
+
return hostSuspectsOrHunts(room, actor) && !isSpotted(room, actor);
|
|
183
|
+
}
|
|
184
|
+
/** Has this host (and so all its IC, p.247) got eyes on the persona? */
|
|
185
|
+
export function isSpotted(room, actor) {
|
|
186
|
+
return room.host?.spotted.has(actor.name) ?? false;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* THE HOST SEES YOU. One door for every way of being made -- a blown
|
|
190
|
+
* Sleaze's free mark (p.236), a Patrol sighting, Probe's grip -- so the
|
|
191
|
+
* fact that alert and spotted are two things is written in one place.
|
|
192
|
+
*/
|
|
193
|
+
export function spot(room, actor) {
|
|
194
|
+
const host = room.host;
|
|
195
|
+
if (!host)
|
|
196
|
+
return;
|
|
197
|
+
host.alert = true;
|
|
198
|
+
host.spotted.add(actor.name);
|
|
199
|
+
}
|
|
164
200
|
/**
|
|
165
201
|
* IS THIS PERSONA A LEGITIMATE USER? (p.248, Patrol.)
|
|
166
202
|
*
|
|
@@ -234,39 +270,46 @@ export function ambientPatrol(room, actor) {
|
|
|
234
270
|
// back, it is not watching for you. See hostIsHunting.
|
|
235
271
|
if (room.hostSanctioned)
|
|
236
272
|
return out;
|
|
237
|
-
// Already
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
if (room
|
|
241
|
-
return out;
|
|
242
|
-
if (looksLegitimate(room, actor))
|
|
273
|
+
// Already SEEN: the alerted host's ice owns that persona (hostIsHunting
|
|
274
|
+
// -> the host arena's Combat Turn). A CRACKED host is no longer exempt
|
|
275
|
+
// -- see hostIsHunting for why that ruling was retired.
|
|
276
|
+
if (isSpotted(room, actor))
|
|
243
277
|
return out;
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
278
|
+
// TWO CADENCES, AND THE HOST'S ALERT PICKS BETWEEN THEM (Data Trails
|
|
279
|
+
// p.86, the "constantly in combat" report of 2026-09-14). An
|
|
280
|
+
// unsuspecting host sweeps on the rating interval and lets a marked
|
|
281
|
+
// user be (p.248). A host that KNOWS it has an intruder -- a Brute
|
|
282
|
+
// Force it felt, a Sleaze it caught, a sighting -- runs Matrix
|
|
283
|
+
// Perception "every action", and it is not reassured by a mark: host
|
|
284
|
+
// security stays "vigilant for unauthorized users, even those with
|
|
285
|
+
// marks" (DT p.168-169), and the mark a Brute Force just planted is
|
|
286
|
+
// exactly what it is looking at. This used to return early on alert
|
|
287
|
+
// instead, which is why running silent never got its roll.
|
|
288
|
+
const focused = room.hostAlert;
|
|
289
|
+
// A persona that Hid THIS beat is not re-swept on the same beat: the
|
|
290
|
+
// hide was its action; the host's new perception is its own (p.240).
|
|
291
|
+
if (focused && room.host?.justHid.delete(actor.name))
|
|
249
292
|
return out;
|
|
293
|
+
if (!focused) {
|
|
294
|
+
if (looksLegitimate(room, actor))
|
|
295
|
+
return out;
|
|
296
|
+
// The sweep is on a clock (Data Trails p.86) -- it is not looking
|
|
297
|
+
// every single moment until it has reason to.
|
|
298
|
+
const due = (room.patrolCountdown ?? rollPatrolInterval(room.hostRating)) - 1;
|
|
299
|
+
if (due > 0) {
|
|
300
|
+
room.patrolCountdown = due;
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
room.patrolCountdown = rollPatrolInterval(room.hostRating);
|
|
250
304
|
}
|
|
251
|
-
|
|
252
|
-
let spotted;
|
|
253
|
-
if (!actor.runningSilent) {
|
|
254
|
-
// p.235: no test. A visible icon in the host is simply seen.
|
|
255
|
-
spotted = true;
|
|
256
|
-
out.meta.push(`Patrol IC -- sweep: icon not running silent, spotted automatically (no test, p.235)`);
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
const look = rollPool(room.hostRating * 2, room.hostAttributes().dataProcessing);
|
|
260
|
-
const hide = rollPool(actor.logic + actor.matrixAttribute('sleaze'));
|
|
261
|
-
// p.236: a tie goes to the hider.
|
|
262
|
-
spotted = look.hits > hide.hits;
|
|
263
|
-
out.meta.push(`Patrol IC -- Matrix Perception (Host Rating x2 [Data Processing]): ${formatRoll(look)} v. Logic + Sleaze: ${formatRoll(hide)}`);
|
|
264
|
-
}
|
|
305
|
+
const spotted = patrolPerception(room, actor, out);
|
|
265
306
|
if (!spotted) {
|
|
266
|
-
out.lines.push(
|
|
307
|
+
out.lines.push(focused
|
|
308
|
+
? ` Patrol IC is HUNTING -- it quarters the datastream around you, hard, and slides past. Your silence held. For now.`
|
|
309
|
+
: ` Something quarters the datastream around you and moves on. Your silence held.`);
|
|
267
310
|
return out;
|
|
268
311
|
}
|
|
269
|
-
room
|
|
312
|
+
spot(room, actor);
|
|
270
313
|
actor.sneaking = false;
|
|
271
314
|
// NAME THE HOST THAT FOUND YOU (rG8LtMoy5DHQJ2NuG: "I got a
|
|
272
315
|
// notification that an IC has found me, however I haven't entered a
|
|
@@ -282,10 +325,32 @@ export function ambientPatrol(room, actor) {
|
|
|
282
325
|
// So it says WHICH host, and where it is. That is the whole fix; the
|
|
283
326
|
// deeper problem -- that this engine has no inside-vs-outside-host
|
|
284
327
|
// state for the player to have crossed -- is its own item.
|
|
285
|
-
out.lines.push(
|
|
286
|
-
|
|
328
|
+
out.lines.push(focused
|
|
329
|
+
? ` {red-fg}${hostLabel(room, { capital: true })} makes you -- the hunting Patrol locks onto your icon and every program in the architecture has you now.{/red-fg}`
|
|
330
|
+
: ` {red-fg}${hostLabel(room, { capital: true })} makes you -- an unmarked icon where none should be. You're inside its architecture, on ${room.name}'s patch of grid, and it knows it has an intruder.{/red-fg}`);
|
|
331
|
+
out.world.push(focused
|
|
332
|
+
? `${room.name}'s hunting Patrol IC found ${actor.name} -- ice closing.`
|
|
333
|
+
: `${room.name}'s Patrol IC made ${actor.name} on a routine sweep -- alarm flagged, ice hunting.`);
|
|
287
334
|
return out;
|
|
288
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* ONE MATRIX PERCEPTION BY THE HOST'S PATROL against one persona, the
|
|
338
|
+
* dice canon prints and nothing more: a non-silent icon is seen with no
|
|
339
|
+
* test (p.235); a silent one is an Opposed Test, Host Rating x2 [Data
|
|
340
|
+
* Processing] (the IC pool, p.247; the perception bracket, p.241) v.
|
|
341
|
+
* Logic + Sleaze, and a tie goes to the hider (p.236). Returns whether
|
|
342
|
+
* the persona was seen; the caller decides what that costs.
|
|
343
|
+
*/
|
|
344
|
+
export function patrolPerception(room, actor, out) {
|
|
345
|
+
if (!actor.runningSilent) {
|
|
346
|
+
out.meta.push(`Patrol IC -- sweep: icon not running silent, spotted automatically (no test, p.235)`);
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
const look = rollPool(room.hostRating * 2, room.hostAttributes().dataProcessing);
|
|
350
|
+
const hide = rollPool(actor.logic + actor.matrixAttribute('sleaze'));
|
|
351
|
+
out.meta.push(`Patrol IC -- Matrix Perception (Host Rating x2 [Data Processing]): ${formatRoll(look)} v. Logic + Sleaze: ${formatRoll(hide)}`);
|
|
352
|
+
return look.hits > hide.hits;
|
|
353
|
+
}
|
|
289
354
|
/**
|
|
290
355
|
* THE HOST'S WHOLE TURN: its eyes if it has not made you, its ice if it
|
|
291
356
|
* has. One entry point, so the caller never has to know which half of
|
|
@@ -618,11 +683,17 @@ function dealBiofeedback(actor, dv, type, out) {
|
|
|
618
683
|
* pre-alert patrolling exists, the interval table is what it needs.
|
|
619
684
|
*/
|
|
620
685
|
function patrolActs(room, actor, out) {
|
|
621
|
-
//
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
686
|
+
// A persona the host can already see (which is what this composition
|
|
687
|
+
// is handed) gets no second roll -- Patrol's perception is the one in
|
|
688
|
+
// patrolPerception, spent on personas it has NOT found (ic-brain.ts
|
|
689
|
+
// runs it against each unspotted icon inside during the fight).
|
|
690
|
+
if (isSpotted(room, actor)) {
|
|
691
|
+
out.lines.push(` {red-fg}Patrol IC keeps your icon in view and hands every move to the host.{/red-fg}`);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (patrolPerception(room, actor, out)) {
|
|
695
|
+
spot(room, actor);
|
|
696
|
+
out.lines.push(` {red-fg}Patrol IC sweeps your icon and hands what it sees to the host -- it has you now.{/red-fg}`);
|
|
626
697
|
}
|
|
627
698
|
else {
|
|
628
699
|
// "Does not take Matrix damage when it fails" -- a whiff costs it
|
|
@@ -659,6 +730,8 @@ function probeActs(room, actor, type, out, ice) {
|
|
|
659
730
|
}
|
|
660
731
|
const now = held + 1;
|
|
661
732
|
room.hostMarksOn.set(actor.name, now);
|
|
733
|
+
// A grip is a sighting: the host and every program see what Probe holds.
|
|
734
|
+
spot(room, actor);
|
|
662
735
|
out.lines.push(` {red-fg}Probe IC gets a grip -- the host holds ${now} mark${now === 1 ? '' : 's'} on you now${now >= MAX_MARKS ? ', all it can carry' : ''}.{/red-fg}`);
|
|
663
736
|
out.world.push(`${room.name}'s ice tightened its hold on ${actor.name}.`);
|
|
664
737
|
}
|
|
@@ -44,6 +44,9 @@ export function clearMarksOn(actor, scene) {
|
|
|
44
44
|
if ((room.host?.marksOn.get(actor.name) ?? 0) > 0)
|
|
45
45
|
had++;
|
|
46
46
|
room.host?.marksOn.delete(actor.name);
|
|
47
|
+
// A rebooted persona is a fresh icon: whatever the host had SPOTTED
|
|
48
|
+
// is gone with the marks (Host.spotted) -- it has to find you again.
|
|
49
|
+
room.host?.spotted.delete(actor.name);
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
return had;
|
|
@@ -267,6 +267,11 @@ export function leaveMatrix(scene, actor, opts) {
|
|
|
267
267
|
actor.bodyRoom = undefined;
|
|
268
268
|
lines.push(`You're back in your body in ${body.name}.`);
|
|
269
269
|
}
|
|
270
|
+
// A LOOSE-END CLEANUP ENDS HERE, whichever door the persona left by --
|
|
271
|
+
// a clean jack-out, a torn link-lock, a bricked deck, Scramble, GOD.
|
|
272
|
+
// Every exit is one of this function's callers, so this is the one
|
|
273
|
+
// place the hub takes the scene back (Game.onPersonaLeftMatrix).
|
|
274
|
+
lines.push(...(scene.ownerGame?.onPersonaLeftMatrix?.(actor) ?? []));
|
|
270
275
|
actor.performAction('jacks out', 'stirring awake', { quiet: scene.isHumanControlled?.(actor) ?? false });
|
|
271
276
|
scene.addWorldEvent(`${actor.name} jacked out of the Matrix.`);
|
|
272
277
|
scene.updateStatus();
|
|
@@ -97,6 +97,40 @@ export function camerasLive(rooms, room) {
|
|
|
97
97
|
return true;
|
|
98
98
|
return !hosts.some(r => r.hostCracked);
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* WHAT THE CAMERAS STILL HOLD WHEN THE RUN ENDS (loose ends, 2026-09-14).
|
|
102
|
+
*
|
|
103
|
+
* `camSeen` is the set of rooms whose cameras were called out during the
|
|
104
|
+
* run (Game._camSeenRooms -- "a camera's dead eye caught ALL of it").
|
|
105
|
+
* The line promised the footage was "already somewhere else", and this
|
|
106
|
+
* is where: the host those cameras are slaved to. Footage survives the
|
|
107
|
+
* run when the room's feeds are STILL live at the end -- its master host
|
|
108
|
+
* never cracked, its cluster never looped or bricked -- and there is a
|
|
109
|
+
* host anywhere to hold it (standalone recorders keep nothing a decker
|
|
110
|
+
* could reach, so they leave no loose end). Grouped under one master
|
|
111
|
+
* (the one with the most rooms, then by name): one run, one record.
|
|
112
|
+
*/
|
|
113
|
+
export function liveFootage(rooms, camSeen) {
|
|
114
|
+
const byHost = new Map();
|
|
115
|
+
for (const name of camSeen) {
|
|
116
|
+
const room = Object.values(rooms).find(r => r.name === name);
|
|
117
|
+
if (!room || !camerasLive(rooms, room))
|
|
118
|
+
continue;
|
|
119
|
+
const master = cameraMasterHost(rooms, room);
|
|
120
|
+
if (!master)
|
|
121
|
+
continue;
|
|
122
|
+
const list = byHost.get(master) ?? [];
|
|
123
|
+
list.push(room);
|
|
124
|
+
byHost.set(master, list);
|
|
125
|
+
}
|
|
126
|
+
let best;
|
|
127
|
+
for (const [host, seen] of byHost) {
|
|
128
|
+
if (!best || seen.length > best.rooms.length || (seen.length === best.rooms.length && host.name.localeCompare(best.host.name) < 0)) {
|
|
129
|
+
best = { host, rooms: seen };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return best;
|
|
133
|
+
}
|
|
100
134
|
/** Can THIS persona watch the room's feeds remotely? Its own host
|
|
101
135
|
* cracked or marked; a hostless watched room answers to whoever owns
|
|
102
136
|
* any of the site's hosts. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.186.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.",
|