@sharpee/engine 0.9.60-beta
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/LICENSE +21 -0
- package/README.md +328 -0
- package/dist/action-context-factory.d.ts +11 -0
- package/dist/action-context-factory.d.ts.map +1 -0
- package/dist/action-context-factory.js +258 -0
- package/dist/action-context-factory.js.map +1 -0
- package/dist/capability-dispatch-helper.d.ts +106 -0
- package/dist/capability-dispatch-helper.d.ts.map +1 -0
- package/dist/capability-dispatch-helper.js +269 -0
- package/dist/capability-dispatch-helper.js.map +1 -0
- package/dist/command-executor.d.ts +53 -0
- package/dist/command-executor.d.ts.map +1 -0
- package/dist/command-executor.js +329 -0
- package/dist/command-executor.js.map +1 -0
- package/dist/event-adapter.d.ts +44 -0
- package/dist/event-adapter.d.ts.map +1 -0
- package/dist/event-adapter.js +127 -0
- package/dist/event-adapter.js.map +1 -0
- package/dist/event-sequencer.d.ts +73 -0
- package/dist/event-sequencer.d.ts.map +1 -0
- package/dist/event-sequencer.js +134 -0
- package/dist/event-sequencer.js.map +1 -0
- package/dist/events/event-emitter.d.ts +34 -0
- package/dist/events/event-emitter.d.ts.map +1 -0
- package/dist/events/event-emitter.js +67 -0
- package/dist/events/event-emitter.js.map +1 -0
- package/dist/game-engine.d.ts +292 -0
- package/dist/game-engine.d.ts.map +1 -0
- package/dist/game-engine.js +1631 -0
- package/dist/game-engine.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/narrative/index.d.ts +5 -0
- package/dist/narrative/index.d.ts.map +1 -0
- package/dist/narrative/index.js +10 -0
- package/dist/narrative/index.js.map +1 -0
- package/dist/narrative/narrative-settings.d.ts +73 -0
- package/dist/narrative/narrative-settings.d.ts.map +1 -0
- package/dist/narrative/narrative-settings.js +28 -0
- package/dist/narrative/narrative-settings.js.map +1 -0
- package/dist/parser-interface.d.ts +77 -0
- package/dist/parser-interface.d.ts.map +1 -0
- package/dist/parser-interface.js +48 -0
- package/dist/parser-interface.js.map +1 -0
- package/dist/platform-operations.d.ts +83 -0
- package/dist/platform-operations.d.ts.map +1 -0
- package/dist/platform-operations.js +218 -0
- package/dist/platform-operations.js.map +1 -0
- package/dist/save-restore-service.d.ts +133 -0
- package/dist/save-restore-service.d.ts.map +1 -0
- package/dist/save-restore-service.js +446 -0
- package/dist/save-restore-service.js.map +1 -0
- package/dist/scheduler/index.d.ts +9 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +25 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/scheduler-service.d.ts +75 -0
- package/dist/scheduler/scheduler-service.d.ts.map +1 -0
- package/dist/scheduler/scheduler-service.js +310 -0
- package/dist/scheduler/scheduler-service.js.map +1 -0
- package/dist/scheduler/seeded-random.d.ts +7 -0
- package/dist/scheduler/seeded-random.d.ts.map +1 -0
- package/dist/scheduler/seeded-random.js +11 -0
- package/dist/scheduler/seeded-random.js.map +1 -0
- package/dist/scheduler/types.d.ts +134 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +9 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/shared-data-keys.d.ts +53 -0
- package/dist/shared-data-keys.d.ts.map +1 -0
- package/dist/shared-data-keys.js +29 -0
- package/dist/shared-data-keys.js.map +1 -0
- package/dist/story.d.ts +211 -0
- package/dist/story.d.ts.map +1 -0
- package/dist/story.js +60 -0
- package/dist/story.js.map +1 -0
- package/dist/test-helpers/mock-text-service.d.ts +11 -0
- package/dist/test-helpers/mock-text-service.d.ts.map +1 -0
- package/dist/test-helpers/mock-text-service.js +47 -0
- package/dist/test-helpers/mock-text-service.js.map +1 -0
- package/dist/turn-event-processor.d.ts +89 -0
- package/dist/turn-event-processor.d.ts.map +1 -0
- package/dist/turn-event-processor.js +144 -0
- package/dist/turn-event-processor.js.map +1 -0
- package/dist/types.d.ts +214 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/vocabulary-manager.d.ts +35 -0
- package/dist/vocabulary-manager.d.ts.map +1 -0
- package/dist/vocabulary-manager.js +74 -0
- package/dist/vocabulary-manager.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 David Cornelson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# @sharpee/engine
|
|
2
|
+
|
|
3
|
+
Runtime engine for the Sharpee IF Platform. This package provides the core game loop, command execution, and turn management.
|
|
4
|
+
|
|
5
|
+
> **Architecture Update (Phase 3.5)**: The CommandExecutor has been refactored from a 723-line god object to a 177-line thin orchestrator. Actions now own their complete event lifecycle through the three-phase pattern (validate/execute/report).
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The engine package brings together all the Sharpee components into a running game:
|
|
10
|
+
|
|
11
|
+
- **GameEngine**: Main runtime that manages game state and turn execution
|
|
12
|
+
- **CommandExecutor**: Thin orchestrator (177 lines) that coordinates the action pipeline
|
|
13
|
+
- **EventSequencer**: Ensures events are properly ordered within turns (1.1, 1.2, 1.3...)
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
User Input
|
|
19
|
+
↓
|
|
20
|
+
[GameEngine]
|
|
21
|
+
↓
|
|
22
|
+
[CommandExecutor] (Thin Orchestrator)
|
|
23
|
+
├─→ [Parser] → ParsedCommand
|
|
24
|
+
├─→ [Validator] → ValidatedCommand
|
|
25
|
+
└─→ [Action] (Three-Phase Pattern)
|
|
26
|
+
├─→ validate() → ValidationResult
|
|
27
|
+
├─→ execute() → Mutations only
|
|
28
|
+
└─→ report() → ISemanticEvent[]
|
|
29
|
+
↓
|
|
30
|
+
[EventProcessor] → World Changes
|
|
31
|
+
↓
|
|
32
|
+
Turn Result
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Action Three-Phase Pattern
|
|
36
|
+
|
|
37
|
+
Actions follow a strict three-phase pattern for clean separation of concerns:
|
|
38
|
+
|
|
39
|
+
1. **Validate Phase**: Check if the action can be performed (no mutations)
|
|
40
|
+
2. **Execute Phase**: Perform state mutations only (no events)
|
|
41
|
+
3. **Report Phase**: Generate events based on final state (no mutations)
|
|
42
|
+
|
|
43
|
+
The CommandExecutor simply orchestrates these phases, delegating all responsibility to the appropriate components. Actions own their complete event lifecycle, including error events.
|
|
44
|
+
|
|
45
|
+
## Basic Usage
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { createStandardEngine } from '@sharpee/engine';
|
|
49
|
+
import { WorldModel } from '@sharpee/world-model';
|
|
50
|
+
|
|
51
|
+
// Create a game engine
|
|
52
|
+
const engine = createStandardEngine();
|
|
53
|
+
|
|
54
|
+
// Set language (NEW: automatic parser and language provider loading)
|
|
55
|
+
await engine.setLanguage('en-US');
|
|
56
|
+
|
|
57
|
+
// Or use a story with language configuration
|
|
58
|
+
const story = {
|
|
59
|
+
config: {
|
|
60
|
+
id: 'my-story',
|
|
61
|
+
title: 'My Adventure',
|
|
62
|
+
author: 'Me',
|
|
63
|
+
version: '1.0.0',
|
|
64
|
+
language: 'en-US' // Language automatically loaded
|
|
65
|
+
},
|
|
66
|
+
initializeWorld: (world) => { /* ... */ },
|
|
67
|
+
createPlayer: (world) => { /* ... */ }
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
await engine.setStory(story); // Automatically sets up language
|
|
71
|
+
|
|
72
|
+
// Start the engine
|
|
73
|
+
engine.start();
|
|
74
|
+
|
|
75
|
+
// Execute turns
|
|
76
|
+
const result = await engine.executeTurn('take sword');
|
|
77
|
+
console.log(`Turn ${result.turn}: ${result.success ? 'Success' : 'Failed'}`);
|
|
78
|
+
|
|
79
|
+
// Access game state
|
|
80
|
+
const context = engine.getContext();
|
|
81
|
+
console.log(`Current turn: ${context.currentTurn}`);
|
|
82
|
+
|
|
83
|
+
// Access parser and language provider if needed
|
|
84
|
+
const parser = engine.getParser();
|
|
85
|
+
const languageProvider = engine.getLanguageProvider();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Custom Game Engine
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { GameEngine, EngineConfig } from '@sharpee/engine';
|
|
92
|
+
import { IWorldModel, IFEntity } from '@sharpee/world-model';
|
|
93
|
+
|
|
94
|
+
// Create your world
|
|
95
|
+
const world: IWorldModel = createMyWorld();
|
|
96
|
+
const player: IFEntity = createPlayer();
|
|
97
|
+
|
|
98
|
+
// Configure engine
|
|
99
|
+
const config: EngineConfig = {
|
|
100
|
+
maxHistory: 50,
|
|
101
|
+
collectTiming: true,
|
|
102
|
+
onEvent: (event) => console.log(`Event: ${event.type}`),
|
|
103
|
+
onError: (error, context) => console.error(`Error at turn ${context.currentTurn}:`, error)
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Create engine
|
|
107
|
+
const engine = new GameEngine(world, player, config);
|
|
108
|
+
|
|
109
|
+
// Listen to engine events
|
|
110
|
+
engine.on('turn:complete', (result) => {
|
|
111
|
+
console.log(`Turn ${result.turn} complete with ${result.events.length} events`);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
engine.on('game:over', (context) => {
|
|
115
|
+
console.log('Game over!');
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Atomic Events Architecture
|
|
120
|
+
|
|
121
|
+
Events are self-contained with all necessary data embedded at creation time:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// Example event from taking action
|
|
125
|
+
{
|
|
126
|
+
type: 'if.event.taken',
|
|
127
|
+
timestamp: 1692345678,
|
|
128
|
+
data: {
|
|
129
|
+
itemSnapshot: { // Complete entity state
|
|
130
|
+
id: 'sword',
|
|
131
|
+
name: 'silver sword',
|
|
132
|
+
description: 'A gleaming blade',
|
|
133
|
+
location: 'player',
|
|
134
|
+
traits: { /* ... */ }
|
|
135
|
+
},
|
|
136
|
+
actorSnapshot: { /* ... */ }
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This enables:
|
|
142
|
+
- **Historical Replay**: Events contain complete state at that moment
|
|
143
|
+
- **No World Queries**: Text services use embedded data, not world lookups
|
|
144
|
+
- **Consistency**: Entity state is captured after all mutations complete
|
|
145
|
+
|
|
146
|
+
## Event Sequencing
|
|
147
|
+
|
|
148
|
+
Events are automatically sequenced within turns:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Turn 1
|
|
152
|
+
1.1 - action.started
|
|
153
|
+
1.2 - if.event.taken (main action)
|
|
154
|
+
1.3 - action.success
|
|
155
|
+
|
|
156
|
+
// Turn 2
|
|
157
|
+
2.1 - action.started
|
|
158
|
+
2.2 - if.event.exited (leaving room)
|
|
159
|
+
2.3 - if.event.entered (entering room)
|
|
160
|
+
2.4 - if.event.looked (auto-look)
|
|
161
|
+
2.5 - action.success
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Language Management
|
|
165
|
+
|
|
166
|
+
The engine automatically loads language providers and parsers based on language codes:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Set language directly
|
|
170
|
+
await engine.setLanguage('en-US'); // Loads @sharpee/lang-en-us and @sharpee/parser-en-us
|
|
171
|
+
|
|
172
|
+
// Change language at runtime
|
|
173
|
+
await engine.setLanguage('es'); // Switches to Spanish
|
|
174
|
+
|
|
175
|
+
// Language from story config
|
|
176
|
+
const story = {
|
|
177
|
+
config: { language: 'ja', /* ... */ }
|
|
178
|
+
};
|
|
179
|
+
await engine.setStory(story); // Automatically uses Japanese
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Naming Convention
|
|
183
|
+
|
|
184
|
+
Language packages follow a predictable naming pattern:
|
|
185
|
+
- Language Provider: `@sharpee/lang-{language-code}`
|
|
186
|
+
- Parser: `@sharpee/parser-{language-code}`
|
|
187
|
+
|
|
188
|
+
For example:
|
|
189
|
+
- English (US): `@sharpee/lang-en-us`, `@sharpee/parser-en-us`
|
|
190
|
+
- Spanish: `@sharpee/lang-es`, `@sharpee/parser-es`
|
|
191
|
+
- Japanese: `@sharpee/lang-ja`, `@sharpee/parser-ja`
|
|
192
|
+
|
|
193
|
+
## Save/Load
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Save game state
|
|
197
|
+
const saveData = engine.saveState();
|
|
198
|
+
localStorage.setItem('save', JSON.stringify(saveData));
|
|
199
|
+
|
|
200
|
+
// Load game state
|
|
201
|
+
const loadData = JSON.parse(localStorage.getItem('save'));
|
|
202
|
+
engine.loadState(loadData);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Integration with Story Files
|
|
206
|
+
|
|
207
|
+
The engine is designed to work with TypeScript story files:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// my-story.ts
|
|
211
|
+
import { Story } from '@sharpee/forge';
|
|
212
|
+
|
|
213
|
+
export default new Story()
|
|
214
|
+
.title('My Adventure')
|
|
215
|
+
.author('Me')
|
|
216
|
+
.room('start', room => room
|
|
217
|
+
.name('Starting Room')
|
|
218
|
+
.description('You are in a small room.')
|
|
219
|
+
.exit('north', 'hallway')
|
|
220
|
+
)
|
|
221
|
+
.build();
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## API Reference
|
|
225
|
+
|
|
226
|
+
### GameEngine
|
|
227
|
+
|
|
228
|
+
- `start()`: Start the engine
|
|
229
|
+
- `stop()`: Stop the engine
|
|
230
|
+
- `executeTurn(input: string)`: Execute a turn with user input
|
|
231
|
+
- `getContext()`: Get current game context
|
|
232
|
+
- `getWorld()`: Get world model
|
|
233
|
+
- `saveState()`: Save game state
|
|
234
|
+
- `loadState(state)`: Load game state
|
|
235
|
+
- `getHistory()`: Get turn history
|
|
236
|
+
- `getRecentEvents(count)`: Get recent events
|
|
237
|
+
- `setLanguage(languageCode: string)`: Set language (automatically loads parser and language provider)
|
|
238
|
+
- `setStory(story: Story)`: Set story (automatically configures language from story config)
|
|
239
|
+
- `getParser()`: Get current parser instance
|
|
240
|
+
- `getLanguageProvider()`: Get current language provider instance
|
|
241
|
+
|
|
242
|
+
### Events
|
|
243
|
+
|
|
244
|
+
The engine emits these events:
|
|
245
|
+
|
|
246
|
+
- `turn:start`: Turn is starting
|
|
247
|
+
- `turn:complete`: Turn completed successfully
|
|
248
|
+
- `turn:failed`: Turn failed with error
|
|
249
|
+
- `event`: Individual event processed
|
|
250
|
+
- `state:changed`: Game state changed
|
|
251
|
+
- `game:over`: Game has ended
|
|
252
|
+
|
|
253
|
+
### Turn Results
|
|
254
|
+
|
|
255
|
+
Each turn returns:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
interface TurnResult {
|
|
259
|
+
turn: number;
|
|
260
|
+
input: string;
|
|
261
|
+
events: SequencedEvent[];
|
|
262
|
+
success: boolean;
|
|
263
|
+
error?: string;
|
|
264
|
+
actionId?: string;
|
|
265
|
+
parsedCommand?: IParsedCommand;
|
|
266
|
+
timing?: TimingData;
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Where SequencedEvent includes:
|
|
271
|
+
```typescript
|
|
272
|
+
interface SequencedEvent {
|
|
273
|
+
type: string;
|
|
274
|
+
data: any;
|
|
275
|
+
sequence: number;
|
|
276
|
+
timestamp: Date;
|
|
277
|
+
turn: number;
|
|
278
|
+
scope: 'turn' | 'global' | 'system';
|
|
279
|
+
source?: string;
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Development
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Build the package
|
|
287
|
+
pnpm build
|
|
288
|
+
|
|
289
|
+
# Run tests
|
|
290
|
+
pnpm test
|
|
291
|
+
|
|
292
|
+
# Run tests with coverage
|
|
293
|
+
pnpm test:coverage
|
|
294
|
+
|
|
295
|
+
# Watch mode for tests
|
|
296
|
+
pnpm test:watch
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Testing
|
|
300
|
+
|
|
301
|
+
The engine package includes comprehensive test coverage:
|
|
302
|
+
|
|
303
|
+
### Unit Tests
|
|
304
|
+
- `game-engine.test.ts` - Core game engine functionality
|
|
305
|
+
- `command-executor.test.ts` - Command parsing and execution
|
|
306
|
+
- `event-sequencer.test.ts` - Event ordering and utilities
|
|
307
|
+
- `story.test.ts` - Story interface and configuration
|
|
308
|
+
- `text-service.test.ts` - Text output formatting
|
|
309
|
+
- `types.test.ts` - Type definitions and contracts
|
|
310
|
+
|
|
311
|
+
### Integration Tests
|
|
312
|
+
- `integration.test.ts` - Full game flow and component interaction
|
|
313
|
+
|
|
314
|
+
### Test Fixtures
|
|
315
|
+
- `fixtures/index.ts` - Reusable test utilities and mocks
|
|
316
|
+
|
|
317
|
+
### Running Tests
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Run all tests
|
|
321
|
+
pnpm test
|
|
322
|
+
|
|
323
|
+
# Run specific test file
|
|
324
|
+
pnpm test game-engine
|
|
325
|
+
|
|
326
|
+
# Generate coverage report
|
|
327
|
+
pnpm test:coverage
|
|
328
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Context Factory - Creates ActionContext for action execution
|
|
3
|
+
*/
|
|
4
|
+
import { ActionContext, Action, ScopeResolver, ValidatedCommand } from '@sharpee/stdlib';
|
|
5
|
+
import { WorldModel } from '@sharpee/world-model';
|
|
6
|
+
import { GameContext } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Create an ActionContext for action execution
|
|
9
|
+
*/
|
|
10
|
+
export declare function createActionContext(world: WorldModel, gameContext: GameContext, command: ValidatedCommand, action: Action, scopeResolver: ScopeResolver): ActionContext;
|
|
11
|
+
//# sourceMappingURL=action-context-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-context-factory.d.ts","sourceRoot":"","sources":["../src/action-context-factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAA+E,MAAM,iBAAiB,CAAC;AACtK,OAAO,EAAE,UAAU,EAAuB,MAAM,sBAAsB,CAAC;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA+CtC;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,GAC3B,aAAa,CAuPf"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Action Context Factory - Creates ActionContext for action execution
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createActionContext = createActionContext;
|
|
7
|
+
const stdlib_1 = require("@sharpee/stdlib");
|
|
8
|
+
const world_model_1 = require("@sharpee/world-model");
|
|
9
|
+
const core_1 = require("@sharpee/core");
|
|
10
|
+
const shared_data_keys_1 = require("./shared-data-keys");
|
|
11
|
+
/**
|
|
12
|
+
* Helper to get entity from command slot
|
|
13
|
+
*/
|
|
14
|
+
function getEntityFromSlot(command, slot) {
|
|
15
|
+
switch (slot) {
|
|
16
|
+
case 'target':
|
|
17
|
+
case 'directObject':
|
|
18
|
+
case 'item':
|
|
19
|
+
return command.directObject?.entity ?? null;
|
|
20
|
+
case 'container':
|
|
21
|
+
case 'recipient':
|
|
22
|
+
case 'instrument':
|
|
23
|
+
case 'indirectObject':
|
|
24
|
+
return command.indirectObject?.entity ?? null;
|
|
25
|
+
default:
|
|
26
|
+
return command.directObject?.entity ?? null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate appropriate scope error based on requirement and actual scope
|
|
31
|
+
*/
|
|
32
|
+
function getScopeError(required, actual, entity) {
|
|
33
|
+
const params = { item: entity.name };
|
|
34
|
+
if (actual === stdlib_1.ScopeLevel.UNAWARE) {
|
|
35
|
+
return { valid: false, error: stdlib_1.ScopeErrors.NOT_KNOWN, params };
|
|
36
|
+
}
|
|
37
|
+
if (required >= stdlib_1.ScopeLevel.VISIBLE && actual < stdlib_1.ScopeLevel.VISIBLE) {
|
|
38
|
+
return { valid: false, error: stdlib_1.ScopeErrors.NOT_VISIBLE, params };
|
|
39
|
+
}
|
|
40
|
+
if (required >= stdlib_1.ScopeLevel.REACHABLE && actual < stdlib_1.ScopeLevel.REACHABLE) {
|
|
41
|
+
return { valid: false, error: stdlib_1.ScopeErrors.NOT_REACHABLE, params };
|
|
42
|
+
}
|
|
43
|
+
if (required >= stdlib_1.ScopeLevel.CARRIED && actual < stdlib_1.ScopeLevel.CARRIED) {
|
|
44
|
+
return { valid: false, error: stdlib_1.ScopeErrors.NOT_CARRIED, params };
|
|
45
|
+
}
|
|
46
|
+
return { valid: false, error: stdlib_1.ScopeErrors.OUT_OF_SCOPE, params };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create an ActionContext for action execution
|
|
50
|
+
*/
|
|
51
|
+
function createActionContext(world, gameContext, command, action, scopeResolver) {
|
|
52
|
+
const player = gameContext.player;
|
|
53
|
+
const currentLocation = world.getLocation(player.id)
|
|
54
|
+
? world.getEntity(world.getLocation(player.id))
|
|
55
|
+
: player;
|
|
56
|
+
// Create sharedData object separately so it can be referenced in closures
|
|
57
|
+
const sharedData = {};
|
|
58
|
+
// Create the event method
|
|
59
|
+
const event = (type, data) => {
|
|
60
|
+
// Add standard entities
|
|
61
|
+
const entities = {
|
|
62
|
+
actor: player.id,
|
|
63
|
+
location: currentLocation?.id || player.id
|
|
64
|
+
};
|
|
65
|
+
// Add entities from command
|
|
66
|
+
if (command.directObject?.entity) {
|
|
67
|
+
entities.target = command.directObject.entity.id;
|
|
68
|
+
}
|
|
69
|
+
if (command.indirectObject?.entity) {
|
|
70
|
+
entities.indirect = command.indirectObject.entity.id;
|
|
71
|
+
}
|
|
72
|
+
// Create the event
|
|
73
|
+
return {
|
|
74
|
+
id: `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
75
|
+
type,
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
data: {
|
|
78
|
+
...data,
|
|
79
|
+
// Include action context in data instead of metadata
|
|
80
|
+
actionId: action.id,
|
|
81
|
+
turn: gameContext.currentTurn
|
|
82
|
+
},
|
|
83
|
+
entities
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
// World querying
|
|
88
|
+
world,
|
|
89
|
+
player,
|
|
90
|
+
currentLocation: currentLocation,
|
|
91
|
+
command,
|
|
92
|
+
scopeResolver,
|
|
93
|
+
action,
|
|
94
|
+
// Shared data for passing information between phases
|
|
95
|
+
sharedData,
|
|
96
|
+
// Validation result - set by CommandExecutor after validate() phase
|
|
97
|
+
validationResult: undefined,
|
|
98
|
+
// Scope checking methods (delegate to scopeResolver)
|
|
99
|
+
canSee: (entity) => {
|
|
100
|
+
return scopeResolver.canSee(player, entity);
|
|
101
|
+
},
|
|
102
|
+
canReach: (entity) => {
|
|
103
|
+
return scopeResolver.canReach(player, entity);
|
|
104
|
+
},
|
|
105
|
+
canTake: (entity) => {
|
|
106
|
+
// Basic implementation - can be enhanced
|
|
107
|
+
return !entity.has('if.trait.scenery') &&
|
|
108
|
+
!entity.has('if.trait.fixed') &&
|
|
109
|
+
entity.type !== 'room' &&
|
|
110
|
+
entity.type !== 'location';
|
|
111
|
+
},
|
|
112
|
+
isInScope: (entity) => {
|
|
113
|
+
const level = scopeResolver.getScope(player, entity);
|
|
114
|
+
return level >= stdlib_1.ScopeLevel.AWARE;
|
|
115
|
+
},
|
|
116
|
+
getVisible: () => {
|
|
117
|
+
return scopeResolver.getVisible(player);
|
|
118
|
+
},
|
|
119
|
+
getInScope: () => {
|
|
120
|
+
// Get all entities and filter by scope
|
|
121
|
+
const allEntities = world.getAllEntities();
|
|
122
|
+
return allEntities.filter(entity => {
|
|
123
|
+
const level = scopeResolver.getScope(player, entity);
|
|
124
|
+
return level >= stdlib_1.ScopeLevel.AWARE;
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
// Scope validation methods (Phase 4 parser refactor)
|
|
128
|
+
getEntityScope: (entity) => {
|
|
129
|
+
return scopeResolver.getScope(player, entity);
|
|
130
|
+
},
|
|
131
|
+
getSlotScope: (slot) => {
|
|
132
|
+
const entity = getEntityFromSlot(command, slot);
|
|
133
|
+
if (!entity) {
|
|
134
|
+
return stdlib_1.ScopeLevel.UNAWARE;
|
|
135
|
+
}
|
|
136
|
+
return scopeResolver.getScope(player, entity);
|
|
137
|
+
},
|
|
138
|
+
requireScope: (entity, required) => {
|
|
139
|
+
const actualScope = scopeResolver.getScope(player, entity);
|
|
140
|
+
if (actualScope >= required) {
|
|
141
|
+
return { ok: true, actualScope };
|
|
142
|
+
}
|
|
143
|
+
const error = getScopeError(required, actualScope, entity);
|
|
144
|
+
return { ok: false, error, actualScope };
|
|
145
|
+
},
|
|
146
|
+
requireSlotScope: (slot, required) => {
|
|
147
|
+
const entity = getEntityFromSlot(command, slot);
|
|
148
|
+
if (!entity) {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
error: { valid: false, error: 'no_target', params: { slot } }
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const actualScope = scopeResolver.getScope(player, entity);
|
|
155
|
+
if (actualScope >= required) {
|
|
156
|
+
return { ok: true, actualScope };
|
|
157
|
+
}
|
|
158
|
+
const error = getScopeError(required, actualScope, entity);
|
|
159
|
+
return { ok: false, error, actualScope };
|
|
160
|
+
},
|
|
161
|
+
requireCarriedOrImplicitTake: (entity) => {
|
|
162
|
+
const actualScope = scopeResolver.getScope(player, entity);
|
|
163
|
+
// Case 1: Already carried - success, no implicit take needed
|
|
164
|
+
if (actualScope >= stdlib_1.ScopeLevel.CARRIED) {
|
|
165
|
+
return { ok: true };
|
|
166
|
+
}
|
|
167
|
+
// Case 2: Not reachable - can't take it, return scope error
|
|
168
|
+
if (actualScope < stdlib_1.ScopeLevel.REACHABLE) {
|
|
169
|
+
const error = getScopeError(stdlib_1.ScopeLevel.REACHABLE, actualScope, entity);
|
|
170
|
+
return { ok: false, error };
|
|
171
|
+
}
|
|
172
|
+
// Case 3: Reachable but not carried - attempt implicit take
|
|
173
|
+
// Check if implicit take is disabled at story level (ADR-104)
|
|
174
|
+
if (gameContext.implicitActions?.implicitTake === false) {
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
error: { valid: false, error: stdlib_1.ScopeErrors.NOT_CARRIED, params: { item: entity.name } }
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// Check if implicit take is disabled at action level (ADR-104)
|
|
181
|
+
if (action.allowImplicitTake === false) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
error: { valid: false, error: stdlib_1.ScopeErrors.NOT_CARRIED, params: { item: entity.name } }
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// Check if entity can be taken (not scenery, room, door)
|
|
188
|
+
if (entity.has(world_model_1.TraitType.SCENERY) || entity.has(world_model_1.TraitType.ROOM) || entity.has(world_model_1.TraitType.DOOR)) {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
error: { valid: false, error: 'fixed_in_place', params: { item: entity.name } }
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Create a synthetic command for the taking action
|
|
195
|
+
const takeCommand = {
|
|
196
|
+
parsed: {
|
|
197
|
+
rawInput: `take ${entity.name}`,
|
|
198
|
+
action: stdlib_1.takingAction.id,
|
|
199
|
+
tokens: [],
|
|
200
|
+
structure: { verb: { tokens: [0], text: 'take', head: 'take' } },
|
|
201
|
+
pattern: 'VERB_NOUN',
|
|
202
|
+
confidence: 1.0
|
|
203
|
+
},
|
|
204
|
+
actionId: stdlib_1.takingAction.id,
|
|
205
|
+
directObject: {
|
|
206
|
+
entity,
|
|
207
|
+
parsed: {
|
|
208
|
+
text: entity.name,
|
|
209
|
+
candidates: [entity.name]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
// Create a sub-context for the taking action
|
|
214
|
+
const takeContext = createActionContext(world, gameContext, takeCommand, stdlib_1.takingAction, scopeResolver);
|
|
215
|
+
// Run the taking action's validate phase
|
|
216
|
+
const validation = stdlib_1.takingAction.validate(takeContext);
|
|
217
|
+
if (!validation.valid) {
|
|
218
|
+
// Take validation failed - return the error
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
error: {
|
|
222
|
+
valid: false,
|
|
223
|
+
error: validation.error || 'cannot_take',
|
|
224
|
+
params: validation.params
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
// Execute the taking action
|
|
229
|
+
stdlib_1.takingAction.execute(takeContext);
|
|
230
|
+
// Get the report events from the taking action
|
|
231
|
+
const takeEvents = stdlib_1.takingAction.report ? stdlib_1.takingAction.report(takeContext) : [];
|
|
232
|
+
// Filter out action.success events - the implicit_take message replaces them
|
|
233
|
+
// Keep if.event.taken for state tracking
|
|
234
|
+
const filteredTakeEvents = takeEvents.filter(e => e.type !== 'action.success');
|
|
235
|
+
// Create the implicit take event (for "(first taking the X)" message)
|
|
236
|
+
const implicitTakeEvent = (0, core_1.createEvent)('if.event.implicit_take', {
|
|
237
|
+
item: entity.id,
|
|
238
|
+
itemName: entity.name
|
|
239
|
+
}, {
|
|
240
|
+
actor: player.id,
|
|
241
|
+
target: entity.id,
|
|
242
|
+
location: currentLocation?.id || player.id
|
|
243
|
+
});
|
|
244
|
+
// Combine: implicit take notification + state change events (no success message)
|
|
245
|
+
const implicitTakeEvents = [implicitTakeEvent, ...filteredTakeEvents];
|
|
246
|
+
// Store in sharedData for the report phase to access
|
|
247
|
+
const existingEvents = sharedData[shared_data_keys_1.SharedDataKeys.IMPLICIT_TAKE_EVENTS] ?? [];
|
|
248
|
+
sharedData[shared_data_keys_1.SharedDataKeys.IMPLICIT_TAKE_EVENTS] = [...existingEvents, ...implicitTakeEvents];
|
|
249
|
+
return {
|
|
250
|
+
ok: true,
|
|
251
|
+
implicitTakeEvents
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
// Event creation
|
|
255
|
+
event
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=action-context-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-context-factory.js","sourceRoot":"","sources":["../src/action-context-factory.ts"],"names":[],"mappings":"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"}
|