@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,144 @@
1
+ // ────────────────────────────────────────────────────────────────────────────
2
+ // Constants
3
+ // ────────────────────────────────────────────────────────────────────────────
4
+ /** Number of consecutive same-domain detections required to establish a theme. */
5
+ const THEME_LOCK_THRESHOLD = 3;
6
+ /** Confidence threshold for a new domain to override an existing theme. */
7
+ const THEME_OVERRIDE_CONFIDENCE = 0.7;
8
+ /** Crisis always takes over — no theme can suppress it. */
9
+ const CRISIS_DOMAIN = 'crisis_management';
10
+ // ────────────────────────────────────────────────────────────────────────────
11
+ // ConversationContext
12
+ // ────────────────────────────────────────────────────────────────────────────
13
+ /**
14
+ * Maintains context awareness across a full conversation, not just per-message.
15
+ *
16
+ * If the conversation is about security architecture, a brief tangent about
17
+ * lunch shouldn't reset the context to "general." The class tracks a
18
+ * conversation *theme* that locks after 3+ consistent detections and only
19
+ * shifts when a new domain arrives with high confidence.
20
+ *
21
+ * CRITICAL: Crisis context (`crisis_management`) ALWAYS overrides the
22
+ * conversation theme. If the user suddenly says "we just got breached,"
23
+ * crisis takes over immediately regardless of theme.
24
+ */
25
+ export class ConversationContext {
26
+ history = [];
27
+ dominantDomain = 'general';
28
+ domainStreak = 0;
29
+ conversationTheme = null;
30
+ // ── Recording ───────────────────────────────────────────────────────────
31
+ /**
32
+ * Record a new context detection. Updates streak tracking and may
33
+ * auto-establish a conversation theme after enough consistent detections.
34
+ */
35
+ recordDetection(message, domain, confidence) {
36
+ this.history.push({
37
+ message,
38
+ domain,
39
+ confidence,
40
+ timestamp: Date.now(),
41
+ });
42
+ // Update streak tracking
43
+ if (domain === this.dominantDomain) {
44
+ this.domainStreak++;
45
+ }
46
+ else {
47
+ this.dominantDomain = domain;
48
+ this.domainStreak = 1;
49
+ }
50
+ // Auto-establish theme after THEME_LOCK_THRESHOLD consecutive detections
51
+ if (this.conversationTheme === null &&
52
+ this.domainStreak >= THEME_LOCK_THRESHOLD &&
53
+ this.dominantDomain !== 'general') {
54
+ this.conversationTheme = this.dominantDomain;
55
+ }
56
+ }
57
+ // ── Effective domain ────────────────────────────────────────────────────
58
+ /**
59
+ * Get the effective domain considering conversation history.
60
+ *
61
+ * Rules:
62
+ * 1. Crisis ALWAYS wins — bypasses any theme.
63
+ * 2. If a theme is set and the new detection is 'general' or low confidence,
64
+ * return the theme (the tangent doesn't break it).
65
+ * 3. If a theme is set and the new detection is a DIFFERENT specific domain
66
+ * with high confidence (> 0.7), update the theme to the new domain.
67
+ * 4. If no theme is set, return the raw detection unchanged.
68
+ */
69
+ getEffectiveDomain(currentDetection, currentConfidence) {
70
+ // Rule 1: Crisis always overrides
71
+ if (currentDetection === CRISIS_DOMAIN) {
72
+ this.conversationTheme = CRISIS_DOMAIN;
73
+ return CRISIS_DOMAIN;
74
+ }
75
+ // No theme → raw detection
76
+ if (this.conversationTheme === null) {
77
+ return currentDetection;
78
+ }
79
+ // Theme is set — evaluate the new detection
80
+ if (currentDetection === 'general' || currentConfidence < THEME_OVERRIDE_CONFIDENCE) {
81
+ // Low-signal message: theme holds
82
+ return this.conversationTheme;
83
+ }
84
+ if (currentDetection !== this.conversationTheme) {
85
+ // High-confidence different domain: shift the theme
86
+ this.conversationTheme = currentDetection;
87
+ }
88
+ return this.conversationTheme;
89
+ }
90
+ // ── Manual control ──────────────────────────────────────────────────────
91
+ /** Explicitly set conversation theme (user override). */
92
+ setTheme(domain) {
93
+ this.conversationTheme = domain;
94
+ }
95
+ /** Clear theme — returns to pure auto-detection. */
96
+ clearTheme() {
97
+ this.conversationTheme = null;
98
+ }
99
+ // ── Introspection ──────────────────────────────────────────────────────
100
+ /** Get conversation summary with theme, distribution, and streak info. */
101
+ getSummary() {
102
+ const distribution = {};
103
+ for (const record of this.history) {
104
+ distribution[record.domain] = (distribution[record.domain] ?? 0) + 1;
105
+ }
106
+ return {
107
+ theme: this.conversationTheme,
108
+ messageCount: this.history.length,
109
+ domainDistribution: distribution,
110
+ currentStreak: {
111
+ domain: this.dominantDomain,
112
+ count: this.domainStreak,
113
+ },
114
+ };
115
+ }
116
+ // ── Lifecycle ──────────────────────────────────────────────────────────
117
+ /** Reset for a new conversation — clears all state. */
118
+ reset() {
119
+ this.history = [];
120
+ this.dominantDomain = 'general';
121
+ this.domainStreak = 0;
122
+ this.conversationTheme = null;
123
+ }
124
+ // ── Persistence ──────────────────────────────────────────────────────
125
+ /** Serialize state for vault persistence. Caps history at 50 records. */
126
+ serialize() {
127
+ return {
128
+ theme: this.conversationTheme,
129
+ dominantDomain: this.dominantDomain,
130
+ domainStreak: this.domainStreak,
131
+ history: this.history.slice(-50),
132
+ };
133
+ }
134
+ /** Restore a ConversationContext from previously serialized state. */
135
+ static restore(state) {
136
+ const ctx = new ConversationContext();
137
+ ctx.conversationTheme = state.theme;
138
+ ctx.dominantDomain = state.dominantDomain;
139
+ ctx.domainStreak = state.domainStreak;
140
+ ctx.history = [...state.history];
141
+ return ctx;
142
+ }
143
+ }
144
+ //# sourceMappingURL=conversation-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-context.js","sourceRoot":"","sources":["conversation-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { ContextDomain, EmotionalRegister, TraitSource } from '../schema.js';
2
+ import type { EmotionalTrajectory } from './emotional-tracker.js';
3
+ import type { ContextRecommendation } from './recommender.js';
4
+ export interface ChatMessage {
5
+ role: 'user' | 'assistant';
6
+ content: string;
7
+ timestamp: number;
8
+ /** Personality engine output attached to assistant messages. */
9
+ metadata?: AssistantMetadata;
10
+ }
11
+ export interface AssistantMetadata {
12
+ domain: ContextDomain;
13
+ emotionalRegister: EmotionalRegister;
14
+ emotionalTrajectory?: EmotionalTrajectory;
15
+ conversationTheme?: ContextDomain;
16
+ corrected?: boolean;
17
+ originalDomain?: ContextDomain;
18
+ confidence?: number;
19
+ stakes: string;
20
+ complexity: string;
21
+ activeTraits: TraitSource[];
22
+ customWeightsApplied?: Partial<Record<string, number>>;
23
+ recommendation?: ContextRecommendation;
24
+ }
25
+ export interface ExportedMessage {
26
+ role: 'user' | 'assistant';
27
+ content: string;
28
+ timestamp: number;
29
+ context?: {
30
+ domain: ContextDomain;
31
+ emotionalRegister: EmotionalRegister;
32
+ emotionalTrajectory?: EmotionalTrajectory;
33
+ conversationTheme?: ContextDomain;
34
+ corrected?: boolean;
35
+ originalDomain?: ContextDomain;
36
+ confidence?: number;
37
+ stakes: string;
38
+ complexity: string;
39
+ };
40
+ activeTraits?: Array<{
41
+ traitName: string;
42
+ weight: number;
43
+ sourceName: string;
44
+ }>;
45
+ customWeightsApplied?: Partial<Record<string, number>>;
46
+ recommendation?: ContextRecommendation;
47
+ }
48
+ export interface ExportedConversation {
49
+ id: string;
50
+ title: string;
51
+ exportedAt: number;
52
+ messageCount: number;
53
+ messages: ExportedMessage[];
54
+ summary: {
55
+ dominantContexts: Array<{
56
+ domain: ContextDomain;
57
+ percentage: number;
58
+ }>;
59
+ emotionalArc: EmotionalRegister[];
60
+ correctionsApplied: number;
61
+ uniqueSourcesReferenced: string[];
62
+ };
63
+ }
64
+ export declare class ConversationExporter {
65
+ /**
66
+ * Build an export from conversation messages with their metadata.
67
+ */
68
+ export(messages: ChatMessage[], conversationId: string): ExportedConversation;
69
+ /** Export to JSON string. */
70
+ toJSON(conversation: ExportedConversation): string;
71
+ /** Export to Markdown (human-readable report). */
72
+ toMarkdown(conversation: ExportedConversation): string;
73
+ /** Export to CSV (one row per assistant message for analysis). */
74
+ toCSV(conversation: ExportedConversation): string;
75
+ private buildSummary;
76
+ }
77
+ //# sourceMappingURL=conversation-export.d.ts.map
@@ -0,0 +1,254 @@
1
+ // ────────────────────────────────────────────────────────────────────────────
2
+ // Helpers
3
+ // ────────────────────────────────────────────────────────────────────────────
4
+ /** Human-readable label for a domain. */
5
+ function domainLabel(domain) {
6
+ return domain
7
+ .split('_')
8
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
9
+ .join(' ');
10
+ }
11
+ /** Domain emoji for markdown output. */
12
+ const DOMAIN_EMOJI = {
13
+ security_review: '🛡️',
14
+ code_engineering: '💻',
15
+ architecture_design: '🏗️',
16
+ debugging: '🔍',
17
+ team_leadership: '👥',
18
+ one_on_one: '🤝',
19
+ sales_pitch: '💰',
20
+ negotiation: '🤝',
21
+ marketing_content: '📣',
22
+ strategic_planning: '📊',
23
+ crisis_management: '🚨',
24
+ creative_work: '🎨',
25
+ writing_content: '✍️',
26
+ decision_making: '⚖️',
27
+ learning_research: '📚',
28
+ personal_development: '🌱',
29
+ general: '💬',
30
+ };
31
+ /** Escape a CSV field value — wraps in quotes if it contains commas, quotes, or newlines. */
32
+ function csvEscape(value) {
33
+ if (value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r')) {
34
+ return '"' + value.replace(/"/g, '""') + '"';
35
+ }
36
+ return value;
37
+ }
38
+ /** Auto-generate a title from the first user message. */
39
+ function generateTitle(messages) {
40
+ const firstUser = messages.find(m => m.role === 'user');
41
+ if (!firstUser)
42
+ return 'Empty Conversation';
43
+ const text = firstUser.content.trim();
44
+ if (text.length <= 60)
45
+ return text;
46
+ return text.slice(0, 57) + '...';
47
+ }
48
+ // ────────────────────────────────────────────────────────────────────────────
49
+ // ConversationExporter
50
+ // ────────────────────────────────────────────────────────────────────────────
51
+ export class ConversationExporter {
52
+ /**
53
+ * Build an export from conversation messages with their metadata.
54
+ */
55
+ export(messages, conversationId) {
56
+ const exportedMessages = messages.map(msg => {
57
+ if (msg.role === 'user' || !msg.metadata) {
58
+ return { role: msg.role, content: msg.content, timestamp: msg.timestamp };
59
+ }
60
+ const meta = msg.metadata;
61
+ return {
62
+ role: msg.role,
63
+ content: msg.content,
64
+ timestamp: msg.timestamp,
65
+ context: {
66
+ domain: meta.domain,
67
+ emotionalRegister: meta.emotionalRegister,
68
+ emotionalTrajectory: meta.emotionalTrajectory,
69
+ conversationTheme: meta.conversationTheme,
70
+ corrected: meta.corrected,
71
+ originalDomain: meta.originalDomain,
72
+ confidence: meta.confidence,
73
+ stakes: meta.stakes,
74
+ complexity: meta.complexity,
75
+ },
76
+ activeTraits: meta.activeTraits.map(t => ({
77
+ traitName: t.traitKey,
78
+ weight: parseFloat(t.traitKey), // placeholder — actual weight comes from the mix
79
+ sourceName: t.sourceName,
80
+ })),
81
+ customWeightsApplied: meta.customWeightsApplied,
82
+ recommendation: meta.recommendation,
83
+ };
84
+ });
85
+ // Fix activeTraits weight: we don't have the actual mix weight here, so
86
+ // we set weight from the trait data as-is. The caller provides the
87
+ // full trait source which already has behavioralInstruction etc.
88
+ // For export, we'll use a default weight of 1.0 for active traits since
89
+ // they were deemed active by the threshold in getActiveSources.
90
+ for (const msg of exportedMessages) {
91
+ if (msg.activeTraits) {
92
+ for (const trait of msg.activeTraits) {
93
+ trait.weight = 1.0;
94
+ }
95
+ }
96
+ }
97
+ const summary = this.buildSummary(exportedMessages);
98
+ return {
99
+ id: conversationId,
100
+ title: generateTitle(messages),
101
+ exportedAt: Date.now(),
102
+ messageCount: messages.length,
103
+ messages: exportedMessages,
104
+ summary,
105
+ };
106
+ }
107
+ /** Export to JSON string. */
108
+ toJSON(conversation) {
109
+ return JSON.stringify(conversation, null, 2);
110
+ }
111
+ /** Export to Markdown (human-readable report). */
112
+ toMarkdown(conversation) {
113
+ const lines = [];
114
+ // Header
115
+ lines.push(`# Conversation: ${conversation.title}`);
116
+ lines.push('');
117
+ const date = new Date(conversation.exportedAt).toISOString().split('T')[0];
118
+ lines.push(`**Date:** ${date} | **Messages:** ${conversation.messageCount}`);
119
+ // Dominant contexts
120
+ if (conversation.summary.dominantContexts.length > 0) {
121
+ const contexts = conversation.summary.dominantContexts
122
+ .map(c => `${domainLabel(c.domain)} (${Math.round(c.percentage)}%)`)
123
+ .join(', ');
124
+ lines.push(`**Dominant contexts:** ${contexts}`);
125
+ }
126
+ // Sources referenced
127
+ if (conversation.summary.uniqueSourcesReferenced.length > 0) {
128
+ lines.push(`**Historical minds referenced:** ${conversation.summary.uniqueSourcesReferenced.join(', ')}`);
129
+ }
130
+ if (conversation.summary.correctionsApplied > 0) {
131
+ lines.push(`**Corrections applied:** ${conversation.summary.correctionsApplied}`);
132
+ }
133
+ lines.push('');
134
+ // Messages
135
+ for (const msg of conversation.messages) {
136
+ lines.push('---');
137
+ lines.push('');
138
+ if (msg.role === 'user') {
139
+ lines.push(`**You:** ${msg.content}`);
140
+ }
141
+ else {
142
+ // Build assistant header
143
+ const emoji = msg.context ? (DOMAIN_EMOJI[msg.context.domain] ?? '💬') : '💬';
144
+ const domainStr = msg.context ? domainLabel(msg.context.domain) : 'General';
145
+ const confidenceStr = msg.context?.confidence != null
146
+ ? (msg.context.confidence >= 0.8 ? 'Confident' : msg.context.confidence >= 0.5 ? 'Moderate' : 'Low confidence')
147
+ : '';
148
+ const headerParts = [emoji, domainStr];
149
+ if (confidenceStr)
150
+ headerParts.push(`· ${confidenceStr}`);
151
+ lines.push(`**Architect** [${headerParts.join(' ')}]:`);
152
+ lines.push(msg.content);
153
+ // Active traits
154
+ if (msg.activeTraits && msg.activeTraits.length > 0) {
155
+ const traitList = msg.activeTraits
156
+ .slice(0, 8) // top 8 to avoid clutter
157
+ .map(t => `${formatTraitName(t.traitName)} (${t.sourceName})`)
158
+ .join(', ');
159
+ lines.push(`*Active: ${traitList}*`);
160
+ }
161
+ // Correction note
162
+ if (msg.context?.corrected && msg.context.originalDomain) {
163
+ lines.push(`*Corrected from ${domainLabel(msg.context.originalDomain)}*`);
164
+ }
165
+ }
166
+ lines.push('');
167
+ }
168
+ lines.push('---');
169
+ return lines.join('\n');
170
+ }
171
+ /** Export to CSV (one row per assistant message for analysis). */
172
+ toCSV(conversation) {
173
+ const headers = [
174
+ 'timestamp', 'domain', 'emotion', 'trajectory', 'stakes', 'complexity', 'confidence',
175
+ 'top_trait_1', 'top_trait_1_weight', 'top_trait_1_source',
176
+ 'top_trait_2', 'top_trait_2_weight', 'top_trait_2_source',
177
+ 'top_trait_3', 'top_trait_3_weight', 'top_trait_3_source',
178
+ 'top_trait_4', 'top_trait_4_weight', 'top_trait_4_source',
179
+ 'top_trait_5', 'top_trait_5_weight', 'top_trait_5_source',
180
+ 'correction_applied', 'recommendation_shown',
181
+ ];
182
+ const rows = [headers.join(',')];
183
+ for (const msg of conversation.messages) {
184
+ if (msg.role !== 'assistant' || !msg.context)
185
+ continue;
186
+ const traits = msg.activeTraits ?? [];
187
+ const top5 = traits.slice(0, 5);
188
+ const fields = [
189
+ String(msg.timestamp),
190
+ csvEscape(msg.context.domain),
191
+ csvEscape(msg.context.emotionalRegister),
192
+ csvEscape(msg.context.emotionalTrajectory ?? ''),
193
+ csvEscape(msg.context.stakes),
194
+ csvEscape(msg.context.complexity),
195
+ msg.context.confidence != null ? String(msg.context.confidence) : '',
196
+ ];
197
+ // Top 5 traits (3 columns each)
198
+ for (let i = 0; i < 5; i++) {
199
+ if (i < top5.length) {
200
+ fields.push(csvEscape(top5[i].traitName));
201
+ fields.push(String(top5[i].weight));
202
+ fields.push(csvEscape(top5[i].sourceName));
203
+ }
204
+ else {
205
+ fields.push('', '', '');
206
+ }
207
+ }
208
+ fields.push(msg.context.corrected ? 'true' : 'false');
209
+ fields.push(msg.recommendation ? 'true' : 'false');
210
+ rows.push(fields.join(','));
211
+ }
212
+ return rows.join('\n');
213
+ }
214
+ // ── Private ────────────────────────────────────────────────────────────
215
+ buildSummary(messages) {
216
+ const assistantMessages = messages.filter(m => m.role === 'assistant' && m.context);
217
+ // Dominant contexts
218
+ const domainCounts = new Map();
219
+ for (const msg of assistantMessages) {
220
+ const domain = msg.context.domain;
221
+ domainCounts.set(domain, (domainCounts.get(domain) ?? 0) + 1);
222
+ }
223
+ const totalAssistant = assistantMessages.length || 1;
224
+ const dominantContexts = Array.from(domainCounts.entries())
225
+ .map(([domain, count]) => ({ domain, percentage: (count / totalAssistant) * 100 }))
226
+ .sort((a, b) => b.percentage - a.percentage);
227
+ // Emotional arc — one emotion per assistant turn
228
+ const emotionalArc = assistantMessages
229
+ .map(m => m.context.emotionalRegister);
230
+ // Corrections applied
231
+ const correctionsApplied = assistantMessages
232
+ .filter(m => m.context.corrected === true).length;
233
+ // Unique sources
234
+ const sourceSet = new Set();
235
+ for (const msg of assistantMessages) {
236
+ if (msg.activeTraits) {
237
+ for (const trait of msg.activeTraits) {
238
+ sourceSet.add(trait.sourceName);
239
+ }
240
+ }
241
+ }
242
+ const uniqueSourcesReferenced = Array.from(sourceSet).sort();
243
+ return { dominantContexts, emotionalArc, correctionsApplied, uniqueSourcesReferenced };
244
+ }
245
+ }
246
+ /** Format a camelCase trait key into human-readable form. */
247
+ function formatTraitName(key) {
248
+ // "adversarialThinking" → "Adversarial Thinking"
249
+ return key
250
+ .replace(/([A-Z])/g, ' $1')
251
+ .replace(/^./, c => c.toUpperCase())
252
+ .trim();
253
+ }
254
+ //# sourceMappingURL=conversation-export.js.map
@@ -0,0 +1,53 @@
1
+ import type { ContextDomain, EmotionalRegister } from '../schema.js';
2
+ export interface DetectionCorrection {
3
+ id: string;
4
+ timestamp: number;
5
+ userMessage: string;
6
+ messageLength: number;
7
+ detectedDomain: ContextDomain;
8
+ correctedDomain: ContextDomain;
9
+ detectedEmotion: EmotionalRegister;
10
+ keywords: string[];
11
+ }
12
+ export interface CorrectionPattern {
13
+ keyword: string;
14
+ fromDomain: ContextDomain;
15
+ toDomain: ContextDomain;
16
+ occurrences: number;
17
+ confidence: number;
18
+ }
19
+ export declare class CorrectionStore {
20
+ private corrections;
21
+ private patterns;
22
+ /** Record a new correction. Generates id/timestamp and extracts keywords. */
23
+ addCorrection(correction: Omit<DetectionCorrection, 'id' | 'timestamp' | 'keywords'>): void;
24
+ /** Get all stored corrections. */
25
+ getCorrections(): DetectionCorrection[];
26
+ /** Get correction patterns sorted by confidence descending. */
27
+ getPatterns(): CorrectionPattern[];
28
+ /**
29
+ * Given a message and detected domain, check if corrections suggest a
30
+ * different domain. Returns the corrected domain if pattern confidence
31
+ * > 0.6 and occurrences >= 3, else null.
32
+ */
33
+ suggestCorrection(message: string, detectedDomain: ContextDomain): ContextDomain | null;
34
+ /** Recompute patterns from all stored corrections. */
35
+ private recomputePatterns;
36
+ /** Serialize for encrypted storage. */
37
+ serialize(): string;
38
+ /** Deserialize from encrypted storage. */
39
+ static deserialize(data: string): CorrectionStore;
40
+ /** Clear all corrections (user data deletion). */
41
+ clear(): void;
42
+ /** Stats for debugging. */
43
+ getStats(): {
44
+ totalCorrections: number;
45
+ topMisclassifications: Array<{
46
+ from: ContextDomain;
47
+ to: ContextDomain;
48
+ count: number;
49
+ }>;
50
+ correctionRate: Record<string, number>;
51
+ };
52
+ }
53
+ //# sourceMappingURL=correction-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correction-store.d.ts","sourceRoot":"","sources":["correction-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAMrE,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,aAAa,CAAC;IAC9B,eAAe,EAAE,aAAa,CAAC;IAC/B,eAAe,EAAE,iBAAiB,CAAC;IACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AA0DD,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,QAAQ,CAA2B;IAE3C,6EAA6E;IAC7E,aAAa,CACX,UAAU,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,CAAC,GACrE,IAAI;IAUP,kCAAkC;IAClC,cAAc,IAAI,mBAAmB,EAAE;IAIvC,+DAA+D;IAC/D,WAAW,IAAI,iBAAiB,EAAE;IAIlC;;;;OAIG;IACH,iBAAiB,CACf,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,aAAa,GAC5B,aAAa,GAAG,IAAI;IAoBvB,sDAAsD;IACtD,OAAO,CAAC,iBAAiB;IAwCzB,uCAAuC;IACvC,SAAS,IAAI,MAAM;IAOnB,0CAA0C;IAC1C,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAWjD,kDAAkD;IAClD,KAAK,IAAI,IAAI;IAKb,2BAA2B;IAC3B,QAAQ,IAAI;QACV,gBAAgB,EAAE,MAAM,CAAC;QACzB,qBAAqB,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,aAAa,CAAC;YAAC,EAAE,EAAE,aAAa,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACxF,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACxC;CAoCF"}