@narrative-os/cli 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/commands/bible.d.ts +1 -0
- package/dist/commands/bible.js +49 -0
- package/dist/commands/clone.d.ts +1 -0
- package/dist/commands/clone.js +37 -0
- package/dist/commands/config.d.ts +9 -0
- package/dist/commands/config.js +72 -0
- package/dist/commands/continue.d.ts +1 -0
- package/dist/commands/continue.js +54 -0
- package/dist/commands/delete.d.ts +1 -0
- package/dist/commands/delete.js +32 -0
- package/dist/commands/export.d.ts +1 -0
- package/dist/commands/export.js +99 -0
- package/dist/commands/generate.d.ts +1 -0
- package/dist/commands/generate.js +72 -0
- package/dist/commands/hint.d.ts +5 -0
- package/dist/commands/hint.js +68 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +27 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +21 -0
- package/dist/commands/memories.d.ts +1 -0
- package/dist/commands/memories.js +59 -0
- package/dist/commands/read.d.ts +1 -0
- package/dist/commands/read.js +42 -0
- package/dist/commands/regenerate.d.ts +1 -0
- package/dist/commands/regenerate.js +60 -0
- package/dist/commands/state.d.ts +1 -0
- package/dist/commands/state.js +76 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +51 -0
- package/dist/commands/validate.d.ts +1 -0
- package/dist/commands/validate.js +93 -0
- package/dist/config/store.d.ts +24 -0
- package/dist/config/store.js +183 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/package.json +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bibleCommand(storyId: string): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bibleCommand = bibleCommand;
|
|
4
|
+
const store_js_1 = require("../config/store.js");
|
|
5
|
+
function bibleCommand(storyId) {
|
|
6
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
7
|
+
if (!story) {
|
|
8
|
+
console.error(`Story not found: ${storyId}`);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const { bible } = story;
|
|
12
|
+
console.log(`\n# ${bible.title}`);
|
|
13
|
+
console.log('ā'.repeat(60));
|
|
14
|
+
console.log(`\n**Theme:** ${bible.theme}`);
|
|
15
|
+
console.log(`**Genre:** ${bible.genre}`);
|
|
16
|
+
console.log(`**Setting:** ${bible.setting}`);
|
|
17
|
+
console.log(`**Tone:** ${bible.tone}`);
|
|
18
|
+
console.log(`\n**Premise:**`);
|
|
19
|
+
console.log(bible.premise);
|
|
20
|
+
console.log('\n## Characters');
|
|
21
|
+
console.log('ā'.repeat(60));
|
|
22
|
+
if (bible.characters.length === 0) {
|
|
23
|
+
console.log('No characters defined.');
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
for (const char of bible.characters) {
|
|
27
|
+
console.log(`\n### ${char.name}`);
|
|
28
|
+
console.log(` Role: ${char.role}`);
|
|
29
|
+
console.log(` Personality: ${char.personality.join(', ')}`);
|
|
30
|
+
console.log(` Goals: ${char.goals.join(', ')}`);
|
|
31
|
+
if (char.background) {
|
|
32
|
+
console.log(` Background: ${char.background}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
console.log('\n## Plot Threads');
|
|
37
|
+
console.log('ā'.repeat(60));
|
|
38
|
+
if (bible.plotThreads.length === 0) {
|
|
39
|
+
console.log('No plot threads defined.');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (const thread of bible.plotThreads) {
|
|
43
|
+
console.log(`\n- ${thread.name}`);
|
|
44
|
+
console.log(` Status: ${thread.status}`);
|
|
45
|
+
console.log(` Description: ${thread.description}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function cloneCommand(storyId: string, newTitle: string): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cloneCommand = cloneCommand;
|
|
4
|
+
const engine_1 = require("@narrative-os/engine");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
function cloneCommand(storyId, newTitle) {
|
|
7
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
8
|
+
if (!story) {
|
|
9
|
+
console.error(`Story not found: ${storyId}`);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const { bible, state } = story;
|
|
13
|
+
// Create new bible with same settings but new title
|
|
14
|
+
const newBible = (0, engine_1.createStoryBible)(newTitle, bible.theme, bible.genre, bible.setting, bible.tone, bible.premise, state.totalChapters);
|
|
15
|
+
// Copy characters
|
|
16
|
+
for (const char of bible.characters) {
|
|
17
|
+
newBible.characters.push({ ...char });
|
|
18
|
+
}
|
|
19
|
+
// Copy plot threads
|
|
20
|
+
for (const thread of bible.plotThreads) {
|
|
21
|
+
newBible.plotThreads.push({ ...thread });
|
|
22
|
+
}
|
|
23
|
+
// Create fresh state
|
|
24
|
+
const newState = (0, engine_1.createStoryState)(newBible.id, state.totalChapters);
|
|
25
|
+
const canon = (0, engine_1.extractCanonFromBible)(newBible);
|
|
26
|
+
// Save the cloned story
|
|
27
|
+
(0, store_js_1.saveStory)(newBible, newState, [], canon);
|
|
28
|
+
// Initialize structured state
|
|
29
|
+
let structuredState = (0, engine_1.createStructuredState)(newBible.id);
|
|
30
|
+
structuredState = (0, engine_1.initializeCharactersFromBible)(structuredState, newBible);
|
|
31
|
+
structuredState = (0, engine_1.initializePlotThreadsFromBible)(structuredState, newBible);
|
|
32
|
+
(0, store_js_1.saveStructuredState)(newBible.id, structuredState);
|
|
33
|
+
console.log(`ā
Story cloned: ${newTitle}`);
|
|
34
|
+
console.log(`Original: ${bible.title} (${storyId})`);
|
|
35
|
+
console.log(`New ID: ${newBible.id}`);
|
|
36
|
+
console.log(`\nNext: Run "nos generate ${newBible.id}" to start writing.`);
|
|
37
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Config {
|
|
2
|
+
provider: 'openai' | 'deepseek';
|
|
3
|
+
apiKey: string;
|
|
4
|
+
model: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function configCommand(): Promise<void>;
|
|
7
|
+
export declare function getConfig(): Config | null;
|
|
8
|
+
export declare function applyConfig(): void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configCommand = configCommand;
|
|
4
|
+
exports.getConfig = getConfig;
|
|
5
|
+
exports.applyConfig = applyConfig;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const os_1 = require("os");
|
|
9
|
+
const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.narrative-os');
|
|
10
|
+
const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, 'config.json');
|
|
11
|
+
const PROVIDERS = [
|
|
12
|
+
{ name: 'OpenAI', value: 'openai', models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo'] },
|
|
13
|
+
{ name: 'DeepSeek', value: 'deepseek', models: ['deepseek-chat', 'deepseek-reasoner'] },
|
|
14
|
+
];
|
|
15
|
+
const DEEPSEEK_MODEL_MAP = {
|
|
16
|
+
'deepseek-chat': 'deepseek-chat',
|
|
17
|
+
'deepseek-reasoner': 'deepseek-reasoner',
|
|
18
|
+
};
|
|
19
|
+
function loadConfig() {
|
|
20
|
+
if (!(0, fs_1.existsSync)(CONFIG_FILE))
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse((0, fs_1.readFileSync)(CONFIG_FILE, 'utf-8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function saveConfig(config) {
|
|
30
|
+
if (!(0, fs_1.existsSync)(CONFIG_DIR))
|
|
31
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
32
|
+
(0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
33
|
+
}
|
|
34
|
+
async function configCommand() {
|
|
35
|
+
const { select, password } = await import('@inquirer/prompts');
|
|
36
|
+
const existing = loadConfig();
|
|
37
|
+
const provider = await select({
|
|
38
|
+
message: 'Select LLM provider:',
|
|
39
|
+
choices: PROVIDERS.map(p => ({ name: p.name, value: p.value })),
|
|
40
|
+
default: existing?.provider,
|
|
41
|
+
});
|
|
42
|
+
const providerInfo = PROVIDERS.find(p => p.value === provider);
|
|
43
|
+
const model = await select({
|
|
44
|
+
message: 'Select model:',
|
|
45
|
+
choices: providerInfo.models.map(m => ({ name: m, value: m })),
|
|
46
|
+
default: existing?.model || providerInfo.models[0],
|
|
47
|
+
});
|
|
48
|
+
const apiKey = await password({
|
|
49
|
+
message: `Enter ${providerInfo.name} API key:`,
|
|
50
|
+
mask: '*',
|
|
51
|
+
});
|
|
52
|
+
const config = { provider: provider, model, apiKey };
|
|
53
|
+
saveConfig(config);
|
|
54
|
+
console.log(`\nConfiguration saved for ${providerInfo.name}`);
|
|
55
|
+
console.log(`Model: ${model}`);
|
|
56
|
+
}
|
|
57
|
+
function getConfig() {
|
|
58
|
+
return loadConfig();
|
|
59
|
+
}
|
|
60
|
+
function applyConfig() {
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
if (config) {
|
|
63
|
+
process.env.LLM_PROVIDER = config.provider;
|
|
64
|
+
process.env.LLM_MODEL = config.model;
|
|
65
|
+
if (config.provider === 'openai') {
|
|
66
|
+
process.env.OPENAI_API_KEY = config.apiKey;
|
|
67
|
+
}
|
|
68
|
+
else if (config.provider === 'deepseek') {
|
|
69
|
+
process.env.DEEPSEEK_API_KEY = config.apiKey;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function continueCommand(storyId: string): Promise<void>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.continueCommand = continueCommand;
|
|
4
|
+
const engine_1 = require("@narrative-os/engine");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
async function continueCommand(storyId) {
|
|
7
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
8
|
+
if (!story) {
|
|
9
|
+
console.error(`Story not found: ${storyId}`);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
let { bible, state, chapters, canon } = story;
|
|
13
|
+
if (state.currentChapter >= state.totalChapters) {
|
|
14
|
+
console.log('Story is already complete!');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Load or initialize vector store for memory
|
|
18
|
+
const vectorStore = (0, engine_1.getVectorStore)(storyId);
|
|
19
|
+
const existingData = (0, store_js_1.loadVectorStore)(storyId);
|
|
20
|
+
if (existingData) {
|
|
21
|
+
await vectorStore.load(existingData);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
await vectorStore.initialize();
|
|
25
|
+
}
|
|
26
|
+
console.log(`Continuing story: ${bible.title}`);
|
|
27
|
+
console.log(`Generating chapters ${state.currentChapter + 1} to ${state.totalChapters}...\n`);
|
|
28
|
+
while (state.currentChapter < state.totalChapters) {
|
|
29
|
+
const nextChapterNumber = state.currentChapter + 1;
|
|
30
|
+
const context = {
|
|
31
|
+
bible,
|
|
32
|
+
state,
|
|
33
|
+
chapterNumber: nextChapterNumber,
|
|
34
|
+
targetWordCount: 1500,
|
|
35
|
+
};
|
|
36
|
+
try {
|
|
37
|
+
const result = await (0, engine_1.generateChapter)(context, { canon, vectorStore });
|
|
38
|
+
chapters = [...chapters, result.chapter];
|
|
39
|
+
state = (0, engine_1.updateStoryState)(state, result.summary);
|
|
40
|
+
(0, store_js_1.saveStory)(bible, state, chapters, canon);
|
|
41
|
+
(0, store_js_1.saveVectorStore)(storyId, vectorStore.serialize());
|
|
42
|
+
const violationWarn = result.violations.length > 0 ? ` [${result.violations.length} violations]` : '';
|
|
43
|
+
const memoryInfo = result.memoriesExtracted > 0 ? ` [${result.memoriesExtracted} memories]` : '';
|
|
44
|
+
console.log(`ā Chapter ${result.chapter.number}: ${result.chapter.title} (${result.chapter.wordCount} words)${violationWarn}${memoryInfo}`);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error(`\nFailed at Chapter ${nextChapterNumber}:`, error);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
console.log('\nStory complete!');
|
|
52
|
+
console.log(`Total: ${chapters.length} chapters`);
|
|
53
|
+
console.log(`Total words: ${chapters.reduce((sum, ch) => sum + ch.wordCount, 0)}`);
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function deleteCommand(storyId: string, force?: boolean): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteCommand = deleteCommand;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const store_js_1 = require("../config/store.js");
|
|
8
|
+
const STORIES_DIR = (0, path_1.join)((0, os_1.homedir)(), '.narrative-os', 'stories');
|
|
9
|
+
function deleteCommand(storyId, force = false) {
|
|
10
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
11
|
+
if (!story) {
|
|
12
|
+
console.error(`Story not found: ${storyId}`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
console.log(`Story: ${story.bible.title}`);
|
|
16
|
+
console.log(`ID: ${storyId}`);
|
|
17
|
+
console.log(`Chapters: ${story.state.currentChapter}/${story.state.totalChapters}`);
|
|
18
|
+
if (!force) {
|
|
19
|
+
console.log('\nā ļø This will permanently delete the story and all its chapters.');
|
|
20
|
+
console.log('Use --force to skip this confirmation.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const storyDir = (0, path_1.join)(STORIES_DIR, storyId);
|
|
24
|
+
if ((0, fs_1.existsSync)(storyDir)) {
|
|
25
|
+
(0, fs_1.rmSync)(storyDir, { recursive: true, force: true });
|
|
26
|
+
console.log(`\nā
Story "${story.bible.title}" deleted.`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.error(`Story directory not found: ${storyDir}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function exportCommand(storyId: string, format?: string, output?: string): void;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.exportCommand = exportCommand;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
function exportCommand(storyId, format = 'markdown', output) {
|
|
7
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
8
|
+
if (!story) {
|
|
9
|
+
console.error(`Story not found: ${storyId}`);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const { bible, chapters } = story;
|
|
13
|
+
let content;
|
|
14
|
+
let extension;
|
|
15
|
+
switch (format.toLowerCase()) {
|
|
16
|
+
case 'txt':
|
|
17
|
+
case 'text':
|
|
18
|
+
content = exportAsText(bible, chapters);
|
|
19
|
+
extension = 'txt';
|
|
20
|
+
break;
|
|
21
|
+
case 'md':
|
|
22
|
+
case 'markdown':
|
|
23
|
+
default:
|
|
24
|
+
content = exportAsMarkdown(bible, chapters);
|
|
25
|
+
extension = 'md';
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
const filename = output || `${bible.title.replace(/[^a-zA-Z0-9]/g, '_')}.${extension}`;
|
|
29
|
+
(0, fs_1.writeFileSync)(filename, content, 'utf-8');
|
|
30
|
+
console.log(`ā
Exported ${chapters.length} chapters to ${filename}`);
|
|
31
|
+
}
|
|
32
|
+
function exportAsMarkdown(bible, chapters) {
|
|
33
|
+
const lines = [];
|
|
34
|
+
// Title page
|
|
35
|
+
lines.push(`# ${bible.title}`);
|
|
36
|
+
lines.push('');
|
|
37
|
+
lines.push(`**Theme:** ${bible.theme}`);
|
|
38
|
+
lines.push(`**Genre:** ${bible.genre}`);
|
|
39
|
+
lines.push(`**Setting:** ${bible.setting}`);
|
|
40
|
+
lines.push(`**Tone:** ${bible.tone}`);
|
|
41
|
+
lines.push('');
|
|
42
|
+
lines.push(`## Premise`);
|
|
43
|
+
lines.push(bible.premise);
|
|
44
|
+
lines.push('');
|
|
45
|
+
// Characters
|
|
46
|
+
if (bible.characters.length > 0) {
|
|
47
|
+
lines.push('## Characters');
|
|
48
|
+
lines.push('');
|
|
49
|
+
for (const char of bible.characters) {
|
|
50
|
+
lines.push(`### ${char.name}`);
|
|
51
|
+
lines.push(`- **Role:** ${char.role}`);
|
|
52
|
+
lines.push(`- **Traits:** ${char.traits.join(', ')}`);
|
|
53
|
+
lines.push(`- **Goals:** ${char.goals.join(', ')}`);
|
|
54
|
+
if (char.background) {
|
|
55
|
+
lines.push(`- **Background:** ${char.background}`);
|
|
56
|
+
}
|
|
57
|
+
lines.push('');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Chapters
|
|
61
|
+
if (chapters.length > 0) {
|
|
62
|
+
lines.push('---');
|
|
63
|
+
lines.push('');
|
|
64
|
+
for (const chapter of chapters) {
|
|
65
|
+
lines.push(`# Chapter ${chapter.number}: ${chapter.title}`);
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push(chapter.content);
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(`*Word count: ${chapter.wordCount}*`);
|
|
70
|
+
lines.push('');
|
|
71
|
+
lines.push('---');
|
|
72
|
+
lines.push('');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
function exportAsText(bible, chapters) {
|
|
78
|
+
const lines = [];
|
|
79
|
+
lines.push(bible.title.toUpperCase());
|
|
80
|
+
lines.push('');
|
|
81
|
+
lines.push(`Theme: ${bible.theme}`);
|
|
82
|
+
lines.push(`Genre: ${bible.genre}`);
|
|
83
|
+
lines.push(`Setting: ${bible.setting}`);
|
|
84
|
+
lines.push('');
|
|
85
|
+
lines.push('PREMISE');
|
|
86
|
+
lines.push(bible.premise);
|
|
87
|
+
lines.push('');
|
|
88
|
+
if (chapters.length > 0) {
|
|
89
|
+
for (const chapter of chapters) {
|
|
90
|
+
lines.push(`CHAPTER ${chapter.number}: ${chapter.title.toUpperCase()}`);
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push(chapter.content);
|
|
93
|
+
lines.push('');
|
|
94
|
+
lines.push('---');
|
|
95
|
+
lines.push('');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return lines.join('\n');
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateCommand(storyId: string): Promise<void>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateCommand = generateCommand;
|
|
4
|
+
const engine_1 = require("@narrative-os/engine");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
async function generateCommand(storyId) {
|
|
7
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
8
|
+
if (!story) {
|
|
9
|
+
console.error(`ā Story not found: ${storyId}\n`);
|
|
10
|
+
console.log('š” Try one of these:');
|
|
11
|
+
console.log(' ⢠List all stories: nos list');
|
|
12
|
+
console.log(' ⢠Create new story: nos init --title "My Story"');
|
|
13
|
+
console.log(' ⢠Check story status: nos status');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const { bible, state, chapters, canon } = story;
|
|
17
|
+
if (state.currentChapter >= state.totalChapters) {
|
|
18
|
+
console.log('Story is complete!');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const nextChapterNumber = state.currentChapter + 1;
|
|
22
|
+
const context = {
|
|
23
|
+
bible,
|
|
24
|
+
state,
|
|
25
|
+
chapterNumber: nextChapterNumber,
|
|
26
|
+
targetWordCount: 1500,
|
|
27
|
+
};
|
|
28
|
+
// Load or initialize vector store for memory
|
|
29
|
+
const vectorStore = (0, engine_1.getVectorStore)(storyId);
|
|
30
|
+
const existingData = (0, store_js_1.loadVectorStore)(storyId);
|
|
31
|
+
if (existingData) {
|
|
32
|
+
await vectorStore.load(existingData);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
await vectorStore.initialize();
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const result = await (0, engine_1.generateChapter)(context, { canon, vectorStore });
|
|
39
|
+
const newChapters = [...chapters, result.chapter];
|
|
40
|
+
const newState = (0, engine_1.updateStoryState)(state, result.summary);
|
|
41
|
+
(0, store_js_1.saveStory)(bible, newState, newChapters, canon);
|
|
42
|
+
// Save vector store
|
|
43
|
+
(0, store_js_1.saveVectorStore)(storyId, vectorStore.serialize());
|
|
44
|
+
console.log(`\nā
Chapter ${result.chapter.number} generated!`);
|
|
45
|
+
console.log(` Title: ${result.chapter.title}`);
|
|
46
|
+
console.log(` Words: ${result.chapter.wordCount}`);
|
|
47
|
+
if (result.violations.length > 0) {
|
|
48
|
+
console.log(` ā ļø Canon violations: ${result.violations.length}`);
|
|
49
|
+
}
|
|
50
|
+
if (result.memoriesExtracted > 0) {
|
|
51
|
+
console.log(` š§ Memories extracted: ${result.memoriesExtracted}`);
|
|
52
|
+
}
|
|
53
|
+
console.log(` Summary: ${result.summary.summary}`);
|
|
54
|
+
const progress = Math.round((newState.currentChapter / state.totalChapters) * 100);
|
|
55
|
+
console.log(`\nš Progress: ${newState.currentChapter}/${state.totalChapters} (${progress}%)`);
|
|
56
|
+
console.log(`\nš” Next steps:`);
|
|
57
|
+
if (newState.currentChapter < state.totalChapters) {
|
|
58
|
+
console.log(` ⢠Generate next chapter: nos generate ${storyId}`);
|
|
59
|
+
console.log(` ⢠Read this chapter: nos read ${storyId} ${result.chapter.number}`);
|
|
60
|
+
console.log(` ⢠Auto-generate rest: nos continue ${storyId}`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.log(` š Story complete!`);
|
|
64
|
+
console.log(` ⢠Export to file: nos export ${storyId}`);
|
|
65
|
+
console.log(` ⢠Read full story: nos read ${storyId}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('Generation failed:', error);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.showHint = showHint;
|
|
4
|
+
exports.showWelcome = showWelcome;
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
function showHint(context) {
|
|
7
|
+
const stories = (0, store_js_1.listStories)();
|
|
8
|
+
console.log('\nš” Quick Tips:\n');
|
|
9
|
+
if (stories.length === 0) {
|
|
10
|
+
console.log(' You have no stories yet.');
|
|
11
|
+
console.log(' Create one: nos init --title "My Story"');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// Find an active story (not complete)
|
|
15
|
+
const activeStory = stories.find(s => s.currentChapter < s.totalChapters);
|
|
16
|
+
const storyId = context?.storyId || activeStory?.id || stories[0].id;
|
|
17
|
+
const story = (0, store_js_1.loadStory)(storyId);
|
|
18
|
+
if (!story)
|
|
19
|
+
return;
|
|
20
|
+
const { state } = story;
|
|
21
|
+
const isComplete = state.currentChapter >= state.totalChapters;
|
|
22
|
+
// Show hints based on context
|
|
23
|
+
if (context?.afterCommand === 'init') {
|
|
24
|
+
console.log(` Your story "${story.bible.title}" is ready!`);
|
|
25
|
+
console.log(` Generate Chapter 1: nos generate ${storyId}`);
|
|
26
|
+
}
|
|
27
|
+
else if (isComplete) {
|
|
28
|
+
console.log(` Story "${story.bible.title}" is complete! š`);
|
|
29
|
+
console.log(` Export to file: nos export ${storyId}`);
|
|
30
|
+
console.log(` Read the story: nos read ${storyId}`);
|
|
31
|
+
console.log(` Clone as template: nos clone ${storyId} "New Version"`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(` Continue "${story.bible.title}" (${state.currentChapter}/${state.totalChapters} chapters)`);
|
|
35
|
+
console.log(` Generate next: nos generate ${storyId}`);
|
|
36
|
+
console.log(` Auto-complete: nos continue ${storyId}`);
|
|
37
|
+
console.log(` Check status: nos status ${storyId}`);
|
|
38
|
+
}
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log(' Other useful commands:');
|
|
41
|
+
console.log(' nos list List all stories');
|
|
42
|
+
console.log(' nos bible <id> View story bible');
|
|
43
|
+
console.log(' nos memories <id> Search memories');
|
|
44
|
+
console.log(' nos validate <id> Check consistency');
|
|
45
|
+
console.log(' nos --help Show all commands');
|
|
46
|
+
}
|
|
47
|
+
function showWelcome() {
|
|
48
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
49
|
+
console.log('ā š Narrative OS - AI Story Engine ā');
|
|
50
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
51
|
+
const stories = (0, store_js_1.listStories)();
|
|
52
|
+
if (stories.length === 0) {
|
|
53
|
+
console.log('Welcome! Let\'s create your first story.\n');
|
|
54
|
+
console.log('š” Quick Start:');
|
|
55
|
+
console.log(' nos init --title "My Adventure" --chapters 10');
|
|
56
|
+
console.log('\nOr explore options:');
|
|
57
|
+
console.log(' nos init --help');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.log(`You have ${stories.length} story(s).\n`);
|
|
61
|
+
console.log('š” Quick Commands:');
|
|
62
|
+
console.log(' nos list See all stories');
|
|
63
|
+
console.log(' nos status Check story status');
|
|
64
|
+
console.log(' nos generate <id> Write next chapter');
|
|
65
|
+
console.log(' nos --help All commands');
|
|
66
|
+
}
|
|
67
|
+
console.log('');
|
|
68
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initCommand = initCommand;
|
|
4
|
+
const engine_1 = require("@narrative-os/engine");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
async function initCommand(options) {
|
|
7
|
+
console.log('Creating new story...\n');
|
|
8
|
+
const title = options.title || 'Untitled Story';
|
|
9
|
+
const theme = options.theme || 'Redemption';
|
|
10
|
+
const genre = options.genre || 'Science Fiction';
|
|
11
|
+
const setting = options.setting || 'Neo-Tokyo 2145';
|
|
12
|
+
const tone = options.tone || 'Dark, philosophical';
|
|
13
|
+
const premise = options.premise || 'A detective discovers a conspiracy that challenges everything she knows about reality.';
|
|
14
|
+
const targetChapters = parseInt(options.chapters || '5');
|
|
15
|
+
let bible = (0, engine_1.createStoryBible)(title, theme, genre, setting, tone, premise, targetChapters);
|
|
16
|
+
bible = (0, engine_1.addCharacter)(bible, 'Mira Kade', 'protagonist', ['determined', 'cynical', 'brilliant'], ['uncover the truth', 'protect her sister']);
|
|
17
|
+
bible = (0, engine_1.addCharacter)(bible, 'The Architect', 'antagonist', ['charismatic', 'ruthless', 'visionary'], ['reshape society', 'eliminate obstacles']);
|
|
18
|
+
const state = (0, engine_1.createStoryState)(bible.id, targetChapters);
|
|
19
|
+
(0, store_js_1.saveStory)(bible, state, []);
|
|
20
|
+
console.log(`\nā
Story created: ${title}`);
|
|
21
|
+
console.log(` ID: ${bible.id}`);
|
|
22
|
+
console.log(` Target chapters: ${targetChapters}`);
|
|
23
|
+
console.log(`\nš” Next steps:`);
|
|
24
|
+
console.log(` ⢠Generate Chapter 1: nos generate ${bible.id}`);
|
|
25
|
+
console.log(` ⢠View story bible: nos bible ${bible.id}`);
|
|
26
|
+
console.log(` ⢠Check status: nos status ${bible.id}`);
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function listCommand(): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listCommand = listCommand;
|
|
4
|
+
const store_js_1 = require("../config/store.js");
|
|
5
|
+
function listCommand() {
|
|
6
|
+
const stories = (0, store_js_1.listStories)();
|
|
7
|
+
if (stories.length === 0) {
|
|
8
|
+
console.log('No stories found. Run "nos init" to create one.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
console.log(`Found ${stories.length} story(s):\n`);
|
|
12
|
+
for (const story of stories) {
|
|
13
|
+
const progress = Math.round((story.currentChapter / story.totalChapters) * 100);
|
|
14
|
+
const status = story.currentChapter >= story.totalChapters ? 'ā
Complete' : 'ā³ In Progress';
|
|
15
|
+
console.log(` ${story.id}`);
|
|
16
|
+
console.log(` Title: ${story.title}`);
|
|
17
|
+
console.log(` Progress: ${story.currentChapter}/${story.totalChapters} (${progress}%)`);
|
|
18
|
+
console.log(` Status: ${status}`);
|
|
19
|
+
console.log('');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function memoriesCommand(storyId: string, query?: string): Promise<void>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memoriesCommand = memoriesCommand;
|
|
4
|
+
const engine_1 = require("@narrative-os/engine");
|
|
5
|
+
const store_js_1 = require("../config/store.js");
|
|
6
|
+
async function memoriesCommand(storyId, query) {
|
|
7
|
+
// Load vector store
|
|
8
|
+
const vectorStore = (0, engine_1.getVectorStore)(storyId);
|
|
9
|
+
const existingData = (0, store_js_1.loadVectorStore)(storyId);
|
|
10
|
+
if (existingData) {
|
|
11
|
+
await vectorStore.load(existingData);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log('No memories found for this story.');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const allMemories = vectorStore.getAllMemories();
|
|
18
|
+
if (allMemories.length === 0) {
|
|
19
|
+
console.log('No memories found for this story.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (query) {
|
|
23
|
+
// Search memories
|
|
24
|
+
console.log(`Searching memories for: "${query}"\n`);
|
|
25
|
+
const results = await vectorStore.searchSimilar(query, 10);
|
|
26
|
+
console.log(`Found ${results.length} relevant memories:\n`);
|
|
27
|
+
for (let i = 0; i < results.length; i++) {
|
|
28
|
+
const r = results[i];
|
|
29
|
+
console.log(`${i + 1}. [${r.memory.category}] Chapter ${r.memory.chapterNumber}`);
|
|
30
|
+
console.log(` ${r.memory.content.substring(0, 80)}...`);
|
|
31
|
+
console.log(` Relevance: ${(1 - r.score).toFixed(3)}`);
|
|
32
|
+
console.log('');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// List all memories
|
|
37
|
+
console.log(`Total memories: ${allMemories.length}\n`);
|
|
38
|
+
// Group by category
|
|
39
|
+
const byCategory = {};
|
|
40
|
+
for (const mem of allMemories) {
|
|
41
|
+
if (!byCategory[mem.category]) {
|
|
42
|
+
byCategory[mem.category] = [];
|
|
43
|
+
}
|
|
44
|
+
byCategory[mem.category].push(mem);
|
|
45
|
+
}
|
|
46
|
+
for (const [category, memories] of Object.entries(byCategory)) {
|
|
47
|
+
console.log(`\n## ${category.toUpperCase()} (${memories.length})`);
|
|
48
|
+
console.log('ā'.repeat(60));
|
|
49
|
+
for (const mem of memories.slice(0, 5)) { // Show first 5 per category
|
|
50
|
+
console.log(`\n Chapter ${mem.chapterNumber}:`);
|
|
51
|
+
console.log(` ${mem.content.substring(0, 100)}...`);
|
|
52
|
+
}
|
|
53
|
+
if (memories.length > 5) {
|
|
54
|
+
console.log(`\n ... and ${memories.length - 5} more`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
console.log('');
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readCommand(storyId: string, chapterNumber?: number): void;
|