@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.
- package/dist/agents/canonValidator.d.ts +9 -0
- package/dist/agents/canonValidator.js +51 -0
- package/dist/agents/chapterPlanner.d.ts +50 -0
- package/dist/agents/chapterPlanner.js +250 -0
- package/dist/agents/completeness.d.ts +7 -0
- package/dist/agents/completeness.js +51 -0
- package/dist/agents/memoryExtractor.d.ts +12 -0
- package/dist/agents/memoryExtractor.js +82 -0
- package/dist/agents/stateUpdater.d.ts +30 -0
- package/dist/agents/stateUpdater.js +150 -0
- package/dist/agents/storyDirector.d.ts +40 -0
- package/dist/agents/storyDirector.js +213 -0
- package/dist/agents/summarizer.d.ts +8 -0
- package/dist/agents/summarizer.js +56 -0
- package/dist/agents/tensionController.d.ts +68 -0
- package/dist/agents/tensionController.js +197 -0
- package/dist/agents/writer.d.ts +12 -0
- package/dist/agents/writer.js +148 -0
- package/dist/constraints/constraintGraph.d.ts +117 -0
- package/dist/constraints/constraintGraph.js +381 -0
- package/dist/constraints/validator.d.ts +58 -0
- package/dist/constraints/validator.js +236 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +115 -0
- package/dist/llm/client.d.ts +14 -0
- package/dist/llm/client.js +108 -0
- package/dist/memory/canonStore.d.ts +20 -0
- package/dist/memory/canonStore.js +110 -0
- package/dist/memory/memoryRetriever.d.ts +28 -0
- package/dist/memory/memoryRetriever.js +126 -0
- package/dist/memory/stateUpdater.d.ts +49 -0
- package/dist/memory/stateUpdater.js +315 -0
- package/dist/memory/vectorStore.d.ts +41 -0
- package/dist/memory/vectorStore.js +166 -0
- package/dist/pipeline/generateChapter.d.ts +17 -0
- package/dist/pipeline/generateChapter.js +75 -0
- package/dist/story/bible.d.ts +4 -0
- package/dist/story/bible.js +53 -0
- package/dist/story/state.d.ts +3 -0
- package/dist/story/state.js +27 -0
- package/dist/story/structuredState.d.ts +39 -0
- package/dist/story/structuredState.js +159 -0
- package/dist/test/canon.test.d.ts +1 -0
- package/dist/test/canon.test.js +104 -0
- package/dist/test/chapter-planner.test.d.ts +1 -0
- package/dist/test/chapter-planner.test.js +171 -0
- package/dist/test/constraints.test.d.ts +1 -0
- package/dist/test/constraints.test.js +210 -0
- package/dist/test/simple.test.d.ts +1 -0
- package/dist/test/simple.test.js +51 -0
- package/dist/test/state-updater.test.d.ts +1 -0
- package/dist/test/state-updater.test.js +200 -0
- package/dist/test/story-director.test.d.ts +1 -0
- package/dist/test/story-director.test.js +142 -0
- package/dist/test/structured-state.test.d.ts +1 -0
- package/dist/test/structured-state.test.js +144 -0
- package/dist/test/tension-controller.test.d.ts +1 -0
- package/dist/test/tension-controller.test.js +116 -0
- package/dist/test/vector-memory.test.d.ts +1 -0
- package/dist/test/vector-memory.test.js +153 -0
- package/dist/test/world-simulation.test.d.ts +1 -0
- package/dist/test/world-simulation.test.js +152 -0
- package/dist/types/index.d.ts +79 -0
- package/dist/types/index.js +3 -0
- package/dist/world/characterAgent.d.ts +73 -0
- package/dist/world/characterAgent.js +232 -0
- package/dist/world/eventResolver.d.ts +52 -0
- package/dist/world/eventResolver.js +205 -0
- package/dist/world/worldState.d.ts +93 -0
- package/dist/world/worldState.js +258 -0
- package/package.json +43 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CanonStore } from '../memory/canonStore.js';
|
|
2
|
+
export interface CanonValidationResult {
|
|
3
|
+
valid: boolean;
|
|
4
|
+
violations: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class CanonValidator {
|
|
7
|
+
validate(chapterText: string, canon: CanonStore): Promise<CanonValidationResult>;
|
|
8
|
+
}
|
|
9
|
+
export declare const canonValidator: CanonValidator;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canonValidator = exports.CanonValidator = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const VALIDATOR_PROMPT = `Check the following chapter against the Story Canon. Identify any contradictions.
|
|
6
|
+
|
|
7
|
+
## Story Canon
|
|
8
|
+
{{canon}}
|
|
9
|
+
|
|
10
|
+
## Chapter Text
|
|
11
|
+
{{chapterText}}
|
|
12
|
+
|
|
13
|
+
## Instructions
|
|
14
|
+
List any contradictions between the chapter and the canon facts. A contradiction occurs when:
|
|
15
|
+
- A character's status/background is different from canon
|
|
16
|
+
- A plot thread status is contradicted
|
|
17
|
+
- World rules are violated
|
|
18
|
+
|
|
19
|
+
Return JSON:
|
|
20
|
+
{
|
|
21
|
+
"valid": true/false,
|
|
22
|
+
"violations": ["description of contradiction 1", "description of contradiction 2"]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
If no contradictions, return {"valid": true, "violations": []}`;
|
|
26
|
+
class CanonValidator {
|
|
27
|
+
async validate(chapterText, canon) {
|
|
28
|
+
if (canon.facts.length === 0) {
|
|
29
|
+
return { valid: true, violations: [] };
|
|
30
|
+
}
|
|
31
|
+
const { formatCanonForPrompt } = await import('../memory/canonStore.js');
|
|
32
|
+
const canonSection = formatCanonForPrompt(canon);
|
|
33
|
+
const prompt = VALIDATOR_PROMPT
|
|
34
|
+
.replace('{{canon}}', canonSection)
|
|
35
|
+
.replace('{{chapterText}}', chapterText.substring(0, 3000));
|
|
36
|
+
const response = await (0, client_js_1.getLLM)().complete(prompt, {
|
|
37
|
+
temperature: 0.1,
|
|
38
|
+
maxTokens: 500,
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
const result = JSON.parse(response);
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return { valid: true, violations: [] };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.CanonValidator = CanonValidator;
|
|
50
|
+
exports.canonValidator = new CanonValidator();
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fub25WYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnRzL2Nhbm9uVmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGdEQUEwQztBQVExQyxNQUFNLGdCQUFnQixHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrREFvQnNDLENBQUM7QUFFaEUsTUFBYSxjQUFjO0lBQ3pCLEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBbUIsRUFBRSxLQUFpQjtRQUNuRCxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzdCLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUN6QyxDQUFDO1FBRUQsTUFBTSxFQUFFLG9CQUFvQixFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN6RSxNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVqRCxNQUFNLE1BQU0sR0FBRyxnQkFBZ0I7YUFDNUIsT0FBTyxDQUFDLFdBQVcsRUFBRSxZQUFZLENBQUM7YUFDbEMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7UUFFOUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFBLGtCQUFNLEdBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFO1lBQy9DLFdBQVcsRUFBRSxHQUFHO1lBQ2hCLFNBQVMsRUFBRSxHQUFHO1NBQ2YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQTBCLENBQUM7WUFDN0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUN6QyxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBekJELHdDQXlCQztBQUVZLFFBQUEsY0FBYyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBnZXRMTE0gfSBmcm9tICcuLi9sbG0vY2xpZW50LmpzJztcclxuaW1wb3J0IHR5cGUgeyBDYW5vblN0b3JlIH0gZnJvbSAnLi4vbWVtb3J5L2Nhbm9uU3RvcmUuanMnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBDYW5vblZhbGlkYXRpb25SZXN1bHQge1xyXG4gIHZhbGlkOiBib29sZWFuO1xyXG4gIHZpb2xhdGlvbnM6IHN0cmluZ1tdO1xyXG59XHJcblxyXG5jb25zdCBWQUxJREFUT1JfUFJPTVBUID0gYENoZWNrIHRoZSBmb2xsb3dpbmcgY2hhcHRlciBhZ2FpbnN0IHRoZSBTdG9yeSBDYW5vbi4gSWRlbnRpZnkgYW55IGNvbnRyYWRpY3Rpb25zLlxyXG5cclxuIyMgU3RvcnkgQ2Fub25cclxue3tjYW5vbn19XHJcblxyXG4jIyBDaGFwdGVyIFRleHRcclxue3tjaGFwdGVyVGV4dH19XHJcblxyXG4jIyBJbnN0cnVjdGlvbnNcclxuTGlzdCBhbnkgY29udHJhZGljdGlvbnMgYmV0d2VlbiB0aGUgY2hhcHRlciBhbmQgdGhlIGNhbm9uIGZhY3RzLiBBIGNvbnRyYWRpY3Rpb24gb2NjdXJzIHdoZW46XHJcbi0gQSBjaGFyYWN0ZXIncyBzdGF0dXMvYmFja2dyb3VuZCBpcyBkaWZmZXJlbnQgZnJvbSBjYW5vblxyXG4tIEEgcGxvdCB0aHJlYWQgc3RhdHVzIGlzIGNvbnRyYWRpY3RlZFxyXG4tIFdvcmxkIHJ1bGVzIGFyZSB2aW9sYXRlZFxyXG5cclxuUmV0dXJuIEpTT046XHJcbntcclxuICBcInZhbGlkXCI6IHRydWUvZmFsc2UsXHJcbiAgXCJ2aW9sYXRpb25zXCI6IFtcImRlc2NyaXB0aW9uIG9mIGNvbnRyYWRpY3Rpb24gMVwiLCBcImRlc2NyaXB0aW9uIG9mIGNvbnRyYWRpY3Rpb24gMlwiXVxyXG59XHJcblxyXG5JZiBubyBjb250cmFkaWN0aW9ucywgcmV0dXJuIHtcInZhbGlkXCI6IHRydWUsIFwidmlvbGF0aW9uc1wiOiBbXX1gO1xyXG5cclxuZXhwb3J0IGNsYXNzIENhbm9uVmFsaWRhdG9yIHtcclxuICBhc3luYyB2YWxpZGF0ZShjaGFwdGVyVGV4dDogc3RyaW5nLCBjYW5vbjogQ2Fub25TdG9yZSk6IFByb21pc2U8Q2Fub25WYWxpZGF0aW9uUmVzdWx0PiB7XHJcbiAgICBpZiAoY2Fub24uZmFjdHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIHJldHVybiB7IHZhbGlkOiB0cnVlLCB2aW9sYXRpb25zOiBbXSB9O1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgZm9ybWF0Q2Fub25Gb3JQcm9tcHQgfSA9IGF3YWl0IGltcG9ydCgnLi4vbWVtb3J5L2Nhbm9uU3RvcmUuanMnKTtcclxuICAgIGNvbnN0IGNhbm9uU2VjdGlvbiA9IGZvcm1hdENhbm9uRm9yUHJvbXB0KGNhbm9uKTtcclxuXHJcbiAgICBjb25zdCBwcm9tcHQgPSBWQUxJREFUT1JfUFJPTVBUXHJcbiAgICAgIC5yZXBsYWNlKCd7e2Nhbm9ufX0nLCBjYW5vblNlY3Rpb24pXHJcbiAgICAgIC5yZXBsYWNlKCd7e2NoYXB0ZXJUZXh0fX0nLCBjaGFwdGVyVGV4dC5zdWJzdHJpbmcoMCwgMzAwMCkpO1xyXG5cclxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZ2V0TExNKCkuY29tcGxldGUocHJvbXB0LCB7XHJcbiAgICAgIHRlbXBlcmF0dXJlOiAwLjEsXHJcbiAgICAgIG1heFRva2VuczogNTAwLFxyXG4gICAgfSk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgcmVzdWx0ID0gSlNPTi5wYXJzZShyZXNwb25zZSkgYXMgQ2Fub25WYWxpZGF0aW9uUmVzdWx0O1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiB7IHZhbGlkOiB0cnVlLCB2aW9sYXRpb25zOiBbXSB9O1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IGNhbm9uVmFsaWRhdG9yID0gbmV3IENhbm9uVmFsaWRhdG9yKCk7XHJcbiJdfQ==
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { StoryBible, StoryState } from '../types/index.js';
|
|
2
|
+
import type { StoryStructuredState } from '../story/structuredState.js';
|
|
3
|
+
import type { DirectorOutput, ChapterObjective } from './storyDirector.js';
|
|
4
|
+
export interface Scene {
|
|
5
|
+
id: string;
|
|
6
|
+
sequence: number;
|
|
7
|
+
goal: string;
|
|
8
|
+
description: string;
|
|
9
|
+
tension: number;
|
|
10
|
+
characters: string[];
|
|
11
|
+
setting: string;
|
|
12
|
+
estimatedWords: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ChapterOutline {
|
|
15
|
+
chapterNumber: number;
|
|
16
|
+
overallGoal: string;
|
|
17
|
+
tone: string;
|
|
18
|
+
totalEstimatedWords: number;
|
|
19
|
+
scenes: Scene[];
|
|
20
|
+
transitions: string[];
|
|
21
|
+
notes: string;
|
|
22
|
+
}
|
|
23
|
+
export interface PlannerContext {
|
|
24
|
+
bible: StoryBible;
|
|
25
|
+
state: StoryState;
|
|
26
|
+
structuredState: StoryStructuredState;
|
|
27
|
+
directorOutput: DirectorOutput;
|
|
28
|
+
targetWordCount?: number;
|
|
29
|
+
}
|
|
30
|
+
export declare class ChapterPlanner {
|
|
31
|
+
plan(context: PlannerContext): Promise<ChapterOutline>;
|
|
32
|
+
private buildPrompt;
|
|
33
|
+
/**
|
|
34
|
+
* Format chapter outline for writer prompt
|
|
35
|
+
*/
|
|
36
|
+
formatForPrompt(outline: ChapterOutline): string;
|
|
37
|
+
/**
|
|
38
|
+
* Generate fallback outline without LLM
|
|
39
|
+
*/
|
|
40
|
+
generateFallbackOutline(directorOutput: DirectorOutput, targetWordCount?: number): ChapterOutline;
|
|
41
|
+
/**
|
|
42
|
+
* Validate that outline meets objectives
|
|
43
|
+
*/
|
|
44
|
+
validateOutline(outline: ChapterOutline, objectives: ChapterObjective[]): {
|
|
45
|
+
valid: boolean;
|
|
46
|
+
coverage: number;
|
|
47
|
+
missedObjectives: string[];
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export declare const chapterPlanner: ChapterPlanner;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.chapterPlanner = exports.ChapterPlanner = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const CHAPTER_PLANNER_PROMPT = `You are the Chapter Planner for a narrative AI system. Convert chapter objectives into a detailed scene-by-scene outline.
|
|
6
|
+
|
|
7
|
+
## Story Context
|
|
8
|
+
|
|
9
|
+
**Title:** {{title}}
|
|
10
|
+
**Genre:** {{genre}}
|
|
11
|
+
**Setting:** {{setting}}
|
|
12
|
+
|
|
13
|
+
## Chapter Direction
|
|
14
|
+
|
|
15
|
+
**Chapter:** {{chapterNumber}}
|
|
16
|
+
**Overall Goal:** {{overallGoal}}
|
|
17
|
+
**Tone:** {{tone}}
|
|
18
|
+
**Target Word Count:** {{targetWordCount}}
|
|
19
|
+
|
|
20
|
+
### Objectives (in priority order)
|
|
21
|
+
{{objectives}}
|
|
22
|
+
|
|
23
|
+
### Focus Characters
|
|
24
|
+
{{focusCharacters}}
|
|
25
|
+
|
|
26
|
+
### Suggested Scenes
|
|
27
|
+
{{suggestedScenes}}
|
|
28
|
+
|
|
29
|
+
## Current Story State
|
|
30
|
+
|
|
31
|
+
**Story Tension:** {{storyTension}}%
|
|
32
|
+
**Target Tension:** {{targetTension}}%
|
|
33
|
+
|
|
34
|
+
### Character States
|
|
35
|
+
{{characters}}
|
|
36
|
+
|
|
37
|
+
### Active Plot Threads
|
|
38
|
+
{{plotThreads}}
|
|
39
|
+
|
|
40
|
+
## Your Task
|
|
41
|
+
|
|
42
|
+
Create a detailed scene-by-scene outline for this chapter. Each scene should:
|
|
43
|
+
1. Have a clear goal that serves the chapter objectives
|
|
44
|
+
2. Build tension progressively toward the chapter climax
|
|
45
|
+
3. Include specific characters and setting
|
|
46
|
+
4. Have an estimated word count (scenes typically 300-800 words)
|
|
47
|
+
|
|
48
|
+
Output JSON with this structure:
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
"chapterNumber": {{chapterNumber}},
|
|
52
|
+
"overallGoal": "{{overallGoal}}",
|
|
53
|
+
"tone": "{{tone}}",
|
|
54
|
+
"totalEstimatedWords": 2500,
|
|
55
|
+
"scenes": [
|
|
56
|
+
{
|
|
57
|
+
"id": "scene-1",
|
|
58
|
+
"sequence": 1,
|
|
59
|
+
"goal": "What this scene accomplishes",
|
|
60
|
+
"description": "Detailed description of what happens",
|
|
61
|
+
"tension": 0.2,
|
|
62
|
+
"characters": ["Character names present"],
|
|
63
|
+
"setting": "Where scene takes place",
|
|
64
|
+
"estimatedWords": 400
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"transitions": ["How scenes connect"],
|
|
68
|
+
"notes": "Additional guidance for the writer"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Guidelines:
|
|
72
|
+
- Create 3-6 scenes per chapter
|
|
73
|
+
- Tension should build progressively (low → medium → high)
|
|
74
|
+
- Each scene should serve at least one objective
|
|
75
|
+
- Opening scene: establish situation
|
|
76
|
+
- Middle scenes: develop conflict, advance objectives
|
|
77
|
+
- Final scene: climax or resolution hook
|
|
78
|
+
- Total word count should match target (default ~2500)`;
|
|
79
|
+
class ChapterPlanner {
|
|
80
|
+
async plan(context) {
|
|
81
|
+
const { bible, state, structuredState, directorOutput, targetWordCount = 2500 } = context;
|
|
82
|
+
const prompt = this.buildPrompt(bible, state, structuredState, directorOutput, targetWordCount);
|
|
83
|
+
const result = await (0, client_js_1.getLLM)().completeJSON(prompt, {
|
|
84
|
+
temperature: 0.4,
|
|
85
|
+
maxTokens: 2500,
|
|
86
|
+
});
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
buildPrompt(bible, state, structuredState, directorOutput, targetWordCount) {
|
|
90
|
+
const currentTension = Math.round(structuredState.tension * 100);
|
|
91
|
+
const targetTension = Math.round(4 * (state.currentChapter / state.totalChapters) * (1 - state.currentChapter / state.totalChapters) * 100);
|
|
92
|
+
// Format objectives
|
|
93
|
+
const objectives = directorOutput.objectives
|
|
94
|
+
.map(obj => {
|
|
95
|
+
const priorityEmoji = { critical: '🔴', high: '🟠', medium: '🟡', low: '🟢' }[obj.priority];
|
|
96
|
+
return `${priorityEmoji} [${obj.type.toUpperCase()}] ${obj.description}`;
|
|
97
|
+
})
|
|
98
|
+
.join('\n');
|
|
99
|
+
// Format characters
|
|
100
|
+
const characters = Object.values(structuredState.characters)
|
|
101
|
+
.map(c => `- ${c.name}: ${c.emotionalState}, at ${c.location}`)
|
|
102
|
+
.join('\n') || 'No character data.';
|
|
103
|
+
// Format plot threads
|
|
104
|
+
const plotThreads = Object.values(structuredState.plotThreads)
|
|
105
|
+
.filter(t => t.status !== 'resolved')
|
|
106
|
+
.map(t => `- ${t.name} (${t.status}, ${Math.round(t.tension * 100)}% tension)`)
|
|
107
|
+
.join('\n') || 'No active plot threads.';
|
|
108
|
+
// Format suggested scenes
|
|
109
|
+
const suggestedScenes = directorOutput.suggestedScenes
|
|
110
|
+
.map(s => `- ${s}`)
|
|
111
|
+
.join('\n') || 'No suggestions.';
|
|
112
|
+
return CHAPTER_PLANNER_PROMPT
|
|
113
|
+
.replace('{{title}}', bible.title)
|
|
114
|
+
.replace('{{genre}}', bible.genre)
|
|
115
|
+
.replace('{{setting}}', bible.setting)
|
|
116
|
+
.replace(/{{chapterNumber}}/g, directorOutput.chapterNumber.toString())
|
|
117
|
+
.replace('{{overallGoal}}', directorOutput.overallGoal)
|
|
118
|
+
.replace('{{tone}}', directorOutput.tone)
|
|
119
|
+
.replace('{{targetWordCount}}', `${targetWordCount} words`)
|
|
120
|
+
.replace('{{objectives}}', objectives)
|
|
121
|
+
.replace('{{focusCharacters}}', directorOutput.focusCharacters.join(', '))
|
|
122
|
+
.replace('{{suggestedScenes}}', suggestedScenes)
|
|
123
|
+
.replace('{{storyTension}}', currentTension.toString())
|
|
124
|
+
.replace('{{targetTension}}', targetTension.toString())
|
|
125
|
+
.replace('{{characters}}', characters)
|
|
126
|
+
.replace('{{plotThreads}}', plotThreads);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Format chapter outline for writer prompt
|
|
130
|
+
*/
|
|
131
|
+
formatForPrompt(outline) {
|
|
132
|
+
const lines = ['## Chapter Outline'];
|
|
133
|
+
lines.push(`\n**Chapter ${outline.chapterNumber}: ${outline.overallGoal}**`);
|
|
134
|
+
lines.push(`**Tone:** ${outline.tone}`);
|
|
135
|
+
lines.push(`**Estimated Length:** ${outline.totalEstimatedWords} words`);
|
|
136
|
+
if (outline.scenes.length > 0) {
|
|
137
|
+
lines.push('\n### Scene Breakdown');
|
|
138
|
+
for (const scene of outline.scenes) {
|
|
139
|
+
const tensionBar = '█'.repeat(Math.round(scene.tension * 10)) + '░'.repeat(10 - Math.round(scene.tension * 10));
|
|
140
|
+
lines.push(`\n**Scene ${scene.sequence}** [${tensionBar}] ${Math.round(scene.tension * 100)}% tension`);
|
|
141
|
+
lines.push(`- **Goal:** ${scene.goal}`);
|
|
142
|
+
lines.push(`- **Setting:** ${scene.setting}`);
|
|
143
|
+
lines.push(`- **Characters:** ${scene.characters.join(', ')}`);
|
|
144
|
+
lines.push(`- **Description:** ${scene.description}`);
|
|
145
|
+
lines.push(`- **Estimated:** ${scene.estimatedWords} words`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (outline.transitions.length > 0) {
|
|
149
|
+
lines.push('\n### Scene Transitions');
|
|
150
|
+
for (let i = 0; i < outline.transitions.length; i++) {
|
|
151
|
+
lines.push(`${i + 1} → ${i + 2}: ${outline.transitions[i]}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (outline.notes) {
|
|
155
|
+
lines.push(`\n**Planner Notes:** ${outline.notes}`);
|
|
156
|
+
}
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Generate fallback outline without LLM
|
|
161
|
+
*/
|
|
162
|
+
generateFallbackOutline(directorOutput, targetWordCount = 2500) {
|
|
163
|
+
const scenes = [];
|
|
164
|
+
const sceneCount = Math.max(3, Math.min(6, Math.floor(targetWordCount / 500)));
|
|
165
|
+
const wordsPerScene = Math.floor(targetWordCount / sceneCount);
|
|
166
|
+
// Build scenes based on objectives
|
|
167
|
+
const criticalObjectives = directorOutput.objectives.filter(o => o.priority === 'critical');
|
|
168
|
+
const highObjectives = directorOutput.objectives.filter(o => o.priority === 'high');
|
|
169
|
+
// Scene 1: Setup
|
|
170
|
+
scenes.push({
|
|
171
|
+
id: 'scene-1',
|
|
172
|
+
sequence: 1,
|
|
173
|
+
goal: 'Establish current situation and character states',
|
|
174
|
+
description: 'Opening scene that sets up the chapter context',
|
|
175
|
+
tension: 0.2,
|
|
176
|
+
characters: directorOutput.focusCharacters.slice(0, 2),
|
|
177
|
+
setting: 'Current location',
|
|
178
|
+
estimatedWords: wordsPerScene,
|
|
179
|
+
});
|
|
180
|
+
// Middle scenes: Build tension and address objectives
|
|
181
|
+
for (let i = 2; i < sceneCount; i++) {
|
|
182
|
+
const tension = 0.3 + (i / sceneCount) * 0.5; // Build from 30% to 80%
|
|
183
|
+
const objective = criticalObjectives[i - 2] || highObjectives[i - 2];
|
|
184
|
+
scenes.push({
|
|
185
|
+
id: `scene-${i}`,
|
|
186
|
+
sequence: i,
|
|
187
|
+
goal: objective ? `Address: ${objective.description.substring(0, 50)}...` : 'Develop plot and character',
|
|
188
|
+
description: objective
|
|
189
|
+
? `Scene focusing on ${objective.type} objective related to ${objective.relatedCharacter || 'plot'}`
|
|
190
|
+
: 'Development scene advancing the story',
|
|
191
|
+
tension: Math.round(tension * 100) / 100,
|
|
192
|
+
characters: directorOutput.focusCharacters,
|
|
193
|
+
setting: 'Story location',
|
|
194
|
+
estimatedWords: wordsPerScene,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Final scene: Climax/Resolution
|
|
198
|
+
scenes.push({
|
|
199
|
+
id: `scene-${sceneCount}`,
|
|
200
|
+
sequence: sceneCount,
|
|
201
|
+
goal: criticalObjectives[0]?.description || 'Chapter climax or resolution',
|
|
202
|
+
description: 'Climactic scene that resolves or escalates the chapter tension',
|
|
203
|
+
tension: 0.9,
|
|
204
|
+
characters: directorOutput.focusCharacters,
|
|
205
|
+
setting: 'Key location',
|
|
206
|
+
estimatedWords: wordsPerScene,
|
|
207
|
+
});
|
|
208
|
+
// Generate transitions
|
|
209
|
+
const transitions = [];
|
|
210
|
+
for (let i = 0; i < scenes.length - 1; i++) {
|
|
211
|
+
transitions.push(`Natural progression from ${scenes[i].goal} to ${scenes[i + 1].goal}`);
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
chapterNumber: directorOutput.chapterNumber,
|
|
215
|
+
overallGoal: directorOutput.overallGoal,
|
|
216
|
+
tone: directorOutput.tone,
|
|
217
|
+
totalEstimatedWords: scenes.reduce((sum, s) => sum + s.estimatedWords, 0),
|
|
218
|
+
scenes,
|
|
219
|
+
transitions,
|
|
220
|
+
notes: 'Auto-generated outline based on director objectives. Adjust as needed for narrative flow.',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Validate that outline meets objectives
|
|
225
|
+
*/
|
|
226
|
+
validateOutline(outline, objectives) {
|
|
227
|
+
const covered = new Set();
|
|
228
|
+
const missed = [];
|
|
229
|
+
// Check each objective against scenes
|
|
230
|
+
for (const obj of objectives) {
|
|
231
|
+
const isCovered = outline.scenes.some(scene => scene.goal.toLowerCase().includes(obj.type) ||
|
|
232
|
+
scene.description.toLowerCase().includes(obj.description.toLowerCase().substring(0, 20)));
|
|
233
|
+
if (isCovered) {
|
|
234
|
+
covered.add(obj.id);
|
|
235
|
+
}
|
|
236
|
+
else if (obj.priority === 'critical' || obj.priority === 'high') {
|
|
237
|
+
missed.push(obj.description);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const coverage = objectives.length > 0 ? covered.size / objectives.length : 1;
|
|
241
|
+
return {
|
|
242
|
+
valid: missed.length === 0,
|
|
243
|
+
coverage,
|
|
244
|
+
missedObjectives: missed,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.ChapterPlanner = ChapterPlanner;
|
|
249
|
+
exports.chapterPlanner = new ChapterPlanner();
|
|
250
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcHRlclBsYW5uZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnRzL2NoYXB0ZXJQbGFubmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGdEQUEwQztBQWtDMUMsTUFBTSxzQkFBc0IsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozt1REF5RXdCLENBQUM7QUFFeEQsTUFBYSxjQUFjO0lBQ3pCLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBdUI7UUFDaEMsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLGNBQWMsRUFBRSxlQUFlLEdBQUcsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDO1FBRTFGLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBRWhHLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBQSxrQkFBTSxHQUFFLENBQUMsWUFBWSxDQUFpQixNQUFNLEVBQUU7WUFDakUsV0FBVyxFQUFFLEdBQUc7WUFDaEIsU0FBUyxFQUFFLElBQUk7U0FDaEIsQ0FBQyxDQUFDO1FBRUgsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVPLFdBQVcsQ0FDakIsS0FBaUIsRUFDakIsS0FBaUIsRUFDakIsZUFBcUMsRUFDckMsY0FBOEIsRUFDOUIsZUFBdUI7UUFFdkIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQzlCLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FB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RUFBRSxDQUFDLENBQUM7WUFDdEIsQ0FBQztpQkFBTSxJQUFJLEdBQUcsQ0FBQyxRQUFRLEtBQUssVUFBVSxJQUFJLEdBQUcsQ0FBQyxRQUFRLEtBQUssTUFBTSxFQUFFLENBQUM7Z0JBQ2xFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTlFLE9BQU87WUFDTCxLQUFLLEVBQUUsTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQzFCLFFBQVE7WUFDUixnQkFBZ0IsRUFBRSxNQUFNO1NBQ3pCLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFyTkQsd0NBcU5DO0FBRVksUUFBQSxjQUFjLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldExMTSB9IGZyb20gJy4uL2xsbS9jbGllbnQuanMnO1xyXG5pbXBvcnQgdHlwZSB7IFN0b3J5QmlibGUsIFN0b3J5U3RhdGUgfSBmcm9tICcuLi90eXBlcy9pbmRleC5qcyc7XHJcbmltcG9ydCB0eXBlIHsgU3RvcnlTdHJ1Y3R1cmVkU3RhdGUgfSBmcm9tICcuLi9zdG9yeS9zdHJ1Y3R1cmVkU3RhdGUuanMnO1xyXG5pbXBvcnQgdHlwZSB7IERpcmVjdG9yT3V0cHV0LCBDaGFwdGVyT2JqZWN0aXZlIH0gZnJvbSAnLi9zdG9yeURpcmVjdG9yLmpzJztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgU2NlbmUge1xyXG4gIGlkOiBzdHJpbmc7XHJcbiAgc2VxdWVuY2U6IG51bWJlcjtcclxuICBnb2FsOiBzdHJpbmc7XHJcbiAgZGVzY3JpcHRpb246IHN0cmluZztcclxuICB0ZW5zaW9uOiBudW1iZXI7IC8vIDAuMCB0byAxLjBcclxuICBjaGFyYWN0ZXJzOiBzdHJpbmdbXTtcclxuICBzZXR0aW5nOiBzdHJpbmc7XHJcbiAgZXN0aW1hdGVkV29yZHM6IG51bWJlcjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBDaGFwdGVyT3V0bGluZSB7XHJcbiAgY2hhcHRlck51bWJlcjogbnVtYmVyO1xyXG4gIG92ZXJhbGxHb2FsOiBzdHJpbmc7XHJcbiAgdG9uZTogc3RyaW5nO1xyXG4gIHRvdGFsRXN0aW1hdGVkV29yZHM6IG51bWJlcjtcclxuICBzY2VuZXM6IFNjZW5lW107XHJcbiAgdHJhbnNpdGlvbnM6IHN0cmluZ1tdO1xyXG4gIG5vdGVzOiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGxhbm5lckNvbnRleHQge1xyXG4gIGJpYmxlOiBTdG9yeUJpYmxlO1xyXG4gIHN0YXRlOiBTdG9yeVN0YXRlO1xyXG4gIHN0cnVjdHVyZWRTdGF0ZTogU3RvcnlTdHJ1Y3R1cmVkU3RhdGU7XHJcbiAgZGlyZWN0b3JPdXRwdXQ6IERpcmVjdG9yT3V0cHV0O1xyXG4gIHRhcmdldFdvcmRDb3VudD86IG51bWJlcjtcclxufVxyXG5cclxuY29uc3QgQ0hBUFRFUl9QTEFOTkVSX1BST01QVCA9IGBZb3UgYXJlIHRoZSBDaGFwdGVyIFBsYW5uZXIgZm9yIGEgbmFycmF0aXZlIEFJIHN5c3RlbS4gQ29udmVydCBjaGFwdGVyIG9iamVjdGl2ZXMgaW50byBhIGRldGFpbGVkIHNjZW5lLWJ5LXNjZW5lIG91dGxpbmUuXHJcblxyXG4jIyBTdG9yeSBDb250ZXh0XHJcblxyXG4qKlRpdGxlOioqIHt7dGl0bGV9fVxyXG4qKkdlbnJlOioqIHt7Z2VucmV9fVxyXG4qKlNldHRpbmc6Kioge3tzZXR0aW5nfX1cclxuXHJcbiMjIENoYXB0ZXIgRGlyZWN0aW9uXHJcblxyXG4qKkNoYXB0ZXI6Kioge3tjaGFwdGVyTnVtYmVyfX1cclxuKipPdmVyYWxsIEdvYWw6Kioge3tvdmVyYWxsR29hbH19XHJcbioqVG9uZToqKiB7e3RvbmV9fVxyXG4qKlRhcmdldCBXb3JkIENvdW50OioqIHt7dGFyZ2V0V29yZENvdW50fX1cclxuXHJcbiMjIyBPYmplY3RpdmVzIChpbiBwcmlvcml0eSBvcmRlcilcclxue3tvYmplY3RpdmVzfX1cclxuXHJcbiMjIyBGb2N1cyBDaGFyYWN0ZXJzXHJcbnt7Zm9jdXNDaGFyYWN0ZXJzfX1cclxuXHJcbiMjIyBTdWdnZXN0ZWQgU2NlbmVzXHJcbnt7c3VnZ2VzdGVkU2NlbmVzfX1cclxuXHJcbiMjIEN1cnJlbnQgU3RvcnkgU3RhdGVcclxuXHJcbioqU3RvcnkgVGVuc2lvbjoqKiB7e3N0b3J5VGVuc2lvbn19JVxyXG4qKlRhcmdldCBUZW5zaW9uOioqIHt7dGFyZ2V0VGVuc2lvbn19JVxyXG5cclxuIyMjIENoYXJhY3RlciBTdGF0ZXNcclxue3tjaGFyYWN0ZXJzfX1cclxuXHJcbiMjIyBBY3RpdmUgUGxvdCBUaHJlYWRzXHJcbnt7cGxvdFRocmVhZHN9fVxyXG5cclxuIyMgWW91ciBUYXNrXHJcblxyXG5DcmVhdGUgYSBkZXRhaWxlZCBzY2VuZS1ieS1zY2VuZSBvdXRsaW5lIGZvciB0aGlzIGNoYXB0ZXIuIEVhY2ggc2NlbmUgc2hvdWxkOlxyXG4xLiBIYXZlIGEgY2xlYXIgZ29hbCB0aGF0IHNlcnZlcyB0aGUgY2hhcHRlciBvYmplY3RpdmVzXHJcbjIuIEJ1aWxkIHRlbnNpb24gcHJvZ3Jlc3NpdmVseSB0b3dhcmQgdGhlIGNoYXB0ZXIgY2xpbWF4XHJcbjMuIEluY2x1ZGUgc3BlY2lmaWMgY2hhcmFjdGVycyBhbmQgc2V0dGluZ1xyXG40LiBIYXZlIGFuIGVzdGltYXRlZCB3b3JkIGNvdW50IChzY2VuZXMgdHlwaWNhbGx5IDMwMC04MDAgd29yZHMpXHJcblxyXG5PdXRwdXQgSlNPTiB3aXRoIHRoaXMgc3RydWN0dXJlOlxyXG5cclxue1xyXG4gIFwiY2hhcHRlck51bWJlclwiOiB7e2NoYXB0ZXJOdW1iZXJ9fSxcclxuICBcIm92ZXJhbGxHb2FsXCI6IFwie3tvdmVyYWxsR29hbH19XCIsXHJcbiAgXCJ0b25lXCI6IFwie3t0b25lfX1cIixcclxuICBcInRvdGFsRXN0aW1hdGVkV29yZHNcIjogMjUwMCxcclxuICBcInNjZW5lc1wiOiBbXHJcbiAgICB7XHJcbiAgICAgIFwiaWRcIjogXCJzY2VuZS0xXCIsXHJcbiAgICAgIFwic2VxdWVuY2VcIjogMSxcclxuICAgICAgXCJnb2FsXCI6IFwiV2hhdCB0aGlzIHNjZW5lIGFjY29tcGxpc2hlc1wiLFxyXG4gICAgICBcImRlc2NyaXB0aW9uXCI6IFwiRGV0YWlsZWQgZGVzY3JpcHRpb24gb2Ygd2hhdCBoYXBwZW5zXCIsXHJcbiAgICAgIFwidGVuc2lvblwiOiAwLjIsXHJcbiAgICAgIFwiY2hhcmFjdGVyc1wiOiBbXCJDaGFyYWN0ZXIgbmFtZXMgcHJlc2VudFwiXSxcclxuICAgICAgXCJzZXR0aW5nXCI6IFwiV2hlcmUgc2NlbmUgdGFrZXMgcGxhY2VcIixcclxuICAgICAgXCJlc3RpbWF0ZWRXb3Jkc1wiOiA0MDBcclxuICAgIH1cclxuICBdLFxyXG4gIFwidHJhbnNpdGlvbnNcIjogW1wiSG93IHNjZW5lcyBjb25uZWN0XCJdLFxyXG4gIFwibm90ZXNcIjogXCJBZGRpdGlvbmFsIGd1aWRhbmNlIGZvciB0aGUgd3JpdGVyXCJcclxufVxyXG5cclxuR3VpZGVsaW5lczpcclxuLSBDcmVhdGUgMy02IHNjZW5lcyBwZXIgY2hhcHRlclxyXG4tIFRlbnNpb24gc2hvdWxkIGJ1aWxkIHByb2dyZXNzaXZlbHkgKGxvdyDihpIgbWVkaXVtIOKGkiBoaWdoKVxyXG4tIEVhY2ggc2NlbmUgc2hvdWxkIHNlcnZlIGF0IGxlYXN0IG9uZSBvYmplY3RpdmVcclxuLSBPcGVuaW5nIHNjZW5lOiBlc3RhYmxpc2ggc2l0dWF0aW9uXHJcbi0gTWlkZGxlIHNjZW5lczogZGV2ZWxvcCBjb25mbGljdCwgYWR2YW5jZSBvYmplY3RpdmVzXHJcbi0gRmluYWwgc2NlbmU6IGNsaW1heCBvciByZXNvbHV0aW9uIGhvb2tcclxuLSBUb3RhbCB3b3JkIGNvdW50IHNob3VsZCBtYXRjaCB0YXJnZXQgKGRlZmF1bHQgfjI1MDApYDtcclxuXHJcbmV4cG9ydCBjbGFzcyBDaGFwdGVyUGxhbm5lciB7XHJcbiAgYXN5bmMgcGxhbihjb250ZXh0OiBQbGFubmVyQ29udGV4dCk6IFByb21pc2U8Q2hhcHRlck91dGxpbmU+IHtcclxuICAgIGNvbnN0IHsgYmlibGUsIHN0YXRlLCBzdHJ1Y3R1cmVkU3RhdGUsIGRpcmVjdG9yT3V0cHV0LCB0YXJnZXRXb3JkQ291bnQgPSAyNTAwIH0gPSBjb250ZXh0O1xyXG4gICAgXHJcbiAgICBjb25zdCBwcm9tcHQgPSB0aGlzLmJ1aWxkUHJvbXB0KGJpYmxlLCBzdGF0ZSwgc3RydWN0dXJlZFN0YXRlLCBkaXJlY3Rvck91dHB1dCwgdGFyZ2V0V29yZENvdW50KTtcclxuICAgIFxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2V0TExNKCkuY29tcGxldGVKU09OPENoYXB0ZXJPdXRsaW5lPihwcm9tcHQsIHtcclxuICAgICAgdGVtcGVyYXR1cmU6IDAuNCxcclxuICAgICAgbWF4VG9rZW5zOiAyNTAwLFxyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG4gIFxyXG4gIHByaXZhdGUgYnVpbGRQcm9tcHQoXHJcbiAgICBiaWJsZTogU3RvcnlCaWJsZSxcclxuICAgIHN0YXRlOiBTdG9yeVN0YXRlLFxyXG4gICAgc3RydWN0dXJlZFN0YXRlOiBTdG9yeVN0cnVjdHVyZWRTdGF0ZSxcclxuICAgIGRpcmVjdG9yT3V0cHV0OiBEaXJlY3Rvck91dHB1dCxcclxuICAgIHRhcmdldFdvcmRDb3VudDogbnVtYmVyXHJcbiAgKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGN1cnJlbnRUZW5zaW9uID0gTWF0aC5yb3VuZChzdHJ1Y3R1cmVkU3RhdGUudGVuc2lvbiAqIDEwMCk7XHJcbiAgICBjb25zdCB0YXJnZXRUZW5zaW9uID0gTWF0aC5yb3VuZChcclxuICAgICAgNCAqIChzdGF0ZS5jdXJyZW50Q2hhcHRlciAvIHN0YXRlLnRvdGFsQ2hhcHRlcnMpICogKDEgLSBzdGF0ZS5jdXJyZW50Q2hhcHRlciAvIHN0YXRlLnRvdGFsQ2hhcHRlcnMpICogMTAwXHJcbiAgICApO1xyXG4gICAgXHJcbiAgICAvLyBGb3JtYXQgb2JqZWN0aXZlc1xyXG4gICAgY29uc3Qgb2JqZWN0aXZlcyA9IGRpcmVjdG9yT3V0cHV0Lm9iamVjdGl2ZXNcclxuICAgICAgLm1hcChvYmogPT4ge1xyXG4gICAgICAgIGNvbnN0IHByaW9yaXR5RW1vamkgPSB7IGNyaXRpY2FsOiAn8J+UtCcsIGhpZ2g6ICfwn5+gJywgbWVkaXVtOiAn8J+foScsIGxvdzogJ/Cfn6InIH1bb2JqLnByaW9yaXR5XTtcclxuICAgICAgICByZXR1cm4gYCR7cHJpb3JpdHlFbW9qaX0gWyR7b2JqLnR5cGUudG9VcHBlckNhc2UoKX1dICR7b2JqLmRlc2NyaXB0aW9ufWA7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5qb2luKCdcXG4nKTtcclxuICAgIFxyXG4gICAgLy8gRm9ybWF0IGNoYXJhY3RlcnNcclxuICAgIGNvbnN0IGNoYXJhY3RlcnMgPSBPYmplY3QudmFsdWVzKHN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzKVxyXG4gICAgICAubWFwKGMgPT4gYC0gJHtjLm5hbWV9OiAke2MuZW1vdGlvbmFsU3RhdGV9LCBhdCAke2MubG9jYXRpb259YClcclxuICAgICAgLmpvaW4oJ1xcbicpIHx8ICdObyBjaGFyYWN0ZXIgZGF0YS4nO1xyXG4gICAgXHJcbiAgICAvLyBGb3JtYXQgcGxvdCB0aHJlYWRzXHJcbiAgICBjb25zdCBwbG90VGhyZWFkcyA9IE9iamVjdC52YWx1ZXMoc3RydWN0dXJlZFN0YXRlLnBsb3RUaHJlYWRzKVxyXG4gICAgICAuZmlsdGVyKHQgPT4gdC5zdGF0dXMgIT09ICdyZXNvbHZlZCcpXHJcbiAgICAgIC5tYXAodCA9PiBgLSAke3QubmFtZX0gKCR7dC5zdGF0dXN9LCAke01hdGgucm91bmQodC50ZW5zaW9uICogMTAwKX0lIHRlbnNpb24pYClcclxuICAgICAgLmpvaW4oJ1xcbicpIHx8ICdObyBhY3RpdmUgcGxvdCB0aHJlYWRzLic7XHJcbiAgICBcclxuICAgIC8vIEZvcm1hdCBzdWdnZXN0ZWQgc2NlbmVzXHJcbiAgICBjb25zdCBzdWdnZXN0ZWRTY2VuZXMgPSBkaXJlY3Rvck91dHB1dC5zdWdnZXN0ZWRTY2VuZXNcclxuICAgICAgLm1hcChzID0+IGAtICR7c31gKVxyXG4gICAgICAuam9pbignXFxuJykgfHwgJ05vIHN1Z2dlc3Rpb25zLic7XHJcbiAgICBcclxuICAgIHJldHVybiBDSEFQVEVSX1BMQU5ORVJfUFJPTVBUXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RpdGxlfX0nLCBiaWJsZS50aXRsZSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Z2VucmV9fScsIGJpYmxlLmdlbnJlKVxyXG4gICAgICAucmVwbGFjZSgne3tzZXR0aW5nfX0nLCBiaWJsZS5zZXR0aW5nKVxyXG4gICAgICAucmVwbGFjZSgve3tjaGFwdGVyTnVtYmVyfX0vZywgZGlyZWN0b3JPdXRwdXQuY2hhcHRlck51bWJlci50b1N0cmluZygpKVxyXG4gICAgICAucmVwbGFjZSgne3tvdmVyYWxsR29hbH19JywgZGlyZWN0b3JPdXRwdXQub3ZlcmFsbEdvYWwpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RvbmV9fScsIGRpcmVjdG9yT3V0cHV0LnRvbmUpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RhcmdldFdvcmRDb3VudH19JywgYCR7dGFyZ2V0V29yZENvdW50fSB3b3Jkc2ApXHJcbiAgICAgIC5yZXBsYWNlKCd7e29iamVjdGl2ZXN9fScsIG9iamVjdGl2ZXMpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2ZvY3VzQ2hhcmFjdGVyc319JywgZGlyZWN0b3JPdXRwdXQuZm9jdXNDaGFyYWN0ZXJzLmpvaW4oJywgJykpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3N1Z2dlc3RlZFNjZW5lc319Jywgc3VnZ2VzdGVkU2NlbmVzKVxyXG4gICAgICAucmVwbGFjZSgne3tzdG9yeVRlbnNpb259fScsIGN1cnJlbnRUZW5zaW9uLnRvU3RyaW5nKCkpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RhcmdldFRlbnNpb259fScsIHRhcmdldFRlbnNpb24udG9TdHJpbmcoKSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Y2hhcmFjdGVyc319JywgY2hhcmFjdGVycylcclxuICAgICAgLnJlcGxhY2UoJ3t7cGxvdFRocmVhZHN9fScsIHBsb3RUaHJlYWRzKTtcclxuICB9XHJcbiAgXHJcbiAgLyoqXHJcbiAgICogRm9ybWF0IGNoYXB0ZXIgb3V0bGluZSBmb3Igd3JpdGVyIHByb21wdFxyXG4gICAqL1xyXG4gIGZvcm1hdEZvclByb21wdChvdXRsaW5lOiBDaGFwdGVyT3V0bGluZSk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbJyMjIENoYXB0ZXIgT3V0bGluZSddO1xyXG4gICAgXHJcbiAgICBsaW5lcy5wdXNoKGBcXG4qKkNoYXB0ZXIgJHtvdXRsaW5lLmNoYXB0ZXJOdW1iZXJ9OiAke291dGxpbmUub3ZlcmFsbEdvYWx9KipgKTtcclxuICAgIGxpbmVzLnB1c2goYCoqVG9uZToqKiAke291dGxpbmUudG9uZX1gKTtcclxuICAgIGxpbmVzLnB1c2goYCoqRXN0aW1hdGVkIExlbmd0aDoqKiAke291dGxpbmUudG90YWxFc3RpbWF0ZWRXb3Jkc30gd29yZHNgKTtcclxuICAgIFxyXG4gICAgaWYgKG91dGxpbmUuc2NlbmVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgbGluZXMucHVzaCgnXFxuIyMjIFNjZW5lIEJyZWFrZG93bicpO1xyXG4gICAgICBcclxuICAgICAgZm9yIChjb25zdCBzY2VuZSBvZiBvdXRsaW5lLnNjZW5lcykge1xyXG4gICAgICAgIGNvbnN0IHRlbnNpb25CYXIgPSAn4paIJy5yZXBlYXQoTWF0aC5yb3VuZChzY2VuZS50ZW5zaW9uICogMTApKSArICfilpEnLnJlcGVhdCgxMCAtIE1hdGgucm91bmQoc2NlbmUudGVuc2lvbiAqIDEwKSk7XHJcbiAgICAgICAgbGluZXMucHVzaChgXFxuKipTY2VuZSAke3NjZW5lLnNlcXVlbmNlfSoqIFske3RlbnNpb25CYXJ9XSAke01hdGgucm91bmQoc2NlbmUudGVuc2lvbiAqIDEwMCl9JSB0ZW5zaW9uYCk7XHJcbiAgICAgICAgbGluZXMucHVzaChgLSAqKkdvYWw6KiogJHtzY2VuZS5nb2FsfWApO1xyXG4gICAgICAgIGxpbmVzLnB1c2goYC0gKipTZXR0aW5nOioqICR7c2NlbmUuc2V0dGluZ31gKTtcclxuICAgICAgICBsaW5lcy5wdXNoKGAtICoqQ2hhcmFjdGVyczoqKiAke3NjZW5lLmNoYXJhY3RlcnMuam9pbignLCAnKX1gKTtcclxuICAgICAgICBsaW5lcy5wdXNoKGAtICoqRGVzY3JpcHRpb246KiogJHtzY2VuZS5kZXNjcmlwdGlvbn1gKTtcclxuICAgICAgICBsaW5lcy5wdXNoKGAtICoqRXN0aW1hdGVkOioqICR7c2NlbmUuZXN0aW1hdGVkV29yZHN9IHdvcmRzYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIFxyXG4gICAgaWYgKG91dGxpbmUudHJhbnNpdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBsaW5lcy5wdXNoKCdcXG4jIyMgU2NlbmUgVHJhbnNpdGlvbnMnKTtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvdXRsaW5lLnRyYW5zaXRpb25zLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgbGluZXMucHVzaChgJHtpICsgMX0g4oaSICR7aSArIDJ9OiAke291dGxpbmUudHJhbnNpdGlvbnNbaV19YCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIFxyXG4gICAgaWYgKG91dGxpbmUubm90ZXMpIHtcclxuICAgICAgbGluZXMucHVzaChgXFxuKipQbGFubmVyIE5vdGVzOioqICR7b3V0bGluZS5ub3Rlc31gKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xyXG4gIH1cclxuICBcclxuICAvKipcclxuICAgKiBHZW5lcmF0ZSBmYWxsYmFjayBvdXRsaW5lIHdpdGhvdXQgTExNXHJcbiAgICovXHJcbiAgZ2VuZXJhdGVGYWxsYmFja091dGxpbmUoXHJcbiAgICBkaXJlY3Rvck91dHB1dDogRGlyZWN0b3JPdXRwdXQsXHJcbiAgICB0YXJnZXRXb3JkQ291bnQ6IG51bWJlciA9IDI1MDBcclxuICApOiBDaGFwdGVyT3V0bGluZSB7XHJcbiAgICBjb25zdCBzY2VuZXM6IFNjZW5lW10gPSBbXTtcclxuICAgIGNvbnN0IHNjZW5lQ291bnQgPSBNYXRoLm1heCgzLCBNYXRoLm1pbig2LCBNYXRoLmZsb29yKHRhcmdldFdvcmRDb3VudCAvIDUwMCkpKTtcclxuICAgIGNvbnN0IHdvcmRzUGVyU2NlbmUgPSBNYXRoLmZsb29yKHRhcmdldFdvcmRDb3VudCAvIHNjZW5lQ291bnQpO1xyXG4gICAgXHJcbiAgICAvLyBCdWlsZCBzY2VuZXMgYmFzZWQgb24gb2JqZWN0aXZlc1xyXG4gICAgY29uc3QgY3JpdGljYWxPYmplY3RpdmVzID0gZGlyZWN0b3JPdXRwdXQub2JqZWN0aXZlcy5maWx0ZXIobyA9PiBvLnByaW9yaXR5ID09PSAnY3JpdGljYWwnKTtcclxuICAgIGNvbnN0IGhpZ2hPYmplY3RpdmVzID0gZGlyZWN0b3JPdXRwdXQub2JqZWN0aXZlcy5maWx0ZXIobyA9PiBvLnByaW9yaXR5ID09PSAnaGlnaCcpO1xyXG4gICAgXHJcbiAgICAvLyBTY2VuZSAxOiBTZXR1cFxyXG4gICAgc2NlbmVzLnB1c2goe1xyXG4gICAgICBpZDogJ3NjZW5lLTEnLFxyXG4gICAgICBzZXF1ZW5jZTogMSxcclxuICAgICAgZ29hbDogJ0VzdGFibGlzaCBjdXJyZW50IHNpdHVhdGlvbiBhbmQgY2hhcmFjdGVyIHN0YXRlcycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnT3BlbmluZyBzY2VuZSB0aGF0IHNldHMgdXAgdGhlIGNoYXB0ZXIgY29udGV4dCcsXHJcbiAgICAgIHRlbnNpb246IDAuMixcclxuICAgICAgY2hhcmFjdGVyczogZGlyZWN0b3JPdXRwdXQuZm9jdXNDaGFyYWN0ZXJzLnNsaWNlKDAsIDIpLFxyXG4gICAgICBzZXR0aW5nOiAnQ3VycmVudCBsb2NhdGlvbicsXHJcbiAgICAgIGVzdGltYXRlZFdvcmRzOiB3b3Jkc1BlclNjZW5lLFxyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIC8vIE1pZGRsZSBzY2VuZXM6IEJ1aWxkIHRlbnNpb24gYW5kIGFkZHJlc3Mgb2JqZWN0aXZlc1xyXG4gICAgZm9yIChsZXQgaSA9IDI7IGkgPCBzY2VuZUNvdW50OyBpKyspIHtcclxuICAgICAgY29uc3QgdGVuc2lvbiA9IDAuMyArIChpIC8gc2NlbmVDb3VudCkgKiAwLjU7IC8vIEJ1aWxkIGZyb20gMzAlIHRvIDgwJVxyXG4gICAgICBjb25zdCBvYmplY3RpdmUgPSBjcml0aWNhbE9iamVjdGl2ZXNbaSAtIDJdIHx8IGhpZ2hPYmplY3RpdmVzW2kgLSAyXTtcclxuICAgICAgXHJcbiAgICAgIHNjZW5lcy5wdXNoKHtcclxuICAgICAgICBpZDogYHNjZW5lLSR7aX1gLFxyXG4gICAgICAgIHNlcXVlbmNlOiBpLFxyXG4gICAgICAgIGdvYWw6IG9iamVjdGl2ZSA/IGBBZGRyZXNzOiAke29iamVjdGl2ZS5kZXNjcmlwdGlvbi5zdWJzdHJpbmcoMCwgNTApfS4uLmAgOiAnRGV2ZWxvcCBwbG90IGFuZCBjaGFyYWN0ZXInLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiBvYmplY3RpdmUgXHJcbiAgICAgICAgICA/IGBTY2VuZSBmb2N1c2luZyBvbiAke29iamVjdGl2ZS50eXBlfSBvYmplY3RpdmUgcmVsYXRlZCB0byAke29iamVjdGl2ZS5yZWxhdGVkQ2hhcmFjdGVyIHx8ICdwbG90J31gXHJcbiAgICAgICAgICA6ICdEZXZlbG9wbWVudCBzY2VuZSBhZHZhbmNpbmcgdGhlIHN0b3J5JyxcclxuICAgICAgICB0ZW5zaW9uOiBNYXRoLnJvdW5kKHRlbnNpb24gKiAxMDApIC8gMTAwLFxyXG4gICAgICAgIGNoYXJhY3RlcnM6IGRpcmVjdG9yT3V0cHV0LmZvY3VzQ2hhcmFjdGVycyxcclxuICAgICAgICBzZXR0aW5nOiAnU3RvcnkgbG9jYXRpb24nLFxyXG4gICAgICAgIGVzdGltYXRlZFdvcmRzOiB3b3Jkc1BlclNjZW5lLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLy8gRmluYWwgc2NlbmU6IENsaW1heC9SZXNvbHV0aW9uXHJcbiAgICBzY2VuZXMucHVzaCh7XHJcbiAgICAgIGlkOiBgc2NlbmUtJHtzY2VuZUNvdW50fWAsXHJcbiAgICAgIHNlcXVlbmNlOiBzY2VuZUNvdW50LFxyXG4gICAgICBnb2FsOiBjcml0aWNhbE9iamVjdGl2ZXNbMF0/LmRlc2NyaXB0aW9uIHx8ICdDaGFwdGVyIGNsaW1heCBvciByZXNvbHV0aW9uJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDbGltYWN0aWMgc2NlbmUgdGhhdCByZXNvbHZlcyBvciBlc2NhbGF0ZXMgdGhlIGNoYXB0ZXIgdGVuc2lvbicsXHJcbiAgICAgIHRlbnNpb246IDAuOSxcclxuICAgICAgY2hhcmFjdGVyczogZGlyZWN0b3JPdXRwdXQuZm9jdXNDaGFyYWN0ZXJzLFxyXG4gICAgICBzZXR0aW5nOiAnS2V5IGxvY2F0aW9uJyxcclxuICAgICAgZXN0aW1hdGVkV29yZHM6IHdvcmRzUGVyU2NlbmUsXHJcbiAgICB9KTtcclxuICAgIFxyXG4gICAgLy8gR2VuZXJhdGUgdHJhbnNpdGlvbnNcclxuICAgIGNvbnN0IHRyYW5zaXRpb25zOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzY2VuZXMubGVuZ3RoIC0gMTsgaSsrKSB7XHJcbiAgICAgIHRyYW5zaXRpb25zLnB1c2goYE5hdHVyYWwgcHJvZ3Jlc3Npb24gZnJvbSAke3NjZW5lc1tpXS5nb2FsfSB0byAke3NjZW5lc1tpICsgMV0uZ29hbH1gKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgY2hhcHRlck51bWJlcjogZGlyZWN0b3JPdXRwdXQuY2hhcHRlck51bWJlcixcclxuICAgICAgb3ZlcmFsbEdvYWw6IGRpcmVjdG9yT3V0cHV0Lm92ZXJhbGxHb2FsLFxyXG4gICAgICB0b25lOiBkaXJlY3Rvck91dHB1dC50b25lLFxyXG4gICAgICB0b3RhbEVzdGltYXRlZFdvcmRzOiBzY2VuZXMucmVkdWNlKChzdW0sIHMpID0+IHN1bSArIHMuZXN0aW1hdGVkV29yZHMsIDApLFxyXG4gICAgICBzY2VuZXMsXHJcbiAgICAgIHRyYW5zaXRpb25zLFxyXG4gICAgICBub3RlczogJ0F1dG8tZ2VuZXJhdGVkIG91dGxpbmUgYmFzZWQgb24gZGlyZWN0b3Igb2JqZWN0aXZlcy4gQWRqdXN0IGFzIG5lZWRlZCBmb3IgbmFycmF0aXZlIGZsb3cuJyxcclxuICAgIH07XHJcbiAgfVxyXG4gIFxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlIHRoYXQgb3V0bGluZSBtZWV0cyBvYmplY3RpdmVzXHJcbiAgICovXHJcbiAgdmFsaWRhdGVPdXRsaW5lKG91dGxpbmU6IENoYXB0ZXJPdXRsaW5lLCBvYmplY3RpdmVzOiBDaGFwdGVyT2JqZWN0aXZlW10pOiB7XHJcbiAgICB2YWxpZDogYm9vbGVhbjtcclxuICAgIGNvdmVyYWdlOiBudW1iZXI7XHJcbiAgICBtaXNzZWRPYmplY3RpdmVzOiBzdHJpbmdbXTtcclxuICB9IHtcclxuICAgIGNvbnN0IGNvdmVyZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcclxuICAgIGNvbnN0IG1pc3NlZDogc3RyaW5nW10gPSBbXTtcclxuICAgIFxyXG4gICAgLy8gQ2hlY2sgZWFjaCBvYmplY3RpdmUgYWdhaW5zdCBzY2VuZXNcclxuICAgIGZvciAoY29uc3Qgb2JqIG9mIG9iamVjdGl2ZXMpIHtcclxuICAgICAgY29uc3QgaXNDb3ZlcmVkID0gb3V0bGluZS5zY2VuZXMuc29tZShzY2VuZSA9PiBcclxuICAgICAgICBzY2VuZS5nb2FsLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMob2JqLnR5cGUpIHx8XHJcbiAgICAgICAgc2NlbmUuZGVzY3JpcHRpb24udG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhvYmouZGVzY3JpcHRpb24udG9Mb3dlckNhc2UoKS5zdWJzdHJpbmcoMCwgMjApKVxyXG4gICAgICApO1xyXG4gICAgICBcclxuICAgICAgaWYgKGlzQ292ZXJlZCkge1xyXG4gICAgICAgIGNvdmVyZWQuYWRkKG9iai5pZCk7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqLnByaW9yaXR5ID09PSAnY3JpdGljYWwnIHx8IG9iai5wcmlvcml0eSA9PT0gJ2hpZ2gnKSB7XHJcbiAgICAgICAgbWlzc2VkLnB1c2gob2JqLmRlc2NyaXB0aW9uKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgXHJcbiAgICBjb25zdCBjb3ZlcmFnZSA9IG9iamVjdGl2ZXMubGVuZ3RoID4gMCA/IGNvdmVyZWQuc2l6ZSAvIG9iamVjdGl2ZXMubGVuZ3RoIDogMTtcclxuICAgIFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdmFsaWQ6IG1pc3NlZC5sZW5ndGggPT09IDAsXHJcbiAgICAgIGNvdmVyYWdlLFxyXG4gICAgICBtaXNzZWRPYmplY3RpdmVzOiBtaXNzZWQsXHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IGNoYXB0ZXJQbGFubmVyID0gbmV3IENoYXB0ZXJQbGFubmVyKCk7XHJcbiJdfQ==
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CompletenessResult } from '../types/index.js';
|
|
2
|
+
export declare class CompletenessChecker {
|
|
3
|
+
private promptTemplate;
|
|
4
|
+
constructor();
|
|
5
|
+
check(chapterText: string): Promise<CompletenessResult>;
|
|
6
|
+
}
|
|
7
|
+
export declare const completenessChecker: CompletenessChecker;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.completenessChecker = exports.CompletenessChecker = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const COMPLETENESS_PROMPT = `Determine whether the following chapter text ends at a natural stopping point.
|
|
6
|
+
|
|
7
|
+
A chapter is COMPLETE if:
|
|
8
|
+
- It ends at the end of a scene or chapter break
|
|
9
|
+
- It does not cut off mid-sentence or mid-paragraph
|
|
10
|
+
- It has narrative closure for this segment
|
|
11
|
+
|
|
12
|
+
A chapter is INCOMPLETE if:
|
|
13
|
+
- It cuts off mid-sentence
|
|
14
|
+
- It ends abruptly mid-scene
|
|
15
|
+
- The narrative clearly continues
|
|
16
|
+
|
|
17
|
+
## Chapter Text
|
|
18
|
+
|
|
19
|
+
{{chapterText}}
|
|
20
|
+
|
|
21
|
+
## Response
|
|
22
|
+
|
|
23
|
+
Return only one word:
|
|
24
|
+
|
|
25
|
+
COMPLETE
|
|
26
|
+
|
|
27
|
+
or
|
|
28
|
+
|
|
29
|
+
INCOMPLETE`;
|
|
30
|
+
class CompletenessChecker {
|
|
31
|
+
promptTemplate;
|
|
32
|
+
constructor() {
|
|
33
|
+
this.promptTemplate = COMPLETENESS_PROMPT;
|
|
34
|
+
}
|
|
35
|
+
async check(chapterText) {
|
|
36
|
+
const prompt = this.promptTemplate.replace('{{chapterText}}', chapterText);
|
|
37
|
+
const response = await (0, client_js_1.getLLM)().complete(prompt, {
|
|
38
|
+
temperature: 0.1,
|
|
39
|
+
maxTokens: 10,
|
|
40
|
+
});
|
|
41
|
+
const normalized = response.trim().toUpperCase();
|
|
42
|
+
const isComplete = normalized.includes('COMPLETE') && !normalized.includes('INCOMPLETE');
|
|
43
|
+
return {
|
|
44
|
+
isComplete,
|
|
45
|
+
reason: isComplete ? undefined : 'Chapter appears to be cut off mid-content',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.CompletenessChecker = CompletenessChecker;
|
|
50
|
+
exports.completenessChecker = new CompletenessChecker();
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGVuZXNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50cy9jb21wbGV0ZW5lc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0RBQTBDO0FBRzFDLE1BQU0sbUJBQW1CLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztXQXdCakIsQ0FBQztBQUVaLE1BQWEsbUJBQW1CO0lBQ3RCLGNBQWMsQ0FBUztJQUUvQjtRQUNFLElBQUksQ0FBQyxjQUFjLEdBQUcsbUJBQW1CLENBQUM7SUFDNUMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBbUI7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFM0UsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFBLGtCQUFNLEdBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFO1lBQy9DLFdBQVcsRUFBRSxHQUFHO1lBQ2hCLFNBQVMsRUFBRSxFQUFFO1NBQ2QsQ0FBQyxDQUFDO1FBRUgsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pELE1BQU0sVUFBVSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRXpGLE9BQU87WUFDTCxVQUFVO1lBQ1YsTUFBTSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQywyQ0FBMkM7U0FDN0UsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQXZCRCxrREF1QkM7QUFFWSxRQUFBLG1CQUFtQixHQUFHLElBQUksbUJBQW1CLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGdldExMTSB9IGZyb20gJy4uL2xsbS9jbGllbnQuanMnO1xyXG5pbXBvcnQgdHlwZSB7IENvbXBsZXRlbmVzc1Jlc3VsdCB9IGZyb20gJy4uL3R5cGVzL2luZGV4LmpzJztcclxuXHJcbmNvbnN0IENPTVBMRVRFTkVTU19QUk9NUFQgPSBgRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGZvbGxvd2luZyBjaGFwdGVyIHRleHQgZW5kcyBhdCBhIG5hdHVyYWwgc3RvcHBpbmcgcG9pbnQuXHJcblxyXG5BIGNoYXB0ZXIgaXMgQ09NUExFVEUgaWY6XHJcbi0gSXQgZW5kcyBhdCB0aGUgZW5kIG9mIGEgc2NlbmUgb3IgY2hhcHRlciBicmVha1xyXG4tIEl0IGRvZXMgbm90IGN1dCBvZmYgbWlkLXNlbnRlbmNlIG9yIG1pZC1wYXJhZ3JhcGhcclxuLSBJdCBoYXMgbmFycmF0aXZlIGNsb3N1cmUgZm9yIHRoaXMgc2VnbWVudFxyXG5cclxuQSBjaGFwdGVyIGlzIElOQ09NUExFVEUgaWY6XHJcbi0gSXQgY3V0cyBvZmYgbWlkLXNlbnRlbmNlXHJcbi0gSXQgZW5kcyBhYnJ1cHRseSBtaWQtc2NlbmVcclxuLSBUaGUgbmFycmF0aXZlIGNsZWFybHkgY29udGludWVzXHJcblxyXG4jIyBDaGFwdGVyIFRleHRcclxuXHJcbnt7Y2hhcHRlclRleHR9fVxyXG5cclxuIyMgUmVzcG9uc2VcclxuXHJcblJldHVybiBvbmx5IG9uZSB3b3JkOlxyXG5cclxuQ09NUExFVEVcclxuXHJcbm9yXHJcblxyXG5JTkNPTVBMRVRFYDtcclxuXHJcbmV4cG9ydCBjbGFzcyBDb21wbGV0ZW5lc3NDaGVja2VyIHtcclxuICBwcml2YXRlIHByb21wdFRlbXBsYXRlOiBzdHJpbmc7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5wcm9tcHRUZW1wbGF0ZSA9IENPTVBMRVRFTkVTU19QUk9NUFQ7XHJcbiAgfVxyXG5cclxuICBhc3luYyBjaGVjayhjaGFwdGVyVGV4dDogc3RyaW5nKTogUHJvbWlzZTxDb21wbGV0ZW5lc3NSZXN1bHQ+IHtcclxuICAgIGNvbnN0IHByb21wdCA9IHRoaXMucHJvbXB0VGVtcGxhdGUucmVwbGFjZSgne3tjaGFwdGVyVGV4dH19JywgY2hhcHRlclRleHQpO1xyXG5cclxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZ2V0TExNKCkuY29tcGxldGUocHJvbXB0LCB7XHJcbiAgICAgIHRlbXBlcmF0dXJlOiAwLjEsXHJcbiAgICAgIG1heFRva2VuczogMTAsXHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBub3JtYWxpemVkID0gcmVzcG9uc2UudHJpbSgpLnRvVXBwZXJDYXNlKCk7XHJcbiAgICBjb25zdCBpc0NvbXBsZXRlID0gbm9ybWFsaXplZC5pbmNsdWRlcygnQ09NUExFVEUnKSAmJiAhbm9ybWFsaXplZC5pbmNsdWRlcygnSU5DT01QTEVURScpO1xyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlzQ29tcGxldGUsXHJcbiAgICAgIHJlYXNvbjogaXNDb21wbGV0ZSA/IHVuZGVmaW5lZCA6ICdDaGFwdGVyIGFwcGVhcnMgdG8gYmUgY3V0IG9mZiBtaWQtY29udGVudCcsXHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IGNvbXBsZXRlbmVzc0NoZWNrZXIgPSBuZXcgQ29tcGxldGVuZXNzQ2hlY2tlcigpO1xyXG4iXX0=
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Chapter, StoryBible } from '../types/index.js';
|
|
2
|
+
import type { NarrativeMemory } from '../memory/vectorStore.js';
|
|
3
|
+
interface ExtractedMemory {
|
|
4
|
+
content: string;
|
|
5
|
+
category: NarrativeMemory['category'];
|
|
6
|
+
}
|
|
7
|
+
export declare class MemoryExtractor {
|
|
8
|
+
extract(chapter: Chapter, bible: StoryBible): Promise<ExtractedMemory[]>;
|
|
9
|
+
extractFromSummary(chapterNumber: number, summary: string, bible: StoryBible): Promise<ExtractedMemory[]>;
|
|
10
|
+
}
|
|
11
|
+
export declare const memoryExtractor: MemoryExtractor;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memoryExtractor = exports.MemoryExtractor = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const EXTRACTION_PROMPT = `You are a narrative memory extractor. Your job is to analyze a chapter and extract important facts that should be remembered for future chapters.
|
|
6
|
+
|
|
7
|
+
## Story Bible
|
|
8
|
+
|
|
9
|
+
**Title:** {{title}}
|
|
10
|
+
**Genre:** {{genre}}
|
|
11
|
+
**Setting:** {{setting}}
|
|
12
|
+
|
|
13
|
+
## Chapter to Analyze
|
|
14
|
+
|
|
15
|
+
**Chapter {{chapterNumber}}: {{chapterTitle}}**
|
|
16
|
+
|
|
17
|
+
{{chapterContent}}
|
|
18
|
+
|
|
19
|
+
## Extraction Task
|
|
20
|
+
|
|
21
|
+
Extract 5-10 important narrative memories from this chapter. Focus on:
|
|
22
|
+
|
|
23
|
+
1. **Events** - Significant things that happened (plot points, discoveries, battles, meetings)
|
|
24
|
+
2. **Character** - Character development, new traits revealed, relationships changed
|
|
25
|
+
3. **World** - New world details revealed (locations, cultures, magic systems, technology)
|
|
26
|
+
4. **Plot** - Plot thread developments, mysteries introduced, foreshadowing
|
|
27
|
+
|
|
28
|
+
For each memory:
|
|
29
|
+
- Write a clear, standalone sentence that captures the fact
|
|
30
|
+
- Categorize it appropriately
|
|
31
|
+
- Be specific enough that it would be useful for maintaining continuity
|
|
32
|
+
|
|
33
|
+
Respond with JSON only:
|
|
34
|
+
{
|
|
35
|
+
"memories": [
|
|
36
|
+
{"content": "Alice discovered the ancient map hidden in her grandmother's attic", "category": "event"},
|
|
37
|
+
{"content": "Bob is secretly afraid of water due to a childhood drowning incident", "category": "character"},
|
|
38
|
+
{"content": "The city of Eldoria has a strict curfew enforced by mechanical guards", "category": "world"},
|
|
39
|
+
{"content": "The prophecy mentions three keys that must be found before the eclipse", "category": "plot"}
|
|
40
|
+
]
|
|
41
|
+
}`;
|
|
42
|
+
class MemoryExtractor {
|
|
43
|
+
async extract(chapter, bible) {
|
|
44
|
+
const prompt = EXTRACTION_PROMPT
|
|
45
|
+
.replace('{{title}}', bible.title)
|
|
46
|
+
.replace('{{genre}}', bible.genre)
|
|
47
|
+
.replace('{{setting}}', bible.setting)
|
|
48
|
+
.replace('{{chapterNumber}}', chapter.number.toString())
|
|
49
|
+
.replace('{{chapterTitle}}', chapter.title)
|
|
50
|
+
.replace('{{chapterContent}}', chapter.content.substring(0, 8000)); // Limit content length
|
|
51
|
+
const result = await (0, client_js_1.getLLM)().completeJSON(prompt, {
|
|
52
|
+
temperature: 0.3,
|
|
53
|
+
maxTokens: 2000,
|
|
54
|
+
});
|
|
55
|
+
return result.memories || [];
|
|
56
|
+
}
|
|
57
|
+
async extractFromSummary(chapterNumber, summary, bible) {
|
|
58
|
+
const prompt = `You are a narrative memory extractor. Extract important facts from this chapter summary.
|
|
59
|
+
|
|
60
|
+
## Story
|
|
61
|
+
**Title:** ${bible.title}
|
|
62
|
+
**Genre:** ${bible.genre}
|
|
63
|
+
|
|
64
|
+
## Chapter ${chapterNumber} Summary
|
|
65
|
+
${summary}
|
|
66
|
+
|
|
67
|
+
Extract 3-5 key memories (events, character moments, world details, plot developments). Respond with JSON:
|
|
68
|
+
{
|
|
69
|
+
"memories": [
|
|
70
|
+
{"content": "description of what happened", "category": "event|character|world|plot"}
|
|
71
|
+
]
|
|
72
|
+
}`;
|
|
73
|
+
const result = await (0, client_js_1.getLLM)().completeJSON(prompt, {
|
|
74
|
+
temperature: 0.3,
|
|
75
|
+
maxTokens: 1000,
|
|
76
|
+
});
|
|
77
|
+
return result.memories || [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.MemoryExtractor = MemoryExtractor;
|
|
81
|
+
exports.memoryExtractor = new MemoryExtractor();
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5RXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50cy9tZW1vcnlFeHRyYWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0RBQTBDO0FBYTFDLE1BQU0saUJBQWlCLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQW9DeEIsQ0FBQztBQUVILE1BQWEsZUFBZTtJQUMxQixLQUFLLENBQUMsT0FBTyxDQUFDLE9BQWdCLEVBQUUsS0FBaUI7UUFDL0MsTUFBTSxNQUFNLEdBQUcsaUJBQWlCO2FBQzdCLE9BQU8sQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQzthQUNqQyxPQUFPLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUM7YUFDakMsT0FBTyxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDO2FBQ3JDLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO2FBQ3ZELE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDO2FBQzFDLE9BQU8sQ0FBQyxvQkFBb0IsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLHVCQUF1QjtRQUU3RixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEsa0JBQU0sR0FBRSxDQUFDLFlBQVksQ0FBbUIsTUFBTSxFQUFFO1lBQ25FLFdBQVcsRUFBRSxHQUFHO1lBQ2hCLFNBQVMsRUFBRSxJQUFJO1NBQ2hCLENBQUMsQ0FBQztRQUVILE9BQU8sTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxhQUFxQixFQUFFLE9BQWUsRUFBRSxLQUFpQjtRQUNoRixNQUFNLE1BQU0sR0FBRzs7O2FBR04sS0FBSyxDQUFDLEtBQUs7YUFDWCxLQUFLLENBQUMsS0FBSzs7YUFFWCxhQUFhO0VBQ3hCLE9BQU87Ozs7Ozs7RUFPUCxDQUFDO1FBRUMsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFBLGtCQUFNLEdBQUUsQ0FBQyxZQUFZLENBQW1CLE1BQU0sRUFBRTtZQUNuRSxXQUFXLEVBQUUsR0FBRztZQUNoQixTQUFTLEVBQUUsSUFBSTtTQUNoQixDQUFDLENBQUM7UUFFSCxPQUFPLE1BQU0sQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDO0lBQy9CLENBQUM7Q0FDRjtBQTFDRCwwQ0EwQ0M7QUFFWSxRQUFBLGVBQWUsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2V0TExNIH0gZnJvbSAnLi4vbGxtL2NsaWVudC5qcyc7XHJcbmltcG9ydCB0eXBlIHsgQ2hhcHRlciwgU3RvcnlCaWJsZSB9IGZyb20gJy4uL3R5cGVzL2luZGV4LmpzJztcclxuaW1wb3J0IHR5cGUgeyBOYXJyYXRpdmVNZW1vcnkgfSBmcm9tICcuLi9tZW1vcnkvdmVjdG9yU3RvcmUuanMnO1xyXG5cclxuaW50ZXJmYWNlIEV4dHJhY3RlZE1lbW9yeSB7XHJcbiAgY29udGVudDogc3RyaW5nO1xyXG4gIGNhdGVnb3J5OiBOYXJyYXRpdmVNZW1vcnlbJ2NhdGVnb3J5J107XHJcbn1cclxuXHJcbmludGVyZmFjZSBFeHRyYWN0aW9uT3V0cHV0IHtcclxuICBtZW1vcmllczogRXh0cmFjdGVkTWVtb3J5W107XHJcbn1cclxuXHJcbmNvbnN0IEVYVFJBQ1RJT05fUFJPTVBUID0gYFlvdSBhcmUgYSBuYXJyYXRpdmUgbWVtb3J5IGV4dHJhY3Rvci4gWW91ciBqb2IgaXMgdG8gYW5hbHl6ZSBhIGNoYXB0ZXIgYW5kIGV4dHJhY3QgaW1wb3J0YW50IGZhY3RzIHRoYXQgc2hvdWxkIGJlIHJlbWVtYmVyZWQgZm9yIGZ1dHVyZSBjaGFwdGVycy5cclxuXHJcbiMjIFN0b3J5IEJpYmxlXHJcblxyXG4qKlRpdGxlOioqIHt7dGl0bGV9fVxyXG4qKkdlbnJlOioqIHt7Z2VucmV9fVxyXG4qKlNldHRpbmc6Kioge3tzZXR0aW5nfX1cclxuXHJcbiMjIENoYXB0ZXIgdG8gQW5hbHl6ZVxyXG5cclxuKipDaGFwdGVyIHt7Y2hhcHRlck51bWJlcn19OiB7e2NoYXB0ZXJUaXRsZX19KipcclxuXHJcbnt7Y2hhcHRlckNvbnRlbnR9fVxyXG5cclxuIyMgRXh0cmFjdGlvbiBUYXNrXHJcblxyXG5FeHRyYWN0IDUtMTAgaW1wb3J0YW50IG5hcnJhdGl2ZSBtZW1vcmllcyBmcm9tIHRoaXMgY2hhcHRlci4gRm9jdXMgb246XHJcblxyXG4xLiAqKkV2ZW50cyoqIC0gU2lnbmlmaWNhbnQgdGhpbmdzIHRoYXQgaGFwcGVuZWQgKHBsb3QgcG9pbnRzLCBkaXNjb3ZlcmllcywgYmF0dGxlcywgbWVldGluZ3MpXHJcbjIuICoqQ2hhcmFjdGVyKiogLSBDaGFyYWN0ZXIgZGV2ZWxvcG1lbnQsIG5ldyB0cmFpdHMgcmV2ZWFsZWQsIHJlbGF0aW9uc2hpcHMgY2hhbmdlZFxyXG4zLiAqKldvcmxkKiogLSBOZXcgd29ybGQgZGV0YWlscyByZXZlYWxlZCAobG9jYXRpb25zLCBjdWx0dXJlcywgbWFnaWMgc3lzdGVtcywgdGVjaG5vbG9neSlcclxuNC4gKipQbG90KiogLSBQbG90IHRocmVhZCBkZXZlbG9wbWVudHMsIG15c3RlcmllcyBpbnRyb2R1Y2VkLCBmb3Jlc2hhZG93aW5nXHJcblxyXG5Gb3IgZWFjaCBtZW1vcnk6XHJcbi0gV3JpdGUgYSBjbGVhciwgc3RhbmRhbG9uZSBzZW50ZW5jZSB0aGF0IGNhcHR1cmVzIHRoZSBmYWN0XHJcbi0gQ2F0ZWdvcml6ZSBpdCBhcHByb3ByaWF0ZWx5XHJcbi0gQmUgc3BlY2lmaWMgZW5vdWdoIHRoYXQgaXQgd291bGQgYmUgdXNlZnVsIGZvciBtYWludGFpbmluZyBjb250aW51aXR5XHJcblxyXG5SZXNwb25kIHdpdGggSlNPTiBvbmx5OlxyXG57XHJcbiAgXCJtZW1vcmllc1wiOiBbXHJcbiAgICB7XCJjb250ZW50XCI6IFwiQWxpY2UgZGlzY292ZXJlZCB0aGUgYW5jaWVudCBtYXAgaGlkZGVuIGluIGhlciBncmFuZG1vdGhlcidzIGF0dGljXCIsIFwiY2F0ZWdvcnlcIjogXCJldmVudFwifSxcclxuICAgIHtcImNvbnRlbnRcIjogXCJCb2IgaXMgc2VjcmV0bHkgYWZyYWlkIG9mIHdhdGVyIGR1ZSB0byBhIGNoaWxkaG9vZCBkcm93bmluZyBpbmNpZGVudFwiLCBcImNhdGVnb3J5XCI6IFwiY2hhcmFjdGVyXCJ9LFxyXG4gICAge1wiY29udGVudFwiOiBcIlRoZSBjaXR5IG9mIEVsZG9yaWEgaGFzIGEgc3RyaWN0IGN1cmZldyBlbmZvcmNlZCBieSBtZWNoYW5pY2FsIGd1YXJkc1wiLCBcImNhdGVnb3J5XCI6IFwid29ybGRcIn0sXHJcbiAgICB7XCJjb250ZW50XCI6IFwiVGhlIHByb3BoZWN5IG1lbnRpb25zIHRocmVlIGtleXMgdGhhdCBtdXN0IGJlIGZvdW5kIGJlZm9yZSB0aGUgZWNsaXBzZVwiLCBcImNhdGVnb3J5XCI6IFwicGxvdFwifVxyXG4gIF1cclxufWA7XHJcblxyXG5leHBvcnQgY2xhc3MgTWVtb3J5RXh0cmFjdG9yIHtcclxuICBhc3luYyBleHRyYWN0KGNoYXB0ZXI6IENoYXB0ZXIsIGJpYmxlOiBTdG9yeUJpYmxlKTogUHJvbWlzZTxFeHRyYWN0ZWRNZW1vcnlbXT4ge1xyXG4gICAgY29uc3QgcHJvbXB0ID0gRVhUUkFDVElPTl9QUk9NUFRcclxuICAgICAgLnJlcGxhY2UoJ3t7dGl0bGV9fScsIGJpYmxlLnRpdGxlKVxyXG4gICAgICAucmVwbGFjZSgne3tnZW5yZX19JywgYmlibGUuZ2VucmUpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3NldHRpbmd9fScsIGJpYmxlLnNldHRpbmcpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2NoYXB0ZXJOdW1iZXJ9fScsIGNoYXB0ZXIubnVtYmVyLnRvU3RyaW5nKCkpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2NoYXB0ZXJUaXRsZX19JywgY2hhcHRlci50aXRsZSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Y2hhcHRlckNvbnRlbnR9fScsIGNoYXB0ZXIuY29udGVudC5zdWJzdHJpbmcoMCwgODAwMCkpOyAvLyBMaW1pdCBjb250ZW50IGxlbmd0aFxyXG5cclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdldExMTSgpLmNvbXBsZXRlSlNPTjxFeHRyYWN0aW9uT3V0cHV0Pihwcm9tcHQsIHtcclxuICAgICAgdGVtcGVyYXR1cmU6IDAuMyxcclxuICAgICAgbWF4VG9rZW5zOiAyMDAwLFxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdC5tZW1vcmllcyB8fCBbXTtcclxuICB9XHJcblxyXG4gIGFzeW5jIGV4dHJhY3RGcm9tU3VtbWFyeShjaGFwdGVyTnVtYmVyOiBudW1iZXIsIHN1bW1hcnk6IHN0cmluZywgYmlibGU6IFN0b3J5QmlibGUpOiBQcm9taXNlPEV4dHJhY3RlZE1lbW9yeVtdPiB7XHJcbiAgICBjb25zdCBwcm9tcHQgPSBgWW91IGFyZSBhIG5hcnJhdGl2ZSBtZW1vcnkgZXh0cmFjdG9yLiBFeHRyYWN0IGltcG9ydGFudCBmYWN0cyBmcm9tIHRoaXMgY2hhcHRlciBzdW1tYXJ5LlxyXG5cclxuIyMgU3RvcnlcclxuKipUaXRsZToqKiAke2JpYmxlLnRpdGxlfVxyXG4qKkdlbnJlOioqICR7YmlibGUuZ2VucmV9XHJcblxyXG4jIyBDaGFwdGVyICR7Y2hhcHRlck51bWJlcn0gU3VtbWFyeVxyXG4ke3N1bW1hcnl9XHJcblxyXG5FeHRyYWN0IDMtNSBrZXkgbWVtb3JpZXMgKGV2ZW50cywgY2hhcmFjdGVyIG1vbWVudHMsIHdvcmxkIGRldGFpbHMsIHBsb3QgZGV2ZWxvcG1lbnRzKS4gUmVzcG9uZCB3aXRoIEpTT046XHJcbntcclxuICBcIm1lbW9yaWVzXCI6IFtcclxuICAgIHtcImNvbnRlbnRcIjogXCJkZXNjcmlwdGlvbiBvZiB3aGF0IGhhcHBlbmVkXCIsIFwiY2F0ZWdvcnlcIjogXCJldmVudHxjaGFyYWN0ZXJ8d29ybGR8cGxvdFwifVxyXG4gIF1cclxufWA7XHJcblxyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2V0TExNKCkuY29tcGxldGVKU09OPEV4dHJhY3Rpb25PdXRwdXQ+KHByb21wdCwge1xyXG4gICAgICB0ZW1wZXJhdHVyZTogMC4zLFxyXG4gICAgICBtYXhUb2tlbnM6IDEwMDAsXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gcmVzdWx0Lm1lbW9yaWVzIHx8IFtdO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IG1lbW9yeUV4dHJhY3RvciA9IG5ldyBNZW1vcnlFeHRyYWN0b3IoKTtcclxuIl19
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Chapter, StoryBible } from '../types/index.js';
|
|
2
|
+
import type { StoryStructuredState } from '../story/structuredState.js';
|
|
3
|
+
interface StateUpdateOutput {
|
|
4
|
+
characterUpdates: Array<{
|
|
5
|
+
name: string;
|
|
6
|
+
emotionalState?: string;
|
|
7
|
+
location?: string;
|
|
8
|
+
newKnowledge?: string[];
|
|
9
|
+
relationshipChanges?: Array<{
|
|
10
|
+
with: string;
|
|
11
|
+
status: string;
|
|
12
|
+
}>;
|
|
13
|
+
development?: string;
|
|
14
|
+
}>;
|
|
15
|
+
plotThreadUpdates: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
status?: 'dormant' | 'active' | 'escalating' | 'resolved';
|
|
18
|
+
tensionChange?: number;
|
|
19
|
+
summary?: string;
|
|
20
|
+
}>;
|
|
21
|
+
newQuestions: string[];
|
|
22
|
+
resolvedQuestions: string[];
|
|
23
|
+
recentEvents: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare class StateUpdater {
|
|
26
|
+
extractStateChanges(chapter: Chapter, bible: StoryBible, currentState: StoryStructuredState): Promise<StateUpdateOutput>;
|
|
27
|
+
applyUpdates(state: StoryStructuredState, updates: StateUpdateOutput, chapterNumber: number): StoryStructuredState;
|
|
28
|
+
}
|
|
29
|
+
export declare const stateUpdater: StateUpdater;
|
|
30
|
+
export {};
|