@narrative-os/cli 0.1.9 → 0.1.11
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/README.md +10 -2
- package/dist/commands/config.d.ts +3 -3
- package/dist/commands/config.js +75 -18
- package/dist/commands/version.d.ts +1 -0
- package/dist/commands/version.js +114 -0
- package/dist/index.js +6 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ nos continue <story-id>
|
|
|
28
28
|
|
|
29
29
|
| Command | Description |
|
|
30
30
|
|---------|-------------|
|
|
31
|
-
| `nos init` | Create a new story |
|
|
31
|
+
| `nos init` | Create a new story (interactive prompts) |
|
|
32
32
|
| `nos generate <id>` | Generate next chapter |
|
|
33
33
|
| `nos continue <id>` | Auto-generate remaining chapters |
|
|
34
34
|
| `nos status [id]` | View story status |
|
|
@@ -39,7 +39,15 @@ nos continue <story-id>
|
|
|
39
39
|
| `nos validate <id>` | Validate story consistency |
|
|
40
40
|
| `nos export <id>` | Export story to markdown |
|
|
41
41
|
| `nos delete <id>` | Delete a story |
|
|
42
|
-
| `nos config` | Configure LLM settings |
|
|
42
|
+
| `nos config` | Configure LLM settings (multi-model) |
|
|
43
|
+
| `nos version` | Show version information |
|
|
44
|
+
|
|
45
|
+
## Supported LLM Providers
|
|
46
|
+
|
|
47
|
+
- **OpenAI** - GPT-4o, GPT-4o-mini, GPT-4-turbo
|
|
48
|
+
- **DeepSeek** - deepseek-chat, deepseek-reasoner
|
|
49
|
+
- **Alibaba Cloud** - Qwen models (qwen-max, qwen-plus, qwen-turbo, text-embedding-v3)
|
|
50
|
+
- **ByteDance Ark** - Doubao models (doubao-pro-128k, doubao-lite-128k, doubao-embedding)
|
|
43
51
|
|
|
44
52
|
## Features
|
|
45
53
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
interface ModelConfig {
|
|
2
2
|
name: string;
|
|
3
|
-
provider: 'openai' | 'deepseek';
|
|
3
|
+
provider: 'openai' | 'deepseek' | 'alibaba' | 'ark';
|
|
4
4
|
apiKey: string;
|
|
5
5
|
baseURL?: string;
|
|
6
6
|
model: string;
|
|
7
|
-
purpose: 'reasoning' | 'chat' | 'fast';
|
|
7
|
+
purpose: 'reasoning' | 'chat' | 'fast' | 'embedding';
|
|
8
8
|
}
|
|
9
9
|
interface MultiModelConfig {
|
|
10
10
|
models: ModelConfig[];
|
|
11
11
|
defaultModel: string;
|
|
12
12
|
}
|
|
13
13
|
interface LegacyConfig {
|
|
14
|
-
provider: 'openai' | 'deepseek';
|
|
14
|
+
provider: 'openai' | 'deepseek' | 'alibaba' | 'ark';
|
|
15
15
|
apiKey: string;
|
|
16
16
|
model: string;
|
|
17
17
|
}
|
package/dist/commands/config.js
CHANGED
|
@@ -11,6 +11,8 @@ const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, 'config.json');
|
|
|
11
11
|
const PROVIDERS = [
|
|
12
12
|
{ name: 'OpenAI', value: 'openai', models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo'] },
|
|
13
13
|
{ name: 'DeepSeek', value: 'deepseek', models: ['deepseek-chat', 'deepseek-reasoner'] },
|
|
14
|
+
{ name: 'Alibaba Cloud (Qwen)', value: 'alibaba', models: ['qwen-max', 'qwen-plus', 'qwen-turbo', 'text-embedding-v3'] },
|
|
15
|
+
{ name: 'ByteDance Ark', value: 'ark', models: ['doubao-pro-128k', 'doubao-lite-128k', 'doubao-embedding'] },
|
|
14
16
|
];
|
|
15
17
|
function loadConfig() {
|
|
16
18
|
if (!(0, fs_1.existsSync)(CONFIG_FILE))
|
|
@@ -91,26 +93,66 @@ async function configCommand(showOnly = false) {
|
|
|
91
93
|
choices: providerInfo.models.map(m => ({ name: m, value: m })),
|
|
92
94
|
default: provider === 'deepseek' ? 'deepseek-chat' : 'gpt-4o-mini',
|
|
93
95
|
});
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
default: provider !== 'deepseek',
|
|
98
|
-
});
|
|
96
|
+
// Determine if provider supports embeddings natively
|
|
97
|
+
const supportsEmbeddings = provider === 'alibaba' || provider === 'ark' || provider === 'openai';
|
|
98
|
+
const needsSeparateEmbedding = provider === 'deepseek';
|
|
99
99
|
let embeddingConfig;
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
if (needsSeparateEmbedding) {
|
|
101
|
+
// DeepSeek doesn't support embeddings, ask for alternative
|
|
102
|
+
const useOpenAIEmbeddings = await confirm({
|
|
103
|
+
message: 'Use OpenAI for embeddings? (DeepSeek does not support embeddings)',
|
|
104
|
+
default: true,
|
|
104
105
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
if (useOpenAIEmbeddings) {
|
|
107
|
+
const openAIEmbedKey = await password({
|
|
108
|
+
message: 'Enter OpenAI API key (for embeddings):',
|
|
109
|
+
mask: '*',
|
|
110
|
+
});
|
|
111
|
+
embeddingConfig = {
|
|
112
|
+
name: 'embedding',
|
|
113
|
+
provider: 'openai',
|
|
114
|
+
apiKey: openAIEmbedKey,
|
|
115
|
+
model: 'text-embedding-3-small',
|
|
116
|
+
purpose: 'embedding',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (supportsEmbeddings) {
|
|
121
|
+
// Provider supports embeddings, ask if they want to use it
|
|
122
|
+
const useProviderEmbeddings = await confirm({
|
|
123
|
+
message: `Use ${provider === 'alibaba' ? 'Alibaba Cloud' : provider === 'ark' ? 'ByteDance Ark' : 'OpenAI'} for embeddings?`,
|
|
124
|
+
default: true,
|
|
125
|
+
});
|
|
126
|
+
if (useProviderEmbeddings) {
|
|
127
|
+
const embedModel = provider === 'alibaba'
|
|
128
|
+
? 'text-embedding-v3'
|
|
129
|
+
: provider === 'ark'
|
|
130
|
+
? 'doubao-embedding'
|
|
131
|
+
: 'text-embedding-3-small';
|
|
132
|
+
embeddingConfig = {
|
|
133
|
+
name: 'embedding',
|
|
134
|
+
provider: provider,
|
|
135
|
+
apiKey,
|
|
136
|
+
model: embedModel,
|
|
137
|
+
purpose: 'embedding',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Set baseURL based on provider
|
|
142
|
+
let baseURL;
|
|
143
|
+
switch (provider) {
|
|
144
|
+
case 'deepseek':
|
|
145
|
+
baseURL = 'https://api.deepseek.com';
|
|
146
|
+
break;
|
|
147
|
+
case 'alibaba':
|
|
148
|
+
baseURL = 'https://dashscope.aliyuncs.com/compatible-mode/v1';
|
|
149
|
+
break;
|
|
150
|
+
case 'ark':
|
|
151
|
+
baseURL = 'https://ark.cn-beijing.volces.com/api/v3';
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
baseURL = undefined;
|
|
112
155
|
}
|
|
113
|
-
const baseURL = provider === 'deepseek' ? 'https://api.deepseek.com' : undefined;
|
|
114
156
|
const models = [
|
|
115
157
|
{
|
|
116
158
|
name: 'reasoning',
|
|
@@ -141,7 +183,10 @@ async function configCommand(showOnly = false) {
|
|
|
141
183
|
console.log(` Reasoning: ${reasoningModel}`);
|
|
142
184
|
console.log(` Chat: ${chatModel}`);
|
|
143
185
|
if (embeddingConfig) {
|
|
144
|
-
|
|
186
|
+
const embedProvider = embeddingConfig.provider === 'alibaba' ? 'Alibaba Cloud'
|
|
187
|
+
: embeddingConfig.provider === 'ark' ? 'ByteDance Ark'
|
|
188
|
+
: 'OpenAI';
|
|
189
|
+
console.log(` Embeddings: ${embedProvider} (${embeddingConfig.model})`);
|
|
145
190
|
}
|
|
146
191
|
else {
|
|
147
192
|
console.log(` Embeddings: Mock (no API configured)`);
|
|
@@ -188,6 +233,12 @@ function applyConfig() {
|
|
|
188
233
|
else if (model.provider === 'deepseek') {
|
|
189
234
|
process.env.DEEPSEEK_API_KEY = model.apiKey;
|
|
190
235
|
}
|
|
236
|
+
else if (model.provider === 'alibaba') {
|
|
237
|
+
process.env.ALIBABA_API_KEY = model.apiKey;
|
|
238
|
+
}
|
|
239
|
+
else if (model.provider === 'ark') {
|
|
240
|
+
process.env.ARK_API_KEY = model.apiKey;
|
|
241
|
+
}
|
|
191
242
|
}
|
|
192
243
|
}
|
|
193
244
|
else {
|
|
@@ -200,5 +251,11 @@ function applyConfig() {
|
|
|
200
251
|
else if (config.provider === 'deepseek') {
|
|
201
252
|
process.env.DEEPSEEK_API_KEY = config.apiKey;
|
|
202
253
|
}
|
|
254
|
+
else if (config.provider === 'alibaba') {
|
|
255
|
+
process.env.ALIBABA_API_KEY = config.apiKey;
|
|
256
|
+
}
|
|
257
|
+
else if (config.provider === 'ark') {
|
|
258
|
+
process.env.ARK_API_KEY = config.apiKey;
|
|
259
|
+
}
|
|
203
260
|
}
|
|
204
261
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function versionCommand(): void;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.versionCommand = versionCommand;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
// Get the directory of the current file (works in both ESM and CommonJS)
|
|
7
|
+
function getCurrentDir() {
|
|
8
|
+
try {
|
|
9
|
+
// For CommonJS
|
|
10
|
+
return __dirname;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// Fallback
|
|
14
|
+
return process.cwd();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function getPackageInfo(packageName) {
|
|
18
|
+
try {
|
|
19
|
+
// Try to find package in node_modules
|
|
20
|
+
const currentDir = getCurrentDir();
|
|
21
|
+
const possiblePaths = [
|
|
22
|
+
(0, path_1.join)(process.cwd(), 'node_modules', packageName, 'package.json'),
|
|
23
|
+
(0, path_1.join)(currentDir, '..', '..', 'node_modules', packageName, 'package.json'),
|
|
24
|
+
(0, path_1.join)(currentDir, '..', '..', '..', '..', 'node_modules', packageName, 'package.json'),
|
|
25
|
+
];
|
|
26
|
+
for (const pkgPath of possiblePaths) {
|
|
27
|
+
try {
|
|
28
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
29
|
+
return {
|
|
30
|
+
name: pkg.name,
|
|
31
|
+
version: pkg.version,
|
|
32
|
+
description: pkg.description,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function getCLIPackageInfo() {
|
|
46
|
+
try {
|
|
47
|
+
const currentDir = getCurrentDir();
|
|
48
|
+
const pkgPath = (0, path_1.join)(currentDir, '..', '..', 'package.json');
|
|
49
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
50
|
+
return {
|
|
51
|
+
name: pkg.name,
|
|
52
|
+
version: pkg.version,
|
|
53
|
+
description: pkg.description,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { name: '@narrative-os/cli', version: 'unknown' };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function versionCommand() {
|
|
61
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
62
|
+
console.log('║ Narrative OS - Version Information ║');
|
|
63
|
+
console.log('╚════════════════════════════════════════════════════════╝\n');
|
|
64
|
+
// CLI Info
|
|
65
|
+
const cli = getCLIPackageInfo();
|
|
66
|
+
console.log('📦 CLI');
|
|
67
|
+
console.log(` Name: ${cli.name}`);
|
|
68
|
+
console.log(` Version: ${cli.version}`);
|
|
69
|
+
if (cli.description) {
|
|
70
|
+
console.log(` Desc: ${cli.description}`);
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
// Engine Info
|
|
74
|
+
const engine = getPackageInfo('@narrative-os/engine');
|
|
75
|
+
;
|
|
76
|
+
if (engine) {
|
|
77
|
+
console.log('⚙️ Engine');
|
|
78
|
+
console.log(` Name: ${engine.name}`);
|
|
79
|
+
console.log(` Version: ${engine.version}`);
|
|
80
|
+
if (engine.description) {
|
|
81
|
+
console.log(` Desc: ${engine.description}`);
|
|
82
|
+
}
|
|
83
|
+
console.log();
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log('⚙️ Engine: Not installed\n');
|
|
87
|
+
}
|
|
88
|
+
// Future modules (check if installed)
|
|
89
|
+
const futureModules = [
|
|
90
|
+
'@narrative-os/skills',
|
|
91
|
+
'@narrative-os/characters',
|
|
92
|
+
'@narrative-os/worlds',
|
|
93
|
+
'@narrative-os/plots',
|
|
94
|
+
];
|
|
95
|
+
const installedModules = futureModules
|
|
96
|
+
.map(name => getPackageInfo(name))
|
|
97
|
+
.filter((info) => info !== null);
|
|
98
|
+
if (installedModules.length > 0) {
|
|
99
|
+
console.log('🧩 Extension Modules');
|
|
100
|
+
for (const mod of installedModules) {
|
|
101
|
+
console.log(` • ${mod.name}@${mod.version}`);
|
|
102
|
+
}
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
// Check for local development mode
|
|
106
|
+
const currentDir = getCurrentDir();
|
|
107
|
+
const isLocalDev = currentDir.includes('apps/cli');
|
|
108
|
+
if (isLocalDev) {
|
|
109
|
+
console.log('🛠️ Development Mode: Local source\n');
|
|
110
|
+
}
|
|
111
|
+
console.log('─────────────────────────────────────────────────────────');
|
|
112
|
+
console.log('For updates: npm install -g @narrative-os/cli@latest');
|
|
113
|
+
console.log('─────────────────────────────────────────────────────────');
|
|
114
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ const read_js_1 = require("./commands/read.js");
|
|
|
14
14
|
const bible_js_1 = require("./commands/bible.js");
|
|
15
15
|
const state_js_1 = require("./commands/state.js");
|
|
16
16
|
const hint_js_1 = require("./commands/hint.js");
|
|
17
|
+
const version_js_1 = require("./commands/version.js");
|
|
17
18
|
(0, config_js_1.applyConfig)();
|
|
18
19
|
const program = new commander_1.Command();
|
|
19
20
|
program
|
|
@@ -130,4 +131,9 @@ program
|
|
|
130
131
|
.action((storyId) => {
|
|
131
132
|
(0, hint_js_1.showHint)({ storyId });
|
|
132
133
|
});
|
|
134
|
+
program
|
|
135
|
+
.command('version')
|
|
136
|
+
.alias('v')
|
|
137
|
+
.description('Show version information')
|
|
138
|
+
.action(version_js_1.versionCommand);
|
|
133
139
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narrative-os/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "AI-native narrative engine for long-form story generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@inquirer/prompts": "^8.3.0",
|
|
42
|
-
"@narrative-os/engine": "0.1.
|
|
42
|
+
"@narrative-os/engine": "0.1.7",
|
|
43
43
|
"commander": "^12.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|