@auxiora/personality 1.0.0 → 1.3.1

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 (182) hide show
  1. package/dist/__tests__/architect-awareness-collector.test.d.ts +2 -0
  2. package/dist/__tests__/architect-awareness-collector.test.d.ts.map +1 -0
  3. package/dist/__tests__/architect-awareness-collector.test.js +57 -0
  4. package/dist/__tests__/architect-awareness-collector.test.js.map +1 -0
  5. package/dist/__tests__/architect-bridge.test.d.ts +2 -0
  6. package/dist/__tests__/architect-bridge.test.d.ts.map +1 -0
  7. package/dist/__tests__/architect-bridge.test.js +59 -0
  8. package/dist/__tests__/architect-bridge.test.js.map +1 -0
  9. package/dist/__tests__/soul-bias-parser.test.d.ts +2 -0
  10. package/dist/__tests__/soul-bias-parser.test.d.ts.map +1 -0
  11. package/dist/__tests__/soul-bias-parser.test.js +47 -0
  12. package/dist/__tests__/soul-bias-parser.test.js.map +1 -0
  13. package/dist/architect-awareness-collector.d.ts +20 -0
  14. package/dist/architect-awareness-collector.d.ts.map +1 -0
  15. package/dist/architect-awareness-collector.js +41 -0
  16. package/dist/architect-awareness-collector.js.map +1 -0
  17. package/dist/architect-bridge.d.ts +35 -0
  18. package/dist/architect-bridge.d.ts.map +1 -0
  19. package/dist/architect-bridge.js +70 -0
  20. package/dist/architect-bridge.js.map +1 -0
  21. package/dist/index.d.ts +5 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/marketplace/schema.d.ts +6 -6
  26. package/dist/soul-bias-parser.d.ts +10 -0
  27. package/dist/soul-bias-parser.d.ts.map +1 -0
  28. package/dist/soul-bias-parser.js +48 -0
  29. package/dist/soul-bias-parser.js.map +1 -0
  30. package/lib/context-detector.d.ts +23 -0
  31. package/lib/context-detector.js +275 -0
  32. package/lib/context-profiles.d.ts +3 -0
  33. package/lib/context-profiles.js +550 -0
  34. package/lib/conversation-context.d.ts +70 -0
  35. package/lib/conversation-context.js +144 -0
  36. package/lib/conversation-export.d.ts +77 -0
  37. package/lib/conversation-export.js +254 -0
  38. package/lib/correction-store.d.ts +53 -0
  39. package/lib/correction-store.js +185 -0
  40. package/lib/custom-weights.d.ts +49 -0
  41. package/lib/custom-weights.js +181 -0
  42. package/lib/decision-log.d.ts +41 -0
  43. package/lib/decision-log.js +145 -0
  44. package/lib/emotional-overrides.d.ts +14 -0
  45. package/lib/emotional-overrides.js +86 -0
  46. package/lib/emotional-tracker.d.ts +41 -0
  47. package/lib/emotional-tracker.js +210 -0
  48. package/lib/feedback-store.d.ts +45 -0
  49. package/lib/feedback-store.js +152 -0
  50. package/lib/index.d.ts +204 -0
  51. package/lib/index.d.ts.map +1 -0
  52. package/lib/index.js +620 -0
  53. package/lib/index.js.map +1 -0
  54. package/lib/persistence-adapter.d.ts +55 -0
  55. package/lib/persistence-adapter.js +50 -0
  56. package/lib/persistence.d.ts +55 -0
  57. package/lib/persistence.js +123 -0
  58. package/lib/preference-history.d.ts +45 -0
  59. package/lib/preference-history.js +132 -0
  60. package/lib/prompt-assembler.d.ts +16 -0
  61. package/lib/prompt-assembler.js +66 -0
  62. package/lib/recommender.d.ts +25 -0
  63. package/lib/recommender.js +125 -0
  64. package/lib/schema.d.ts +177 -0
  65. package/lib/schema.d.ts.map +1 -0
  66. package/lib/schema.js +2 -0
  67. package/lib/schema.js.map +1 -0
  68. package/lib/source-map.d.ts +9 -0
  69. package/lib/source-map.js +223 -0
  70. package/lib/system-prompt.d.ts +2 -0
  71. package/lib/system-prompt.js +102 -0
  72. package/lib/the-architect/context-detector.d.ts +23 -0
  73. package/lib/the-architect/context-detector.d.ts.map +1 -0
  74. package/lib/the-architect/context-detector.js +275 -0
  75. package/lib/the-architect/context-detector.js.map +1 -0
  76. package/lib/the-architect/context-profiles.d.ts +3 -0
  77. package/lib/the-architect/context-profiles.d.ts.map +1 -0
  78. package/lib/the-architect/context-profiles.js +550 -0
  79. package/lib/the-architect/context-profiles.js.map +1 -0
  80. package/lib/the-architect/conversation-context.d.ts +70 -0
  81. package/lib/the-architect/conversation-context.js +144 -0
  82. package/lib/the-architect/conversation-context.js.map +1 -0
  83. package/lib/the-architect/conversation-export.d.ts +77 -0
  84. package/lib/the-architect/conversation-export.js +254 -0
  85. package/lib/the-architect/correction-store.d.ts +53 -0
  86. package/lib/the-architect/correction-store.d.ts.map +1 -0
  87. package/lib/the-architect/correction-store.js +185 -0
  88. package/lib/the-architect/correction-store.js.map +1 -0
  89. package/lib/the-architect/custom-weights.d.ts +49 -0
  90. package/lib/the-architect/custom-weights.js +181 -0
  91. package/lib/the-architect/decision-log.d.ts +41 -0
  92. package/lib/the-architect/decision-log.d.ts.map +1 -0
  93. package/lib/the-architect/decision-log.js +145 -0
  94. package/lib/the-architect/decision-log.js.map +1 -0
  95. package/lib/the-architect/emotional-overrides.d.ts +14 -0
  96. package/lib/the-architect/emotional-overrides.d.ts.map +1 -0
  97. package/lib/the-architect/emotional-overrides.js +86 -0
  98. package/lib/the-architect/emotional-overrides.js.map +1 -0
  99. package/lib/the-architect/emotional-tracker.d.ts +41 -0
  100. package/lib/the-architect/emotional-tracker.js +210 -0
  101. package/lib/the-architect/feedback-store.d.ts +45 -0
  102. package/lib/the-architect/feedback-store.d.ts.map +1 -0
  103. package/lib/the-architect/feedback-store.js +152 -0
  104. package/lib/the-architect/feedback-store.js.map +1 -0
  105. package/lib/the-architect/index.d.ts +199 -0
  106. package/lib/the-architect/index.d.ts.map +1 -0
  107. package/lib/the-architect/index.js +606 -0
  108. package/lib/the-architect/index.js.map +1 -0
  109. package/lib/the-architect/persistence-adapter.d.ts +55 -0
  110. package/lib/the-architect/persistence-adapter.js +50 -0
  111. package/lib/the-architect/persistence.d.ts +55 -0
  112. package/lib/the-architect/persistence.js +123 -0
  113. package/lib/the-architect/preference-history.d.ts +45 -0
  114. package/lib/the-architect/preference-history.d.ts.map +1 -0
  115. package/lib/the-architect/preference-history.js +132 -0
  116. package/lib/the-architect/preference-history.js.map +1 -0
  117. package/lib/the-architect/prompt-assembler.d.ts +16 -0
  118. package/lib/the-architect/prompt-assembler.d.ts.map +1 -0
  119. package/lib/the-architect/prompt-assembler.js +66 -0
  120. package/lib/the-architect/prompt-assembler.js.map +1 -0
  121. package/lib/the-architect/recommender.d.ts +25 -0
  122. package/lib/the-architect/recommender.js +125 -0
  123. package/lib/the-architect/source-map.d.ts +9 -0
  124. package/lib/the-architect/source-map.d.ts.map +1 -0
  125. package/lib/the-architect/source-map.js +223 -0
  126. package/lib/the-architect/source-map.js.map +1 -0
  127. package/lib/the-architect/system-prompt.d.ts +2 -0
  128. package/lib/the-architect/system-prompt.d.ts.map +1 -0
  129. package/lib/the-architect/system-prompt.js +102 -0
  130. package/lib/the-architect/system-prompt.js.map +1 -0
  131. package/lib/the-architect/trait-to-instruction.d.ts +12 -0
  132. package/lib/the-architect/trait-to-instruction.d.ts.map +1 -0
  133. package/lib/the-architect/trait-to-instruction.js +330 -0
  134. package/lib/the-architect/trait-to-instruction.js.map +1 -0
  135. package/lib/trait-to-instruction.d.ts +12 -0
  136. package/lib/trait-to-instruction.js +330 -0
  137. package/lib/user-model-synthesizer.d.ts +100 -0
  138. package/lib/user-model-synthesizer.js +224 -0
  139. package/package.json +15 -3
  140. package/modes/advisor.md +0 -24
  141. package/modes/analyst.md +0 -25
  142. package/modes/companion.md +0 -24
  143. package/modes/legal.md +0 -1188
  144. package/modes/operator.md +0 -24
  145. package/modes/roast.md +0 -24
  146. package/modes/socratic.md +0 -24
  147. package/modes/writer.md +0 -23
  148. package/src/__tests__/builder.test.ts +0 -78
  149. package/src/__tests__/conversation-builder.test.ts +0 -386
  150. package/src/__tests__/escalation.test.ts +0 -172
  151. package/src/__tests__/manager.test.ts +0 -141
  152. package/src/__tests__/parser.test.ts +0 -101
  153. package/src/__tests__/security-floor.test.ts +0 -212
  154. package/src/builder.ts +0 -75
  155. package/src/conversation-builder.ts +0 -279
  156. package/src/escalation.ts +0 -162
  157. package/src/index.ts +0 -55
  158. package/src/manager.ts +0 -119
  159. package/src/marketplace/__tests__/scanner.test.ts +0 -159
  160. package/src/marketplace/__tests__/schema.test.ts +0 -269
  161. package/src/marketplace/scanner.ts +0 -85
  162. package/src/marketplace/schema.ts +0 -141
  163. package/src/modes/__tests__/mode-detector.test.ts +0 -149
  164. package/src/modes/__tests__/mode-loader.test.ts +0 -143
  165. package/src/modes/__tests__/prompt-assembler.test.ts +0 -291
  166. package/src/modes/mode-detector.ts +0 -84
  167. package/src/modes/mode-loader.ts +0 -105
  168. package/src/modes/prompt-assembler.ts +0 -278
  169. package/src/modes/types.ts +0 -67
  170. package/src/parser.ts +0 -132
  171. package/src/security-floor.ts +0 -147
  172. package/src/types.ts +0 -27
  173. package/src/voice-profiles.ts +0 -88
  174. package/templates/chill.md +0 -30
  175. package/templates/creative.md +0 -29
  176. package/templates/friendly.md +0 -28
  177. package/templates/mentor.md +0 -31
  178. package/templates/minimal.md +0 -24
  179. package/templates/professional.md +0 -28
  180. package/templates/technical.md +0 -30
  181. package/tsconfig.json +0 -12
  182. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,185 @@
1
+ // ────────────────────────────────────────────────────────────────────────────
2
+ // Stopwords — common English words that carry no domain signal
3
+ // ────────────────────────────────────────────────────────────────────────────
4
+ const STOPWORDS = new Set([
5
+ 'this', 'that', 'with', 'from', 'have', 'been', 'were', 'they', 'them',
6
+ 'their', 'what', 'when', 'where', 'which', 'while', 'will', 'would',
7
+ 'could', 'should', 'about', 'after', 'again', 'also', 'because', 'before',
8
+ 'between', 'both', 'came', 'come', 'does', 'done', 'each', 'else', 'even',
9
+ 'every', 'good', 'great', 'here', 'into', 'just', 'know', 'like', 'long',
10
+ 'look', 'make', 'many', 'more', 'most', 'much', 'must', 'need', 'only',
11
+ 'other', 'over', 'same', 'some', 'such', 'take', 'tell', 'than', 'then',
12
+ 'there', 'these', 'thing', 'think', 'those', 'through', 'time', 'under',
13
+ 'upon', 'very', 'want', 'well', 'went', 'your', 'able', 'back', 'being',
14
+ 'call', 'case', 'down', 'find', 'first', 'give', 'going', 'hand', 'help',
15
+ 'high', 'keep', 'last', 'left', 'life', 'line', 'made', 'might', 'move',
16
+ 'name', 'next', 'open', 'part', 'place', 'point', 'right', 'show', 'side',
17
+ 'since', 'small', 'start', 'still', 'turn', 'used', 'using', 'work',
18
+ 'world', 'year', 'away', 'best', 'came', 'dear', 'didn', 'don', 'end',
19
+ 'enough', 'ever', 'far', 'few', 'get', 'got', 'had', 'has', 'her', 'him',
20
+ 'his', 'how', 'its', 'let', 'may', 'new', 'now', 'off', 'old', 'one',
21
+ 'our', 'out', 'own', 'put', 'ran', 'run', 'say', 'she', 'too', 'try',
22
+ 'two', 'use', 'way', 'who', 'why', 'big', 'can', 'day', 'did', 'for',
23
+ 'got', 'him', 'not', 'the', 'and', 'are', 'but',
24
+ ]);
25
+ // ────────────────────────────────────────────────────────────────────────────
26
+ // Helpers
27
+ // ────────────────────────────────────────────────────────────────────────────
28
+ /** Extract meaningful keywords from a message. */
29
+ function extractKeywords(message) {
30
+ return message
31
+ .toLowerCase()
32
+ .split(/\s+/)
33
+ .map(w => w.replace(/[^a-z0-9]/g, ''))
34
+ .filter(w => w.length > 3 && !STOPWORDS.has(w));
35
+ }
36
+ /** Generate a v4-style UUID without crypto dependency. */
37
+ function generateId() {
38
+ const hex = '0123456789abcdef';
39
+ const segments = [8, 4, 4, 4, 12];
40
+ return segments.map(len => {
41
+ let s = '';
42
+ for (let i = 0; i < len; i++) {
43
+ s += hex[Math.floor(Math.random() * 16)];
44
+ }
45
+ return s;
46
+ }).join('-');
47
+ }
48
+ // ────────────────────────────────────────────────────────────────────────────
49
+ // CorrectionStore
50
+ // ────────────────────────────────────────────────────────────────────────────
51
+ export class CorrectionStore {
52
+ corrections = [];
53
+ patterns = [];
54
+ /** Record a new correction. Generates id/timestamp and extracts keywords. */
55
+ addCorrection(correction) {
56
+ this.corrections.push({
57
+ ...correction,
58
+ id: generateId(),
59
+ timestamp: Date.now(),
60
+ keywords: extractKeywords(correction.userMessage),
61
+ });
62
+ this.recomputePatterns();
63
+ }
64
+ /** Get all stored corrections. */
65
+ getCorrections() {
66
+ return this.corrections;
67
+ }
68
+ /** Get correction patterns sorted by confidence descending. */
69
+ getPatterns() {
70
+ return [...this.patterns].sort((a, b) => b.confidence - a.confidence);
71
+ }
72
+ /**
73
+ * Given a message and detected domain, check if corrections suggest a
74
+ * different domain. Returns the corrected domain if pattern confidence
75
+ * > 0.6 and occurrences >= 3, else null.
76
+ */
77
+ suggestCorrection(message, detectedDomain) {
78
+ const messageKeywords = extractKeywords(message);
79
+ if (messageKeywords.length === 0)
80
+ return null;
81
+ // Find matching patterns: keyword present in message, fromDomain matches
82
+ const matches = this.patterns.filter(p => p.fromDomain === detectedDomain &&
83
+ p.confidence > 0.6 &&
84
+ p.occurrences >= 3 &&
85
+ messageKeywords.includes(p.keyword));
86
+ if (matches.length === 0)
87
+ return null;
88
+ // Pick the match with highest confidence; break ties with occurrences
89
+ matches.sort((a, b) => b.confidence - a.confidence || b.occurrences - a.occurrences);
90
+ return matches[0].toDomain;
91
+ }
92
+ /** Recompute patterns from all stored corrections. */
93
+ recomputePatterns() {
94
+ // Count how many corrections contain each keyword (for confidence denominator)
95
+ const keywordTotals = new Map();
96
+ for (const c of this.corrections) {
97
+ const seen = new Set(c.keywords);
98
+ for (const kw of seen) {
99
+ keywordTotals.set(kw, (keywordTotals.get(kw) ?? 0) + 1);
100
+ }
101
+ }
102
+ // Group by (keyword, fromDomain, toDomain) and count occurrences
103
+ const groups = new Map();
104
+ for (const c of this.corrections) {
105
+ const seen = new Set(c.keywords);
106
+ for (const kw of seen) {
107
+ const key = `${kw}|${c.detectedDomain}|${c.correctedDomain}`;
108
+ const existing = groups.get(key);
109
+ if (existing) {
110
+ existing.occurrences++;
111
+ }
112
+ else {
113
+ groups.set(key, {
114
+ keyword: kw,
115
+ fromDomain: c.detectedDomain,
116
+ toDomain: c.correctedDomain,
117
+ occurrences: 1,
118
+ });
119
+ }
120
+ }
121
+ }
122
+ this.patterns = [];
123
+ for (const g of groups.values()) {
124
+ const total = keywordTotals.get(g.keyword) ?? 1;
125
+ this.patterns.push({
126
+ ...g,
127
+ confidence: g.occurrences / total,
128
+ });
129
+ }
130
+ }
131
+ /** Serialize for encrypted storage. */
132
+ serialize() {
133
+ return JSON.stringify({
134
+ corrections: this.corrections,
135
+ patterns: this.patterns,
136
+ });
137
+ }
138
+ /** Deserialize from encrypted storage. */
139
+ static deserialize(data) {
140
+ const store = new CorrectionStore();
141
+ const parsed = JSON.parse(data);
142
+ store.corrections = parsed.corrections;
143
+ store.patterns = parsed.patterns;
144
+ return store;
145
+ }
146
+ /** Clear all corrections (user data deletion). */
147
+ clear() {
148
+ this.corrections = [];
149
+ this.patterns = [];
150
+ }
151
+ /** Stats for debugging. */
152
+ getStats() {
153
+ const pairCounts = new Map();
154
+ const domainDetected = new Map();
155
+ const domainCorrected = new Map();
156
+ for (const c of this.corrections) {
157
+ // Count pair
158
+ const key = `${c.detectedDomain}→${c.correctedDomain}`;
159
+ const existing = pairCounts.get(key);
160
+ if (existing) {
161
+ existing.count++;
162
+ }
163
+ else {
164
+ pairCounts.set(key, { from: c.detectedDomain, to: c.correctedDomain, count: 1 });
165
+ }
166
+ // Count detected and corrected per domain
167
+ domainDetected.set(c.detectedDomain, (domainDetected.get(c.detectedDomain) ?? 0) + 1);
168
+ domainCorrected.set(c.detectedDomain, (domainCorrected.get(c.detectedDomain) ?? 0) + 1);
169
+ }
170
+ const topMisclassifications = [...pairCounts.values()]
171
+ .sort((a, b) => b.count - a.count);
172
+ // correctionRate = corrections for domain / total times that domain was detected
173
+ const correctionRate = {};
174
+ for (const [domain, correctedCount] of domainCorrected) {
175
+ const detectedCount = domainDetected.get(domain) ?? 1;
176
+ correctionRate[domain] = correctedCount / detectedCount;
177
+ }
178
+ return {
179
+ totalCorrections: this.corrections.length,
180
+ topMisclassifications,
181
+ correctionRate,
182
+ };
183
+ }
184
+ }
185
+ //# sourceMappingURL=correction-store.js.map
@@ -0,0 +1,49 @@
1
+ import type { TraitMix, ContextDomain } from '../schema.js';
2
+ import type { PreferenceHistory } from './preference-history.js';
3
+ export interface WeightPreset {
4
+ name: string;
5
+ description: string;
6
+ overrides: Partial<Record<keyof TraitMix, number>>;
7
+ }
8
+ export declare const WEIGHT_PRESETS: Record<string, WeightPreset>;
9
+ /**
10
+ * User-defined trait weight adjustments. These are ADDITIVE offsets applied
11
+ * after context profiles and emotional overrides, allowing users to
12
+ * permanently nudge the personality toward their preferences.
13
+ *
14
+ * Offsets are clamped to [-0.3, +0.3] — enough to meaningfully shift
15
+ * behavior without fully overriding the context profile.
16
+ */
17
+ export declare class CustomWeights {
18
+ private overrides;
19
+ /**
20
+ * Set a custom weight offset for a trait.
21
+ * Clamps to [-0.3, +0.3]. Throws if the trait key is invalid.
22
+ */
23
+ setOverride(trait: keyof TraitMix, offset: number): void;
24
+ /** Remove a custom override for a single trait. */
25
+ removeOverride(trait: keyof TraitMix): void;
26
+ /** Get all current overrides. Returns a shallow copy. */
27
+ getOverrides(): Partial<Record<keyof TraitMix, number>>;
28
+ /**
29
+ * Apply overrides to a trait mix. For each override, adds the offset
30
+ * and clamps the result to [0.0, 1.0].
31
+ */
32
+ apply(baseMix: TraitMix): TraitMix;
33
+ /**
34
+ * Apply overrides using history-resolved offsets instead of raw last-write values.
35
+ * Falls back to standard apply() when no history entries exist for a trait.
36
+ */
37
+ applyWithHistory(baseMix: TraitMix, currentDomain: ContextDomain | undefined, history: PreferenceHistory): TraitMix;
38
+ /** All available presets. */
39
+ static get presets(): Record<string, WeightPreset>;
40
+ /** Load a preset, replacing all current overrides. Throws if preset not found. */
41
+ loadPreset(presetName: string): void;
42
+ /** Serialize overrides to JSON string for persistence. */
43
+ serialize(): string;
44
+ /** Deserialize a CustomWeights instance from a JSON string. */
45
+ static deserialize(data: string): CustomWeights;
46
+ /** Clear all overrides. */
47
+ clear(): void;
48
+ }
49
+ //# sourceMappingURL=custom-weights.d.ts.map
@@ -0,0 +1,181 @@
1
+ // ────────────────────────────────────────────────────────────────────────────
2
+ // Constants
3
+ // ────────────────────────────────────────────────────────────────────────────
4
+ /** Maximum absolute offset a user can apply to any trait. */
5
+ const MAX_OFFSET = 0.3;
6
+ /** All valid trait keys from TraitMix. */
7
+ const VALID_TRAITS = new Set([
8
+ 'inversion', 'firstPrinciples', 'mentalSimulation', 'adversarialThinking',
9
+ 'secondOrder', 'systemsView', 'simplification', 'storytelling',
10
+ 'tacticalEmpathy', 'genuineCuriosity', 'radicalCandor', 'standardSetting',
11
+ 'developmentalCoaching', 'strategicGenerosity', 'stoicCalm', 'paranoidVigilance',
12
+ 'valueEquation', 'ooda', 'buildForChange', 'humanCenteredDesign',
13
+ 'constraintCreativity', 'regretMinimization', 'doorClassification',
14
+ 'probabilistic', 'plannedAbandonment', 'warmth', 'urgency', 'humor', 'verbosity',
15
+ ]);
16
+ // ────────────────────────────────────────────────────────────────────────────
17
+ // Presets
18
+ // ────────────────────────────────────────────────────────────────────────────
19
+ export const WEIGHT_PRESETS = {
20
+ the_ciso: {
21
+ name: 'The CISO',
22
+ description: 'Extra paranoia, adversarial thinking, and rigor. For security-focused work.',
23
+ overrides: {
24
+ adversarialThinking: +0.2,
25
+ paranoidVigilance: +0.2,
26
+ inversion: +0.15,
27
+ systemsView: +0.1,
28
+ humor: -0.15,
29
+ warmth: -0.1,
30
+ },
31
+ },
32
+ the_builder: {
33
+ name: 'The Builder',
34
+ description: 'Bias toward action, simplicity, and shipping. Less analysis, more execution.',
35
+ overrides: {
36
+ valueEquation: +0.2,
37
+ ooda: +0.2,
38
+ buildForChange: +0.15,
39
+ constraintCreativity: +0.15,
40
+ secondOrder: -0.1,
41
+ verbosity: -0.15,
42
+ },
43
+ },
44
+ the_coach: {
45
+ name: 'The Coach',
46
+ description: 'Extra empathy, patience, and developmental focus. For leadership and mentoring.',
47
+ overrides: {
48
+ tacticalEmpathy: +0.2,
49
+ developmentalCoaching: +0.2,
50
+ genuineCuriosity: +0.15,
51
+ warmth: +0.2,
52
+ radicalCandor: +0.1,
53
+ urgency: -0.2,
54
+ adversarialThinking: -0.15,
55
+ },
56
+ },
57
+ the_strategist: {
58
+ name: 'The Strategist',
59
+ description: 'Deep second-order thinking, inversion, and long-term framing.',
60
+ overrides: {
61
+ inversion: +0.2,
62
+ secondOrder: +0.2,
63
+ probabilistic: +0.15,
64
+ doorClassification: +0.15,
65
+ plannedAbandonment: +0.1,
66
+ verbosity: +0.15,
67
+ ooda: -0.1,
68
+ humor: -0.1,
69
+ },
70
+ },
71
+ the_closer: {
72
+ name: 'The Closer',
73
+ description: 'Sales-focused energy. Value equations, storytelling, urgency.',
74
+ overrides: {
75
+ valueEquation: +0.25,
76
+ storytelling: +0.2,
77
+ simplification: +0.15,
78
+ urgency: +0.15,
79
+ humor: +0.1,
80
+ stoicCalm: -0.1,
81
+ adversarialThinking: -0.15,
82
+ },
83
+ },
84
+ };
85
+ // ────────────────────────────────────────────────────────────────────────────
86
+ // CustomWeights
87
+ // ────────────────────────────────────────────────────────────────────────────
88
+ /**
89
+ * User-defined trait weight adjustments. These are ADDITIVE offsets applied
90
+ * after context profiles and emotional overrides, allowing users to
91
+ * permanently nudge the personality toward their preferences.
92
+ *
93
+ * Offsets are clamped to [-0.3, +0.3] — enough to meaningfully shift
94
+ * behavior without fully overriding the context profile.
95
+ */
96
+ export class CustomWeights {
97
+ overrides = {};
98
+ // ── Set / Remove ────────────────────────────────────────────────────────
99
+ /**
100
+ * Set a custom weight offset for a trait.
101
+ * Clamps to [-0.3, +0.3]. Throws if the trait key is invalid.
102
+ */
103
+ setOverride(trait, offset) {
104
+ if (!VALID_TRAITS.has(trait)) {
105
+ throw new Error(`Invalid trait key: ${trait}`);
106
+ }
107
+ this.overrides[trait] = Math.min(MAX_OFFSET, Math.max(-MAX_OFFSET, offset));
108
+ }
109
+ /** Remove a custom override for a single trait. */
110
+ removeOverride(trait) {
111
+ delete this.overrides[trait];
112
+ }
113
+ /** Get all current overrides. Returns a shallow copy. */
114
+ getOverrides() {
115
+ return { ...this.overrides };
116
+ }
117
+ // ── Application ─────────────────────────────────────────────────────────
118
+ /**
119
+ * Apply overrides to a trait mix. For each override, adds the offset
120
+ * and clamps the result to [0.0, 1.0].
121
+ */
122
+ apply(baseMix) {
123
+ const result = { ...baseMix };
124
+ for (const [trait, offset] of Object.entries(this.overrides)) {
125
+ result[trait] = Math.min(1.0, Math.max(0.0, result[trait] + offset));
126
+ }
127
+ return result;
128
+ }
129
+ /**
130
+ * Apply overrides using history-resolved offsets instead of raw last-write values.
131
+ * Falls back to standard apply() when no history entries exist for a trait.
132
+ */
133
+ applyWithHistory(baseMix, currentDomain, history) {
134
+ const result = { ...baseMix };
135
+ const rawOverrides = this.overrides;
136
+ // Collect all traits that have either raw overrides or history entries
137
+ const traits = new Set(Object.keys(rawOverrides));
138
+ for (const trait of traits) {
139
+ const historyOffset = history.getEffectiveOffset(trait, currentDomain ?? undefined);
140
+ // Use history-resolved offset if history has entries for this trait, otherwise fall back to raw
141
+ const offset = historyOffset !== 0 ? historyOffset : (rawOverrides[trait] ?? 0);
142
+ result[trait] = Math.min(1.0, Math.max(0.0, result[trait] + offset));
143
+ }
144
+ return result;
145
+ }
146
+ // ── Presets ─────────────────────────────────────────────────────────────
147
+ /** All available presets. */
148
+ static get presets() {
149
+ return WEIGHT_PRESETS;
150
+ }
151
+ /** Load a preset, replacing all current overrides. Throws if preset not found. */
152
+ loadPreset(presetName) {
153
+ const preset = WEIGHT_PRESETS[presetName];
154
+ if (!preset) {
155
+ throw new Error(`Unknown preset: ${presetName}. Available: ${Object.keys(WEIGHT_PRESETS).join(', ')}`);
156
+ }
157
+ this.overrides = { ...preset.overrides };
158
+ }
159
+ // ── Serialization ───────────────────────────────────────────────────────
160
+ /** Serialize overrides to JSON string for persistence. */
161
+ serialize() {
162
+ return JSON.stringify(this.overrides);
163
+ }
164
+ /** Deserialize a CustomWeights instance from a JSON string. */
165
+ static deserialize(data) {
166
+ const instance = new CustomWeights();
167
+ const parsed = JSON.parse(data);
168
+ for (const [trait, offset] of Object.entries(parsed)) {
169
+ if (VALID_TRAITS.has(trait) && typeof offset === 'number') {
170
+ instance.overrides[trait] = Math.min(MAX_OFFSET, Math.max(-MAX_OFFSET, offset));
171
+ }
172
+ }
173
+ return instance;
174
+ }
175
+ // ── Lifecycle ───────────────────────────────────────────────────────────
176
+ /** Clear all overrides. */
177
+ clear() {
178
+ this.overrides = {};
179
+ }
180
+ }
181
+ //# sourceMappingURL=custom-weights.js.map
@@ -0,0 +1,41 @@
1
+ import type { ContextDomain } from '../schema.js';
2
+ export type DecisionStatus = 'active' | 'revisit' | 'completed' | 'abandoned';
3
+ export interface Decision {
4
+ id: string;
5
+ timestamp: number;
6
+ domain: ContextDomain;
7
+ summary: string;
8
+ context: string;
9
+ status: DecisionStatus;
10
+ followUpDate?: number;
11
+ outcome?: string;
12
+ tags: string[];
13
+ }
14
+ export interface DecisionQuery {
15
+ domain?: ContextDomain;
16
+ status?: DecisionStatus;
17
+ since?: number;
18
+ search?: string;
19
+ limit?: number;
20
+ }
21
+ export declare class DecisionLog {
22
+ private decisions;
23
+ private maxDecisions;
24
+ /** Record a new decision. Auto-generates id, timestamp, and tags. */
25
+ addDecision(decision: Omit<Decision, 'id' | 'timestamp' | 'tags'>): Decision;
26
+ /** Update an existing decision's status or outcome. */
27
+ updateDecision(id: string, updates: Partial<Pick<Decision, 'status' | 'outcome' | 'followUpDate'>>): void;
28
+ /** Query decisions with filters. All filters are AND-combined. */
29
+ query(q: DecisionQuery): Decision[];
30
+ /** Get decisions due for follow-up (followUpDate <= now). */
31
+ getDueFollowUps(): Decision[];
32
+ /** Get recent decisions for a domain (for context in new conversations). */
33
+ getRecentForDomain(domain: ContextDomain, limit?: number): Decision[];
34
+ /** Serialize for encrypted storage. */
35
+ serialize(): string;
36
+ /** Deserialize from encrypted storage. */
37
+ static deserialize(data: string): DecisionLog;
38
+ /** Clear all decisions (user data deletion). */
39
+ clear(): void;
40
+ }
41
+ //# sourceMappingURL=decision-log.d.ts.map
@@ -0,0 +1,145 @@
1
+ // ────────────────────────────────────────────────────────────────────────────
2
+ // Stopwords — common English words filtered from tag extraction
3
+ // ────────────────────────────────────────────────────────────────────────────
4
+ const STOPWORDS = new Set([
5
+ 'this', 'that', 'with', 'from', 'have', 'been', 'were', 'they', 'them',
6
+ 'their', 'what', 'when', 'where', 'which', 'while', 'will', 'would',
7
+ 'could', 'should', 'about', 'after', 'again', 'also', 'because', 'before',
8
+ 'between', 'both', 'came', 'come', 'does', 'done', 'each', 'else', 'even',
9
+ 'every', 'good', 'great', 'here', 'into', 'just', 'know', 'like', 'long',
10
+ 'look', 'make', 'many', 'more', 'most', 'much', 'must', 'need', 'only',
11
+ 'other', 'over', 'same', 'some', 'such', 'take', 'tell', 'than', 'then',
12
+ 'there', 'these', 'thing', 'think', 'those', 'through', 'time', 'under',
13
+ 'upon', 'very', 'want', 'well', 'went', 'your', 'able', 'back', 'being',
14
+ 'call', 'case', 'down', 'find', 'first', 'give', 'going', 'hand', 'help',
15
+ 'high', 'keep', 'last', 'left', 'life', 'line', 'made', 'might', 'move',
16
+ 'name', 'next', 'open', 'part', 'place', 'point', 'right', 'show', 'side',
17
+ 'since', 'small', 'start', 'still', 'turn', 'used', 'using', 'work',
18
+ 'world', 'year', 'away', 'best', 'came', 'dear', 'didn', 'don', 'end',
19
+ 'enough', 'ever', 'far', 'few', 'get', 'got', 'had', 'has', 'her', 'him',
20
+ 'his', 'how', 'its', 'let', 'may', 'new', 'now', 'off', 'old', 'one',
21
+ 'our', 'out', 'own', 'put', 'ran', 'run', 'say', 'she', 'too', 'try',
22
+ 'two', 'use', 'way', 'who', 'why', 'big', 'can', 'day', 'did', 'for',
23
+ 'got', 'him', 'not', 'the', 'and', 'are', 'but',
24
+ ]);
25
+ // ────────────────────────────────────────────────────────────────────────────
26
+ // Helpers
27
+ // ────────────────────────────────────────────────────────────────────────────
28
+ /** Extract meaningful keyword tags from text. */
29
+ function extractTags(text) {
30
+ const words = text
31
+ .toLowerCase()
32
+ .split(/\s+/)
33
+ .map(w => w.replace(/[^a-z0-9]/g, ''))
34
+ .filter(w => w.length >= 4 && !STOPWORDS.has(w));
35
+ // Deduplicate while preserving order
36
+ return [...new Set(words)];
37
+ }
38
+ /** Generate a v4-style UUID without crypto dependency. */
39
+ function generateId() {
40
+ const hex = '0123456789abcdef';
41
+ const segments = [8, 4, 4, 4, 12];
42
+ return segments.map(len => {
43
+ let s = '';
44
+ for (let i = 0; i < len; i++) {
45
+ s += hex[Math.floor(Math.random() * 16)];
46
+ }
47
+ return s;
48
+ }).join('-');
49
+ }
50
+ // ────────────────────────────────────────────────────────────────────────────
51
+ // DecisionLog
52
+ // ────────────────────────────────────────────────────────────────────────────
53
+ export class DecisionLog {
54
+ decisions = [];
55
+ maxDecisions = 500;
56
+ /** Record a new decision. Auto-generates id, timestamp, and tags. */
57
+ addDecision(decision) {
58
+ const entry = {
59
+ ...decision,
60
+ id: generateId(),
61
+ timestamp: Date.now(),
62
+ tags: extractTags(`${decision.summary} ${decision.context}`),
63
+ };
64
+ this.decisions.push(entry);
65
+ // Enforce capacity — drop oldest when over limit
66
+ if (this.decisions.length > this.maxDecisions) {
67
+ this.decisions = this.decisions.slice(this.decisions.length - this.maxDecisions);
68
+ }
69
+ return entry;
70
+ }
71
+ /** Update an existing decision's status or outcome. */
72
+ updateDecision(id, updates) {
73
+ const decision = this.decisions.find(d => d.id === id);
74
+ if (!decision) {
75
+ throw new Error(`Decision not found: ${id}`);
76
+ }
77
+ if (updates.status !== undefined)
78
+ decision.status = updates.status;
79
+ if (updates.outcome !== undefined)
80
+ decision.outcome = updates.outcome;
81
+ if (updates.followUpDate !== undefined)
82
+ decision.followUpDate = updates.followUpDate;
83
+ }
84
+ /** Query decisions with filters. All filters are AND-combined. */
85
+ query(q) {
86
+ let results = this.decisions.filter(d => {
87
+ if (q.domain !== undefined && d.domain !== q.domain)
88
+ return false;
89
+ if (q.status !== undefined && d.status !== q.status)
90
+ return false;
91
+ if (q.since !== undefined && d.timestamp < q.since)
92
+ return false;
93
+ if (q.search !== undefined) {
94
+ const needle = q.search.toLowerCase();
95
+ const haystack = `${d.summary} ${d.context} ${d.tags.join(' ')}`.toLowerCase();
96
+ if (!haystack.includes(needle))
97
+ return false;
98
+ }
99
+ return true;
100
+ });
101
+ // Sort by timestamp descending (most recent first)
102
+ results.sort((a, b) => b.timestamp - a.timestamp);
103
+ if (q.limit !== undefined && q.limit > 0) {
104
+ results = results.slice(0, q.limit);
105
+ }
106
+ return results;
107
+ }
108
+ /** Get decisions due for follow-up (followUpDate <= now). */
109
+ getDueFollowUps() {
110
+ const now = Date.now();
111
+ return this.decisions
112
+ .filter(d => d.followUpDate !== undefined && d.followUpDate <= now)
113
+ .sort((a, b) => b.timestamp - a.timestamp);
114
+ }
115
+ /** Get recent decisions for a domain (for context in new conversations). */
116
+ getRecentForDomain(domain, limit = 10) {
117
+ return this.decisions
118
+ .filter(d => d.domain === domain)
119
+ .sort((a, b) => b.timestamp - a.timestamp)
120
+ .slice(0, limit);
121
+ }
122
+ /** Serialize for encrypted storage. */
123
+ serialize() {
124
+ return JSON.stringify({ decisions: this.decisions });
125
+ }
126
+ /** Deserialize from encrypted storage. */
127
+ static deserialize(data) {
128
+ const log = new DecisionLog();
129
+ try {
130
+ const parsed = JSON.parse(data);
131
+ if (Array.isArray(parsed.decisions)) {
132
+ log.decisions = parsed.decisions;
133
+ }
134
+ }
135
+ catch {
136
+ // Corrupt data — return empty log
137
+ }
138
+ return log;
139
+ }
140
+ /** Clear all decisions (user data deletion). */
141
+ clear() {
142
+ this.decisions = [];
143
+ }
144
+ }
145
+ //# sourceMappingURL=decision-log.js.map
@@ -0,0 +1,14 @@
1
+ import type { TraitMix, EmotionalRegister } from '../schema.js';
2
+ /**
3
+ * Multipliers applied on top of the context profile's base trait values.
4
+ * Values > 1.0 amplify a trait; values < 1.0 dampen it.
5
+ * After multiplication, all traits are capped at 1.0 by `applyEmotionalOverride`.
6
+ */
7
+ export declare const EMOTIONAL_OVERRIDES: Record<EmotionalRegister, Partial<Record<keyof TraitMix, number>>>;
8
+ /**
9
+ * Applies emotional multipliers to a base trait mix, producing a new TraitMix
10
+ * where each trait is multiplied by its override value (defaulting to 1.0)
11
+ * and capped at 1.0.
12
+ */
13
+ export declare function applyEmotionalOverride(baseMix: TraitMix, emotion: EmotionalRegister): TraitMix;
14
+ //# sourceMappingURL=emotional-overrides.d.ts.map