@changw98ic/dashboard 1.0.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.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @changw98ic/dashboard
2
+
3
+ 可视化面板 - Fastify 后端。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @changw98ic/dashboard
9
+ ```
10
+
11
+ ## 使用
12
+
13
+ ```typescript
14
+ import { createDashboard } from '@changw98ic/dashboard';
15
+
16
+ const dashboard = createDashboard({
17
+ port: 3000,
18
+ projectRoot: '/path/to/novel'
19
+ });
20
+
21
+ await dashboard.start();
22
+ ```
23
+
24
+ ## 命令行
25
+
26
+ ```bash
27
+ npx webnovel dashboard
28
+ ```
29
+
30
+ ## 文档
31
+
32
+ 详见 [项目主页](https://github.com/changw98ic/webnovel-writer-skill#readme)
33
+
34
+ ## 致谢
35
+
36
+ 本项目基于 [lingfengQAQ/webnovel-writer-skill](https://github.com/lingfengQAQ/webnovel-writer-skill) 开发。
37
+
38
+ ## License
39
+
40
+ MIT
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @changw98ic/dashboard
3
+ *
4
+ * 可视化面板 - Fastify 后端
5
+ */
6
+ import Fastify from 'fastify';
7
+ export interface DashboardOptions {
8
+ port?: number;
9
+ host?: string;
10
+ projectRoot: string;
11
+ staticDir?: string;
12
+ }
13
+ export declare function createDashboard(options: DashboardOptions): Promise<{
14
+ fastify: Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault> & PromiseLike<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
15
+ start: () => Promise<Fastify.FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, Fastify.FastifyBaseLogger, Fastify.FastifyTypeProviderDefault>>;
16
+ stop: () => Promise<void>;
17
+ }>;
18
+ export { projectRoutes } from './routes/project.js';
19
+ export { chapterRoutes } from './routes/chapter.js';
20
+ export { entityRoutes } from './routes/entity.js';
21
+ export { statsRoutes } from './routes/stats.js';
22
+ export default createDashboard;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,OAAO,MAAM,SAAS,CAAC;AA8B9B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB;;;;GA0E9D;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,eAAe,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @changw98ic/dashboard
3
+ *
4
+ * 可视化面板 - Fastify 后端
5
+ */
6
+ import Fastify from 'fastify';
7
+ import cors from '@fastify/cors';
8
+ import staticPlugin from '@fastify/static';
9
+ import { existsSync } from 'fs';
10
+ import { join, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { projectRoutes } from './routes/project.js';
13
+ import { chapterRoutes } from './routes/chapter.js';
14
+ import { entityRoutes } from './routes/entity.js';
15
+ import { statsRoutes } from './routes/stats.js';
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ function resolveStaticDir(staticDir) {
18
+ const candidates = [
19
+ staticDir,
20
+ join(__dirname, '../frontend/dist'),
21
+ join(__dirname, '../../../webnovel-writer/dashboard/frontend/dist'),
22
+ ];
23
+ for (const candidate of candidates) {
24
+ if (candidate && existsSync(candidate)) {
25
+ return candidate;
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ export async function createDashboard(options) {
31
+ const { port = 3000, host = 'localhost', projectRoot, staticDir } = options;
32
+ const resolvedStaticDir = resolveStaticDir(staticDir);
33
+ const fastify = Fastify({
34
+ logger: {
35
+ level: 'info',
36
+ },
37
+ });
38
+ // 注册 CORS
39
+ await fastify.register(cors, {
40
+ origin: true,
41
+ });
42
+ // 注册静态文件服务
43
+ if (resolvedStaticDir) {
44
+ await fastify.register(staticPlugin, {
45
+ root: resolvedStaticDir,
46
+ prefix: '/assets/',
47
+ });
48
+ }
49
+ // 注册路由
50
+ await fastify.register(projectRoutes, { prefix: '/api/project', projectRoot });
51
+ await fastify.register(chapterRoutes, { prefix: '/api/chapters', projectRoot });
52
+ await fastify.register(entityRoutes, { prefix: '/api/entities', projectRoot });
53
+ await fastify.register(statsRoutes, { prefix: '/api/stats', projectRoot });
54
+ // 健康检查
55
+ fastify.get('/api/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
56
+ // SPA fallback
57
+ fastify.setNotFoundHandler((request, reply) => {
58
+ if (request.url.startsWith('/api/')) {
59
+ reply.code(404).send({ error: 'Not found' });
60
+ }
61
+ else {
62
+ if (resolvedStaticDir) {
63
+ reply.sendFile('index.html');
64
+ return;
65
+ }
66
+ reply.type('text/html').send(`
67
+ <!doctype html>
68
+ <html lang="zh-CN">
69
+ <head>
70
+ <meta charset="utf-8" />
71
+ <title>Webnovel Dashboard</title>
72
+ </head>
73
+ <body>
74
+ <h1>Webnovel Dashboard API 已启动</h1>
75
+ <p>未找到前端静态资源目录,请先构建或提供 staticDir。</p>
76
+ </body>
77
+ </html>
78
+ `);
79
+ }
80
+ });
81
+ return {
82
+ fastify,
83
+ start: async () => {
84
+ await fastify.listen({ port, host });
85
+ console.log(`Dashboard running at http://${host}:${port}`);
86
+ if (resolvedStaticDir) {
87
+ console.log(`Dashboard static assets: ${resolvedStaticDir}`);
88
+ }
89
+ else {
90
+ console.warn('Dashboard static assets not found; API-only mode enabled.');
91
+ }
92
+ return fastify;
93
+ },
94
+ stop: async () => {
95
+ await fastify.close();
96
+ },
97
+ };
98
+ }
99
+ export { projectRoutes } from './routes/project.js';
100
+ export { chapterRoutes } from './routes/chapter.js';
101
+ export { entityRoutes } from './routes/entity.js';
102
+ export { statsRoutes } from './routes/stats.js';
103
+ export default createDashboard;
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Chapter Routes - 章节管理 API
3
+ */
4
+ import type { FastifyPluginAsync } from 'fastify';
5
+ interface ChapterRoutesOptions {
6
+ projectRoot: string;
7
+ }
8
+ export declare const chapterRoutes: FastifyPluginAsync<ChapterRoutesOptions>;
9
+ export {};
10
+ //# sourceMappingURL=chapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chapter.d.ts","sourceRoot":"","sources":["../../src/routes/chapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAKhE,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,eAAO,MAAM,aAAa,EAAE,kBAAkB,CAAC,oBAAoB,CA6FlE,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { StateManager, IndexManager } from '@changw98ic/data';
2
+ import { readFile } from 'fs/promises';
3
+ import { join } from 'path';
4
+ export const chapterRoutes = async (fastify, options) => {
5
+ const { projectRoot } = options;
6
+ // 获取章节列表
7
+ fastify.get('/', async (_request, reply) => {
8
+ const stateManager = new StateManager({ projectRoot });
9
+ if (!stateManager.exists()) {
10
+ return reply.code(404).send({ error: 'Project not initialized' });
11
+ }
12
+ const state = await stateManager.loadState();
13
+ const chapterMetas = Object.entries(state.chapter_meta || {}).map(([num, meta]) => {
14
+ const m = meta;
15
+ return {
16
+ chapter: parseInt(num),
17
+ title: m.title,
18
+ word_count: m.word_count,
19
+ location: m.location,
20
+ summary: m.summary,
21
+ };
22
+ });
23
+ return {
24
+ chapters: chapterMetas.sort((a, b) => a.chapter - b.chapter),
25
+ total: chapterMetas.length,
26
+ };
27
+ });
28
+ // 获取单个章节详情
29
+ fastify.get('/:chapter', async (request, reply) => {
30
+ const { chapter } = request.params;
31
+ const chapterNum = parseInt(chapter);
32
+ const stateManager = new StateManager({ projectRoot });
33
+ const indexManager = new IndexManager({ projectRoot });
34
+ if (!stateManager.exists()) {
35
+ return reply.code(404).send({ error: 'Project not initialized' });
36
+ }
37
+ const state = await stateManager.loadState();
38
+ const meta = state.chapter_meta?.[chapterNum.toString()];
39
+ if (!meta) {
40
+ return reply.code(404).send({ error: 'Chapter not found' });
41
+ }
42
+ // 获取章节的场景
43
+ const scenes = indexManager.getScenes(chapterNum);
44
+ return {
45
+ chapter: chapterNum,
46
+ title: meta.title,
47
+ word_count: meta.word_count,
48
+ location: meta.location,
49
+ summary: meta.summary,
50
+ scenes,
51
+ };
52
+ });
53
+ // 获取章节正文
54
+ fastify.get('/:chapter/content', async (request, reply) => {
55
+ const { chapter } = request.params;
56
+ const chapterNum = parseInt(chapter);
57
+ const stateManager = new StateManager({ projectRoot });
58
+ if (!stateManager.exists()) {
59
+ return reply.code(404).send({ error: 'Project not initialized' });
60
+ }
61
+ const state = await stateManager.loadState();
62
+ const meta = state.chapter_meta?.[chapterNum.toString()];
63
+ if (!meta || !meta.location) {
64
+ return reply.code(404).send({ error: 'Chapter content not found' });
65
+ }
66
+ try {
67
+ const contentPath = join(projectRoot, meta.location);
68
+ const content = await readFile(contentPath, 'utf-8');
69
+ return {
70
+ chapter: chapterNum,
71
+ title: meta.title,
72
+ content,
73
+ word_count: content.length,
74
+ };
75
+ }
76
+ catch {
77
+ return reply.code(404).send({ error: 'Chapter file not found' });
78
+ }
79
+ });
80
+ };
81
+ //# sourceMappingURL=chapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chapter.js","sourceRoot":"","sources":["../../src/routes/chapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Entity Routes - 实体管理 API
3
+ */
4
+ import type { FastifyPluginAsync } from 'fastify';
5
+ interface EntityRoutesOptions {
6
+ projectRoot: string;
7
+ }
8
+ export declare const entityRoutes: FastifyPluginAsync<EntityRoutesOptions>;
9
+ export {};
10
+ //# sourceMappingURL=entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../src/routes/entity.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,UAAU,mBAAmB;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,eAAO,MAAM,YAAY,EAAE,kBAAkB,CAAC,mBAAmB,CA0IhE,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { IndexManager } from '@changw98ic/data';
2
+ export const entityRoutes = async (fastify, options) => {
3
+ const { projectRoot } = options;
4
+ // 获取实体列表
5
+ fastify.get('/', async (request, _reply) => {
6
+ const query = request.query;
7
+ const indexManager = new IndexManager({ projectRoot });
8
+ const entities = indexManager.getEntities({
9
+ type: query.type,
10
+ tier: query.tier,
11
+ limit: query.limit || 50,
12
+ });
13
+ return {
14
+ entities: entities.map(e => ({
15
+ id: e.id,
16
+ name: e.canonical_name,
17
+ type: e.type,
18
+ tier: e.tier,
19
+ first_appearance: e.first_appearance,
20
+ last_appearance: e.last_appearance,
21
+ is_protagonist: e.is_protagonist,
22
+ })),
23
+ total: entities.length,
24
+ };
25
+ });
26
+ // 获取核心实体
27
+ fastify.get('/core', async (_request, _reply) => {
28
+ const indexManager = new IndexManager({ projectRoot });
29
+ const entities = indexManager.getCoreEntities();
30
+ return {
31
+ entities: entities.map(e => ({
32
+ id: e.id,
33
+ name: e.canonical_name,
34
+ type: e.type,
35
+ tier: e.tier,
36
+ current: e.current,
37
+ last_appearance: e.last_appearance,
38
+ })),
39
+ total: entities.length,
40
+ };
41
+ });
42
+ // 搜索实体
43
+ fastify.get('/search', async (request, reply) => {
44
+ const query = request.query;
45
+ if (!query.q) {
46
+ return reply.code(400).send({ error: 'Missing search query' });
47
+ }
48
+ const indexManager = new IndexManager({ projectRoot });
49
+ const entities = indexManager.searchEntities(query.q, query.limit || 20);
50
+ return {
51
+ query: query.q,
52
+ entities: entities.map(e => ({
53
+ id: e.id,
54
+ name: e.canonical_name,
55
+ type: e.type,
56
+ tier: e.tier,
57
+ last_appearance: e.last_appearance,
58
+ })),
59
+ total: entities.length,
60
+ };
61
+ });
62
+ // 获取单个实体详情
63
+ fastify.get('/:id', async (request, reply) => {
64
+ const { id } = request.params;
65
+ const indexManager = new IndexManager({ projectRoot });
66
+ const entity = indexManager.getEntityById(id);
67
+ if (!entity) {
68
+ return reply.code(404).send({ error: 'Entity not found' });
69
+ }
70
+ // 获取别名
71
+ const aliases = indexManager.getAliasesForEntity(id);
72
+ // 获取状态变化历史
73
+ const stateChanges = indexManager.getStateChanges(id, 20);
74
+ // 获取关系
75
+ const relationships = indexManager.getRelationships(id, 20);
76
+ return {
77
+ ...entity,
78
+ aliases,
79
+ state_changes: stateChanges,
80
+ relationships,
81
+ };
82
+ });
83
+ // 获取实体关系图谱
84
+ fastify.get('/graph', async (_request, _reply) => {
85
+ const indexManager = new IndexManager({ projectRoot });
86
+ const entities = indexManager.getEntities({ limit: 100 });
87
+ const nodes = entities.map(e => ({
88
+ id: e.id,
89
+ label: e.canonical_name,
90
+ type: e.type,
91
+ tier: e.tier,
92
+ }));
93
+ // 获取所有关系
94
+ const edges = [];
95
+ for (const entity of entities.slice(0, 50)) {
96
+ const rels = indexManager.getRelationships(entity.id, 10);
97
+ for (const rel of rels) {
98
+ edges.push({
99
+ source: rel.from_entity,
100
+ target: rel.to_entity,
101
+ type: rel.type,
102
+ });
103
+ }
104
+ }
105
+ return { nodes, edges };
106
+ });
107
+ // 获取最近出场记录
108
+ fastify.get('/recent', async (request, _reply) => {
109
+ const query = request.query;
110
+ const indexManager = new IndexManager({ projectRoot });
111
+ const recent = indexManager.getRecentAppearances(query.limit || 20);
112
+ return {
113
+ entities: recent,
114
+ };
115
+ });
116
+ };
117
+ //# sourceMappingURL=entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity.js","sourceRoot":"","sources":["../../src/routes/entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Project Routes - 项目信息 API
3
+ */
4
+ import type { FastifyPluginAsync } from 'fastify';
5
+ interface ProjectRoutesOptions {
6
+ projectRoot: string;
7
+ }
8
+ export declare const projectRoutes: FastifyPluginAsync<ProjectRoutesOptions>;
9
+ export {};
10
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,EAAE,kBAAkB,CAAC,oBAAoB,CA4FlE,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { StateManager } from '@changw98ic/data';
2
+ export const projectRoutes = async (fastify, options) => {
3
+ const { projectRoot } = options;
4
+ // 获取项目信息
5
+ fastify.get('/info', async (_request, reply) => {
6
+ const stateManager = new StateManager({ projectRoot });
7
+ if (!stateManager.exists()) {
8
+ return reply.code(404).send({ error: 'Project not initialized' });
9
+ }
10
+ const state = await stateManager.loadState();
11
+ return {
12
+ title: state.project_info.title,
13
+ genre: state.project_info.genre,
14
+ target_words: state.project_info.target_words,
15
+ target_chapters: state.project_info.target_chapters,
16
+ current_chapter: state.progress.current_chapter,
17
+ total_words: state.progress.total_words,
18
+ created_at: state.project_info.created_at,
19
+ };
20
+ });
21
+ // 获取进度信息
22
+ fastify.get('/progress', async (_request, reply) => {
23
+ const stateManager = new StateManager({ projectRoot });
24
+ if (!stateManager.exists()) {
25
+ return reply.code(404).send({ error: 'Project not initialized' });
26
+ }
27
+ const state = await stateManager.loadState();
28
+ return {
29
+ current_chapter: state.progress.current_chapter,
30
+ total_words: state.progress.total_words,
31
+ completed_chapters: state.progress.completed_chapters || 0,
32
+ progress_percent: state.project_info.target_chapters
33
+ ? Math.round((state.progress.current_chapter / state.project_info.target_chapters) * 100)
34
+ : 0,
35
+ };
36
+ });
37
+ // 获取主角状态
38
+ fastify.get('/protagonist', async (_request, reply) => {
39
+ const stateManager = new StateManager({ projectRoot });
40
+ if (!stateManager.exists()) {
41
+ return reply.code(404).send({ error: 'Project not initialized' });
42
+ }
43
+ const state = await stateManager.loadState();
44
+ return state.protagonist_state || {};
45
+ });
46
+ // 获取伏笔
47
+ fastify.get('/foreshadowing', async (_request, reply) => {
48
+ const stateManager = new StateManager({ projectRoot });
49
+ if (!stateManager.exists()) {
50
+ return reply.code(404).send({ error: 'Project not initialized' });
51
+ }
52
+ const state = await stateManager.loadState();
53
+ const foreshadowing = state.plot_threads?.foreshadowing || [];
54
+ return {
55
+ active: foreshadowing.filter((f) => f.status === 'active'),
56
+ resolved: foreshadowing.filter((f) => f.status === 'resolved'),
57
+ total: foreshadowing.length,
58
+ };
59
+ });
60
+ // 获取 Strand Tracker
61
+ fastify.get('/strands', async (_request, reply) => {
62
+ const stateManager = new StateManager({ projectRoot });
63
+ if (!stateManager.exists()) {
64
+ return reply.code(404).send({ error: 'Project not initialized' });
65
+ }
66
+ const state = await stateManager.loadState();
67
+ return {
68
+ entries: state.strand_tracker?.entries || [],
69
+ quest_consecutive: state.strand_tracker?.quest_consecutive || 0,
70
+ fire_gap: state.strand_tracker?.fire_gap || 0,
71
+ constellation_gap: state.strand_tracker?.constellation_gap || 0,
72
+ };
73
+ });
74
+ };
75
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Stats Routes - 统计信息 API
3
+ */
4
+ import type { FastifyPluginAsync } from 'fastify';
5
+ interface StatsRoutesOptions {
6
+ projectRoot: string;
7
+ }
8
+ export declare const statsRoutes: FastifyPluginAsync<StatsRoutesOptions>;
9
+ export {};
10
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/routes/stats.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGhE,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,kBAAkB,CAAC,kBAAkB,CAgK9D,CAAC"}