rewind-mcp-server 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.
- package/README.md +140 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +62 -0
- package/dist/client.js.map +1 -0
- package/dist/consent.d.ts +10 -0
- package/dist/consent.js +148 -0
- package/dist/consent.js.map +1 -0
- package/dist/github-auth.d.ts +21 -0
- package/dist/github-auth.js +60 -0
- package/dist/github-auth.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +93 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +3 -0
- package/dist/resources.js +80 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +59 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/collecting.d.ts +3 -0
- package/dist/tools/collecting.js +92 -0
- package/dist/tools/collecting.js.map +1 -0
- package/dist/tools/cross-domain.d.ts +3 -0
- package/dist/tools/cross-domain.js +114 -0
- package/dist/tools/cross-domain.js.map +1 -0
- package/dist/tools/helpers.d.ts +32 -0
- package/dist/tools/helpers.js +69 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/listening.d.ts +3 -0
- package/dist/tools/listening.js +176 -0
- package/dist/tools/listening.js.map +1 -0
- package/dist/tools/reading.d.ts +3 -0
- package/dist/tools/reading.js +85 -0
- package/dist/tools/reading.js.map +1 -0
- package/dist/tools/running.d.ts +3 -0
- package/dist/tools/running.js +135 -0
- package/dist/tools/running.js.map +1 -0
- package/dist/tools/watching.d.ts +3 -0
- package/dist/tools/watching.js +138 -0
- package/dist/tools/watching.js.map +1 -0
- package/dist/worker.d.ts +20 -0
- package/dist/worker.js +173 -0
- package/dist/worker.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { fmt } from './tools/helpers.js';
|
|
3
|
+
export function registerResources(server, client) {
|
|
4
|
+
// Sync status resource
|
|
5
|
+
server.resource('sync-status', 'rewind://sync/status', {
|
|
6
|
+
description: 'Current sync health and last sync times for each data domain',
|
|
7
|
+
}, async (uri) => {
|
|
8
|
+
const data = await client.get('/health/sync');
|
|
9
|
+
const lines = ['Sync Status:'];
|
|
10
|
+
for (const [domain, info] of Object.entries(data.domains)) {
|
|
11
|
+
const lastSync = info.last_sync
|
|
12
|
+
? new Date(info.last_sync).toLocaleString()
|
|
13
|
+
: 'never';
|
|
14
|
+
const items = info.items_synced !== null
|
|
15
|
+
? ` (${fmt(info.items_synced)} items)`
|
|
16
|
+
: '';
|
|
17
|
+
lines.push(`${domain}: ${info.status} -- last sync: ${lastSync}${items}`);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
contents: [
|
|
21
|
+
{ uri: uri.href, text: lines.join('\n'), mimeType: 'text/plain' },
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
// Listening year-in-review
|
|
26
|
+
server.resource('listening-year', new ResourceTemplate('rewind://listening/year/{year}', {
|
|
27
|
+
list: undefined,
|
|
28
|
+
}), {
|
|
29
|
+
description: 'Listening year-in-review statistics for a given year',
|
|
30
|
+
}, async (uri, params) => {
|
|
31
|
+
const year = params.year;
|
|
32
|
+
const data = await client.get(`/listening/year/${year}`);
|
|
33
|
+
return {
|
|
34
|
+
contents: [
|
|
35
|
+
{
|
|
36
|
+
uri: uri.href,
|
|
37
|
+
text: JSON.stringify(data, null, 2),
|
|
38
|
+
mimeType: 'application/json',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
// Running year-in-review
|
|
44
|
+
server.resource('running-year', new ResourceTemplate('rewind://running/year/{year}', {
|
|
45
|
+
list: undefined,
|
|
46
|
+
}), {
|
|
47
|
+
description: 'Running year-in-review statistics for a given year',
|
|
48
|
+
}, async (uri, params) => {
|
|
49
|
+
const year = params.year;
|
|
50
|
+
const data = await client.get(`/running/year/${year}`);
|
|
51
|
+
return {
|
|
52
|
+
contents: [
|
|
53
|
+
{
|
|
54
|
+
uri: uri.href,
|
|
55
|
+
text: JSON.stringify(data, null, 2),
|
|
56
|
+
mimeType: 'application/json',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
// Watching year-in-review
|
|
62
|
+
server.resource('watching-year', new ResourceTemplate('rewind://watching/year/{year}', {
|
|
63
|
+
list: undefined,
|
|
64
|
+
}), {
|
|
65
|
+
description: 'Watching year-in-review statistics for a given year',
|
|
66
|
+
}, async (uri, params) => {
|
|
67
|
+
const year = params.year;
|
|
68
|
+
const data = await client.get(`/watching/year/${year}`);
|
|
69
|
+
return {
|
|
70
|
+
contents: [
|
|
71
|
+
{
|
|
72
|
+
uri: uri.href,
|
|
73
|
+
text: JSON.stringify(data, null, 2),
|
|
74
|
+
mimeType: 'application/json',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP server factory.
|
|
3
|
+
* Used by both the stdio entry point (index.ts) and the remote Worker entry point (worker.ts).
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { RewindClient } from './client.js';
|
|
7
|
+
export declare function createServer(client: RewindClient): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP server factory.
|
|
3
|
+
* Used by both the stdio entry point (index.ts) and the remote Worker entry point (worker.ts).
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { READ_ONLY_ANNOTATIONS } from './tools/helpers.js';
|
|
7
|
+
import { registerListeningTools } from './tools/listening.js';
|
|
8
|
+
import { registerRunningTools } from './tools/running.js';
|
|
9
|
+
import { registerWatchingTools } from './tools/watching.js';
|
|
10
|
+
import { registerCollectingTools } from './tools/collecting.js';
|
|
11
|
+
import { registerReadingTools } from './tools/reading.js';
|
|
12
|
+
import { registerCrossDomainTools } from './tools/cross-domain.js';
|
|
13
|
+
import { registerResources } from './resources.js';
|
|
14
|
+
import { registerPrompts } from './prompts.js';
|
|
15
|
+
export function createServer(client) {
|
|
16
|
+
const server = new McpServer({
|
|
17
|
+
name: 'rewind',
|
|
18
|
+
version: '0.1.0',
|
|
19
|
+
});
|
|
20
|
+
// System tool
|
|
21
|
+
server.tool('get_health', 'Check the health and sync status of the Rewind API. Returns API status and last sync times for each data domain.', {}, READ_ONLY_ANNOTATIONS, async () => {
|
|
22
|
+
try {
|
|
23
|
+
const health = await client.get('/health');
|
|
24
|
+
const syncHealth = await client.get('/health/sync');
|
|
25
|
+
const lines = [`API Status: ${health.status}`, ''];
|
|
26
|
+
for (const [domain, info] of Object.entries(syncHealth.domains)) {
|
|
27
|
+
const lastSync = info.last_sync
|
|
28
|
+
? new Date(info.last_sync).toLocaleString()
|
|
29
|
+
: 'never';
|
|
30
|
+
const items = info.items_synced !== null ? ` (${info.items_synced} items)` : '';
|
|
31
|
+
lines.push(`${domain}: ${info.status} -- last sync: ${lastSync}${items}`);
|
|
32
|
+
}
|
|
33
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: 'text',
|
|
40
|
+
text: `Failed to check health: ${error instanceof Error ? error.message : String(error)}`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// Register all domain tools
|
|
48
|
+
registerListeningTools(server, client);
|
|
49
|
+
registerRunningTools(server, client);
|
|
50
|
+
registerWatchingTools(server, client);
|
|
51
|
+
registerCollectingTools(server, client);
|
|
52
|
+
registerReadingTools(server, client);
|
|
53
|
+
registerCrossDomainTools(server, client);
|
|
54
|
+
// Register resources and prompts
|
|
55
|
+
registerResources(server, client);
|
|
56
|
+
registerPrompts(server);
|
|
57
|
+
return server;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { withErrorHandling, fmt, READ_ONLY_ANNOTATIONS, dateFilterParams, } from './helpers.js';
|
|
3
|
+
export function registerCollectingTools(server, client) {
|
|
4
|
+
// get_vinyl_collection
|
|
5
|
+
server.tool('get_vinyl_collection', 'Browse the vinyl record collection from Discogs. Returns records with artist, title, year, format, and label. Supports search by artist or title, and pagination.', {
|
|
6
|
+
query: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe("Optional: search by artist or album title (e.g. 'Beastie Boys', 'Dark Side')"),
|
|
10
|
+
format: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Optional: filter by format (e.g. 'Vinyl', 'CD', 'Cassette')"),
|
|
14
|
+
genre: z.string().optional().describe('Optional: filter by genre'),
|
|
15
|
+
artist: z.string().optional().describe('Optional: filter by artist name'),
|
|
16
|
+
sort: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Optional: sort field (default: date_added). Options: date_added, title, year, artist'),
|
|
20
|
+
order: z
|
|
21
|
+
.enum(['asc', 'desc'])
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Optional: sort order (default: desc)'),
|
|
24
|
+
limit: z
|
|
25
|
+
.number()
|
|
26
|
+
.min(1)
|
|
27
|
+
.max(50)
|
|
28
|
+
.default(10)
|
|
29
|
+
.describe('Number of records to return'),
|
|
30
|
+
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
31
|
+
...dateFilterParams,
|
|
32
|
+
}, READ_ONLY_ANNOTATIONS, async ({ query, format, genre, artist, sort, order, limit, page, date, from, to, }) => withErrorHandling(async () => {
|
|
33
|
+
const data = await client.get('/collecting/vinyl', {
|
|
34
|
+
q: query,
|
|
35
|
+
format,
|
|
36
|
+
genre,
|
|
37
|
+
artist,
|
|
38
|
+
sort,
|
|
39
|
+
order,
|
|
40
|
+
limit,
|
|
41
|
+
page,
|
|
42
|
+
date,
|
|
43
|
+
from,
|
|
44
|
+
to,
|
|
45
|
+
});
|
|
46
|
+
if (!data.data.length)
|
|
47
|
+
return 'No vinyl records found.';
|
|
48
|
+
const lines = [
|
|
49
|
+
`Vinyl Collection (page ${data.pagination.page} of ${data.pagination.total_pages}, ${fmt(data.pagination.total)} total):`,
|
|
50
|
+
];
|
|
51
|
+
for (const [i, r] of data.data.entries()) {
|
|
52
|
+
const num = (data.pagination.page - 1) * data.pagination.limit + i + 1;
|
|
53
|
+
const artist = r.artists.join(', ');
|
|
54
|
+
const year = r.year ? ` (${r.year})` : '';
|
|
55
|
+
const format = r.format_detail
|
|
56
|
+
? ` [${r.format_detail}]`
|
|
57
|
+
: ` [${r.format}]`;
|
|
58
|
+
lines.push(`${num}. ${artist} -- ${r.title}${year}${format} (${r.label})`);
|
|
59
|
+
}
|
|
60
|
+
if (data.pagination.total_pages > data.pagination.page) {
|
|
61
|
+
lines.push(`\nPage ${data.pagination.page} of ${data.pagination.total_pages}. Use page=${data.pagination.page + 1} to see more.`);
|
|
62
|
+
}
|
|
63
|
+
return lines.join('\n');
|
|
64
|
+
}));
|
|
65
|
+
// get_collecting_stats
|
|
66
|
+
server.tool('get_collecting_stats', 'Get overall collection statistics including total items, format breakdown (vinyl, CD, cassette), unique artists, genre data, and year range. Supports date filtering.', { ...dateFilterParams }, READ_ONLY_ANNOTATIONS, async ({ date, from, to }) => withErrorHandling(async () => {
|
|
67
|
+
const { data } = await client.get('/collecting/stats', { date, from, to });
|
|
68
|
+
const lines = [
|
|
69
|
+
'Collection Stats:',
|
|
70
|
+
`- Total items: ${fmt(data.total_items)}`,
|
|
71
|
+
];
|
|
72
|
+
if (data.by_format && Object.keys(data.by_format).length) {
|
|
73
|
+
lines.push('- By format:');
|
|
74
|
+
for (const [format, count] of Object.entries(data.by_format)) {
|
|
75
|
+
lines.push(` ${format}: ${fmt(count)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (data.unique_artists)
|
|
79
|
+
lines.push(`- Unique artists: ${fmt(data.unique_artists)}`);
|
|
80
|
+
if (data.top_genre)
|
|
81
|
+
lines.push(`- Top genre: ${data.top_genre}`);
|
|
82
|
+
if (data.wantlist_count)
|
|
83
|
+
lines.push(`- Wantlist: ${fmt(data.wantlist_count)}`);
|
|
84
|
+
if (data.oldest_release_year && data.newest_release_year) {
|
|
85
|
+
lines.push(`- Year range: ${data.oldest_release_year} -- ${data.newest_release_year}`);
|
|
86
|
+
}
|
|
87
|
+
if (data.added_this_year)
|
|
88
|
+
lines.push(`- Added this year: ${data.added_this_year}`);
|
|
89
|
+
return lines.join('\n');
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=collecting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collecting.js","sourceRoot":"","sources":["../../src/tools/collecting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { withErrorHandling, timeAgo, fmt, READ_ONLY_ANNOTATIONS, } from './helpers.js';
|
|
3
|
+
export function registerCrossDomainTools(server, client) {
|
|
4
|
+
// search
|
|
5
|
+
server.tool('search', 'Search across all domains (listening, running, watching, collecting, reading) using full-text search. Returns matching artists, albums, movies, articles, runs, and more.', {
|
|
6
|
+
query: z.string().describe('Search query text'),
|
|
7
|
+
domain: z
|
|
8
|
+
.enum(['listening', 'running', 'watching', 'collecting', 'reading'])
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('Optional: filter results to a single domain'),
|
|
11
|
+
limit: z
|
|
12
|
+
.number()
|
|
13
|
+
.min(1)
|
|
14
|
+
.max(50)
|
|
15
|
+
.default(10)
|
|
16
|
+
.describe('Number of results to return'),
|
|
17
|
+
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
18
|
+
}, READ_ONLY_ANNOTATIONS, async ({ query, domain, limit, page }) => withErrorHandling(async () => {
|
|
19
|
+
const params = {
|
|
20
|
+
q: query,
|
|
21
|
+
limit,
|
|
22
|
+
page,
|
|
23
|
+
};
|
|
24
|
+
if (domain)
|
|
25
|
+
params.domain = domain;
|
|
26
|
+
const data = await client.get('/search', params);
|
|
27
|
+
if (!data.data.length)
|
|
28
|
+
return `No results found for "${query}"${domain ? ` in ${domain}` : ''}.`;
|
|
29
|
+
const lines = [
|
|
30
|
+
`Search results for "${query}" (${fmt(data.pagination.total)} total):`,
|
|
31
|
+
];
|
|
32
|
+
for (const [i, r] of data.data.entries()) {
|
|
33
|
+
const sub = r.subtitle ? ` -- ${r.subtitle}` : '';
|
|
34
|
+
lines.push(`${i + 1}. [${r.domain}/${r.entity_type}] ${r.title}${sub}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}));
|
|
38
|
+
// get_feed
|
|
39
|
+
server.tool('get_feed', 'Get the unified activity feed across all domains. Returns a chronological list of recent activities (listens, runs, watches, reads, collection adds). Supports date filtering.', {
|
|
40
|
+
limit: z
|
|
41
|
+
.number()
|
|
42
|
+
.min(1)
|
|
43
|
+
.max(50)
|
|
44
|
+
.default(10)
|
|
45
|
+
.describe('Number of feed items to return'),
|
|
46
|
+
domain: z
|
|
47
|
+
.enum(['listening', 'running', 'watching', 'collecting', 'reading'])
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Optional: filter feed to a single domain'),
|
|
50
|
+
date: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Optional: filter to a specific date (YYYY-MM-DD)'),
|
|
54
|
+
from: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('Optional: start of date range (ISO 8601)'),
|
|
58
|
+
to: z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('Optional: end of date range (ISO 8601)'),
|
|
62
|
+
}, READ_ONLY_ANNOTATIONS, async ({ limit, domain, date, from, to }) => withErrorHandling(async () => {
|
|
63
|
+
const params = {
|
|
64
|
+
limit,
|
|
65
|
+
date,
|
|
66
|
+
from,
|
|
67
|
+
to,
|
|
68
|
+
};
|
|
69
|
+
const path = domain ? `/feed/domain/${domain}` : '/feed';
|
|
70
|
+
const data = await client.get(path, params);
|
|
71
|
+
if (!data.data.length)
|
|
72
|
+
return 'No feed activity found for the given filters.';
|
|
73
|
+
const lines = ['Activity Feed:'];
|
|
74
|
+
for (const item of data.data) {
|
|
75
|
+
const sub = item.subtitle ? ` -- ${item.subtitle}` : '';
|
|
76
|
+
lines.push(`- [${item.domain}] ${item.title}${sub} (${timeAgo(item.occurred_at)})`);
|
|
77
|
+
}
|
|
78
|
+
if (data.pagination.has_more) {
|
|
79
|
+
lines.push('\nMore items available. Increase limit or narrow date range.');
|
|
80
|
+
}
|
|
81
|
+
return lines.join('\n');
|
|
82
|
+
}));
|
|
83
|
+
// get_on_this_day
|
|
84
|
+
server.tool('get_on_this_day', "Get historical 'on this day' items -- what happened on a given date in previous years across all domains. Defaults to today. Great for nostalgia and reflection.", {
|
|
85
|
+
month: z
|
|
86
|
+
.number()
|
|
87
|
+
.min(1)
|
|
88
|
+
.max(12)
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Optional: month (1-12). Defaults to current month.'),
|
|
91
|
+
day: z
|
|
92
|
+
.number()
|
|
93
|
+
.min(1)
|
|
94
|
+
.max(31)
|
|
95
|
+
.optional()
|
|
96
|
+
.describe('Optional: day (1-31). Defaults to current day.'),
|
|
97
|
+
}, READ_ONLY_ANNOTATIONS, async ({ month, day }) => withErrorHandling(async () => {
|
|
98
|
+
const params = { month, day };
|
|
99
|
+
const data = await client.get('/feed/on-this-day', params);
|
|
100
|
+
if (!data.years.length)
|
|
101
|
+
return "No 'on this day' history found.";
|
|
102
|
+
const lines = [`On This Day (${data.month}/${data.day}):`];
|
|
103
|
+
for (const yearGroup of data.years) {
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push(`${yearGroup.year}:`);
|
|
106
|
+
for (const item of yearGroup.items) {
|
|
107
|
+
const sub = item.subtitle ? ` -- ${item.subtitle}` : '';
|
|
108
|
+
lines.push(` - [${item.domain}] ${item.title}${sub}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=cross-domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-domain.js","sourceRoot":"","sources":["../../src/tools/cross-domain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,GAAG,EACH,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAEtB,MAAM,UAAU,wBAAwB,CACtC,MAAiB,EACjB,MAAoB;IAEpB,SAAS;IACT,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,2KAA2K,EAC3K;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC/C,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;aACnE,QAAQ,EAAE;aACV,QAAQ,CAAC,6CAA6C,CAAC;QAC1D,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KAC1E,EACD,qBAAqB,EACrB,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CACvC,iBAAiB,CAAC,KAAK,IAAI,EAAE;QAC3B,MAAM,MAAM,GAAoC;YAC9C,CAAC,EAAE,KAAK;YACR,KAAK;YACL,IAAI;SACL,CAAC;QACF,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QAEnC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAQ1B,SAAS,EAAE,MAAM,CAAC,CAAC;QAEtB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YACnB,OAAO,yBAAyB,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;QAE5E,MAAM,KAAK,GAAG;YACZ,uBAAuB,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU;SACvE,CAAC;QAEF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACzC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,IAAI,CACR,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,EAAE,CAC5D,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CACL,CAAC;IAEF,WAAW;IACX,MAAM,CAAC,IAAI,CACT,UAAU,EACV,gLAAgL,EAChL;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,gCAAgC,CAAC;QAC7C,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;aACnE,QAAQ,EAAE;aACV,QAAQ,CAAC,0CAA0C,CAAC;QACvD,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0CAA0C,CAAC;QACvD,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,wCAAwC,CAAC;KACtD,EACD,qBAAqB,EACrB,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,CAC1C,iBAAiB,CAAC,KAAK,IAAI,EAAE;QAC3B,MAAM,MAAM,GAAgD;YAC1D,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,EAAE;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACzD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAS1B,IAAI,EAAE,MAAM,CAAC,CAAC;QAEjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YACnB,OAAO,+CAA+C,CAAC;QAEzD,MAAM,KAAK,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,IAAI,CACR,MAAM,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,GAAG,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CACxE,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CACR,8DAA8D,CAC/D,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CACL,CAAC;IAEF,kBAAkB;IAClB,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kKAAkK,EAClK;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,oDAAoD,CAAC;QACjE,GAAG,EAAE,CAAC;aACH,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,gDAAgD,CAAC;KAC9D,EACD,qBAAqB,EACrB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CACvB,iBAAiB,CAAC,KAAK,IAAI,EAAE;QAC3B,MAAM,MAAM,GAAuC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAClE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAY1B,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAEhC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,iCAAiC,CAAC;QAEjE,MAAM,KAAK,GAAG,CAAC,gBAAgB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAE3D,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CACL,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { RewindClient } from '../client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wrap a tool handler with standard error handling.
|
|
5
|
+
* Returns { content, isError: true } on failure.
|
|
6
|
+
*/
|
|
7
|
+
export declare function withErrorHandling(fn: () => Promise<string>): Promise<{
|
|
8
|
+
content: {
|
|
9
|
+
type: 'text';
|
|
10
|
+
text: string;
|
|
11
|
+
}[];
|
|
12
|
+
isError?: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
/** Format a date string as "Jan 15, 2025" */
|
|
15
|
+
export declare function formatDate(iso: string | null | undefined): string;
|
|
16
|
+
/** Format a date string as relative time like "2h ago" */
|
|
17
|
+
export declare function timeAgo(iso: string): string;
|
|
18
|
+
/** Format a number with commas */
|
|
19
|
+
export declare function fmt(n: number | null | undefined): string;
|
|
20
|
+
/** Common date filter params reused across tools. */
|
|
21
|
+
export declare const dateFilterParams: {
|
|
22
|
+
date: z.ZodOptional<z.ZodString>;
|
|
23
|
+
from: z.ZodOptional<z.ZodString>;
|
|
24
|
+
to: z.ZodOptional<z.ZodString>;
|
|
25
|
+
};
|
|
26
|
+
/** Standard annotations for all Rewind tools (read-only, open-world). */
|
|
27
|
+
export declare const READ_ONLY_ANNOTATIONS: {
|
|
28
|
+
readOnlyHint: true;
|
|
29
|
+
destructiveHint: false;
|
|
30
|
+
openWorldHint: true;
|
|
31
|
+
};
|
|
32
|
+
export type { RewindClient };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a tool handler with standard error handling.
|
|
4
|
+
* Returns { content, isError: true } on failure.
|
|
5
|
+
*/
|
|
6
|
+
export async function withErrorHandling(fn) {
|
|
7
|
+
try {
|
|
8
|
+
const text = await fn();
|
|
9
|
+
return { content: [{ type: 'text', text }] };
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
15
|
+
isError: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Format a date string as "Jan 15, 2025" */
|
|
20
|
+
export function formatDate(iso) {
|
|
21
|
+
if (!iso)
|
|
22
|
+
return 'unknown';
|
|
23
|
+
return new Date(iso).toLocaleDateString('en-US', {
|
|
24
|
+
month: 'short',
|
|
25
|
+
day: 'numeric',
|
|
26
|
+
year: 'numeric',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/** Format a date string as relative time like "2h ago" */
|
|
30
|
+
export function timeAgo(iso) {
|
|
31
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
32
|
+
const minutes = Math.floor(diff / 60_000);
|
|
33
|
+
if (minutes < 1)
|
|
34
|
+
return 'just now';
|
|
35
|
+
if (minutes < 60)
|
|
36
|
+
return `${minutes}m ago`;
|
|
37
|
+
const hours = Math.floor(minutes / 60);
|
|
38
|
+
if (hours < 24)
|
|
39
|
+
return `${hours}h ago`;
|
|
40
|
+
const days = Math.floor(hours / 24);
|
|
41
|
+
if (days < 7)
|
|
42
|
+
return `${days}d ago`;
|
|
43
|
+
return formatDate(iso);
|
|
44
|
+
}
|
|
45
|
+
/** Format a number with commas */
|
|
46
|
+
export function fmt(n) {
|
|
47
|
+
if (n === null || n === undefined)
|
|
48
|
+
return '0';
|
|
49
|
+
return n.toLocaleString('en-US');
|
|
50
|
+
}
|
|
51
|
+
/** Common date filter params reused across tools. */
|
|
52
|
+
export const dateFilterParams = {
|
|
53
|
+
date: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('Optional: filter to a specific date (YYYY-MM-DD)'),
|
|
57
|
+
from: z
|
|
58
|
+
.string()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Optional: start of date range (ISO 8601)'),
|
|
61
|
+
to: z.string().optional().describe('Optional: end of date range (ISO 8601)'),
|
|
62
|
+
};
|
|
63
|
+
/** Standard annotations for all Rewind tools (read-only, open-world). */
|
|
64
|
+
export const READ_ONLY_ANNOTATIONS = {
|
|
65
|
+
readOnlyHint: true,
|
|
66
|
+
destructiveHint: false,
|
|
67
|
+
openWorldHint: true,
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,EAAE,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;YACtD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,UAAU,CAAC,GAA8B;IACvD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC/C,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;KAChB,CAAC,CAAC;AACL,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACnC,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,GAAG,OAAO,OAAO,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,KAAK,OAAO,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACpC,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,IAAI,OAAO,CAAC;IACpC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,GAAG,CAAC,CAA4B;IAC9C,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAC9C,OAAO,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,0CAA0C,CAAC;IACvD,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;CAC7E,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,YAAY,EAAE,IAAa;IAC3B,eAAe,EAAE,KAAc;IAC/B,aAAa,EAAE,IAAa;CAC7B,CAAC"}
|