@actalk/inkos-core 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.
Files changed (89) hide show
  1. package/dist/__tests__/models.test.d.ts +2 -0
  2. package/dist/__tests__/models.test.d.ts.map +1 -0
  3. package/dist/__tests__/models.test.js +328 -0
  4. package/dist/__tests__/models.test.js.map +1 -0
  5. package/dist/__tests__/state-manager.test.d.ts +2 -0
  6. package/dist/__tests__/state-manager.test.d.ts.map +1 -0
  7. package/dist/__tests__/state-manager.test.js +264 -0
  8. package/dist/__tests__/state-manager.test.js.map +1 -0
  9. package/dist/__tests__/writer-parser.test.d.ts +2 -0
  10. package/dist/__tests__/writer-parser.test.d.ts.map +1 -0
  11. package/dist/__tests__/writer-parser.test.js +183 -0
  12. package/dist/__tests__/writer-parser.test.js.map +1 -0
  13. package/dist/agents/architect.d.ts +16 -0
  14. package/dist/agents/architect.d.ts.map +1 -0
  15. package/dist/agents/architect.js +85 -0
  16. package/dist/agents/architect.js.map +1 -0
  17. package/dist/agents/base.d.ts +18 -0
  18. package/dist/agents/base.d.ts.map +1 -0
  19. package/dist/agents/base.js +11 -0
  20. package/dist/agents/base.js.map +1 -0
  21. package/dist/agents/continuity.d.ts +19 -0
  22. package/dist/agents/continuity.d.ts.map +1 -0
  23. package/dist/agents/continuity.js +114 -0
  24. package/dist/agents/continuity.js.map +1 -0
  25. package/dist/agents/radar.d.ts +21 -0
  26. package/dist/agents/radar.d.ts.map +1 -0
  27. package/dist/agents/radar.js +60 -0
  28. package/dist/agents/radar.js.map +1 -0
  29. package/dist/agents/reviser.d.ts +17 -0
  30. package/dist/agents/reviser.d.ts.map +1 -0
  31. package/dist/agents/reviser.js +99 -0
  32. package/dist/agents/reviser.js.map +1 -0
  33. package/dist/agents/writer.d.ts +30 -0
  34. package/dist/agents/writer.d.ts.map +1 -0
  35. package/dist/agents/writer.js +284 -0
  36. package/dist/agents/writer.js.map +1 -0
  37. package/dist/index.d.ts +19 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +24 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/llm/provider.d.ts +20 -0
  42. package/dist/llm/provider.d.ts.map +1 -0
  43. package/dist/llm/provider.js +41 -0
  44. package/dist/llm/provider.js.map +1 -0
  45. package/dist/models/book.d.ts +40 -0
  46. package/dist/models/book.d.ts.map +1 -0
  47. package/dist/models/book.js +32 -0
  48. package/dist/models/book.js.map +1 -0
  49. package/dist/models/chapter.d.ts +33 -0
  50. package/dist/models/chapter.d.ts.map +1 -0
  51. package/dist/models/chapter.js +25 -0
  52. package/dist/models/chapter.js.map +1 -0
  53. package/dist/models/project.d.ts +189 -0
  54. package/dist/models/project.d.ts.map +1 -0
  55. package/dist/models/project.js +44 -0
  56. package/dist/models/project.js.map +1 -0
  57. package/dist/models/state.d.ts +48 -0
  58. package/dist/models/state.d.ts.map +1 -0
  59. package/dist/models/state.js +6 -0
  60. package/dist/models/state.js.map +1 -0
  61. package/dist/notify/dispatcher.d.ts +7 -0
  62. package/dist/notify/dispatcher.d.ts.map +1 -0
  63. package/dist/notify/dispatcher.js +27 -0
  64. package/dist/notify/dispatcher.js.map +1 -0
  65. package/dist/notify/feishu.d.ts +5 -0
  66. package/dist/notify/feishu.d.ts.map +1 -0
  67. package/dist/notify/feishu.js +26 -0
  68. package/dist/notify/feishu.js.map +1 -0
  69. package/dist/notify/telegram.d.ts +6 -0
  70. package/dist/notify/telegram.d.ts.map +1 -0
  71. package/dist/notify/telegram.js +17 -0
  72. package/dist/notify/telegram.js.map +1 -0
  73. package/dist/notify/wechat-work.d.ts +5 -0
  74. package/dist/notify/wechat-work.d.ts.map +1 -0
  75. package/dist/notify/wechat-work.js +15 -0
  76. package/dist/notify/wechat-work.js.map +1 -0
  77. package/dist/pipeline/runner.d.ts +30 -0
  78. package/dist/pipeline/runner.d.ts.map +1 -0
  79. package/dist/pipeline/runner.js +141 -0
  80. package/dist/pipeline/runner.js.map +1 -0
  81. package/dist/pipeline/scheduler.d.ts +24 -0
  82. package/dist/pipeline/scheduler.d.ts.map +1 -0
  83. package/dist/pipeline/scheduler.js +102 -0
  84. package/dist/pipeline/scheduler.js.map +1 -0
  85. package/dist/state/manager.d.ts +20 -0
  86. package/dist/state/manager.d.ts.map +1 -0
  87. package/dist/state/manager.js +128 -0
  88. package/dist/state/manager.js.map +1 -0
  89. package/package.json +35 -0
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { WriterAgent } from "../agents/writer.js";
3
+ /**
4
+ * WriterAgent.parseOutput is private, so we access it via prototype to test
5
+ * the extraction logic directly without needing to mock the full LLM pipeline.
6
+ */
7
+ function callParseOutput(chapterNumber, content) {
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ const proto = WriterAgent.prototype;
10
+ return proto.parseOutput.call(null, chapterNumber, content);
11
+ }
12
+ // ---------------------------------------------------------------------------
13
+ // Full tagged output
14
+ // ---------------------------------------------------------------------------
15
+ describe("WriterAgent parseOutput", () => {
16
+ const fullOutput = [
17
+ "=== PRE_WRITE_CHECK ===",
18
+ "| 检查项 | 本章记录 | 备注 |",
19
+ "|--------|----------|------|",
20
+ "| 上下文范围 | 第1章 | |",
21
+ "",
22
+ "=== CHAPTER_TITLE ===",
23
+ "吞天之始",
24
+ "",
25
+ "=== CHAPTER_CONTENT ===",
26
+ "陈风站在悬崖边,俯视着脚下的万丈深渊。",
27
+ "一股强烈的吸力从深渊中传来,仿佛有什么东西在召唤他。",
28
+ "",
29
+ "=== POST_SETTLEMENT ===",
30
+ "| 结算项 | 本章记录 | 备注 |",
31
+ "|--------|----------|------|",
32
+ "| 资源账本 | 期初0 / 增量+100 / 期末100 | |",
33
+ "",
34
+ "=== UPDATED_STATE ===",
35
+ "# 状态卡",
36
+ "| 字段 | 值 |",
37
+ "|------|-----|",
38
+ "| 章节 | 1 |",
39
+ "",
40
+ "=== UPDATED_LEDGER ===",
41
+ "# 资源账本",
42
+ "| 章节 | 期初 | 来源 | 增量 | 期末 |",
43
+ "|------|------|------|------|------|",
44
+ "| 1 | 0 | 深渊果实 | +100 | 100 |",
45
+ "",
46
+ "=== UPDATED_HOOKS ===",
47
+ "# 伏笔池",
48
+ "| ID | 伏笔 | 状态 |",
49
+ "|-----|------|------|",
50
+ "| H001 | 深渊之物 | open |",
51
+ ].join("\n");
52
+ it("extracts all sections from a complete tagged output", () => {
53
+ const result = callParseOutput(1, fullOutput);
54
+ expect(result.chapterNumber).toBe(1);
55
+ expect(result.title).toBe("吞天之始");
56
+ expect(result.content).toContain("陈风站在悬崖边");
57
+ expect(result.content).toContain("召唤他");
58
+ expect(result.preWriteCheck).toContain("检查项");
59
+ expect(result.postSettlement).toContain("资源账本");
60
+ expect(result.updatedState).toContain("状态卡");
61
+ expect(result.updatedLedger).toContain("深渊果实");
62
+ expect(result.updatedHooks).toContain("H001");
63
+ });
64
+ it("calculates wordCount as the length of chapter content", () => {
65
+ const result = callParseOutput(1, fullOutput);
66
+ const expectedContent = "陈风站在悬崖边,俯视着脚下的万丈深渊。\n一股强烈的吸力从深渊中传来,仿佛有什么东西在召唤他。";
67
+ expect(result.wordCount).toBe(expectedContent.length);
68
+ });
69
+ // -------------------------------------------------------------------------
70
+ // Missing sections
71
+ // -------------------------------------------------------------------------
72
+ it("returns default title when CHAPTER_TITLE is missing", () => {
73
+ const output = [
74
+ "=== CHAPTER_CONTENT ===",
75
+ "Some content here.",
76
+ ].join("\n");
77
+ const result = callParseOutput(42, output);
78
+ expect(result.title).toBe("第42章");
79
+ });
80
+ it("returns empty content when CHAPTER_CONTENT is missing", () => {
81
+ const output = [
82
+ "=== CHAPTER_TITLE ===",
83
+ "A Title",
84
+ ].join("\n");
85
+ const result = callParseOutput(1, output);
86
+ expect(result.content).toBe("");
87
+ expect(result.wordCount).toBe(0);
88
+ });
89
+ it("returns fallback strings for missing state sections", () => {
90
+ const output = [
91
+ "=== CHAPTER_TITLE ===",
92
+ "Title",
93
+ "",
94
+ "=== CHAPTER_CONTENT ===",
95
+ "Content.",
96
+ ].join("\n");
97
+ const result = callParseOutput(1, output);
98
+ expect(result.updatedState).toBe("(状态卡未更新)");
99
+ expect(result.updatedLedger).toBe("(账本未更新)");
100
+ expect(result.updatedHooks).toBe("(伏笔池未更新)");
101
+ });
102
+ it("returns empty string for missing PRE_WRITE_CHECK", () => {
103
+ const output = [
104
+ "=== CHAPTER_TITLE ===",
105
+ "Title",
106
+ "",
107
+ "=== CHAPTER_CONTENT ===",
108
+ "Content.",
109
+ ].join("\n");
110
+ const result = callParseOutput(1, output);
111
+ expect(result.preWriteCheck).toBe("");
112
+ });
113
+ it("returns empty string for missing POST_SETTLEMENT", () => {
114
+ const output = [
115
+ "=== CHAPTER_TITLE ===",
116
+ "Title",
117
+ "",
118
+ "=== CHAPTER_CONTENT ===",
119
+ "Content.",
120
+ ].join("\n");
121
+ const result = callParseOutput(1, output);
122
+ expect(result.postSettlement).toBe("");
123
+ });
124
+ // -------------------------------------------------------------------------
125
+ // Edge cases
126
+ // -------------------------------------------------------------------------
127
+ it("handles completely empty input", () => {
128
+ const result = callParseOutput(1, "");
129
+ expect(result.chapterNumber).toBe(1);
130
+ expect(result.title).toBe("第1章");
131
+ expect(result.content).toBe("");
132
+ expect(result.wordCount).toBe(0);
133
+ expect(result.updatedState).toBe("(状态卡未更新)");
134
+ expect(result.updatedLedger).toBe("(账本未更新)");
135
+ expect(result.updatedHooks).toBe("(伏笔池未更新)");
136
+ });
137
+ it("handles content with no tags at all", () => {
138
+ const result = callParseOutput(5, "Just some random text without tags");
139
+ expect(result.title).toBe("第5章");
140
+ expect(result.content).toBe("");
141
+ expect(result.wordCount).toBe(0);
142
+ });
143
+ it("preserves multiline content within a section", () => {
144
+ const output = [
145
+ "=== CHAPTER_CONTENT ===",
146
+ "第一段:这里是开头。",
147
+ "",
148
+ "第二段:这里是中间。",
149
+ "",
150
+ "第三段:这里是结尾。",
151
+ "",
152
+ "=== POST_SETTLEMENT ===",
153
+ "No settlement.",
154
+ ].join("\n");
155
+ const result = callParseOutput(1, output);
156
+ expect(result.content).toContain("第一段");
157
+ expect(result.content).toContain("第二段");
158
+ expect(result.content).toContain("第三段");
159
+ });
160
+ it("trims whitespace from extracted section values", () => {
161
+ const output = [
162
+ "=== CHAPTER_TITLE ===",
163
+ " 吞天之始 ",
164
+ "",
165
+ "=== CHAPTER_CONTENT ===",
166
+ " 内容 ",
167
+ ].join("\n");
168
+ const result = callParseOutput(1, output);
169
+ expect(result.title).toBe("吞天之始");
170
+ expect(result.content).toBe("内容");
171
+ });
172
+ it("correctly counts Chinese characters in wordCount", () => {
173
+ const chineseContent = "这是一段测试文本,包含二十个中文字符加上标点符号。";
174
+ const output = [
175
+ "=== CHAPTER_CONTENT ===",
176
+ chineseContent,
177
+ ].join("\n");
178
+ const result = callParseOutput(1, output);
179
+ // wordCount is content.length which counts each character (including punctuation)
180
+ expect(result.wordCount).toBe(chineseContent.length);
181
+ });
182
+ });
183
+ //# sourceMappingURL=writer-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer-parser.test.js","sourceRoot":"","sources":["../../src/__tests__/writer-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { BaseAgent } from "./base.js";
2
+ import type { BookConfig } from "../models/book.js";
3
+ export interface ArchitectOutput {
4
+ readonly storyBible: string;
5
+ readonly volumeOutline: string;
6
+ readonly styleGuide: string;
7
+ readonly currentState: string;
8
+ readonly pendingHooks: string;
9
+ }
10
+ export declare class ArchitectAgent extends BaseAgent {
11
+ get name(): string;
12
+ generateFoundation(book: BookConfig): Promise<ArchitectOutput>;
13
+ writeFoundationFiles(bookDir: string, output: ArchitectOutput): Promise<void>;
14
+ private parseSections;
15
+ }
16
+ //# sourceMappingURL=architect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architect.d.ts","sourceRoot":"","sources":["../../src/agents/architect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,cAAe,SAAQ,SAAS;IAC3C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC;IAqD9D,oBAAoB,CACxB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC;IA8BhB,OAAO,CAAC,aAAa;CAiBtB"}
@@ -0,0 +1,85 @@
1
+ import { BaseAgent } from "./base.js";
2
+ import { writeFile, mkdir } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ export class ArchitectAgent extends BaseAgent {
5
+ get name() {
6
+ return "architect";
7
+ }
8
+ async generateFoundation(book) {
9
+ const systemPrompt = `你是一个专业的网络小说架构师。你的任务是为一本新小说生成完整的基础设定。
10
+
11
+ 要求:
12
+ - 平台:${book.platform}
13
+ - 题材:${book.genre}
14
+ - 目标章数:${book.targetChapters}章
15
+ - 每章字数:${book.chapterWordCount}字
16
+
17
+ 你需要生成以下内容,每个部分用 === SECTION: <name> === 分隔:
18
+
19
+ === SECTION: story_bible ===
20
+ 世界观设定、势力分布、核心规则体系、主角设定(身份/金手指/性格底色)、重要配角
21
+
22
+ === SECTION: volume_outline ===
23
+ 卷纲规划,每卷包含:卷名、章节范围、核心冲突、关键转折、收益目标
24
+
25
+ === SECTION: style_guide ===
26
+ 文风锁定:叙事视角、语言风格、禁忌清单、爽点回路设计、节奏规则
27
+
28
+ === SECTION: current_state ===
29
+ 初始状态卡(第0章),包含:
30
+ | 字段 | 值 |
31
+ |------|-----|
32
+ | 当前章节 | 0 |
33
+ | 当前位置 | (起始地点) |
34
+ | 主角状态 | (初始状态) |
35
+ | 当前目标 | (第一个目标) |
36
+ | 当前限制 | (初始限制) |
37
+ | 当前敌我 | (初始关系) |
38
+ | 当前冲突 | (第一个冲突) |
39
+
40
+ === SECTION: pending_hooks ===
41
+ 初始伏笔池(Markdown表格):
42
+ | hook_id | 起始章节 | 类型 | 状态 | 最近推进 | 预期回收 | 备注 |
43
+
44
+ 生成内容必须:
45
+ 1. 符合${book.platform}平台口味
46
+ 2. 主角杀伐果断,不圣母
47
+ 3. 有明确的数值/资源体系可追踪
48
+ 4. 伏笔前后呼应,不留悬空线`;
49
+ const response = await this.chat([
50
+ { role: "system", content: systemPrompt },
51
+ {
52
+ role: "user",
53
+ content: `请为标题为"${book.title}"的${book.genre}小说生成完整基础设定。`,
54
+ },
55
+ ], { maxTokens: 16384, temperature: 0.8 });
56
+ return this.parseSections(response.content);
57
+ }
58
+ async writeFoundationFiles(bookDir, output) {
59
+ const storyDir = join(bookDir, "story");
60
+ await mkdir(storyDir, { recursive: true });
61
+ await Promise.all([
62
+ writeFile(join(storyDir, "story_bible.md"), output.storyBible, "utf-8"),
63
+ writeFile(join(storyDir, "volume_outline.md"), output.volumeOutline, "utf-8"),
64
+ writeFile(join(storyDir, "style_guide.md"), output.styleGuide, "utf-8"),
65
+ writeFile(join(storyDir, "current_state.md"), output.currentState, "utf-8"),
66
+ writeFile(join(storyDir, "pending_hooks.md"), output.pendingHooks, "utf-8"),
67
+ writeFile(join(storyDir, "particle_ledger.md"), "# 资源账本\n\n| 章节 | 期初值 | 来源 | 完整度 | 增量 | 期末值 | 依据 |\n|------|--------|------|--------|------|--------|------|\n| 0 | 0 | 初始化 | - | 0 | 0 | 开书初始 |\n", "utf-8"),
68
+ ]);
69
+ }
70
+ parseSections(content) {
71
+ const extract = (name) => {
72
+ const regex = new RegExp(`=== SECTION: ${name} ===\\s*([\\s\\S]*?)(?==== SECTION:|$)`);
73
+ const match = content.match(regex);
74
+ return match?.[1]?.trim() ?? `[${name} 生成失败,需要重新生成]`;
75
+ };
76
+ return {
77
+ storyBible: extract("story_bible"),
78
+ volumeOutline: extract("volume_outline"),
79
+ styleGuide: extract("style_guide"),
80
+ currentState: extract("current_state"),
81
+ pendingHooks: extract("pending_hooks"),
82
+ };
83
+ }
84
+ }
85
+ //# sourceMappingURL=architect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architect.js","sourceRoot":"","sources":["../../src/agents/architect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAY,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C,IAAI,IAAI;QACN,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,IAAgB;QACvC,MAAM,YAAY,GAAG;;;OAGlB,IAAI,CAAC,QAAQ;OACb,IAAI,CAAC,KAAK;SACR,IAAI,CAAC,cAAc;SACnB,IAAI,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BvB,IAAI,CAAC,QAAQ;;;gBAGJ,CAAC;QAEb,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC;YAC/B,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;YACzC;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,SAAS,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,aAAa;aACzD;SACF,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QAE3C,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,OAAe,EACf,MAAuB;QAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3C,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC;YACvE,SAAS,CACP,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,EACnC,MAAM,CAAC,aAAa,EACpB,OAAO,CACR;YACD,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC;YACvE,SAAS,CACP,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EAClC,MAAM,CAAC,YAAY,EACnB,OAAO,CACR;YACD,SAAS,CACP,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EAClC,MAAM,CAAC,YAAY,EACnB,OAAO,CACR;YACD,SAAS,CACP,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,EACpC,mJAAmJ,EACnJ,OAAO,CACR;SACF,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,OAAe;QACnC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE;YACvC,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,gBAAgB,IAAI,wCAAwC,CAC7D,CAAC;YACF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,eAAe,CAAC;QACvD,CAAC,CAAC;QAEF,OAAO;YACL,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC;YAClC,aAAa,EAAE,OAAO,CAAC,gBAAgB,CAAC;YACxC,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC;YAClC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC;YACtC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC;SACvC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type OpenAI from "openai";
2
+ import type { LLMMessage, LLMResponse } from "../llm/provider.js";
3
+ export interface AgentContext {
4
+ readonly client: OpenAI;
5
+ readonly model: string;
6
+ readonly projectRoot: string;
7
+ readonly bookId?: string;
8
+ }
9
+ export declare abstract class BaseAgent {
10
+ protected readonly ctx: AgentContext;
11
+ constructor(ctx: AgentContext);
12
+ protected chat(messages: ReadonlyArray<LLMMessage>, options?: {
13
+ readonly temperature?: number;
14
+ readonly maxTokens?: number;
15
+ }): Promise<LLMResponse>;
16
+ abstract get name(): string;
17
+ }
18
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/agents/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGlE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8BAAsB,SAAS;IAC7B,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,YAAY,CAAC;gBAEzB,GAAG,EAAE,YAAY;cAIb,IAAI,CAClB,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EACnC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACvE,OAAO,CAAC,WAAW,CAAC;IAIvB,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,11 @@
1
+ import { chatCompletion } from "../llm/provider.js";
2
+ export class BaseAgent {
3
+ ctx;
4
+ constructor(ctx) {
5
+ this.ctx = ctx;
6
+ }
7
+ async chat(messages, options) {
8
+ return chatCompletion(this.ctx.client, this.ctx.model, messages, options);
9
+ }
10
+ }
11
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/agents/base.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AASpD,MAAM,OAAgB,SAAS;IACV,GAAG,CAAe;IAErC,YAAY,GAAiB;QAC3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAES,KAAK,CAAC,IAAI,CAClB,QAAmC,EACnC,OAAwE;QAExE,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;CAGF"}
@@ -0,0 +1,19 @@
1
+ import { BaseAgent } from "./base.js";
2
+ export interface AuditResult {
3
+ readonly passed: boolean;
4
+ readonly issues: ReadonlyArray<AuditIssue>;
5
+ readonly summary: string;
6
+ }
7
+ export interface AuditIssue {
8
+ readonly severity: "critical" | "warning" | "info";
9
+ readonly category: string;
10
+ readonly description: string;
11
+ readonly suggestion: string;
12
+ }
13
+ export declare class ContinuityAuditor extends BaseAgent {
14
+ get name(): string;
15
+ auditChapter(bookDir: string, chapterContent: string, chapterNumber: number): Promise<AuditResult>;
16
+ private parseAuditResult;
17
+ private readFileSafe;
18
+ }
19
+ //# sourceMappingURL=continuity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"continuity.d.ts","sourceRoot":"","sources":["../../src/agents/continuity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,SAAS;IAC9C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,CAAC;IAkEvB,OAAO,CAAC,gBAAgB;YAwCV,YAAY;CAO3B"}
@@ -0,0 +1,114 @@
1
+ import { BaseAgent } from "./base.js";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ export class ContinuityAuditor extends BaseAgent {
5
+ get name() {
6
+ return "continuity-auditor";
7
+ }
8
+ async auditChapter(bookDir, chapterContent, chapterNumber) {
9
+ const [currentState, ledger, hooks, styleGuide] = await Promise.all([
10
+ this.readFileSafe(join(bookDir, "story/current_state.md")),
11
+ this.readFileSafe(join(bookDir, "story/particle_ledger.md")),
12
+ this.readFileSafe(join(bookDir, "story/pending_hooks.md")),
13
+ this.readFileSafe(join(bookDir, "story/style_guide.md")),
14
+ ]);
15
+ const systemPrompt = `你是一位严格的网络小说审稿编辑。你的任务是对章节进行连续性、一致性和质量审查。
16
+
17
+ 审查维度:
18
+ 1. OOC检查:角色行为是否符合已确立人设
19
+ 2. 时间线检查:时间/地点是否连贯
20
+ 3. 设定冲突:是否违反已确立的世界观规则
21
+ 4. 战力崩坏:是否出现不合理的实力变化
22
+ 5. 数值检查:资源/数值变动是否与账本一致
23
+ 6. 伏笔检查:是否有遗漏或矛盾的伏笔
24
+ 7. 节奏检查:是否拖沓或跳跃
25
+ 8. 文风检查:是否偏离风格指南
26
+ 9. 信息越界:角色是否知道了不该知道的信息
27
+ 10. 词汇疲劳:是否有过度重复的表达
28
+
29
+ 输出格式必须为 JSON:
30
+ {
31
+ "passed": true/false,
32
+ "issues": [
33
+ {
34
+ "severity": "critical|warning|info",
35
+ "category": "审查维度名称",
36
+ "description": "具体问题描述",
37
+ "suggestion": "修改建议"
38
+ }
39
+ ],
40
+ "summary": "一句话总结审查结论"
41
+ }
42
+
43
+ 只有当存在 critical 级别问题时,passed 才为 false。`;
44
+ const userPrompt = `请审查第${chapterNumber}章。
45
+
46
+ ## 当前状态卡
47
+ ${currentState}
48
+
49
+ ## 资源账本
50
+ ${ledger}
51
+
52
+ ## 伏笔池
53
+ ${hooks}
54
+
55
+ ## 文风指南
56
+ ${styleGuide}
57
+
58
+ ## 待审章节内容
59
+ ${chapterContent}`;
60
+ const response = await this.chat([
61
+ { role: "system", content: systemPrompt },
62
+ { role: "user", content: userPrompt },
63
+ ], { temperature: 0.3, maxTokens: 4096 });
64
+ return this.parseAuditResult(response.content);
65
+ }
66
+ parseAuditResult(content) {
67
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
68
+ if (!jsonMatch) {
69
+ return {
70
+ passed: false,
71
+ issues: [
72
+ {
73
+ severity: "critical",
74
+ category: "系统错误",
75
+ description: "审稿输出格式异常,无法解析",
76
+ suggestion: "重新运行审稿",
77
+ },
78
+ ],
79
+ summary: "审稿输出解析失败",
80
+ };
81
+ }
82
+ try {
83
+ const parsed = JSON.parse(jsonMatch[0]);
84
+ return {
85
+ passed: Boolean(parsed.passed),
86
+ issues: Array.isArray(parsed.issues) ? parsed.issues : [],
87
+ summary: String(parsed.summary ?? ""),
88
+ };
89
+ }
90
+ catch {
91
+ return {
92
+ passed: false,
93
+ issues: [
94
+ {
95
+ severity: "critical",
96
+ category: "系统错误",
97
+ description: "审稿 JSON 解析失败",
98
+ suggestion: "重新运行审稿",
99
+ },
100
+ ],
101
+ summary: "审稿 JSON 解析失败",
102
+ };
103
+ }
104
+ }
105
+ async readFileSafe(path) {
106
+ try {
107
+ return await readFile(path, "utf-8");
108
+ }
109
+ catch {
110
+ return "(文件不存在)";
111
+ }
112
+ }
113
+ }
114
+ //# sourceMappingURL=continuity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"continuity.js","sourceRoot":"","sources":["../../src/agents/continuity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { BaseAgent } from "./base.js";
2
+ import type { Platform, Genre } from "../models/book.js";
3
+ export interface RadarResult {
4
+ readonly recommendations: ReadonlyArray<RadarRecommendation>;
5
+ readonly marketSummary: string;
6
+ readonly timestamp: string;
7
+ }
8
+ export interface RadarRecommendation {
9
+ readonly platform: Platform;
10
+ readonly genre: Genre;
11
+ readonly concept: string;
12
+ readonly confidence: number;
13
+ readonly reasoning: string;
14
+ readonly benchmarkTitles: ReadonlyArray<string>;
15
+ }
16
+ export declare class RadarAgent extends BaseAgent {
17
+ get name(): string;
18
+ scan(platforms: ReadonlyArray<Platform>): Promise<RadarResult>;
19
+ private parseResult;
20
+ }
21
+ //# sourceMappingURL=radar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/agents/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC7D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACjD;AAED,qBAAa,UAAW,SAAQ,SAAS;IACvC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IA0CpE,OAAO,CAAC,WAAW;CAiBpB"}
@@ -0,0 +1,60 @@
1
+ import { BaseAgent } from "./base.js";
2
+ export class RadarAgent extends BaseAgent {
3
+ get name() {
4
+ return "radar";
5
+ }
6
+ async scan(platforms) {
7
+ const systemPrompt = `你是一个专业的网络小说市场分析师。你的任务是分析当前网文市场热度,推荐有潜力的题材和概念。
8
+
9
+ 你需要基于以下平台的当前趋势进行分析:${platforms.join("、")}
10
+
11
+ 分析维度:
12
+ 1. 当前热门题材和标签
13
+ 2. 高追读/收藏的作品类型
14
+ 3. 市场空白和机会点
15
+ 4. 风险提示(过度饱和的题材)
16
+
17
+ 输出格式必须为 JSON:
18
+ {
19
+ "recommendations": [
20
+ {
21
+ "platform": "平台名",
22
+ "genre": "题材类型",
23
+ "concept": "一句话概念描述",
24
+ "confidence": 0.0-1.0,
25
+ "reasoning": "推荐理由",
26
+ "benchmarkTitles": ["对标书1", "对标书2"]
27
+ }
28
+ ],
29
+ "marketSummary": "整体市场概述"
30
+ }
31
+
32
+ 推荐数量:3-5个,按 confidence 降序排列。`;
33
+ const response = await this.chat([
34
+ { role: "system", content: systemPrompt },
35
+ {
36
+ role: "user",
37
+ content: `请分析当前${platforms.join("、")}平台的网文市场热度,给出开书建议。`,
38
+ },
39
+ ], { temperature: 0.6, maxTokens: 4096 });
40
+ return this.parseResult(response.content);
41
+ }
42
+ parseResult(content) {
43
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
44
+ if (!jsonMatch) {
45
+ throw new Error("Radar output format error: no JSON found");
46
+ }
47
+ try {
48
+ const parsed = JSON.parse(jsonMatch[0]);
49
+ return {
50
+ recommendations: parsed.recommendations ?? [],
51
+ marketSummary: parsed.marketSummary ?? "",
52
+ timestamp: new Date().toISOString(),
53
+ };
54
+ }
55
+ catch (e) {
56
+ throw new Error(`Radar JSON parse error: ${e}`);
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=radar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar.js","sourceRoot":"","sources":["../../src/agents/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAkBtC,MAAM,OAAO,UAAW,SAAQ,SAAS;IACvC,IAAI,IAAI;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAkC;QAC3C,MAAM,YAAY,GAAG;;qBAEJ,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;6BAuBX,CAAC;QAE1B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAC9B;YACE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;YACzC;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,QAAQ,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,mBAAmB;aACxD;SACF,EACD,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CACtC,CAAC;QAEF,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEO,WAAW,CAAC,OAAe;QACjC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC/C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,OAAO;gBACL,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,EAAE;gBAC7C,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;gBACzC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import { BaseAgent } from "./base.js";
2
+ import type { AuditIssue } from "./continuity.js";
3
+ export interface ReviseOutput {
4
+ readonly revisedContent: string;
5
+ readonly wordCount: number;
6
+ readonly fixedIssues: ReadonlyArray<string>;
7
+ readonly updatedState: string;
8
+ readonly updatedLedger: string;
9
+ readonly updatedHooks: string;
10
+ }
11
+ export declare class ReviserAgent extends BaseAgent {
12
+ get name(): string;
13
+ reviseChapter(bookDir: string, chapterContent: string, chapterNumber: number, issues: ReadonlyArray<AuditIssue>): Promise<ReviseOutput>;
14
+ private parseOutput;
15
+ private readFileSafe;
16
+ }
17
+ //# sourceMappingURL=reviser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviser.d.ts","sourceRoot":"","sources":["../../src/agents/reviser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAIlD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,YAAa,SAAQ,SAAS;IACzC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAEK,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,GAChC,OAAO,CAAC,YAAY,CAAC;IAuExB,OAAO,CAAC,WAAW;YAyBL,YAAY;CAO3B"}