novel-writer-style-cn 0.21.0 → 0.21.1
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/cli.js +1 -1
- package/dist/plugins/manager.js +86 -0
- package/dist/utils/interactive.js +154 -0
- package/dist/utils/project.js +75 -0
- package/dist/version.js +31 -0
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 插件管理器
|
|
10
|
+
*/
|
|
11
|
+
export class PluginManager {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.plugins = new Map();
|
|
14
|
+
this.loadPlugins();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 加载插件
|
|
19
|
+
*/
|
|
20
|
+
loadPlugins() {
|
|
21
|
+
try {
|
|
22
|
+
const pluginsDir = path.join(__dirname, '..', '..', 'plugins');
|
|
23
|
+
if (fs.existsSync(pluginsDir)) {
|
|
24
|
+
const pluginDirs = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
25
|
+
.filter(dirent => dirent.isDirectory())
|
|
26
|
+
.map(dirent => dirent.name);
|
|
27
|
+
|
|
28
|
+
for (const pluginName of pluginDirs) {
|
|
29
|
+
this.loadPlugin(pluginName);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.warn('Failed to load plugins:', error.message);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 加载单个插件
|
|
39
|
+
*/
|
|
40
|
+
loadPlugin(pluginName) {
|
|
41
|
+
try {
|
|
42
|
+
const pluginPath = path.join(__dirname, '..', '..', 'plugins', pluginName);
|
|
43
|
+
const packagePath = path.join(pluginPath, 'package.json');
|
|
44
|
+
|
|
45
|
+
if (fs.existsSync(packagePath)) {
|
|
46
|
+
const packageJson = fs.readJsonSync(packagePath);
|
|
47
|
+
this.plugins.set(pluginName, {
|
|
48
|
+
name: pluginName,
|
|
49
|
+
version: packageJson.version || '1.0.0',
|
|
50
|
+
description: packageJson.description || '',
|
|
51
|
+
path: pluginPath
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.warn(`Failed to load plugin ${pluginName}:`, error.message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 获取所有插件
|
|
61
|
+
*/
|
|
62
|
+
getPlugins() {
|
|
63
|
+
return Array.from(this.plugins.values());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 获取插件
|
|
68
|
+
*/
|
|
69
|
+
getPlugin(name) {
|
|
70
|
+
return this.plugins.get(name);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 检查插件是否存在
|
|
75
|
+
*/
|
|
76
|
+
hasPlugin(name) {
|
|
77
|
+
return this.plugins.has(name);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 列出所有插件
|
|
82
|
+
*/
|
|
83
|
+
listPlugins() {
|
|
84
|
+
return this.getPlugins();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 显示项目横幅
|
|
7
|
+
*/
|
|
8
|
+
export function displayProjectBanner() {
|
|
9
|
+
console.log(chalk.cyan.bold('\n📚 Novel Writer Style CN'));
|
|
10
|
+
console.log(chalk.gray('AI 驱动的中文小说创作工具\n'));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 选择 AI 助手
|
|
15
|
+
*/
|
|
16
|
+
export async function selectAIAssistant(configs) {
|
|
17
|
+
if (!isInteractive()) {
|
|
18
|
+
return configs[0]; // 默认返回第一个配置
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const choices = configs.map(config => ({
|
|
22
|
+
name: `${config.displayName} (${config.name})`,
|
|
23
|
+
value: config
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const { assistant } = await inquirer.prompt([
|
|
27
|
+
{
|
|
28
|
+
type: 'list',
|
|
29
|
+
name: 'assistant',
|
|
30
|
+
message: '选择 AI 助手:',
|
|
31
|
+
choices
|
|
32
|
+
}
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
return assistant;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 选择写作方法
|
|
40
|
+
*/
|
|
41
|
+
export async function selectWritingMethod() {
|
|
42
|
+
if (!isInteractive()) {
|
|
43
|
+
return 'structured'; // 默认返回结构化写作
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { method } = await inquirer.prompt([
|
|
47
|
+
{
|
|
48
|
+
type: 'list',
|
|
49
|
+
name: 'method',
|
|
50
|
+
message: '选择写作方法:',
|
|
51
|
+
choices: [
|
|
52
|
+
{ name: '结构化写作 (推荐)', value: 'structured' },
|
|
53
|
+
{ name: '自由写作', value: 'free' },
|
|
54
|
+
{ name: '模板写作', value: 'template' }
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
return method;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 选择脚本类型
|
|
64
|
+
*/
|
|
65
|
+
export async function selectScriptType() {
|
|
66
|
+
if (!isInteractive()) {
|
|
67
|
+
return 'novel'; // 默认返回小说
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const { type } = await inquirer.prompt([
|
|
71
|
+
{
|
|
72
|
+
type: 'list',
|
|
73
|
+
name: 'type',
|
|
74
|
+
message: '选择创作类型:',
|
|
75
|
+
choices: [
|
|
76
|
+
{ name: '长篇小说', value: 'novel' },
|
|
77
|
+
{ name: '短篇故事', value: 'story' },
|
|
78
|
+
{ name: '剧本', value: 'script' },
|
|
79
|
+
{ name: '其他', value: 'other' }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
return type;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 确认专家模式
|
|
89
|
+
*/
|
|
90
|
+
export async function confirmExpertMode() {
|
|
91
|
+
if (!isInteractive()) {
|
|
92
|
+
return false; // 默认不启用专家模式
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { expert } = await inquirer.prompt([
|
|
96
|
+
{
|
|
97
|
+
type: 'confirm',
|
|
98
|
+
name: 'expert',
|
|
99
|
+
message: '启用专家模式? (提供更多高级选项)',
|
|
100
|
+
default: false
|
|
101
|
+
}
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
return expert;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 显示步骤信息
|
|
109
|
+
*/
|
|
110
|
+
export function displayStep(step, total, message) {
|
|
111
|
+
console.log(chalk.blue(`[${step}/${total}]`) + ' ' + message);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 检查是否在交互模式
|
|
116
|
+
*/
|
|
117
|
+
export function isInteractive() {
|
|
118
|
+
return process.stdin.isTTY && process.stdout.isTTY;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 显示加载动画
|
|
123
|
+
*/
|
|
124
|
+
export function createSpinner(text) {
|
|
125
|
+
return ora(text);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 显示成功消息
|
|
130
|
+
*/
|
|
131
|
+
export function displaySuccess(message) {
|
|
132
|
+
console.log(chalk.green('✓ ' + message));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 显示错误消息
|
|
137
|
+
*/
|
|
138
|
+
export function displayError(message) {
|
|
139
|
+
console.log(chalk.red('✗ ' + message));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 显示警告消息
|
|
144
|
+
*/
|
|
145
|
+
export function displayWarning(message) {
|
|
146
|
+
console.log(chalk.yellow('⚠ ' + message));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 显示信息消息
|
|
151
|
+
*/
|
|
152
|
+
export function displayInfo(message) {
|
|
153
|
+
console.log(chalk.blue('ℹ ' + message));
|
|
154
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 确保项目根目录存在
|
|
10
|
+
*/
|
|
11
|
+
export function ensureProjectRoot() {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
return cwd;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取项目信息
|
|
18
|
+
*/
|
|
19
|
+
export function getProjectInfo() {
|
|
20
|
+
try {
|
|
21
|
+
const projectRoot = ensureProjectRoot();
|
|
22
|
+
const packagePath = path.join(projectRoot, 'package.json');
|
|
23
|
+
|
|
24
|
+
if (fs.existsSync(packagePath)) {
|
|
25
|
+
const packageJson = fs.readJsonSync(packagePath);
|
|
26
|
+
return {
|
|
27
|
+
name: packageJson.name || 'unknown',
|
|
28
|
+
version: packageJson.version || '1.0.0',
|
|
29
|
+
description: packageJson.description || '',
|
|
30
|
+
root: projectRoot,
|
|
31
|
+
installedAI: [] // 添加默认的 AI 配置数组
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
name: path.basename(projectRoot),
|
|
37
|
+
version: '1.0.0',
|
|
38
|
+
description: '',
|
|
39
|
+
root: projectRoot,
|
|
40
|
+
installedAI: [] // 添加默认的 AI 配置数组
|
|
41
|
+
};
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return {
|
|
44
|
+
name: 'unknown',
|
|
45
|
+
version: '1.0.0',
|
|
46
|
+
description: '',
|
|
47
|
+
root: process.cwd(),
|
|
48
|
+
installedAI: [] // 添加默认的 AI 配置数组
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 检查是否在项目根目录
|
|
55
|
+
*/
|
|
56
|
+
export function isProjectRoot(dir = process.cwd()) {
|
|
57
|
+
const packagePath = path.join(dir, 'package.json');
|
|
58
|
+
return fs.existsSync(packagePath);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 查找项目根目录
|
|
63
|
+
*/
|
|
64
|
+
export function findProjectRoot(startDir = process.cwd()) {
|
|
65
|
+
let currentDir = startDir;
|
|
66
|
+
|
|
67
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
68
|
+
if (isProjectRoot(currentDir)) {
|
|
69
|
+
return currentDir;
|
|
70
|
+
}
|
|
71
|
+
currentDir = path.dirname(currentDir);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return startDir;
|
|
75
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取版本号
|
|
10
|
+
*/
|
|
11
|
+
export function getVersion() {
|
|
12
|
+
try {
|
|
13
|
+
const packagePath = path.join(__dirname, '..', 'package.json');
|
|
14
|
+
const packageJson = fs.readJsonSync(packagePath);
|
|
15
|
+
return packageJson.version || '0.21.0';
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return '0.21.0';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获取版本信息
|
|
23
|
+
*/
|
|
24
|
+
export function getVersionInfo() {
|
|
25
|
+
const version = getVersion();
|
|
26
|
+
return {
|
|
27
|
+
version,
|
|
28
|
+
name: 'novel-writer-style-cn',
|
|
29
|
+
description: 'AI 驱动的中文小说创作工具'
|
|
30
|
+
};
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "novel-writer-style-cn",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI 驱动的中文小说创作工具 - 基于结构化工作流的智能写作助手",
|
|
6
6
|
"keywords": [
|
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"url": "https://github.com/lsg1103275794/novel-writer-style-cn/issues"
|
|
62
62
|
},
|
|
63
63
|
"novelWriter": {
|
|
64
|
-
"plugins": [
|
|
64
|
+
"plugins": [
|
|
65
|
+
"style-learning"
|
|
66
|
+
],
|
|
65
67
|
"version": "0.21.0"
|
|
66
68
|
}
|
|
67
69
|
}
|