@sharpee/plugins 3.1.0 → 3.5.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.
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The banded-scalar crossing engine (ADR-262).
3
+ *
4
+ * A continuous meter — score, hunger severity, madness — is a number that moves.
5
+ * As it moves it crosses *bands* (ranks, hunger stages) at absolute thresholds.
6
+ * This module is the shared machinery that detects those crossings and turns
7
+ * them into events, so each metering concept keeps only its bespoke Chord
8
+ * surface and lowers to one engine (ADR-262 D1).
9
+ *
10
+ * Two responsibilities, split into two plugin factories over one detector:
11
+ *
12
+ * - {@link createBandDataWatcher} emits the generic **data** event
13
+ * `if.event.band_crossed` carrying the whole crossed span (ADR-262 D2). It
14
+ * is the always-on part — a TypeScript story reads it and renders promotions
15
+ * itself; a Chord story gets it too.
16
+ * - {@link createBandNarrator} emits **narration** events carrying a messageId
17
+ * under the four verbosity modes (ADR-262 D3). This is the Chord render
18
+ * layer; a rung with no author phrase speaks an overridable platform
19
+ * fallback, and only `silent` suppresses.
20
+ *
21
+ * Both share {@link BandCrossingDetector}: rise-only (ADR-262 D5), the band is
22
+ * derived from the value every turn via `bandOf`, and the only persisted state
23
+ * is the last-announced band id, for crossing edge-detection across
24
+ * save/restore.
25
+ */
26
+ import { type WorldModel } from '@sharpee/world-model';
27
+ import type { TurnPlugin } from './turn-plugin.js';
28
+ /** How a consumer narrates a crossing (ADR-262 D3). */
29
+ export type BandAnnounceMode = 'all' | 'collapsed' | 'combined' | 'silent';
30
+ /**
31
+ * A rung the engine tracks: a stable id, its absolute threshold, an optional
32
+ * display name (for narration params), and an optional per-band narration
33
+ * phrase message id (the author's `says` key, resolved to a message id).
34
+ */
35
+ export interface BandRung {
36
+ id: string;
37
+ threshold: number;
38
+ name?: string;
39
+ phraseId?: string;
40
+ }
41
+ /** The span a value crossed on one turn (ADR-262 D2). */
42
+ export interface BandCrossingSpan {
43
+ concept: string;
44
+ /** The band left behind (the last announced), or null from the bottom. */
45
+ fromId: string | null;
46
+ /** The band reached this turn. */
47
+ toId: string;
48
+ /** Every band entered this turn, in order — excludes `from`, includes `to`. */
49
+ rungsCrossed: BandRung[];
50
+ /** The scalar value at the crossing. */
51
+ value: number;
52
+ }
53
+ /** Payload of `if.event.band_crossed` (ADR-262 D2) — ids, never display names. */
54
+ export interface BandCrossedData {
55
+ concept: string;
56
+ from: string | null;
57
+ to: string;
58
+ bandsCrossed: string[];
59
+ value: number;
60
+ }
61
+ /** Shared configuration for both the data watcher and the narrator. */
62
+ export interface BandCrossingConfig {
63
+ /** Unique plugin id. */
64
+ id: string;
65
+ /** Run order; a crossing observes a turn others produced, so keep it low. */
66
+ priority: number;
67
+ /** The concept name carried in the data event and params. */
68
+ concept: string;
69
+ /** Gate: skip entirely when the concept is not installed (e.g. scoring off). */
70
+ isEnabled?: (world: WorldModel) => boolean;
71
+ /** Read the current scalar value from the world. */
72
+ value: (world: WorldModel) => number;
73
+ /** Read the ordered bands (ascending by threshold) from the world. */
74
+ bands: (world: WorldModel) => BandRung[];
75
+ /**
76
+ * Silently seed the baseline when the value is at or below this — the bottom
77
+ * rung is where the player *starts*, so announcing it would report a
78
+ * promotion no one earned (scoring's rung-at-0 case). Omit when the meter
79
+ * starts below every band (hunger: severity 0 is below all rungs).
80
+ */
81
+ seedAtOrBelow?: number;
82
+ }
83
+ /** Serialized state: the id of the band last announced. */
84
+ export interface BandWatcherState {
85
+ lastAnnouncedId: string | null;
86
+ }
87
+ /**
88
+ * A watcher that emits the generic `if.event.band_crossed` data event on a rise
89
+ * (ADR-262 D2). One event per turn, carrying the whole crossed span, no
90
+ * messageId. `dataEventId` is passed in (typically `IFEvents.BAND_CROSSED`) so
91
+ * this package stays free of if-domain.
92
+ */
93
+ export declare function createBandDataWatcher(config: BandCrossingConfig, dataEventId: string): TurnPlugin;
94
+ /** Params handed to a narration message (ADR-262 D4). */
95
+ export interface BandNarrationParams extends Record<string, unknown> {
96
+ band: string;
97
+ from: string | null;
98
+ to: string;
99
+ count: number;
100
+ bands: string;
101
+ value: number;
102
+ }
103
+ export interface BandNarratorConfig extends BandCrossingConfig {
104
+ mode: BandAnnounceMode;
105
+ /**
106
+ * The event id carrying the narration messageId (rendered via ADR-097). Its
107
+ * payload is `{ messageId, params }`.
108
+ */
109
+ narrationEventId: string;
110
+ /** Message id spoken when a crossed rung has no author phrase (ADR-262 D3). */
111
+ fallbackPhraseId: string;
112
+ /** The concept-level span phrase for `combined` mode (ADR-262 D4). */
113
+ combinedPhraseId?: string;
114
+ /**
115
+ * Map a rung + span to message params. Defaults to the generic
116
+ * {@link BandNarrationParams}; a concept overrides it to match its authored
117
+ * `says` phrases (scoring keeps `{rank}`/`{score}`).
118
+ */
119
+ paramsFor?: (rung: BandRung, span: BandCrossingSpan) => Record<string, unknown>;
120
+ }
121
+ /**
122
+ * A narrator that renders a crossing under the four announce modes (ADR-262
123
+ * D3): `all` speaks each crossed band's phrase, `collapsed` only the terminal
124
+ * band's, `combined` one span message, `silent` nothing. A crossed rung with no
125
+ * phrase speaks the overridable `fallbackPhraseId`, so silence comes only from
126
+ * `silent`.
127
+ */
128
+ export declare function createBandNarrator(config: BandNarratorConfig): TurnPlugin;
129
+ //# sourceMappingURL=band-crossing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"band-crossing.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/band-crossing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,uDAAuD;AACvD,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE3E;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,YAAY,EAAE,QAAQ,EAAE,CAAC;IACzB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC;IAC3C,oDAAoD;IACpD,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;IACrC,sEAAsE;IACtE,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,QAAQ,EAAE,CAAC;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,2DAA2D;AAC3D,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAmFD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,MAAM,GAClB,UAAU,CAWZ;AAED,yDAAyD;AACzD,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,IAAI,EAAE,gBAAgB,CAAC;IACvB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,UAAU,CA+BzE"}
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ /**
3
+ * The banded-scalar crossing engine (ADR-262).
4
+ *
5
+ * A continuous meter — score, hunger severity, madness — is a number that moves.
6
+ * As it moves it crosses *bands* (ranks, hunger stages) at absolute thresholds.
7
+ * This module is the shared machinery that detects those crossings and turns
8
+ * them into events, so each metering concept keeps only its bespoke Chord
9
+ * surface and lowers to one engine (ADR-262 D1).
10
+ *
11
+ * Two responsibilities, split into two plugin factories over one detector:
12
+ *
13
+ * - {@link createBandDataWatcher} emits the generic **data** event
14
+ * `if.event.band_crossed` carrying the whole crossed span (ADR-262 D2). It
15
+ * is the always-on part — a TypeScript story reads it and renders promotions
16
+ * itself; a Chord story gets it too.
17
+ * - {@link createBandNarrator} emits **narration** events carrying a messageId
18
+ * under the four verbosity modes (ADR-262 D3). This is the Chord render
19
+ * layer; a rung with no author phrase speaks an overridable platform
20
+ * fallback, and only `silent` suppresses.
21
+ *
22
+ * Both share {@link BandCrossingDetector}: rise-only (ADR-262 D5), the band is
23
+ * derived from the value every turn via `bandOf`, and the only persisted state
24
+ * is the last-announced band id, for crossing edge-detection across
25
+ * save/restore.
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.createBandDataWatcher = createBandDataWatcher;
29
+ exports.createBandNarrator = createBandNarrator;
30
+ const core_1 = require("@sharpee/core");
31
+ const world_model_1 = require("@sharpee/world-model");
32
+ /**
33
+ * The crossing detector shared by both plugin factories. Holds the
34
+ * last-announced band id, derives the current band from the value every turn,
35
+ * and returns the crossed span on a rise (or null: not enabled, no bands, at
36
+ * the seeded baseline, same band, or a fall).
37
+ */
38
+ class BandCrossingDetector {
39
+ config;
40
+ lastAnnouncedId = null;
41
+ constructor(config) {
42
+ this.config = config;
43
+ }
44
+ detect(world) {
45
+ const { config } = this;
46
+ if (config.isEnabled && !config.isEnabled(world))
47
+ return null;
48
+ const bands = config.bands(world);
49
+ if (bands.length === 0)
50
+ return null;
51
+ const value = config.value(world);
52
+ const currentIndex = (0, world_model_1.bandOf)(value, bands.map(b => b.threshold));
53
+ // Baseline seed: at/below the start value, adopt the current band silently
54
+ // so the bottom rung never fires as a promotion (ADR-262, scoring's score<=0).
55
+ if (config.seedAtOrBelow !== undefined && value <= config.seedAtOrBelow) {
56
+ this.lastAnnouncedId = currentIndex < 0 ? null : bands[currentIndex].id;
57
+ return null;
58
+ }
59
+ // Below every band: out of the ladder entirely. Reset so a later rise reads
60
+ // as a fresh crossing from the bottom (hunger recovering below `peckish`).
61
+ if (currentIndex < 0) {
62
+ this.lastAnnouncedId = null;
63
+ return null;
64
+ }
65
+ const lastIndex = this.lastAnnouncedId === null
66
+ ? -1
67
+ : bands.findIndex(b => b.id === this.lastAnnouncedId);
68
+ // Rise only (ADR-262 D5). Same band or a fall: track the position so
69
+ // re-crossing announces again, but say nothing now.
70
+ if (currentIndex <= lastIndex) {
71
+ this.lastAnnouncedId = bands[currentIndex].id;
72
+ return null;
73
+ }
74
+ const rungsCrossed = bands.slice(lastIndex + 1, currentIndex + 1);
75
+ const fromId = lastIndex < 0 ? null : bands[lastIndex].id;
76
+ const toId = bands[currentIndex].id;
77
+ this.lastAnnouncedId = toId;
78
+ return { concept: config.concept, fromId, toId, rungsCrossed, value };
79
+ }
80
+ getState() {
81
+ return { lastAnnouncedId: this.lastAnnouncedId };
82
+ }
83
+ setState(state) {
84
+ this.lastAnnouncedId = state?.lastAnnouncedId ?? null;
85
+ }
86
+ }
87
+ /** A plugin built from a detector plus an emit strategy. */
88
+ function makePlugin(config, emit) {
89
+ const detector = new BandCrossingDetector(config);
90
+ return {
91
+ id: config.id,
92
+ priority: config.priority,
93
+ onAfterAction(ctx) {
94
+ const span = detector.detect(ctx.world);
95
+ return span ? emit(span) : [];
96
+ },
97
+ getState: () => detector.getState(),
98
+ setState: (state) => detector.setState(state),
99
+ };
100
+ }
101
+ /**
102
+ * A watcher that emits the generic `if.event.band_crossed` data event on a rise
103
+ * (ADR-262 D2). One event per turn, carrying the whole crossed span, no
104
+ * messageId. `dataEventId` is passed in (typically `IFEvents.BAND_CROSSED`) so
105
+ * this package stays free of if-domain.
106
+ */
107
+ function createBandDataWatcher(config, dataEventId) {
108
+ return makePlugin(config, (span) => {
109
+ const data = {
110
+ concept: span.concept,
111
+ from: span.fromId,
112
+ to: span.toId,
113
+ bandsCrossed: span.rungsCrossed.map(r => r.id),
114
+ value: span.value,
115
+ };
116
+ return [(0, core_1.createEvent)(dataEventId, data)];
117
+ });
118
+ }
119
+ /**
120
+ * A narrator that renders a crossing under the four announce modes (ADR-262
121
+ * D3): `all` speaks each crossed band's phrase, `collapsed` only the terminal
122
+ * band's, `combined` one span message, `silent` nothing. A crossed rung with no
123
+ * phrase speaks the overridable `fallbackPhraseId`, so silence comes only from
124
+ * `silent`.
125
+ */
126
+ function createBandNarrator(config) {
127
+ const genericParams = (rung, span) => ({
128
+ band: rung.name ?? rung.id,
129
+ from: span.fromId,
130
+ to: span.toId,
131
+ count: span.rungsCrossed.length,
132
+ bands: span.rungsCrossed.map(r => r.name ?? r.id).join(', '),
133
+ value: span.value,
134
+ });
135
+ const paramsFor = config.paramsFor ?? genericParams;
136
+ const line = (messageId, params) => (0, core_1.createEvent)(config.narrationEventId, { messageId, params });
137
+ return makePlugin(config, (span) => {
138
+ switch (config.mode) {
139
+ case 'silent':
140
+ return [];
141
+ case 'all':
142
+ return span.rungsCrossed.map(rung => line(rung.phraseId ?? config.fallbackPhraseId, paramsFor(rung, span)));
143
+ case 'collapsed': {
144
+ const top = span.rungsCrossed[span.rungsCrossed.length - 1];
145
+ return [line(top.phraseId ?? config.fallbackPhraseId, paramsFor(top, span))];
146
+ }
147
+ case 'combined': {
148
+ const top = span.rungsCrossed[span.rungsCrossed.length - 1];
149
+ return [line(config.combinedPhraseId ?? config.fallbackPhraseId, genericParams(top, span))];
150
+ }
151
+ }
152
+ });
153
+ }
154
+ //# sourceMappingURL=band-crossing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"band-crossing.js","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/band-crossing.ts"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export { TurnPlugin } from './turn-plugin';
2
- export { TurnPluginContext, TurnPluginActionResult } from './turn-plugin-context';
3
- export { PluginRegistry } from './plugin-registry';
1
+ export { TurnPlugin } from './turn-plugin.js';
2
+ export { TurnPluginContext, TurnPluginActionResult } from './turn-plugin-context.js';
3
+ export { PluginRegistry } from './plugin-registry.js';
4
+ export { createBandDataWatcher, createBandNarrator, } from './band-crossing.js';
5
+ export type { BandAnnounceMode, BandRung, BandCrossingSpan, BandCrossedData, BandCrossingConfig, BandWatcherState, BandNarrationParams, BandNarratorConfig, } from './band-crossing.js';
4
6
  //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
package/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PluginRegistry = void 0;
4
- var plugin_registry_1 = require("./plugin-registry");
5
- Object.defineProperty(exports, "PluginRegistry", { enumerable: true, get: function () { return plugin_registry_1.PluginRegistry; } });
3
+ exports.createBandNarrator = exports.createBandDataWatcher = exports.PluginRegistry = void 0;
4
+ var plugin_registry_js_1 = require("./plugin-registry.js");
5
+ Object.defineProperty(exports, "PluginRegistry", { enumerable: true, get: function () { return plugin_registry_js_1.PluginRegistry; } });
6
+ // Banded-scalar crossing engine (ADR-262)
7
+ var band_crossing_js_1 = require("./band-crossing.js");
8
+ Object.defineProperty(exports, "createBandDataWatcher", { enumerable: true, get: function () { return band_crossing_js_1.createBandDataWatcher; } });
9
+ Object.defineProperty(exports, "createBandNarrator", { enumerable: true, get: function () { return band_crossing_js_1.createBandNarrator; } });
6
10
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/index.ts"],"names":[],"mappings":";;;AAEA,qDAAmD;AAA1C,iHAAA,cAAc,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/index.ts"],"names":[],"mappings":";;;AAEA,2DAAsD;AAA7C,oHAAA,cAAc,OAAA;AAEvB,0CAA0C;AAC1C,uDAG4B;AAF1B,yHAAA,qBAAqB,OAAA;AACrB,sHAAA,kBAAkB,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sharpee/plugins",
3
- "version": "3.1.0",
3
+ "version": "3.5.0",
4
4
  "description": "Plugin contracts for Sharpee engine turn-cycle extensibility",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -12,8 +12,8 @@
12
12
  }
13
13
  },
14
14
  "dependencies": {
15
- "@sharpee/core": "^3.1.0",
16
- "@sharpee/world-model": "^3.1.0"
15
+ "@sharpee/core": "^3.5.0",
16
+ "@sharpee/world-model": "^3.5.0"
17
17
  },
18
18
  "keywords": [
19
19
  "interactive-fiction",
@@ -1,4 +1,4 @@
1
- import { TurnPlugin } from './turn-plugin';
1
+ import { TurnPlugin } from './turn-plugin.js';
2
2
  /**
3
3
  * Holds the turn plugins for a running game and hands them to the engine in
4
4
  * priority order each turn (ADR-120). The engine owns the single registry;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/plugin-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAsC;IAErD,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAOlC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAIb,8EAA8E;IAC9E,MAAM,IAAI,UAAU,EAAE;IAMtB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3C;;;OAGG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUpC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAQjD"}
1
+ {"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/plugin-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAsC;IAErD,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAOlC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAIb,8EAA8E;IAC9E,MAAM,IAAI,UAAU,EAAE;IAMtB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3C;;;OAGG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUpC;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAQjD"}
@@ -4,7 +4,15 @@ import { WorldModel } from '@sharpee/world-model';
4
4
  export interface TurnPluginActionResult {
5
5
  /** The action's id (the verb that ran). */
6
6
  actionId: string;
7
- /** Whether the action succeeded. Plugins only run after successful actions. */
7
+ /**
8
+ * Whether the action GENUINELY succeeded (platform-issue-sweep Phase 7):
9
+ * false when the action was refused/blocked — including modern blocked()
10
+ * paths that reuse the primary event type with `blocked: true` /
11
+ * `failed: true` instead of emitting `action.error`. Plugins still run
12
+ * after refused actions (NPC/scheduler ticks are turn-level); consumers
13
+ * that must not react to refusals (state-machine action triggers) gate on
14
+ * this flag.
15
+ */
8
16
  success: boolean;
9
17
  /** The action's direct-object entity, when it had one. */
10
18
  targetId?: EntityId;
@@ -1 +1 @@
1
- {"version":3,"file":"turn-plugin-context.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/turn-plugin-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACrC,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,wCAAwC;IACxC,cAAc,EAAE,QAAQ,CAAC;IACzB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,gDAAgD;IAChD,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,wDAAwD;IACxD,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;CACjC"}
1
+ {"version":3,"file":"turn-plugin-context.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/turn-plugin-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACrC,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,wCAAwC;IACxC,cAAc,EAAE,QAAQ,CAAC;IACzB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,gDAAgD;IAChD,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,wDAAwD;IACxD,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;CACjC"}
package/turn-plugin.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ISemanticEvent } from '@sharpee/core';
2
- import { TurnPluginContext } from './turn-plugin-context';
2
+ import { TurnPluginContext } from './turn-plugin-context.js';
3
3
  /**
4
4
  * A turn-cycle plugin: code that runs once after each successful player action
5
5
  * to contribute additional world changes and events (ADR-120).
@@ -1 +1 @@
1
- {"version":3,"file":"turn-plugin.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/turn-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAAC;IAC5D,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,OAAO,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACjC"}
1
+ {"version":3,"file":"turn-plugin.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee_v2/packages/plugins/src/turn-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAAC;IAC5D,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,OAAO,CAAC;IACrB,wEAAwE;IACxE,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACjC"}