dsh-novel 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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/cordis.patch.yml +3 -0
  4. package/lib/client.js +1560 -0
  5. package/lib/client.js.map +1 -0
  6. package/lib/index.js +1436 -0
  7. package/lib/index.js.map +1 -0
  8. package/lib/types/client/NovelWorkspaceView.d.ts +3 -0
  9. package/lib/types/client/entity-client.d.ts +17 -0
  10. package/lib/types/client/index.d.ts +3 -0
  11. package/lib/types/client/noveel-shapes.d.ts +1 -0
  12. package/lib/types/client/novel-api.d.ts +1 -0
  13. package/lib/types/client/section-icons.d.ts +5 -0
  14. package/lib/types/client/sections/ChapterSection.d.ts +2 -0
  15. package/lib/types/client/sections/LevelSection.d.ts +2 -0
  16. package/lib/types/client/sections/ListDetailSection.d.ts +13 -0
  17. package/lib/types/client/sections/OutlineSection.d.ts +2 -0
  18. package/lib/types/client/sections/OverviewSection.d.ts +2 -0
  19. package/lib/types/client/sections/SkillSection.d.ts +3 -0
  20. package/lib/types/client/sections/TimelineSection.d.ts +2 -0
  21. package/lib/types/client/sections/WorldSection.d.ts +2 -0
  22. package/lib/types/client/sections/owned-sections.d.ts +4 -0
  23. package/lib/types/client/sections/types.d.ts +14 -0
  24. package/lib/types/client/styles.d.ts +1 -0
  25. package/lib/types/client/ui/EntitySidebar.d.ts +10 -0
  26. package/lib/types/client/ui/RelationPanel.d.ts +6 -0
  27. package/lib/types/client/ui/TemplateRead.d.ts +13 -0
  28. package/lib/types/client/ui/TimelinePanel.d.ts +8 -0
  29. package/lib/types/client/ui/controls.d.ts +22 -0
  30. package/lib/types/client/ui/live-reload.d.ts +2 -0
  31. package/lib/types/index.d.ts +5 -0
  32. package/lib/types/novel/contract.d.ts +2 -0
  33. package/lib/types/novel/defaults.d.ts +66 -0
  34. package/lib/types/novel/domains.d.ts +12 -0
  35. package/lib/types/novel/host-skills.d.ts +58 -0
  36. package/lib/types/novel/http.d.ts +5 -0
  37. package/lib/types/novel/normalize-entity.d.ts +18 -0
  38. package/lib/types/novel/noveel-shapes.d.ts +98 -0
  39. package/lib/types/novel/outline-labels.d.ts +10 -0
  40. package/lib/types/novel/schema.d.ts +3 -0
  41. package/lib/types/novel/seed.d.ts +27 -0
  42. package/lib/types/novel/store.d.ts +96 -0
  43. package/lib/types/novel/template-fields.d.ts +17 -0
  44. package/lib/types/novel/timeline-labels.d.ts +2 -0
  45. package/lib/types/novel/tools.d.ts +3 -0
  46. package/package.json +77 -0
  47. package/seed/skills/chapter//345/216/273AI/345/221/263/344/270/216/350/264/250/346/243/200.md +34 -0
  48. package/seed/skills/chapter//345/257/271/350/257/235/344/270/216/346/203/205/347/273/252.md +52 -0
  49. package/seed/skills/chapter//347/253/240/350/212/202/346/225/260/346/215/256/347/273/264/346/212/244.md +61 -0
  50. package/seed/skills/chapter//347/253/240/350/212/202/350/212/202/345/245/217/344/270/216/345/274/200/345/244/264.md +61 -0
  51. package/seed/skills/chapter//347/253/240/351/246/226/351/222/251/345/255/220.md +40 -0
  52. package/seed/skills/creature//345/274/202/345/205/275/344/270/216/347/201/265/346/244/215.md +11 -0
  53. package/seed/skills/creature//347/224/237/347/211/251/346/241/243/346/241/210/350/246/201/347/264/240.md +13 -0
  54. package/seed/skills/genres//344/273/231/344/276/240/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +32 -0
  55. package/seed/skills/genres//344/273/231/344/276/240/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  56. package/seed/skills/genres//345/216/206/345/217/262/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +32 -0
  57. package/seed/skills/genres//345/216/206/345/217/262/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  58. package/seed/skills/genres//346/202/254/347/226/221/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +33 -0
  59. package/seed/skills/genres//346/202/254/347/226/221/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  60. package/seed/skills/genres//346/234/253/344/270/226/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +33 -0
  61. package/seed/skills/genres//346/234/253/344/270/226/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  62. package/seed/skills/genres//347/216/204/345/271/273/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +32 -0
  63. package/seed/skills/genres//347/216/204/345/271/273/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +22 -0
  64. package/seed/skills/genres//347/247/221/345/271/273/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +33 -0
  65. package/seed/skills/genres//347/247/221/345/271/273/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  66. package/seed/skills/genres//350/250/200/346/203/205/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +31 -0
  67. package/seed/skills/genres//350/250/200/346/203/205/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  68. package/seed/skills/genres//351/203/275/345/270/202/overview//351/242/230/346/235/220/350/247/204/345/210/231.md +32 -0
  69. package/seed/skills/genres//351/203/275/345/270/202/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +21 -0
  70. package/seed/skills/item//346/265/201/350/275/254/344/270/216/345/275/222/345/261/236.md +22 -0
  71. package/seed/skills/item//347/211/251/345/223/201/346/241/243/346/241/210/350/246/201/347/264/240.md +13 -0
  72. package/seed/skills/level//346/210/220/351/225/277/344/270/216/347/210/275/347/202/271.md +44 -0
  73. package/seed/skills/level//350/203/275/345/212/233/344/270/216/344/273/243/344/273/267.md +42 -0
  74. package/seed/skills/outline//345/211/247/346/203/205/351/252/250/346/236/266/346/265/201/346/260/264/347/272/277.md +51 -0
  75. package/seed/skills/outline//347/273/223/346/236/204/344/270/216/345/215/267/347/253/240/346/250/241/346/235/277.md +68 -0
  76. package/seed/skills/outline//351/273/204/351/207/221/344/270/211/347/253/240/344/270/216/351/252/214/346/224/266.md +42 -0
  77. package/seed/skills/overview//345/215/226/347/202/271/344/270/216/345/256/232/344/275/215.md +52 -0
  78. package/seed/skills/overview//345/274/200/344/271/246/347/247/215/345/255/220.md +60 -0
  79. package/seed/skills/overview//346/240/207/351/242/230/345/210/233/344/275/234.md +43 -0
  80. package/seed/skills/review/chapter//347/253/240/350/212/202/345/256/241/346/237/245.md +72 -0
  81. package/seed/skills/review/outline//345/244/247/347/272/262/345/256/241/346/237/245.md +74 -0
  82. package/seed/skills/role//344/272/272/347/211/251/345/241/221/351/200/240.md +52 -0
  83. package/seed/skills/role//345/205/263/347/263/273/344/270/216/351/205/215/350/247/222.md +53 -0
  84. package/seed/skills/role//350/247/222/350/211/262/346/241/243/346/241/210.md +52 -0
  85. package/seed/skills/timeline//344/272/213/344/273/266/350/275/264/350/247/204/345/210/222.md +33 -0
  86. package/seed/skills/timeline//347/212/266/346/200/201/345/220/214/346/255/245.md +41 -0
  87. package/seed/skills/world//344/270/226/347/225/214/350/247/204/345/210/231.md +30 -0
  88. package/seed/skills/world//344/274/217/347/254/224/350/264/246/346/234/254.md +44 -0
  89. package/seed/skills/world//345/212/277/345/212/233/344/270/216/345/234/260/345/233/276.md +52 -0
  90. package/seed/skills/writing-style/da-feng-da-geng-ren/STYLE.md +132 -0
  91. package/seed/skills/writing-style/da-feng-da-geng-ren/meta.json +6 -0
  92. package/seed/skills/writing-style/hei-dao-da-feng/STYLE.md +144 -0
  93. package/seed/skills/writing-style/hei-dao-da-feng/meta.json +6 -0
  94. package/seed/skills/writing-style/hei-dao-xie-huang/STYLE.md +139 -0
  95. package/seed/skills/writing-style/hei-dao-xie-huang/meta.json +6 -0
  96. package/seed/templates//344/273/231/344/276/240.json +1322 -0
  97. package/seed/templates//345/216/206/345/217/262.json +1318 -0
  98. package/seed/templates//346/202/254/347/226/221.json +1318 -0
  99. package/seed/templates//346/234/253/344/270/226.json +1127 -0
  100. package/seed/templates//347/216/204/345/271/273.json +1322 -0
  101. package/seed/templates//347/247/221/345/271/273.json +1322 -0
  102. package/seed/templates//350/250/200/346/203/205.json +1318 -0
  103. package/seed/templates//351/203/275/345/270/202.json +1318 -0
@@ -0,0 +1,98 @@
1
+ export declare const WORLD_KINDS: readonly [{
2
+ readonly value: "universe";
3
+ readonly label: "宇宙";
4
+ }, {
5
+ readonly value: "multiverse";
6
+ readonly label: "多元宇宙";
7
+ }, {
8
+ readonly value: "galaxy";
9
+ readonly label: "星系";
10
+ }, {
11
+ readonly value: "realm";
12
+ readonly label: "界域";
13
+ }, {
14
+ readonly value: "domain";
15
+ readonly label: "域";
16
+ }, {
17
+ readonly value: "plane";
18
+ readonly label: "位面";
19
+ }, {
20
+ readonly value: "planet";
21
+ readonly label: "星球";
22
+ }, {
23
+ readonly value: "continent";
24
+ readonly label: "大陆";
25
+ }, {
26
+ readonly value: "mainland";
27
+ readonly label: "大陆";
28
+ }, {
29
+ readonly value: "region";
30
+ readonly label: "地区";
31
+ }, {
32
+ readonly value: "mountain";
33
+ readonly label: "山脉";
34
+ }, {
35
+ readonly value: "secret_realm";
36
+ readonly label: "秘境/禁地";
37
+ }, {
38
+ readonly value: "country";
39
+ readonly label: "国家";
40
+ }, {
41
+ readonly value: "empire";
42
+ readonly label: "帝国";
43
+ }, {
44
+ readonly value: "kingdom";
45
+ readonly label: "王国";
46
+ }, {
47
+ readonly value: "city";
48
+ readonly label: "城市";
49
+ }, {
50
+ readonly value: "town";
51
+ readonly label: "城镇";
52
+ }, {
53
+ readonly value: "settlement";
54
+ readonly label: "聚落";
55
+ }, {
56
+ readonly value: "faction";
57
+ readonly label: "势力";
58
+ }, {
59
+ readonly value: "sect";
60
+ readonly label: "宗门/门派";
61
+ }, {
62
+ readonly value: "clan";
63
+ readonly label: "家族/氏族";
64
+ }, {
65
+ readonly value: "guild";
66
+ readonly label: "公会";
67
+ }, {
68
+ readonly value: "army";
69
+ readonly label: "军队";
70
+ }, {
71
+ readonly value: "corporation";
72
+ readonly label: "公司/集团";
73
+ }, {
74
+ readonly value: "alliance";
75
+ readonly label: "联盟";
76
+ }, {
77
+ readonly value: "cult";
78
+ readonly label: "教派";
79
+ }, {
80
+ readonly value: "academy";
81
+ readonly label: "学院";
82
+ }, {
83
+ readonly value: "custom";
84
+ readonly label: "其他";
85
+ }];
86
+ export declare function emptyLevelSystem(): {
87
+ name: string;
88
+ category: string;
89
+ description: string;
90
+ levels: {
91
+ name: string;
92
+ subLevels: {
93
+ name: string;
94
+ }[];
95
+ promotionCondition: string;
96
+ abilities: string;
97
+ }[];
98
+ };
@@ -0,0 +1,10 @@
1
+ export declare function asOrdinal(value: unknown): number | undefined;
2
+ export declare function canonicalizeOutlineKind(raw: unknown): 'volume' | 'chapter_segment' | undefined;
3
+ export declare function outlineKindOf(data: Record<string, unknown>): 'volume' | 'chapter_segment';
4
+ export declare function volumeChapterLabel(ordinal: unknown, unit: '卷' | '章', name: string): string;
5
+ export declare function outlineNodeLabel(data: Record<string, unknown>, fallback: string): string;
6
+ export declare function chapterNodeLabel(data: Record<string, unknown>, fallback: string): string;
7
+ export declare function compareOrdinal(a: unknown, b: unknown): number;
8
+ export declare function sortByOrdinalName<T extends {
9
+ name?: string | null;
10
+ }>(items: T[], ordinalOf: (item: T) => unknown): T[];
@@ -0,0 +1,3 @@
1
+ import type { PGlite } from '@electric-sql/pglite';
2
+ /** Create the single-novel schema used inside one workspace PGlite directory. */
3
+ export declare function initNovelSchema(db: PGlite): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import type { PGlite } from '@electric-sql/pglite';
2
+ export declare function seedTemplatesDir(): string;
3
+ export declare function seedSkillsDir(): string;
4
+ export declare function loadRecommendedTemplate(category?: string | null): unknown;
5
+ export declare function listBuiltinWritingStylePresets(): Array<{
6
+ id: string;
7
+ slug: string;
8
+ name: string;
9
+ }>;
10
+ export declare function seedWritingStyleBuiltins(db: PGlite): Promise<void>;
11
+ export declare const SECTION_TO_FOLDER: Record<string, string>;
12
+ export interface SeedSkillRow {
13
+ section: string;
14
+ folder: string;
15
+ agent_kind: string;
16
+ title: string;
17
+ body: string;
18
+ }
19
+ /** Disk skill markdown used both to seed a workspace and to advertise module skills before init. */
20
+ export declare function listSeedSkillRows(): SeedSkillRow[];
21
+ /** Seed generic skill markdown (genre-specific files under seed/skills/genres are not loaded). */
22
+ export declare function seedNovelSkills(db: PGlite, _category: string): Promise<void>;
23
+ export declare function listWritingStyles(db: PGlite): Promise<Array<{
24
+ id: string;
25
+ name: string;
26
+ slug: string;
27
+ }>>;
@@ -0,0 +1,96 @@
1
+ import { ENTITY_DOMAINS, isEntityDomain, type EntityDomain } from './domains.ts';
2
+ export declare const NOVEL_DIR = ".dsh-novel";
3
+ export declare const LEGACY_NOVEL_DIR = ".noveel";
4
+ export declare const META_FILE = "meta.json";
5
+ export interface NovelMeta {
6
+ version: 1;
7
+ novelId: string;
8
+ createdAt: string;
9
+ }
10
+ export interface NovelRecord {
11
+ id: string;
12
+ title: string;
13
+ description: string | null;
14
+ cover: string | null;
15
+ category: string;
16
+ writing_style_id: string | null;
17
+ chapter_count: number;
18
+ word_count: number;
19
+ blueprint_json: unknown;
20
+ outline_draft_md: string | null;
21
+ outline_final_md: string | null;
22
+ outline_status: string;
23
+ created_at: string;
24
+ updated_at: string;
25
+ }
26
+ export interface EntityRecord {
27
+ domain: string;
28
+ id: string;
29
+ name: string | null;
30
+ data: unknown;
31
+ created_at: string;
32
+ updated_at: string;
33
+ }
34
+ export interface SkillRecord {
35
+ id: string;
36
+ section: string;
37
+ folder: string;
38
+ agent_kind: string;
39
+ title: string;
40
+ body: string;
41
+ created_at: string;
42
+ updated_at: string;
43
+ }
44
+ /** Return whether a workspace directory has been provisioned as a novel. */
45
+ export declare function isNovelWorkspace(workspacePath: string): Promise<boolean>;
46
+ /** Initialize `.dsh-novel` + PGlite + default novel row for one workspace directory. */
47
+ export declare function provisionNovelWorkspace(workspacePath: string, input?: {
48
+ title?: string | undefined;
49
+ category?: string | undefined;
50
+ writingStyleId?: string | undefined;
51
+ }): Promise<{
52
+ meta: NovelMeta;
53
+ novel: NovelRecord;
54
+ alreadyInitialized: boolean;
55
+ }>;
56
+ /** Load the singleton novel row. */
57
+ export declare function getNovel(workspacePath: string): Promise<NovelRecord>;
58
+ /** Patch novel metadata / blueprint. */
59
+ export declare function updateNovel(workspacePath: string, patch: Partial<Pick<NovelRecord, 'title' | 'description' | 'cover' | 'category' | 'writing_style_id' | 'blueprint_json' | 'outline_draft_md' | 'outline_final_md' | 'outline_status'>>): Promise<NovelRecord>;
60
+ /** List entities in one domain. */
61
+ export declare function listEntities(workspacePath: string, domain: EntityDomain): Promise<EntityRecord[]>;
62
+ /** Load one entity. */
63
+ export declare function getEntity(workspacePath: string, id: string): Promise<EntityRecord | undefined>;
64
+ /** Insert or replace an entity. */
65
+ export declare function upsertEntity(workspacePath: string, domain: EntityDomain, data: Record<string, unknown>, id?: string): Promise<EntityRecord>;
66
+ /** Delete one entity. */
67
+ export declare function deleteEntity(workspacePath: string, id: string): Promise<boolean>;
68
+ /** Form template JSON for the workspace novel. */
69
+ export declare function getTemplate(workspacePath: string): Promise<unknown>;
70
+ /** Replace the form template. */
71
+ export declare function saveTemplate(workspacePath: string, config: unknown): Promise<unknown>;
72
+ /** List writing skills. */
73
+ export declare function listSkills(workspacePath: string): Promise<SkillRecord[]>;
74
+ /** Create or update a skill. */
75
+ export declare function upsertSkill(workspacePath: string, skill: {
76
+ id?: string | undefined;
77
+ section: string;
78
+ folder?: string | undefined;
79
+ agentKind?: string | undefined;
80
+ title: string;
81
+ body: string;
82
+ }): Promise<SkillRecord>;
83
+ /** Delete a skill. */
84
+ export declare function deleteSkill(workspacePath: string, id: string): Promise<boolean>;
85
+ /** Static write contract for tools. Book-specific field keys still come from get_template. */
86
+ export declare function describeSchema(): {
87
+ domains: typeof ENTITY_DOMAINS;
88
+ notes: string;
89
+ write: Record<string, string>;
90
+ };
91
+ export { ENTITY_DOMAINS, isEntityDomain };
92
+ export declare function listWorkspaceWritingStyles(workspacePath: string): Promise<Array<{
93
+ id: string;
94
+ name: string;
95
+ slug: string;
96
+ }>>;
@@ -0,0 +1,17 @@
1
+ import type { ContentSection } from './domains.ts';
2
+ export declare const TEMPLATE_PRESET_MAIN_CATEGORIES: readonly ["玄幻", "都市", "科幻", "末世", "仙侠", "言情", "悬疑", "历史"];
3
+ export type TemplatePresetMainCategory = (typeof TEMPLATE_PRESET_MAIN_CATEGORIES)[number];
4
+ export declare function normalizeTemplatePresetCategory(raw: string | null | undefined): TemplatePresetMainCategory;
5
+ export interface FormField {
6
+ key: string;
7
+ label: string;
8
+ component?: string;
9
+ options?: Array<{
10
+ label: string;
11
+ value: string;
12
+ }>;
13
+ }
14
+ /** Pick human-editable fields from a Noveel form_templates.config blob. */
15
+ export declare function fieldsOf(template: unknown, section: ContentSection, extra?: 'chapterSegment' | 'timeline'): FormField[];
16
+ export declare function getByPath(obj: Record<string, unknown>, path: string): unknown;
17
+ export declare function setByPath(obj: Record<string, unknown>, path: string, value: unknown): Record<string, unknown>;
@@ -0,0 +1,2 @@
1
+ export declare function timelineEventTypeLabel(eventType: unknown): string | undefined;
2
+ export declare function timelineResolvedLabel(eventType: unknown, isResolved: unknown): string | undefined;
@@ -0,0 +1,3 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ /** Register novel CRUD tools, DSH skills, and a system-prompt context dump. */
3
+ export declare function registerNovelHost(ctx: Context): void;
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "dsh-novel",
3
+ "version": "0.1.0",
4
+ "description": "Standard DSH plugin: novel workspace, PGlite canon, tools, skills, and content tab",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/ddedook/dsh-novel.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/ddedook/dsh-novel/issues"
12
+ },
13
+ "homepage": "https://github.com/ddedook/dsh-novel#readme",
14
+ "type": "module",
15
+ "main": "lib/index.js",
16
+ "types": "lib/types/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./lib/types/index.d.ts",
20
+ "default": "./lib/index.js"
21
+ },
22
+ "./client": {
23
+ "types": "./lib/types/client/index.d.ts",
24
+ "default": "./lib/client.js"
25
+ },
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "cordis.patch.yml",
30
+ "seed/**",
31
+ "lib/**/*.js",
32
+ "lib/**/*.map",
33
+ "lib/types/**/*.d.ts",
34
+ "README.md"
35
+ ],
36
+ "engines": {
37
+ "node": "^22.19.0 || >=24.0.0"
38
+ },
39
+ "dsh": {
40
+ "client": {
41
+ "inject": [
42
+ "@deepseek-ai/dsh-client-runtime",
43
+ "@deepseek-ai/dsh-client-ui-conversation"
44
+ ],
45
+ "platform": "web"
46
+ },
47
+ "bundle": {
48
+ "patch": "./cordis.patch.yml"
49
+ }
50
+ },
51
+ "dependencies": {
52
+ "@deepseek-ai/cordis": "4.0.1",
53
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
54
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6",
55
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
56
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
57
+ "@deepseek-ai/dsh-session": "0.1.0-rc.6",
58
+ "@deepseek-ai/dsh-skill": "0.1.0-rc.6",
59
+ "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.6",
60
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
61
+ "@electric-sql/pglite": "^0.4.5",
62
+ "react": "18.3.1"
63
+ },
64
+ "devDependencies": {
65
+ "@types/node": "^22.20.0",
66
+ "@types/react": "^18",
67
+ "tsdown": "0.22.2",
68
+ "typescript": "6.0.3",
69
+ "vitest": "4.1.8"
70
+ },
71
+ "scripts": {
72
+ "build": "tsdown && tsc -p tsconfig.json --emitDeclarationOnly && tsc -p tsconfig.client.json --emitDeclarationOnly",
73
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
74
+ "test": "vitest run",
75
+ "check": "pnpm run build && pnpm run typecheck && pnpm run test"
76
+ }
77
+ }
@@ -0,0 +1,34 @@
1
+ # 去AI味与质检
2
+
3
+ 提升场景感与人物差异;按读者读感修文。正式判定(`accepted` 等)由审查 skill / `submitChapterReview` 负责;写作侧只做自检与修订。
4
+
5
+ ## 核心原则
6
+
7
+ 1. 保留:已发生事实、人物硬设定、信息边界、伏笔、物件归属、时间序、章末牵引。
8
+ 2. 不为「像人」而加错别字、病句、隐形字符或伪造经历。
9
+ 3. 同类问题连续出现再修;单次可不处理(成簇才修)。
10
+
11
+ ## 审计对象(读者症状 → 诊断;成簇才修)
12
+
13
+ - 「读着像作文/假」← 否定式并列过密(「不是X,而是Y」)、格言化旁白(「权力是…」「命运从不…」)、解释性推进(叙述者替读者下结论)
14
+ - 「全员一个腔」← 人物口吻均质;段落模板过齐
15
+ - 「场面摸不着」← 抽象感官词替代可触摸细节;悬空判断(「局势复杂」无场景落点)
16
+ - 「段段总结收束」← 万能转折词堆砌、每段末口号式收束
17
+
18
+ ## 二稿顺序
19
+
20
+ 1. 列出不可改事件与信息边界。
21
+ 2. 挑 3–8 处表达簇场景化改写(物件/停顿/误说/他人反应)。
22
+ 3. 重写成连续正文,勿保留初稿句序骨架。
23
+ 4. 按章节合同与读者验收五问复验(见《章节节奏与开头》)。
24
+
25
+ ## 修复顺序
26
+
27
+ 保留必兑爽点与事实 → 最小片段替换 → 无效再整章 → 复验合同与五问 → 仍有小问题则记质量债并停止死循环(勿与审查判定死磕)。
28
+
29
+ ## 禁忌
30
+
31
+ - 以外部「AI检测分」为唯一目标反复重写。
32
+ - 修文时改掉必须事件或章末钩子。
33
+ - 全词表机械替换制造假「人味」。
34
+ - 写作侧自行宣布 `accepted` / 正式放行。
@@ -0,0 +1,52 @@
1
+ # 对话与情绪
2
+
3
+ 对话揭示人物、推动情节、制造冲突;情绪曲线服务章目标。对白排版与口吻直接决定读者是否出戏。
4
+
5
+ ## 核心原则
6
+
7
+ 1. 每句对话至少服务:推情节 / 揭人物 / 造冲突 / 传信息 / 表情感 / 造悬念。
8
+ 2. 简洁;真实对话可打断、迟疑、话未说完。
9
+ 3. 不同身份风险偏好与用词不同;闭眼听对白应能分辨说话人,三人同腔 = 失败。
10
+
11
+ ## 对白标点(硬约束)
12
+
13
+ - 人物说出的话一律用中文弯引号:`“……”`
14
+ - **禁止**:英文直引号 `""`、直角引号「」、圆括号 `()`、方括号 `[]`、书名号 `《》`、`『』` 等充当对白外壳
15
+ - 标签习惯:`道:“……”` 或 `“……”某某道`;多用动作/神态代替连续「他说/她道」
16
+ - 内心独白:不入引号,用叙述或斜切内心;**禁止**括号夹注(如`(他心想……)`)
17
+ - 省略、打断用 `……` / 话未说完截断;不以 `...` 或破折号堆砌替代引号
18
+
19
+ ## 可执行清单
20
+
21
+ ### 对话
22
+
23
+ - 删寒暄与无信息问答。
24
+ - 潜台词:表面说 A,实际争 B(对白是给对方听的版本)。
25
+ - 冲突对话:目标对立,各不让步或假意让步。
26
+ - 设定用行动/冲突带出,禁止说明书腔大段讲设定。
27
+
28
+ ### 视角与信息差
29
+
30
+ - 单场戏默认跟一个 POV,禁止无标跳头(读者会懵)。
31
+ - 读者信息与角色信息不强行对齐;用信息差推冲突。
32
+
33
+ ### 情绪曲线
34
+
35
+ - 定本章主情绪与起伏点(加压→误判→爆发→余波)。
36
+ - 情绪落在身体反应、物件、他人反应上,少用抽象词。
37
+ - 虐点后有补偿或新目标,避免纯虐空转。
38
+ - 每章至少一个可读回报(关系/信息/局势),与节奏 skill 一致。
39
+
40
+ ## 修订自检(改对话时内心核对,勿单独交报告)
41
+
42
+ - 无效句是否已删或改成有目的的版本
43
+ - 关系/信息是否因对话产生净变化
44
+ - 三人说话是否像同一个人
45
+ - 对白外壳是否全部为 “”
46
+
47
+ ## 禁忌
48
+
49
+ - 「你好」「吃了吗」式无效对话。
50
+ - 用对话大段讲设定(说明书腔)。
51
+ - 格言化旁白替代人物当场反应。
52
+ - 非 “” 对白外壳或括号夹注对白/内心。
@@ -0,0 +1,61 @@
1
+ # 章节数据维护
2
+
3
+ 正文落库用 `mutate_entities`(domain=`chapter`)。身份只要 `ordinal`(章号)+ `name`(短名,如 `灭门夜`);界面显示「第1章 灭门夜」,**不要**把「第1章」写进 `name`。`chapterNo` 仅作 `ordinal` 的兼容别名。`content` 是正文。可选 `relatedOutlineId` 或 `relatedOutlineName` 挂到大纲章节点。
4
+
5
+ 写章时除正文外,必须用 `mutate_entities` 同步本章引起的设定变更。目的:防止下一章读者出戏(人突然没了、神器归属错、生物首次出场无档)。
6
+
7
+ ## 必须同步的设定变化
8
+
9
+ | 类型 | domain | 示例 |
10
+ |------|--------|------|
11
+ | 新出场人物 / 人物档案变化 | `role` | 新配角、主角受伤后状态更新 |
12
+ | 关系变化 | `roleRelation` | 结盟、决裂、师徒(一条有向边即可) |
13
+ | 人物履历 | `roleTimeline` | 晋升、负伤、重大抉择 |
14
+ | 物品流转 | `item` | 获得神器、损毁、转手 |
15
+ | 物品履历 | `itemTimeline` | 认主、封印、损毁 |
16
+ | 新出场生物 / 生物档案变化 | `creature` | 新异兽、灵植状态变化 |
17
+ | 生物履历 | `creatureTimeline` | 驯化、反噬、死亡 |
18
+ | 世界节点 | `world` | 新地点、势力易主 |
19
+ | 世界线 | `worldTimeline` | 某地战乱、政权更迭 |
20
+ | 主时间线 | `timeline` | 冲突、悬念、伏笔、转折 |
21
+ | 等级体系 | `level` | 体系/等级规则变化(较少见) |
22
+
23
+ ## 可声明无变更
24
+
25
+ 若本章仅推进剧情、不改动任何设定档案,不必 mutate 其它域。
26
+
27
+ ## owner 与宿主(易混)
28
+
29
+ - `item` / `creature` 的 `owner` = 归属主人的**人物名字符串**。
30
+ - 附属时间线宿主用 `roleName` / `itemName` / `creatureName`(或对应 `*Id`),不是 owner 字段。
31
+ - 主人变更 = 实体 `owner` + 对应 `*Timeline`,缺一不可。
32
+
33
+ ## 各域 payload 必填
34
+
35
+ | domain | 写入 |
36
+ |--------|------|
37
+ | `chapter` | `ordinal` + `name`;正文放 `content` |
38
+ | `role` / `item` / `creature` | `name` + 模板字段顶层 key |
39
+ | `roleRelation` | 双方引用(from/to id 或 name)+ `relationType` + 非空 `content` |
40
+ | `roleTimeline` | `roleId`\|`roleName` + `timeLabel` + `timePoint` + 非空 `content` |
41
+ | `itemTimeline` | `itemId`\|`itemName` + `timeLabel` + `timePoint` + `content` |
42
+ | `creatureTimeline` | `creatureId`\|`creatureName` + `timeLabel` + `timePoint` + `content` |
43
+ | `worldTimeline` | `worldNodeId`\|`worldNodeName` + `timeLabel` + `timePoint` + `content` |
44
+ | `timeline` | `timeLabel` + `timePoint` + `title` + `content` + `eventType` |
45
+ | `world` | `name` + `kind` |
46
+ | `level` | `system.name` + 非空 `system.levels` |
47
+
48
+ ## 流程
49
+
50
+ 1. `query_entities` / `get_entities` 读对应大纲章合同与相关设定
51
+ 2. 写正文
52
+ 3. `mutate_entities` 写入 `chapter`(`ordinal` + `name` + `content`)
53
+ 4. 本章改动的设定同样用 `mutate_entities` 写入对应域
54
+
55
+ ## 禁忌
56
+
57
+ - 正文出现新人物名却不写入 `role`
58
+ - 正文出现新生物名却不写入 `creature`
59
+ - 只写正文不同步设定变更
60
+ - 用空 query 拉全书索引浪费上下文(应带名称查询)
61
+ - 把「第N章」写进 `name`
@@ -0,0 +1,61 @@
1
+ # 章节节奏与开头
2
+
3
+ 每一章是完整叙事单元;开篇决定去留,读完须有净变化。章尾钩子见《章首钩子》。
4
+
5
+ ## 核心原则
6
+
7
+ 1. 开篇不劝退:前几段须有即时张力、推动事件或情感冲击。
8
+ 2. 章内张力有升有落;读完净变化(关系/信息/局势至少一项)能一句话说清。
9
+ 3. 主角用选择推动局面,而非纯旁观。
10
+ 4. 若系统注入 `chapterWordTarget`,正文须落在区间内;**达标不等于不注水**。
11
+
12
+ ## 读者验收五问(写前自检,勿单独输出规划稿)
13
+
14
+ 1. 开篇会不会让我想划走?
15
+ 2. 读完我能一句话说清「得到了什么」吗?
16
+ 3. 有没有哪段像说明书/复读/注水?
17
+ 4. 对白是否像不同的人在说话,且全是 “”?
18
+ 5. 章末我是否想立刻看下一章(真期待,非假钩)?
19
+
20
+ ## 强力开头(优先 5 类)
21
+
22
+ 1. **行动中开场**:冲突高潮点切入。
23
+ 2. **反常情境**:不合常理,逼问怎么回事。
24
+ 3. **震撼对话**:一句改变关系/局势的话(对白用 “”)。
25
+ 4. **倒计时**:明确时限与后果。
26
+ 5. **重大发现**:线索/真相改变理解。
27
+
28
+ ## 承上(禁复述)
29
+
30
+ - 用回声细节、未完成动作续写、物件/伤势状态承接上章。
31
+ - 禁止「上回说到」式复盘;读者已知信息不重复讲解。
32
+
33
+ ## 开头禁忌
34
+
35
+ | 类型 | 为何致命 |
36
+ |------|----------|
37
+ | 天气/起床流水账 | 无冲突,劝退 |
38
+ | 「上回说到」复述 | 浪费篇幅 |
39
+ | 大段世界观倾倒 | 无行动 |
40
+ | 无意义寒暄 | 无信息 |
41
+
42
+ ## 章内节奏
43
+
44
+ - 开场加压 → 中段升级或误判 → 高潮兑现/反转 → 章末牵引。
45
+ - 每场戏至少推进:情节 / 人物 / 信息 之一。
46
+ - 打破预期:读者以为会 A 时给代价更高的 B。
47
+ - 单章场景宜紧凑(通常 1–3 场),避免无信息切场。
48
+
49
+ ## 写前自检(内心核对,勿单独交作业)
50
+
51
+ - 开头是否不劝退、落在哪一类手段上
52
+ - 本章必须事件是否可兑现
53
+ - 一句话净变化是什么
54
+ - 章末翻页欲是否成立(钩子细则见《章首钩子》)
55
+
56
+ ## 禁忌
57
+
58
+ - 全章解释、回顾、重复无新信息。
59
+ - 高潮在开场后一路泄气至章末。
60
+ - 主角全程被推着走,无主动选择。
61
+ - 单独输出规划稿代替正文。
@@ -0,0 +1,40 @@
1
+ # 章首钩子
2
+
3
+ 章尾逼读、制造翻页欲;钩子强度与信息边界匹配。开头类型与章骨架见《章节节奏与开头》。
4
+
5
+ ## 核心原则
6
+
7
+ 1. 每章结尾必须有有效钩子(危机、揭示、未完成动作、两难等)。
8
+ 2. **验收主句:翻页欲**——钩子须改写读者对局势的理解或下一步期待。
9
+ 3. 假钩子伤害信任,比弱钩更糟。
10
+
11
+ ## 章首(交叉引用)
12
+
13
+ 开头手段(行动切入 / 反常画面 / 危险对话 / 倒计时 / 发现物证等)见《章节节奏与开头》。引子后迅速进入本章目标,不长时间空转。
14
+
15
+ ## 章尾钩子(常用)
16
+
17
+ 1. **突然揭示**:信息改写现状。
18
+ 2. **紧急危机**:下一章必须应对。
19
+ 3. **未完成动作**:打断在结果前。
20
+ 4. **身份反转**:关系重定义。
21
+ 5. **两难选择**:决定前截断。
22
+ 6. **新压力源**:更强敌/规则反噬/资源争夺。
23
+
24
+ ## 悬念强度
25
+
26
+ - 弱:好奇细节 → 中:威胁人物目标 → 强:威胁生存/身份/关系根基。
27
+ - 长篇交替使用,避免章章同质「更大反派出现」。
28
+
29
+ ## 写前自检(内心核对,勿单独交作业)
30
+
31
+ - 章尾具体落点是什么,读者会期待什么
32
+ - 是否真改写期待(非装饰性停顿)
33
+ - 留给下章的未决问题是否可在后续兑现
34
+
35
+ ## 禁忌
36
+
37
+ - 假钩子:下章立刻无关或纯搞笑消解。
38
+ - 剧透终局;或钩子依赖读者未知的百科设定。
39
+ - 开篇加压后大段降温至无聊铺垫。
40
+ - 单独输出钩子规划稿代替正文。
@@ -0,0 +1,11 @@
1
+ # 异兽与灵植
2
+
3
+ 按 `kind` 分型写清辨识与代价;批量创建时字段写全。
4
+
5
+ - **异兽(beast)**:血脉/神通/克制关系写清;危险等级与栖息环境对应。
6
+ - **灵植(plant)**:通灵条件、药性/毒性、采摘代价;勿写成普通道具(道具走 item)。
7
+ - **灵体(spirit)**:依附物、显形条件、对主人的羁绊或反噬。
8
+ - **普通动物(animal)**:可作氛围与线索,仍需一两点可辨特征。
9
+ - **其他(other)**:写清为何不成上述四类,以及核心能力/危险边界。
10
+
11
+ 批量创建时每批 3~5 只,字段写全后再下一批;有主人时先确保人物已存在,再填 `owner`(人物名)。关键节点同步 `creatureTimeline`。
@@ -0,0 +1,13 @@
1
+ # 生物档案要素
2
+
3
+ 除人物外的生物(动物、异兽、通灵植物、灵体等)写入时注意。读者向:出场有辨识与代价,归属不乱。
4
+
5
+ ## 写库要点
6
+
7
+ 1. **种类 `kind`**:库表标量 `animal|beast|plant|spirit|other`,不要塞进 profile。
8
+ 2. **名称唯一**:全书生物名唯一;别名可写在档案字段。
9
+ 3. **主人可选**:有主则 **`owner` 传人物名字符串**(勿传 UUID / 勿用 `ownerId`);野生/无主省略或置空。
10
+ 4. **档案写满**:栖息、习性、能力、外形、危险等级、来历等按模板 key 覆盖大半,避免只剩名字。
11
+ 5. **时间线**:驯养、觉醒、战损、易主等关键节点写进 `creatureTimeline`(须 `creatureId|creatureName` + `timeLabel` + 整数 `timePoint` + 非空 `content`;有标题则写 `title`)。
12
+
13
+ 写作时突出辨识特征与战力代价,勿与人物档案混写。有主人时先确保人物已存在。
@@ -0,0 +1,32 @@
1
+ # 题材规则 · 仙侠
2
+
3
+ 偏修仙/仙侠:道与劫、宗门天梯、飞升长线。与玄幻升级流共享骨架,强调「修」的代价与境界质变。
4
+
5
+ ## 读者期待
6
+
7
+ - 从凡到仙的阶梯感;心性、机缘、天劫同样重要。
8
+ - 爽点:破境、渡劫、悟道、夺宝、名震一方、飞升在望。
9
+ - 仙凡对照:人情债与天道冷规则交织。
10
+
11
+ ## 大纲重点
12
+
13
+ 1. 境界体系写清质变差异(不只改称号)。
14
+ 2. 机缘有代价:因果、心魔、天妒、宗门争夺。
15
+ 3. 宗门/散修/魔道三角张力,内部派系可用。
16
+ 4. 每卷至少一个「渡劫或近死破境」节点。
17
+ 5. 长线指向更高天域/飞升,但不透支终局。
18
+
19
+ ## 章纲/正文重点
20
+
21
+ - 修炼戏要有风险与选择,忌闭关旁白涨战力。
22
+ - 法宝/功法有使用史与暴露风险。
23
+ - 章尾优先:心魔、天劫征兆、宗门追杀令、上界注视。
24
+
25
+ ## 雷点
26
+
27
+ - 境界灌水无质变;无心性的纯数值仙。
28
+ - 全程打怪升级,无因果与人情。
29
+
30
+ ## 联动区块
31
+
32
+ level · world(规则/势力)· role(心性缺陷)