mia-code 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.coaia/pde/d77620fc-1cd9-47e2-ba00-c03e114e42e9.jsonl +16 -0
  3. package/.coaia/pde/de44d838-b58b-4e91-b791-dd3b0f940ed1.jsonl +60 -0
  4. package/.gemini/settings.json +8 -0
  5. package/.hch/issue_.env +4 -0
  6. package/.hch/issue_add__2601211715.json +77 -0
  7. package/.hch/issue_add__2601211715.md +4 -0
  8. package/.hch/issue_add__2602242020.json +78 -0
  9. package/.hch/issue_add__2602242020.md +7 -0
  10. package/.hch/issues.json +2312 -0
  11. package/.hch/issues.md +30 -0
  12. package/260123084839.coaia-narrative.autoRevisionOfInitial_NewStructuralTensionChart-to-initiate-HierarchicalThinking.txt +5 -0
  13. package/2602010101.issue.txt +31 -0
  14. package/BUGS.md +242 -0
  15. package/CLAUDE.md +2 -0
  16. package/ENHANCEMENTS.md +129 -0
  17. package/FEATURES_ENDING_SESSIONS.md +21 -0
  18. package/FIXES.md +114 -0
  19. package/GUILLAUME.md +77 -0
  20. package/KINSHIP.md +50 -0
  21. package/LAUNCH__session_id__MiaCodeNextWorkReviewAndCommits_2601312020.sh +7 -0
  22. package/PHASE_2.md +153 -0
  23. package/PHASE_2_IMPLEMENTATION.md +134 -0
  24. package/README.md +203 -0
  25. package/RESUME__issueMaker__540244c2-b096-40d8-8c3f-398408d3e0eb.2602041757.sh +1 -0
  26. package/RUN_COPILOT_with_related_folders__260130.sh +2 -0
  27. package/WS__mia-code__260214__IAIP_PDE.code-workspace +29 -0
  28. package/WS__mia-code__src332__260122.code-workspace +23 -0
  29. package/_env.sh +12 -0
  30. package/dist/cli.d.ts +11 -0
  31. package/dist/cli.js +679 -0
  32. package/dist/commands.d.ts +43 -0
  33. package/dist/commands.js +108 -0
  34. package/dist/config.d.ts +8 -0
  35. package/dist/config.js +57 -0
  36. package/dist/formatting.d.ts +12 -0
  37. package/dist/formatting.js +133 -0
  38. package/dist/geminiHeadless.d.ts +25 -0
  39. package/dist/geminiHeadless.js +246 -0
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.js +186 -0
  42. package/dist/mcp/config-generator.d.ts +23 -0
  43. package/dist/mcp/config-generator.js +116 -0
  44. package/dist/mcp/index.d.ts +18 -0
  45. package/dist/mcp/index.js +43 -0
  46. package/dist/mcp/miaco-server.d.ts +15 -0
  47. package/dist/mcp/miaco-server.js +161 -0
  48. package/dist/mcp/miatel-server.d.ts +15 -0
  49. package/dist/mcp/miatel-server.js +123 -0
  50. package/dist/mcp/miawa-server.d.ts +15 -0
  51. package/dist/mcp/miawa-server.js +125 -0
  52. package/dist/mcp/utils.d.ts +51 -0
  53. package/dist/mcp/utils.js +76 -0
  54. package/dist/multiline-input.d.ts +98 -0
  55. package/dist/multiline-input.js +630 -0
  56. package/dist/narrative/index.d.ts +9 -0
  57. package/dist/narrative/index.js +11 -0
  58. package/dist/narrative/router.d.ts +89 -0
  59. package/dist/narrative/router.js +186 -0
  60. package/dist/narrative/tracer.d.ts +75 -0
  61. package/dist/narrative/tracer.js +180 -0
  62. package/dist/sessionStore.d.ts +10 -0
  63. package/dist/sessionStore.js +93 -0
  64. package/dist/types.d.ts +44 -0
  65. package/dist/types.js +1 -0
  66. package/dist/unifier.d.ts +6 -0
  67. package/dist/unifier.js +147 -0
  68. package/issue-358--architecture/ARCHITECTURE_OVERVIEW.md +60 -0
  69. package/issue-358--architecture/CLI_INTEGRATION.md +61 -0
  70. package/issue-358--architecture/COVER_ART_BRIEF.md +68 -0
  71. package/issue-358--architecture/MEMORY_SYSTEM.md +89 -0
  72. package/issue-358--architecture/PERSONA_REGISTRY.md +97 -0
  73. package/issue-358--architecture/PODCAST_PRODUCTION_PLAN.md +61 -0
  74. package/issue-358--architecture/PODCAST_SCRIPT_FINAL.md +109 -0
  75. package/issue-358--architecture/PROTOTYPE_CHARACTER_SPEC.md +59 -0
  76. package/issue-358--architecture/RESOURCES.md +41 -0
  77. package/issue-358--architecture/TEAM_LISTENING_GUIDE.md +53 -0
  78. package/llms-gemini-cli.txt +145 -0
  79. package/package.json +39 -0
  80. package/samples/copilot/session-state/be76abaa-a27f-4725-b2a9-22fb45f7e0f7/checkpoints/index.md +6 -0
  81. package/samples/copilot/session-state/be76abaa-a27f-4725-b2a9-22fb45f7e0f7/events.jsonl +213 -0
  82. package/samples/copilot/session-state/be76abaa-a27f-4725-b2a9-22fb45f7e0f7/plan.md +243 -0
  83. package/samples/copilot/session-state/be76abaa-a27f-4725-b2a9-22fb45f7e0f7/workspace.yaml +5 -0
  84. package/src/cli.ts +742 -0
  85. package/src/commands.ts +127 -0
  86. package/src/config.ts +67 -0
  87. package/src/formatting.ts +157 -0
  88. package/src/geminiHeadless.ts +300 -0
  89. package/src/index.ts +194 -0
  90. package/src/mcp/config-generator.ts +141 -0
  91. package/src/mcp/index.ts +55 -0
  92. package/src/mcp/miaco-server.ts +199 -0
  93. package/src/mcp/miatel-server.ts +138 -0
  94. package/src/mcp/miawa-server.ts +158 -0
  95. package/src/mcp/utils.ts +121 -0
  96. package/src/multiline-input.ts +739 -0
  97. package/src/narrative/index.ts +33 -0
  98. package/src/narrative/router.ts +260 -0
  99. package/src/narrative/tracer.ts +249 -0
  100. package/src/sessionStore.ts +111 -0
  101. package/src/types.ts +49 -0
  102. package/src/unifier.ts +171 -0
  103. package/tsconfig.json +15 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Narrative Intelligence Integration for mia-code
3
+ *
4
+ * Exports the core narrative intelligence components:
5
+ * - NarrativeRouter: Routes events to miaco/miatel/miawa based on three-universe analysis
6
+ * - MiaCodeTracer: Observability for mia-code operations
7
+ */
8
+
9
+ // Router exports
10
+ export {
11
+ NarrativeRouter,
12
+ getNarrativeRouter,
13
+ MiaCodeEvent,
14
+ RoutingResult,
15
+ UNIVERSE_TO_CLI,
16
+ CLI_TO_UNIVERSE,
17
+ Universe,
18
+ ThreeUniverseAnalysis,
19
+ StoryBeat,
20
+ NarrativeFunction,
21
+ EmotionalTone,
22
+ CoherenceResult,
23
+ } from "./router.js";
24
+
25
+ // Tracer exports
26
+ export {
27
+ MiaCodeTracer,
28
+ getTracer,
29
+ removeTracer,
30
+ MiaCodeOperation,
31
+ NarrativeEventType,
32
+ NarrativeMetrics,
33
+ } from "./tracer.js";
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Narrative Intelligence Integration for mia-code
3
+ *
4
+ * Bridges the three-universe model from @langchain/langgraph-narrative-intelligence (that I publish as : ava-langchain-narrative-tracing and not @langchain/langgraph-narrative-intelligence)
5
+ * to mia-code's miaco/miatel/miawa architecture.
6
+ *
7
+ * Universe Mapping:
8
+ * - ENGINEER (Mia) → miaco (charts, technical precision)
9
+ * - CEREMONY (Ava8) → miawa (ceremonies, relational protocols)
10
+ * - STORY_ENGINE (Miette) → miatel (beats, narrative patterns)
11
+ */
12
+
13
+ import {
14
+ ThreeUniverseProcessor,
15
+ NarrativeCoherenceEngine,
16
+ Universe,
17
+ ThreeUniverseAnalysis,
18
+ StoryBeat,
19
+ createStoryBeat,
20
+ NarrativeFunction,
21
+ CoherenceResult,
22
+ EmotionalTone,
23
+ classifyEmotionalTone,
24
+ } from "ava-langgraph-narrative-intelligence";
25
+
26
+ /**
27
+ * Maps universe to mia-code CLI
28
+ */
29
+ export const UNIVERSE_TO_CLI: Record<Universe, string> = {
30
+ [Universe.ENGINEER]: "miaco",
31
+ [Universe.CEREMONY]: "miawa",
32
+ [Universe.STORY_ENGINE]: "miatel",
33
+ };
34
+
35
+ /**
36
+ * Maps CLI to universe
37
+ */
38
+ export const CLI_TO_UNIVERSE: Record<string, Universe> = {
39
+ miaco: Universe.ENGINEER,
40
+ miawa: Universe.CEREMONY,
41
+ miatel: Universe.STORY_ENGINE,
42
+ };
43
+
44
+ /**
45
+ * Mia-code event that can be analyzed through three universes
46
+ */
47
+ export interface MiaCodeEvent {
48
+ id: string;
49
+ type: "user_input" | "agent_action" | "chart_update" | "beat_created" | "ceremony_action";
50
+ content: string;
51
+ source?: "miaco" | "miatel" | "miawa";
52
+ metadata?: Record<string, unknown>;
53
+ timestamp?: Date;
54
+ }
55
+
56
+ /**
57
+ * Result of routing decision
58
+ */
59
+ export interface RoutingResult {
60
+ leadCli: "miaco" | "miatel" | "miawa";
61
+ leadUniverse: Universe;
62
+ analysis: ThreeUniverseAnalysis;
63
+ suggestedAction: string;
64
+ coherence: number;
65
+ }
66
+
67
+ /**
68
+ * NarrativeRouter - Routes events to the appropriate mia-code CLI
69
+ * based on three-universe analysis
70
+ */
71
+ export class NarrativeRouter {
72
+ private processor: ThreeUniverseProcessor;
73
+ private coherenceEngine: NarrativeCoherenceEngine;
74
+ private beatHistory: StoryBeat[] = [];
75
+ private beatSequence: number = 0;
76
+
77
+ constructor() {
78
+ this.processor = new ThreeUniverseProcessor();
79
+ this.coherenceEngine = new NarrativeCoherenceEngine();
80
+ }
81
+
82
+ /**
83
+ * Analyze an event and determine the best CLI to handle it
84
+ */
85
+ route(event: MiaCodeEvent): RoutingResult {
86
+ // Convert to format expected by processor
87
+ const processedEvent = {
88
+ content: event.content,
89
+ type: event.type,
90
+ source: event.source,
91
+ ...event.metadata,
92
+ };
93
+
94
+ // Run three-universe analysis
95
+ const analysis = this.processor.process(processedEvent, this.mapEventType(event.type));
96
+
97
+ // Map lead universe to CLI
98
+ const leadCli = UNIVERSE_TO_CLI[analysis.leadUniverse] as "miaco" | "miatel" | "miawa";
99
+
100
+ // Determine suggested action based on analysis
101
+ const suggestedAction = this.deriveSuggestedAction(analysis);
102
+
103
+ return {
104
+ leadCli,
105
+ leadUniverse: analysis.leadUniverse,
106
+ analysis,
107
+ suggestedAction,
108
+ coherence: analysis.coherenceScore,
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Record a story beat and update coherence tracking
114
+ */
115
+ recordBeat(content: string, cli: "miaco" | "miatel" | "miawa"): StoryBeat {
116
+ this.beatSequence++;
117
+
118
+ // Classify emotional tone
119
+ const toneResult = classifyEmotionalTone(content);
120
+
121
+ // Determine narrative function from content
122
+ const narrativeFunction = this.inferNarrativeFunction(content);
123
+
124
+ // Map CLI to universe
125
+ const leadUniverse = CLI_TO_UNIVERSE[cli];
126
+
127
+ // Create the beat
128
+ const beat = createStoryBeat(
129
+ `beat_${this.beatSequence}`,
130
+ this.beatSequence,
131
+ content,
132
+ narrativeFunction,
133
+ Math.ceil(this.beatSequence / 10), // Rough act calculation
134
+ {
135
+ emotionalTone: toneResult.classification,
136
+ leadUniverse,
137
+ }
138
+ );
139
+
140
+ this.beatHistory.push(beat);
141
+ return beat;
142
+ }
143
+
144
+ /**
145
+ * Analyze coherence of accumulated beats
146
+ */
147
+ analyzeCoherence(): CoherenceResult | null {
148
+ if (this.beatHistory.length === 0) {
149
+ return null;
150
+ }
151
+ const result = this.coherenceEngine.analyze(this.beatHistory);
152
+ // Handle case where result is CoherenceEngineState
153
+ if ('coherenceScore' in result && result.coherenceScore) {
154
+ return result as CoherenceResult;
155
+ }
156
+ return null;
157
+ }
158
+
159
+ /**
160
+ * Get trinity assessment (Mia/Miette/Ava8 perspectives on quality)
161
+ */
162
+ getTrinityAssessment(): { mia: string; miette: string; ava8: string } | null {
163
+ const result = this.analyzeCoherence();
164
+ if (!result) return null;
165
+ return {
166
+ mia: result.trinityAssessment.mia,
167
+ miette: result.trinityAssessment.miette,
168
+ ava8: result.trinityAssessment.ava8,
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Get gaps that need addressing
174
+ */
175
+ getGaps(): Array<{ type: string; severity: string; description: string }> {
176
+ const result = this.analyzeCoherence();
177
+ if (!result) return [];
178
+ return result.gaps.map(gap => ({
179
+ type: gap.gapType,
180
+ severity: gap.severity,
181
+ description: gap.description,
182
+ }));
183
+ }
184
+
185
+ /**
186
+ * Reset the router (clear beat history)
187
+ */
188
+ reset(): void {
189
+ this.beatHistory = [];
190
+ this.beatSequence = 0;
191
+ }
192
+
193
+ private mapEventType(type: MiaCodeEvent["type"]): string {
194
+ const mapping: Record<string, string> = {
195
+ user_input: "user.input",
196
+ agent_action: "agent.action",
197
+ chart_update: "github.push",
198
+ beat_created: "agent.action",
199
+ ceremony_action: "system.event",
200
+ };
201
+ return mapping[type] || "system.event";
202
+ }
203
+
204
+ private inferNarrativeFunction(content: string): NarrativeFunction {
205
+ const lower = content.toLowerCase();
206
+
207
+ if (lower.includes("begin") || lower.includes("start") || lower.includes("init")) {
208
+ return NarrativeFunction.INCITING_INCIDENT;
209
+ }
210
+ if (lower.includes("complete") || lower.includes("finish") || lower.includes("done")) {
211
+ return NarrativeFunction.RESOLUTION;
212
+ }
213
+ if (lower.includes("problem") || lower.includes("issue") || lower.includes("bug")) {
214
+ return NarrativeFunction.COMPLICATION;
215
+ }
216
+ if (lower.includes("fix") || lower.includes("resolve") || lower.includes("solved")) {
217
+ return NarrativeFunction.RESOLUTION;
218
+ }
219
+ if (lower.includes("major") || lower.includes("significant") || lower.includes("breakthrough")) {
220
+ return NarrativeFunction.TURNING_POINT;
221
+ }
222
+
223
+ return NarrativeFunction.RISING_ACTION;
224
+ }
225
+
226
+ private deriveSuggestedAction(analysis: ThreeUniverseAnalysis): string {
227
+ const engineer = analysis.engineer;
228
+ const ceremony = analysis.ceremony;
229
+ const storyEngine = analysis.storyEngine;
230
+
231
+ // Use highest confidence perspective's suggestion
232
+ if (engineer.confidence >= ceremony.confidence && engineer.confidence >= storyEngine.confidence) {
233
+ return engineer.suggestedFlows[0] || "analyze";
234
+ }
235
+ if (ceremony.confidence >= storyEngine.confidence) {
236
+ return ceremony.suggestedFlows[0] || "witness";
237
+ }
238
+ return storyEngine.suggestedFlows[0] || "narrate";
239
+ }
240
+ }
241
+
242
+ // Re-export useful types
243
+ export {
244
+ Universe,
245
+ ThreeUniverseAnalysis,
246
+ StoryBeat,
247
+ NarrativeFunction,
248
+ EmotionalTone,
249
+ CoherenceResult,
250
+ };
251
+
252
+ // Export singleton for easy use
253
+ let routerInstance: NarrativeRouter | null = null;
254
+
255
+ export function getNarrativeRouter(): NarrativeRouter {
256
+ if (!routerInstance) {
257
+ routerInstance = new NarrativeRouter();
258
+ }
259
+ return routerInstance;
260
+ }
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Narrative Tracing Integration for mia-code
3
+ *
4
+ * Integrates @langchain/narrative-tracing for observability that I published as : ava-langchain-narrative-tracing and not @langchain/narrative-tracing
5
+ * across mia-code operations.
6
+ */
7
+
8
+ import {
9
+ NarrativeTracingHandler,
10
+ NarrativeEventType,
11
+ NarrativeMetrics,
12
+ createNarrativeMetrics,
13
+ } from "ava-langchain-narrative-tracing";
14
+
15
+ import { Universe, ThreeUniverseAnalysis } from "./router.js";
16
+
17
+ /**
18
+ * mia-code operation types
19
+ */
20
+ export type MiaCodeOperation =
21
+ | "chart_create"
22
+ | "chart_update"
23
+ | "chart_complete"
24
+ | "beat_create"
25
+ | "beat_analyze"
26
+ | "ceremony_init"
27
+ | "ceremony_advance"
28
+ | "user_input"
29
+ | "agent_response"
30
+ | "routing_decision";
31
+
32
+ /**
33
+ * MiaCodeTracer - Wraps NarrativeTracingHandler for mia-code specific operations
34
+ */
35
+ export class MiaCodeTracer {
36
+ private handler: NarrativeTracingHandler;
37
+ private metrics: NarrativeMetrics;
38
+ private sessionId: string;
39
+ private startTime: number;
40
+
41
+ constructor(options: {
42
+ sessionId: string;
43
+ storyId?: string;
44
+ publicKey?: string;
45
+ secretKey?: string;
46
+ }) {
47
+ this.sessionId = options.sessionId;
48
+ this.startTime = Date.now();
49
+
50
+ this.handler = new NarrativeTracingHandler({
51
+ storyId: options.storyId || `mia_${options.sessionId}`,
52
+ sessionId: options.sessionId,
53
+ publicKey: options.publicKey || process.env.LANGFUSE_PUBLIC_KEY,
54
+ secretKey: options.secretKey || process.env.LANGFUSE_SECRET_KEY,
55
+ });
56
+
57
+ this.metrics = createNarrativeMetrics();
58
+ }
59
+
60
+ /**
61
+ * Start tracing a session
62
+ */
63
+ startSession(): string {
64
+ const traceId = this.handler.startStoryGeneration();
65
+ return traceId;
66
+ }
67
+
68
+ /**
69
+ * Log a chart operation (miaco)
70
+ */
71
+ logChartOperation(
72
+ chartId: string,
73
+ operation: "create" | "update" | "complete" | "add_step",
74
+ data: Record<string, unknown>
75
+ ): void {
76
+ this.handler.logEvent({
77
+ eventType: NarrativeEventType.BEAT_CREATED,
78
+ beatId: chartId,
79
+ metadata: {
80
+ cli: "miaco",
81
+ operation,
82
+ ...data,
83
+ },
84
+ });
85
+ this.metrics.beatsGenerated++;
86
+ }
87
+
88
+ /**
89
+ * Log a beat operation (miatel)
90
+ */
91
+ logBeatOperation(
92
+ beatId: string,
93
+ content: string,
94
+ sequence: number,
95
+ narrativeFunction: string
96
+ ): void {
97
+ this.handler.logBeatCreation(
98
+ beatId,
99
+ content,
100
+ sequence,
101
+ narrativeFunction
102
+ );
103
+ this.metrics.beatsGenerated++;
104
+ }
105
+
106
+ /**
107
+ * Log a ceremony operation (miawa)
108
+ */
109
+ logCeremonyOperation(
110
+ ceremonyId: string,
111
+ operation: "init" | "advance" | "close",
112
+ movement?: string,
113
+ data?: Record<string, unknown>
114
+ ): void {
115
+ this.handler.logEvent({
116
+ eventType: NarrativeEventType.CHARACTER_ARC_UPDATED,
117
+ metadata: {
118
+ cli: "miawa",
119
+ operation,
120
+ movement,
121
+ ceremonyId,
122
+ ...data,
123
+ },
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Log a three-universe routing decision
129
+ */
130
+ logRoutingDecision(analysis: ThreeUniverseAnalysis, targetCli: string): void {
131
+ this.handler.logThreeUniverseAnalysis({
132
+ eventId: `route_${Date.now()}`,
133
+ engineerIntent: analysis.engineer.intent,
134
+ engineerConfidence: analysis.engineer.confidence,
135
+ ceremonyIntent: analysis.ceremony.intent,
136
+ ceremonyConfidence: analysis.ceremony.confidence,
137
+ storyEngineIntent: analysis.storyEngine.intent,
138
+ storyEngineConfidence: analysis.storyEngine.confidence,
139
+ leadUniverse: this.universeToString(analysis.leadUniverse),
140
+ coherenceScore: analysis.coherenceScore,
141
+ });
142
+
143
+ this.handler.logRoutingDecision({
144
+ decisionId: `decision_${Date.now()}`,
145
+ backend: targetCli,
146
+ flow: analysis.engineer.suggestedFlows[0] || "default",
147
+ score: analysis.coherenceScore,
148
+ leadUniverse: this.universeToString(analysis.leadUniverse),
149
+ });
150
+
151
+ this.metrics.routingDecisions++;
152
+
153
+ // Update alignment metrics
154
+ this.metrics.engineerAlignment =
155
+ (this.metrics.engineerAlignment + analysis.engineer.confidence) / 2;
156
+ this.metrics.ceremonyAlignment =
157
+ (this.metrics.ceremonyAlignment + analysis.ceremony.confidence) / 2;
158
+ this.metrics.storyEngineAlignment =
159
+ (this.metrics.storyEngineAlignment + analysis.storyEngine.confidence) / 2;
160
+ this.metrics.crossUniverseCoherence =
161
+ (this.metrics.crossUniverseCoherence + analysis.coherenceScore) / 2;
162
+ }
163
+
164
+ /**
165
+ * Log a gap identified in the narrative
166
+ */
167
+ logGap(type: string, severity: number, description: string): void {
168
+ this.handler.logGapIdentified(type, description, severity);
169
+ }
170
+
171
+ /**
172
+ * Log user input
173
+ */
174
+ logUserInput(content: string): void {
175
+ this.handler.logEvent({
176
+ eventType: NarrativeEventType.BEAT_CREATED,
177
+ beatId: `input_${Date.now()}`,
178
+ metadata: { type: "user_input", content: content.slice(0, 200) },
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Log agent response
184
+ */
185
+ logAgentResponse(content: string, cli: string): void {
186
+ this.handler.logEvent({
187
+ eventType: NarrativeEventType.BEAT_ENRICHED,
188
+ beatId: `response_${Date.now()}`,
189
+ metadata: { type: "agent_response", cli, content: content.slice(0, 200) },
190
+ });
191
+ this.metrics.enrichmentsApplied++;
192
+ }
193
+
194
+ /**
195
+ * Get correlation headers for external calls
196
+ */
197
+ getCorrelationHeaders(): Record<string, string> {
198
+ return {
199
+ "X-Mia-Session-Id": this.sessionId,
200
+ "X-Mia-Trace-Start": this.startTime.toString(),
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Get current metrics
206
+ */
207
+ getMetrics(): NarrativeMetrics {
208
+ this.metrics.totalGenerationTimeMs = Date.now() - this.startTime;
209
+ if (this.metrics.beatsGenerated > 0) {
210
+ this.metrics.averageBeatTimeMs =
211
+ this.metrics.totalGenerationTimeMs / this.metrics.beatsGenerated;
212
+ }
213
+ return { ...this.metrics };
214
+ }
215
+
216
+ /**
217
+ * End session and flush traces
218
+ */
219
+ async endSession(): Promise<void> {
220
+ this.handler.endStoryGeneration(Date.now() - this.startTime);
221
+ await this.handler.flush();
222
+ }
223
+
224
+ private universeToString(universe: Universe): string {
225
+ const mapping: Record<Universe, string> = {
226
+ [Universe.ENGINEER]: "engineer",
227
+ [Universe.CEREMONY]: "ceremony",
228
+ [Universe.STORY_ENGINE]: "story_engine",
229
+ };
230
+ return mapping[universe] || "unknown";
231
+ }
232
+ }
233
+
234
+ // Export types
235
+ export { NarrativeEventType, NarrativeMetrics };
236
+
237
+ // Singleton tracer instance per session
238
+ const tracers: Map<string, MiaCodeTracer> = new Map();
239
+
240
+ export function getTracer(sessionId: string): MiaCodeTracer {
241
+ if (!tracers.has(sessionId)) {
242
+ tracers.set(sessionId, new MiaCodeTracer({ sessionId }));
243
+ }
244
+ return tracers.get(sessionId)!;
245
+ }
246
+
247
+ export function removeTracer(sessionId: string): void {
248
+ tracers.delete(sessionId);
249
+ }
@@ -0,0 +1,111 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { MiaCodeSessionMeta, ChatMessage } from "./types.js";
5
+
6
+ const SESSIONS_FILE = path.join(os.homedir(), ".mia-code-sessions.json");
7
+ const HISTORY_DIR = path.join(os.homedir(), ".mia-code-history");
8
+
9
+ interface SessionIndex {
10
+ byProjectRoot: Record<string, MiaCodeSessionMeta>;
11
+ byId: Record<string, MiaCodeSessionMeta>;
12
+ }
13
+
14
+ function loadIndex(): SessionIndex {
15
+ if (!fs.existsSync(SESSIONS_FILE)) {
16
+ return { byProjectRoot: {}, byId: {} };
17
+ }
18
+ try {
19
+ const raw = fs.readFileSync(SESSIONS_FILE, "utf8");
20
+ const parsed = JSON.parse(raw) as SessionIndex;
21
+ return {
22
+ byProjectRoot: parsed.byProjectRoot || {},
23
+ byId: parsed.byId || {}
24
+ };
25
+ } catch {
26
+ return { byProjectRoot: {}, byId: {} };
27
+ }
28
+ }
29
+
30
+ function saveIndex(index: SessionIndex): void {
31
+ fs.writeFileSync(SESSIONS_FILE, JSON.stringify(index, null, 2), "utf8");
32
+ }
33
+
34
+ export function rememberSession(meta: MiaCodeSessionMeta): void {
35
+ const idx = loadIndex();
36
+ if (meta.projectRoot) {
37
+ idx.byProjectRoot[meta.projectRoot] = meta;
38
+ }
39
+ idx.byId[meta.id] = meta;
40
+ saveIndex(idx);
41
+ }
42
+
43
+ export function markSessionInitialized(id: string): void {
44
+ const idx = loadIndex();
45
+ const session = idx.byId[id];
46
+ if (session) {
47
+ session.initialized = true;
48
+ if (session.projectRoot) {
49
+ idx.byProjectRoot[session.projectRoot] = session;
50
+ }
51
+ saveIndex(idx);
52
+ }
53
+ }
54
+
55
+ export function isSessionInitialized(id: string): boolean {
56
+ const idx = loadIndex();
57
+ return idx.byId[id]?.initialized ?? false;
58
+ }
59
+
60
+ export function getLastSessionForProject(projectRoot: string): MiaCodeSessionMeta | null {
61
+ const idx = loadIndex();
62
+ return idx.byProjectRoot[projectRoot] ?? null;
63
+ }
64
+
65
+ export function getSessionById(id: string): MiaCodeSessionMeta | null {
66
+ const idx = loadIndex();
67
+ return idx.byId[id] ?? null;
68
+ }
69
+
70
+ export function listSessions(): MiaCodeSessionMeta[] {
71
+ const idx = loadIndex();
72
+ return Object.values(idx.byId);
73
+ }
74
+
75
+ export function clearSessions(): void {
76
+ saveIndex({ byProjectRoot: {}, byId: {} });
77
+ }
78
+
79
+ // ── Chat history persistence ────────────────────────────────────────
80
+
81
+ function ensureHistoryDir(): void {
82
+ if (!fs.existsSync(HISTORY_DIR)) {
83
+ fs.mkdirSync(HISTORY_DIR, { recursive: true });
84
+ }
85
+ }
86
+
87
+ function historyFile(sessionId: string): string {
88
+ // Sanitize session ID for safe filenames
89
+ const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
90
+ return path.join(HISTORY_DIR, `${safe}.jsonl`);
91
+ }
92
+
93
+ export function saveChatMessage(sessionId: string, msg: ChatMessage): void {
94
+ ensureHistoryDir();
95
+ const line = JSON.stringify(msg) + "\n";
96
+ fs.appendFileSync(historyFile(sessionId), line, "utf8");
97
+ }
98
+
99
+ export function loadChatHistory(sessionId: string): ChatMessage[] {
100
+ const file = historyFile(sessionId);
101
+ if (!fs.existsSync(file)) return [];
102
+ try {
103
+ const raw = fs.readFileSync(file, "utf8");
104
+ return raw
105
+ .split("\n")
106
+ .filter(l => l.trim())
107
+ .map(l => JSON.parse(l) as ChatMessage);
108
+ } catch {
109
+ return [];
110
+ }
111
+ }
package/src/types.ts ADDED
@@ -0,0 +1,49 @@
1
+ export type Role = "user" | "assistant" | "system";
2
+
3
+ export type Engine = "gemini" | "claude" | "copilot";
4
+
5
+ export interface MiaCodeConfig {
6
+ engine: Engine;
7
+ geminiBinary: string;
8
+ claudeBinary: string;
9
+ copilotBinary: string;
10
+ model: string;
11
+ headlessOutputFormat: "json" | "stream-json";
12
+ defaultMode: "code" | "chat";
13
+ defaultProjectRoot: string | null;
14
+ yoloMode: boolean;
15
+ }
16
+
17
+ export interface MiaCodeSessionMeta {
18
+ id: string;
19
+ startedAt: string;
20
+ model: string;
21
+ projectRoot: string | null;
22
+ initialized?: boolean; // Has engine acknowledged this session?
23
+ }
24
+
25
+ export interface ChatMessage {
26
+ role: "user" | "assistant";
27
+ text: string;
28
+ timestamp: string;
29
+ }
30
+
31
+ export interface GeminiJsonEvent {
32
+ type: "init" | "message" | "tool_use" | "tool_result" | "error" | "result" | string;
33
+ session_id?: string;
34
+ timestamp?: string;
35
+ role?: Role;
36
+ text?: string;
37
+ content?: string;
38
+ tool?: {
39
+ name: string;
40
+ input: unknown;
41
+ };
42
+ result?: unknown;
43
+ error?: {
44
+ code: string;
45
+ message: string;
46
+ };
47
+ raw?: unknown;
48
+ [key: string]: unknown;
49
+ }