korbus-mcp 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/LICENSE +21 -0
- package/README.md +251 -0
- package/dist/bus/gateway.d.ts +11 -0
- package/dist/bus/gateway.d.ts.map +1 -0
- package/dist/bus/gateway.js +36 -0
- package/dist/bus/gateway.js.map +1 -0
- package/dist/bus/gyeonggi.d.ts +9 -0
- package/dist/bus/gyeonggi.d.ts.map +1 -0
- package/dist/bus/gyeonggi.js +69 -0
- package/dist/bus/gyeonggi.js.map +1 -0
- package/dist/bus/seoul.d.ts +9 -0
- package/dist/bus/seoul.d.ts.map +1 -0
- package/dist/bus/seoul.js +72 -0
- package/dist/bus/seoul.js.map +1 -0
- package/dist/db.d.ts +55 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +409 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +71 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/notifier/console.d.ts +3 -0
- package/dist/notifier/console.d.ts.map +1 -0
- package/dist/notifier/console.js +4 -0
- package/dist/notifier/console.js.map +1 -0
- package/dist/notifier/dispatcher.d.ts +11 -0
- package/dist/notifier/dispatcher.d.ts.map +1 -0
- package/dist/notifier/dispatcher.js +28 -0
- package/dist/notifier/dispatcher.js.map +1 -0
- package/dist/notifier/telegram.d.ts +3 -0
- package/dist/notifier/telegram.d.ts.map +1 -0
- package/dist/notifier/telegram.js +14 -0
- package/dist/notifier/telegram.js.map +1 -0
- package/dist/notifier/webhook.d.ts +3 -0
- package/dist/notifier/webhook.d.ts.map +1 -0
- package/dist/notifier/webhook.js +6 -0
- package/dist/notifier/webhook.js.map +1 -0
- package/dist/openclaw/dispatcher.d.ts +10 -0
- package/dist/openclaw/dispatcher.d.ts.map +1 -0
- package/dist/openclaw/dispatcher.js +50 -0
- package/dist/openclaw/dispatcher.js.map +1 -0
- package/dist/openclaw/index.d.ts +21 -0
- package/dist/openclaw/index.d.ts.map +1 -0
- package/dist/openclaw/index.js +39 -0
- package/dist/openclaw/index.js.map +1 -0
- package/dist/openclaw/service.d.ts +11 -0
- package/dist/openclaw/service.d.ts.map +1 -0
- package/dist/openclaw/service.js +28 -0
- package/dist/openclaw/service.js.map +1 -0
- package/dist/openclaw/tools.d.ts +27 -0
- package/dist/openclaw/tools.d.ts.map +1 -0
- package/dist/openclaw/tools.js +318 -0
- package/dist/openclaw/tools.js.map +1 -0
- package/dist/scheduler.d.ts +15 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +106 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/tools/alarm.d.ts +3 -0
- package/dist/tools/alarm.d.ts.map +1 -0
- package/dist/tools/alarm.js +118 -0
- package/dist/tools/alarm.js.map +1 -0
- package/dist/tools/arrival.d.ts +4 -0
- package/dist/tools/arrival.d.ts.map +1 -0
- package/dist/tools/arrival.js +37 -0
- package/dist/tools/arrival.js.map +1 -0
- package/dist/tools/helpers.d.ts +14 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +14 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/poll.d.ts +4 -0
- package/dist/tools/poll.d.ts.map +1 -0
- package/dist/tools/poll.js +17 -0
- package/dist/tools/poll.js.map +1 -0
- package/dist/tools/search.d.ts +4 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +26 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/package.json +73 -0
- package/prisma/migrations/20260303085107_init/migration.sql +62 -0
- package/prisma/migrations/20260303120821_add_once_alarm_fields/migration.sql +22 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +72 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import cron from 'node-cron';
|
|
2
|
+
import { listActiveAlarms, hasRecentNotification, createNotificationLog, markAlarmFired } from './db.js';
|
|
3
|
+
export async function pollActiveAlarms(deps, options) {
|
|
4
|
+
const now = options?.now ?? new Date();
|
|
5
|
+
const dryRun = options?.dryRun ?? false;
|
|
6
|
+
// 1. Get active alarms for current time
|
|
7
|
+
const alarms = await listActiveAlarms(now);
|
|
8
|
+
if (!alarms.length) {
|
|
9
|
+
return { checkedAlarms: 0, groupedQueries: 0, notificationsSent: 0, dryRun };
|
|
10
|
+
}
|
|
11
|
+
// 2. Group by stationId:routeId to minimize API calls
|
|
12
|
+
const groups = new Map();
|
|
13
|
+
for (const alarm of alarms) {
|
|
14
|
+
const key = `${alarm.stationId}:${alarm.routeId}`;
|
|
15
|
+
if (!groups.has(key))
|
|
16
|
+
groups.set(key, []);
|
|
17
|
+
groups.get(key).push(alarm);
|
|
18
|
+
}
|
|
19
|
+
let notificationsSent = 0;
|
|
20
|
+
// 3. Process each group
|
|
21
|
+
const since = new Date(now.getTime() - 10 * 60 * 1000);
|
|
22
|
+
const results = await Promise.allSettled([...groups.values()].map(async (groupAlarms) => {
|
|
23
|
+
const first = groupAlarms[0];
|
|
24
|
+
const stationRef = {
|
|
25
|
+
id: first.station.id,
|
|
26
|
+
region: first.station.region,
|
|
27
|
+
arsId: first.station.arsId,
|
|
28
|
+
};
|
|
29
|
+
const arrivals = await deps.gateway.getArrivals(stationRef, first.route.id);
|
|
30
|
+
for (const alarm of groupAlarms) {
|
|
31
|
+
let alarmFired = false;
|
|
32
|
+
for (const arrival of arrivals) {
|
|
33
|
+
if (arrival.arrivalSec > alarm.alertMinutes * 60)
|
|
34
|
+
continue;
|
|
35
|
+
const vehicleId = arrival.vehicleId || `route:${arrival.routeId}`;
|
|
36
|
+
// Dedup once per alarm+vehicle, then dispatch to all channels
|
|
37
|
+
const hasRecent = await hasRecentNotification(alarm.id, vehicleId, since);
|
|
38
|
+
if (hasRecent)
|
|
39
|
+
continue;
|
|
40
|
+
for (const channel of alarm.channels) {
|
|
41
|
+
if (!dryRun) {
|
|
42
|
+
await deps.dispatcher.dispatch({ type: channel.type, config: channel.config }, {
|
|
43
|
+
alarmId: alarm.id,
|
|
44
|
+
stationName: alarm.station.name,
|
|
45
|
+
routeName: alarm.route.name,
|
|
46
|
+
arrivalSec: arrival.arrivalSec,
|
|
47
|
+
arrivalMsg: arrival.arrivalMsg,
|
|
48
|
+
vehicleId,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
notificationsSent += 1;
|
|
52
|
+
}
|
|
53
|
+
if (!dryRun) {
|
|
54
|
+
await createNotificationLog({
|
|
55
|
+
alarmId: alarm.id,
|
|
56
|
+
vehicleId,
|
|
57
|
+
message: arrival.arrivalMsg,
|
|
58
|
+
channel: alarm.channels.map((c) => c.type).join(','),
|
|
59
|
+
});
|
|
60
|
+
alarmFired = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Mark ONCE alarms as fired after successful notification
|
|
64
|
+
if (alarmFired && alarm.type === 'ONCE') {
|
|
65
|
+
await markAlarmFired(alarm.id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}));
|
|
69
|
+
for (const r of results) {
|
|
70
|
+
if (r.status === 'rejected') {
|
|
71
|
+
console.error('[scheduler] group poll failed:', r.reason);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
checkedAlarms: alarms.length,
|
|
76
|
+
groupedQueries: groups.size,
|
|
77
|
+
notificationsSent,
|
|
78
|
+
dryRun,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function startScheduler(deps) {
|
|
82
|
+
let running = false;
|
|
83
|
+
const task = cron.schedule('* * * * *', async () => {
|
|
84
|
+
if (running) {
|
|
85
|
+
console.error('[scheduler] previous poll still running, skipping');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
running = true;
|
|
89
|
+
try {
|
|
90
|
+
const result = await pollActiveAlarms(deps);
|
|
91
|
+
console.error(`[scheduler] poll complete: ${result.checkedAlarms} alarms, ${result.notificationsSent} notifications`);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error('[scheduler] poll error:', err);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
running = false;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
console.error('[scheduler] started (every minute)');
|
|
101
|
+
return () => {
|
|
102
|
+
task.stop();
|
|
103
|
+
console.error('[scheduler] stopped');
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alarm.d.ts","sourceRoot":"","sources":["../../src/tools/alarm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAwHnD"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createAlarm, createOnceAlarm, listAlarms, findAlarm, updateAlarm, deleteAlarm } from '../db.js';
|
|
3
|
+
import { CoreError } from '../errors.js';
|
|
4
|
+
import { textResult, errorResult } from './helpers.js';
|
|
5
|
+
const dayOfWeekEnum = z.enum(['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']);
|
|
6
|
+
const scheduleSchema = z.object({
|
|
7
|
+
dayOfWeek: z.array(dayOfWeekEnum),
|
|
8
|
+
startTime: z.string().regex(/^\d{2}:\d{2}$/),
|
|
9
|
+
endTime: z.string().regex(/^\d{2}:\d{2}$/),
|
|
10
|
+
});
|
|
11
|
+
const channelSchema = z.union([
|
|
12
|
+
z.object({ type: z.literal('CONSOLE'), config: z.record(z.never()).optional() }),
|
|
13
|
+
z.object({ type: z.literal('WEBHOOK'), config: z.object({ url: z.string().url() }) }),
|
|
14
|
+
z.object({ type: z.literal('TELEGRAM'), config: z.object({ chatId: z.string().min(1) }) }),
|
|
15
|
+
]);
|
|
16
|
+
export function registerAlarmTools(server) {
|
|
17
|
+
server.tool('list_alarms', 'List all registered bus alarms', {}, async () => {
|
|
18
|
+
try {
|
|
19
|
+
const alarms = await listAlarms();
|
|
20
|
+
return textResult(alarms);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return errorResult(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
server.tool('create_alarm', 'Create a recurring bus arrival alarm', {
|
|
27
|
+
station_id: z.string().min(1).describe('Station ID'),
|
|
28
|
+
route_id: z.string().min(1).describe('Route ID'),
|
|
29
|
+
label: z.string().optional().describe('Label for this alarm'),
|
|
30
|
+
alert_minutes: z.number().int().min(1).max(30).describe('Alert when bus is within N minutes'),
|
|
31
|
+
schedules: z.array(scheduleSchema).describe('When to monitor'),
|
|
32
|
+
channels: z.array(channelSchema).describe('How to notify'),
|
|
33
|
+
}, async (input) => {
|
|
34
|
+
try {
|
|
35
|
+
const alarm = await createAlarm({
|
|
36
|
+
stationId: input.station_id,
|
|
37
|
+
routeId: input.route_id,
|
|
38
|
+
label: input.label,
|
|
39
|
+
alertMinutes: input.alert_minutes,
|
|
40
|
+
schedules: input.schedules,
|
|
41
|
+
channels: input.channels,
|
|
42
|
+
});
|
|
43
|
+
return textResult(alarm);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return errorResult(error);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.tool('create_once_alarm', 'Create a one-time bus arrival alarm (fires once then expires)', {
|
|
50
|
+
station_id: z.string().min(1).describe('Station ID'),
|
|
51
|
+
route_id: z.string().min(1).describe('Route ID'),
|
|
52
|
+
label: z.string().optional().describe('Label for this alarm'),
|
|
53
|
+
alert_minutes: z.number().int().min(1).max(30).describe('Alert when bus is within N minutes'),
|
|
54
|
+
active_until: z.string().optional().describe('Monitor until this time (HH:mm or ISO datetime). Omit to monitor indefinitely until fired.'),
|
|
55
|
+
channels: z.array(channelSchema).describe('How to notify'),
|
|
56
|
+
}, async (input) => {
|
|
57
|
+
try {
|
|
58
|
+
const alarm = await createOnceAlarm({
|
|
59
|
+
stationId: input.station_id,
|
|
60
|
+
routeId: input.route_id,
|
|
61
|
+
label: input.label,
|
|
62
|
+
alertMinutes: input.alert_minutes,
|
|
63
|
+
activeUntil: input.active_until,
|
|
64
|
+
channels: input.channels,
|
|
65
|
+
});
|
|
66
|
+
return textResult(alarm);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return errorResult(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
server.tool('update_alarm', 'Update an existing bus alarm', {
|
|
73
|
+
alarm_id: z.string().min(1).describe('Alarm ID to update'),
|
|
74
|
+
patch: z.object({
|
|
75
|
+
label: z.string().optional(),
|
|
76
|
+
alertMinutes: z.number().int().min(1).max(30).optional(),
|
|
77
|
+
enabled: z.boolean().optional(),
|
|
78
|
+
schedules: z.array(scheduleSchema).optional(),
|
|
79
|
+
channels: z.array(channelSchema).optional(),
|
|
80
|
+
}),
|
|
81
|
+
}, async ({ alarm_id, patch }) => {
|
|
82
|
+
try {
|
|
83
|
+
const existing = await findAlarm(alarm_id);
|
|
84
|
+
if (!existing) {
|
|
85
|
+
throw new CoreError({ code: 'NOT_FOUND', message: `Alarm not found: ${alarm_id}`, retryable: false });
|
|
86
|
+
}
|
|
87
|
+
const updated = await updateAlarm(alarm_id, patch);
|
|
88
|
+
return textResult(updated);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return errorResult(error);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
server.tool('delete_alarm', 'Delete a bus alarm (confirm=true required)', {
|
|
95
|
+
alarm_id: z.string().min(1).describe('Alarm ID to delete'),
|
|
96
|
+
confirm: z.boolean().describe('Must be true to confirm deletion'),
|
|
97
|
+
}, async ({ alarm_id, confirm }) => {
|
|
98
|
+
try {
|
|
99
|
+
if (!confirm) {
|
|
100
|
+
throw new CoreError({
|
|
101
|
+
code: 'VALIDATION_ERROR',
|
|
102
|
+
message: 'confirm=true is required to delete an alarm',
|
|
103
|
+
retryable: false,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const existing = await findAlarm(alarm_id);
|
|
107
|
+
if (!existing) {
|
|
108
|
+
throw new CoreError({ code: 'NOT_FOUND', message: `Alarm not found: ${alarm_id}`, retryable: false });
|
|
109
|
+
}
|
|
110
|
+
await deleteAlarm(alarm_id);
|
|
111
|
+
return textResult({ deleted: true, alarm_id });
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return errorResult(error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=alarm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alarm.js","sourceRoot":"","sources":["../../src/tools/alarm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrival.d.ts","sourceRoot":"","sources":["../../src/tools/arrival.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,QAmC1E"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { findStationById, upsertRoutes } from '../db.js';
|
|
3
|
+
import { CoreError } from '../errors.js';
|
|
4
|
+
import { textResult, errorResult } from './helpers.js';
|
|
5
|
+
export function registerArrivalTools(server, gateway) {
|
|
6
|
+
server.tool('get_arrivals', 'Get real-time bus arrival info for a station (optionally filtered by route)', {
|
|
7
|
+
station_id: z.string().min(1).describe('Station ID (from search_stations)'),
|
|
8
|
+
route_id: z.string().optional().describe('Route ID to filter (from search_routes)'),
|
|
9
|
+
}, async ({ station_id, route_id }) => {
|
|
10
|
+
try {
|
|
11
|
+
const stationRef = await findStationById(station_id);
|
|
12
|
+
if (!stationRef) {
|
|
13
|
+
throw new CoreError({
|
|
14
|
+
code: 'NOT_FOUND',
|
|
15
|
+
message: `Station not found: ${station_id}. Use search_stations first.`,
|
|
16
|
+
retryable: false,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const arrivals = await gateway.getArrivals(stationRef, route_id);
|
|
20
|
+
// Auto-cache routes discovered via arrivals
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const routes = arrivals.flatMap((a) => {
|
|
23
|
+
if (seen.has(a.routeId))
|
|
24
|
+
return [];
|
|
25
|
+
seen.add(a.routeId);
|
|
26
|
+
return [{ id: a.routeId, name: a.routeName, region: stationRef.region }];
|
|
27
|
+
});
|
|
28
|
+
if (routes.length)
|
|
29
|
+
await upsertRoutes(routes);
|
|
30
|
+
return textResult(arrivals);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return errorResult(error);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=arrival.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrival.js","sourceRoot":"","sources":["../../src/tools/arrival.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,OAAmB;IACzE,MAAM,CAAC,IAAI,CACT,cAAc,EACd,6EAA6E,EAC7E;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;QAC3E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;KACpF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,SAAS,CAAC;oBAClB,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,sBAAsB,UAAU,8BAA8B;oBACvE,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAEjE,4CAA4C;YAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBACpC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;oBAAE,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBACpB,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3E,CAAC,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;YAE9C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function textResult(data: unknown): {
|
|
2
|
+
content: {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
}[];
|
|
6
|
+
};
|
|
7
|
+
export declare function errorResult(error: unknown): {
|
|
8
|
+
isError: boolean;
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO;;;;;EAIvC;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO;;;;;;EAMzC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { toCoreError } from '../errors.js';
|
|
2
|
+
export function textResult(data) {
|
|
3
|
+
return {
|
|
4
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export function errorResult(error) {
|
|
8
|
+
const coreError = toCoreError(error);
|
|
9
|
+
return {
|
|
10
|
+
isError: true,
|
|
11
|
+
content: [{ type: 'text', text: JSON.stringify(coreError.toJSON(), null, 2) }],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACxF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.d.ts","sourceRoot":"","sources":["../../src/tools/poll.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGlE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,QAgBlE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pollActiveAlarms } from '../scheduler.js';
|
|
3
|
+
import { textResult, errorResult } from './helpers.js';
|
|
4
|
+
export function registerPollTools(server, deps) {
|
|
5
|
+
server.tool('poll_now', 'Run immediate polling for active alarms (checks arrivals and sends notifications)', {
|
|
6
|
+
dry_run: z.boolean().optional().describe('If true, check but do not send notifications'),
|
|
7
|
+
}, async ({ dry_run }) => {
|
|
8
|
+
try {
|
|
9
|
+
const result = await pollActiveAlarms(deps, { dryRun: dry_run });
|
|
10
|
+
return textResult(result);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return errorResult(error);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=poll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poll.js","sourceRoot":"","sources":["../../src/tools/poll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAiB,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,IAAc;IACjE,MAAM,CAAC,IAAI,CACT,UAAU,EACV,mFAAmF,EACnF;QACE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;KACzF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACpB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACjE,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,QA8BzE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { upsertStations, upsertRoutes } from '../db.js';
|
|
3
|
+
import { textResult, errorResult } from './helpers.js';
|
|
4
|
+
export function registerSearchTools(server, gateway) {
|
|
5
|
+
server.tool('search_stations', 'Search bus stations by name (Seoul + Gyeonggi) and cache results', { query: z.string().min(1).describe('Station name to search') }, async ({ query }) => {
|
|
6
|
+
try {
|
|
7
|
+
const stations = await gateway.searchStations(query.trim());
|
|
8
|
+
const saved = await upsertStations(stations);
|
|
9
|
+
return textResult(saved);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return errorResult(error);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
server.tool('search_routes', 'Search bus routes by name/number (Seoul + Gyeonggi) and cache results', { query: z.string().min(1).describe('Route name/number to search') }, async ({ query }) => {
|
|
16
|
+
try {
|
|
17
|
+
const routes = await gateway.searchRoutes(query.trim());
|
|
18
|
+
const saved = await upsertRoutes(routes);
|
|
19
|
+
return textResult(saved);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return errorResult(error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,OAAmB;IACxE,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kEAAkE,EAClE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,EAC/D,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC7C,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,uEAAuE,EACvE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,EACpE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;YACzC,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export type Region = 'SEOUL' | 'GYEONGGI';
|
|
2
|
+
export type DayOfWeek = 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT' | 'SUN';
|
|
3
|
+
export type ChannelType = 'CONSOLE' | 'WEBHOOK' | 'TELEGRAM';
|
|
4
|
+
export type AlarmType = 'RECURRING' | 'ONCE';
|
|
5
|
+
export interface ScheduleWindow {
|
|
6
|
+
dayOfWeek: DayOfWeek[];
|
|
7
|
+
startTime: string;
|
|
8
|
+
endTime: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ConsoleChannelConfig {
|
|
11
|
+
type: 'CONSOLE';
|
|
12
|
+
config?: Record<string, never>;
|
|
13
|
+
}
|
|
14
|
+
export interface WebhookChannelConfig {
|
|
15
|
+
type: 'WEBHOOK';
|
|
16
|
+
config: {
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface TelegramChannelConfig {
|
|
21
|
+
type: 'TELEGRAM';
|
|
22
|
+
config: {
|
|
23
|
+
chatId: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export type ChannelConfig = ConsoleChannelConfig | WebhookChannelConfig | TelegramChannelConfig;
|
|
27
|
+
export interface StationRef {
|
|
28
|
+
id: string;
|
|
29
|
+
region: Region;
|
|
30
|
+
arsId?: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface Station {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
region: Region;
|
|
36
|
+
arsId?: string | null;
|
|
37
|
+
posX?: number;
|
|
38
|
+
posY?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface Route {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
region: Region;
|
|
44
|
+
}
|
|
45
|
+
export interface Arrival {
|
|
46
|
+
routeId: string;
|
|
47
|
+
routeName: string;
|
|
48
|
+
stationId: string;
|
|
49
|
+
vehicleId?: string;
|
|
50
|
+
arrivalSec: number;
|
|
51
|
+
arrivalMsg: string;
|
|
52
|
+
}
|
|
53
|
+
export interface AlarmChannel {
|
|
54
|
+
type: ChannelType;
|
|
55
|
+
config: string;
|
|
56
|
+
}
|
|
57
|
+
export interface Alarm {
|
|
58
|
+
id: string;
|
|
59
|
+
label?: string | null;
|
|
60
|
+
stationId: string;
|
|
61
|
+
routeId: string;
|
|
62
|
+
alertMinutes: number;
|
|
63
|
+
type: AlarmType;
|
|
64
|
+
activeUntil?: Date | null;
|
|
65
|
+
firedAt?: Date | null;
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
schedules: ScheduleWindow[];
|
|
68
|
+
channels: AlarmChannel[];
|
|
69
|
+
createdAt: Date;
|
|
70
|
+
}
|
|
71
|
+
export interface AlarmWithRelations extends Alarm {
|
|
72
|
+
station: Station;
|
|
73
|
+
route: Route;
|
|
74
|
+
}
|
|
75
|
+
export interface CreateAlarmInput {
|
|
76
|
+
label?: string;
|
|
77
|
+
stationId: string;
|
|
78
|
+
routeId: string;
|
|
79
|
+
alertMinutes: number;
|
|
80
|
+
schedules: ScheduleWindow[];
|
|
81
|
+
channels: ChannelConfig[];
|
|
82
|
+
}
|
|
83
|
+
export interface CreateOnceAlarmInput {
|
|
84
|
+
label?: string;
|
|
85
|
+
stationId: string;
|
|
86
|
+
routeId: string;
|
|
87
|
+
alertMinutes: number;
|
|
88
|
+
activeUntil?: string;
|
|
89
|
+
channels: ChannelConfig[];
|
|
90
|
+
}
|
|
91
|
+
export interface UpdateAlarmInput {
|
|
92
|
+
label?: string;
|
|
93
|
+
alertMinutes?: number;
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
schedules?: ScheduleWindow[];
|
|
96
|
+
channels?: ChannelConfig[];
|
|
97
|
+
}
|
|
98
|
+
export interface NotificationPayload {
|
|
99
|
+
alarmId: string;
|
|
100
|
+
stationName: string;
|
|
101
|
+
routeName: string;
|
|
102
|
+
arrivalSec: number;
|
|
103
|
+
arrivalMsg: string;
|
|
104
|
+
vehicleId: string;
|
|
105
|
+
}
|
|
106
|
+
export interface PollResult {
|
|
107
|
+
checkedAlarms: number;
|
|
108
|
+
groupedQueries: number;
|
|
109
|
+
notificationsSent: number;
|
|
110
|
+
dryRun: boolean;
|
|
111
|
+
}
|
|
112
|
+
export declare function getNowSlot(now: Date): {
|
|
113
|
+
day: DayOfWeek;
|
|
114
|
+
time: string;
|
|
115
|
+
};
|
|
116
|
+
export declare function includesNow(schedule: ScheduleWindow, now: Date): boolean;
|
|
117
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// --- Time utilities ---
|
|
2
|
+
const DAY_MAP = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
|
|
3
|
+
export function getNowSlot(now) {
|
|
4
|
+
const day = DAY_MAP[now.getDay()];
|
|
5
|
+
const hh = String(now.getHours()).padStart(2, '0');
|
|
6
|
+
const mm = String(now.getMinutes()).padStart(2, '0');
|
|
7
|
+
return { day, time: `${hh}:${mm}` };
|
|
8
|
+
}
|
|
9
|
+
export function includesNow(schedule, now) {
|
|
10
|
+
const { day, time } = getNowSlot(now);
|
|
11
|
+
if (!schedule.dayOfWeek.includes(day)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return schedule.startTime <= time && schedule.endTime >= time;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA0IA,yBAAyB;AAEzB,MAAM,OAAO,GAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE/E,MAAM,UAAU,UAAU,CAAC,GAAS;IAClC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAwB,EAAE,GAAS;IAC7D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,QAAQ,CAAC,SAAS,IAAI,IAAI,IAAI,QAAQ,CAAC,OAAO,IAAI,IAAI,CAAC;AAChE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "korbus-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Seoul & Gyeonggi real-time bus arrival info, station/route search, and alarm notifications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "BearMett",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/BearMett/korbus-mcp.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/BearMett/korbus-mcp#readme",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"model-context-protocol",
|
|
16
|
+
"bus",
|
|
17
|
+
"seoul",
|
|
18
|
+
"gyeonggi",
|
|
19
|
+
"korea",
|
|
20
|
+
"transit",
|
|
21
|
+
"real-time"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"main": "dist/openclaw/index.js",
|
|
27
|
+
"bin": {
|
|
28
|
+
"korbus-mcp": "dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"prisma/schema.prisma",
|
|
33
|
+
"prisma/migrations"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc && node -e \"const fs=require('fs');const f='dist/index.js';const c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c)\"",
|
|
37
|
+
"start": "node dist/index.js",
|
|
38
|
+
"dev": "tsx src/index.ts",
|
|
39
|
+
"db:generate": "prisma generate",
|
|
40
|
+
"db:migrate": "prisma migrate dev",
|
|
41
|
+
"postinstall": "prisma generate",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
46
|
+
"@prisma/client": "^6.5.0",
|
|
47
|
+
"@sinclair/typebox": "0.34.48",
|
|
48
|
+
"prisma": "^6.5.0",
|
|
49
|
+
"axios": "^1.7.9",
|
|
50
|
+
"fast-xml-parser": "^5.2.0",
|
|
51
|
+
"node-cron": "^3.0.3",
|
|
52
|
+
"zod": "^3.24.2"
|
|
53
|
+
},
|
|
54
|
+
"openclaw": {
|
|
55
|
+
"extensions": [
|
|
56
|
+
"./dist/openclaw/index.js"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"openclaw": "*"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"openclaw": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"typescript": "^5.7.3",
|
|
69
|
+
"@types/node": "^22.13.5",
|
|
70
|
+
"@types/node-cron": "^3.0.11",
|
|
71
|
+
"tsx": "^4.19.3"
|
|
72
|
+
}
|
|
73
|
+
}
|