ava-langgraph-narrative-intelligence 0.1.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 (58) hide show
  1. package/README.md +268 -0
  2. package/dist/graphs/index.cjs +1511 -0
  3. package/dist/graphs/index.cjs.map +1 -0
  4. package/dist/graphs/index.d.cts +2 -0
  5. package/dist/graphs/index.d.ts +2 -0
  6. package/dist/graphs/index.js +1468 -0
  7. package/dist/graphs/index.js.map +1 -0
  8. package/dist/index-Btxk3nQm.d.cts +430 -0
  9. package/dist/index-CgXXxuIH.d.ts +430 -0
  10. package/dist/index-CweT-D3c.d.cts +122 -0
  11. package/dist/index-D-zWH42e.d.cts +66 -0
  12. package/dist/index-D71kh3nE.d.cts +213 -0
  13. package/dist/index-DApls3w2.d.ts +66 -0
  14. package/dist/index-UamXITgg.d.ts +122 -0
  15. package/dist/index-v9AlRC0M.d.ts +213 -0
  16. package/dist/index.cjs +2753 -0
  17. package/dist/index.cjs.map +1 -0
  18. package/dist/index.d.cts +6 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +2654 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/integrations/index.cjs +654 -0
  23. package/dist/integrations/index.cjs.map +1 -0
  24. package/dist/integrations/index.d.cts +2 -0
  25. package/dist/integrations/index.d.ts +2 -0
  26. package/dist/integrations/index.js +614 -0
  27. package/dist/integrations/index.js.map +1 -0
  28. package/dist/ncp-tXS9Jr9e.d.cts +132 -0
  29. package/dist/ncp-tXS9Jr9e.d.ts +132 -0
  30. package/dist/nodes/index.cjs +226 -0
  31. package/dist/nodes/index.cjs.map +1 -0
  32. package/dist/nodes/index.d.cts +2 -0
  33. package/dist/nodes/index.d.ts +2 -0
  34. package/dist/nodes/index.js +196 -0
  35. package/dist/nodes/index.js.map +1 -0
  36. package/dist/schemas/index.cjs +550 -0
  37. package/dist/schemas/index.cjs.map +1 -0
  38. package/dist/schemas/index.d.cts +2 -0
  39. package/dist/schemas/index.d.ts +2 -0
  40. package/dist/schemas/index.js +484 -0
  41. package/dist/schemas/index.js.map +1 -0
  42. package/dist/unified_state_bridge-CIDm1kuf.d.cts +266 -0
  43. package/dist/unified_state_bridge-CIDm1kuf.d.ts +266 -0
  44. package/package.json +91 -0
  45. package/src/graphs/coherence_engine.ts +1027 -0
  46. package/src/graphs/index.ts +47 -0
  47. package/src/graphs/three_universe_processor.ts +1136 -0
  48. package/src/index.ts +181 -0
  49. package/src/integrations/index.ts +17 -0
  50. package/src/integrations/redis_state.ts +691 -0
  51. package/src/nodes/emotional_classifier.ts +289 -0
  52. package/src/nodes/index.ts +17 -0
  53. package/src/schemas/index.ts +75 -0
  54. package/src/schemas/ncp.ts +312 -0
  55. package/src/schemas/unified_state_bridge.ts +681 -0
  56. package/src/tests/coherence_engine.test.ts +273 -0
  57. package/src/tests/three_universe_processor.test.ts +309 -0
  58. package/src/tests/unified_state_bridge.test.ts +360 -0
@@ -0,0 +1,1511 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/graphs/index.ts
21
+ var graphs_exports = {};
22
+ __export(graphs_exports, {
23
+ EventType: () => EventType,
24
+ GapSeverity: () => GapSeverity,
25
+ GapType: () => GapType,
26
+ NarrativeCoherenceEngine: () => NarrativeCoherenceEngine,
27
+ RoutingTarget: () => RoutingTarget,
28
+ ThreeUniverseProcessor: () => ThreeUniverseProcessor,
29
+ analyzeCeremonyPerspective: () => analyzeCeremonyPerspective,
30
+ analyzeEngineerPerspective: () => analyzeEngineerPerspective,
31
+ analyzeStoryEnginePerspective: () => analyzeStoryEnginePerspective,
32
+ ceremonyIntentKeywords: () => ceremonyIntentKeywords,
33
+ createCoherenceScore: () => createCoherenceScore,
34
+ createComponentScore: () => createComponentScore,
35
+ createGap: () => createGap,
36
+ createTrinityAssessment: () => createTrinityAssessment,
37
+ engineerIntentKeywords: () => engineerIntentKeywords,
38
+ storyEngineIntentKeywords: () => storyEngineIntentKeywords,
39
+ synthesizePerspectives: () => synthesizePerspectives
40
+ });
41
+ module.exports = __toCommonJS(graphs_exports);
42
+
43
+ // src/schemas/unified_state_bridge.ts
44
+ function createUniversePerspective(universe, intent, confidence, options = {}) {
45
+ return {
46
+ universe,
47
+ intent,
48
+ confidence,
49
+ suggestedFlows: options.suggestedFlows ?? [],
50
+ context: options.context ?? {}
51
+ };
52
+ }
53
+ function createThreeUniverseAnalysis(engineer, ceremony, storyEngine, leadUniverse, coherenceScore) {
54
+ return {
55
+ engineer,
56
+ ceremony,
57
+ storyEngine,
58
+ leadUniverse,
59
+ coherenceScore,
60
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
61
+ };
62
+ }
63
+ function createStoryBeat(id, sequence, content, narrativeFunction, act, options = {}) {
64
+ return {
65
+ id,
66
+ sequence,
67
+ content,
68
+ narrativeFunction,
69
+ act,
70
+ universeAnalysis: options.universeAnalysis,
71
+ leadUniverse: options.leadUniverse ?? "story_engine" /* STORY_ENGINE */,
72
+ emotionalTone: options.emotionalTone ?? "neutral",
73
+ thematicTags: options.thematicTags ?? [],
74
+ characterId: options.characterId,
75
+ characterArcImpact: options.characterArcImpact ?? 0,
76
+ source: options.source ?? "generator",
77
+ sourceEventId: options.sourceEventId,
78
+ timestamp: options.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
79
+ enrichmentsApplied: options.enrichmentsApplied ?? [],
80
+ qualityScore: options.qualityScore ?? 0.5
81
+ };
82
+ }
83
+
84
+ // src/graphs/three_universe_processor.ts
85
+ var EventType = /* @__PURE__ */ ((EventType2) => {
86
+ EventType2["GITHUB_PUSH"] = "github.push";
87
+ EventType2["GITHUB_ISSUE"] = "github.issue";
88
+ EventType2["GITHUB_PR"] = "github.pull_request";
89
+ EventType2["GITHUB_COMMENT"] = "github.comment";
90
+ EventType2["GITHUB_REVIEW"] = "github.review";
91
+ EventType2["USER_INPUT"] = "user.input";
92
+ EventType2["AGENT_ACTION"] = "agent.action";
93
+ EventType2["SYSTEM_EVENT"] = "system.event";
94
+ return EventType2;
95
+ })(EventType || {});
96
+ function engineerIntentKeywords() {
97
+ return {
98
+ feature_implementation: [
99
+ "feat:",
100
+ "feature",
101
+ "add",
102
+ "implement",
103
+ "create",
104
+ "new"
105
+ ],
106
+ bug_fix: ["fix:", "bug", "hotfix", "patch", "resolve", "correct"],
107
+ refactor: ["refactor", "refact:", "cleanup", "restructure", "reorganize"],
108
+ documentation: ["docs:", "doc:", "documentation", "readme", "comment"],
109
+ testing: ["test:", "tests:", "testing", "spec", "coverage"],
110
+ dependency: ["deps:", "dependency", "upgrade", "update", "bump"],
111
+ configuration: ["config:", "configure", "settings", "env"],
112
+ performance: ["perf:", "performance", "optimize", "speed", "cache"],
113
+ security: ["security", "sec:", "vulnerability", "auth", "permission"],
114
+ ci_cd: ["ci:", "cd:", "pipeline", "workflow", "build"]
115
+ };
116
+ }
117
+ function analyzeEngineerPerspective(state) {
118
+ const event = state.event;
119
+ const eventType = state.eventType;
120
+ let content = "";
121
+ const payload = event.payload;
122
+ if (payload) {
123
+ const commits = payload.commits;
124
+ if (commits) {
125
+ content = commits.map((c) => c.message || "").join(" ");
126
+ } else if (payload.issue) {
127
+ const issue = payload.issue;
128
+ content = (issue.title || "") + " " + (issue.body || "");
129
+ } else if (payload.pull_request) {
130
+ const pr = payload.pull_request;
131
+ content = (pr.title || "") + " " + (pr.body || "");
132
+ }
133
+ } else if (event.content) {
134
+ content = event.content;
135
+ }
136
+ const contentLower = content.toLowerCase();
137
+ const keywords = engineerIntentKeywords();
138
+ const intentScores = {};
139
+ for (const [intent2, terms] of Object.entries(keywords)) {
140
+ const score = terms.filter(
141
+ (term) => contentLower.includes(term.toLowerCase())
142
+ ).length;
143
+ if (score > 0) {
144
+ intentScores[intent2] = score / terms.length;
145
+ }
146
+ }
147
+ let intent;
148
+ let confidence;
149
+ if (Object.keys(intentScores).length > 0) {
150
+ intent = Object.entries(intentScores).reduce(
151
+ (a, b) => a[1] > b[1] ? a : b
152
+ )[0];
153
+ confidence = Math.min(0.95, 0.6 + intentScores[intent] * 0.4);
154
+ } else {
155
+ intent = "maintenance";
156
+ confidence = 0.5;
157
+ }
158
+ const flowMap = {
159
+ feature_implementation: [
160
+ "code_review",
161
+ "integration_test",
162
+ "documentation_update"
163
+ ],
164
+ bug_fix: ["regression_test", "root_cause_analysis", "changelog_update"],
165
+ refactor: ["architecture_review", "performance_test", "code_quality"],
166
+ documentation: ["doc_review", "example_validation"],
167
+ testing: ["coverage_analysis", "test_quality_review"],
168
+ dependency: ["security_scan", "compatibility_test"],
169
+ configuration: ["validation_test", "rollback_plan"],
170
+ performance: ["benchmark", "profiling", "optimization_review"],
171
+ security: ["security_audit", "penetration_test", "credential_scan"],
172
+ ci_cd: ["pipeline_validation", "deployment_test"],
173
+ maintenance: ["standard_ci"]
174
+ };
175
+ const suggestedFlows = flowMap[intent] || ["standard_ci"];
176
+ const context = {
177
+ detectedKeywords: Object.entries(intentScores).filter(([, v]) => v > 0).map(([k]) => k),
178
+ contentLength: content.length,
179
+ eventType,
180
+ technicalScope: determineTechnicalScope(content, event),
181
+ estimatedComplexity: estimateComplexity(content, event)
182
+ };
183
+ const perspective = createUniversePerspective(
184
+ "engineer" /* ENGINEER */,
185
+ intent,
186
+ confidence,
187
+ { suggestedFlows, context }
188
+ );
189
+ return { ...state, engineerPerspective: perspective };
190
+ }
191
+ function determineTechnicalScope(content, _event) {
192
+ const contentLower = content.toLowerCase();
193
+ if (["api", "endpoint", "route"].some((kw) => contentLower.includes(kw))) {
194
+ return "api_layer";
195
+ }
196
+ if (["database", "schema", "migration"].some((kw) => contentLower.includes(kw))) {
197
+ return "data_layer";
198
+ }
199
+ if (["ui", "component", "frontend"].some((kw) => contentLower.includes(kw))) {
200
+ return "presentation_layer";
201
+ }
202
+ if (["test", "spec"].some((kw) => contentLower.includes(kw))) {
203
+ return "testing";
204
+ }
205
+ if (["config", "env", "settings"].some((kw) => contentLower.includes(kw))) {
206
+ return "configuration";
207
+ }
208
+ return "general";
209
+ }
210
+ function estimateComplexity(content, event) {
211
+ const payload = event.payload;
212
+ if (payload) {
213
+ const commits = payload.commits;
214
+ if (commits) {
215
+ if (commits.length > 5) return "high";
216
+ if (commits.length > 2) return "medium";
217
+ }
218
+ }
219
+ if (content.length > 500) return "high";
220
+ if (content.length > 100) return "medium";
221
+ return "low";
222
+ }
223
+ function ceremonyIntentKeywords() {
224
+ return {
225
+ co_creation: ["we", "together", "team", "pair", "collaborate", "co-author"],
226
+ gratitude_expression: [
227
+ "thanks",
228
+ "thank you",
229
+ "grateful",
230
+ "appreciate",
231
+ "credit"
232
+ ],
233
+ witnessing: ["witness", "observe", "acknowledge", "see", "recognize"],
234
+ sacred_pause: ["pause", "reflect", "consider", "contemplate", "breathe"],
235
+ relationship_building: [
236
+ "connect",
237
+ "relationship",
238
+ "community",
239
+ "support"
240
+ ],
241
+ healing: ["heal", "restore", "repair", "reconcile", "mend"],
242
+ celebration: [
243
+ "celebrate",
244
+ "milestone",
245
+ "achievement",
246
+ "success",
247
+ "complete"
248
+ ],
249
+ offering: ["offer", "gift", "contribute", "share", "give"]
250
+ };
251
+ }
252
+ function analyzeCeremonyPerspective(state) {
253
+ const event = state.event;
254
+ const contributors = extractContributors(event);
255
+ const content = extractContent(event);
256
+ const contentLower = content.toLowerCase();
257
+ const keywords = ceremonyIntentKeywords();
258
+ const intentScores = {};
259
+ for (const [intent2, terms] of Object.entries(keywords)) {
260
+ const score = terms.filter((term) => contentLower.includes(term)).length;
261
+ if (score > 0) {
262
+ intentScores[intent2] = score / terms.length;
263
+ }
264
+ }
265
+ if (contributors.length > 1) {
266
+ intentScores.co_creation = (intentScores.co_creation || 0) + 0.5;
267
+ }
268
+ let intent;
269
+ let confidence;
270
+ if (Object.keys(intentScores).length > 0) {
271
+ intent = Object.entries(intentScores).reduce(
272
+ (a, b) => a[1] > b[1] ? a : b
273
+ )[0];
274
+ confidence = Math.min(0.95, 0.5 + intentScores[intent] * 0.4);
275
+ } else {
276
+ intent = "individual_offering";
277
+ confidence = 0.6;
278
+ }
279
+ const flowMap = {
280
+ co_creation: ["witness_collaboration", "honor_contributions", "amplify_voices"],
281
+ gratitude_expression: [
282
+ "amplify_acknowledgment",
283
+ "record_connection",
284
+ "reciprocity_check"
285
+ ],
286
+ witnessing: ["hold_space", "reflect_back", "presence"],
287
+ sacred_pause: ["create_silence", "contemplation_prompt", "breathing_space"],
288
+ relationship_building: [
289
+ "map_connections",
290
+ "strengthen_ties",
291
+ "introduce_support"
292
+ ],
293
+ healing: ["compassion_response", "restoration_path", "forgiveness_space"],
294
+ celebration: ["amplify_joy", "community_acknowledgment", "gratitude_circle"],
295
+ offering: ["receive_gracefully", "honor_gift", "share_forward"],
296
+ individual_offering: [
297
+ "witness_work",
298
+ "hold_space",
299
+ "gentle_acknowledgment"
300
+ ]
301
+ };
302
+ const suggestedFlows = flowMap[intent] || ["witness_work", "hold_space"];
303
+ const context = {
304
+ contributors,
305
+ isCollaborative: contributors.length > 1,
306
+ senderEnergy: assessEnergy(content),
307
+ witnessingNeeded: needsWitnessing(content, event),
308
+ relationshipDepth: assessRelationshipDepth(contributors, event),
309
+ sevenGenerationRelevance: assessLongTermImpact(content, event)
310
+ };
311
+ const perspective = createUniversePerspective(
312
+ "ceremony" /* CEREMONY */,
313
+ intent,
314
+ confidence,
315
+ { suggestedFlows, context }
316
+ );
317
+ return { ...state, ceremonyPerspective: perspective };
318
+ }
319
+ function extractContributors(event) {
320
+ const contributors = [];
321
+ if (event.sender) {
322
+ contributors.push(event.sender);
323
+ }
324
+ const payload = event.payload;
325
+ if (payload) {
326
+ const commits = payload.commits;
327
+ if (commits) {
328
+ for (const commit of commits) {
329
+ const author = commit.author?.name;
330
+ if (author && !contributors.includes(author)) {
331
+ contributors.push(author);
332
+ }
333
+ }
334
+ }
335
+ const issue = payload.issue;
336
+ if (issue) {
337
+ const user = issue.user;
338
+ if (user?.login && !contributors.includes(user.login)) {
339
+ contributors.push(user.login);
340
+ }
341
+ }
342
+ const pr = payload.pull_request;
343
+ if (pr) {
344
+ const user = pr.user;
345
+ if (user?.login && !contributors.includes(user.login)) {
346
+ contributors.push(user.login);
347
+ }
348
+ }
349
+ }
350
+ return contributors.length > 0 ? contributors : ["unknown"];
351
+ }
352
+ function extractContent(event) {
353
+ if (event.content) {
354
+ return event.content;
355
+ }
356
+ const payload = event.payload;
357
+ if (payload) {
358
+ const parts = [];
359
+ const commits = payload.commits;
360
+ if (commits) {
361
+ parts.push(...commits.map((c) => c.message || ""));
362
+ }
363
+ const issue = payload.issue;
364
+ if (issue) {
365
+ parts.push(issue.title || "");
366
+ parts.push(issue.body || "");
367
+ }
368
+ const pr = payload.pull_request;
369
+ if (pr) {
370
+ parts.push(pr.title || "");
371
+ parts.push(pr.body || "");
372
+ }
373
+ const comment = payload.comment;
374
+ if (comment) {
375
+ parts.push(comment.body || "");
376
+ }
377
+ return parts.filter(Boolean).join(" ");
378
+ }
379
+ return "";
380
+ }
381
+ function assessEnergy(content) {
382
+ const contentLower = content.toLowerCase();
383
+ if (["urgent", "critical", "asap", "emergency"].some(
384
+ (w) => contentLower.includes(w)
385
+ )) {
386
+ return "urgent_flow";
387
+ }
388
+ if (["excited", "happy", "great", "awesome"].some(
389
+ (w) => contentLower.includes(w)
390
+ )) {
391
+ return "joyful_flow";
392
+ }
393
+ if (["stuck", "blocked", "help", "issue"].some(
394
+ (w) => contentLower.includes(w)
395
+ )) {
396
+ return "seeking_support";
397
+ }
398
+ if (["thoughtful", "consider", "reflect"].some(
399
+ (w) => contentLower.includes(w)
400
+ )) {
401
+ return "contemplative_flow";
402
+ }
403
+ return "steady_flow";
404
+ }
405
+ function needsWitnessing(content, _event) {
406
+ const contentLower = content.toLowerCase();
407
+ if (["first", "new", "trying", "learning", "help"].some(
408
+ (w) => contentLower.includes(w)
409
+ )) {
410
+ return true;
411
+ }
412
+ if (["complete", "achieve", "milestone", "done"].some(
413
+ (w) => contentLower.includes(w)
414
+ )) {
415
+ return true;
416
+ }
417
+ return false;
418
+ }
419
+ function assessRelationshipDepth(contributors, _event) {
420
+ if (contributors.length > 2) return "community";
421
+ if (contributors.length > 1) return "pair";
422
+ return "individual";
423
+ }
424
+ function assessLongTermImpact(content, _event) {
425
+ const contentLower = content.toLowerCase();
426
+ let score = 0.3;
427
+ if (["architecture", "foundation", "core", "framework"].some(
428
+ (w) => contentLower.includes(w)
429
+ )) {
430
+ score += 0.3;
431
+ }
432
+ if (["document", "guide", "tutorial", "example"].some(
433
+ (w) => contentLower.includes(w)
434
+ )) {
435
+ score += 0.2;
436
+ }
437
+ if (["breaking", "migration", "deprecate"].some(
438
+ (w) => contentLower.includes(w)
439
+ )) {
440
+ score += 0.2;
441
+ }
442
+ return Math.min(1, score);
443
+ }
444
+ function storyEngineIntentKeywords() {
445
+ return {
446
+ inciting_incident: ["init", "start", "begin", "new", "first", "introduce"],
447
+ rising_action: ["add", "implement", "build", "develop", "progress", "continue"],
448
+ turning_point: ["feat:", "major", "significant", "pivot", "change", "transform"],
449
+ complication: ["issue", "problem", "bug", "error", "conflict", "challenge"],
450
+ crisis: ["critical", "urgent", "breaking", "emergency", "blocker"],
451
+ climax: ["complete", "finish", "final", "release", "launch", "deploy"],
452
+ resolution: ["fix", "resolve", "close", "merge", "done"],
453
+ denouement: ["cleanup", "refactor", "optimize", "polish", "improve"]
454
+ };
455
+ }
456
+ function analyzeStoryEnginePerspective(state) {
457
+ const event = state.event;
458
+ const content = extractContent(event);
459
+ const contentLower = content.toLowerCase();
460
+ const keywords = storyEngineIntentKeywords();
461
+ const intentScores = {};
462
+ for (const [intent2, terms] of Object.entries(keywords)) {
463
+ const score = terms.filter((term) => contentLower.includes(term)).length;
464
+ if (score > 0) {
465
+ intentScores[intent2] = score / terms.length;
466
+ }
467
+ }
468
+ let intent;
469
+ let confidence;
470
+ if (Object.keys(intentScores).length > 0) {
471
+ intent = Object.entries(intentScores).reduce(
472
+ (a, b) => a[1] > b[1] ? a : b
473
+ )[0];
474
+ confidence = Math.min(0.95, 0.55 + intentScores[intent] * 0.4);
475
+ } else {
476
+ intent = "rising_action";
477
+ confidence = 0.5;
478
+ }
479
+ const actMap = {
480
+ inciting_incident: 1,
481
+ rising_action: 2,
482
+ turning_point: 2,
483
+ complication: 2,
484
+ crisis: 2,
485
+ climax: 3,
486
+ resolution: 3,
487
+ denouement: 3
488
+ };
489
+ const act = actMap[intent] || 2;
490
+ const functionMap = {
491
+ inciting_incident: "inciting_incident",
492
+ rising_action: "rising_action",
493
+ turning_point: "turning_point",
494
+ complication: "complication",
495
+ crisis: "crisis",
496
+ climax: "climax",
497
+ resolution: "resolution",
498
+ denouement: "denouement"
499
+ };
500
+ const narrativeFunction = functionMap[intent] || "beat";
501
+ const flowMap = {
502
+ inciting_incident: ["establish_stakes", "introduce_characters", "set_tone"],
503
+ rising_action: ["advance_narrative", "develop_characters", "build_tension"],
504
+ turning_point: ["mark_pivot", "shift_perspective", "update_arc"],
505
+ complication: ["deepen_conflict", "raise_stakes", "add_obstacle"],
506
+ crisis: ["peak_tension", "force_decision", "approach_climax"],
507
+ climax: ["resolve_main_conflict", "character_transformation", "theme_revelation"],
508
+ resolution: ["tie_loose_ends", "show_consequences", "new_equilibrium"],
509
+ denouement: ["reflect_journey", "hint_future", "final_image"]
510
+ };
511
+ const suggestedFlows = flowMap[intent] || [
512
+ "advance_narrative",
513
+ "update_arc_position"
514
+ ];
515
+ const dramaticTension = calculateDramaticTension(intent, content);
516
+ const context = {
517
+ act,
518
+ narrativeFunction,
519
+ dramaticTension,
520
+ suggestedNextBeat: suggestNextBeat(intent),
521
+ characterImpact: assessCharacterImpact(content),
522
+ themeResonance: assessThemeResonance(content),
523
+ pacingSuggestion: suggestPacing(intent, dramaticTension)
524
+ };
525
+ const perspective = createUniversePerspective(
526
+ "story_engine" /* STORY_ENGINE */,
527
+ intent,
528
+ confidence,
529
+ { suggestedFlows, context }
530
+ );
531
+ return { ...state, storyEnginePerspective: perspective };
532
+ }
533
+ function calculateDramaticTension(intent, content) {
534
+ const baseTension = {
535
+ inciting_incident: 0.4,
536
+ rising_action: 0.5,
537
+ turning_point: 0.7,
538
+ complication: 0.6,
539
+ crisis: 0.9,
540
+ climax: 1,
541
+ resolution: 0.4,
542
+ denouement: 0.2
543
+ };
544
+ let tension = baseTension[intent] || 0.5;
545
+ const contentLower = content.toLowerCase();
546
+ if (["urgent", "critical", "breaking"].some((w) => contentLower.includes(w))) {
547
+ tension = Math.min(1, tension + 0.2);
548
+ }
549
+ if (["minor", "small", "trivial"].some((w) => contentLower.includes(w))) {
550
+ tension = Math.max(0.1, tension - 0.2);
551
+ }
552
+ return Math.round(tension * 100) / 100;
553
+ }
554
+ function suggestNextBeat(currentIntent) {
555
+ const nextBeatMap = {
556
+ inciting_incident: "rising_action",
557
+ rising_action: "complication",
558
+ turning_point: "rising_action",
559
+ complication: "crisis",
560
+ crisis: "climax",
561
+ climax: "resolution",
562
+ resolution: "denouement",
563
+ denouement: "inciting_incident"
564
+ // New cycle
565
+ };
566
+ return nextBeatMap[currentIntent] || "rising_action";
567
+ }
568
+ function assessCharacterImpact(content) {
569
+ const contentLower = content.toLowerCase();
570
+ if (["transform", "change", "grow", "learn"].some(
571
+ (w) => contentLower.includes(w)
572
+ )) {
573
+ return "transformative";
574
+ }
575
+ if (["challenge", "struggle", "overcome"].some(
576
+ (w) => contentLower.includes(w)
577
+ )) {
578
+ return "character_testing";
579
+ }
580
+ if (["connect", "relationship", "team"].some((w) => contentLower.includes(w))) {
581
+ return "relational";
582
+ }
583
+ return "incremental";
584
+ }
585
+ function assessThemeResonance(content) {
586
+ const contentLower = content.toLowerCase();
587
+ const themes = [];
588
+ if (["together", "team", "collaborate"].some((w) => contentLower.includes(w))) {
589
+ themes.push("collaboration");
590
+ }
591
+ if (["integrate", "connect", "bridge"].some((w) => contentLower.includes(w))) {
592
+ themes.push("integration");
593
+ }
594
+ if (["coherent", "consistent", "unified"].some(
595
+ (w) => contentLower.includes(w)
596
+ )) {
597
+ themes.push("coherence");
598
+ }
599
+ if (["transform", "change", "evolve"].some((w) => contentLower.includes(w))) {
600
+ themes.push("transformation");
601
+ }
602
+ return themes.length > 0 ? themes.join(", ") : "development";
603
+ }
604
+ function suggestPacing(intent, tension) {
605
+ if (tension > 0.8) return "accelerate";
606
+ if (tension < 0.3) return "breathe";
607
+ if (intent === "inciting_incident" || intent === "climax") return "emphasize";
608
+ return "steady";
609
+ }
610
+ function synthesizePerspectives(state) {
611
+ const engineer = state.engineerPerspective;
612
+ const ceremony = state.ceremonyPerspective;
613
+ const storyEngine = state.storyEnginePerspective;
614
+ if (!engineer || !ceremony || !storyEngine) {
615
+ return {
616
+ ...state,
617
+ error: "Missing one or more perspectives"
618
+ };
619
+ }
620
+ const lead = determineLeadUniverse(engineer, ceremony, storyEngine);
621
+ const coherence = calculateCoherence(engineer, ceremony, storyEngine);
622
+ const analysis = createThreeUniverseAnalysis(
623
+ engineer,
624
+ ceremony,
625
+ storyEngine,
626
+ lead,
627
+ coherence
628
+ );
629
+ return {
630
+ ...state,
631
+ analysis,
632
+ leadUniverse: lead,
633
+ coherenceScore: coherence
634
+ };
635
+ }
636
+ function determineLeadUniverse(engineer, ceremony, storyEngine) {
637
+ const ceremonyContext = ceremony.context;
638
+ if (ceremonyContext.witnessingNeeded) {
639
+ return "ceremony" /* CEREMONY */;
640
+ }
641
+ if (ceremonyContext.isCollaborative) {
642
+ return "ceremony" /* CEREMONY */;
643
+ }
644
+ const storyContext = storyEngine.context;
645
+ if (storyContext.dramaticTension > 0.8) {
646
+ return "story_engine" /* STORY_ENGINE */;
647
+ }
648
+ if (storyContext.narrativeFunction === "climax" || storyContext.narrativeFunction === "turning_point") {
649
+ return "story_engine" /* STORY_ENGINE */;
650
+ }
651
+ const engineerContext = engineer.context;
652
+ if (engineerContext.estimatedComplexity === "high") {
653
+ return "engineer" /* ENGINEER */;
654
+ }
655
+ if (engineer.intent === "security" || engineer.intent === "bug_fix") {
656
+ return "engineer" /* ENGINEER */;
657
+ }
658
+ const perspectives = [
659
+ [engineer, "engineer" /* ENGINEER */],
660
+ [ceremony, "ceremony" /* CEREMONY */],
661
+ [storyEngine, "story_engine" /* STORY_ENGINE */]
662
+ ];
663
+ return perspectives.reduce(
664
+ (a, b) => a[0].confidence > b[0].confidence ? a : b
665
+ )[1];
666
+ }
667
+ function calculateCoherence(engineer, ceremony, storyEngine) {
668
+ const avgConfidence = (engineer.confidence + ceremony.confidence + storyEngine.confidence) / 3;
669
+ let bonus = 0;
670
+ const engineerUrgent = ["security", "bug_fix", "performance"].includes(
671
+ engineer.intent
672
+ );
673
+ const ceremonyUrgent = ceremony.context.senderEnergy === "urgent_flow";
674
+ const storyUrgent = storyEngine.context.dramaticTension > 0.7;
675
+ if ([engineerUrgent, ceremonyUrgent, storyUrgent].filter(Boolean).length >= 2) {
676
+ bonus += 0.1;
677
+ }
678
+ const confidences = [
679
+ engineer.confidence,
680
+ ceremony.confidence,
681
+ storyEngine.confidence
682
+ ];
683
+ const confidenceSpread = Math.max(...confidences) - Math.min(...confidences);
684
+ const penalty = confidenceSpread * 0.2;
685
+ const coherence = avgConfidence + bonus - penalty;
686
+ return Math.round(Math.max(0, Math.min(1, coherence)) * 100) / 100;
687
+ }
688
+ var ThreeUniverseProcessor = class {
689
+ tracingCallback;
690
+ constructor(options = {}) {
691
+ this.tracingCallback = options.tracingCallback;
692
+ }
693
+ /**
694
+ * Process an event through all three universes.
695
+ *
696
+ * @param event The event data (webhook payload, user input, etc.)
697
+ * @param eventType Type of event (e.g., "github.push", "user.input")
698
+ * @returns ThreeUniverseAnalysis with all perspectives and synthesis
699
+ */
700
+ process(event, eventType = "unknown") {
701
+ let state = {
702
+ event,
703
+ eventType
704
+ };
705
+ state = analyzeEngineerPerspective(state);
706
+ state = analyzeCeremonyPerspective(state);
707
+ state = analyzeStoryEnginePerspective(state);
708
+ state = synthesizePerspectives(state);
709
+ if (state.error) {
710
+ throw new Error(`Processing error: ${state.error}`);
711
+ }
712
+ const analysis = state.analysis;
713
+ if (this.tracingCallback && analysis) {
714
+ const eventId = event.eventId || event.id || `${eventType}_${Date.now()}`;
715
+ const eventContent = this.extractEventContent(event);
716
+ this.tracingCallback(
717
+ eventId,
718
+ eventContent,
719
+ perspectiveToRecord(analysis.engineer),
720
+ perspectiveToRecord(analysis.ceremony),
721
+ perspectiveToRecord(analysis.storyEngine),
722
+ analysis.leadUniverse,
723
+ analysis.coherenceScore
724
+ );
725
+ }
726
+ return analysis;
727
+ }
728
+ extractEventContent(event) {
729
+ if (event.content) {
730
+ return String(event.content).slice(0, 500);
731
+ }
732
+ const payload = event.payload;
733
+ if (payload && typeof payload === "object") {
734
+ const issue = payload.issue;
735
+ if (issue?.title) return issue.title;
736
+ const pr = payload.pull_request;
737
+ if (pr?.title) return pr.title;
738
+ const comment = payload.comment;
739
+ if (comment?.body) return comment.body.slice(0, 500);
740
+ }
741
+ if (event.message) {
742
+ return String(event.message).slice(0, 500);
743
+ }
744
+ return `Event: ${event.eventType || "unknown"}`;
745
+ }
746
+ /**
747
+ * Convenience method for processing GitHub webhooks.
748
+ */
749
+ processWebhook(webhookPayload) {
750
+ let eventType = "github.push";
751
+ const payload = webhookPayload.payload;
752
+ if (payload) {
753
+ if (payload.issue) {
754
+ eventType = "github.issue";
755
+ } else if (payload.pull_request) {
756
+ eventType = "github.pull_request";
757
+ } else if (payload.comment) {
758
+ eventType = "github.comment";
759
+ }
760
+ }
761
+ return this.process(webhookPayload, eventType);
762
+ }
763
+ /**
764
+ * Create a story beat from event and analysis.
765
+ */
766
+ createBeatFromAnalysis(event, analysis, sequence) {
767
+ const functionMap = {
768
+ inciting_incident: "inciting_incident" /* INCITING_INCIDENT */,
769
+ rising_action: "rising_action" /* RISING_ACTION */,
770
+ turning_point: "turning_point" /* TURNING_POINT */,
771
+ complication: "complication" /* COMPLICATION */,
772
+ crisis: "crisis" /* CRISIS */,
773
+ climax: "climax" /* CLIMAX */,
774
+ resolution: "resolution" /* RESOLUTION */,
775
+ denouement: "denouement" /* DENOUEMENT */
776
+ };
777
+ const storyIntent = analysis.storyEngine.intent;
778
+ const narrativeFunc = functionMap[storyIntent] || "beat" /* BEAT */;
779
+ const act = analysis.storyEngine.context.act || 2;
780
+ let content = extractContent(event);
781
+ if (!content) {
782
+ content = String(event.eventType || "event");
783
+ }
784
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
785
+ const beatId = `beat_${timestamp}`;
786
+ let sourceEventId;
787
+ const payload = event.payload;
788
+ if (payload) {
789
+ const headCommit = payload.head_commit;
790
+ if (headCommit?.id) {
791
+ sourceEventId = headCommit.id;
792
+ } else if (payload.issue) {
793
+ const issue = payload.issue;
794
+ sourceEventId = String(issue.id);
795
+ } else if (payload.pull_request) {
796
+ const pr = payload.pull_request;
797
+ sourceEventId = String(pr.id);
798
+ }
799
+ }
800
+ return createStoryBeat(beatId, sequence, content.slice(0, 500), narrativeFunc, act, {
801
+ universeAnalysis: analysis,
802
+ leadUniverse: analysis.leadUniverse,
803
+ source: "processor",
804
+ sourceEventId
805
+ });
806
+ }
807
+ };
808
+ function perspectiveToRecord(perspective) {
809
+ return {
810
+ universe: perspective.universe,
811
+ intent: perspective.intent,
812
+ confidence: perspective.confidence,
813
+ suggestedFlows: perspective.suggestedFlows,
814
+ context: perspective.context
815
+ };
816
+ }
817
+
818
+ // src/graphs/coherence_engine.ts
819
+ var GapType = /* @__PURE__ */ ((GapType2) => {
820
+ GapType2["STRUCTURAL"] = "structural";
821
+ GapType2["THEMATIC"] = "thematic";
822
+ GapType2["CHARACTER"] = "character";
823
+ GapType2["SENSORY"] = "sensory";
824
+ GapType2["CONTINUITY"] = "continuity";
825
+ return GapType2;
826
+ })(GapType || {});
827
+ var GapSeverity = /* @__PURE__ */ ((GapSeverity2) => {
828
+ GapSeverity2["CRITICAL"] = "critical";
829
+ GapSeverity2["MODERATE"] = "moderate";
830
+ GapSeverity2["MINOR"] = "minor";
831
+ return GapSeverity2;
832
+ })(GapSeverity || {});
833
+ var RoutingTarget = /* @__PURE__ */ ((RoutingTarget2) => {
834
+ RoutingTarget2["STORYTELLER"] = "storyteller";
835
+ RoutingTarget2["STRUCTURIST"] = "structurist";
836
+ RoutingTarget2["ARCHITECT"] = "architect";
837
+ RoutingTarget2["AUTHOR"] = "author";
838
+ return RoutingTarget2;
839
+ })(RoutingTarget || {});
840
+ function createGap(id, gapType, severity, description, suggestedRoute, options = {}) {
841
+ return {
842
+ id,
843
+ gapType,
844
+ severity,
845
+ description,
846
+ location: options.location ?? {},
847
+ suggestedRoute,
848
+ resolved: options.resolved ?? false,
849
+ resolution: options.resolution
850
+ };
851
+ }
852
+ function createComponentScore(score, status, options = {}) {
853
+ return {
854
+ score,
855
+ status,
856
+ issues: options.issues ?? [],
857
+ suggestions: options.suggestions ?? []
858
+ };
859
+ }
860
+ function createCoherenceScore(overall, narrativeFlow, characterConsistency, pacing, themeSaturation, continuity) {
861
+ return {
862
+ overall,
863
+ narrativeFlow,
864
+ characterConsistency,
865
+ pacing,
866
+ themeSaturation,
867
+ continuity,
868
+ analyzedAt: (/* @__PURE__ */ new Date()).toISOString()
869
+ };
870
+ }
871
+ function createTrinityAssessment(mia, miette, ava8, priorities = []) {
872
+ return { mia, miette, ava8, priorities };
873
+ }
874
+ var NarrativeCoherenceEngine = class {
875
+ strictMode;
876
+ gapCounter;
877
+ constructor(options = {}) {
878
+ this.strictMode = options.strictMode ?? false;
879
+ this.gapCounter = 0;
880
+ }
881
+ generateGapId() {
882
+ this.gapCounter += 1;
883
+ return `gap_${this.gapCounter}`;
884
+ }
885
+ /**
886
+ * Analyze narrative flow - how smoothly the story progresses.
887
+ *
888
+ * Checks:
889
+ * - Beat transitions (jarring vs smooth)
890
+ * - Logical causality between beats
891
+ * - Pacing consistency
892
+ */
893
+ analyzeNarrativeFlow(state) {
894
+ const beats = state.beats;
895
+ const issues = [];
896
+ const suggestions = [];
897
+ let score;
898
+ let status;
899
+ if (beats.length < 2) {
900
+ score = 50;
901
+ issues.push("Too few beats to assess flow");
902
+ suggestions.push("Add more story beats to establish narrative rhythm");
903
+ } else {
904
+ const functions = beats.map((b) => b.narrativeFunction);
905
+ let hasProperStructure = false;
906
+ for (let i = 0; i < functions.length; i++) {
907
+ const func = functions[i];
908
+ if (["setup", "introduction", "discovery"].includes(func)) {
909
+ hasProperStructure = true;
910
+ break;
911
+ } else if (["confrontation", "crisis", "climax"].includes(func)) {
912
+ if (!hasProperStructure) {
913
+ issues.push(`Beat ${i + 1} escalates without proper setup`);
914
+ hasProperStructure = true;
915
+ }
916
+ }
917
+ }
918
+ let prevTone;
919
+ let jarringTransitions = 0;
920
+ for (let i = 0; i < beats.length; i++) {
921
+ const beat = beats[i];
922
+ if (prevTone && beat.emotionalTone) {
923
+ const jarringPairs = [
924
+ ["devastating", "joyful"],
925
+ ["fearful", "peaceful"],
926
+ ["triumphant", "devastating"]
927
+ ];
928
+ for (const [p1, p2] of jarringPairs) {
929
+ if (prevTone.toLowerCase().includes(p1) && beat.emotionalTone.toLowerCase().includes(p2) || prevTone.toLowerCase().includes(p2) && beat.emotionalTone.toLowerCase().includes(p1)) {
930
+ jarringTransitions += 1;
931
+ issues.push(`Jarring emotional transition at Beat ${i + 1}`);
932
+ }
933
+ }
934
+ }
935
+ prevTone = beat.emotionalTone;
936
+ }
937
+ let baseScore = 85;
938
+ baseScore -= jarringTransitions * 10;
939
+ baseScore -= issues.filter((i) => i.includes("without proper setup")).length * 15;
940
+ score = Math.max(0, Math.min(100, baseScore));
941
+ if (jarringTransitions > 0) {
942
+ suggestions.push("Add transitional beats to smooth emotional shifts");
943
+ }
944
+ if (!hasProperStructure) {
945
+ suggestions.push(
946
+ "Consider adding setup beats before major confrontations"
947
+ );
948
+ }
949
+ }
950
+ if (score >= 70) {
951
+ status = "good";
952
+ } else if (score >= 50) {
953
+ status = "warning";
954
+ } else {
955
+ status = "critical";
956
+ }
957
+ state.narrativeFlowScore = createComponentScore(score, status, {
958
+ issues,
959
+ suggestions
960
+ });
961
+ return state;
962
+ }
963
+ /**
964
+ * Analyze character consistency across the narrative.
965
+ *
966
+ * Checks:
967
+ * - Character voice consistency
968
+ * - Arc progression logic
969
+ * - Relationship evolution coherence
970
+ */
971
+ analyzeCharacterConsistency(state) {
972
+ const beats = state.beats;
973
+ const characters = state.characters;
974
+ const issues = [];
975
+ const suggestions = [];
976
+ let score;
977
+ let status;
978
+ if (characters.length === 0) {
979
+ score = 50;
980
+ issues.push("No character data provided");
981
+ suggestions.push("Define character states to enable consistency analysis");
982
+ } else {
983
+ const characterBeats = {};
984
+ for (const char of characters) {
985
+ characterBeats[char.id] = [];
986
+ }
987
+ for (let i = 0; i < beats.length; i++) {
988
+ const beat = beats[i];
989
+ if (beat.characterId && characterBeats[beat.characterId]) {
990
+ characterBeats[beat.characterId].push(i);
991
+ }
992
+ }
993
+ for (const [charId, appearances] of Object.entries(characterBeats)) {
994
+ if (appearances.length >= 2) {
995
+ for (let i = 1; i < appearances.length; i++) {
996
+ const gap = appearances[i] - appearances[i - 1];
997
+ if (gap > 5) {
998
+ const char = characters.find((c) => c.id === charId);
999
+ const name = char?.name || charId;
1000
+ issues.push(`Character '${name}' disappears for ${gap} beats`);
1001
+ suggestions.push(
1002
+ `Consider adding '${name}' to beats between ${appearances[i - 1] + 1} and ${appearances[i] + 1}`
1003
+ );
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ for (const char of characters) {
1009
+ if (char.arcPosition < 0.1 && beats.length > 5) {
1010
+ issues.push(`Character '${char.name}' has minimal arc progression`);
1011
+ }
1012
+ }
1013
+ let baseScore = 90;
1014
+ baseScore -= issues.filter((i) => i.includes("disappears")).length * 8;
1015
+ baseScore -= issues.filter((i) => i.includes("minimal arc")).length * 12;
1016
+ score = Math.max(0, Math.min(100, baseScore));
1017
+ }
1018
+ if (score >= 70) {
1019
+ status = "good";
1020
+ } else if (score >= 50) {
1021
+ status = "warning";
1022
+ } else {
1023
+ status = "critical";
1024
+ }
1025
+ state.characterConsistencyScore = createComponentScore(score, status, {
1026
+ issues,
1027
+ suggestions
1028
+ });
1029
+ return state;
1030
+ }
1031
+ /**
1032
+ * Analyze narrative pacing.
1033
+ *
1034
+ * Checks:
1035
+ * - Tension/relief distribution
1036
+ * - Beat density per section
1037
+ * - Climax positioning
1038
+ */
1039
+ analyzePacing(state) {
1040
+ const beats = state.beats;
1041
+ const issues = [];
1042
+ const suggestions = [];
1043
+ let score;
1044
+ let status;
1045
+ if (beats.length < 3) {
1046
+ score = 50;
1047
+ issues.push("Too few beats to assess pacing");
1048
+ suggestions.push("Add more beats to establish proper pacing rhythm");
1049
+ } else {
1050
+ const functions = beats.map((b) => b.narrativeFunction.toLowerCase());
1051
+ const climaxPositions = functions.map((f, i) => f.includes("climax") ? i : -1).filter((i) => i >= 0);
1052
+ if (climaxPositions.length === 0) {
1053
+ issues.push("No climax beat identified");
1054
+ suggestions.push("Ensure at least one beat has a climax function");
1055
+ } else {
1056
+ const lastClimax = climaxPositions[climaxPositions.length - 1];
1057
+ const total = beats.length;
1058
+ if (lastClimax < total * 0.5) {
1059
+ issues.push("Climax occurs too early in the narrative");
1060
+ suggestions.push(
1061
+ "Move climax to later in the story or add post-climax resolution beats"
1062
+ );
1063
+ }
1064
+ }
1065
+ const highTensionFuncs = [
1066
+ "confrontation",
1067
+ "crisis",
1068
+ "climax",
1069
+ "revelation"
1070
+ ];
1071
+ let consecutiveHigh = 0;
1072
+ let maxConsecutive = 0;
1073
+ for (const func of functions) {
1074
+ if (highTensionFuncs.some((ht) => func.includes(ht))) {
1075
+ consecutiveHigh += 1;
1076
+ maxConsecutive = Math.max(maxConsecutive, consecutiveHigh);
1077
+ } else {
1078
+ consecutiveHigh = 0;
1079
+ }
1080
+ }
1081
+ if (maxConsecutive > 3) {
1082
+ issues.push(
1083
+ `Found ${maxConsecutive} consecutive high-tension beats`
1084
+ );
1085
+ suggestions.push(
1086
+ "Add breathing room with quieter beats between intense moments"
1087
+ );
1088
+ }
1089
+ let baseScore = 85;
1090
+ if (climaxPositions.length === 0) {
1091
+ baseScore -= 20;
1092
+ } else if (climaxPositions[climaxPositions.length - 1] < beats.length * 0.5) {
1093
+ baseScore -= 15;
1094
+ }
1095
+ baseScore -= Math.min(20, maxConsecutive * 5);
1096
+ score = Math.max(0, Math.min(100, baseScore));
1097
+ }
1098
+ if (score >= 70) {
1099
+ status = "good";
1100
+ } else if (score >= 50) {
1101
+ status = "warning";
1102
+ } else {
1103
+ status = "critical";
1104
+ }
1105
+ state.pacingScore = createComponentScore(score, status, {
1106
+ issues,
1107
+ suggestions
1108
+ });
1109
+ return state;
1110
+ }
1111
+ /**
1112
+ * Analyze how well themes permeate the narrative.
1113
+ *
1114
+ * Checks:
1115
+ * - Theme presence across beats
1116
+ * - Theme introduction and payoff
1117
+ * - Theme strength consistency
1118
+ */
1119
+ analyzeThemeSaturation(state) {
1120
+ const beats = state.beats;
1121
+ const themes = state.themes;
1122
+ const issues = [];
1123
+ const suggestions = [];
1124
+ let score;
1125
+ let status;
1126
+ if (themes.length === 0) {
1127
+ score = 50;
1128
+ issues.push("No themes defined");
1129
+ suggestions.push(
1130
+ "Define thematic threads to enable saturation analysis"
1131
+ );
1132
+ } else {
1133
+ const themeCoverage = {};
1134
+ for (const theme of themes) {
1135
+ let beatsWithTheme = 0;
1136
+ for (const beat of beats) {
1137
+ if (beat.thematicTags?.includes(theme.id)) {
1138
+ beatsWithTheme += 1;
1139
+ }
1140
+ }
1141
+ const coverage = beatsWithTheme / Math.max(beats.length, 1);
1142
+ themeCoverage[theme.name] = coverage;
1143
+ if (coverage < 0.2 && theme.strength > 0.5) {
1144
+ issues.push(
1145
+ `Theme '${theme.name}' is important but appears rarely`
1146
+ );
1147
+ suggestions.push(
1148
+ `Weave '${theme.name}' into more beats to fulfill its promise`
1149
+ );
1150
+ }
1151
+ if (coverage > 0.3 && theme.strength < 0.3) {
1152
+ issues.push(
1153
+ `Theme '${theme.name}' appears often but lacks impact`
1154
+ );
1155
+ suggestions.push(
1156
+ `Strengthen the thematic weight of '${theme.name}' in key beats`
1157
+ );
1158
+ }
1159
+ }
1160
+ const coverageValues = Object.values(themeCoverage);
1161
+ const avgCoverage = coverageValues.reduce((a, b) => a + b, 0) / Math.max(coverageValues.length, 1);
1162
+ let baseScore = Math.min(100, avgCoverage * 100 + 20);
1163
+ baseScore -= issues.filter((i) => i.includes("rarely")).length * 10;
1164
+ baseScore -= issues.filter((i) => i.includes("lacks impact")).length * 8;
1165
+ score = Math.max(0, Math.min(100, baseScore));
1166
+ }
1167
+ if (score >= 70) {
1168
+ status = "good";
1169
+ } else if (score >= 50) {
1170
+ status = "warning";
1171
+ } else {
1172
+ status = "critical";
1173
+ }
1174
+ state.themeSaturationScore = createComponentScore(score, status, {
1175
+ issues,
1176
+ suggestions
1177
+ });
1178
+ return state;
1179
+ }
1180
+ /**
1181
+ * Analyze narrative continuity.
1182
+ *
1183
+ * Checks:
1184
+ * - Timeline consistency
1185
+ * - Detail consistency across beats
1186
+ * - Setting/location coherence
1187
+ */
1188
+ analyzeContinuity(state) {
1189
+ const beats = state.beats;
1190
+ const issues = [];
1191
+ const suggestions = [];
1192
+ let score;
1193
+ let status;
1194
+ if (beats.length < 2) {
1195
+ score = 70;
1196
+ issues.push("Too few beats for continuity analysis");
1197
+ } else {
1198
+ const sequences = beats.map((b) => b.sequence);
1199
+ const sortedSequences = [...sequences].sort((a, b) => a - b);
1200
+ if (JSON.stringify(sequences) !== JSON.stringify(sortedSequences)) {
1201
+ issues.push("Beat sequences are not in order");
1202
+ suggestions.push("Reorder beats to ensure logical sequence progression");
1203
+ }
1204
+ if (sequences.length !== new Set(sequences).size) {
1205
+ issues.push("Duplicate beat sequence numbers found");
1206
+ suggestions.push("Ensure each beat has a unique sequence number");
1207
+ }
1208
+ const maxSeq = Math.max(...sequences);
1209
+ const expected = new Set(
1210
+ Array.from({ length: maxSeq }, (_, i) => i + 1)
1211
+ );
1212
+ const actual = new Set(sequences);
1213
+ const missing = [...expected].filter((x) => !actual.has(x));
1214
+ if (missing.length > 0 && missing.length <= 3) {
1215
+ issues.push(`Missing beat sequences: ${missing.sort().join(", ")}`);
1216
+ suggestions.push("Fill in missing beat sequences or renumber");
1217
+ }
1218
+ let baseScore = 90;
1219
+ baseScore -= issues.filter((i) => i.includes("not in order")).length * 20;
1220
+ baseScore -= issues.filter((i) => i.includes("Duplicate")).length * 15;
1221
+ baseScore -= issues.filter((i) => i.includes("Missing")).length * 5;
1222
+ score = Math.max(0, Math.min(100, baseScore));
1223
+ }
1224
+ if (score >= 70) {
1225
+ status = "good";
1226
+ } else if (score >= 50) {
1227
+ status = "warning";
1228
+ } else {
1229
+ status = "critical";
1230
+ }
1231
+ state.continuityScore = createComponentScore(score, status, {
1232
+ issues,
1233
+ suggestions
1234
+ });
1235
+ return state;
1236
+ }
1237
+ /**
1238
+ * Calculate the overall coherence score from components.
1239
+ */
1240
+ calculateOverallScore(state) {
1241
+ const components = [
1242
+ state.narrativeFlowScore,
1243
+ state.characterConsistencyScore,
1244
+ state.pacingScore,
1245
+ state.themeSaturationScore,
1246
+ state.continuityScore
1247
+ ];
1248
+ const validScores = components.filter((c) => c !== void 0).map((c) => c.score);
1249
+ if (validScores.length > 0) {
1250
+ const weights = [1.2, 1.2, 1, 1, 0.8];
1251
+ const weightedSum = validScores.reduce(
1252
+ (sum, s, i) => sum + s * weights[i],
1253
+ 0
1254
+ );
1255
+ const totalWeight = weights.slice(0, validScores.length).reduce((a, b) => a + b, 0);
1256
+ state.overallScore = weightedSum / totalWeight;
1257
+ } else {
1258
+ state.overallScore = 50;
1259
+ }
1260
+ return state;
1261
+ }
1262
+ /**
1263
+ * Identify narrative gaps from component analyses.
1264
+ */
1265
+ identifyGaps(state) {
1266
+ const gaps = [];
1267
+ const componentMappings = [
1268
+ ["narrativeFlowScore", "structural" /* STRUCTURAL */],
1269
+ ["characterConsistencyScore", "character" /* CHARACTER */],
1270
+ ["pacingScore", "structural" /* STRUCTURAL */],
1271
+ ["themeSaturationScore", "thematic" /* THEMATIC */],
1272
+ ["continuityScore", "continuity" /* CONTINUITY */]
1273
+ ];
1274
+ for (const [componentKey, gapType] of componentMappings) {
1275
+ const component = state[componentKey];
1276
+ if (component?.issues) {
1277
+ for (const issue of component.issues) {
1278
+ let severity;
1279
+ if (component.status === "critical") {
1280
+ severity = "critical" /* CRITICAL */;
1281
+ } else if (issue.includes("rarely") || issue.includes("disappears")) {
1282
+ severity = "moderate" /* MODERATE */;
1283
+ } else {
1284
+ severity = "minor" /* MINOR */;
1285
+ }
1286
+ let route;
1287
+ if (gapType === "structural" /* STRUCTURAL */) {
1288
+ route = "structurist" /* STRUCTURIST */;
1289
+ } else if (gapType === "character" /* CHARACTER */) {
1290
+ route = "storyteller" /* STORYTELLER */;
1291
+ } else if (gapType === "thematic" /* THEMATIC */) {
1292
+ route = "structurist" /* STRUCTURIST */;
1293
+ } else if (gapType === "sensory" /* SENSORY */) {
1294
+ route = "storyteller" /* STORYTELLER */;
1295
+ } else {
1296
+ route = "author" /* AUTHOR */;
1297
+ }
1298
+ gaps.push(
1299
+ createGap(
1300
+ this.generateGapId(),
1301
+ gapType,
1302
+ severity,
1303
+ issue,
1304
+ route,
1305
+ { location: { component: componentKey } }
1306
+ )
1307
+ );
1308
+ }
1309
+ }
1310
+ }
1311
+ const severityOrder = {
1312
+ ["critical" /* CRITICAL */]: 0,
1313
+ ["moderate" /* MODERATE */]: 1,
1314
+ ["minor" /* MINOR */]: 2
1315
+ };
1316
+ gaps.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
1317
+ state.gaps = gaps;
1318
+ return state;
1319
+ }
1320
+ /**
1321
+ * Generate Trinity perspective assessment (Mia/Miette/Ava8).
1322
+ *
1323
+ * Each persona provides feedback aligned with their perspective:
1324
+ * - Mia 🧠: Structural/logical analysis
1325
+ * - Miette 🌸: Emotional/resonance analysis
1326
+ * - Ava8 🎨: Atmospheric/sensory analysis
1327
+ */
1328
+ generateTrinityAssessment(state) {
1329
+ const gaps = state.gaps || [];
1330
+ const flow = state.narrativeFlowScore;
1331
+ const character = state.characterConsistencyScore;
1332
+ const pacing = state.pacingScore;
1333
+ const theme = state.themeSaturationScore;
1334
+ const continuity = state.continuityScore;
1335
+ const miaParts = [];
1336
+ if (flow) {
1337
+ miaParts.push(`Structure is ${flow.score.toFixed(0)}% sound.`);
1338
+ if (flow.issues.length > 0) {
1339
+ miaParts.push(`Key structural gap: ${flow.issues[0]}`);
1340
+ }
1341
+ }
1342
+ if (pacing && pacing.score < 70) {
1343
+ miaParts.push(`Pacing needs attention (${pacing.score.toFixed(0)}%).`);
1344
+ if (pacing.suggestions.length > 0) {
1345
+ miaParts.push(pacing.suggestions[0]);
1346
+ }
1347
+ }
1348
+ if (continuity && continuity.score < 80) {
1349
+ miaParts.push(
1350
+ `Continuity has ${continuity.issues.length} issues to address.`
1351
+ );
1352
+ }
1353
+ const mia = miaParts.length > 0 ? miaParts.join(" ") : "Structure analysis unavailable.";
1354
+ const mietteParts = [];
1355
+ if (character) {
1356
+ if (character.score >= 80) {
1357
+ mietteParts.push("Character arcs are resonating well.");
1358
+ } else {
1359
+ mietteParts.push(
1360
+ `Character consistency is ${character.score.toFixed(0)}%.`
1361
+ );
1362
+ if (character.issues.length > 0) {
1363
+ mietteParts.push(`The emotional gap: ${character.issues[0]}`);
1364
+ }
1365
+ }
1366
+ }
1367
+ if (theme) {
1368
+ if (theme.score >= 70) {
1369
+ mietteParts.push("Themes are landing with emotional weight.");
1370
+ } else {
1371
+ mietteParts.push("Themes need stronger emotional anchoring.");
1372
+ }
1373
+ }
1374
+ if (flow?.issues) {
1375
+ const jarring = flow.issues.filter((i) => i.includes("Jarring"));
1376
+ if (jarring.length > 0) {
1377
+ mietteParts.push("Emotional transitions feel abrupt in places.");
1378
+ }
1379
+ }
1380
+ const miette = mietteParts.length > 0 ? mietteParts.join(" ") : "Emotional analysis unavailable.";
1381
+ const ava8Parts = [];
1382
+ const sensoryGaps = gaps.filter((g) => g.gapType === "sensory" /* SENSORY */);
1383
+ if (sensoryGaps.length > 0) {
1384
+ ava8Parts.push(`Found ${sensoryGaps.length} sensory gaps to address.`);
1385
+ }
1386
+ if (pacing && pacing.score >= 70) {
1387
+ ava8Parts.push("Atmospheric rhythm feels balanced.");
1388
+ } else {
1389
+ ava8Parts.push("Atmosphere could use more grounding moments.");
1390
+ }
1391
+ if (pacing?.issues.some((i) => i.includes("consecutive high-tension"))) {
1392
+ ava8Parts.push(
1393
+ "The dense tension sections may benefit from visual breathing room."
1394
+ );
1395
+ }
1396
+ const ava8 = ava8Parts.length > 0 ? ava8Parts.join(" ") : "Atmospheric analysis unavailable.";
1397
+ const priorities = [];
1398
+ const criticalGaps = gaps.filter(
1399
+ (g) => g.severity === "critical" /* CRITICAL */
1400
+ );
1401
+ if (criticalGaps.length > 0) {
1402
+ priorities.push(...criticalGaps.slice(0, 3).map((g) => g.description));
1403
+ } else {
1404
+ const moderateGaps = gaps.filter(
1405
+ (g) => g.severity === "moderate" /* MODERATE */
1406
+ );
1407
+ if (moderateGaps.length > 0) {
1408
+ priorities.push(
1409
+ ...moderateGaps.slice(0, 3).map((g) => g.description)
1410
+ );
1411
+ }
1412
+ }
1413
+ if (priorities.length === 0) {
1414
+ priorities.push("Minor polish items only - narrative is coherent");
1415
+ }
1416
+ state.trinityAssessment = createTrinityAssessment(
1417
+ mia,
1418
+ miette,
1419
+ ava8,
1420
+ priorities
1421
+ );
1422
+ return state;
1423
+ }
1424
+ /**
1425
+ * Build the final coherence result object.
1426
+ */
1427
+ buildCoherenceResult(state) {
1428
+ state.coherenceScore = createCoherenceScore(
1429
+ state.overallScore || 50,
1430
+ state.narrativeFlowScore || createComponentScore(50, "warning"),
1431
+ state.characterConsistencyScore || createComponentScore(50, "warning"),
1432
+ state.pacingScore || createComponentScore(50, "warning"),
1433
+ state.themeSaturationScore || createComponentScore(50, "warning"),
1434
+ state.continuityScore || createComponentScore(50, "warning")
1435
+ );
1436
+ return state;
1437
+ }
1438
+ /**
1439
+ * Analyze narrative coherence.
1440
+ *
1441
+ * @param beats List of story beats to analyze
1442
+ * @param characters Optional list of character states
1443
+ * @param themes Optional list of thematic threads
1444
+ * @param includeMetadata Whether to include full analysis state
1445
+ * @returns CoherenceResult with coherenceScore, gaps, and trinityAssessment
1446
+ */
1447
+ analyze(beats, characters = [], themes = [], includeMetadata = false) {
1448
+ let state = {
1449
+ beats,
1450
+ characters,
1451
+ themes
1452
+ };
1453
+ state = this.analyzeNarrativeFlow(state);
1454
+ state = this.analyzeCharacterConsistency(state);
1455
+ state = this.analyzePacing(state);
1456
+ state = this.analyzeThemeSaturation(state);
1457
+ state = this.analyzeContinuity(state);
1458
+ state = this.calculateOverallScore(state);
1459
+ state = this.identifyGaps(state);
1460
+ state = this.generateTrinityAssessment(state);
1461
+ state = this.buildCoherenceResult(state);
1462
+ if (includeMetadata) {
1463
+ return state;
1464
+ } else {
1465
+ return {
1466
+ coherenceScore: state.coherenceScore,
1467
+ gaps: state.gaps || [],
1468
+ trinityAssessment: state.trinityAssessment
1469
+ };
1470
+ }
1471
+ }
1472
+ /**
1473
+ * Group gaps by their routing target.
1474
+ *
1475
+ * @param gaps List of identified gaps
1476
+ * @returns Dictionary mapping routing target to list of gaps
1477
+ */
1478
+ getRoutingSuggestions(gaps) {
1479
+ const routing = {
1480
+ ["storyteller" /* STORYTELLER */]: [],
1481
+ ["structurist" /* STRUCTURIST */]: [],
1482
+ ["architect" /* ARCHITECT */]: [],
1483
+ ["author" /* AUTHOR */]: []
1484
+ };
1485
+ for (const gap of gaps) {
1486
+ routing[gap.suggestedRoute].push(gap);
1487
+ }
1488
+ return routing;
1489
+ }
1490
+ };
1491
+ // Annotate the CommonJS export names for ESM import in node:
1492
+ 0 && (module.exports = {
1493
+ EventType,
1494
+ GapSeverity,
1495
+ GapType,
1496
+ NarrativeCoherenceEngine,
1497
+ RoutingTarget,
1498
+ ThreeUniverseProcessor,
1499
+ analyzeCeremonyPerspective,
1500
+ analyzeEngineerPerspective,
1501
+ analyzeStoryEnginePerspective,
1502
+ ceremonyIntentKeywords,
1503
+ createCoherenceScore,
1504
+ createComponentScore,
1505
+ createGap,
1506
+ createTrinityAssessment,
1507
+ engineerIntentKeywords,
1508
+ storyEngineIntentKeywords,
1509
+ synthesizePerspectives
1510
+ });
1511
+ //# sourceMappingURL=index.cjs.map