@dayinxisheng/novel-tools 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2026-03-10
9
+
10
+ ### Added
11
+
12
+ #### style 命令
13
+ - `style extract` - 从 JSONL 文件提取章节内容
14
+ - 支持指定提取章节数量(-n, --count)
15
+ - 支持指定起始章节号(-s, --start)
16
+ - 支持随机选择章节(--random)
17
+ - 支持多种输出格式:text、markdown
18
+ - 支持输出到文件或 stdout
19
+ - `style info` - 显示 JSONL 文件信息
20
+ - 显示总章节数、总字数
21
+ - 显示平均章节字数
22
+ - 显示最短/最长章节
23
+
24
+ #### 新增服务
25
+ - `StyleCommandService` - 风格命令服务
26
+ - JSONL 文件解析
27
+ - 章节内容提取
28
+ - 文件信息统计
29
+ - 随机章节选择
30
+
31
+ #### 新增类型定义
32
+ - `ChapterData` - 章节数据接口
33
+ - `ExtractOptions` - 提取选项接口
34
+ - `ExtractResult` - 提取结果接口
35
+ - `JsonlInfo` - 文件信息接口
36
+
37
+ ### Changed
38
+ - 更新 `commands/index.ts` 注册 style 命令
39
+
8
40
  ## [0.2.0] - 2026-03-09
9
41
 
10
42
  ### Added
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,eAAO,MAAM,GAAG,SAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkCpC,eAAO,MAAM,GAAG,SAAc,CAAC"}
@@ -6,6 +6,7 @@ import { createCheckCommand } from './check.js';
6
6
  import { createSnapshotCommand } from './snapshot.js';
7
7
  import { createEventCommand } from './event.js';
8
8
  import { createTempSettingCommand } from './temp-setting.js';
9
+ import { createStyleCommand } from './style.js';
9
10
  import { CLI_NAME, CLI_VERSION, CLI_DESCRIPTION } from '../core/constants.js';
10
11
  /**
11
12
  * 主 CLI 程序
@@ -23,6 +24,7 @@ function createCli() {
23
24
  program.addCommand(createSnapshotCommand());
24
25
  program.addCommand(createEventCommand());
25
26
  program.addCommand(createTempSettingCommand());
27
+ program.addCommand(createStyleCommand());
26
28
  return program;
27
29
  }
28
30
  // 导出供测试使用
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE9E;;GAEG;AACH,SAAS,SAAS;IAChB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,eAAe,CAAC;SAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;IAExB,QAAQ;IACR,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAE/C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,UAAU;AACV,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAE/B,cAAc;AACd,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE9E;;GAEG;AACH,SAAS,SAAS;IAChB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,eAAe,CAAC;SAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;IAExB,QAAQ;IACR,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,UAAU,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAEzC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,UAAU;AACV,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAE/B,cAAc;AACd,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * 创建 style 命令 - 用于从 JSONL 文件提取章节内容供风格分析
4
+ */
5
+ export declare function createStyleCommand(): Command;
6
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/commands/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAyE5C"}
@@ -0,0 +1,75 @@
1
+ import { Command } from 'commander';
2
+ import { StyleCommandService } from '../services/style-command.service.js';
3
+ import { CliUtils } from './shared.js';
4
+ /**
5
+ * 创建 style 命令 - 用于从 JSONL 文件提取章节内容供风格分析
6
+ */
7
+ export function createStyleCommand() {
8
+ const cmd = new Command('style');
9
+ cmd.description('从 JSONL 文件提取章节内容,用于写作风格分析');
10
+ // style extract — 提取章节内容
11
+ cmd
12
+ .command('extract')
13
+ .argument('<jsonlFile>', 'JSONL 文件路径')
14
+ .option('-o, --output <path>', '输出文件路径(默认输出到 stdout)')
15
+ .option('-n, --count <number>', '提取章节数量', '10')
16
+ .option('-s, --start <number>', '起始章节号', '1')
17
+ .option('--random', '随机选择章节')
18
+ .option('--format <format>', '输出格式: text | markdown', 'markdown')
19
+ .action(async (jsonlFile, options) => {
20
+ try {
21
+ const service = new StyleCommandService();
22
+ const count = parseInt(options.count, 10);
23
+ if (isNaN(count) || count < 1) {
24
+ CliUtils.error('章节数量必须是正整数');
25
+ process.exit(1);
26
+ }
27
+ const start = parseInt(options.start, 10);
28
+ if (isNaN(start) || start < 1) {
29
+ CliUtils.error('起始章节号必须是正整数');
30
+ process.exit(1);
31
+ }
32
+ const result = await service.extractFromJsonl(jsonlFile, {
33
+ count,
34
+ start,
35
+ random: options.random || false,
36
+ format: options.format,
37
+ });
38
+ if (options.output) {
39
+ await service.writeToFile(result, options.output);
40
+ CliUtils.success(`已提取 ${result.chapterCount} 章,保存到: ${options.output}`);
41
+ }
42
+ else {
43
+ console.log(result.content);
44
+ }
45
+ }
46
+ catch (error) {
47
+ CliUtils.error(error instanceof Error ? error.message : String(error));
48
+ process.exit(1);
49
+ }
50
+ });
51
+ // style info — 显示 JSONL 文件信息
52
+ cmd
53
+ .command('info')
54
+ .argument('<jsonlFile>', 'JSONL 文件路径')
55
+ .action(async (jsonlFile) => {
56
+ try {
57
+ const service = new StyleCommandService();
58
+ const info = await service.getJsonlInfo(jsonlFile);
59
+ console.log('\n📊 JSONL 文件信息\n');
60
+ console.log(`文件路径: ${jsonlFile}`);
61
+ console.log(`总章节数: ${info.totalChapters}`);
62
+ console.log(`总字数: ${info.totalWords.toLocaleString()}`);
63
+ console.log(`平均章节字数: ${info.avgWordsPerChapter.toLocaleString()}`);
64
+ console.log(`最短章节: 第 ${info.minChapter.chapter_id} 章 (${info.minChapter.chapter_length} 字)`);
65
+ console.log(`最长章节: 第 ${info.maxChapter.chapter_id} 章 (${info.maxChapter.chapter_length} 字)`);
66
+ console.log('');
67
+ }
68
+ catch (error) {
69
+ CliUtils.error(error instanceof Error ? error.message : String(error));
70
+ process.exit(1);
71
+ }
72
+ });
73
+ return cmd;
74
+ }
75
+ //# sourceMappingURL=style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/commands/style.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ interface ChapterData {
2
+ chapter_id: number;
3
+ chapter: string;
4
+ chapter_length: number;
5
+ }
6
+ interface ExtractOptions {
7
+ count: number;
8
+ start: number;
9
+ random: boolean;
10
+ format: 'text' | 'markdown';
11
+ }
12
+ interface ExtractResult {
13
+ content: string;
14
+ chapterCount: number;
15
+ totalWords: number;
16
+ }
17
+ interface JsonlInfo {
18
+ totalChapters: number;
19
+ totalWords: number;
20
+ avgWordsPerChapter: number;
21
+ minChapter: ChapterData;
22
+ maxChapter: ChapterData;
23
+ }
24
+ /**
25
+ * Style 命令服务
26
+ */
27
+ export declare class StyleCommandService {
28
+ /**
29
+ * 从 JSONL 文件提取章节内容
30
+ */
31
+ extractFromJsonl(jsonlPath: string, options: ExtractOptions): Promise<ExtractResult>;
32
+ /**
33
+ * 获取 JSONL 文件信息
34
+ */
35
+ getJsonlInfo(jsonlPath: string): Promise<JsonlInfo>;
36
+ /**
37
+ * 解析 JSONL 文件
38
+ */
39
+ private parseJsonlFile;
40
+ /**
41
+ * 随机选择章节
42
+ */
43
+ private randomSelect;
44
+ /**
45
+ * 格式化内容
46
+ */
47
+ private formatContent;
48
+ /**
49
+ * 写入文件
50
+ */
51
+ writeToFile(result: ExtractResult, outputPath: string): Promise<void>;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=style-command.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-command.service.d.ts","sourceRoot":"","sources":["../../src/services/style-command.service.ts"],"names":[],"mappings":"AAGA,UAAU,WAAW;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CAC7B;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,SAAS;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,WAAW,CAAC;IACxB,UAAU,EAAE,WAAW,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAmC1F;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAmBzD;;OAEG;YACW,cAAc;IA2B5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAK5E"}
@@ -0,0 +1,113 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ /**
4
+ * Style 命令服务
5
+ */
6
+ export class StyleCommandService {
7
+ /**
8
+ * 从 JSONL 文件提取章节内容
9
+ */
10
+ async extractFromJsonl(jsonlPath, options) {
11
+ // 读取并解析 JSONL 文件
12
+ const chapters = await this.parseJsonlFile(jsonlPath);
13
+ if (chapters.length === 0) {
14
+ throw new Error('JSONL 文件为空或格式错误');
15
+ }
16
+ // 选择章节
17
+ let selectedChapters;
18
+ if (options.random) {
19
+ // 随机选择
20
+ selectedChapters = this.randomSelect(chapters, options.count);
21
+ }
22
+ else {
23
+ // 从起始章节开始连续选择
24
+ const startIdx = Math.max(0, options.start - 1);
25
+ const endIdx = Math.min(chapters.length, startIdx + options.count);
26
+ selectedChapters = chapters.slice(startIdx, endIdx);
27
+ }
28
+ if (selectedChapters.length === 0) {
29
+ throw new Error(`没有找到符合条件的章节(起始: ${options.start}, 数量: ${options.count})`);
30
+ }
31
+ // 生成内容
32
+ const content = this.formatContent(selectedChapters, options.format);
33
+ return {
34
+ content,
35
+ chapterCount: selectedChapters.length,
36
+ totalWords: selectedChapters.reduce((sum, ch) => sum + ch.chapter_length, 0),
37
+ };
38
+ }
39
+ /**
40
+ * 获取 JSONL 文件信息
41
+ */
42
+ async getJsonlInfo(jsonlPath) {
43
+ const chapters = await this.parseJsonlFile(jsonlPath);
44
+ if (chapters.length === 0) {
45
+ throw new Error('JSONL 文件为空或格式错误');
46
+ }
47
+ const totalWords = chapters.reduce((sum, ch) => sum + ch.chapter_length, 0);
48
+ const sortedByLength = [...chapters].sort((a, b) => a.chapter_length - b.chapter_length);
49
+ return {
50
+ totalChapters: chapters.length,
51
+ totalWords,
52
+ avgWordsPerChapter: Math.round(totalWords / chapters.length),
53
+ minChapter: sortedByLength[0],
54
+ maxChapter: sortedByLength[sortedByLength.length - 1],
55
+ };
56
+ }
57
+ /**
58
+ * 解析 JSONL 文件
59
+ */
60
+ async parseJsonlFile(jsonlPath) {
61
+ const content = await fs.readFile(jsonlPath, 'utf-8');
62
+ const lines = content.split('\n').filter(line => line.trim());
63
+ const chapters = [];
64
+ for (const line of lines) {
65
+ try {
66
+ const data = JSON.parse(line);
67
+ // 验证数据格式
68
+ if (typeof data.chapter_id === 'number' &&
69
+ typeof data.chapter === 'string' &&
70
+ typeof data.chapter_length === 'number') {
71
+ chapters.push(data);
72
+ }
73
+ }
74
+ catch (error) {
75
+ // 跳过无效行
76
+ continue;
77
+ }
78
+ }
79
+ // 按 chapter_id 排序
80
+ return chapters.sort((a, b) => a.chapter_id - b.chapter_id);
81
+ }
82
+ /**
83
+ * 随机选择章节
84
+ */
85
+ randomSelect(chapters, count) {
86
+ const shuffled = [...chapters].sort(() => Math.random() - 0.5);
87
+ return shuffled.slice(0, Math.min(count, chapters.length));
88
+ }
89
+ /**
90
+ * 格式化内容
91
+ */
92
+ formatContent(chapters, format) {
93
+ if (format === 'markdown') {
94
+ // Markdown 格式:带章节标题
95
+ return chapters
96
+ .map(ch => `## 第${ch.chapter_id}章\n\n${ch.chapter}`)
97
+ .join('\n\n---\n\n');
98
+ }
99
+ else {
100
+ // 纯文本格式:直接拼接
101
+ return chapters.map(ch => ch.chapter).join('\n\n');
102
+ }
103
+ }
104
+ /**
105
+ * 写入文件
106
+ */
107
+ async writeToFile(result, outputPath) {
108
+ const dir = path.dirname(outputPath);
109
+ await fs.mkdir(dir, { recursive: true });
110
+ await fs.writeFile(outputPath, result.content, 'utf-8');
111
+ }
112
+ }
113
+ //# sourceMappingURL=style-command.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-command.service.js","sourceRoot":"","sources":["../../src/services/style-command.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dayinxisheng/novel-tools",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "小说创作辅助工具集 - TypeScript 实现",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -58,5 +58,8 @@
58
58
  "dist",
59
59
  "README.md",
60
60
  "CHANGELOG.md"
61
- ]
61
+ ],
62
+ "publishConfig": {
63
+ "access": "public"
64
+ }
62
65
  }