@sharpee/character 0.9.106 → 0.9.107

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.
Files changed (137) hide show
  1. package/apply.d.ts +29 -7
  2. package/apply.d.ts.map +1 -1
  3. package/apply.js +15 -7
  4. package/apply.js.map +1 -1
  5. package/character-builder.d.ts +67 -4
  6. package/character-builder.d.ts.map +1 -1
  7. package/character-builder.js +116 -7
  8. package/character-builder.js.map +1 -1
  9. package/conversation/acl.d.ts +62 -0
  10. package/conversation/acl.d.ts.map +1 -0
  11. package/conversation/acl.js +117 -0
  12. package/conversation/acl.js.map +1 -0
  13. package/conversation/builder.d.ts +247 -0
  14. package/conversation/builder.d.ts.map +1 -0
  15. package/conversation/builder.js +324 -0
  16. package/conversation/builder.js.map +1 -0
  17. package/conversation/constraint-evaluator.d.ts +147 -0
  18. package/conversation/constraint-evaluator.d.ts.map +1 -0
  19. package/conversation/constraint-evaluator.js +247 -0
  20. package/conversation/constraint-evaluator.js.map +1 -0
  21. package/conversation/conversation-messages.d.ts +56 -0
  22. package/conversation/conversation-messages.d.ts.map +1 -0
  23. package/conversation/conversation-messages.js +69 -0
  24. package/conversation/conversation-messages.js.map +1 -0
  25. package/conversation/dialogue-extension.d.ts +87 -0
  26. package/conversation/dialogue-extension.d.ts.map +1 -0
  27. package/conversation/dialogue-extension.js +302 -0
  28. package/conversation/dialogue-extension.js.map +1 -0
  29. package/conversation/dialogue-types.d.ts +71 -0
  30. package/conversation/dialogue-types.d.ts.map +1 -0
  31. package/conversation/dialogue-types.js +13 -0
  32. package/conversation/dialogue-types.js.map +1 -0
  33. package/conversation/index.d.ts +19 -0
  34. package/conversation/index.d.ts.map +1 -0
  35. package/conversation/index.js +37 -0
  36. package/conversation/index.js.map +1 -0
  37. package/conversation/lifecycle.d.ts +212 -0
  38. package/conversation/lifecycle.d.ts.map +1 -0
  39. package/conversation/lifecycle.js +348 -0
  40. package/conversation/lifecycle.js.map +1 -0
  41. package/conversation/response-types.d.ts +98 -0
  42. package/conversation/response-types.d.ts.map +1 -0
  43. package/conversation/response-types.js +30 -0
  44. package/conversation/response-types.js.map +1 -0
  45. package/conversation/topic-registry.d.ts +130 -0
  46. package/conversation/topic-registry.d.ts.map +1 -0
  47. package/conversation/topic-registry.js +187 -0
  48. package/conversation/topic-registry.js.map +1 -0
  49. package/goals/builder.d.ts +135 -0
  50. package/goals/builder.d.ts.map +1 -0
  51. package/goals/builder.js +193 -0
  52. package/goals/builder.js.map +1 -0
  53. package/goals/goal-activation.d.ts +99 -0
  54. package/goals/goal-activation.d.ts.map +1 -0
  55. package/goals/goal-activation.js +212 -0
  56. package/goals/goal-activation.js.map +1 -0
  57. package/goals/goal-types.d.ts +138 -0
  58. package/goals/goal-types.d.ts.map +1 -0
  59. package/goals/goal-types.js +20 -0
  60. package/goals/goal-types.js.map +1 -0
  61. package/goals/index.d.ts +15 -0
  62. package/goals/index.d.ts.map +1 -0
  63. package/goals/index.js +24 -0
  64. package/goals/index.js.map +1 -0
  65. package/goals/pathfinding.d.ts +67 -0
  66. package/goals/pathfinding.d.ts.map +1 -0
  67. package/goals/pathfinding.js +134 -0
  68. package/goals/pathfinding.js.map +1 -0
  69. package/goals/step-evaluator.d.ts +52 -0
  70. package/goals/step-evaluator.d.ts.map +1 -0
  71. package/goals/step-evaluator.js +153 -0
  72. package/goals/step-evaluator.js.map +1 -0
  73. package/index.d.ts +6 -1
  74. package/index.d.ts.map +1 -1
  75. package/index.js +60 -1
  76. package/index.js.map +1 -1
  77. package/influence/builder.d.ts +136 -0
  78. package/influence/builder.d.ts.map +1 -0
  79. package/influence/builder.js +198 -0
  80. package/influence/builder.js.map +1 -0
  81. package/influence/index.d.ts +16 -0
  82. package/influence/index.d.ts.map +1 -0
  83. package/influence/index.js +25 -0
  84. package/influence/index.js.map +1 -0
  85. package/influence/influence-duration.d.ts +82 -0
  86. package/influence/influence-duration.d.ts.map +1 -0
  87. package/influence/influence-duration.js +148 -0
  88. package/influence/influence-duration.js.map +1 -0
  89. package/influence/influence-evaluator.d.ts +55 -0
  90. package/influence/influence-evaluator.d.ts.map +1 -0
  91. package/influence/influence-evaluator.js +183 -0
  92. package/influence/influence-evaluator.js.map +1 -0
  93. package/influence/influence-messages.d.ts +30 -0
  94. package/influence/influence-messages.d.ts.map +1 -0
  95. package/influence/influence-messages.js +40 -0
  96. package/influence/influence-messages.js.map +1 -0
  97. package/influence/influence-types.d.ts +123 -0
  98. package/influence/influence-types.d.ts.map +1 -0
  99. package/influence/influence-types.js +12 -0
  100. package/influence/influence-types.js.map +1 -0
  101. package/influence/pc-influence.d.ts +38 -0
  102. package/influence/pc-influence.d.ts.map +1 -0
  103. package/influence/pc-influence.js +56 -0
  104. package/influence/pc-influence.js.map +1 -0
  105. package/package.json +4 -3
  106. package/propagation/builder.d.ts +47 -0
  107. package/propagation/builder.d.ts.map +1 -0
  108. package/propagation/builder.js +46 -0
  109. package/propagation/builder.js.map +1 -0
  110. package/propagation/fact-transfer.d.ts +47 -0
  111. package/propagation/fact-transfer.d.ts.map +1 -0
  112. package/propagation/fact-transfer.js +76 -0
  113. package/propagation/fact-transfer.js.map +1 -0
  114. package/propagation/index.d.ts +16 -0
  115. package/propagation/index.d.ts.map +1 -0
  116. package/propagation/index.js +28 -0
  117. package/propagation/index.js.map +1 -0
  118. package/propagation/propagation-evaluator.d.ts +53 -0
  119. package/propagation/propagation-evaluator.d.ts.map +1 -0
  120. package/propagation/propagation-evaluator.js +231 -0
  121. package/propagation/propagation-evaluator.js.map +1 -0
  122. package/propagation/propagation-messages.d.ts +30 -0
  123. package/propagation/propagation-messages.d.ts.map +1 -0
  124. package/propagation/propagation-messages.js +37 -0
  125. package/propagation/propagation-messages.js.map +1 -0
  126. package/propagation/propagation-types.d.ts +100 -0
  127. package/propagation/propagation-types.d.ts.map +1 -0
  128. package/propagation/propagation-types.js +68 -0
  129. package/propagation/propagation-types.js.map +1 -0
  130. package/propagation/visibility.d.ts +46 -0
  131. package/propagation/visibility.d.ts.map +1 -0
  132. package/propagation/visibility.js +79 -0
  133. package/propagation/visibility.js.map +1 -0
  134. package/tick-phases.d.ts +93 -0
  135. package/tick-phases.d.ts.map +1 -0
  136. package/tick-phases.js +433 -0
  137. package/tick-phases.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-types.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/character/src/conversation/response-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAMvD;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,MAAM,GACN,KAAK,GACL,SAAS,GACT,QAAQ,GACR,UAAU,GACV,SAAS,GACT,aAAa,CAAC;AAMlB;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,MAAM,EAAE,cAAc,CAAC;IAEvB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC;IAEvC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAMD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,MAAM,EAAE,cAAc,CAAC;IAEvB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IAEd,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAElB,+DAA+D;IAC/D,IAAI,EAAE,IAAI,CAAC;IAEX,wEAAwE;IACxE,SAAS,EAAE,SAAS,CAAC;IAErB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAMD,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,MAAM,EAAE,cAAc,CAAC;IAEvB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,sCAAsC;IACtC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAE1C,4DAA4D;IAC5D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;CAC3C;AAMD,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IAEd,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;AAM1D,0CAA0C;AAC1C,wBAAgB,wBAAwB,IAAI,kBAAkB,CAK7D;AAED,sCAAsC;AACtC,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * Conversation response types (ADR-142)
4
+ *
5
+ * Type definitions for constraint-based response selection:
6
+ * ResponseAction, ResponseCandidate, ResponseIntent, and
7
+ * conversation/evidence tracking records.
8
+ *
9
+ * Public interface: ResponseAction, ResponseCandidate, ResponseIntent,
10
+ * ConversationRecord, ConversationEntry, EvidenceRecord, EvidenceEntry.
11
+ * Owner context: @sharpee/character / conversation
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.createConversationRecord = createConversationRecord;
15
+ exports.createEvidenceRecord = createEvidenceRecord;
16
+ // ---------------------------------------------------------------------------
17
+ // Factory helpers
18
+ // ---------------------------------------------------------------------------
19
+ /** Create an empty ConversationRecord. */
20
+ function createConversationRecord() {
21
+ return {
22
+ responses: new Map(),
23
+ history: new Map(),
24
+ };
25
+ }
26
+ /** Create an empty EvidenceRecord. */
27
+ function createEvidenceRecord() {
28
+ return new Map();
29
+ }
30
+ //# sourceMappingURL=response-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-types.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/character/src/conversation/response-types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AA0IH,4DAKC;AAGD,oDAEC;AAfD,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,0CAA0C;AAC1C,SAAgB,wBAAwB;IACtC,OAAO;QACL,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,OAAO,EAAE,IAAI,GAAG,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,sCAAsC;AACtC,SAAgB,oBAAoB;IAClC,OAAO,IAAI,GAAG,EAAE,CAAC;AACnB,CAAC"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Topic registry and resolution (ADR-142)
3
+ *
4
+ * Authors define topics with keyword sets and optional relationships.
5
+ * The registry resolves free-text player input to authored topics
6
+ * using exact normalized word matching with neighborhood fallback.
7
+ *
8
+ * Public interface: TopicDef, TopicRegistry.
9
+ * Owner context: @sharpee/character / conversation
10
+ */
11
+ import { CharacterModelTrait } from "../../world-model/index";
12
+ /** An authored topic definition with keywords, relationships, and availability. */
13
+ export interface TopicDef {
14
+ /** The canonical topic name (used as key). */
15
+ name: string;
16
+ /**
17
+ * Exact keyword set for matching player input.
18
+ * Stored normalized (lowercase, trimmed). Each entry can be
19
+ * a single word or a multi-word phrase.
20
+ */
21
+ keywords: string[];
22
+ /**
23
+ * Related topic names — the neighborhood for fallback matching.
24
+ * When the player's input doesn't match any topic exactly but
25
+ * matches a related topic, the NPC can redirect.
26
+ */
27
+ related?: string[];
28
+ /**
29
+ * Predicate names that must all be satisfied for this topic to be
30
+ * available to the player. Evaluated against the NPC's character state.
31
+ * If empty or undefined, the topic is always available.
32
+ */
33
+ availableWhen?: string[];
34
+ }
35
+ /** The result of resolving player text to a topic. */
36
+ export type TopicResolution = {
37
+ type: 'exact';
38
+ topic: TopicDef;
39
+ } | {
40
+ type: 'related';
41
+ topic: TopicDef;
42
+ via: TopicDef;
43
+ } | {
44
+ type: 'none';
45
+ };
46
+ /**
47
+ * Registry of authored topics for a single NPC.
48
+ *
49
+ * Topics are defined once during character building. At runtime,
50
+ * the registry resolves player free-text input to the best matching
51
+ * topic, considering keyword matches and topic neighborhoods.
52
+ */
53
+ export declare class TopicRegistry {
54
+ private readonly topics;
55
+ /**
56
+ * Register a topic definition.
57
+ *
58
+ * @param def - The topic definition to register
59
+ * @throws Error if a topic with the same name is already registered
60
+ */
61
+ define(def: TopicDef): void;
62
+ /**
63
+ * Get a topic by its canonical name.
64
+ *
65
+ * @param name - The topic name
66
+ * @returns The topic definition, or undefined
67
+ */
68
+ get(name: string): TopicDef | undefined;
69
+ /**
70
+ * Check whether a topic is available given the NPC's current state.
71
+ *
72
+ * @param name - The topic name
73
+ * @param npcTrait - The NPC's CharacterModelTrait for predicate evaluation
74
+ * @returns True if the topic exists and its availability predicates are satisfied
75
+ */
76
+ isAvailable(name: string, npcTrait: CharacterModelTrait): boolean;
77
+ /**
78
+ * Resolve player free-text input to a topic.
79
+ *
80
+ * Resolution algorithm:
81
+ * 1. Normalize input to lowercase words
82
+ * 2. Score each available topic by keyword hits (exact word match)
83
+ * 3. If any topic has hits, select the one with the most hits (exact match)
84
+ * 4. If no exact match, check if input matches keywords of any related topic
85
+ * and redirect through the neighborhood
86
+ * 5. If no match at all, return { type: 'none' }
87
+ *
88
+ * @param text - Raw text from the player (e.g., "the murder weapon")
89
+ * @param npcTrait - The NPC's CharacterModelTrait for availability checks
90
+ * @returns Resolution result: exact match, related redirect, or no match
91
+ */
92
+ resolve(text: string, npcTrait: CharacterModelTrait): TopicResolution;
93
+ /**
94
+ * Search for a related-topic redirect when no exact match was found.
95
+ *
96
+ * For each available topic with related topics, checks if the input
97
+ * matches any related topic's keywords. Returns the first match as
98
+ * a redirect resolution.
99
+ *
100
+ * @param inputWords - Input split into normalized words
101
+ * @param inputNormalized - Full normalized input string
102
+ * @param npcTrait - The NPC's CharacterModelTrait for availability checks
103
+ * @returns Related redirect resolution, or { type: 'none' }
104
+ */
105
+ private findRelatedRedirect;
106
+ /**
107
+ * Get all registered topic names.
108
+ *
109
+ * @returns Array of topic names
110
+ */
111
+ getTopicNames(): string[];
112
+ /**
113
+ * Get all topics that are currently available to the player.
114
+ *
115
+ * @param npcTrait - The NPC's CharacterModelTrait for predicate evaluation
116
+ * @returns Array of available topic definitions
117
+ */
118
+ getAvailableTopics(npcTrait: CharacterModelTrait): TopicDef[];
119
+ /**
120
+ * Score how well the input matches a keyword set.
121
+ * Each keyword that appears as a word or phrase in the input scores 1.
122
+ *
123
+ * @param inputWords - Input split into normalized words
124
+ * @param inputNormalized - Full normalized input string
125
+ * @param keywords - The topic's keyword set (already normalized)
126
+ * @returns Number of keyword hits
127
+ */
128
+ private scoreKeywordMatch;
129
+ }
130
+ //# sourceMappingURL=topic-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-registry.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/character/src/conversation/topic-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAM3D,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,sDAAsD;AACtD,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAMrB;;;;;;GAMG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAE3D;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAY3B;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvC;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,OAAO;IAWjE;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe;IA0BrE;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IAwB3B;;;;OAIG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;;OAKG;IACH,kBAAkB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,QAAQ,EAAE;IAc7D;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;CAmB1B"}
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ /**
3
+ * Topic registry and resolution (ADR-142)
4
+ *
5
+ * Authors define topics with keyword sets and optional relationships.
6
+ * The registry resolves free-text player input to authored topics
7
+ * using exact normalized word matching with neighborhood fallback.
8
+ *
9
+ * Public interface: TopicDef, TopicRegistry.
10
+ * Owner context: @sharpee/character / conversation
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.TopicRegistry = void 0;
14
+ // ---------------------------------------------------------------------------
15
+ // Topic registry
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Registry of authored topics for a single NPC.
19
+ *
20
+ * Topics are defined once during character building. At runtime,
21
+ * the registry resolves player free-text input to the best matching
22
+ * topic, considering keyword matches and topic neighborhoods.
23
+ */
24
+ class TopicRegistry {
25
+ topics = new Map();
26
+ /**
27
+ * Register a topic definition.
28
+ *
29
+ * @param def - The topic definition to register
30
+ * @throws Error if a topic with the same name is already registered
31
+ */
32
+ define(def) {
33
+ if (this.topics.has(def.name)) {
34
+ throw new Error(`Topic '${def.name}' is already defined`);
35
+ }
36
+ // Normalize keywords at registration time
37
+ const normalized = {
38
+ ...def,
39
+ keywords: def.keywords.map(k => k.toLowerCase().trim()),
40
+ };
41
+ this.topics.set(def.name, normalized);
42
+ }
43
+ /**
44
+ * Get a topic by its canonical name.
45
+ *
46
+ * @param name - The topic name
47
+ * @returns The topic definition, or undefined
48
+ */
49
+ get(name) {
50
+ return this.topics.get(name);
51
+ }
52
+ /**
53
+ * Check whether a topic is available given the NPC's current state.
54
+ *
55
+ * @param name - The topic name
56
+ * @param npcTrait - The NPC's CharacterModelTrait for predicate evaluation
57
+ * @returns True if the topic exists and its availability predicates are satisfied
58
+ */
59
+ isAvailable(name, npcTrait) {
60
+ const topic = this.topics.get(name);
61
+ if (!topic)
62
+ return false;
63
+ if (!topic.availableWhen || topic.availableWhen.length === 0) {
64
+ return true;
65
+ }
66
+ return topic.availableWhen.every(pred => npcTrait.evaluate(pred));
67
+ }
68
+ /**
69
+ * Resolve player free-text input to a topic.
70
+ *
71
+ * Resolution algorithm:
72
+ * 1. Normalize input to lowercase words
73
+ * 2. Score each available topic by keyword hits (exact word match)
74
+ * 3. If any topic has hits, select the one with the most hits (exact match)
75
+ * 4. If no exact match, check if input matches keywords of any related topic
76
+ * and redirect through the neighborhood
77
+ * 5. If no match at all, return { type: 'none' }
78
+ *
79
+ * @param text - Raw text from the player (e.g., "the murder weapon")
80
+ * @param npcTrait - The NPC's CharacterModelTrait for availability checks
81
+ * @returns Resolution result: exact match, related redirect, or no match
82
+ */
83
+ resolve(text, npcTrait) {
84
+ const inputWords = text.toLowerCase().trim().split(/\s+/);
85
+ const inputNormalized = text.toLowerCase().trim();
86
+ // Phase 1: Score each available topic by keyword hits
87
+ let bestTopic;
88
+ let bestScore = 0;
89
+ for (const topic of this.topics.values()) {
90
+ if (!this.isAvailable(topic.name, npcTrait))
91
+ continue;
92
+ const score = this.scoreKeywordMatch(inputWords, inputNormalized, topic.keywords);
93
+ if (score > bestScore) {
94
+ bestScore = score;
95
+ bestTopic = topic;
96
+ }
97
+ }
98
+ if (bestTopic) {
99
+ return { type: 'exact', topic: bestTopic };
100
+ }
101
+ // Phase 2: Check related topic neighborhoods
102
+ return this.findRelatedRedirect(inputWords, inputNormalized, npcTrait);
103
+ }
104
+ /**
105
+ * Search for a related-topic redirect when no exact match was found.
106
+ *
107
+ * For each available topic with related topics, checks if the input
108
+ * matches any related topic's keywords. Returns the first match as
109
+ * a redirect resolution.
110
+ *
111
+ * @param inputWords - Input split into normalized words
112
+ * @param inputNormalized - Full normalized input string
113
+ * @param npcTrait - The NPC's CharacterModelTrait for availability checks
114
+ * @returns Related redirect resolution, or { type: 'none' }
115
+ */
116
+ findRelatedRedirect(inputWords, inputNormalized, npcTrait) {
117
+ for (const topic of this.topics.values()) {
118
+ if (!this.isAvailable(topic.name, npcTrait))
119
+ continue;
120
+ if (topic.related) {
121
+ for (const relatedName of topic.related) {
122
+ const relatedTopic = this.topics.get(relatedName);
123
+ if (!relatedTopic)
124
+ continue;
125
+ const score = this.scoreKeywordMatch(inputWords, inputNormalized, relatedTopic.keywords);
126
+ if (score > 0) {
127
+ return { type: 'related', topic, via: relatedTopic };
128
+ }
129
+ }
130
+ }
131
+ }
132
+ return { type: 'none' };
133
+ }
134
+ /**
135
+ * Get all registered topic names.
136
+ *
137
+ * @returns Array of topic names
138
+ */
139
+ getTopicNames() {
140
+ return Array.from(this.topics.keys());
141
+ }
142
+ /**
143
+ * Get all topics that are currently available to the player.
144
+ *
145
+ * @param npcTrait - The NPC's CharacterModelTrait for predicate evaluation
146
+ * @returns Array of available topic definitions
147
+ */
148
+ getAvailableTopics(npcTrait) {
149
+ const result = [];
150
+ for (const topic of this.topics.values()) {
151
+ if (this.isAvailable(topic.name, npcTrait)) {
152
+ result.push(topic);
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ // -------------------------------------------------------------------------
158
+ // Private helpers
159
+ // -------------------------------------------------------------------------
160
+ /**
161
+ * Score how well the input matches a keyword set.
162
+ * Each keyword that appears as a word or phrase in the input scores 1.
163
+ *
164
+ * @param inputWords - Input split into normalized words
165
+ * @param inputNormalized - Full normalized input string
166
+ * @param keywords - The topic's keyword set (already normalized)
167
+ * @returns Number of keyword hits
168
+ */
169
+ scoreKeywordMatch(inputWords, inputNormalized, keywords) {
170
+ let score = 0;
171
+ for (const keyword of keywords) {
172
+ if (keyword.includes(' ')) {
173
+ // Multi-word phrase: check substring match in full input
174
+ if (inputNormalized.includes(keyword)) {
175
+ score++;
176
+ }
177
+ }
178
+ else if (inputWords.includes(keyword)) {
179
+ // Single word: check exact word match
180
+ score++;
181
+ }
182
+ }
183
+ return score;
184
+ }
185
+ }
186
+ exports.TopicRegistry = TopicRegistry;
187
+ //# sourceMappingURL=topic-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-registry.js","sourceRoot":"","sources":["../../../../../../../repos/sharpee/packages/character/src/conversation/topic-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Goal builder API (ADR-145 layer 5)
3
+ *
4
+ * Fluent builder for defining NPC goals with activation conditions,
5
+ * pursuit modes, behavior sequences, and interruption rules.
6
+ * Returns from CharacterBuilder.goal(id) and compiles to GoalDef
7
+ * stored in CompiledCharacter.goalDefs.
8
+ *
9
+ * Public interface: GoalBuilder.
10
+ * Owner context: @sharpee/character / goals
11
+ */
12
+ import { GoalPriority, PursuitMode, GoalStep, GoalDef } from './goal-types';
13
+ /**
14
+ * Fluent builder for a single goal definition.
15
+ *
16
+ * Usage:
17
+ * ```
18
+ * builder.goal('eliminate-player')
19
+ * .activatesWhen('knows murder discovered', 'has weapon')
20
+ * .priority('critical')
21
+ * .mode('prepared')
22
+ * .pursues([
23
+ * { type: 'moveTo', target: 'study' },
24
+ * { type: 'acquire', target: 'knife' },
25
+ * ])
26
+ * .actsWhen('alone with player')
27
+ * .act('colonel-attacks-player')
28
+ * .onInterrupt('colonel-retreats')
29
+ * .resumeOnClear(true)
30
+ * .done()
31
+ * ```
32
+ */
33
+ export declare class GoalBuilder<TParent> {
34
+ private readonly _id;
35
+ private readonly _parent;
36
+ private readonly _finalize;
37
+ private readonly _activatesWhen;
38
+ private readonly _interruptedBy;
39
+ private _priority;
40
+ private _mode;
41
+ private _steps;
42
+ private readonly _actsWhen;
43
+ private _actMessageId?;
44
+ private _onInterrupt?;
45
+ private _resumeOnClear;
46
+ /**
47
+ * Create a new goal builder.
48
+ *
49
+ * @param id - Unique goal identifier
50
+ * @param parent - Parent builder to return to on .done()
51
+ * @param finalize - Callback to register the compiled GoalDef
52
+ */
53
+ constructor(id: string, parent: TParent, finalize: (def: GoalDef) => void);
54
+ /**
55
+ * Set predicate conditions that activate this goal.
56
+ *
57
+ * @param predicates - Predicate names (all must be true)
58
+ * @returns this for chaining
59
+ */
60
+ activatesWhen(...predicates: string[]): GoalBuilder<TParent>;
61
+ /**
62
+ * Set goal priority.
63
+ *
64
+ * @param priority - Priority word
65
+ * @returns this for chaining
66
+ */
67
+ priority(priority: GoalPriority): GoalBuilder<TParent>;
68
+ /**
69
+ * Set pursuit mode.
70
+ *
71
+ * @param mode - How the NPC pursues the goal
72
+ * @returns this for chaining
73
+ */
74
+ mode(mode: PursuitMode): GoalBuilder<TParent>;
75
+ /**
76
+ * Set the behavior sequence (for sequential and prepared modes).
77
+ *
78
+ * @param steps - Array of goal steps
79
+ * @returns this for chaining
80
+ */
81
+ pursues(steps: GoalStep[]): GoalBuilder<TParent>;
82
+ /**
83
+ * Set conditions for the final act (opportunistic/prepared modes).
84
+ *
85
+ * @param predicates - Predicate names (all must be true)
86
+ * @returns this for chaining
87
+ */
88
+ actsWhen(...predicates: string[]): GoalBuilder<TParent>;
89
+ /**
90
+ * Set the message ID for the final act.
91
+ *
92
+ * @param messageId - Message ID
93
+ * @returns this for chaining
94
+ */
95
+ act(messageId: string): GoalBuilder<TParent>;
96
+ /**
97
+ * Set predicate conditions that interrupt (suspend) this goal.
98
+ *
99
+ * @param predicates - Predicate names
100
+ * @returns this for chaining
101
+ */
102
+ interruptedBy(...predicates: string[]): GoalBuilder<TParent>;
103
+ /**
104
+ * Set the message ID when the goal is interrupted.
105
+ *
106
+ * @param messageId - Message ID
107
+ * @returns this for chaining
108
+ */
109
+ onInterrupt(messageId: string): GoalBuilder<TParent>;
110
+ /**
111
+ * Set whether the goal resumes from where it left off after interruption.
112
+ *
113
+ * @param resume - Whether to resume
114
+ * @returns this for chaining
115
+ */
116
+ resumeOnClear(resume: boolean): GoalBuilder<TParent>;
117
+ /**
118
+ * Finalize this goal definition and return the parent builder.
119
+ *
120
+ * @returns The parent builder
121
+ */
122
+ done(): TParent;
123
+ /**
124
+ * Compile the parent builder, auto-finalizing this goal.
125
+ * Allows calling .compile() directly from a goal chain without .done().
126
+ *
127
+ * @returns Compiled character data (delegates to parent's compile())
128
+ */
129
+ compile(): ReturnType<TParent extends {
130
+ compile(): infer R;
131
+ } ? () => R : never>;
132
+ /** @internal Build the GoalDef without finalizing. */
133
+ _buildDef(): GoalDef;
134
+ }
135
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../../../repos/sharpee/packages/character/src/goals/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,OAAO,EACR,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,WAAW,CAAC,OAAO;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAS;IAE/B;;;;;;OAMG;gBACS,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI;IAMzE;;;;;OAKG;IACH,aAAa,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC;IAK5D;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC;IAKtD;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC;IAK7C;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC;IAKhD;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC;IAKvD;;;;;OAKG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC;IAK5C;;;;;OAKG;IACH,aAAa,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC;IAK5D;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC;IAKpD;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAKpD;;;;OAIG;IACH,IAAI,IAAI,OAAO;IAKf;;;;;OAKG;IACH,OAAO,IAAI,UAAU,CAAC,OAAO,SAAS;QAAE,OAAO,IAAI,MAAM,CAAC,CAAA;KAAE,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC;IAK/E,sDAAsD;IACtD,SAAS,IAAI,OAAO;CAiBrB"}