@rpgm-tools/neo-angband-mod-sdk 0.25.0 → 0.26.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.
@@ -131,6 +131,70 @@
131
131
  * write to it succeeded or failed. Its own kind,
132
132
  * like "display:replace" - there is nothing to
133
133
  * range over, so it has no wildcard either.
134
+ * - "mod:install" - install a CONTENT mod from archive bytes the mod
135
+ * holds in memory, through the same door the
136
+ * player's own zip import uses. Its own kind, like
137
+ * "display:replace": there is nothing to range over,
138
+ * so it has no wildcard. Two things bound it, and
139
+ * they are what make it proportionate rather than
140
+ * total. An archive that ships CODE, or whose
141
+ * manifest asks for any capability, is refused - so
142
+ * this grants "may add records to my library", not
143
+ * "may write and deploy a program". And an install
144
+ * is not an ENABLE: what arrives is switched off, and
145
+ * the player is shown its own capability list before
146
+ * any of it runs, which is what stops one grant
147
+ * turning into every grant.
148
+ * - "mod:session" - load a CONTENT mod into this session only, so it
149
+ * composes into the game on the next reload and is
150
+ * gone with the window. Bounded exactly as
151
+ * "mod:install" is - code and capability requests are
152
+ * refused - and deliberately NOT the same grant, since
153
+ * an install waits to be switched on and this does not.
154
+ * `grantCovers` compares the action so neither can be
155
+ * sold under the other's sentence. It is a shorter
156
+ * LIFETIME for the archive and not a smaller reach for
157
+ * the records: what composes, composes.
158
+ * - "debug:spawn" - conjure an item or a creature into the live game the
159
+ * way the debug commands do. Its own kind and no
160
+ * wildcard, and here that is the whole point rather
161
+ * than a consequence of there being one string: this
162
+ * is the grant a player is most likely to want to
163
+ * check for by name, so it must never arrive as part
164
+ * of something broader. What it adds over what a
165
+ * plugin can already reach through `ctx.core` is not
166
+ * the ability - `wizCreateObj` and friends take a
167
+ * `debug` flag the CALLER supplies - but the mark: the
168
+ * character is asked about and flagged, through the
169
+ * game's own confirmation and before anything is
170
+ * placed, so "the debug commands cannot be scored"
171
+ * stays true with a mod in the picture.
172
+ * - "debug:wizard" - drive the WHOLE debug set, not just the two spawns:
173
+ * depth, experience, gold, stats, acquirement,
174
+ * mapping. Its own action beside "spawn" rather than a
175
+ * wider reading of it, because the two cost the player
176
+ * different things. Spawning happens to the character
177
+ * they are playing and costs them the score. This one
178
+ * refuses to run until the session has been cut loose
179
+ * from its save slot - one way, checked by the host on
180
+ * every call - so it costs them the session and leaves
181
+ * the character on disk untouched. Neither is a
182
+ * superset of the other and `grantCovers` compares the
183
+ * action, so one consent cannot buy both.
184
+ * - "ui:panel.mount" - draw with real HTML instead of the character grid: a
185
+ * panel of the mod's own, mounted on the page above
186
+ * the game. A THIRD "ui:" action, and the reason it is
187
+ * not a third region name is the same reason
188
+ * "ui:region.create" is not a seventh: the sentence a
189
+ * player agrees to is different. "replace" hands over
190
+ * something the game draws, "create" adds a rectangle
191
+ * of the game's own character grid, and this one puts
192
+ * a piece of web page on top - which can look like the
193
+ * game's own interface, style anything inside itself,
194
+ * and read what the player types into it. No wildcard,
195
+ * and "ui:*.replace" does not cover it: `grantCovers`
196
+ * compares the action, so a mod that may redraw the
197
+ * vitals still cannot mount a panel without asking.
134
198
  * - "ui:region.create" - ADD a rectangle of your own to the player's screen
135
199
  * (ModPlugin.regions), rather than take one of the
136
200
  * game's. The only "ui:" capability whose ACTION is
@@ -176,10 +240,16 @@ export type ParsedCapability = {
176
240
  } | {
177
241
  kind: "ui";
178
242
  region: string;
179
- action: "replace" | "create";
243
+ action: "replace" | "create" | "mount";
180
244
  } | {
181
245
  kind: "backup";
182
246
  action: "folder";
247
+ } | {
248
+ kind: "mod";
249
+ action: "install" | "session";
250
+ } | {
251
+ kind: "debug";
252
+ action: "spawn" | "wizard";
183
253
  };
184
254
  /**
185
255
  * Parse and validate a capability string against the vocabulary above,
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuJG;AAEH,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE5D,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAE7C,2DAA2D;AAC3D,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AA6CzC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CA8C7D;AAiED;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAE1C,OAAO;IAUP;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa;IAgB1D;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKzB;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOxB,0EAA0E;IAC1E,kBAAkB,IAAI,OAAO;IAI7B,6DAA6D;IAC7D,iBAAiB,IAAI,OAAO;CAG7B"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuNG;AAEH,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE5D,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAE7C,2DAA2D;AAC3D,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAA;CAAE,CAAC;AAyElD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CA2F7D;AAoFD;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAE1C,OAAO;IAUP;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa;IAgB1D;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKzB;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOxB,0EAA0E;IAC1E,kBAAkB,IAAI,OAAO;IAI7B,6DAA6D;IAC7D,iBAAiB,IAAI,OAAO;CAG7B"}
@@ -131,6 +131,70 @@
131
131
  * write to it succeeded or failed. Its own kind,
132
132
  * like "display:replace" - there is nothing to
133
133
  * range over, so it has no wildcard either.
134
+ * - "mod:install" - install a CONTENT mod from archive bytes the mod
135
+ * holds in memory, through the same door the
136
+ * player's own zip import uses. Its own kind, like
137
+ * "display:replace": there is nothing to range over,
138
+ * so it has no wildcard. Two things bound it, and
139
+ * they are what make it proportionate rather than
140
+ * total. An archive that ships CODE, or whose
141
+ * manifest asks for any capability, is refused - so
142
+ * this grants "may add records to my library", not
143
+ * "may write and deploy a program". And an install
144
+ * is not an ENABLE: what arrives is switched off, and
145
+ * the player is shown its own capability list before
146
+ * any of it runs, which is what stops one grant
147
+ * turning into every grant.
148
+ * - "mod:session" - load a CONTENT mod into this session only, so it
149
+ * composes into the game on the next reload and is
150
+ * gone with the window. Bounded exactly as
151
+ * "mod:install" is - code and capability requests are
152
+ * refused - and deliberately NOT the same grant, since
153
+ * an install waits to be switched on and this does not.
154
+ * `grantCovers` compares the action so neither can be
155
+ * sold under the other's sentence. It is a shorter
156
+ * LIFETIME for the archive and not a smaller reach for
157
+ * the records: what composes, composes.
158
+ * - "debug:spawn" - conjure an item or a creature into the live game the
159
+ * way the debug commands do. Its own kind and no
160
+ * wildcard, and here that is the whole point rather
161
+ * than a consequence of there being one string: this
162
+ * is the grant a player is most likely to want to
163
+ * check for by name, so it must never arrive as part
164
+ * of something broader. What it adds over what a
165
+ * plugin can already reach through `ctx.core` is not
166
+ * the ability - `wizCreateObj` and friends take a
167
+ * `debug` flag the CALLER supplies - but the mark: the
168
+ * character is asked about and flagged, through the
169
+ * game's own confirmation and before anything is
170
+ * placed, so "the debug commands cannot be scored"
171
+ * stays true with a mod in the picture.
172
+ * - "debug:wizard" - drive the WHOLE debug set, not just the two spawns:
173
+ * depth, experience, gold, stats, acquirement,
174
+ * mapping. Its own action beside "spawn" rather than a
175
+ * wider reading of it, because the two cost the player
176
+ * different things. Spawning happens to the character
177
+ * they are playing and costs them the score. This one
178
+ * refuses to run until the session has been cut loose
179
+ * from its save slot - one way, checked by the host on
180
+ * every call - so it costs them the session and leaves
181
+ * the character on disk untouched. Neither is a
182
+ * superset of the other and `grantCovers` compares the
183
+ * action, so one consent cannot buy both.
184
+ * - "ui:panel.mount" - draw with real HTML instead of the character grid: a
185
+ * panel of the mod's own, mounted on the page above
186
+ * the game. A THIRD "ui:" action, and the reason it is
187
+ * not a third region name is the same reason
188
+ * "ui:region.create" is not a seventh: the sentence a
189
+ * player agrees to is different. "replace" hands over
190
+ * something the game draws, "create" adds a rectangle
191
+ * of the game's own character grid, and this one puts
192
+ * a piece of web page on top - which can look like the
193
+ * game's own interface, style anything inside itself,
194
+ * and read what the player types into it. No wildcard,
195
+ * and "ui:*.replace" does not cover it: `grantCovers`
196
+ * compares the action, so a mod that may redraw the
197
+ * vitals still cannot mount a panel without asking.
134
198
  * - "ui:region.create" - ADD a rectangle of your own to the player's screen
135
199
  * (ModPlugin.regions), rather than take one of the
136
200
  * game's. The only "ui:" capability whose ACTION is
@@ -190,6 +254,34 @@ const UI_RE = /^ui:(\*|messages|sidebar|status|menu|screen)\.replace$/;
190
254
  * the note there.
191
255
  */
192
256
  const UI_CREATE_RE = /^ui:region\.create$/;
257
+ /**
258
+ * `ui:panel.mount` - draw with real HTML instead of the character grid.
259
+ *
260
+ * A THIRD ACTION, for the same reason `create` was a second one rather than a
261
+ * seventh region name: what the player is agreeing to is a different sentence.
262
+ * `replace` hands a mod something the game already draws. `create` gives it a
263
+ * rectangle of the game's own character grid, painted with the same seven
264
+ * methods every other surface has. This one puts a piece of WEB PAGE above the
265
+ * game - arbitrary markup and styling, which can be made to look exactly like
266
+ * the game's own interface, and which can hold a real text field and read what
267
+ * is typed into it.
268
+ *
269
+ * NO WILDCARD, for the reason `create` has none: a mod either may mount panels
270
+ * or it may not, and there is no set of panel names to range over, because a
271
+ * panel does not exist until the mod asks for one.
272
+ *
273
+ * AND `ui:*.replace` MUST NOT COVER IT. `grantCovers` compares the action as
274
+ * well as the region, so this holds by construction rather than by a rule
275
+ * somebody has to remember - which is exactly what that comparison was added
276
+ * for when `create` arrived.
277
+ *
278
+ * WHAT IT IS NOT. It is not a containment boundary and this module's header
279
+ * already says why: a plugin's code runs in the page's own realm and can reach
280
+ * the document with no capability at all. What this grant buys is a panel the
281
+ * HOST owns - one it can place, stack, take the keyboard back from and close -
282
+ * plus a sentence the player reads before any of it happens.
283
+ */
284
+ const UI_MOUNT_RE = /^ui:panel\.mount$/;
193
285
  const STATE_RE = /^state:(\*|[a-z][a-z0-9-]*)\.read$/;
194
286
  const NETWORK_RE = /^network:(\*|[a-zA-Z0-9.-]+)$/;
195
287
  /** The override domains ModRegistryHost gates, plus the "*" wildcard. */
@@ -220,6 +312,45 @@ export function parseCapability(cap) {
220
312
  if (cap === "backup:folder") {
221
313
  return { kind: "backup", action: "folder" };
222
314
  }
315
+ /* "mod:install": hand archive bytes to the same install door the player's own
316
+ * zip import uses. Its own kind and no wildcard, same reasoning as the two
317
+ * above. What bounds it is not this grammar - it is that the door refuses an
318
+ * archive carrying code or asking for capabilities, and that installing is not
319
+ * enabling, so what arrives is consented to on its own terms before it runs. */
320
+ if (cap === "mod:install") {
321
+ return { kind: "mod", action: "install" };
322
+ }
323
+ /* "mod:session": load content into THIS session only, without it joining the
324
+ * library. Bounded the same way `mod:install` is - the door refuses an archive
325
+ * carrying code or asking for capabilities - and separated from it because the
326
+ * two say different things to a player. An install arrives switched OFF and waits
327
+ * to be turned on; a session load is on for the rest of the session as soon as
328
+ * the game reloads. That is more, not less, so it cannot be sold under the other
329
+ * one's sentence: `grantCovers` compares the action for exactly that reason. */
330
+ if (cap === "mod:session") {
331
+ return { kind: "mod", action: "session" };
332
+ }
333
+ /* "debug:spawn": put an item or a creature into the live game the way the debug
334
+ * commands do, marking the character the way they do. Its own kind and no
335
+ * wildcard on purpose - a player asking "which of my mods can conjure things"
336
+ * must be able to read the answer off one line, and no broader grant may ever
337
+ * carry this one along. */
338
+ if (cap === "debug:spawn") {
339
+ return { kind: "debug", action: "spawn" };
340
+ }
341
+ /* "debug:wizard": drive the whole debug set - depth, experience, gold, stats,
342
+ * acquirement, mapping - and not just the two spawns. A separate string from
343
+ * "debug:spawn" because it is a separate bargain, not a bigger helping of the
344
+ * same one. Spawning acts on the character the player is actually playing, after
345
+ * the game's own question, and leaves them playing it. This one refuses to run
346
+ * at all until the session has been cut loose from its save slot, one way, so
347
+ * the character it happens to has already stopped being written to disk. Neither
348
+ * is a superset of the other - one costs the score, the other costs the session -
349
+ * so `grantCovers` compares the action and neither can be sold under the other's
350
+ * sentence. */
351
+ if (cap === "debug:wizard") {
352
+ return { kind: "debug", action: "wizard" };
353
+ }
223
354
  const ui = UI_RE.exec(cap);
224
355
  if (ui) {
225
356
  return { kind: "ui", region: ui[1], action: "replace" };
@@ -230,6 +361,12 @@ export function parseCapability(cap) {
230
361
  if (UI_CREATE_RE.test(cap)) {
231
362
  return { kind: "ui", region: "region", action: "create" };
232
363
  }
364
+ /* `panel` is the region NAME, on the same terms `region` is above: the literal
365
+ * the author wrote, so one `kind: "ui"` arm keeps one shape. `action` is what
366
+ * separates the three, and `grantCovers` compares it. */
367
+ if (UI_MOUNT_RE.test(cap)) {
368
+ return { kind: "ui", region: "panel", action: "mount" };
369
+ }
233
370
  const event = EVENT_RE.exec(cap);
234
371
  if (event) {
235
372
  return { kind: "event", name: event[1] };
@@ -278,6 +415,25 @@ function grantCovers(grant, request) {
278
415
  /* Exact match only, same reasoning as "display" - there is exactly one
279
416
  * backup capability and no wildcard grant could ever cover it. */
280
417
  return grant.kind === "backup";
418
+ case "mod":
419
+ /* THE ACTION IS COMPARED, not just the kind, and it is the #261 lesson
420
+ * applied before it could be re-learned here: `mod:install` puts a pack in
421
+ * the library switched off, `mod:session` switches one on for the rest of the
422
+ * session. Neither is a superset of the other, there is no wildcard, and a
423
+ * kind-only comparison would have let one consent buy both. */
424
+ return grant.kind === "mod" && grant.action === request.action;
425
+ case "debug":
426
+ /* Exact match only, and here that is the point rather than a consequence:
427
+ * this is the grant a player is most likely to check for by name, so it
428
+ * must never be reachable through anything wider.
429
+ *
430
+ * THE ACTION IS COMPARED, and until "debug:wizard" landed it was not - which
431
+ * was invisible while "spawn" was the only action, and would have been a real
432
+ * hole the moment a second one existed: a player who agreed to a mod
433
+ * conjuring one monster would have been granting it the depth jumps, the
434
+ * experience and the acquirement too. Exactly the #261 lesson, caught by
435
+ * adding the second action rather than by shipping it. */
436
+ return grant.kind === "debug" && grant.action === request.action;
281
437
  case "ui":
282
438
  /* Per region, with one wildcard. A `display` grant is NOT accepted here
283
439
  * and a `ui` grant is not accepted above: owning the dungeon and owning
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpgm-tools/neo-angband-mod-sdk",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Pack schemas, validation, and tooling for Neo Angband mods (content packs, tile packs, scripted plugins)",
5
5
  "license": "GPL-2.0-only",
6
6
  "author": "neostryder (RPGM Tools)",
@@ -131,6 +131,70 @@
131
131
  * write to it succeeded or failed. Its own kind,
132
132
  * like "display:replace" - there is nothing to
133
133
  * range over, so it has no wildcard either.
134
+ * - "mod:install" - install a CONTENT mod from archive bytes the mod
135
+ * holds in memory, through the same door the
136
+ * player's own zip import uses. Its own kind, like
137
+ * "display:replace": there is nothing to range over,
138
+ * so it has no wildcard. Two things bound it, and
139
+ * they are what make it proportionate rather than
140
+ * total. An archive that ships CODE, or whose
141
+ * manifest asks for any capability, is refused - so
142
+ * this grants "may add records to my library", not
143
+ * "may write and deploy a program". And an install
144
+ * is not an ENABLE: what arrives is switched off, and
145
+ * the player is shown its own capability list before
146
+ * any of it runs, which is what stops one grant
147
+ * turning into every grant.
148
+ * - "mod:session" - load a CONTENT mod into this session only, so it
149
+ * composes into the game on the next reload and is
150
+ * gone with the window. Bounded exactly as
151
+ * "mod:install" is - code and capability requests are
152
+ * refused - and deliberately NOT the same grant, since
153
+ * an install waits to be switched on and this does not.
154
+ * `grantCovers` compares the action so neither can be
155
+ * sold under the other's sentence. It is a shorter
156
+ * LIFETIME for the archive and not a smaller reach for
157
+ * the records: what composes, composes.
158
+ * - "debug:spawn" - conjure an item or a creature into the live game the
159
+ * way the debug commands do. Its own kind and no
160
+ * wildcard, and here that is the whole point rather
161
+ * than a consequence of there being one string: this
162
+ * is the grant a player is most likely to want to
163
+ * check for by name, so it must never arrive as part
164
+ * of something broader. What it adds over what a
165
+ * plugin can already reach through `ctx.core` is not
166
+ * the ability - `wizCreateObj` and friends take a
167
+ * `debug` flag the CALLER supplies - but the mark: the
168
+ * character is asked about and flagged, through the
169
+ * game's own confirmation and before anything is
170
+ * placed, so "the debug commands cannot be scored"
171
+ * stays true with a mod in the picture.
172
+ * - "debug:wizard" - drive the WHOLE debug set, not just the two spawns:
173
+ * depth, experience, gold, stats, acquirement,
174
+ * mapping. Its own action beside "spawn" rather than a
175
+ * wider reading of it, because the two cost the player
176
+ * different things. Spawning happens to the character
177
+ * they are playing and costs them the score. This one
178
+ * refuses to run until the session has been cut loose
179
+ * from its save slot - one way, checked by the host on
180
+ * every call - so it costs them the session and leaves
181
+ * the character on disk untouched. Neither is a
182
+ * superset of the other and `grantCovers` compares the
183
+ * action, so one consent cannot buy both.
184
+ * - "ui:panel.mount" - draw with real HTML instead of the character grid: a
185
+ * panel of the mod's own, mounted on the page above
186
+ * the game. A THIRD "ui:" action, and the reason it is
187
+ * not a third region name is the same reason
188
+ * "ui:region.create" is not a seventh: the sentence a
189
+ * player agrees to is different. "replace" hands over
190
+ * something the game draws, "create" adds a rectangle
191
+ * of the game's own character grid, and this one puts
192
+ * a piece of web page on top - which can look like the
193
+ * game's own interface, style anything inside itself,
194
+ * and read what the player types into it. No wildcard,
195
+ * and "ui:*.replace" does not cover it: `grantCovers`
196
+ * compares the action, so a mod that may redraw the
197
+ * vitals still cannot mount a panel without asking.
134
198
  * - "ui:region.create" - ADD a rectangle of your own to the player's screen
135
199
  * (ModPlugin.regions), rather than take one of the
136
200
  * game's. The only "ui:" capability whose ACTION is
@@ -163,8 +227,10 @@ export type ParsedCapability =
163
227
  | { kind: "network"; host: string }
164
228
  | { kind: "registry"; domain: string }
165
229
  | { kind: "display"; action: "replace" }
166
- | { kind: "ui"; region: string; action: "replace" | "create" }
167
- | { kind: "backup"; action: "folder" };
230
+ | { kind: "ui"; region: string; action: "replace" | "create" | "mount" }
231
+ | { kind: "backup"; action: "folder" }
232
+ | { kind: "mod"; action: "install" | "session" }
233
+ | { kind: "debug"; action: "spawn" | "wizard" };
168
234
 
169
235
  const EVENT_RE = /^event:([a-z][a-z0-9-]*)$/;
170
236
  /**
@@ -203,6 +269,34 @@ const UI_RE = /^ui:(\*|messages|sidebar|status|menu|screen)\.replace$/;
203
269
  * the note there.
204
270
  */
205
271
  const UI_CREATE_RE = /^ui:region\.create$/;
272
+ /**
273
+ * `ui:panel.mount` - draw with real HTML instead of the character grid.
274
+ *
275
+ * A THIRD ACTION, for the same reason `create` was a second one rather than a
276
+ * seventh region name: what the player is agreeing to is a different sentence.
277
+ * `replace` hands a mod something the game already draws. `create` gives it a
278
+ * rectangle of the game's own character grid, painted with the same seven
279
+ * methods every other surface has. This one puts a piece of WEB PAGE above the
280
+ * game - arbitrary markup and styling, which can be made to look exactly like
281
+ * the game's own interface, and which can hold a real text field and read what
282
+ * is typed into it.
283
+ *
284
+ * NO WILDCARD, for the reason `create` has none: a mod either may mount panels
285
+ * or it may not, and there is no set of panel names to range over, because a
286
+ * panel does not exist until the mod asks for one.
287
+ *
288
+ * AND `ui:*.replace` MUST NOT COVER IT. `grantCovers` compares the action as
289
+ * well as the region, so this holds by construction rather than by a rule
290
+ * somebody has to remember - which is exactly what that comparison was added
291
+ * for when `create` arrived.
292
+ *
293
+ * WHAT IT IS NOT. It is not a containment boundary and this module's header
294
+ * already says why: a plugin's code runs in the page's own realm and can reach
295
+ * the document with no capability at all. What this grant buys is a panel the
296
+ * HOST owns - one it can place, stack, take the keyboard back from and close -
297
+ * plus a sentence the player reads before any of it happens.
298
+ */
299
+ const UI_MOUNT_RE = /^ui:panel\.mount$/;
206
300
  const STATE_RE = /^state:(\*|[a-z][a-z0-9-]*)\.read$/;
207
301
  const NETWORK_RE = /^network:(\*|[a-zA-Z0-9.-]+)$/;
208
302
  /** The override domains ModRegistryHost gates, plus the "*" wildcard. */
@@ -235,6 +329,45 @@ export function parseCapability(cap: string): ParsedCapability {
235
329
  if (cap === "backup:folder") {
236
330
  return { kind: "backup", action: "folder" };
237
331
  }
332
+ /* "mod:install": hand archive bytes to the same install door the player's own
333
+ * zip import uses. Its own kind and no wildcard, same reasoning as the two
334
+ * above. What bounds it is not this grammar - it is that the door refuses an
335
+ * archive carrying code or asking for capabilities, and that installing is not
336
+ * enabling, so what arrives is consented to on its own terms before it runs. */
337
+ if (cap === "mod:install") {
338
+ return { kind: "mod", action: "install" };
339
+ }
340
+ /* "mod:session": load content into THIS session only, without it joining the
341
+ * library. Bounded the same way `mod:install` is - the door refuses an archive
342
+ * carrying code or asking for capabilities - and separated from it because the
343
+ * two say different things to a player. An install arrives switched OFF and waits
344
+ * to be turned on; a session load is on for the rest of the session as soon as
345
+ * the game reloads. That is more, not less, so it cannot be sold under the other
346
+ * one's sentence: `grantCovers` compares the action for exactly that reason. */
347
+ if (cap === "mod:session") {
348
+ return { kind: "mod", action: "session" };
349
+ }
350
+ /* "debug:spawn": put an item or a creature into the live game the way the debug
351
+ * commands do, marking the character the way they do. Its own kind and no
352
+ * wildcard on purpose - a player asking "which of my mods can conjure things"
353
+ * must be able to read the answer off one line, and no broader grant may ever
354
+ * carry this one along. */
355
+ if (cap === "debug:spawn") {
356
+ return { kind: "debug", action: "spawn" };
357
+ }
358
+ /* "debug:wizard": drive the whole debug set - depth, experience, gold, stats,
359
+ * acquirement, mapping - and not just the two spawns. A separate string from
360
+ * "debug:spawn" because it is a separate bargain, not a bigger helping of the
361
+ * same one. Spawning acts on the character the player is actually playing, after
362
+ * the game's own question, and leaves them playing it. This one refuses to run
363
+ * at all until the session has been cut loose from its save slot, one way, so
364
+ * the character it happens to has already stopped being written to disk. Neither
365
+ * is a superset of the other - one costs the score, the other costs the session -
366
+ * so `grantCovers` compares the action and neither can be sold under the other's
367
+ * sentence. */
368
+ if (cap === "debug:wizard") {
369
+ return { kind: "debug", action: "wizard" };
370
+ }
238
371
  const ui = UI_RE.exec(cap);
239
372
  if (ui) {
240
373
  return { kind: "ui", region: ui[1] as string, action: "replace" };
@@ -245,6 +378,12 @@ export function parseCapability(cap: string): ParsedCapability {
245
378
  if (UI_CREATE_RE.test(cap)) {
246
379
  return { kind: "ui", region: "region", action: "create" };
247
380
  }
381
+ /* `panel` is the region NAME, on the same terms `region` is above: the literal
382
+ * the author wrote, so one `kind: "ui"` arm keeps one shape. `action` is what
383
+ * separates the three, and `grantCovers` compares it. */
384
+ if (UI_MOUNT_RE.test(cap)) {
385
+ return { kind: "ui", region: "panel", action: "mount" };
386
+ }
248
387
  const event = EVENT_RE.exec(cap);
249
388
  if (event) {
250
389
  return { kind: "event", name: event[1] as string };
@@ -300,6 +439,25 @@ function grantCovers(grant: ParsedCapability, request: ParsedCapability): boolea
300
439
  /* Exact match only, same reasoning as "display" - there is exactly one
301
440
  * backup capability and no wildcard grant could ever cover it. */
302
441
  return grant.kind === "backup";
442
+ case "mod":
443
+ /* THE ACTION IS COMPARED, not just the kind, and it is the #261 lesson
444
+ * applied before it could be re-learned here: `mod:install` puts a pack in
445
+ * the library switched off, `mod:session` switches one on for the rest of the
446
+ * session. Neither is a superset of the other, there is no wildcard, and a
447
+ * kind-only comparison would have let one consent buy both. */
448
+ return grant.kind === "mod" && grant.action === request.action;
449
+ case "debug":
450
+ /* Exact match only, and here that is the point rather than a consequence:
451
+ * this is the grant a player is most likely to check for by name, so it
452
+ * must never be reachable through anything wider.
453
+ *
454
+ * THE ACTION IS COMPARED, and until "debug:wizard" landed it was not - which
455
+ * was invisible while "spawn" was the only action, and would have been a real
456
+ * hole the moment a second one existed: a player who agreed to a mod
457
+ * conjuring one monster would have been granting it the depth jumps, the
458
+ * experience and the acquirement too. Exactly the #261 lesson, caught by
459
+ * adding the second action rather than by shipping it. */
460
+ return grant.kind === "debug" && grant.action === request.action;
303
461
  case "ui":
304
462
  /* Per region, with one wildcard. A `display` grant is NOT accepted here
305
463
  * and a `ui` grant is not accepted above: owning the dungeon and owning