@sharpee/parser-en-us 3.0.0 → 3.3.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/english-grammar-engine.d.ts +2 -2
- package/english-grammar-engine.d.ts.map +1 -1
- package/english-grammar-engine.js +27 -7
- package/english-grammar-engine.js.map +1 -1
- package/english-parser.d.ts +34 -1
- package/english-parser.d.ts.map +1 -1
- package/english-parser.js +157 -46
- package/english-parser.js.map +1 -1
- package/grammar.d.ts +6 -2
- package/grammar.d.ts.map +1 -1
- package/grammar.js +346 -92
- package/grammar.js.map +1 -1
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +12 -12
- package/index.js.map +1 -1
- package/package.json +5 -5
- package/slot-consumers/entity-slot-consumer.d.ts +1 -1
- package/slot-consumers/entity-slot-consumer.d.ts.map +1 -1
- package/slot-consumers/entity-slot-consumer.js +8 -8
- package/slot-consumers/entity-slot-consumer.js.map +1 -1
- package/slot-consumers/index.d.ts +6 -6
- package/slot-consumers/index.d.ts.map +1 -1
- package/slot-consumers/index.js +19 -19
- package/slot-consumers/index.js.map +1 -1
- package/slot-consumers/text-slot-consumer.d.ts +1 -1
- package/slot-consumers/text-slot-consumer.d.ts.map +1 -1
- package/slot-consumers/text-slot-consumer.js +5 -5
- package/slot-consumers/text-slot-consumer.js.map +1 -1
- package/slot-consumers/typed-slot-consumer.d.ts +1 -1
- package/slot-consumers/typed-slot-consumer.d.ts.map +1 -1
- package/slot-consumers/vocabulary-slot-consumer.d.ts +1 -1
- package/slot-consumers/vocabulary-slot-consumer.d.ts.map +1 -1
package/grammar.js
CHANGED
|
@@ -4,16 +4,19 @@
|
|
|
4
4
|
* @description Standard grammar patterns for English interactive fiction
|
|
5
5
|
*
|
|
6
6
|
* Rule Priority Guidelines:
|
|
7
|
-
* - 100+:
|
|
7
|
+
* - 100+: Specific/phrasal patterns that must outrank broader ones
|
|
8
8
|
* - 100: Standard patterns
|
|
9
9
|
* - 95: Synonyms/alternatives
|
|
10
10
|
* - 90: Abbreviations
|
|
11
11
|
*
|
|
12
|
-
*
|
|
12
|
+
* Parse-time gating: `.where()` scope constraints are the one parse-time
|
|
13
|
+
* gating mechanism. Trait-based refusal ("that's not something you can
|
|
14
|
+
* enter/climb/open") lives in each action's validate(), never in grammar —
|
|
15
|
+
* the former rule-level `.hasTrait()` API was a parse-time no-op and was
|
|
16
|
+
* deleted (ADR-231 D2a, 2026-07-17).
|
|
13
17
|
*/
|
|
14
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
19
|
exports.defineGrammar = defineGrammar;
|
|
16
|
-
const world_model_1 = require("@sharpee/world-model");
|
|
17
20
|
/**
|
|
18
21
|
* Define English grammar rules
|
|
19
22
|
* @param grammar The grammar builder to use
|
|
@@ -28,7 +31,7 @@ function defineGrammar(grammar) {
|
|
|
28
31
|
// Scope handled by action validation - tries see/feel/hear/smell cascade
|
|
29
32
|
grammar
|
|
30
33
|
.forAction('if.action.examining')
|
|
31
|
-
.verbs(['examine', 'x', 'inspect'])
|
|
34
|
+
.verbs(['examine', 'x', 'inspect', 'check', 'view', 'observe']) // +check/view/observe (ADR-230 D4)
|
|
32
35
|
.pattern(':target')
|
|
33
36
|
.build();
|
|
34
37
|
// "look at" is a phrasal pattern - different structure
|
|
@@ -37,10 +40,11 @@ function defineGrammar(grammar) {
|
|
|
37
40
|
.mapsTo('if.action.examining')
|
|
38
41
|
.withPriority(95)
|
|
39
42
|
.build();
|
|
40
|
-
// Looking with optional adverbs
|
|
43
|
+
// Looking with optional adverbs (ADR-230 D3a: the adverb form is just
|
|
44
|
+
// examining — if.action.examining_carefully had no action behind it)
|
|
41
45
|
grammar
|
|
42
46
|
.define('look [carefully] at :target')
|
|
43
|
-
.mapsTo('if.action.
|
|
47
|
+
.mapsTo('if.action.examining')
|
|
44
48
|
.withPriority(96)
|
|
45
49
|
.build(); // Slightly higher priority, but confidence penalty for skipped optionals
|
|
46
50
|
grammar
|
|
@@ -78,7 +82,7 @@ function defineGrammar(grammar) {
|
|
|
78
82
|
// Scope handled by action validation; SceneryTrait blocks non-portable items
|
|
79
83
|
grammar
|
|
80
84
|
.forAction('if.action.taking')
|
|
81
|
-
.verbs(['take', 'get', 'grab'])
|
|
85
|
+
.verbs(['take', 'get', 'grab', 'acquire', 'collect']) // +acquire/collect (ADR-230 D4; bare `pick` deliberately absent — it would outmatch the `pick up :item` compound)
|
|
82
86
|
.pattern(':item')
|
|
83
87
|
.build();
|
|
84
88
|
// "pick up" is a phrasal verb - different pattern structure
|
|
@@ -90,7 +94,7 @@ function defineGrammar(grammar) {
|
|
|
90
94
|
// Scope (carried) handled by action validation
|
|
91
95
|
grammar
|
|
92
96
|
.forAction('if.action.dropping')
|
|
93
|
-
.verbs(['drop', 'discard'])
|
|
97
|
+
.verbs(['drop', 'discard', 'release']) // +release (ADR-230 D4 patterns reconciliation)
|
|
94
98
|
.pattern(':item')
|
|
95
99
|
.build();
|
|
96
100
|
// "put down" is a phrasal verb - different pattern structure
|
|
@@ -133,13 +137,13 @@ function defineGrammar(grammar) {
|
|
|
133
137
|
// Eating (ADR-087: using forAction)
|
|
134
138
|
grammar
|
|
135
139
|
.forAction('if.action.eating')
|
|
136
|
-
.verbs(['eat', 'consume', 'devour'])
|
|
140
|
+
.verbs(['eat', 'consume', 'devour', 'munch', 'nibble']) // +munch/nibble (ADR-230 D4 patterns reconciliation)
|
|
137
141
|
.pattern(':item')
|
|
138
142
|
.build();
|
|
139
143
|
// Drinking (ADR-087: using forAction)
|
|
140
144
|
grammar
|
|
141
145
|
.forAction('if.action.drinking')
|
|
142
|
-
.verbs(['drink', 'sip', 'quaff'])
|
|
146
|
+
.verbs(['drink', 'sip', 'quaff', 'swallow', 'imbibe']) // +swallow/imbibe (ADR-230 D4)
|
|
143
147
|
.pattern(':item')
|
|
144
148
|
.build();
|
|
145
149
|
// ADR-080 Phase 2: Multi-object commands
|
|
@@ -149,23 +153,20 @@ function defineGrammar(grammar) {
|
|
|
149
153
|
// - "take knife and lamp" matches "take :item", parser creates list
|
|
150
154
|
// - "take all but sword" matches "take :item", parser detects exclusion
|
|
151
155
|
// Container operations
|
|
152
|
-
// Scope handled by action validation
|
|
156
|
+
// Scope and trait-based refusal handled by action validation
|
|
153
157
|
grammar
|
|
154
158
|
.define('put :item in|into|inside :container')
|
|
155
|
-
.hasTrait('container', world_model_1.TraitType.CONTAINER)
|
|
156
159
|
.mapsTo('if.action.inserting')
|
|
157
160
|
.withPriority(100)
|
|
158
161
|
.build();
|
|
159
162
|
grammar
|
|
160
163
|
.define('insert :item in|into :container')
|
|
161
|
-
.hasTrait('container', world_model_1.TraitType.CONTAINER)
|
|
162
164
|
.mapsTo('if.action.inserting')
|
|
163
165
|
.withPriority(100)
|
|
164
166
|
.build();
|
|
165
167
|
// Supporter operations (including hanging!)
|
|
166
168
|
grammar
|
|
167
169
|
.define('put :item on|onto :supporter')
|
|
168
|
-
.hasTrait('supporter', world_model_1.TraitType.SUPPORTER)
|
|
169
170
|
.mapsTo('if.action.putting')
|
|
170
171
|
.withPriority(100)
|
|
171
172
|
.build();
|
|
@@ -185,13 +186,11 @@ function defineGrammar(grammar) {
|
|
|
185
186
|
.forAction('if.action.inventory')
|
|
186
187
|
.verbs(['inventory', 'inv', 'i'])
|
|
187
188
|
.build();
|
|
188
|
-
// Movement (ADR-087:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
.withPriority(100)
|
|
194
|
-
.build();
|
|
189
|
+
// Movement (ADR-087). The old `go :direction` define was DELETED in
|
|
190
|
+
// ADR-230 Phase 6: a `:direction` slot with a `{ type: 'direction' }`
|
|
191
|
+
// constraint always failed at runtime ("PropertyConstraint in slot
|
|
192
|
+
// constraints not yet supported"), so `go north` never worked — the
|
|
193
|
+
// verb+direction literals in the D4 block below replace it.
|
|
195
194
|
// Bare direction commands (ADR-087: consolidated with forAction)
|
|
196
195
|
grammar
|
|
197
196
|
.forAction('if.action.going')
|
|
@@ -211,16 +210,14 @@ function defineGrammar(grammar) {
|
|
|
211
210
|
})
|
|
212
211
|
.build();
|
|
213
212
|
// Opening and closing
|
|
214
|
-
// Scope handled by action validation
|
|
213
|
+
// Scope and trait-based refusal handled by action validation
|
|
215
214
|
grammar
|
|
216
215
|
.define('open :door')
|
|
217
|
-
.hasTrait('door', world_model_1.TraitType.OPENABLE)
|
|
218
216
|
.mapsTo('if.action.opening')
|
|
219
217
|
.withPriority(100)
|
|
220
218
|
.build();
|
|
221
219
|
grammar
|
|
222
220
|
.define('close :door')
|
|
223
|
-
.hasTrait('door', world_model_1.TraitType.OPENABLE)
|
|
224
221
|
.mapsTo('if.action.closing')
|
|
225
222
|
.withPriority(100)
|
|
226
223
|
.build();
|
|
@@ -229,23 +226,19 @@ function defineGrammar(grammar) {
|
|
|
229
226
|
.forAction('if.action.switching_on')
|
|
230
227
|
.verbs(['turn', 'switch', 'flip'])
|
|
231
228
|
.pattern('on :device')
|
|
232
|
-
.hasTrait('device', world_model_1.TraitType.SWITCHABLE)
|
|
233
229
|
.build();
|
|
234
230
|
grammar
|
|
235
231
|
.forAction('if.action.switching_off')
|
|
236
232
|
.verbs(['turn', 'switch', 'flip'])
|
|
237
233
|
.pattern('off :device')
|
|
238
|
-
.hasTrait('device', world_model_1.TraitType.SWITCHABLE)
|
|
239
234
|
.build();
|
|
240
235
|
// Alternative phrasal verb order: "turn lamp on" / "turn lamp off"
|
|
241
236
|
grammar
|
|
242
237
|
.define('turn :device on')
|
|
243
|
-
.hasTrait('device', world_model_1.TraitType.SWITCHABLE)
|
|
244
238
|
.mapsTo('if.action.switching_on')
|
|
245
239
|
.build();
|
|
246
240
|
grammar
|
|
247
241
|
.define('turn :device off')
|
|
248
|
-
.hasTrait('device', world_model_1.TraitType.SWITCHABLE)
|
|
249
242
|
.mapsTo('if.action.switching_off')
|
|
250
243
|
.build();
|
|
251
244
|
// Pushing and pulling (ADR-087: using forAction)
|
|
@@ -257,7 +250,7 @@ function defineGrammar(grammar) {
|
|
|
257
250
|
.build();
|
|
258
251
|
grammar
|
|
259
252
|
.forAction('if.action.pulling')
|
|
260
|
-
.verbs(['pull', 'drag', 'yank'])
|
|
253
|
+
.verbs(['pull', 'drag', 'yank', 'tug']) // +tug (ADR-230 D4)
|
|
261
254
|
.pattern(':target')
|
|
262
255
|
.build();
|
|
263
256
|
// Lowering and raising (ADR-090: capability dispatch)
|
|
@@ -292,6 +285,11 @@ function defineGrammar(grammar) {
|
|
|
292
285
|
.mapsTo('if.action.restarting')
|
|
293
286
|
.withPriority(100)
|
|
294
287
|
.build();
|
|
288
|
+
// Sleeping (ADR-230 D2; +nap/doze/rest/slumber D4)
|
|
289
|
+
grammar
|
|
290
|
+
.forAction('if.action.sleeping')
|
|
291
|
+
.verbs(['sleep', 'nap', 'doze', 'rest', 'slumber'])
|
|
292
|
+
.build();
|
|
295
293
|
// Quitting (ADR-087: using forAction)
|
|
296
294
|
grammar
|
|
297
295
|
.forAction('if.action.quitting')
|
|
@@ -393,36 +391,31 @@ function defineGrammar(grammar) {
|
|
|
393
391
|
.withPriority(100)
|
|
394
392
|
.build();
|
|
395
393
|
// VERB_NOUN_NOUN patterns (Phase 2)
|
|
396
|
-
// Scope handled by action validation
|
|
394
|
+
// Scope and trait-based refusal handled by action validation
|
|
397
395
|
// Giving
|
|
398
396
|
grammar
|
|
399
397
|
.define('give :item to :recipient')
|
|
400
|
-
.hasTrait('recipient', world_model_1.TraitType.ACTOR)
|
|
401
398
|
.mapsTo('if.action.giving')
|
|
402
399
|
.withPriority(100)
|
|
403
400
|
.build();
|
|
404
401
|
grammar
|
|
405
402
|
.define('give :recipient :item')
|
|
406
|
-
.hasTrait('recipient', world_model_1.TraitType.ACTOR)
|
|
407
403
|
.mapsTo('if.action.giving')
|
|
408
404
|
.withPriority(95)
|
|
409
405
|
.build(); // Slightly lower priority than explicit "to"
|
|
410
406
|
grammar
|
|
411
407
|
.define('offer :item to :recipient')
|
|
412
|
-
.hasTrait('recipient', world_model_1.TraitType.ACTOR)
|
|
413
408
|
.mapsTo('if.action.giving')
|
|
414
409
|
.withPriority(100)
|
|
415
410
|
.build();
|
|
416
411
|
// Showing
|
|
417
412
|
grammar
|
|
418
413
|
.define('show :item to :recipient')
|
|
419
|
-
.hasTrait('recipient', world_model_1.TraitType.ACTOR)
|
|
420
414
|
.mapsTo('if.action.showing')
|
|
421
415
|
.withPriority(100)
|
|
422
416
|
.build();
|
|
423
417
|
grammar
|
|
424
418
|
.define('show :recipient :item')
|
|
425
|
-
.hasTrait('recipient', world_model_1.TraitType.ACTOR)
|
|
426
419
|
.mapsTo('if.action.showing')
|
|
427
420
|
.withPriority(95)
|
|
428
421
|
.build();
|
|
@@ -432,6 +425,24 @@ function defineGrammar(grammar) {
|
|
|
432
425
|
.mapsTo('if.action.throwing')
|
|
433
426
|
.withPriority(100)
|
|
434
427
|
.build();
|
|
428
|
+
// Bare general throw (no target) — reaches the action's general-throw
|
|
429
|
+
// branch; `throw away :item` (dropping) still wins via D2b literal
|
|
430
|
+
// specificity, and the at/to forms via their extra literal.
|
|
431
|
+
grammar
|
|
432
|
+
.define('throw :item')
|
|
433
|
+
.mapsTo('if.action.throwing')
|
|
434
|
+
.withPriority(95)
|
|
435
|
+
.build();
|
|
436
|
+
grammar
|
|
437
|
+
.define('toss :item')
|
|
438
|
+
.mapsTo('if.action.throwing')
|
|
439
|
+
.withPriority(95)
|
|
440
|
+
.build();
|
|
441
|
+
grammar
|
|
442
|
+
.define('hurl :item')
|
|
443
|
+
.mapsTo('if.action.throwing')
|
|
444
|
+
.withPriority(95)
|
|
445
|
+
.build();
|
|
435
446
|
grammar
|
|
436
447
|
.define('throw :item to :recipient')
|
|
437
448
|
.mapsTo('if.action.throwing')
|
|
@@ -439,11 +450,21 @@ function defineGrammar(grammar) {
|
|
|
439
450
|
.build();
|
|
440
451
|
// Multiple preposition patterns (Phase 2.1)
|
|
441
452
|
// Scope handled by action validation; state checks (locked, open) in action validate()
|
|
442
|
-
// Taking from container with tool
|
|
453
|
+
// Taking from container with tool (ADR-230 Phase 6: remapped from the
|
|
454
|
+
// orphan if.action.taking_with onto removing — the tool rides the
|
|
455
|
+
// instrument slot and is interceptor-consultable)
|
|
443
456
|
grammar
|
|
444
457
|
.define('take :item from :container with|using :tool')
|
|
445
458
|
.instrument('tool')
|
|
446
|
-
.mapsTo('if.action.
|
|
459
|
+
.mapsTo('if.action.removing')
|
|
460
|
+
.withPriority(110)
|
|
461
|
+
.build();
|
|
462
|
+
// Removing from a container (ADR-230 D2). Priority 110 like the other
|
|
463
|
+
// multi-preposition patterns here, so the from-form outranks taking_off's
|
|
464
|
+
// bare `remove :target` when the command names a source.
|
|
465
|
+
grammar
|
|
466
|
+
.define('remove :item from :container')
|
|
467
|
+
.mapsTo('if.action.removing')
|
|
447
468
|
.withPriority(110)
|
|
448
469
|
.build();
|
|
449
470
|
// Unlocking with key
|
|
@@ -453,12 +474,32 @@ function defineGrammar(grammar) {
|
|
|
453
474
|
.mapsTo('if.action.unlocking')
|
|
454
475
|
.withPriority(110)
|
|
455
476
|
.build();
|
|
456
|
-
//
|
|
477
|
+
// Locking and keyless unlocking (ADR-230 D2). No trait constraint,
|
|
478
|
+
// mirroring the keyed unlock pattern: the action's validate owns
|
|
479
|
+
// not-lockable/no-key messaging (validateKeyRequirements refuses with
|
|
480
|
+
// no_key when the lockable requires a key).
|
|
481
|
+
grammar
|
|
482
|
+
.forAction('if.action.locking')
|
|
483
|
+
.verbs(['lock'])
|
|
484
|
+
.pattern(':target')
|
|
485
|
+
.build();
|
|
486
|
+
grammar
|
|
487
|
+
.define('lock :target with|using :key')
|
|
488
|
+
.instrument('key')
|
|
489
|
+
.mapsTo('if.action.locking')
|
|
490
|
+
.withPriority(110)
|
|
491
|
+
.build();
|
|
492
|
+
grammar
|
|
493
|
+
.forAction('if.action.unlocking')
|
|
494
|
+
.verbs(['unlock'])
|
|
495
|
+
.pattern(':target')
|
|
496
|
+
.build();
|
|
497
|
+
// Opening with tool (ADR-230 D3b: a tool slot on the standard opening
|
|
498
|
+
// action, not a separate id — if.action.opening_with had no action)
|
|
457
499
|
grammar
|
|
458
500
|
.define('open :container with|using :tool')
|
|
459
501
|
.instrument('tool')
|
|
460
|
-
.
|
|
461
|
-
.mapsTo('if.action.opening_with')
|
|
502
|
+
.mapsTo('if.action.opening')
|
|
462
503
|
.withPriority(110)
|
|
463
504
|
.build();
|
|
464
505
|
// Cutting with tool
|
|
@@ -468,10 +509,18 @@ function defineGrammar(grammar) {
|
|
|
468
509
|
.mapsTo('if.action.cutting')
|
|
469
510
|
.withPriority(110)
|
|
470
511
|
.build();
|
|
512
|
+
// Cutting — bare form (2026-07-17, chord go-live G1 shortlist): an
|
|
513
|
+
// untooled cuttable was unreachable for TS and Chord alike; the tooled
|
|
514
|
+
// form above keeps priority 110 so it wins when a tool is named.
|
|
515
|
+
grammar
|
|
516
|
+
.forAction('if.action.cutting')
|
|
517
|
+
.verbs(['cut', 'slice', 'chop'])
|
|
518
|
+
.pattern(':target')
|
|
519
|
+
.build();
|
|
471
520
|
// Attacking - simple patterns (ADR-087: using forAction)
|
|
472
521
|
grammar
|
|
473
522
|
.forAction('if.action.attacking')
|
|
474
|
-
.verbs(['attack', 'kill', 'fight', 'slay', 'murder', 'hit', 'strike'])
|
|
523
|
+
.verbs(['attack', 'kill', 'fight', 'slay', 'murder', 'hit', 'strike', 'break', 'smash', 'destroy']) // +break/smash/destroy (ADR-230 D4)
|
|
475
524
|
.pattern(':target')
|
|
476
525
|
.build();
|
|
477
526
|
// Attacking with weapon (higher priority than simple attack)
|
|
@@ -506,52 +555,196 @@ function defineGrammar(grammar) {
|
|
|
506
555
|
.mapsTo('if.action.digging')
|
|
507
556
|
.withPriority(110)
|
|
508
557
|
.build();
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
grammar
|
|
512
|
-
.define('say :message')
|
|
513
|
-
.mapsTo('if.action.saying')
|
|
514
|
-
.withPriority(100)
|
|
515
|
-
.build();
|
|
558
|
+
// Digging — bare form (2026-07-17, chord go-live G1 shortlist): same
|
|
559
|
+
// bare-grammar hole as cutting.
|
|
516
560
|
grammar
|
|
517
|
-
.
|
|
518
|
-
.
|
|
519
|
-
.
|
|
520
|
-
.withPriority(105)
|
|
561
|
+
.forAction('if.action.digging')
|
|
562
|
+
.verbs(['dig'])
|
|
563
|
+
.pattern(':target')
|
|
521
564
|
.build();
|
|
565
|
+
// Communication patterns (saying/saying_to/writing/writing_on/shouting/
|
|
566
|
+
// whispering) DELETED in ADR-230 Phase 6 (sketch ruling 4/5): the ids had
|
|
567
|
+
// no actions — they parsed and runtime-failed in every story. Grammar
|
|
568
|
+
// returns with the conversation/writing systems; stories (e.g. dungeo's
|
|
569
|
+
// SAY) keep their own story-grammar verbs meanwhile.
|
|
570
|
+
// ADR-231 D4: `:topic` is a TOPIC slot — free text captured verbatim by
|
|
571
|
+
// the TextSlotConsumer, never a positional entity slot. The validator's
|
|
572
|
+
// entity-first attempt resolves an in-scope entity quietly; a topic is
|
|
573
|
+
// never scope-rejected.
|
|
522
574
|
grammar
|
|
523
|
-
.define('
|
|
524
|
-
.
|
|
575
|
+
.define('tell :recipient about :topic')
|
|
576
|
+
.topic('topic')
|
|
577
|
+
.mapsTo('if.action.telling')
|
|
525
578
|
.withPriority(100)
|
|
526
579
|
.build();
|
|
527
580
|
grammar
|
|
528
|
-
.define('
|
|
529
|
-
.
|
|
530
|
-
.
|
|
531
|
-
.build();
|
|
532
|
-
grammar
|
|
533
|
-
.define('shout :message')
|
|
534
|
-
.mapsTo('if.action.shouting')
|
|
581
|
+
.define('ask :recipient about :topic')
|
|
582
|
+
.topic('topic')
|
|
583
|
+
.mapsTo('if.action.asking')
|
|
535
584
|
.withPriority(100)
|
|
536
585
|
.build();
|
|
586
|
+
// asking/telling aliases (ADR-230 Phase 6 — actions revived as minimal
|
|
587
|
+
// interceptable stubs)
|
|
537
588
|
grammar
|
|
538
|
-
.define('
|
|
539
|
-
.
|
|
540
|
-
.mapsTo('if.action.
|
|
589
|
+
.define('question :recipient about :topic')
|
|
590
|
+
.topic('topic')
|
|
591
|
+
.mapsTo('if.action.asking')
|
|
541
592
|
.withPriority(100)
|
|
542
593
|
.build();
|
|
543
594
|
grammar
|
|
544
|
-
.define('
|
|
545
|
-
.
|
|
546
|
-
.mapsTo('if.action.
|
|
595
|
+
.define('inquire of :recipient about :topic')
|
|
596
|
+
.topic('topic')
|
|
597
|
+
.mapsTo('if.action.asking')
|
|
547
598
|
.withPriority(100)
|
|
548
599
|
.build();
|
|
549
600
|
grammar
|
|
550
|
-
.define('
|
|
551
|
-
.
|
|
552
|
-
.mapsTo('if.action.
|
|
601
|
+
.define('inform :recipient about :topic')
|
|
602
|
+
.topic('topic')
|
|
603
|
+
.mapsTo('if.action.telling')
|
|
553
604
|
.withPriority(100)
|
|
554
605
|
.build();
|
|
606
|
+
// Talking (ADR-229 R3): the core route to if.action.talking — the action
|
|
607
|
+
// was wired for interceptors (ADR-228 Phase 5) but previously reachable
|
|
608
|
+
// only via story grammar. No parse-time actor gate (the pattern all
|
|
609
|
+
// trait-gated verbs now follow, ADR-231 D2a): talking's validate owns
|
|
610
|
+
// not_actor/too_far, so those refusals flow through blocked() →
|
|
611
|
+
// onBlocked (interceptor-visible) instead of dying as a parse failure.
|
|
612
|
+
// Story grammar outranks these on priority as usual.
|
|
613
|
+
grammar
|
|
614
|
+
.define('talk to|with :target')
|
|
615
|
+
.mapsTo('if.action.talking')
|
|
616
|
+
.withPriority(100)
|
|
617
|
+
.build();
|
|
618
|
+
grammar
|
|
619
|
+
.define('speak to|with :target')
|
|
620
|
+
.mapsTo('if.action.talking')
|
|
621
|
+
.withPriority(100)
|
|
622
|
+
.build();
|
|
623
|
+
grammar
|
|
624
|
+
.define('chat with :target')
|
|
625
|
+
.mapsTo('if.action.talking')
|
|
626
|
+
.withPriority(100)
|
|
627
|
+
.build();
|
|
628
|
+
grammar
|
|
629
|
+
.define('converse with :target')
|
|
630
|
+
.mapsTo('if.action.talking')
|
|
631
|
+
.withPriority(100)
|
|
632
|
+
.build();
|
|
633
|
+
// ==========================================================================
|
|
634
|
+
// D4 SYNONYM PROMOTION (ADR-230): every verbs.ts synonym parses.
|
|
635
|
+
// Mechanical aliases of existing actions; phrasal/complex forms use
|
|
636
|
+
// .define() per the ADR-087 convention.
|
|
637
|
+
// ==========================================================================
|
|
638
|
+
// going aliases (verbs.ts: walk/run/head/travel; `move` LEFT the going
|
|
639
|
+
// list — Phase 1 ruling, move is manipulation-only).
|
|
640
|
+
// Literal expansion per direction alias, exactly like the bare-direction
|
|
641
|
+
// block below: a `:direction` slot inside .define() does NOT match
|
|
642
|
+
// direction words (the `go :direction` rule above yields
|
|
643
|
+
// "PropertyConstraint not yet supported" — pre-existing; bare directions
|
|
644
|
+
// are what players actually use). These literals also make `go north`
|
|
645
|
+
// work for the first time.
|
|
646
|
+
{
|
|
647
|
+
const directionAliases = {
|
|
648
|
+
north: ['north', 'n'],
|
|
649
|
+
south: ['south', 's'],
|
|
650
|
+
east: ['east', 'e'],
|
|
651
|
+
west: ['west', 'w'],
|
|
652
|
+
northeast: ['northeast', 'ne'],
|
|
653
|
+
northwest: ['northwest', 'nw'],
|
|
654
|
+
southeast: ['southeast', 'se'],
|
|
655
|
+
southwest: ['southwest', 'sw'],
|
|
656
|
+
up: ['up', 'u'],
|
|
657
|
+
down: ['down', 'd'],
|
|
658
|
+
in: ['in', 'inside'],
|
|
659
|
+
out: ['out', 'outside'],
|
|
660
|
+
};
|
|
661
|
+
for (const verb of ['go', 'walk', 'run', 'head', 'travel']) {
|
|
662
|
+
for (const [canonical, aliases] of Object.entries(directionAliases)) {
|
|
663
|
+
for (const alias of aliases) {
|
|
664
|
+
grammar
|
|
665
|
+
.define(`${verb} ${alias}`)
|
|
666
|
+
.mapsTo('if.action.going')
|
|
667
|
+
.withPriority(alias.length === 1 ? 90 : 100)
|
|
668
|
+
.withDefaultSemantics({ direction: canonical })
|
|
669
|
+
.build();
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// `move :target <direction>` → pushing (Phase 1 move ruling), same
|
|
674
|
+
// literal expansion.
|
|
675
|
+
for (const aliases of Object.values(directionAliases)) {
|
|
676
|
+
for (const alias of aliases) {
|
|
677
|
+
grammar
|
|
678
|
+
.define(`move :target ${alias}`)
|
|
679
|
+
.mapsTo('if.action.pushing')
|
|
680
|
+
.withPriority(105)
|
|
681
|
+
.build();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
// exiting alias
|
|
686
|
+
grammar.define('go out').mapsTo('if.action.exiting').withPriority(105).build(); // ADR-231 D2b: phrasal form above bare verb-plus-slot
|
|
687
|
+
// listening alias (hear)
|
|
688
|
+
grammar.define('hear').mapsTo('if.action.listening').withPriority(100).build();
|
|
689
|
+
grammar.define('hear :target').mapsTo('if.action.listening').withPriority(100).build();
|
|
690
|
+
// taking/dropping phrasal aliases
|
|
691
|
+
grammar.define('take up :item').mapsTo('if.action.taking').withPriority(100).build();
|
|
692
|
+
grammar.define('throw away :item').mapsTo('if.action.dropping').withPriority(100).build();
|
|
693
|
+
// putting aliases (place; move-to per the Phase 1 move ruling — putting
|
|
694
|
+
// resolves in/on by destination type when the preposition is `to`)
|
|
695
|
+
grammar.define('place :item in|into|inside :container').mapsTo('if.action.putting').withPriority(100).build();
|
|
696
|
+
grammar.define('place :item on|onto :supporter').mapsTo('if.action.putting').withPriority(100).build();
|
|
697
|
+
// 110 so the to-form outranks pushing's bare `move :target`
|
|
698
|
+
grammar.define('move :item to :destination').mapsTo('if.action.putting').withPriority(110).build();
|
|
699
|
+
// opening/closing aliases
|
|
700
|
+
grammar.define('unwrap :door').mapsTo('if.action.opening').withPriority(100).build();
|
|
701
|
+
grammar.define('uncover :door').mapsTo('if.action.opening').withPriority(100).build();
|
|
702
|
+
grammar.define('shut :door').mapsTo('if.action.closing').withPriority(100).build();
|
|
703
|
+
grammar.define('cover :door').mapsTo('if.action.closing').withPriority(100).build();
|
|
704
|
+
// turning (ADR-230 Phase 6 sketch ruling 1: capability dispatch like
|
|
705
|
+
// lowering/raising). Priority 95 so the switching phrasal forms
|
|
706
|
+
// (`turn :device on`, `turn on :device`) always win.
|
|
707
|
+
grammar.define('turn :target').mapsTo('if.action.turning').withPriority(95).build();
|
|
708
|
+
grammar.define('rotate :target').mapsTo('if.action.turning').withPriority(95).build();
|
|
709
|
+
grammar.define('twist :target').mapsTo('if.action.turning').withPriority(95).build();
|
|
710
|
+
// locking/unlocking aliases
|
|
711
|
+
grammar.define('secure :target').mapsTo('if.action.locking').withPriority(100).build();
|
|
712
|
+
grammar.define('unsecure :target').mapsTo('if.action.unlocking').withPriority(100).build();
|
|
713
|
+
// switching aliases (bare transitive forms — activate/start/deactivate/stop)
|
|
714
|
+
grammar.define('activate :device').mapsTo('if.action.switching_on').withPriority(100).build();
|
|
715
|
+
grammar.define('start :device').mapsTo('if.action.switching_on').withPriority(100).build();
|
|
716
|
+
grammar.define('deactivate :device').mapsTo('if.action.switching_off').withPriority(100).build();
|
|
717
|
+
grammar.define('stop :device').mapsTo('if.action.switching_off').withPriority(100).build();
|
|
718
|
+
// giving/showing aliases
|
|
719
|
+
grammar.define('hand :item to :recipient').mapsTo('if.action.giving').withPriority(100).build();
|
|
720
|
+
grammar.define('hand :recipient :item').mapsTo('if.action.giving').withPriority(100).build();
|
|
721
|
+
grammar.define('display :item to :recipient').mapsTo('if.action.showing').withPriority(100).build();
|
|
722
|
+
grammar.define('present :item to :recipient').mapsTo('if.action.showing').withPriority(100).build();
|
|
723
|
+
// throwing aliases
|
|
724
|
+
grammar.define('toss :item at :target').mapsTo('if.action.throwing').withPriority(100).build();
|
|
725
|
+
grammar.define('toss :item to :recipient').mapsTo('if.action.throwing').withPriority(100).build();
|
|
726
|
+
grammar.define('hurl :item at :target').mapsTo('if.action.throwing').withPriority(100).build();
|
|
727
|
+
grammar.define('hurl :item to :recipient').mapsTo('if.action.throwing').withPriority(100).build();
|
|
728
|
+
// patterns-array reconciliation promotions (PIN 4b): phrasal forms the
|
|
729
|
+
// lang help surface advertises
|
|
730
|
+
grammar.define('munch on :item').mapsTo('if.action.eating').withPriority(100).build();
|
|
731
|
+
grammar.define('nibble on :item').mapsTo('if.action.eating').withPriority(100).build();
|
|
732
|
+
grammar.define('drink from :target').mapsTo('if.action.drinking').withPriority(100).build();
|
|
733
|
+
grammar.define('sip from :target').mapsTo('if.action.drinking').withPriority(100).build();
|
|
734
|
+
grammar.define('let go of :item').mapsTo('if.action.dropping').withPriority(100).build();
|
|
735
|
+
grammar.define('open up :door').mapsTo('if.action.opening').withPriority(100).build();
|
|
736
|
+
grammar.define('power on :device').mapsTo('if.action.switching_on').withPriority(100).build();
|
|
737
|
+
grammar.define('power off :device').mapsTo('if.action.switching_off').withPriority(100).build();
|
|
738
|
+
grammar.define('extract :item from :container').mapsTo('if.action.removing').withPriority(110).build();
|
|
739
|
+
// meta aliases
|
|
740
|
+
grammar.define('save game').mapsTo('if.action.saving').withPriority(100).build();
|
|
741
|
+
grammar.define('load').mapsTo('if.action.restoring').withPriority(100).build();
|
|
742
|
+
grammar.define('load game').mapsTo('if.action.restoring').withPriority(100).build();
|
|
743
|
+
grammar.define('restore game').mapsTo('if.action.restoring').withPriority(100).build();
|
|
744
|
+
grammar.define('exit game').mapsTo('if.action.quitting').withPriority(105).build(); // outranks `exit :container`
|
|
745
|
+
grammar.define('?').mapsTo('if.action.help').withPriority(100).build();
|
|
746
|
+
grammar.define('commands').mapsTo('if.action.help').withPriority(100).build();
|
|
747
|
+
grammar.define('points').mapsTo('if.action.scoring').withPriority(100).build();
|
|
555
748
|
// Touching/sensory actions (ADR-087: using forAction)
|
|
556
749
|
// Scope handled by action validation
|
|
557
750
|
grammar
|
|
@@ -559,52 +752,108 @@ function defineGrammar(grammar) {
|
|
|
559
752
|
.verbs(['touch', 'rub', 'feel', 'pat', 'stroke', 'poke', 'prod'])
|
|
560
753
|
.pattern(':target')
|
|
561
754
|
.build();
|
|
755
|
+
// Listening and smelling (ADR-230 D2) — bare and targeted forms; both
|
|
756
|
+
// actions support the bare shape (ambient sound / room smell).
|
|
757
|
+
grammar
|
|
758
|
+
.define('listen')
|
|
759
|
+
.mapsTo('if.action.listening')
|
|
760
|
+
.withPriority(100)
|
|
761
|
+
.build();
|
|
762
|
+
grammar
|
|
763
|
+
.define('listen to :target')
|
|
764
|
+
.mapsTo('if.action.listening')
|
|
765
|
+
.withPriority(100)
|
|
766
|
+
.build();
|
|
767
|
+
grammar
|
|
768
|
+
.forAction('if.action.smelling')
|
|
769
|
+
.verbs(['smell', 'sniff'])
|
|
770
|
+
.build();
|
|
771
|
+
grammar
|
|
772
|
+
.forAction('if.action.smelling')
|
|
773
|
+
.verbs(['smell', 'sniff'])
|
|
774
|
+
.pattern(':target')
|
|
775
|
+
.build();
|
|
562
776
|
// ============================================================================
|
|
563
777
|
// ENTERING AND EXITING
|
|
564
|
-
// Scope handled by action validation
|
|
778
|
+
// Scope and trait-based refusal handled by action validation
|
|
565
779
|
// ============================================================================
|
|
566
780
|
// Semantic: enter specific enterable thing (priority 100)
|
|
567
781
|
grammar
|
|
568
782
|
.define('enter :portal')
|
|
569
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
570
783
|
.mapsTo('if.action.entering')
|
|
571
784
|
.withPriority(100)
|
|
572
785
|
.build();
|
|
786
|
+
// Prepositional/phrasal entering forms sit at 105 (ADR-231 D2b): the file's
|
|
787
|
+
// guideline puts semantic/phrasal forms above bare verb-plus-slot forms, and
|
|
788
|
+
// these previously tied taking's `get :item` / climbing's `climb :target` at
|
|
789
|
+
// 100 (`exit game` at 105 is the precedent). The literal-before-slot
|
|
790
|
+
// specificity tiebreak also resolves this class structurally.
|
|
573
791
|
grammar
|
|
574
792
|
.define('get in :portal')
|
|
575
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
576
793
|
.mapsTo('if.action.entering')
|
|
577
|
-
.withPriority(
|
|
794
|
+
.withPriority(105)
|
|
578
795
|
.build();
|
|
579
796
|
grammar
|
|
580
797
|
.define('get into :portal')
|
|
581
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
582
798
|
.mapsTo('if.action.entering')
|
|
583
|
-
.withPriority(
|
|
799
|
+
.withPriority(105)
|
|
584
800
|
.build();
|
|
585
801
|
grammar
|
|
586
802
|
.define('climb in :portal')
|
|
587
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
588
803
|
.mapsTo('if.action.entering')
|
|
589
|
-
.withPriority(
|
|
804
|
+
.withPriority(105)
|
|
590
805
|
.build();
|
|
591
806
|
grammar
|
|
592
807
|
.define('climb into :portal')
|
|
593
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
594
808
|
.mapsTo('if.action.entering')
|
|
809
|
+
.withPriority(105)
|
|
810
|
+
.build();
|
|
811
|
+
// Climb a climbable object (priority 100) — ADR-218 §1a (ratchet F2).
|
|
812
|
+
// Routes `climb <thing>` and its synonyms to the climbing action's object-climb
|
|
813
|
+
// path. [2026-07-17, ADR-231 D2a] This block originally claimed parse-time
|
|
814
|
+
// CLIMBABLE gating via .hasTrait(); that call was a no-op and has been
|
|
815
|
+
// deleted — climbing's validate() owns the not_climbable refusal.
|
|
816
|
+
// The prepositional `climb in/into :portal` (entering) and `climb out` (exiting)
|
|
817
|
+
// forms are unaffected — they carry a preposition token these bare forms do not.
|
|
818
|
+
grammar
|
|
819
|
+
.define('climb :target')
|
|
820
|
+
.mapsTo('if.action.climbing')
|
|
821
|
+
.withPriority(100)
|
|
822
|
+
.build();
|
|
823
|
+
grammar
|
|
824
|
+
.define('climb up :target')
|
|
825
|
+
.mapsTo('if.action.climbing')
|
|
826
|
+
.withPriority(100)
|
|
827
|
+
.build();
|
|
828
|
+
grammar
|
|
829
|
+
.define('climb down :target')
|
|
830
|
+
.mapsTo('if.action.climbing')
|
|
831
|
+
.withPriority(100)
|
|
832
|
+
.build();
|
|
833
|
+
grammar
|
|
834
|
+
.define('scale :target')
|
|
835
|
+
.mapsTo('if.action.climbing')
|
|
836
|
+
.withPriority(100)
|
|
837
|
+
.build();
|
|
838
|
+
grammar
|
|
839
|
+
.define('ascend :target')
|
|
840
|
+
.mapsTo('if.action.climbing')
|
|
841
|
+
.withPriority(100)
|
|
842
|
+
.build();
|
|
843
|
+
grammar
|
|
844
|
+
.define('descend :target')
|
|
845
|
+
.mapsTo('if.action.climbing')
|
|
595
846
|
.withPriority(100)
|
|
596
847
|
.build();
|
|
597
848
|
grammar
|
|
598
849
|
.define('go in :portal')
|
|
599
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
600
850
|
.mapsTo('if.action.entering')
|
|
601
|
-
.withPriority(
|
|
851
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above bare verb-plus-slot
|
|
602
852
|
.build();
|
|
603
853
|
grammar
|
|
604
854
|
.define('go into :portal')
|
|
605
|
-
.hasTrait('portal', world_model_1.TraitType.ENTERABLE)
|
|
606
855
|
.mapsTo('if.action.entering')
|
|
607
|
-
.withPriority(
|
|
856
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above bare verb-plus-slot
|
|
608
857
|
.build();
|
|
609
858
|
// Exiting (bare command, no target - exits current container/location)
|
|
610
859
|
grammar
|
|
@@ -615,7 +864,7 @@ function defineGrammar(grammar) {
|
|
|
615
864
|
grammar
|
|
616
865
|
.define('get out')
|
|
617
866
|
.mapsTo('if.action.exiting')
|
|
618
|
-
.withPriority(
|
|
867
|
+
.withPriority(105) // ADR-231 D2b: outranks taking's `get :item` ("out" is not an item)
|
|
619
868
|
.build();
|
|
620
869
|
grammar
|
|
621
870
|
.define('leave')
|
|
@@ -625,28 +874,35 @@ function defineGrammar(grammar) {
|
|
|
625
874
|
grammar
|
|
626
875
|
.define('climb out')
|
|
627
876
|
.mapsTo('if.action.exiting')
|
|
628
|
-
.withPriority(
|
|
877
|
+
.withPriority(105) // ADR-231 D2b: outranks climbing's `climb :target`
|
|
629
878
|
.build();
|
|
630
879
|
// Vehicle-specific synonyms (map to entering/exiting actions)
|
|
631
880
|
grammar
|
|
632
881
|
.define('board :vehicle')
|
|
633
|
-
.hasTrait('vehicle', world_model_1.TraitType.ENTERABLE)
|
|
634
882
|
.mapsTo('if.action.entering')
|
|
635
883
|
.withPriority(100)
|
|
636
884
|
.build();
|
|
637
885
|
grammar
|
|
638
886
|
.define('get on :vehicle')
|
|
639
|
-
.hasTrait('vehicle', world_model_1.TraitType.ENTERABLE)
|
|
640
887
|
.mapsTo('if.action.entering')
|
|
641
|
-
.withPriority(
|
|
888
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above taking's `get :item`
|
|
642
889
|
.build();
|
|
643
890
|
// Exiting with a target (exit specific container/vehicle)
|
|
644
891
|
grammar
|
|
645
892
|
.define('exit :container')
|
|
646
|
-
.hasTrait('container', world_model_1.TraitType.ENTERABLE)
|
|
647
893
|
.mapsTo('if.action.exiting')
|
|
648
894
|
.withPriority(100)
|
|
649
895
|
.build();
|
|
896
|
+
grammar
|
|
897
|
+
.define('get out of :container')
|
|
898
|
+
.mapsTo('if.action.exiting')
|
|
899
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above taking's `get :item`
|
|
900
|
+
.build();
|
|
901
|
+
grammar
|
|
902
|
+
.define('climb out of :container')
|
|
903
|
+
.mapsTo('if.action.exiting')
|
|
904
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above climbing's `climb :target`
|
|
905
|
+
.build();
|
|
650
906
|
grammar
|
|
651
907
|
.define('disembark')
|
|
652
908
|
.mapsTo('if.action.exiting')
|
|
@@ -654,15 +910,13 @@ function defineGrammar(grammar) {
|
|
|
654
910
|
.build();
|
|
655
911
|
grammar
|
|
656
912
|
.define('disembark :vehicle')
|
|
657
|
-
.hasTrait('vehicle', world_model_1.TraitType.ENTERABLE)
|
|
658
913
|
.mapsTo('if.action.exiting')
|
|
659
914
|
.withPriority(100)
|
|
660
915
|
.build();
|
|
661
916
|
grammar
|
|
662
917
|
.define('get off :vehicle')
|
|
663
|
-
.hasTrait('vehicle', world_model_1.TraitType.ENTERABLE)
|
|
664
918
|
.mapsTo('if.action.exiting')
|
|
665
|
-
.withPriority(
|
|
919
|
+
.withPriority(105) // ADR-231 D2b: phrasal form above taking's `get :item`
|
|
666
920
|
.build();
|
|
667
921
|
grammar
|
|
668
922
|
.define('alight')
|