@echoes-io/mcp-server 1.3.3 → 1.4.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 +4 -10
- package/lib/tools/book-generate.d.ts +3 -0
- package/lib/tools/book-generate.js +3 -4
- package/lib/tools/chapter-delete.d.ts +3 -0
- package/lib/tools/chapter-delete.js +5 -6
- package/lib/tools/chapter-info.d.ts +3 -0
- package/lib/tools/chapter-info.js +5 -6
- package/lib/tools/chapter-insert.d.ts +6 -3
- package/lib/tools/chapter-insert.js +18 -13
- package/lib/tools/chapter-refresh.d.ts +3 -0
- package/lib/tools/chapter-refresh.js +9 -10
- package/lib/tools/episode-info.d.ts +3 -0
- package/lib/tools/episode-info.js +5 -6
- package/lib/tools/episode-update.d.ts +3 -0
- package/lib/tools/episode-update.js +5 -6
- package/lib/tools/rag-context.d.ts +3 -0
- package/lib/tools/rag-context.js +3 -4
- package/lib/tools/rag-index.d.ts +3 -0
- package/lib/tools/rag-index.js +8 -9
- package/lib/tools/rag-search.d.ts +3 -0
- package/lib/tools/rag-search.js +3 -4
- package/lib/tools/stats.d.ts +3 -0
- package/lib/tools/stats.js +8 -9
- package/lib/tools/timeline-sync.d.ts +3 -0
- package/lib/tools/timeline-sync.js +25 -23
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +2 -7
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -15,10 +15,7 @@ Add to your MCP client configuration (e.g., `~/.config/q/mcp.json` for Amazon Q)
|
|
|
15
15
|
"mcpServers": {
|
|
16
16
|
"echoes": {
|
|
17
17
|
"command": "npx",
|
|
18
|
-
"args": ["-y", "@echoes-io/mcp-server"]
|
|
19
|
-
"env": {
|
|
20
|
-
"ECHOES_TIMELINE": "your-timeline-name"
|
|
21
|
-
}
|
|
18
|
+
"args": ["-y", "@echoes-io/mcp-server"]
|
|
22
19
|
}
|
|
23
20
|
}
|
|
24
21
|
}
|
|
@@ -38,7 +35,6 @@ Then configure:
|
|
|
38
35
|
"echoes": {
|
|
39
36
|
"command": "echoes-mcp-server",
|
|
40
37
|
"env": {
|
|
41
|
-
"ECHOES_TIMELINE": "your-timeline-name",
|
|
42
38
|
"ECHOES_RAG_PROVIDER": "e5-small",
|
|
43
39
|
"ECHOES_RAG_DB_PATH": "./rag_data.db"
|
|
44
40
|
}
|
|
@@ -47,8 +43,6 @@ Then configure:
|
|
|
47
43
|
}
|
|
48
44
|
```
|
|
49
45
|
|
|
50
|
-
**Important:** The `ECHOES_TIMELINE` environment variable must be set to specify which timeline to work with. All tools operate on this timeline.
|
|
51
|
-
|
|
52
46
|
**Optional RAG Configuration:**
|
|
53
47
|
- `ECHOES_RAG_PROVIDER`: Embedding provider (`e5-small`, `e5-large`, or `gemini`). Default: `e5-small`
|
|
54
48
|
- `ECHOES_GEMINI_API_KEY`: Required if using `gemini` provider
|
|
@@ -56,7 +50,7 @@ Then configure:
|
|
|
56
50
|
|
|
57
51
|
## Available Tools
|
|
58
52
|
|
|
59
|
-
All tools
|
|
53
|
+
All tools require a `timeline` parameter to specify which timeline to operate on.
|
|
60
54
|
|
|
61
55
|
### Content Operations
|
|
62
56
|
- **`words-count`** - Count words and text statistics in markdown files
|
|
@@ -69,7 +63,7 @@ All tools operate on the timeline specified by the `ECHOES_TIMELINE` environment
|
|
|
69
63
|
- Input: `file` (path to chapter file)
|
|
70
64
|
|
|
71
65
|
- **`chapter-insert`** - Insert new chapter with automatic renumbering
|
|
72
|
-
- Input: `arc`, `episode`, `after`, `pov`, `title`, optional: `
|
|
66
|
+
- Input: `arc`, `episode`, `after`, `pov`, `title`, optional: `summary`, `location`, `outfit`, `kink`, `file`
|
|
73
67
|
|
|
74
68
|
- **`chapter-delete`** - Delete chapter from database and optionally from filesystem
|
|
75
69
|
- Input: `arc`, `episode`, `chapter`, optional: `file` (to delete from filesystem)
|
|
@@ -150,7 +144,7 @@ npm run lint:format
|
|
|
150
144
|
- **Database**: SQLite via @echoes-io/tracker (singleton pattern)
|
|
151
145
|
- **Validation**: Zod schemas for type-safe inputs
|
|
152
146
|
- **Testing**: Comprehensive unit and integration tests
|
|
153
|
-
- **
|
|
147
|
+
- **Timeline Parameter**: All tools accept timeline as a required parameter
|
|
154
148
|
|
|
155
149
|
## License
|
|
156
150
|
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const bookGenerateSchema: z.ZodObject<{
|
|
3
|
+
timeline: z.ZodString;
|
|
3
4
|
contentPath: z.ZodString;
|
|
4
5
|
outputPath: z.ZodString;
|
|
5
6
|
episodes: z.ZodOptional<z.ZodString>;
|
|
6
7
|
format: z.ZodOptional<z.ZodEnum<["a4", "a5"]>>;
|
|
7
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
timeline: string;
|
|
8
10
|
contentPath: string;
|
|
9
11
|
outputPath: string;
|
|
10
12
|
episodes?: string | undefined;
|
|
11
13
|
format?: "a4" | "a5" | undefined;
|
|
12
14
|
}, {
|
|
15
|
+
timeline: string;
|
|
13
16
|
contentPath: string;
|
|
14
17
|
outputPath: string;
|
|
15
18
|
episodes?: string | undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { generateBook } from '@echoes-io/books-generator';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getTimeline } from '../utils.js';
|
|
4
3
|
export const bookGenerateSchema = z.object({
|
|
4
|
+
timeline: z.string().describe('Timeline name'),
|
|
5
5
|
contentPath: z.string().describe('Path to timeline content folder'),
|
|
6
6
|
outputPath: z.string().describe('Output PDF file path'),
|
|
7
7
|
episodes: z.string().optional().describe('Comma-separated episode numbers (e.g., "1,2,3")'),
|
|
@@ -9,11 +9,10 @@ export const bookGenerateSchema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
export async function bookGenerate(args) {
|
|
11
11
|
try {
|
|
12
|
-
const timeline = getTimeline();
|
|
13
12
|
await generateBook({
|
|
14
13
|
contentPath: args.contentPath,
|
|
15
14
|
outputPath: args.outputPath,
|
|
16
|
-
timeline,
|
|
15
|
+
timeline: args.timeline,
|
|
17
16
|
episodes: args.episodes,
|
|
18
17
|
format: args.format || 'a4',
|
|
19
18
|
});
|
|
@@ -23,7 +22,7 @@ export async function bookGenerate(args) {
|
|
|
23
22
|
type: 'text',
|
|
24
23
|
text: JSON.stringify({
|
|
25
24
|
success: true,
|
|
26
|
-
timeline,
|
|
25
|
+
timeline: args.timeline,
|
|
27
26
|
outputPath: args.outputPath,
|
|
28
27
|
episodes: args.episodes || 'all',
|
|
29
28
|
format: args.format || 'a4',
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const chapterDeleteSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodString;
|
|
5
6
|
episode: z.ZodNumber;
|
|
6
7
|
chapter: z.ZodNumber;
|
|
7
8
|
file: z.ZodOptional<z.ZodString>;
|
|
8
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
timeline: string;
|
|
9
11
|
arc: string;
|
|
10
12
|
episode: number;
|
|
11
13
|
chapter: number;
|
|
12
14
|
file?: string | undefined;
|
|
13
15
|
}, {
|
|
16
|
+
timeline: string;
|
|
14
17
|
arc: string;
|
|
15
18
|
episode: number;
|
|
16
19
|
chapter: number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unlinkSync } from 'node:fs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getTimeline } from '../utils.js';
|
|
4
3
|
export const chapterDeleteSchema = z.object({
|
|
4
|
+
timeline: z.string().describe('Timeline name'),
|
|
5
5
|
arc: z.string().describe('Arc name'),
|
|
6
6
|
episode: z.number().describe('Episode number'),
|
|
7
7
|
chapter: z.number().describe('Chapter number'),
|
|
@@ -9,12 +9,11 @@ export const chapterDeleteSchema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
export async function chapterDelete(args, tracker) {
|
|
11
11
|
try {
|
|
12
|
-
const
|
|
13
|
-
const existing = await tracker.getChapter(timeline, args.arc, args.episode, args.chapter);
|
|
12
|
+
const existing = await tracker.getChapter(args.timeline, args.arc, args.episode, args.chapter);
|
|
14
13
|
if (!existing) {
|
|
15
|
-
throw new Error(`Chapter not found: ${timeline}/${args.arc}/ep${args.episode}/ch${args.chapter}`);
|
|
14
|
+
throw new Error(`Chapter not found: ${args.timeline}/${args.arc}/ep${args.episode}/ch${args.chapter}`);
|
|
16
15
|
}
|
|
17
|
-
await tracker.deleteChapter(timeline, args.arc, args.episode, args.chapter);
|
|
16
|
+
await tracker.deleteChapter(args.timeline, args.arc, args.episode, args.chapter);
|
|
18
17
|
let fileDeleted = false;
|
|
19
18
|
if (args.file) {
|
|
20
19
|
unlinkSync(args.file);
|
|
@@ -25,7 +24,7 @@ export async function chapterDelete(args, tracker) {
|
|
|
25
24
|
{
|
|
26
25
|
type: 'text',
|
|
27
26
|
text: JSON.stringify({
|
|
28
|
-
timeline,
|
|
27
|
+
timeline: args.timeline,
|
|
29
28
|
arc: args.arc,
|
|
30
29
|
episode: args.episode,
|
|
31
30
|
chapter: args.chapter,
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const chapterInfoSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodString;
|
|
5
6
|
episode: z.ZodNumber;
|
|
6
7
|
chapter: z.ZodNumber;
|
|
7
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
timeline: string;
|
|
8
10
|
arc: string;
|
|
9
11
|
episode: number;
|
|
10
12
|
chapter: number;
|
|
11
13
|
}, {
|
|
14
|
+
timeline: string;
|
|
12
15
|
arc: string;
|
|
13
16
|
episode: number;
|
|
14
17
|
chapter: number;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const chapterInfoSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
arc: z.string().describe('Arc name'),
|
|
5
5
|
episode: z.number().describe('Episode number'),
|
|
6
6
|
chapter: z.number().describe('Chapter number'),
|
|
7
7
|
});
|
|
8
8
|
export async function chapterInfo(args, tracker) {
|
|
9
9
|
try {
|
|
10
|
-
const
|
|
11
|
-
const chapter = await tracker.getChapter(timeline, args.arc, args.episode, args.chapter);
|
|
10
|
+
const chapter = await tracker.getChapter(args.timeline, args.arc, args.episode, args.chapter);
|
|
12
11
|
if (!chapter) {
|
|
13
|
-
throw new Error(`Chapter not found: ${timeline}/${args.arc}/ep${args.episode}/ch${args.chapter}`);
|
|
12
|
+
throw new Error(`Chapter not found: ${args.timeline}/${args.arc}/ep${args.episode}/ch${args.chapter}`);
|
|
14
13
|
}
|
|
15
14
|
return {
|
|
16
15
|
content: [
|
|
17
16
|
{
|
|
18
17
|
type: 'text',
|
|
19
18
|
text: JSON.stringify({
|
|
20
|
-
timeline,
|
|
19
|
+
timeline: args.timeline,
|
|
21
20
|
arc: args.arc,
|
|
22
21
|
episode: args.episode,
|
|
23
22
|
chapter: args.chapter,
|
|
@@ -25,7 +24,7 @@ export async function chapterInfo(args, tracker) {
|
|
|
25
24
|
pov: chapter.pov,
|
|
26
25
|
title: chapter.title,
|
|
27
26
|
date: chapter.date,
|
|
28
|
-
|
|
27
|
+
summary: chapter.summary,
|
|
29
28
|
location: chapter.location,
|
|
30
29
|
outfit: chapter.outfit,
|
|
31
30
|
kink: chapter.kink,
|
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const chapterInsertSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodString;
|
|
5
6
|
episode: z.ZodNumber;
|
|
6
7
|
after: z.ZodNumber;
|
|
7
8
|
pov: z.ZodString;
|
|
8
9
|
title: z.ZodString;
|
|
9
|
-
|
|
10
|
+
summary: z.ZodOptional<z.ZodString>;
|
|
10
11
|
location: z.ZodOptional<z.ZodString>;
|
|
11
12
|
outfit: z.ZodOptional<z.ZodString>;
|
|
12
13
|
kink: z.ZodOptional<z.ZodString>;
|
|
13
14
|
file: z.ZodOptional<z.ZodString>;
|
|
14
15
|
}, "strip", z.ZodTypeAny, {
|
|
16
|
+
timeline: string;
|
|
15
17
|
arc: string;
|
|
16
18
|
episode: number;
|
|
17
19
|
after: number;
|
|
18
20
|
pov: string;
|
|
19
21
|
title: string;
|
|
20
22
|
file?: string | undefined;
|
|
21
|
-
|
|
23
|
+
summary?: string | undefined;
|
|
22
24
|
location?: string | undefined;
|
|
23
25
|
outfit?: string | undefined;
|
|
24
26
|
kink?: string | undefined;
|
|
25
27
|
}, {
|
|
28
|
+
timeline: string;
|
|
26
29
|
arc: string;
|
|
27
30
|
episode: number;
|
|
28
31
|
after: number;
|
|
29
32
|
pov: string;
|
|
30
33
|
title: string;
|
|
31
34
|
file?: string | undefined;
|
|
32
|
-
|
|
35
|
+
summary?: string | undefined;
|
|
33
36
|
location?: string | undefined;
|
|
34
37
|
outfit?: string | undefined;
|
|
35
38
|
kink?: string | undefined;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { getTextStats, parseMarkdown } from '@echoes-io/utils';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getTimeline } from '../utils.js';
|
|
4
3
|
export const chapterInsertSchema = z.object({
|
|
4
|
+
timeline: z.string().describe('Timeline name'),
|
|
5
5
|
arc: z.string().describe('Arc name'),
|
|
6
6
|
episode: z.number().describe('Episode number'),
|
|
7
7
|
after: z.number().describe('Insert after this chapter number'),
|
|
8
8
|
pov: z.string().describe('Point of view character'),
|
|
9
9
|
title: z.string().describe('Chapter title'),
|
|
10
|
-
|
|
10
|
+
summary: z.string().optional().describe('Chapter summary'),
|
|
11
11
|
location: z.string().optional().describe('Chapter location'),
|
|
12
12
|
outfit: z.string().optional().describe('Character outfit'),
|
|
13
13
|
kink: z.string().optional().describe('Content tags'),
|
|
@@ -15,17 +15,16 @@ export const chapterInsertSchema = z.object({
|
|
|
15
15
|
});
|
|
16
16
|
export async function chapterInsert(args, tracker) {
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
const episode = await tracker.getEpisode(timeline, args.arc, args.episode);
|
|
18
|
+
const episode = await tracker.getEpisode(args.timeline, args.arc, args.episode);
|
|
20
19
|
if (!episode) {
|
|
21
|
-
throw new Error(`Episode not found: ${timeline}/${args.arc}/ep${args.episode}`);
|
|
20
|
+
throw new Error(`Episode not found: ${args.timeline}/${args.arc}/ep${args.episode}`);
|
|
22
21
|
}
|
|
23
|
-
const existingChapters = await tracker.getChapters(timeline, args.arc, args.episode);
|
|
22
|
+
const existingChapters = await tracker.getChapters(args.timeline, args.arc, args.episode);
|
|
24
23
|
const newChapterNumber = args.after + 1;
|
|
25
24
|
const chaptersToRenumber = existingChapters.filter((ch) => ch.number >= newChapterNumber);
|
|
26
25
|
for (const chapter of chaptersToRenumber) {
|
|
27
26
|
try {
|
|
28
|
-
await tracker.updateChapter(timeline, args.arc, args.episode, chapter.number, {
|
|
27
|
+
await tracker.updateChapter(args.timeline, args.arc, args.episode, chapter.number, {
|
|
29
28
|
number: chapter.number + 1,
|
|
30
29
|
});
|
|
31
30
|
}
|
|
@@ -49,16 +48,21 @@ export async function chapterInsert(args, tracker) {
|
|
|
49
48
|
paragraphs = stats.paragraphs;
|
|
50
49
|
sentences = stats.sentences;
|
|
51
50
|
}
|
|
52
|
-
|
|
53
|
-
timelineName: timeline,
|
|
51
|
+
const chapterData = {
|
|
52
|
+
timelineName: args.timeline,
|
|
54
53
|
arcName: args.arc,
|
|
55
54
|
episodeNumber: args.episode,
|
|
56
55
|
partNumber: 1,
|
|
57
56
|
number: newChapterNumber,
|
|
57
|
+
timeline: args.timeline,
|
|
58
|
+
arc: args.arc,
|
|
59
|
+
episode: args.episode,
|
|
60
|
+
part: 1,
|
|
61
|
+
chapter: newChapterNumber,
|
|
58
62
|
pov: args.pov,
|
|
59
63
|
title: args.title,
|
|
60
|
-
date: new Date(),
|
|
61
|
-
|
|
64
|
+
date: new Date().toISOString(),
|
|
65
|
+
summary: args.summary || '',
|
|
62
66
|
location: args.location || '',
|
|
63
67
|
outfit: args.outfit || '',
|
|
64
68
|
kink: args.kink || '',
|
|
@@ -68,13 +72,14 @@ export async function chapterInsert(args, tracker) {
|
|
|
68
72
|
paragraphs,
|
|
69
73
|
sentences,
|
|
70
74
|
readingTimeMinutes: Math.ceil(words / 200),
|
|
71
|
-
}
|
|
75
|
+
};
|
|
76
|
+
await tracker.createChapter(chapterData);
|
|
72
77
|
return {
|
|
73
78
|
content: [
|
|
74
79
|
{
|
|
75
80
|
type: 'text',
|
|
76
81
|
text: JSON.stringify({
|
|
77
|
-
timeline,
|
|
82
|
+
timeline: args.timeline,
|
|
78
83
|
arc: args.arc,
|
|
79
84
|
episode: args.episode,
|
|
80
85
|
inserted: {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const chapterRefreshSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
file: z.ZodString;
|
|
5
6
|
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
timeline: string;
|
|
6
8
|
file: string;
|
|
7
9
|
}, {
|
|
10
|
+
timeline: string;
|
|
8
11
|
file: string;
|
|
9
12
|
}>;
|
|
10
13
|
export declare function chapterRefresh(args: z.infer<typeof chapterRefreshSchema>, tracker: Tracker): Promise<{
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { getTextStats, parseMarkdown } from '@echoes-io/utils';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { getTimeline } from '../utils.js';
|
|
5
4
|
export const chapterRefreshSchema = z.object({
|
|
5
|
+
timeline: z.string().describe('Timeline name'),
|
|
6
6
|
file: z.string().describe('Path to chapter markdown file'),
|
|
7
7
|
});
|
|
8
8
|
export async function chapterRefresh(args, tracker) {
|
|
@@ -10,27 +10,26 @@ export async function chapterRefresh(args, tracker) {
|
|
|
10
10
|
const content = readFileSync(args.file, 'utf-8');
|
|
11
11
|
const { metadata, content: markdownContent } = parseMarkdown(content);
|
|
12
12
|
const stats = getTextStats(markdownContent);
|
|
13
|
-
const timeline = getTimeline();
|
|
14
13
|
const arc = metadata.arc;
|
|
15
14
|
const episode = metadata.episode;
|
|
16
15
|
const chapter = metadata.chapter;
|
|
17
16
|
if (!arc || !episode || !chapter) {
|
|
18
17
|
throw new Error('Missing required metadata: arc, episode, or chapter');
|
|
19
18
|
}
|
|
20
|
-
const existing = await tracker.getChapter(timeline, arc, episode, chapter);
|
|
19
|
+
const existing = await tracker.getChapter(args.timeline, arc, episode, chapter);
|
|
21
20
|
if (!existing) {
|
|
22
|
-
throw new Error(`Chapter not found in database: ${timeline}/${arc}/ep${episode}/ch${chapter}`);
|
|
21
|
+
throw new Error(`Chapter not found in database: ${args.timeline}/${arc}/ep${episode}/ch${chapter}`);
|
|
23
22
|
}
|
|
24
23
|
const chapterData = {
|
|
25
|
-
timelineName: timeline,
|
|
24
|
+
timelineName: args.timeline,
|
|
26
25
|
arcName: arc,
|
|
27
26
|
episodeNumber: episode,
|
|
28
27
|
partNumber: metadata.part || 1,
|
|
29
28
|
number: chapter,
|
|
30
29
|
pov: metadata.pov || 'Unknown',
|
|
31
30
|
title: metadata.title || 'Untitled',
|
|
32
|
-
date: new Date(metadata.date || Date.now()),
|
|
33
|
-
|
|
31
|
+
date: new Date(metadata.date || Date.now()).toISOString(),
|
|
32
|
+
summary: metadata.summary || '',
|
|
34
33
|
location: metadata.location || '',
|
|
35
34
|
outfit: metadata.outfit || '',
|
|
36
35
|
kink: metadata.kink || '',
|
|
@@ -41,14 +40,14 @@ export async function chapterRefresh(args, tracker) {
|
|
|
41
40
|
sentences: stats.sentences,
|
|
42
41
|
readingTimeMinutes: Math.ceil(stats.words / 200),
|
|
43
42
|
};
|
|
44
|
-
await tracker.updateChapter(timeline, arc, episode, chapter, chapterData);
|
|
43
|
+
await tracker.updateChapter(args.timeline, arc, episode, chapter, chapterData);
|
|
45
44
|
return {
|
|
46
45
|
content: [
|
|
47
46
|
{
|
|
48
47
|
type: 'text',
|
|
49
48
|
text: JSON.stringify({
|
|
50
49
|
file: args.file,
|
|
51
|
-
timeline,
|
|
50
|
+
timeline: args.timeline,
|
|
52
51
|
arc,
|
|
53
52
|
episode,
|
|
54
53
|
chapter,
|
|
@@ -57,7 +56,7 @@ export async function chapterRefresh(args, tracker) {
|
|
|
57
56
|
pov: chapterData.pov,
|
|
58
57
|
title: chapterData.title,
|
|
59
58
|
date: chapterData.date,
|
|
60
|
-
|
|
59
|
+
summary: chapterData.summary,
|
|
61
60
|
location: chapterData.location,
|
|
62
61
|
},
|
|
63
62
|
stats: {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const episodeInfoSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodString;
|
|
5
6
|
episode: z.ZodNumber;
|
|
6
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
timeline: string;
|
|
7
9
|
arc: string;
|
|
8
10
|
episode: number;
|
|
9
11
|
}, {
|
|
12
|
+
timeline: string;
|
|
10
13
|
arc: string;
|
|
11
14
|
episode: number;
|
|
12
15
|
}>;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const episodeInfoSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
arc: z.string().describe('Arc name'),
|
|
5
5
|
episode: z.number().describe('Episode number'),
|
|
6
6
|
});
|
|
7
7
|
export async function episodeInfo(args, tracker) {
|
|
8
8
|
try {
|
|
9
|
-
const
|
|
10
|
-
const episode = await tracker.getEpisode(timeline, args.arc, args.episode);
|
|
9
|
+
const episode = await tracker.getEpisode(args.timeline, args.arc, args.episode);
|
|
11
10
|
if (!episode) {
|
|
12
|
-
throw new Error(`Episode not found: ${timeline}/${args.arc}/ep${args.episode}`);
|
|
11
|
+
throw new Error(`Episode not found: ${args.timeline}/${args.arc}/ep${args.episode}`);
|
|
13
12
|
}
|
|
14
|
-
const chapters = await tracker.getChapters(timeline, args.arc, args.episode);
|
|
13
|
+
const chapters = await tracker.getChapters(args.timeline, args.arc, args.episode);
|
|
15
14
|
return {
|
|
16
15
|
content: [
|
|
17
16
|
{
|
|
18
17
|
type: 'text',
|
|
19
18
|
text: JSON.stringify({
|
|
20
|
-
timeline,
|
|
19
|
+
timeline: args.timeline,
|
|
21
20
|
arc: args.arc,
|
|
22
21
|
episodeInfo: {
|
|
23
22
|
number: episode.number,
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const episodeUpdateSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodString;
|
|
5
6
|
episode: z.ZodNumber;
|
|
6
7
|
description: z.ZodOptional<z.ZodString>;
|
|
7
8
|
title: z.ZodOptional<z.ZodString>;
|
|
8
9
|
slug: z.ZodOptional<z.ZodString>;
|
|
9
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
timeline: string;
|
|
10
12
|
arc: string;
|
|
11
13
|
episode: number;
|
|
12
14
|
title?: string | undefined;
|
|
13
15
|
description?: string | undefined;
|
|
14
16
|
slug?: string | undefined;
|
|
15
17
|
}, {
|
|
18
|
+
timeline: string;
|
|
16
19
|
arc: string;
|
|
17
20
|
episode: number;
|
|
18
21
|
title?: string | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const episodeUpdateSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
arc: z.string().describe('Arc name'),
|
|
5
5
|
episode: z.number().describe('Episode number'),
|
|
6
6
|
description: z.string().optional().describe('Episode description'),
|
|
@@ -9,10 +9,9 @@ export const episodeUpdateSchema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
export async function episodeUpdate(args, tracker) {
|
|
11
11
|
try {
|
|
12
|
-
const
|
|
13
|
-
const existing = await tracker.getEpisode(timeline, args.arc, args.episode);
|
|
12
|
+
const existing = await tracker.getEpisode(args.timeline, args.arc, args.episode);
|
|
14
13
|
if (!existing) {
|
|
15
|
-
throw new Error(`Episode not found: ${timeline}/${args.arc}/ep${args.episode}`);
|
|
14
|
+
throw new Error(`Episode not found: ${args.timeline}/${args.arc}/ep${args.episode}`);
|
|
16
15
|
}
|
|
17
16
|
const updateData = {};
|
|
18
17
|
if (args.description !== undefined)
|
|
@@ -21,13 +20,13 @@ export async function episodeUpdate(args, tracker) {
|
|
|
21
20
|
updateData.title = args.title;
|
|
22
21
|
if (args.slug !== undefined)
|
|
23
22
|
updateData.slug = args.slug;
|
|
24
|
-
await tracker.updateEpisode(timeline, args.arc, args.episode, updateData);
|
|
23
|
+
await tracker.updateEpisode(args.timeline, args.arc, args.episode, updateData);
|
|
25
24
|
return {
|
|
26
25
|
content: [
|
|
27
26
|
{
|
|
28
27
|
type: 'text',
|
|
29
28
|
text: JSON.stringify({
|
|
30
|
-
timeline,
|
|
29
|
+
timeline: args.timeline,
|
|
31
30
|
arc: args.arc,
|
|
32
31
|
episode: args.episode,
|
|
33
32
|
updated: updateData,
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { RAGSystem } from '@echoes-io/rag';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const ragContextSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
query: z.ZodString;
|
|
5
6
|
arc: z.ZodOptional<z.ZodString>;
|
|
6
7
|
pov: z.ZodOptional<z.ZodString>;
|
|
7
8
|
maxChapters: z.ZodOptional<z.ZodNumber>;
|
|
8
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
timeline: string;
|
|
9
11
|
query: string;
|
|
10
12
|
arc?: string | undefined;
|
|
11
13
|
pov?: string | undefined;
|
|
12
14
|
maxChapters?: number | undefined;
|
|
13
15
|
}, {
|
|
16
|
+
timeline: string;
|
|
14
17
|
query: string;
|
|
15
18
|
arc?: string | undefined;
|
|
16
19
|
pov?: string | undefined;
|
package/lib/tools/rag-context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const ragContextSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
query: z.string().describe('Context query'),
|
|
5
5
|
arc: z.string().optional().describe('Filter by arc name'),
|
|
6
6
|
pov: z.string().optional().describe('Filter by POV character'),
|
|
@@ -8,10 +8,9 @@ export const ragContextSchema = z.object({
|
|
|
8
8
|
});
|
|
9
9
|
export async function ragContext(args, rag) {
|
|
10
10
|
try {
|
|
11
|
-
const timeline = getTimeline();
|
|
12
11
|
const results = await rag.getContext({
|
|
13
12
|
query: args.query,
|
|
14
|
-
timeline,
|
|
13
|
+
timeline: args.timeline,
|
|
15
14
|
arc: args.arc,
|
|
16
15
|
pov: args.pov,
|
|
17
16
|
maxChapters: args.maxChapters,
|
|
@@ -22,7 +21,7 @@ export async function ragContext(args, rag) {
|
|
|
22
21
|
type: 'text',
|
|
23
22
|
text: JSON.stringify({
|
|
24
23
|
query: args.query,
|
|
25
|
-
timeline,
|
|
24
|
+
timeline: args.timeline,
|
|
26
25
|
filters: {
|
|
27
26
|
arc: args.arc || null,
|
|
28
27
|
pov: args.pov || null,
|
package/lib/tools/rag-index.d.ts
CHANGED
|
@@ -2,14 +2,17 @@ import type { RAGSystem } from '@echoes-io/rag';
|
|
|
2
2
|
import type { Tracker } from '@echoes-io/tracker';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
export declare const ragIndexSchema: z.ZodObject<{
|
|
5
|
+
timeline: z.ZodString;
|
|
5
6
|
contentPath: z.ZodOptional<z.ZodString>;
|
|
6
7
|
arc: z.ZodOptional<z.ZodString>;
|
|
7
8
|
episode: z.ZodOptional<z.ZodNumber>;
|
|
8
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
timeline: string;
|
|
9
11
|
contentPath?: string | undefined;
|
|
10
12
|
arc?: string | undefined;
|
|
11
13
|
episode?: number | undefined;
|
|
12
14
|
}, {
|
|
15
|
+
timeline: string;
|
|
13
16
|
contentPath?: string | undefined;
|
|
14
17
|
arc?: string | undefined;
|
|
15
18
|
episode?: number | undefined;
|
package/lib/tools/rag-index.js
CHANGED
|
@@ -2,33 +2,32 @@ import { readdirSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { parseMarkdown } from '@echoes-io/utils';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { getTimeline } from '../utils.js';
|
|
6
5
|
export const ragIndexSchema = z.object({
|
|
6
|
+
timeline: z.string().describe('Timeline name'),
|
|
7
7
|
contentPath: z.string().optional().describe('Path to content directory (required for indexing)'),
|
|
8
8
|
arc: z.string().optional().describe('Index specific arc only'),
|
|
9
9
|
episode: z.number().optional().describe('Index specific episode only (requires arc)'),
|
|
10
10
|
});
|
|
11
11
|
export async function ragIndex(args, tracker, rag) {
|
|
12
12
|
try {
|
|
13
|
-
const timeline = getTimeline();
|
|
14
13
|
let chapters = [];
|
|
15
14
|
// Get chapters based on filters
|
|
16
15
|
if (args.arc && args.episode) {
|
|
17
|
-
chapters = await tracker.getChapters(timeline, args.arc, args.episode);
|
|
16
|
+
chapters = await tracker.getChapters(args.timeline, args.arc, args.episode);
|
|
18
17
|
}
|
|
19
18
|
else if (args.arc) {
|
|
20
|
-
const episodes = await tracker.getEpisodes(timeline, args.arc);
|
|
19
|
+
const episodes = await tracker.getEpisodes(args.timeline, args.arc);
|
|
21
20
|
for (const ep of episodes) {
|
|
22
|
-
const epChapters = await tracker.getChapters(timeline, args.arc, ep.number);
|
|
21
|
+
const epChapters = await tracker.getChapters(args.timeline, args.arc, ep.number);
|
|
23
22
|
chapters.push(...epChapters);
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
else {
|
|
27
|
-
const arcs = await tracker.getArcs(timeline);
|
|
26
|
+
const arcs = await tracker.getArcs(args.timeline);
|
|
28
27
|
for (const arc of arcs) {
|
|
29
|
-
const episodes = await tracker.getEpisodes(timeline, arc.name);
|
|
28
|
+
const episodes = await tracker.getEpisodes(args.timeline, arc.name);
|
|
30
29
|
for (const ep of episodes) {
|
|
31
|
-
const epChapters = await tracker.getChapters(timeline, arc.name, ep.number);
|
|
30
|
+
const epChapters = await tracker.getChapters(args.timeline, arc.name, ep.number);
|
|
32
31
|
chapters.push(...epChapters);
|
|
33
32
|
}
|
|
34
33
|
}
|
|
@@ -85,7 +84,7 @@ export async function ragIndex(args, tracker, rag) {
|
|
|
85
84
|
type: 'text',
|
|
86
85
|
text: JSON.stringify({
|
|
87
86
|
indexed: embeddingChapters.length,
|
|
88
|
-
timeline,
|
|
87
|
+
timeline: args.timeline,
|
|
89
88
|
arc: args.arc || 'all',
|
|
90
89
|
episode: args.episode || 'all',
|
|
91
90
|
}, null, 2),
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { RAGSystem } from '@echoes-io/rag';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const ragSearchSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
query: z.ZodString;
|
|
5
6
|
arc: z.ZodOptional<z.ZodString>;
|
|
6
7
|
pov: z.ZodOptional<z.ZodString>;
|
|
7
8
|
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
8
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
timeline: string;
|
|
9
11
|
query: string;
|
|
10
12
|
arc?: string | undefined;
|
|
11
13
|
pov?: string | undefined;
|
|
12
14
|
maxResults?: number | undefined;
|
|
13
15
|
}, {
|
|
16
|
+
timeline: string;
|
|
14
17
|
query: string;
|
|
15
18
|
arc?: string | undefined;
|
|
16
19
|
pov?: string | undefined;
|
package/lib/tools/rag-search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const ragSearchSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
query: z.string().describe('Search query'),
|
|
5
5
|
arc: z.string().optional().describe('Filter by arc name'),
|
|
6
6
|
pov: z.string().optional().describe('Filter by POV character'),
|
|
@@ -8,9 +8,8 @@ export const ragSearchSchema = z.object({
|
|
|
8
8
|
});
|
|
9
9
|
export async function ragSearch(args, rag) {
|
|
10
10
|
try {
|
|
11
|
-
const timeline = getTimeline();
|
|
12
11
|
const results = await rag.search(args.query, {
|
|
13
|
-
timeline,
|
|
12
|
+
timeline: args.timeline,
|
|
14
13
|
arc: args.arc,
|
|
15
14
|
pov: args.pov,
|
|
16
15
|
maxResults: args.maxResults,
|
|
@@ -21,7 +20,7 @@ export async function ragSearch(args, rag) {
|
|
|
21
20
|
type: 'text',
|
|
22
21
|
text: JSON.stringify({
|
|
23
22
|
query: args.query,
|
|
24
|
-
timeline,
|
|
23
|
+
timeline: args.timeline,
|
|
25
24
|
filters: {
|
|
26
25
|
arc: args.arc || null,
|
|
27
26
|
pov: args.pov || null,
|
package/lib/tools/stats.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const statsSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
arc: z.ZodOptional<z.ZodString>;
|
|
5
6
|
episode: z.ZodOptional<z.ZodNumber>;
|
|
6
7
|
pov: z.ZodOptional<z.ZodString>;
|
|
7
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
timeline: string;
|
|
8
10
|
arc?: string | undefined;
|
|
9
11
|
episode?: number | undefined;
|
|
10
12
|
pov?: string | undefined;
|
|
11
13
|
}, {
|
|
14
|
+
timeline: string;
|
|
12
15
|
arc?: string | undefined;
|
|
13
16
|
episode?: number | undefined;
|
|
14
17
|
pov?: string | undefined;
|
package/lib/tools/stats.js
CHANGED
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getTimeline } from '../utils.js';
|
|
3
2
|
export const statsSchema = z.object({
|
|
3
|
+
timeline: z.string().describe('Timeline name'),
|
|
4
4
|
arc: z.string().optional().describe('Filter by arc name'),
|
|
5
5
|
episode: z.number().optional().describe('Filter by episode number'),
|
|
6
6
|
pov: z.string().optional().describe('Filter by POV character'),
|
|
7
7
|
});
|
|
8
8
|
export async function stats(args, tracker) {
|
|
9
9
|
try {
|
|
10
|
-
const timeline = getTimeline();
|
|
11
10
|
let chapters = [];
|
|
12
11
|
// Get chapters based on filters
|
|
13
12
|
if (args.arc && args.episode) {
|
|
14
|
-
chapters = await tracker.getChapters(timeline, args.arc, args.episode);
|
|
13
|
+
chapters = await tracker.getChapters(args.timeline, args.arc, args.episode);
|
|
15
14
|
}
|
|
16
15
|
else if (args.arc) {
|
|
17
|
-
const episodes = await tracker.getEpisodes(timeline, args.arc);
|
|
16
|
+
const episodes = await tracker.getEpisodes(args.timeline, args.arc);
|
|
18
17
|
for (const ep of episodes) {
|
|
19
|
-
const epChapters = await tracker.getChapters(timeline, args.arc, ep.number);
|
|
18
|
+
const epChapters = await tracker.getChapters(args.timeline, args.arc, ep.number);
|
|
20
19
|
chapters.push(...epChapters);
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
else {
|
|
24
|
-
const arcs = await tracker.getArcs(timeline);
|
|
23
|
+
const arcs = await tracker.getArcs(args.timeline);
|
|
25
24
|
for (const arc of arcs) {
|
|
26
|
-
const episodes = await tracker.getEpisodes(timeline, arc.name);
|
|
25
|
+
const episodes = await tracker.getEpisodes(args.timeline, arc.name);
|
|
27
26
|
for (const ep of episodes) {
|
|
28
|
-
const epChapters = await tracker.getChapters(timeline, arc.name, ep.number);
|
|
27
|
+
const epChapters = await tracker.getChapters(args.timeline, arc.name, ep.number);
|
|
29
28
|
chapters.push(...epChapters);
|
|
30
29
|
}
|
|
31
30
|
}
|
|
@@ -70,7 +69,7 @@ export async function stats(args, tracker) {
|
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
const result = {
|
|
73
|
-
timeline,
|
|
72
|
+
timeline: args.timeline,
|
|
74
73
|
filters: {
|
|
75
74
|
arc: args.arc || null,
|
|
76
75
|
episode: args.episode || null,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { Tracker } from '@echoes-io/tracker';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare const timelineSyncSchema: z.ZodObject<{
|
|
4
|
+
timeline: z.ZodString;
|
|
4
5
|
contentPath: z.ZodString;
|
|
5
6
|
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
timeline: string;
|
|
6
8
|
contentPath: string;
|
|
7
9
|
}, {
|
|
10
|
+
timeline: string;
|
|
8
11
|
contentPath: string;
|
|
9
12
|
}>;
|
|
10
13
|
export declare function timelineSync(args: z.infer<typeof timelineSyncSchema>, tracker: Tracker): Promise<{
|
|
@@ -2,19 +2,18 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { extname, join } from 'node:path';
|
|
3
3
|
import { getTextStats, parseMarkdown } from '@echoes-io/utils';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { getTimeline } from '../utils.js';
|
|
6
5
|
export const timelineSyncSchema = z.object({
|
|
6
|
+
timeline: z.string().describe('Timeline name'),
|
|
7
7
|
contentPath: z.string().describe('Path to content directory'),
|
|
8
8
|
});
|
|
9
9
|
export async function timelineSync(args, tracker) {
|
|
10
10
|
try {
|
|
11
|
-
const timeline = getTimeline();
|
|
12
11
|
let added = 0, updated = 0, deleted = 0, errors = 0;
|
|
13
|
-
let timelineRecord = await tracker.getTimeline(timeline);
|
|
12
|
+
let timelineRecord = await tracker.getTimeline(args.timeline);
|
|
14
13
|
if (!timelineRecord) {
|
|
15
14
|
timelineRecord = await tracker.createTimeline({
|
|
16
|
-
name: timeline,
|
|
17
|
-
description: `Timeline ${timeline}`,
|
|
15
|
+
name: args.timeline,
|
|
16
|
+
description: `Timeline ${args.timeline}`,
|
|
18
17
|
});
|
|
19
18
|
added++;
|
|
20
19
|
}
|
|
@@ -23,10 +22,10 @@ export async function timelineSync(args, tracker) {
|
|
|
23
22
|
.map((entry) => entry.name);
|
|
24
23
|
for (const arcName of arcs) {
|
|
25
24
|
const arcPath = join(args.contentPath, arcName);
|
|
26
|
-
let arc = await tracker.getArc(timeline, arcName);
|
|
25
|
+
let arc = await tracker.getArc(args.timeline, arcName);
|
|
27
26
|
if (!arc) {
|
|
28
27
|
arc = await tracker.createArc({
|
|
29
|
-
timelineName: timeline,
|
|
28
|
+
timelineName: args.timeline,
|
|
30
29
|
name: arcName,
|
|
31
30
|
number: 1,
|
|
32
31
|
description: `Arc ${arcName}`,
|
|
@@ -41,11 +40,11 @@ export async function timelineSync(args, tracker) {
|
|
|
41
40
|
}));
|
|
42
41
|
for (const ep of episodes) {
|
|
43
42
|
const episodePath = join(arcPath, ep.name);
|
|
44
|
-
let episode = await tracker.getEpisode(timeline, arcName, ep.number);
|
|
43
|
+
let episode = await tracker.getEpisode(args.timeline, arcName, ep.number);
|
|
45
44
|
if (!episode) {
|
|
46
45
|
try {
|
|
47
46
|
episode = await tracker.createEpisode({
|
|
48
|
-
timelineName: timeline,
|
|
47
|
+
timelineName: args.timeline,
|
|
49
48
|
arcName: arcName,
|
|
50
49
|
number: ep.number,
|
|
51
50
|
slug: ep.name,
|
|
@@ -57,7 +56,7 @@ export async function timelineSync(args, tracker) {
|
|
|
57
56
|
catch (error) {
|
|
58
57
|
console.error(`Error creating episode ${arcName}/ep${ep.number}:`, error instanceof Error ? error.message : error);
|
|
59
58
|
errors++;
|
|
60
|
-
continue;
|
|
59
|
+
continue;
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
const chapters = readdirSync(episodePath)
|
|
@@ -80,15 +79,13 @@ export async function timelineSync(args, tracker) {
|
|
|
80
79
|
}
|
|
81
80
|
})
|
|
82
81
|
.filter((ch) => ch !== null);
|
|
83
|
-
// Collect unique part numbers
|
|
84
82
|
const partNumbers = new Set(chapters.map((ch) => ch?.metadata.part || 1));
|
|
85
|
-
// Create parts if they don't exist
|
|
86
83
|
for (const partNum of partNumbers) {
|
|
87
84
|
try {
|
|
88
|
-
const existingPart = await tracker.getPart(timeline, arcName, ep.number, partNum);
|
|
85
|
+
const existingPart = await tracker.getPart(args.timeline, arcName, ep.number, partNum);
|
|
89
86
|
if (!existingPart) {
|
|
90
87
|
await tracker.createPart({
|
|
91
|
-
timelineName: timeline,
|
|
88
|
+
timelineName: args.timeline,
|
|
92
89
|
arcName: arcName,
|
|
93
90
|
episodeNumber: ep.number,
|
|
94
91
|
number: partNum,
|
|
@@ -111,17 +108,22 @@ export async function timelineSync(args, tracker) {
|
|
|
111
108
|
if (!chNumber)
|
|
112
109
|
continue;
|
|
113
110
|
try {
|
|
114
|
-
const existing = await tracker.getChapter(timeline, arcName, ep.number, chNumber);
|
|
111
|
+
const existing = await tracker.getChapter(args.timeline, arcName, ep.number, chNumber);
|
|
115
112
|
const data = {
|
|
116
|
-
timelineName: timeline,
|
|
113
|
+
timelineName: args.timeline,
|
|
117
114
|
arcName: arcName,
|
|
118
115
|
episodeNumber: ep.number,
|
|
119
116
|
partNumber: chapterData.metadata.part || 1,
|
|
120
117
|
number: chNumber,
|
|
118
|
+
timeline: args.timeline,
|
|
119
|
+
arc: arcName,
|
|
120
|
+
episode: ep.number,
|
|
121
|
+
part: chapterData.metadata.part || 1,
|
|
122
|
+
chapter: chNumber,
|
|
121
123
|
pov: chapterData.metadata.pov || 'Unknown',
|
|
122
124
|
title: chapterData.metadata.title || 'Untitled',
|
|
123
|
-
date: new Date(chapterData.metadata.date || Date.now()),
|
|
124
|
-
|
|
125
|
+
date: new Date(chapterData.metadata.date || Date.now()).toISOString(),
|
|
126
|
+
summary: chapterData.metadata.summary || '',
|
|
125
127
|
location: chapterData.metadata.location || '',
|
|
126
128
|
outfit: chapterData.metadata.outfit || '',
|
|
127
129
|
kink: chapterData.metadata.kink || '',
|
|
@@ -133,7 +135,7 @@ export async function timelineSync(args, tracker) {
|
|
|
133
135
|
readingTimeMinutes: Math.ceil(chapterData.stats.words / 200),
|
|
134
136
|
};
|
|
135
137
|
if (existing) {
|
|
136
|
-
await tracker.updateChapter(timeline, arcName, ep.number, chNumber, data);
|
|
138
|
+
await tracker.updateChapter(args.timeline, arcName, ep.number, chNumber, data);
|
|
137
139
|
updated++;
|
|
138
140
|
}
|
|
139
141
|
else {
|
|
@@ -148,11 +150,11 @@ export async function timelineSync(args, tracker) {
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
try {
|
|
151
|
-
const dbArcs = await tracker.getArcs(timeline);
|
|
153
|
+
const dbArcs = await tracker.getArcs(args.timeline);
|
|
152
154
|
for (const arc of dbArcs) {
|
|
153
|
-
const dbEpisodes = await tracker.getEpisodes(timeline, arc.name);
|
|
155
|
+
const dbEpisodes = await tracker.getEpisodes(args.timeline, arc.name);
|
|
154
156
|
for (const episode of dbEpisodes) {
|
|
155
|
-
const allChapters = await tracker.getChapters(timeline, arc.name, episode.number);
|
|
157
|
+
const allChapters = await tracker.getChapters(args.timeline, arc.name, episode.number);
|
|
156
158
|
for (const dbChapter of allChapters) {
|
|
157
159
|
let fileExists = false;
|
|
158
160
|
try {
|
|
@@ -195,7 +197,7 @@ export async function timelineSync(args, tracker) {
|
|
|
195
197
|
{
|
|
196
198
|
type: 'text',
|
|
197
199
|
text: JSON.stringify({
|
|
198
|
-
timeline,
|
|
200
|
+
timeline: args.timeline,
|
|
199
201
|
contentPath: args.contentPath,
|
|
200
202
|
summary: {
|
|
201
203
|
added,
|
package/lib/utils.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
package/lib/utils.js
CHANGED
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
if (!timeline) {
|
|
4
|
-
throw new Error('ECHOES_TIMELINE environment variable is not set');
|
|
5
|
-
}
|
|
6
|
-
return timeline;
|
|
7
|
-
}
|
|
1
|
+
export {};
|
|
2
|
+
// Removed getTimeline() - timeline is now a required parameter for all tools
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@echoes-io/mcp-server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"description": "Model Context Protocol server for AI integration with Echoes storytelling platform",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "tsx cli/index.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"lint:publish": "publint --strict",
|
|
14
14
|
"test": "vitest run",
|
|
15
15
|
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"check": "npm run clean && npm run test:coverage && npm run build && npm run lint && npm run clean",
|
|
16
17
|
"prepare": "[ \"$CI\" = \"true\" ] || [ \"$GITHUB_ACTIONS\" = \"true\" ] && echo 'Skipping husky' && exit 0 || husky",
|
|
17
18
|
"clean": "rimraf --glob ./{cli,lib,test}/**/*.{d.ts,js} ./vitest*.{d.ts,js}",
|
|
18
19
|
"prebuild": "npm run clean",
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
]
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@biomejs/biome": "^2.2
|
|
66
|
+
"@biomejs/biome": "^2.3.2",
|
|
66
67
|
"@semantic-release/changelog": "^6.0.3",
|
|
67
68
|
"@semantic-release/git": "^10.0.1",
|
|
68
69
|
"@tsconfig/node22": "^22.0.2",
|
|
@@ -81,11 +82,11 @@
|
|
|
81
82
|
"vitest": "^3.2.4"
|
|
82
83
|
},
|
|
83
84
|
"dependencies": {
|
|
84
|
-
"@echoes-io/books-generator": "^1.0.
|
|
85
|
-
"@echoes-io/models": "^1.0.
|
|
85
|
+
"@echoes-io/books-generator": "^1.0.1",
|
|
86
|
+
"@echoes-io/models": "^1.0.2",
|
|
86
87
|
"@echoes-io/rag": "^1.1.2",
|
|
87
|
-
"@echoes-io/tracker": "^1.0.
|
|
88
|
-
"@echoes-io/utils": "^1.
|
|
88
|
+
"@echoes-io/tracker": "^1.0.1",
|
|
89
|
+
"@echoes-io/utils": "^1.2.0",
|
|
89
90
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
90
91
|
}
|
|
91
92
|
}
|