@narrative-os/engine 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 (71) hide show
  1. package/dist/agents/canonValidator.d.ts +9 -0
  2. package/dist/agents/canonValidator.js +51 -0
  3. package/dist/agents/chapterPlanner.d.ts +50 -0
  4. package/dist/agents/chapterPlanner.js +250 -0
  5. package/dist/agents/completeness.d.ts +7 -0
  6. package/dist/agents/completeness.js +51 -0
  7. package/dist/agents/memoryExtractor.d.ts +12 -0
  8. package/dist/agents/memoryExtractor.js +82 -0
  9. package/dist/agents/stateUpdater.d.ts +30 -0
  10. package/dist/agents/stateUpdater.js +150 -0
  11. package/dist/agents/storyDirector.d.ts +40 -0
  12. package/dist/agents/storyDirector.js +213 -0
  13. package/dist/agents/summarizer.d.ts +8 -0
  14. package/dist/agents/summarizer.js +56 -0
  15. package/dist/agents/tensionController.d.ts +68 -0
  16. package/dist/agents/tensionController.js +197 -0
  17. package/dist/agents/writer.d.ts +12 -0
  18. package/dist/agents/writer.js +148 -0
  19. package/dist/constraints/constraintGraph.d.ts +117 -0
  20. package/dist/constraints/constraintGraph.js +381 -0
  21. package/dist/constraints/validator.d.ts +58 -0
  22. package/dist/constraints/validator.js +236 -0
  23. package/dist/index.d.ts +25 -0
  24. package/dist/index.js +115 -0
  25. package/dist/llm/client.d.ts +14 -0
  26. package/dist/llm/client.js +108 -0
  27. package/dist/memory/canonStore.d.ts +20 -0
  28. package/dist/memory/canonStore.js +110 -0
  29. package/dist/memory/memoryRetriever.d.ts +28 -0
  30. package/dist/memory/memoryRetriever.js +126 -0
  31. package/dist/memory/stateUpdater.d.ts +49 -0
  32. package/dist/memory/stateUpdater.js +315 -0
  33. package/dist/memory/vectorStore.d.ts +41 -0
  34. package/dist/memory/vectorStore.js +166 -0
  35. package/dist/pipeline/generateChapter.d.ts +17 -0
  36. package/dist/pipeline/generateChapter.js +75 -0
  37. package/dist/story/bible.d.ts +4 -0
  38. package/dist/story/bible.js +53 -0
  39. package/dist/story/state.d.ts +3 -0
  40. package/dist/story/state.js +27 -0
  41. package/dist/story/structuredState.d.ts +39 -0
  42. package/dist/story/structuredState.js +159 -0
  43. package/dist/test/canon.test.d.ts +1 -0
  44. package/dist/test/canon.test.js +104 -0
  45. package/dist/test/chapter-planner.test.d.ts +1 -0
  46. package/dist/test/chapter-planner.test.js +171 -0
  47. package/dist/test/constraints.test.d.ts +1 -0
  48. package/dist/test/constraints.test.js +210 -0
  49. package/dist/test/simple.test.d.ts +1 -0
  50. package/dist/test/simple.test.js +51 -0
  51. package/dist/test/state-updater.test.d.ts +1 -0
  52. package/dist/test/state-updater.test.js +200 -0
  53. package/dist/test/story-director.test.d.ts +1 -0
  54. package/dist/test/story-director.test.js +142 -0
  55. package/dist/test/structured-state.test.d.ts +1 -0
  56. package/dist/test/structured-state.test.js +144 -0
  57. package/dist/test/tension-controller.test.d.ts +1 -0
  58. package/dist/test/tension-controller.test.js +116 -0
  59. package/dist/test/vector-memory.test.d.ts +1 -0
  60. package/dist/test/vector-memory.test.js +153 -0
  61. package/dist/test/world-simulation.test.d.ts +1 -0
  62. package/dist/test/world-simulation.test.js +152 -0
  63. package/dist/types/index.d.ts +79 -0
  64. package/dist/types/index.js +3 -0
  65. package/dist/world/characterAgent.d.ts +73 -0
  66. package/dist/world/characterAgent.js +232 -0
  67. package/dist/world/eventResolver.d.ts +52 -0
  68. package/dist/world/eventResolver.js +205 -0
  69. package/dist/world/worldState.d.ts +93 -0
  70. package/dist/world/worldState.js +258 -0
  71. package/package.json +43 -0
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const path_1 = require("path");
5
+ const os_1 = require("os");
6
+ // Load config BEFORE importing engine
7
+ const configPath = (0, path_1.join)((0, os_1.homedir)(), '.narrative-os', 'config.json');
8
+ if ((0, fs_1.existsSync)(configPath)) {
9
+ const config = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
10
+ process.env.LLM_PROVIDER = config.provider;
11
+ process.env.LLM_MODEL = 'deepseek-chat';
12
+ if (config.provider === 'openai') {
13
+ process.env.OPENAI_API_KEY = config.apiKey;
14
+ }
15
+ else if (config.provider === 'deepseek') {
16
+ process.env.DEEPSEEK_API_KEY = config.apiKey;
17
+ }
18
+ console.log(`Loaded config: ${config.provider} / deepseek-chat`);
19
+ }
20
+ const index_js_1 = require("../index.js");
21
+ console.log('Testing Chapter Planner Agent (Phase 7)...\n');
22
+ // Setup test story
23
+ let bible = (0, index_js_1.createStoryBible)('李白传奇', '诗人寻找人生真谛', 'historical-fiction', '唐朝长安及各地', '豪放浪漫', '诗人李白离开长安,游历天下,寻找人生真谛', 10);
24
+ bible = (0, index_js_1.addCharacter)(bible, '李白', 'protagonist', ['豪放', '浪漫', '不羁'], ['寻找人生真谛', '成为伟大诗人']);
25
+ bible = (0, index_js_1.addCharacter)(bible, '杜甫', 'supporting', ['沉郁', '忧国忧民'], ['记录时代变迁']);
26
+ bible = (0, index_js_1.addCharacter)(bible, '高力士', 'antagonist', ['阴险', '权谋'], ['控制李白为朝廷所用']);
27
+ bible = (0, index_js_1.addPlotThread)(bible, '诗人之旅', '李白从长安出发,游历天下');
28
+ bible = (0, index_js_1.addPlotThread)(bible, '宫廷阴谋', '高力士设计控制李白');
29
+ const storyState = (0, index_js_1.createStoryState)('test-story', 10);
30
+ storyState.currentChapter = 4;
31
+ let structuredState = (0, index_js_1.createStructuredState)('test-story');
32
+ structuredState = (0, index_js_1.initializeCharactersFromBible)(structuredState, bible);
33
+ structuredState = (0, index_js_1.initializePlotThreadsFromBible)(structuredState, bible);
34
+ structuredState.tension = 0.5;
35
+ // Activate plot threads
36
+ const threadIds = Object.keys(structuredState.plotThreads);
37
+ if (threadIds[0]) {
38
+ structuredState = (0, index_js_1.updatePlotThread)(structuredState, threadIds[0], { status: 'active', tension: 0.6 }, 4);
39
+ }
40
+ if (threadIds[1]) {
41
+ structuredState = (0, index_js_1.updatePlotThread)(structuredState, threadIds[1], { status: 'escalating', tension: 0.7 }, 4);
42
+ }
43
+ // Add recent events
44
+ structuredState = (0, index_js_1.addRecentEvent)(structuredState, '李白在黄鹤楼与孟浩然告别');
45
+ structuredState = (0, index_js_1.addRecentEvent)(structuredState, '收到宫廷使者传来的密信');
46
+ // Create director output
47
+ const directorOutput = index_js_1.storyDirector.generateFallbackObjectives(storyState, structuredState);
48
+ directorOutput.overallGoal = '李白遭遇宫廷阴谋,与杜甫初次相遇,面临人生抉择';
49
+ directorOutput.tone = '紧张中带有诗意';
50
+ directorOutput.objectives = [
51
+ {
52
+ id: 'obj-1',
53
+ description: '宫廷使者正式传达玄宗召唤,施加压力',
54
+ priority: 'critical',
55
+ type: 'plot',
56
+ relatedPlotThreadId: threadIds[1],
57
+ },
58
+ {
59
+ id: 'obj-2',
60
+ description: '李白与杜甫在江边初次相遇',
61
+ priority: 'high',
62
+ type: 'character',
63
+ relatedCharacter: '杜甫',
64
+ },
65
+ {
66
+ id: 'obj-3',
67
+ description: '展现李白面对召唤的内心挣扎',
68
+ priority: 'high',
69
+ type: 'character',
70
+ relatedCharacter: '李白',
71
+ },
72
+ {
73
+ id: 'obj-4',
74
+ description: '提高章节紧张感至80%',
75
+ priority: 'medium',
76
+ type: 'tension',
77
+ },
78
+ ];
79
+ directorOutput.focusCharacters = ['李白', '杜甫', '高力士'];
80
+ directorOutput.suggestedScenes = [
81
+ '江边送别场景,氛围宁静',
82
+ '宫廷使者突然出现,气氛紧张',
83
+ '李白与杜甫初次对话',
84
+ '李白独自思考,内心挣扎',
85
+ ];
86
+ // Create tension guidance
87
+ const tensionAnalysis = (0, index_js_1.analyzeTension)(storyState, structuredState);
88
+ const tensionGuidance = (0, index_js_1.generateTensionGuidance)(tensionAnalysis, storyState);
89
+ // Test 1: Fallback outline
90
+ console.log('Test 1: Fallback Outline (No LLM)');
91
+ const fallbackOutline = index_js_1.chapterPlanner.generateFallbackOutline(directorOutput, 2500);
92
+ console.log(` Chapter: ${fallbackOutline.chapterNumber}`);
93
+ console.log(` Goal: ${fallbackOutline.overallGoal}`);
94
+ console.log(` Scenes: ${fallbackOutline.scenes.length}`);
95
+ console.log(` Total words: ${fallbackOutline.totalEstimatedWords}`);
96
+ console.log(' Scene breakdown:');
97
+ for (const scene of fallbackOutline.scenes) {
98
+ const bar = '█'.repeat(Math.round(scene.tension * 10)) + '░'.repeat(10 - Math.round(scene.tension * 10));
99
+ console.log(` Scene ${scene.sequence}: [${bar}] ${Math.round(scene.tension * 100)}% - ${scene.goal.substring(0, 40)}...`);
100
+ }
101
+ console.log('✅ Fallback outline generated');
102
+ // Test 2: Format for prompt
103
+ console.log('\nTest 2: Format for Prompt');
104
+ const formatted = index_js_1.chapterPlanner.formatForPrompt(fallbackOutline);
105
+ console.log('--- Formatted Output Preview ---');
106
+ console.log(formatted.substring(0, 800));
107
+ console.log('...');
108
+ console.log('✅ Formatted for writer prompt');
109
+ // Test 3: Validate outline
110
+ console.log('\nTest 3: Validate Outline Coverage');
111
+ const validation = index_js_1.chapterPlanner.validateOutline(fallbackOutline, directorOutput.objectives);
112
+ console.log(` Valid: ${validation.valid}`);
113
+ console.log(` Coverage: ${(validation.coverage * 100).toFixed(0)}%`);
114
+ if (validation.missedObjectives.length > 0) {
115
+ console.log(` Missed: ${validation.missedObjectives.length} objectives`);
116
+ }
117
+ console.log('✅ Outline validated');
118
+ // Test 4: Planner with LLM
119
+ console.log('\nTest 4: Chapter Planner with LLM');
120
+ async function runPlannerTest() {
121
+ try {
122
+ const outline = await index_js_1.chapterPlanner.plan({
123
+ bible,
124
+ state: storyState,
125
+ structuredState,
126
+ directorOutput,
127
+ targetWordCount: 2500,
128
+ });
129
+ console.log('✅ Planner generated scene outline');
130
+ console.log(` Chapter: ${outline.chapterNumber}`);
131
+ console.log(` Goal: ${outline.overallGoal}`);
132
+ console.log(` Tone: ${outline.tone}`);
133
+ console.log(` Scenes: ${outline.scenes.length}`);
134
+ console.log(` Total words: ${outline.totalEstimatedWords}`);
135
+ console.log('\n Scene Details:');
136
+ for (const scene of outline.scenes) {
137
+ const bar = '█'.repeat(Math.round(scene.tension * 10));
138
+ console.log(` ${scene.sequence}. [${bar}] ${scene.goal.substring(0, 45)}...`);
139
+ }
140
+ // Test 5: Format LLM output
141
+ console.log('\nTest 5: Format LLM Output for Prompt');
142
+ const llmFormatted = index_js_1.chapterPlanner.formatForPrompt(outline);
143
+ console.log('--- Formatted LLM Output Preview ---');
144
+ console.log(llmFormatted.substring(0, 1000));
145
+ console.log('...');
146
+ console.log('✅ LLM output formatted');
147
+ // Test 6: Validate LLM outline
148
+ console.log('\nTest 6: Validate LLM Outline');
149
+ const llmValidation = index_js_1.chapterPlanner.validateOutline(outline, directorOutput.objectives);
150
+ console.log(` Valid: ${llmValidation.valid}`);
151
+ console.log(` Coverage: ${(llmValidation.coverage * 100).toFixed(0)}%`);
152
+ console.log('✅ LLM outline validated');
153
+ }
154
+ catch (error) {
155
+ console.log('⚠️ Planner LLM test failed:', error instanceof Error ? error.message : String(error));
156
+ }
157
+ }
158
+ runPlannerTest().then(() => {
159
+ // Test 7: Different word counts
160
+ console.log('\nTest 7: Different Word Counts');
161
+ const shortOutline = index_js_1.chapterPlanner.generateFallbackOutline(directorOutput, 1500);
162
+ console.log(` Short (1500w): ${shortOutline.scenes.length} scenes, ${shortOutline.totalEstimatedWords} words`);
163
+ const mediumOutline = index_js_1.chapterPlanner.generateFallbackOutline(directorOutput, 2500);
164
+ console.log(` Medium (2500w): ${mediumOutline.scenes.length} scenes, ${mediumOutline.totalEstimatedWords} words`);
165
+ const longOutline = index_js_1.chapterPlanner.generateFallbackOutline(directorOutput, 4000);
166
+ console.log(` Long (4000w): ${longOutline.scenes.length} scenes, ${longOutline.totalEstimatedWords} words`);
167
+ console.log('✅ Outline adapts to word count');
168
+ console.log('\n✅ All Chapter Planner tests passed!');
169
+ console.log('\n🎉 Phase 7 (Chapter Planner Agent) tests complete!');
170
+ });
171
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcHRlci1wbGFubmVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC9jaGFwdGVyLXBsYW5uZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJCQUE4QztBQUM5QywrQkFBNEI7QUFDNUIsMkJBQTZCO0FBRTdCLHNDQUFzQztBQUN0QyxNQUFNLFVBQVUsR0FBRyxJQUFBLFdBQUksRUFBQyxJQUFBLFlBQU8sR0FBRSxFQUFFLGVBQWUsRUFBRSxhQUFhLENBQUMsQ0FBQztBQUNuRSxJQUFJLElBQUEsZUFBVSxFQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDM0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFBLGlCQUFZLEVBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDN0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztJQUMzQyxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsR0FBRyxlQUFlLENBQUM7SUFDeEMsSUFBSSxNQUFNLENBQUMsUUFBUSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ2pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDN0MsQ0FBQztTQUFNLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUMxQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDL0MsQ0FBQztJQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLE1BQU0sQ0FBQyxRQUFRLGtCQUFrQixDQUFDLENBQUM7QUFDbkUsQ0FBQztBQUVELDBDQWNxQjtBQUVyQixPQUFPLENBQUMsR0FBRyxDQUFDLDhDQUE4QyxDQUFDLENBQUM7QUFFNUQsbUJBQW1CO0FBQ25CLElBQUksS0FBSyxHQUFHLElB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SCxNQUFNLFdBQVcsR0FBRyx5QkFBYyxDQUFDLHVCQUF1QixDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNqRixPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sWUFBWSxXQUFXLENBQUMsbUJBQW1CLFFBQVEsQ0FBQyxDQUFDO0lBQzdHLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztJQUU5QyxPQUFPLENBQUMsR0FBRyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7SUFDckQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO0FBQ3RFLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCBleGlzdHNTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tICdvcyc7XHJcblxyXG4vLyBMb2FkIGNvbmZpZyBCRUZPUkUgaW1wb3J0aW5nIGVuZ2luZVxyXG5jb25zdCBjb25maWdQYXRoID0gam9pbihob21lZGlyKCksICcubmFycmF0aXZlLW9zJywgJ2NvbmZpZy5qc29uJyk7XHJcbmlmIChleGlzdHNTeW5jKGNvbmZpZ1BhdGgpKSB7XHJcbiAgY29uc3QgY29uZmlnID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0Zi04JykpO1xyXG4gIHByb2Nlc3MuZW52LkxMTV9QUk9WSURFUiA9IGNvbmZpZy5wcm92aWRlcjtcclxuICBwcm9jZXNzLmVudi5MTE1fTU9ERUwgPSAnZGVlcHNlZWstY2hhdCc7XHJcbiAgaWYgKGNvbmZpZy5wcm92aWRlciA9PT0gJ29wZW5haScpIHtcclxuICAgIHByb2Nlc3MuZW52Lk9QRU5BSV9BUElfS0VZID0gY29uZmlnLmFwaUtleTtcclxuICB9IGVsc2UgaWYgKGNvbmZpZy5wcm92aWRlciA9PT0gJ2RlZXBzZWVrJykge1xyXG4gICAgcHJvY2Vzcy5lbnYuREVFUFNFRUtfQVBJX0tFWSA9IGNvbmZpZy5hcGlLZXk7XHJcbiAgfVxyXG4gIGNvbnNvbGUubG9nKGBMb2FkZWQgY29uZmlnOiAke2NvbmZpZy5wcm92aWRlcn0gLyBkZWVwc2Vlay1jaGF0YCk7XHJcbn1cclxuXHJcbmltcG9ydCB7XHJcbiAgY2hhcHRlclBsYW5uZXIsXHJcbiAgc3RvcnlEaXJlY3RvcixcclxuICBjcmVhdGVTdG9yeUJpYmxlLFxyXG4gIGFkZENoYXJhY3RlcixcclxuICBhZGRQbG90VGhyZWFkLFxyXG4gIGNyZWF0ZVN0b3J5U3RhdGUsXHJcbiAgY3JlYXRlU3RydWN0dXJlZFN0YXRlLFxyXG4gIGluaXRpYWxpemVDaGFyYWN0ZXJzRnJvbUJpYmxlLFxyXG4gIGluaXRpYWxpemVQbG90VGhyZWFkc0Zyb21CaWJsZSxcclxuICB1cGRhdGVQbG90VGhyZWFkLFxyXG4gIGFkZFJlY2VudEV2ZW50LFxyXG4gIGdlbmVyYXRlVGVuc2lvbkd1aWRhbmNlLFxyXG4gIGFuYWx5emVUZW5zaW9uLFxyXG59IGZyb20gJy4uL2luZGV4LmpzJztcclxuXHJcbmNvbnNvbGUubG9nKCdUZXN0aW5nIENoYXB0ZXIgUGxhbm5lciBBZ2VudCAoUGhhc2UgNykuLi5cXG4nKTtcclxuXHJcbi8vIFNldHVwIHRlc3Qgc3RvcnlcclxubGV0IGJpYmxlID0gY3JlYXRlU3RvcnlCaWJsZShcclxuICAn5p2O55m95Lyg5aWHJyxcclxuICAn6K+X5Lq65a+75om+5Lq655Sf55yf6LCbJyxcclxuICAnaGlzdG9yaWNhbC1maWN0aW9uJyxcclxuICAn5ZSQ5pyd6ZW/5a6J5Y+K5ZCE5ZywJyxcclxuICAn6LGq5pS+5rWq5ryrJyxcclxuICAn6K+X5Lq65p2O55m956a75byA6ZW/5a6J77yM5ri45Y6G5aSp5LiL77yM5a+75om+5Lq655Sf55yf6LCbJyxcclxuICAxMFxyXG4pO1xyXG5cclxuYmlibGUgPSBhZGRDaGFyYWN0ZXIoYmlibGUsICfmnY7nmb0nLCAncHJvdGFnb25pc3QnLCBbJ+ixquaUvicsICfmtarmvKsnLCAn5LiN576BJ10sIFsn5a+75om+5Lq655Sf55yf6LCbJywgJ+aIkOS4uuS8n+Wkp+ivl+S6uiddKTtcclxuYmlibGUgPSBhZGRDaGFyYWN0ZXIoYmlibGUsICfmnZznlKsnLCAnc3VwcG9ydGluZycsIFsn5rKJ6YOBJywgJ+W/p+WbveW/p+awkSddLCBbJ+iusOW9leaXtuS7o+WPmOi/gSddKTtcclxuYmlibGUgPSBhZGRDaGFyYWN0ZXIoYmlibGUsICfpq5jlipvlo6snLCAnYW50YWdvbmlzdCcsIFsn6Zi06ZmpJywgJ+adg+iwiyddLCBbJ+aOp+WItuadjueZveS4uuacneW7t+aJgOeUqCddKTtcclxuXHJcbmJpYmxlID0gYWRkUGxvdFRocmVhZChiaWJsZSwgJ+ivl+S6uuS5i+aXhScsICfmnY7nmb3ku47plb/lronlh7rlj5HvvIzmuLjljoblpKnkuIsnKTtcclxuYmlibGUgPSBhZGRQbG90VGhyZWFkKGJpYmxlLCAn5a6r5bu36Zi06LCLJywgJ+mrmOWKm+Wjq+iuvuiuoeaOp+WItuadjueZvScpO1xyXG5cclxuY29uc3Qgc3RvcnlTdGF0ZSA9IGNyZWF0ZVN0b3J5U3RhdGUoJ3Rlc3Qtc3RvcnknLCAxMCk7XHJcbnN0b3J5U3RhdGUuY3VycmVudENoYXB0ZXIgPSA0O1xyXG5cclxubGV0IHN0cnVjdHVyZWRTdGF0ZSA9IGNyZWF0ZVN0cnVjdHVyZWRTdGF0ZSgndGVzdC1zdG9yeScpO1xyXG5zdHJ1Y3R1cmVkU3RhdGUgPSBpbml0aWFsaXplQ2hhcmFjdGVyc0Zyb21CaWJsZShzdHJ1Y3R1cmVkU3RhdGUsIGJpYmxlKTtcclxuc3RydWN0dXJlZFN0YXRlID0gaW5pdGlhbGl6ZVBsb3RUaHJlYWRzRnJvbUJpYmxlKHN0cnVjdHVyZWRTdGF0ZSwgYmlibGUpO1xyXG5zdHJ1Y3R1cmVkU3RhdGUudGVuc2lvbiA9IDAuNTtcclxuXHJcbi8vIEFjdGl2YXRlIHBsb3QgdGhyZWFkc1xyXG5jb25zdCB0aHJlYWRJZHMgPSBPYmplY3Qua2V5cyhzdHJ1Y3R1cmVkU3RhdGUucGxvdFRocmVhZHMpO1xyXG5pZiAodGhyZWFkSWRzWzBdKSB7XHJcbiAgc3RydWN0dXJlZFN0YXRlID0gdXBkYXRlUGxvdFRocmVhZChzdHJ1Y3R1cmVkU3RhdGUsIHRocmVhZElkc1swXSwgeyBzdGF0dXM6ICdhY3RpdmUnLCB0ZW5zaW9uOiAwLjYgfSwgNCk7XHJcbn1cclxuaWYgKHRocmVhZElkc1sxXSkge1xyXG4gIHN0cnVjdHVyZWRTdGF0ZSA9IHVwZGF0ZVBsb3RUaHJlYWQoc3RydWN0dXJlZFN0YXRlLCB0aHJlYWRJZHNbMV0sIHsgc3RhdHVzOiAnZXNjYWxhdGluZycsIHRlbnNpb246IDAuNyB9LCA0KTtcclxufVxyXG5cclxuLy8gQWRkIHJlY2VudCBldmVudHNcclxuc3RydWN0dXJlZFN0YXRlID0gYWRkUmVjZW50RXZlbnQoc3RydWN0dXJlZFN0YXRlLCAn5p2O55m95Zyo6buE6bmk5qW85LiO5a2f5rWp54S25ZGK5YirJyk7XHJcbnN0cnVjdHVyZWRTdGF0ZSA9IGFkZFJlY2VudEV2ZW50KHN0cnVjdHVyZWRTdGF0ZSwgJ+aUtuWIsOWuq+W7t+S9v+iAheS8oOadpeeahOWvhuS/oScpO1xyXG5cclxuLy8gQ3JlYXRlIGRpcmVjdG9yIG91dHB1dFxyXG5jb25zdCBkaXJlY3Rvck91dHB1dCA9IHN0b3J5RGlyZWN0b3IuZ2VuZXJhdGVGYWxsYmFja09iamVjdGl2ZXMoc3RvcnlTdGF0ZSwgc3RydWN0dXJlZFN0YXRlKTtcclxuZGlyZWN0b3JPdXRwdXQub3ZlcmFsbEdvYWwgPSAn5p2O55m96YGt6YGH5a6r5bu36Zi06LCL77yM5LiO5p2c55Sr5Yid5qyh55u46YGH77yM6Z2i5Li05Lq655Sf5oqJ5oupJztcclxuZGlyZWN0b3JPdXRwdXQudG9uZSA9ICfntKflvKDkuK3luKbmnInor5fmhI8nO1xyXG5kaXJlY3Rvck91dHB1dC5vYmplY3RpdmVzID0gW1xyXG4gIHtcclxuICAgIGlkOiAnb2JqLTEnLFxyXG4gICAgZGVzY3JpcHRpb246ICflrqvlu7fkvb/ogIXmraPlvI/kvKDovr7njoTlrpflj6zllKTvvIzmlr3liqDljovlipsnLFxyXG4gICAgcHJpb3JpdHk6ICdjcml0aWNhbCcsXHJcbiAgICB0eXBlOiAncGxvdCcsXHJcbiAgICByZWxhdGVkUGxvdFRocmVhZElkOiB0aHJlYWRJZHNbMV0sXHJcbiAgfSxcclxuICB7XHJcbiAgICBpZDogJ29iai0yJyxcclxuICAgIGRlc2NyaXB0aW9uOiAn5p2O55m95LiO5p2c55Sr5Zyo5rGf6L655Yid5qyh55u46YGHJyxcclxuICAgIHByaW9yaXR5OiAnaGlnaCcsXHJcbiAgICB0eXBlOiAnY2hhcmFjdGVyJyxcclxuICAgIHJlbGF0ZWRDaGFyYWN0ZXI6ICfmnZznlKsnLFxyXG4gIH0sXHJcbiAge1xyXG4gICAgaWQ6ICdvYmotMycsXHJcbiAgICBkZXNjcmlwdGlvbjogJ+WxleeOsOadjueZvemdouWvueWPrOWUpOeahOWGheW/g+aMo+aJjicsXHJcbiAgICBwcmlvcml0eTogJ2hpZ2gnLFxyXG4gICAgdHlwZTogJ2NoYXJhY3RlcicsXHJcbiAgICByZWxhdGVkQ2hhcmFjdGVyOiAn5p2O55m9JyxcclxuICB9LFxyXG4gIHtcclxuICAgIGlkOiAnb2JqLTQnLFxyXG4gICAgZGVzY3JpcHRpb246ICfmj5Dpq5jnq6DoioLntKflvKDmhJ/oh7M4MCUnLFxyXG4gICAgcHJpb3JpdHk6ICdtZWRpdW0nLFxyXG4gICAgdHlwZTogJ3RlbnNpb24nLFxyXG4gIH0sXHJcbl07XHJcbmRpcmVjdG9yT3V0cHV0LmZvY3VzQ2hhcmFjdGVycyA9IFsn5p2O55m9JywgJ+adnOeUqycsICfpq5jlipvlo6snXTtcclxuZGlyZWN0b3JPdXRwdXQuc3VnZ2VzdGVkU2NlbmVzID0gW1xyXG4gICfmsZ/ovrnpgIHliKvlnLrmma/vvIzmsJvlm7TlroHpnZknLFxyXG4gICflrqvlu7fkvb/ogIXnqoHnhLblh7rnjrDvvIzmsJTmsJvntKflvKAnLFxyXG4gICfmnY7nmb3kuI7mnZznlKvliJ3mrKHlr7nor50nLFxyXG4gICfmnY7nmb3ni6zoh6rmgJ3ogIPvvIzlhoXlv4PmjKPmiY4nLFxyXG5dO1xyXG5cclxuLy8gQ3JlYXRlIHRlbnNpb24gZ3VpZGFuY2VcclxuY29uc3QgdGVuc2lvbkFuYWx5c2lzID0gYW5hbHl6ZVRlbnNpb24oc3RvcnlTdGF0ZSwgc3RydWN0dXJlZFN0YXRlKTtcclxuY29uc3QgdGVuc2lvbkd1aWRhbmNlID0gZ2VuZXJhdGVUZW5zaW9uR3VpZGFuY2UodGVuc2lvbkFuYWx5c2lzLCBzdG9yeVN0YXRlKTtcclxuXHJcbi8vIFRlc3QgMTogRmFsbGJhY2sgb3V0bGluZVxyXG5jb25zb2xlLmxvZygnVGVzdCAxOiBGYWxsYmFjayBPdXRsaW5lIChObyBMTE0pJyk7XHJcbmNvbnN0IGZhbGxiYWNrT3V0bGluZSA9IGNoYXB0ZXJQbGFubmVyLmdlbmVyYXRlRmFsbGJhY2tPdXRsaW5lKGRpcmVjdG9yT3V0cHV0LCAyNTAwKTtcclxuY29uc29sZS5sb2coYCAgQ2hhcHRlcjogJHtmYWxsYmFja091dGxpbmUuY2hhcHRlck51bWJlcn1gKTtcclxuY29uc29sZS5sb2coYCAgR29hbDogJHtmYWxsYmFja091dGxpbmUub3ZlcmFsbEdvYWx9YCk7XHJcbmNvbnNvbGUubG9nKGAgIFNjZW5lczogJHtmYWxsYmFja091dGxpbmUuc2NlbmVzLmxlbmd0aH1gKTtcclxuY29uc29sZS5sb2coYCAgVG90YWwgd29yZHM6ICR7ZmFsbGJhY2tPdXRsaW5lLnRvdGFsRXN0aW1hdGVkV29yZHN9YCk7XHJcbmNvbnNvbGUubG9nKCcgIFNjZW5lIGJyZWFrZG93bjonKTtcclxuZm9yIChjb25zdCBzY2VuZSBvZiBmYWxsYmFja091dGxpbmUuc2NlbmVzKSB7XHJcbiAgY29uc3QgYmFyID0gJ+KWiCcucmVwZWF0KE1hdGgucm91bmQoc2NlbmUudGVuc2lvbiAqIDEwKSkgKyAn4paRJy5yZXBlYXQoMTAgLSBNYXRoLnJvdW5kKHNjZW5lLnRlbnNpb24gKiAxMCkpO1xyXG4gIGNvbnNvbGUubG9nKGAgICAgU2NlbmUgJHtzY2VuZS5zZXF1ZW5jZX06IFske2Jhcn1dICR7TWF0aC5yb3VuZChzY2VuZS50ZW5zaW9uICogMTAwKX0lIC0gJHtzY2VuZS5nb2FsLnN1YnN0cmluZygwLCA0MCl9Li4uYCk7XHJcbn1cclxuY29uc29sZS5sb2coJ+KchSBGYWxsYmFjayBvdXRsaW5lIGdlbmVyYXRlZCcpO1xyXG5cclxuLy8gVGVzdCAyOiBGb3JtYXQgZm9yIHByb21wdFxyXG5jb25zb2xlLmxvZygnXFxuVGVzdCAyOiBGb3JtYXQgZm9yIFByb21wdCcpO1xyXG5jb25zdCBmb3JtYXR0ZWQgPSBjaGFwdGVyUGxhbm5lci5mb3JtYXRGb3JQcm9tcHQoZmFsbGJhY2tPdXRsaW5lKTtcclxuY29uc29sZS5sb2coJy0tLSBGb3JtYXR0ZWQgT3V0cHV0IFByZXZpZXcgLS0tJyk7XHJcbmNvbnNvbGUubG9nKGZvcm1hdHRlZC5zdWJzdHJpbmcoMCwgODAwKSk7XHJcbmNvbnNvbGUubG9nKCcuLi4nKTtcclxuY29uc29sZS5sb2coJ+KchSBGb3JtYXR0ZWQgZm9yIHdyaXRlciBwcm9tcHQnKTtcclxuXHJcbi8vIFRlc3QgMzogVmFsaWRhdGUgb3V0bGluZVxyXG5jb25zb2xlLmxvZygnXFxuVGVzdCAzOiBWYWxpZGF0ZSBPdXRsaW5lIENvdmVyYWdlJyk7XHJcbmNvbnN0IHZhbGlkYXRpb24gPSBjaGFwdGVyUGxhbm5lci52YWxpZGF0ZU91dGxpbmUoZmFsbGJhY2tPdXRsaW5lLCBkaXJlY3Rvck91dHB1dC5vYmplY3RpdmVzKTtcclxuY29uc29sZS5sb2coYCAgVmFsaWQ6ICR7dmFsaWRhdGlvbi52YWxpZH1gKTtcclxuY29uc29sZS5sb2coYCAgQ292ZXJhZ2U6ICR7KHZhbGlkYXRpb24uY292ZXJhZ2UgKiAxMDApLnRvRml4ZWQoMCl9JWApO1xyXG5pZiAodmFsaWRhdGlvbi5taXNzZWRPYmplY3RpdmVzLmxlbmd0aCA+IDApIHtcclxuICBjb25zb2xlLmxvZyhgICBNaXNzZWQ6ICR7dmFsaWRhdGlvbi5taXNzZWRPYmplY3RpdmVzLmxlbmd0aH0gb2JqZWN0aXZlc2ApO1xyXG59XHJcbmNvbnNvbGUubG9nKCfinIUgT3V0bGluZSB2YWxpZGF0ZWQnKTtcclxuXHJcbi8vIFRlc3QgNDogUGxhbm5lciB3aXRoIExMTVxyXG5jb25zb2xlLmxvZygnXFxuVGVzdCA0OiBDaGFwdGVyIFBsYW5uZXIgd2l0aCBMTE0nKTtcclxuXHJcbmFzeW5jIGZ1bmN0aW9uIHJ1blBsYW5uZXJUZXN0KCkge1xyXG4gIHRyeSB7XHJcbiAgICBjb25zdCBvdXRsaW5lID0gYXdhaXQgY2hhcHRlclBsYW5uZXIucGxhbih7XHJcbiAgICAgIGJpYmxlLFxyXG4gICAgICBzdGF0ZTogc3RvcnlTdGF0ZSxcclxuICAgICAgc3RydWN0dXJlZFN0YXRlLFxyXG4gICAgICBkaXJlY3Rvck91dHB1dCxcclxuICAgICAgdGFyZ2V0V29yZENvdW50OiAyNTAwLFxyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIGNvbnNvbGUubG9nKCfinIUgUGxhbm5lciBnZW5lcmF0ZWQgc2NlbmUgb3V0bGluZScpO1xyXG4gICAgY29uc29sZS5sb2coYCAgQ2hhcHRlcjogJHtvdXRsaW5lLmNoYXB0ZXJOdW1iZXJ9YCk7XHJcbiAgICBjb25zb2xlLmxvZyhgICBHb2FsOiAke291dGxpbmUub3ZlcmFsbEdvYWx9YCk7XHJcbiAgICBjb25zb2xlLmxvZyhgICBUb25lOiAke291dGxpbmUudG9uZX1gKTtcclxuICAgIGNvbnNvbGUubG9nKGAgIFNjZW5lczogJHtvdXRsaW5lLnNjZW5lcy5sZW5ndGh9YCk7XHJcbiAgICBjb25zb2xlLmxvZyhgICBUb3RhbCB3b3JkczogJHtvdXRsaW5lLnRvdGFsRXN0aW1hdGVkV29yZHN9YCk7XHJcbiAgICBcclxuICAgIGNvbnNvbGUubG9nKCdcXG4gIFNjZW5lIERldGFpbHM6Jyk7XHJcbiAgICBmb3IgKGNvbnN0IHNjZW5lIG9mIG91dGxpbmUuc2NlbmVzKSB7XHJcbiAgICAgIGNvbnN0IGJhciA9ICfilognLnJlcGVhdChNYXRoLnJvdW5kKHNjZW5lLnRlbnNpb24gKiAxMCkpO1xyXG4gICAgICBjb25zb2xlLmxvZyhgICAgICR7c2NlbmUuc2VxdWVuY2V9LiBbJHtiYXJ9XSAke3NjZW5lLmdvYWwuc3Vic3RyaW5nKDAsIDQ1KX0uLi5gKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLy8gVGVzdCA1OiBGb3JtYXQgTExNIG91dHB1dFxyXG4gICAgY29uc29sZS5sb2coJ1xcblRlc3QgNTogRm9ybWF0IExMTSBPdXRwdXQgZm9yIFByb21wdCcpO1xyXG4gICAgY29uc3QgbGxtRm9ybWF0dGVkID0gY2hhcHRlclBsYW5uZXIuZm9ybWF0Rm9yUHJvbXB0KG91dGxpbmUpO1xyXG4gICAgY29uc29sZS5sb2coJy0tLSBGb3JtYXR0ZWQgTExNIE91dHB1dCBQcmV2aWV3IC0tLScpO1xyXG4gICAgY29uc29sZS5sb2cobGxtRm9ybWF0dGVkLnN1YnN0cmluZygwLCAxMDAwKSk7XHJcbiAgICBjb25zb2xlLmxvZygnLi4uJyk7XHJcbiAgICBjb25zb2xlLmxvZygn4pyFIExMTSBvdXRwdXQgZm9ybWF0dGVkJyk7XHJcbiAgICBcclxuICAgIC8vIFRlc3QgNjogVmFsaWRhdGUgTExNIG91dGxpbmVcclxuICAgIGNvbnNvbGUubG9nKCdcXG5UZXN0IDY6IFZhbGlkYXRlIExMTSBPdXRsaW5lJyk7XHJcbiAgICBjb25zdCBsbG1WYWxpZGF0aW9uID0gY2hhcHRlclBsYW5uZXIudmFsaWRhdGVPdXRsaW5lKG91dGxpbmUsIGRpcmVjdG9yT3V0cHV0Lm9iamVjdGl2ZXMpO1xyXG4gICAgY29uc29sZS5sb2coYCAgVmFsaWQ6ICR7bGxtVmFsaWRhdGlvbi52YWxpZH1gKTtcclxuICAgIGNvbnNvbGUubG9nKGAgIENvdmVyYWdlOiAkeyhsbG1WYWxpZGF0aW9uLmNvdmVyYWdlICogMTAwKS50b0ZpeGVkKDApfSVgKTtcclxuICAgIGNvbnNvbGUubG9nKCfinIUgTExNIG91dGxpbmUgdmFsaWRhdGVkJyk7XHJcbiAgICBcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgY29uc29sZS5sb2coJ+KaoO+4jyBQbGFubmVyIExMTSB0ZXN0IGZhaWxlZDonLCBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcikpO1xyXG4gIH1cclxufVxyXG5cclxucnVuUGxhbm5lclRlc3QoKS50aGVuKCgpID0+IHtcclxuICAvLyBUZXN0IDc6IERpZmZlcmVudCB3b3JkIGNvdW50c1xyXG4gIGNvbnNvbGUubG9nKCdcXG5UZXN0IDc6IERpZmZlcmVudCBXb3JkIENvdW50cycpO1xyXG4gIFxyXG4gIGNvbnN0IHNob3J0T3V0bGluZSA9IGNoYXB0ZXJQbGFubmVyLmdlbmVyYXRlRmFsbGJhY2tPdXRsaW5lKGRpcmVjdG9yT3V0cHV0LCAxNTAwKTtcclxuICBjb25zb2xlLmxvZyhgICBTaG9ydCAoMTUwMHcpOiAke3Nob3J0T3V0bGluZS5zY2VuZXMubGVuZ3RofSBzY2VuZXMsICR7c2hvcnRPdXRsaW5lLnRvdGFsRXN0aW1hdGVkV29yZHN9IHdvcmRzYCk7XHJcbiAgXHJcbiAgY29uc3QgbWVkaXVtT3V0bGluZSA9IGNoYXB0ZXJQbGFubmVyLmdlbmVyYXRlRmFsbGJhY2tPdXRsaW5lKGRpcmVjdG9yT3V0cHV0LCAyNTAwKTtcclxuICBjb25zb2xlLmxvZyhgICBNZWRpdW0gKDI1MDB3KTogJHttZWRpdW1PdXRsaW5lLnNjZW5lcy5sZW5ndGh9IHNjZW5lcywgJHttZWRpdW1PdXRsaW5lLnRvdGFsRXN0aW1hdGVkV29yZHN9IHdvcmRzYCk7XHJcbiAgXHJcbiAgY29uc3QgbG9uZ091dGxpbmUgPSBjaGFwdGVyUGxhbm5lci5nZW5lcmF0ZUZhbGxiYWNrT3V0bGluZShkaXJlY3Rvck91dHB1dCwgNDAwMCk7XHJcbiAgY29uc29sZS5sb2coYCAgTG9uZyAoNDAwMHcpOiAke2xvbmdPdXRsaW5lLnNjZW5lcy5sZW5ndGh9IHNjZW5lcywgJHtsb25nT3V0bGluZS50b3RhbEVzdGltYXRlZFdvcmRzfSB3b3Jkc2ApO1xyXG4gIGNvbnNvbGUubG9nKCfinIUgT3V0bGluZSBhZGFwdHMgdG8gd29yZCBjb3VudCcpO1xyXG5cclxuICBjb25zb2xlLmxvZygnXFxu4pyFIEFsbCBDaGFwdGVyIFBsYW5uZXIgdGVzdHMgcGFzc2VkIScpO1xyXG4gIGNvbnNvbGUubG9nKCdcXG7wn46JIFBoYXNlIDcgKENoYXB0ZXIgUGxhbm5lciBBZ2VudCkgdGVzdHMgY29tcGxldGUhJyk7XHJcbn0pO1xyXG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const path_1 = require("path");
5
+ const os_1 = require("os");
6
+ // Load config BEFORE importing engine (to initialize LLM correctly)
7
+ const configPath = (0, path_1.join)((0, os_1.homedir)(), '.narrative-os', 'config.json');
8
+ if ((0, fs_1.existsSync)(configPath)) {
9
+ const config = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
10
+ process.env.LLM_PROVIDER = config.provider;
11
+ // Use deepseek-chat (reasoner may not be available for all API keys)
12
+ process.env.LLM_MODEL = 'deepseek-chat';
13
+ if (config.provider === 'openai') {
14
+ process.env.OPENAI_API_KEY = config.apiKey;
15
+ }
16
+ else if (config.provider === 'deepseek') {
17
+ process.env.DEEPSEEK_API_KEY = config.apiKey;
18
+ }
19
+ console.log(`Loaded config: ${config.provider} / ${config.model}`);
20
+ }
21
+ const index_js_1 = require("../index.js");
22
+ console.log('Testing Narrative Constraints Graph (Phase 9)...\n');
23
+ // Setup test data
24
+ const bible = (0, index_js_1.createStoryBible)('侦探故事', '真相与正义', 'mystery', '1920年代上海', '悬疑紧张', '侦探调查连环杀人案,揭开真相', 10);
25
+ let structuredState = (0, index_js_1.createStructuredState)('test-story');
26
+ structuredState = (0, index_js_1.initializeCharactersFromBible)(structuredState, (0, index_js_1.addCharacter)((0, index_js_1.addCharacter)(bible, '陈侦探', 'protagonist', ['聪明', '冷静', '执着'], ['找出凶手', '维护正义']), '凶手', 'antagonist', ['狡猾', '残忍', '伪装'], ['逃避追捕', '继续犯罪']));
27
+ // Set up character states
28
+ structuredState.characters['陈侦探'].emotionalState = '专注';
29
+ structuredState.characters['陈侦探'].location = '上海滩';
30
+ structuredState.characters['陈侦探'].knowledge = ['凶手使用特殊刀具', '第一现场在码头'];
31
+ structuredState.characters['凶手'].emotionalState = '警惕';
32
+ structuredState.characters['凶手'].location = '法租界';
33
+ // Test 1: Create constraint graph
34
+ console.log('Test 1: Create Constraint Graph');
35
+ const graph = (0, index_js_1.createConstraintGraph)();
36
+ graph.addLocation('上海滩', '繁华码头区', 1);
37
+ graph.addLocation('法租界', '外国人居住区', 1);
38
+ graph.addLocation('码头', '第一案发现场', 1);
39
+ graph.addCharacter(structuredState.characters['陈侦探'], 1);
40
+ graph.addCharacter(structuredState.characters['凶手'], 1);
41
+ graph.addEvent('murder-1', '第一起谋杀案', ['凶手'], 1);
42
+ const stats = graph.getStats();
43
+ console.log(` Nodes: ${stats.nodes} (${stats.byType.character} characters, ${stats.byType.location} locations, ${stats.byType.event} events)`);
44
+ console.log(` Edges: ${stats.edges}`);
45
+ console.log('✅ Constraint graph created');
46
+ // Test 2: Query character knowledge
47
+ console.log('\nTest 2: Query Character Knowledge');
48
+ const detectiveKnowledge = graph.getCharacterKnowledge('陈侦探');
49
+ console.log(` 陈侦探 knows ${detectiveKnowledge.length} facts:`);
50
+ for (const fact of detectiveKnowledge) {
51
+ console.log(` - ${fact.label}`);
52
+ }
53
+ console.log('✅ Knowledge query working');
54
+ // Test 3: Query character location
55
+ console.log('\nTest 3: Query Character Location');
56
+ const detectiveLocation = graph.getCharacterLocation('陈侦探');
57
+ const villainLocation = graph.getCharacterLocation('凶手');
58
+ console.log(` 陈侦探 is at: ${detectiveLocation}`);
59
+ console.log(` 凶手 is at: ${villainLocation}`);
60
+ console.log('✅ Location query working');
61
+ // Test 4: Update character location
62
+ console.log('\nTest 4: Update Character Location');
63
+ graph.updateCharacterLocation('陈侦探', '法租界', 3);
64
+ const newLocation = graph.getCharacterLocation('陈侦探');
65
+ console.log(` 陈侦探 moved to: ${newLocation}`);
66
+ console.log('✅ Location update working');
67
+ // Test 5: Check timeline consistency (should pass)
68
+ console.log('\nTest 5: Check Timeline Consistency (Current)');
69
+ const timelineViolations = graph.checkConstraints(3);
70
+ console.log(` Violations found: ${timelineViolations.length}`);
71
+ for (const v of timelineViolations) {
72
+ console.log(` - [${v.severity}] ${v.type}: ${v.description}`);
73
+ }
74
+ console.log('✅ Timeline check complete');
75
+ // Test 6: Create knowledge leak scenario
76
+ console.log('\nTest 6: Knowledge Leak Detection');
77
+ // Add a fact established in chapter 5
78
+ const futureFact = {
79
+ id: 'fact-future',
80
+ type: 'fact',
81
+ label: '凶手真实身份暴露',
82
+ properties: {},
83
+ chapterEstablished: 5,
84
+ };
85
+ graph.addNode(futureFact);
86
+ // Make detective know it in chapter 3 (impossible!)
87
+ graph.addEdge({
88
+ id: 'edge-leak',
89
+ from: 'char-陈侦探',
90
+ to: 'fact-future',
91
+ type: 'knows',
92
+ properties: { since: 3 }, // Chapter 3, but fact established in 5!
93
+ });
94
+ const knowledgeViolations = graph.checkConstraints(3);
95
+ const knowledgeErrors = knowledgeViolations.filter(v => v.type === 'knowledge');
96
+ console.log(` Knowledge violations: ${knowledgeErrors.length}`);
97
+ for (const v of knowledgeErrors) {
98
+ console.log(` ❌ ${v.description}`);
99
+ }
100
+ console.log('✅ Knowledge leak detected');
101
+ // Test 7: Create canon store
102
+ console.log('\nTest 7: Canon Store Setup');
103
+ let canon = (0, index_js_1.createCanonStore)('test-story');
104
+ canon = (0, index_js_1.addFact)(canon, {
105
+ category: 'character',
106
+ subject: '陈侦探',
107
+ attribute: '职业',
108
+ value: '私家侦探',
109
+ chapterEstablished: 1,
110
+ });
111
+ canon = (0, index_js_1.addFact)(canon, {
112
+ category: 'world',
113
+ subject: '上海',
114
+ attribute: '时期',
115
+ value: '1920年代',
116
+ chapterEstablished: 1,
117
+ });
118
+ console.log(` Canon facts: ${canon.facts.length}`);
119
+ console.log('✅ Canon store ready');
120
+ // Test 8: Quick validation (no LLM)
121
+ console.log('\nTest 8: Quick Validation (No LLM)');
122
+ const testChapter = {
123
+ id: 'test-ch-3',
124
+ storyId: 'test-story',
125
+ number: 3,
126
+ title: '追查',
127
+ content: '陈侦探在法租界调查线索。他发现凶手使用特殊刀具,这与第一现场吻合。',
128
+ wordCount: 500,
129
+ summary: '陈侦探在法租界调查',
130
+ generatedAt: new Date(),
131
+ };
132
+ const validator = new index_js_1.Validator(graph);
133
+ const quickResult = validator.quickValidate({
134
+ chapter: testChapter,
135
+ bible,
136
+ structuredState,
137
+ canon,
138
+ previousChapters: [],
139
+ constraintGraph: graph,
140
+ });
141
+ console.log(` Valid: ${quickResult.valid}`);
142
+ console.log(` Violations: ${quickResult.violations.length}`);
143
+ console.log(` Summary: ${quickResult.summary}`);
144
+ console.log('✅ Quick validation complete');
145
+ // Test 9: Format validation result
146
+ console.log('\nTest 9: Format Validation Result');
147
+ const formatted = validator.formatResult(quickResult);
148
+ console.log('--- Formatted Result ---');
149
+ console.log(formatted);
150
+ console.log('✅ Result formatted');
151
+ // Test 10: Graph serialization
152
+ console.log('\nTest 10: Graph Serialization');
153
+ const serialized = graph.serialize();
154
+ const graph2 = (0, index_js_1.createConstraintGraph)();
155
+ graph2.load(serialized);
156
+ const stats2 = graph2.getStats();
157
+ console.log(` Serialized and loaded: ${stats2.nodes} nodes, ${stats2.edges} edges`);
158
+ console.log('✅ Serialization working');
159
+ // Test 11: Canon violation detection
160
+ console.log('\nTest 11: Canon Violation Detection');
161
+ const badChapter = {
162
+ id: 'test-ch-bad',
163
+ storyId: 'test-story',
164
+ number: 3,
165
+ title: '错误章节',
166
+ content: '陈侦探其实不是私家侦探,他是一名警察。故事发生在1930年代的北京。',
167
+ wordCount: 100,
168
+ summary: '包含矛盾内容',
169
+ generatedAt: new Date(),
170
+ };
171
+ const badResult = validator.quickValidate({
172
+ chapter: badChapter,
173
+ bible,
174
+ structuredState,
175
+ canon,
176
+ previousChapters: [],
177
+ constraintGraph: graph,
178
+ });
179
+ console.log(` Valid: ${badResult.valid}`);
180
+ console.log(` Canon violations: ${badResult.violations.filter(v => v.type === 'canon').length}`);
181
+ for (const v of badResult.violations.filter(v => v.type === 'canon')) {
182
+ console.log(` ❌ ${v.description}`);
183
+ }
184
+ console.log('✅ Canon violations detected');
185
+ // Test 12: Full validation with LLM (optional)
186
+ console.log('\nTest 12: Full Validation with LLM');
187
+ async function runLLMValidation() {
188
+ try {
189
+ const llmResult = await validator.validateChapter({
190
+ chapter: testChapter,
191
+ bible,
192
+ structuredState,
193
+ canon,
194
+ previousChapters: [],
195
+ constraintGraph: graph,
196
+ });
197
+ console.log(` LLM Valid: ${llmResult.valid}`);
198
+ console.log(` LLM Violations: ${llmResult.violations.length}`);
199
+ console.log(` LLM Summary: ${llmResult.summary.substring(0, 100)}...`);
200
+ console.log('✅ LLM validation complete');
201
+ }
202
+ catch (error) {
203
+ console.log(' ⚠️ LLM validation skipped (API unavailable)');
204
+ }
205
+ }
206
+ runLLMValidation().then(() => {
207
+ console.log('\n✅ All Constraints Graph tests passed!');
208
+ console.log('\n🎉 Phase 9 (Narrative Constraints Graph) tests complete!');
209
+ });
210
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RyYWludHMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0L2NvbnN0cmFpbnRzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwyQkFBOEM7QUFDOUMsK0JBQTRCO0FBQzVCLDJCQUE2QjtBQUU3QixvRUFBb0U7QUFDcEUsTUFBTSxVQUFVLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBQSxZQUFPLEdBQUUsRUFBRSxlQUFlLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFDbkUsSUFBSSxJQUFBLGVBQVUsRUFBQyxVQUFVLENBQUMsRUFBRSxDQUFDO0lBQzNCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBQSxpQkFBWSxFQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzdELE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUM7SUFDM0MscUVBQXFFO0lBQ3JFLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxHQUFHLGVBQWUsQ0FBQztJQUN4QyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDakMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUM3QyxDQUFDO1NBQU0sSUFBSSxNQUFNLENBQUMsUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUMvQyxDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsTUFBTSxDQUFDLFFBQVEsTUFBTSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUNyRSxDQUFDO0FBRUQsMENBVXFCO0FBRXJCLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0RBQW9ELENBQUMsQ0FBQztBQUVsRSxrQkFBa0I7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dXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlYWRGaWxlU3luYywgZXhpc3RzU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnb3MnO1xyXG5cclxuLy8gTG9hZCBjb25maWcgQkVGT1JFIGltcG9ydGluZyBlbmdpbmUgKHRvIGluaXRpYWxpemUgTExNIGNvcnJlY3RseSlcclxuY29uc3QgY29uZmlnUGF0aCA9IGpvaW4oaG9tZWRpcigpLCAnLm5hcnJhdGl2ZS1vcycsICdjb25maWcuanNvbicpO1xyXG5pZiAoZXhpc3RzU3luYyhjb25maWdQYXRoKSkge1xyXG4gIGNvbnN0IGNvbmZpZyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ1BhdGgsICd1dGYtOCcpKTtcclxuICBwcm9jZXNzLmVudi5MTE1fUFJPVklERVIgPSBjb25maWcucHJvdmlkZXI7XHJcbiAgLy8gVXNlIGRlZXBzZWVrLWNoYXQgKHJlYXNvbmVyIG1heSBub3QgYmUgYXZhaWxhYmxlIGZvciBhbGwgQVBJIGtleXMpXHJcbiAgcHJvY2Vzcy5lbnYuTExNX01PREVMID0gJ2RlZXBzZWVrLWNoYXQnO1xyXG4gIGlmIChjb25maWcucHJvdmlkZXIgPT09ICdvcGVuYWknKSB7XHJcbiAgICBwcm9jZXNzLmVudi5PUEVOQUlfQVBJX0tFWSA9IGNvbmZpZy5hcGlLZXk7XHJcbiAgfSBlbHNlIGlmIChjb25maWcucHJvdmlkZXIgPT09ICdkZWVwc2VlaycpIHtcclxuICAgIHByb2Nlc3MuZW52LkRFRVBTRUVLX0FQSV9LRVkgPSBjb25maWcuYXBpS2V5O1xyXG4gIH1cclxuICBjb25zb2xlLmxvZyhgTG9hZGVkIGNvbmZpZzogJHtjb25maWcucHJvdmlkZXJ9IC8gJHtjb25maWcubW9kZWx9YCk7XHJcbn1cclxuXHJcbmltcG9ydCB7XHJcbiAgY3JlYXRlQ29uc3RyYWludEdyYXBoLFxyXG4gIFZhbGlkYXRvcixcclxuICBjcmVhdGVDYW5vblN0b3JlLFxyXG4gIGFkZEZhY3QsXHJcbiAgY3JlYXRlU3RydWN0dXJlZFN0YXRlLFxyXG4gIGluaXRpYWxpemVDaGFyYWN0ZXJzRnJvbUJpYmxlLFxyXG4gIGNyZWF0ZVN0b3J5QmlibGUsXHJcbiAgYWRkQ2hhcmFjdGVyLFxyXG4gIHR5cGUgQ2hhcHRlcixcclxufSBmcm9tICcuLi9pbmRleC5qcyc7XHJcblxyXG5jb25zb2xlLmxvZygnVGVzdGluZyBOYXJyYXRpdmUgQ29uc3RyYWludHMgR3JhcGggKFBoYXNlIDkpLi4uXFxuJyk7XHJcblxyXG4vLyBTZXR1cCB0ZXN0IGRhdGFcclxuY29uc3QgYmlibGUgPSBjcmVhdGVTdG9yeUJpYmxlKFxyXG4gICfkvqbmjqLmlYXkuosnLFxyXG4gICfnnJ/nm7jkuI7mraPkuYknLFxyXG4gICdteXN0ZXJ5JyxcclxuICAnMTkyMOW5tOS7o+S4iua1tycsXHJcbiAgJ+aCrOeWkee0p+W8oCcsXHJcbiAgJ+S+puaOouiwg+afpei/nueOr+adgOS6uuahiO+8jOaPreW8gOecn+ebuCcsXHJcbiAgMTBcclxuKTtcclxuXHJcbmxldCBzdHJ1Y3R1cmVkU3RhdGUgPSBjcmVhdGVTdHJ1Y3R1cmVkU3RhdGUoJ3Rlc3Qtc3RvcnknKTtcclxuc3RydWN0dXJlZFN0YXRlID0gaW5pdGlhbGl6ZUNoYXJhY3RlcnNGcm9tQmlibGUoXHJcbiAgc3RydWN0dXJlZFN0YXRlLFxyXG4gIGFkZENoYXJhY3RlcihcclxuICAgIGFkZENoYXJhY3RlcihiaWJsZSwgJ+mZiOS+puaOoicsICdwcm90YWdvbmlzdCcsIFsn6IGq5piOJywgJ+WGt+mdmScsICfmiafnnYAnXSwgWyfmib7lh7rlh7bmiYsnLCAn57u05oqk5q2j5LmJJ10pLFxyXG4gICAgJ+WHtuaJiycsXHJcbiAgICAnYW50YWdvbmlzdCcsXHJcbiAgICBbJ+eLoeeMvicsICfmrovlv40nLCAn5Lyq6KOFJ10sXHJcbiAgICBbJ+mAg+mBv+i/veaNlScsICfnu6fnu63niq/nvaonXVxyXG4gIClcclxuKTtcclxuXHJcbi8vIFNldCB1cCBjaGFyYWN0ZXIgc3RhdGVzXHJcbnN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzWyfpmYjkvqbmjqInXS5lbW90aW9uYWxTdGF0ZSA9ICfkuJPms6gnO1xyXG5zdHJ1Y3R1cmVkU3RhdGUuY2hhcmFjdGVyc1sn6ZmI5L6m5o6iJ10ubG9jYXRpb24gPSAn5LiK5rW35rupJztcclxuc3RydWN0dXJlZFN0YXRlLmNoYXJhY3RlcnNbJ+mZiOS+puaOoiddLmtub3dsZWRnZSA9IFsn5Ye25omL5L2/55So54m55q6K5YiA5YW3JywgJ+esrOS4gOeOsOWcuuWcqOeggeWktCddO1xyXG5cclxuc3RydWN0dXJlZFN0YXRlLmNoYXJhY3RlcnNbJ+WHtuaJiyddLmVtb3Rpb25hbFN0YXRlID0gJ+itpuaDlSc7XHJcbnN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzWyflh7bmiYsnXS5sb2NhdGlvbiA9ICfms5Xnp5/nlYwnO1xyXG5cclxuLy8gVGVzdCAxOiBDcmVhdGUgY29uc3RyYWludCBncmFwaFxyXG5jb25zb2xlLmxvZygnVGVzdCAxOiBDcmVhdGUgQ29uc3RyYWludCBHcmFwaCcpO1xyXG5jb25zdCBncmFwaCA9IGNyZWF0ZUNvbnN0cmFpbnRHcmFwaCgpO1xyXG5ncmFwaC5hZGRMb2NhdGlvbign5LiK5rW35rupJywgJ+e5geWNjueggeWktOWMuicsIDEpO1xyXG5ncmFwaC5hZGRMb2NhdGlvbign5rOV56ef55WMJywgJ+WkluWbveS6uuWxheS9j+WMuicsIDEpO1xyXG5ncmFwaC5hZGRMb2NhdGlvbign56CB5aS0JywgJ+esrOS4gOahiOWPkeeOsOWcuicsIDEpO1xyXG5cclxuZ3JhcGguYWRkQ2hhcmFjdGVyKHN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzWyfpmYjkvqbmjqInXSwgMSk7XHJcbmdyYXBoLmFkZENoYXJhY3RlcihzdHJ1Y3R1cmVkU3RhdGUuY2hhcmFjdGVyc1sn5Ye25omLJ10sIDEpO1xyXG5cclxuZ3JhcGguYWRkRXZlbnQoJ211cmRlci0xJywgJ+esrOS4gOi1t+iwi+adgOahiCcsIFsn5Ye25omLJ10sIDEpO1xyXG5cclxuY29uc3Qgc3RhdHMgPSBncmFwaC5nZXRTdGF0cygpO1xyXG5jb25zb2xlLmxvZyhgICBOb2RlczogJHtzdGF0cy5ub2Rlc30gKCR7c3RhdHMuYnlUeXBlLmNoYXJhY3Rlcn0gY2hhcmFjdGVycywgJHtzdGF0cy5ieVR5cGUubG9jYXRpb259IGxvY2F0aW9ucywgJHtzdGF0cy5ieVR5cGUuZXZlbnR9IGV2ZW50cylgKTtcclxuY29uc29sZS5sb2coYCAgRWRnZXM6ICR7c3RhdHMuZWRnZXN9YCk7XHJcbmNvbnNvbGUubG9nKCfinIUgQ29uc3RyYWludCBncmFwaCBjcmVhdGVkJyk7XHJcblxyXG4vLyBUZXN0IDI6IFF1ZXJ5IGNoYXJhY3RlciBrbm93bGVkZ2VcclxuY29uc29sZS5sb2coJ1xcblRlc3QgMjogUXVlcnkgQ2hhcmFjdGVyIEtub3dsZWRnZScpO1xyXG5jb25zdCBkZXRlY3RpdmVLbm93bGVkZ2UgPSBncmFwaC5nZXRDaGFyYWN0ZXJLbm93bGVkZ2UoJ+mZiOS+puaOoicpO1xyXG5jb25zb2xlLmxvZyhgICDpmYjkvqbmjqIga25vd3MgJHtkZXRlY3RpdmVLbm93bGVkZ2UubGVuZ3RofSBmYWN0czpgKTtcclxuZm9yIChjb25zdCBmYWN0IG9mIGRldGVjdGl2ZUtub3dsZWRnZSkge1xyXG4gIGNvbnNvbGUubG9nKGAgICAgLSAke2ZhY3QubGFiZWx9YCk7XHJcbn1cclxuY29uc29sZS5sb2coJ+KchSBLbm93bGVkZ2UgcXVlcnkgd29ya2luZycpO1xyXG5cclxuLy8gVGVzdCAzOiBRdWVyeSBjaGFyYWN0ZXIgbG9jYXRpb25cclxuY29uc29sZS5sb2coJ1xcblRlc3QgMzogUXVlcnkgQ2hhcmFjdGVyIExvY2F0aW9uJyk7XHJcbmNvbnN0IGRldGVjdGl2ZUxvY2F0aW9uID0gZ3JhcGguZ2V0Q2hhcmFjdGVyTG9jYXRpb24oJ+mZiOS+puaOoicpO1xyXG5jb25zdCB2aWxsYWluTG9jYXRpb24gPSBncmFwaC5nZXRDaGFyYWN0ZXJMb2NhdGlvbign5Ye25omLJyk7XHJcbmNvbnNvbGUubG9nKGAgIOmZiOS+puaOoiBpcyBhdDogJHtkZXRlY3RpdmVMb2NhdGlvbn1gKTtcclxuY29uc29sZS5sb2coYCAg5Ye25omLIGlzIGF0OiAke3ZpbGxhaW5Mb2NhdGlvbn1gKTtcclxuY29uc29sZS5sb2coJ+KchSBMb2NhdGlvbiBxdWVyeSB3b3JraW5nJyk7XHJcblxyXG4vLyBUZXN0IDQ6IFVwZGF0ZSBjaGFyYWN0ZXIgbG9jYXRpb25cclxuY29uc29sZS5sb2coJ1xcblRlc3QgNDogVXBkYXRlIENoYXJhY3RlciBMb2NhdGlvbicpO1xyXG5ncmFwaC51cGRhdGVDaGFyYWN0ZXJMb2NhdGlvbign6ZmI5L6m5o6iJywgJ+azleenn+eVjCcsIDMpO1xyXG5jb25zdCBuZXdMb2NhdGlvbiA9IGdyYXBoLmdldENoYXJhY3RlckxvY2F0aW9uKCfpmYjkvqbmjqInKTtcclxuY29uc29sZS5sb2coYCAg6ZmI5L6m5o6iIG1vdmVkIHRvOiAke25ld0xvY2F0aW9ufWApO1xyXG5jb25zb2xlLmxvZygn4pyFIExvY2F0aW9uIHVwZGF0ZSB3b3JraW5nJyk7XHJcblxyXG4vLyBUZXN0IDU6IENoZWNrIHRpbWVsaW5lIGNvbnNpc3RlbmN5IChzaG91bGQgcGFzcylcclxuY29uc29sZS5sb2coJ1xcblRlc3QgNTogQ2hlY2sgVGltZWxpbmUgQ29uc2lzdGVuY3kgKEN1cnJlbnQpJyk7XHJcbmNvbnN0IHRpbWVsaW5lVmlvbGF0aW9ucyA9IGdyYXBoLmNoZWNrQ29uc3RyYWludHMoMyk7XHJcbmNvbnNvbGUubG9nKGAgIFZpb2xhdGlvbnMgZm91bmQ6ICR7dGltZWxpbmVWaW9sYXRpb25zLmxlbmd0aH1gKTtcclxuZm9yIChjb25zdCB2IG9mIHRpbWVsaW5lVmlvbGF0aW9ucykge1xyXG4gIGNvbnNvbGUubG9nKGAgICAgLSBbJHt2LnNldmVyaXR5fV0gJHt2LnR5cGV9OiAke3YuZGVzY3JpcHRpb259YCk7XHJcbn1cclxuY29uc29sZS5sb2coJ+KchSBUaW1lbGluZSBjaGVjayBjb21wbGV0ZScpO1xyXG5cclxuLy8gVGVzdCA2OiBDcmVhdGUga25vd2xlZGdlIGxlYWsgc2NlbmFyaW9cclxuY29uc29sZS5sb2coJ1xcblRlc3QgNjogS25vd2xlZGdlIExlYWsgRGV0ZWN0aW9uJyk7XHJcbi8vIEFkZCBhIGZhY3QgZXN0YWJsaXNoZWQgaW4gY2hhcHRlciA1XHJcbmNvbnN0IGZ1dHVyZUZhY3QgPSB7XHJcbiAgaWQ6ICdmYWN0LWZ1dHVyZScsXHJcbiAgdHlwZTogJ2ZhY3QnIGFzIGNvbnN0LFxyXG4gIGxhYmVsOiAn5Ye25omL55yf5a6e6Lqr5Lu95pq06ZyyJyxcclxuICBwcm9wZXJ0aWVzOiB7fSxcclxuICBjaGFwdGVyRXN0YWJsaXNoZWQ6IDUsXHJcbn07XHJcbmdyYXBoLmFkZE5vZGUoZnV0dXJlRmFjdCk7XHJcblxyXG4vLyBNYWtlIGRldGVjdGl2ZSBrbm93IGl0IGluIGNoYXB0ZXIgMyAoaW1wb3NzaWJsZSEpXHJcbmdyYXBoLmFkZEVkZ2Uoe1xyXG4gIGlkOiAnZWRnZS1sZWFrJyxcclxuICBmcm9tOiAnY2hhci3pmYjkvqbmjqInLFxyXG4gIHRvOiAnZmFjdC1mdXR1cmUnLFxyXG4gIHR5cGU6ICdrbm93cycsXHJcbiAgcHJvcGVydGllczogeyBzaW5jZTogMyB9LCAvLyBDaGFwdGVyIDMsIGJ1dCBmYWN0IGVzdGFibGlzaGVkIGluIDUhXHJcbn0pO1xyXG5cclxuY29uc3Qga25vd2xlZGdlVmlvbGF0aW9ucyA9IGdyYXBoLmNoZWNrQ29uc3RyYWludHMoMyk7XHJcbmNvbnN0IGtub3dsZWRnZUVycm9ycyA9IGtub3dsZWRnZVZpb2xhdGlvbnMuZmlsdGVyKHYgPT4gdi50eXBlID09PSAna25vd2xlZGdlJyk7XHJcbmNvbnNvbGUubG9nKGAgIEtub3dsZWRnZSB2aW9sYXRpb25zOiAke2tub3dsZWRnZUVycm9ycy5sZW5ndGh9YCk7XHJcbmZvciAoY29uc3QgdiBvZiBrbm93bGVkZ2VFcnJvcnMpIHtcclxuICBjb25zb2xlLmxvZyhgICAgIOKdjCAke3YuZGVzY3JpcHRpb259YCk7XHJcbn1cclxuY29uc29sZS5sb2coJ+KchSBLbm93bGVkZ2UgbGVhayBkZXRlY3RlZCcpO1xyXG5cclxuLy8gVGVzdCA3OiBDcmVhdGUgY2Fub24gc3RvcmVcclxuY29uc29sZS5sb2coJ1xcblRlc3QgNzogQ2Fub24gU3RvcmUgU2V0dXAnKTtcclxubGV0IGNhbm9uID0gY3JlYXRlQ2Fub25TdG9yZSgndGVzdC1zdG9yeScpO1xyXG5jYW5vbiA9IGFkZEZhY3QoY2Fub24sIHtcclxuICBjYXRlZ29yeTogJ2NoYXJhY3RlcicsXHJcbiAgc3ViamVjdDogJ+mZiOS+puaOoicsXHJcbiAgYXR0cmlidXRlOiAn6IGM5LiaJyxcclxuICB2YWx1ZTogJ+engeWutuS+puaOoicsXHJcbiAgY2hhcHRlckVzdGFibGlzaGVkOiAxLFxyXG59KTtcclxuY2Fub24gPSBhZGRGYWN0KGNhbm9uLCB7XHJcbiAgY2F0ZWdvcnk6ICd3b3JsZCcsXHJcbiAgc3ViamVjdDogJ+S4iua1tycsXHJcbiAgYXR0cmlidXRlOiAn5pe25pyfJyxcclxuICB2YWx1ZTogJzE5MjDlubTku6MnLFxyXG4gIGNoYXB0ZXJFc3RhYmxpc2hlZDogMSxcclxufSk7XHJcbmNvbnNvbGUubG9nKGAgIENhbm9uIGZhY3RzOiAke2Nhbm9uLmZhY3RzLmxlbmd0aH1gKTtcclxuY29uc29sZS5sb2coJ+KchSBDYW5vbiBzdG9yZSByZWFkeScpO1xyXG5cclxuLy8gVGVzdCA4OiBRdWljayB2YWxpZGF0aW9uIChubyBMTE0pXHJcbmNvbnNvbGUubG9nKCdcXG5UZXN0IDg6IFF1aWNrIFZhbGlkYXRpb24gKE5vIExMTSknKTtcclxuY29uc3QgdGVzdENoYXB0ZXI6IENoYXB0ZXIgPSB7XHJcbiAgaWQ6ICd0ZXN0LWNoLTMnLFxyXG4gIHN0b3J5SWQ6ICd0ZXN0LXN0b3J5JyxcclxuICBudW1iZXI6IDMsXHJcbiAgdGl0bGU6ICfov73mn6UnLFxyXG4gIGNvbnRlbnQ6ICfpmYjkvqbmjqLlnKjms5Xnp5/nlYzosIPmn6Xnur/ntKLjgILku5blj5HnjrDlh7bmiYvkvb/nlKjnibnmrorliIDlhbfvvIzov5nkuI7nrKzkuIDnjrDlnLrlkLvlkIjjgIInLFxyXG4gIHdvcmRDb3VudDogNTAwLFxyXG4gIHN1bW1hcnk6ICfpmYjkvqbmjqLlnKjms5Xnp5/nlYzosIPmn6UnLFxyXG4gIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLFxyXG59O1xyXG5cclxuY29uc3QgdmFsaWRhdG9yID0gbmV3IFZhbGlkYXRvcihncmFwaCk7XHJcbmNvbnN0IHF1aWNrUmVzdWx0ID0gdmFsaWRhdG9yLnF1aWNrVmFsaWRhdGUoe1xyXG4gIGNoYXB0ZXI6IHRlc3RDaGFwdGVyLFxyXG4gIGJpYmxlLFxyXG4gIHN0cnVjdHVyZWRTdGF0ZSxcclxuICBjYW5vbixcclxuICBwcmV2aW91c0NoYXB0ZXJzOiBbXSxcclxuICBjb25zdHJhaW50R3JhcGg6IGdyYXBoLFxyXG59KTtcclxuXHJcbmNvbnNvbGUubG9nKGAgIFZhbGlkOiAke3F1aWNrUmVzdWx0LnZhbGlkfWApO1xyXG5jb25zb2xlLmxvZyhgICBWaW9sYXRpb25zOiAke3F1aWNrUmVzdWx0LnZpb2xhdGlvbnMubGVuZ3RofWApO1xyXG5jb25zb2xlLmxvZyhgICBTdW1tYXJ5OiAke3F1aWNrUmVzdWx0LnN1bW1hcnl9YCk7XHJcbmNvbnNvbGUubG9nKCfinIUgUXVpY2sgdmFsaWRhdGlvbiBjb21wbGV0ZScpO1xyXG5cclxuLy8gVGVzdCA5OiBGb3JtYXQgdmFsaWRhdGlvbiByZXN1bHRcclxuY29uc29sZS5sb2coJ1xcblRlc3QgOTogRm9ybWF0IFZhbGlkYXRpb24gUmVzdWx0Jyk7XHJcbmNvbnN0IGZvcm1hdHRlZCA9IHZhbGlkYXRvci5mb3JtYXRSZXN1bHQocXVpY2tSZXN1bHQpO1xyXG5jb25zb2xlLmxvZygnLS0tIEZvcm1hdHRlZCBSZXN1bHQgLS0tJyk7XHJcbmNvbnNvbGUubG9nKGZvcm1hdHRlZCk7XHJcbmNvbnNvbGUubG9nKCfinIUgUmVzdWx0IGZvcm1hdHRlZCcpO1xyXG5cclxuLy8gVGVzdCAxMDogR3JhcGggc2VyaWFsaXphdGlvblxyXG5jb25zb2xlLmxvZygnXFxuVGVzdCAxMDogR3JhcGggU2VyaWFsaXphdGlvbicpO1xyXG5jb25zdCBzZXJpYWxpemVkID0gZ3JhcGguc2VyaWFsaXplKCk7XHJcbmNvbnN0IGdyYXBoMiA9IGNyZWF0ZUNvbnN0cmFpbnRHcmFwaCgpO1xyXG5ncmFwaDIubG9hZChzZXJpYWxpemVkKTtcclxuY29uc3Qgc3RhdHMyID0gZ3JhcGgyLmdldFN0YXRzKCk7XHJcbmNvbnNvbGUubG9nKGAgIFNlcmlhbGl6ZWQgYW5kIGxvYWRlZDogJHtzdGF0czIubm9kZXN9IG5vZGVzLCAke3N0YXRzMi5lZGdlc30gZWRnZXNgKTtcclxuY29uc29sZS5sb2coJ+KchSBTZXJpYWxpemF0aW9uIHdvcmtpbmcnKTtcclxuXHJcbi8vIFRlc3QgMTE6IENhbm9uIHZpb2xhdGlvbiBkZXRlY3Rpb25cclxuY29uc29sZS5sb2coJ1xcblRlc3QgMTE6IENhbm9uIFZpb2xhdGlvbiBEZXRlY3Rpb24nKTtcclxuY29uc3QgYmFkQ2hhcHRlcjogQ2hhcHRlciA9IHtcclxuICBpZDogJ3Rlc3QtY2gtYmFkJyxcclxuICBzdG9yeUlkOiAndGVzdC1zdG9yeScsXHJcbiAgbnVtYmVyOiAzLFxyXG4gIHRpdGxlOiAn6ZSZ6K+v56ug6IqCJyxcclxuICBjb250ZW50OiAn6ZmI5L6m5o6i5YW25a6e5LiN5piv56eB5a625L6m5o6i77yM5LuW5piv5LiA5ZCN6K2m5a+f44CC5pWF5LqL5Y+R55Sf5ZyoMTkzMOW5tOS7o+eahOWMl+S6rOOAgicsXHJcbiAgd29yZENvdW50OiAxMDAsXHJcbiAgc3VtbWFyeTogJ+WMheWQq+efm+ebvuWGheWuuScsXHJcbiAgZ2VuZXJhdGVkQXQ6IG5ldyBEYXRlKCksXHJcbn07XHJcblxyXG5jb25zdCBiYWRSZXN1bHQgPSB2YWxpZGF0b3IucXVpY2tWYWxpZGF0ZSh7XHJcbiAgY2hhcHRlcjogYmFkQ2hhcHRlcixcclxuICBiaWJsZSxcclxuICBzdHJ1Y3R1cmVkU3RhdGUsXHJcbiAgY2Fub24sXHJcbiAgcHJldmlvdXNDaGFwdGVyczogW10sXHJcbiAgY29uc3RyYWludEdyYXBoOiBncmFwaCxcclxufSk7XHJcblxyXG5jb25zb2xlLmxvZyhgICBWYWxpZDogJHtiYWRSZXN1bHQudmFsaWR9YCk7XHJcbmNvbnNvbGUubG9nKGAgIENhbm9uIHZpb2xhdGlvbnM6ICR7YmFkUmVzdWx0LnZpb2xhdGlvbnMuZmlsdGVyKHYgPT4gdi50eXBlID09PSAnY2Fub24nKS5sZW5ndGh9YCk7XHJcbmZvciAoY29uc3QgdiBvZiBiYWRSZXN1bHQudmlvbGF0aW9ucy5maWx0ZXIodiA9PiB2LnR5cGUgPT09ICdjYW5vbicpKSB7XHJcbiAgY29uc29sZS5sb2coYCAgICDinYwgJHt2LmRlc2NyaXB0aW9ufWApO1xyXG59XHJcbmNvbnNvbGUubG9nKCfinIUgQ2Fub24gdmlvbGF0aW9ucyBkZXRlY3RlZCcpO1xyXG5cclxuLy8gVGVzdCAxMjogRnVsbCB2YWxpZGF0aW9uIHdpdGggTExNIChvcHRpb25hbClcclxuY29uc29sZS5sb2coJ1xcblRlc3QgMTI6IEZ1bGwgVmFsaWRhdGlvbiB3aXRoIExMTScpO1xyXG5cclxuYXN5bmMgZnVuY3Rpb24gcnVuTExNVmFsaWRhdGlvbigpIHtcclxuICB0cnkge1xyXG4gICAgY29uc3QgbGxtUmVzdWx0ID0gYXdhaXQgdmFsaWRhdG9yLnZhbGlkYXRlQ2hhcHRlcih7XHJcbiAgICAgIGNoYXB0ZXI6IHRlc3RDaGFwdGVyLFxyXG4gICAgICBiaWJsZSxcclxuICAgICAgc3RydWN0dXJlZFN0YXRlLFxyXG4gICAgICBjYW5vbixcclxuICAgICAgcHJldmlvdXNDaGFwdGVyczogW10sXHJcbiAgICAgIGNvbnN0cmFpbnRHcmFwaDogZ3JhcGgsXHJcbiAgICB9KTtcclxuICAgIFxyXG4gICAgY29uc29sZS5sb2coYCAgTExNIFZhbGlkOiAke2xsbVJlc3VsdC52YWxpZH1gKTtcclxuICAgIGNvbnNvbGUubG9nKGAgIExMTSBWaW9sYXRpb25zOiAke2xsbVJlc3VsdC52aW9sYXRpb25zLmxlbmd0aH1gKTtcclxuICAgIGNvbnNvbGUubG9nKGAgIExMTSBTdW1tYXJ5OiAke2xsbVJlc3VsdC5zdW1tYXJ5LnN1YnN0cmluZygwLCAxMDApfS4uLmApO1xyXG4gICAgY29uc29sZS5sb2coJ+KchSBMTE0gdmFsaWRhdGlvbiBjb21wbGV0ZScpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBjb25zb2xlLmxvZygnICDimqDvuI8gTExNIHZhbGlkYXRpb24gc2tpcHBlZCAoQVBJIHVuYXZhaWxhYmxlKScpO1xyXG4gIH1cclxufVxyXG5cclxucnVuTExNVmFsaWRhdGlvbigpLnRoZW4oKCkgPT4ge1xyXG4gIGNvbnNvbGUubG9nKCdcXG7inIUgQWxsIENvbnN0cmFpbnRzIEdyYXBoIHRlc3RzIHBhc3NlZCEnKTtcclxuICBjb25zb2xlLmxvZygnXFxu8J+OiSBQaGFzZSA5IChOYXJyYXRpdmUgQ29uc3RyYWludHMgR3JhcGgpIHRlc3RzIGNvbXBsZXRlIScpO1xyXG59KTtcclxuIl19
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const path_1 = require("path");
5
+ const os_1 = require("os");
6
+ // Load config BEFORE importing engine (to initialize LLM correctly)
7
+ const configPath = (0, path_1.join)((0, os_1.homedir)(), '.narrative-os', 'config.json');
8
+ if ((0, fs_1.existsSync)(configPath)) {
9
+ const config = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
10
+ process.env.LLM_PROVIDER = config.provider;
11
+ // Use deepseek-chat (reasoner may not be available for all API keys)
12
+ process.env.LLM_MODEL = 'deepseek-chat';
13
+ if (config.provider === 'openai') {
14
+ process.env.OPENAI_API_KEY = config.apiKey;
15
+ }
16
+ else if (config.provider === 'deepseek') {
17
+ process.env.DEEPSEEK_API_KEY = config.apiKey;
18
+ }
19
+ console.log(`Loaded config: ${config.provider} / ${config.model}`);
20
+ }
21
+ // Now import engine
22
+ const index_js_1 = require("../index.js");
23
+ async function testGeneration() {
24
+ console.log('Testing chapter generation...\n');
25
+ const bible = (0, index_js_1.createStoryBible)('古诗集', '自然与人生', '古典诗歌', '唐朝', '优雅,含蓄', '一位诗人游历山水,写下对自然和人生的感悟', 3);
26
+ const bibleWithChar = (0, index_js_1.addCharacter)(bible, '李白', 'protagonist', ['豪放', '浪漫', '才华横溢'], ['游历名山大川', '留下千古诗篇']);
27
+ const state = (0, index_js_1.createStoryState)(bibleWithChar.id, 3);
28
+ const canon = (0, index_js_1.extractCanonFromBible)(bibleWithChar);
29
+ const context = {
30
+ bible: bibleWithChar,
31
+ state,
32
+ chapterNumber: 1,
33
+ targetWordCount: 500,
34
+ };
35
+ try {
36
+ const result = await (0, index_js_1.generateChapter)(context, { canon });
37
+ console.log('✅ Generation successful!\n');
38
+ console.log(`Title: ${result.chapter.title}`);
39
+ console.log(`Words: ${result.chapter.wordCount}`);
40
+ console.log(`Violations: ${result.violations.length}`);
41
+ console.log('\n--- Content Preview ---');
42
+ console.log(result.chapter.content.substring(0, 500) + '...');
43
+ console.log('\n--- Summary ---');
44
+ console.log(result.summary.summary);
45
+ }
46
+ catch (error) {
47
+ console.error('❌ Generation failed:', error);
48
+ }
49
+ }
50
+ testGeneration();
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltcGxlLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC9zaW1wbGUudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDJCQUE4QztBQUM5QywrQkFBNEI7QUFDNUIsMkJBQTZCO0FBRTdCLG9FQUFvRTtBQUNwRSxNQUFNLFVBQVUsR0FBRyxJQUFBLFdBQUksRUFBQyxJQUFBLFlBQU8sR0FBRSxFQUFFLGVBQWUsRUFBRSxhQUFhLENBQUMsQ0FBQztBQUNuRSxJQUFJLElBQUEsZUFBVSxFQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7SUFDM0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFBLGlCQUFZLEVBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDN0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztJQUMzQyxxRUFBcUU7SUFDckUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEdBQUcsZUFBZSxDQUFDO0lBQ3hDLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNqQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzdDLENBQUM7U0FBTSxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDMUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQy9DLENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixNQUFNLENBQUMsUUFBUSxNQUFNLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO0FBQ3JFLENBQUM7QUFFRCxvQkFBb0I7QUFDcEIsMENBQXVIO0FBR3ZILEtBQUssVUFBVSxjQUFjO0lBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQztJQUUvQyxNQUFNLEtBQUssR0FBRyxJQUFBLDJCQUFnQixFQUM1QixLQUFLLEVBQ0wsT0FBTyxFQUNQLE1BQU0sRUFDTixJQUFJLEVBQ0osT0FBTyxFQUNQLHNCQUFzQixFQUN0QixDQUFDLENBQ0YsQ0FBQztJQUVGLE1BQU0sYUFBYSxHQUFHLElBQUEsdUJBQVksRUFDaEMsS0FBSyxFQUNMLElBQUksRUFDSixhQUFhLEVBQ2IsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxFQUNwQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FDckIsQ0FBQztJQUVGLE1BQU0sS0FBSyxHQUFHLElBQUEsMkJBQWdCLEVBQUMsYUFBYSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNwRCxNQUFNLEtBQUssR0FBRyxJQUFBLGdDQUFxQixFQUFDLGFBQWEsQ0FBQyxDQUFDO0lBRW5ELE1BQU0sT0FBTyxHQUFzQjtRQUNqQyxLQUFLLEVBQUUsYUFBYTtRQUNwQixLQUFLO1FBQ0wsYUFBYSxFQUFFLENBQUM7UUFDaEIsZUFBZSxFQUFFLEdBQUc7S0FDckIsQ0FBQztJQUVGLElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFekQsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1FBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNsRCxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZELE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQztRQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFDOUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ2pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUV0QyxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDL0MsQ0FBQztBQUNILENBQUM7QUFFRCxjQUFjLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlYWRGaWxlU3luYywgZXhpc3RzU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnb3MnO1xyXG5cclxuLy8gTG9hZCBjb25maWcgQkVGT1JFIGltcG9ydGluZyBlbmdpbmUgKHRvIGluaXRpYWxpemUgTExNIGNvcnJlY3RseSlcclxuY29uc3QgY29uZmlnUGF0aCA9IGpvaW4oaG9tZWRpcigpLCAnLm5hcnJhdGl2ZS1vcycsICdjb25maWcuanNvbicpO1xyXG5pZiAoZXhpc3RzU3luYyhjb25maWdQYXRoKSkge1xyXG4gIGNvbnN0IGNvbmZpZyA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ1BhdGgsICd1dGYtOCcpKTtcclxuICBwcm9jZXNzLmVudi5MTE1fUFJPVklERVIgPSBjb25maWcucHJvdmlkZXI7XHJcbiAgLy8gVXNlIGRlZXBzZWVrLWNoYXQgKHJlYXNvbmVyIG1heSBub3QgYmUgYXZhaWxhYmxlIGZvciBhbGwgQVBJIGtleXMpXHJcbiAgcHJvY2Vzcy5lbnYuTExNX01PREVMID0gJ2RlZXBzZWVrLWNoYXQnO1xyXG4gIGlmIChjb25maWcucHJvdmlkZXIgPT09ICdvcGVuYWknKSB7XHJcbiAgICBwcm9jZXNzLmVudi5PUEVOQUlfQVBJX0tFWSA9IGNvbmZpZy5hcGlLZXk7XHJcbiAgfSBlbHNlIGlmIChjb25maWcucHJvdmlkZXIgPT09ICdkZWVwc2VlaycpIHtcclxuICAgIHByb2Nlc3MuZW52LkRFRVBTRUVLX0FQSV9LRVkgPSBjb25maWcuYXBpS2V5O1xyXG4gIH1cclxuICBjb25zb2xlLmxvZyhgTG9hZGVkIGNvbmZpZzogJHtjb25maWcucHJvdmlkZXJ9IC8gJHtjb25maWcubW9kZWx9YCk7XHJcbn1cclxuXHJcbi8vIE5vdyBpbXBvcnQgZW5naW5lXHJcbmltcG9ydCB7IGdlbmVyYXRlQ2hhcHRlciwgY3JlYXRlU3RvcnlCaWJsZSwgYWRkQ2hhcmFjdGVyLCBjcmVhdGVTdG9yeVN0YXRlLCBleHRyYWN0Q2Fub25Gcm9tQmlibGUgfSBmcm9tICcuLi9pbmRleC5qcyc7XHJcbmltcG9ydCB0eXBlIHsgR2VuZXJhdGlvbkNvbnRleHQgfSBmcm9tICcuLi9pbmRleC5qcyc7XHJcblxyXG5hc3luYyBmdW5jdGlvbiB0ZXN0R2VuZXJhdGlvbigpIHtcclxuICBjb25zb2xlLmxvZygnVGVzdGluZyBjaGFwdGVyIGdlbmVyYXRpb24uLi5cXG4nKTtcclxuXHJcbiAgY29uc3QgYmlibGUgPSBjcmVhdGVTdG9yeUJpYmxlKFxyXG4gICAgJ+WPpOivl+mbhicsXHJcbiAgICAn6Ieq54S25LiO5Lq655SfJyxcclxuICAgICflj6Tlhbjor5fmrYwnLFxyXG4gICAgJ+WUkOacnScsXHJcbiAgICAn5LyY6ZuF77yM5ZCr6JOEJyxcclxuICAgICfkuIDkvY3or5fkurrmuLjljoblsbHmsLTvvIzlhpnkuIvlr7noh6rnhLblkozkurrnlJ/nmoTmhJ/mgp8nLFxyXG4gICAgM1xyXG4gICk7XHJcblxyXG4gIGNvbnN0IGJpYmxlV2l0aENoYXIgPSBhZGRDaGFyYWN0ZXIoXHJcbiAgICBiaWJsZSxcclxuICAgICfmnY7nmb0nLFxyXG4gICAgJ3Byb3RhZ29uaXN0JyxcclxuICAgIFsn6LGq5pS+JywgJ+a1qua8qycsICfmiY3ljY7mqKrmuqInXSxcclxuICAgIFsn5ri45Y6G5ZCN5bGx5aSn5bedJywgJ+eVmeS4i+WNg+WPpOivl+evhyddXHJcbiAgKTtcclxuXHJcbiAgY29uc3Qgc3RhdGUgPSBjcmVhdGVTdG9yeVN0YXRlKGJpYmxlV2l0aENoYXIuaWQsIDMpO1xyXG4gIGNvbnN0IGNhbm9uID0gZXh0cmFjdENhbm9uRnJvbUJpYmxlKGJpYmxlV2l0aENoYXIpO1xyXG5cclxuICBjb25zdCBjb250ZXh0OiBHZW5lcmF0aW9uQ29udGV4dCA9IHtcclxuICAgIGJpYmxlOiBiaWJsZVdpdGhDaGFyLFxyXG4gICAgc3RhdGUsXHJcbiAgICBjaGFwdGVyTnVtYmVyOiAxLFxyXG4gICAgdGFyZ2V0V29yZENvdW50OiA1MDAsXHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdlbmVyYXRlQ2hhcHRlcihjb250ZXh0LCB7IGNhbm9uIH0pO1xyXG4gICAgXHJcbiAgICBjb25zb2xlLmxvZygn4pyFIEdlbmVyYXRpb24gc3VjY2Vzc2Z1bCFcXG4nKTtcclxuICAgIGNvbnNvbGUubG9nKGBUaXRsZTogJHtyZXN1bHQuY2hhcHRlci50aXRsZX1gKTtcclxuICAgIGNvbnNvbGUubG9nKGBXb3JkczogJHtyZXN1bHQuY2hhcHRlci53b3JkQ291bnR9YCk7XHJcbiAgICBjb25zb2xlLmxvZyhgVmlvbGF0aW9uczogJHtyZXN1bHQudmlvbGF0aW9ucy5sZW5ndGh9YCk7XHJcbiAgICBjb25zb2xlLmxvZygnXFxuLS0tIENvbnRlbnQgUHJldmlldyAtLS0nKTtcclxuICAgIGNvbnNvbGUubG9nKHJlc3VsdC5jaGFwdGVyLmNvbnRlbnQuc3Vic3RyaW5nKDAsIDUwMCkgKyAnLi4uJyk7XHJcbiAgICBjb25zb2xlLmxvZygnXFxuLS0tIFN1bW1hcnkgLS0tJyk7XHJcbiAgICBjb25zb2xlLmxvZyhyZXN1bHQuc3VtbWFyeS5zdW1tYXJ5KTtcclxuICAgIFxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBjb25zb2xlLmVycm9yKCfinYwgR2VuZXJhdGlvbiBmYWlsZWQ6JywgZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxudGVzdEdlbmVyYXRpb24oKTtcclxuIl19
@@ -0,0 +1 @@
1
+ export {};