@davidwoods/skylight-mcp 0.0.0-stage → 1.7.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 +22 -0
- package/README.md +583 -2
- package/THIRD_PARTY_NOTICES.md +38 -0
- package/dist/api/auth.d.ts +34 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +328 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/client.d.ts +103 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +324 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/constants.d.ts +4 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/constants.js +4 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/credential-store.d.ts +38 -0
- package/dist/api/credential-store.d.ts.map +1 -0
- package/dist/api/credential-store.js +273 -0
- package/dist/api/credential-store.js.map +1 -0
- package/dist/api/credential-types.d.ts +15 -0
- package/dist/api/credential-types.d.ts.map +1 -0
- package/dist/api/credential-types.js +11 -0
- package/dist/api/credential-types.js.map +1 -0
- package/dist/api/endpoints/calendar.d.ts +36 -0
- package/dist/api/endpoints/calendar.d.ts.map +1 -0
- package/dist/api/endpoints/calendar.js +74 -0
- package/dist/api/endpoints/calendar.js.map +1 -0
- package/dist/api/endpoints/categories.d.ts +32 -0
- package/dist/api/endpoints/categories.d.ts.map +1 -0
- package/dist/api/endpoints/categories.js +77 -0
- package/dist/api/endpoints/categories.js.map +1 -0
- package/dist/api/endpoints/chores.d.ts +50 -0
- package/dist/api/endpoints/chores.d.ts.map +1 -0
- package/dist/api/endpoints/chores.js +106 -0
- package/dist/api/endpoints/chores.js.map +1 -0
- package/dist/api/endpoints/devices.d.ts +6 -0
- package/dist/api/endpoints/devices.d.ts.map +1 -0
- package/dist/api/endpoints/devices.js +10 -0
- package/dist/api/endpoints/devices.js.map +1 -0
- package/dist/api/endpoints/frames.d.ts +6 -0
- package/dist/api/endpoints/frames.d.ts.map +1 -0
- package/dist/api/endpoints/frames.js +10 -0
- package/dist/api/endpoints/frames.js.map +1 -0
- package/dist/api/endpoints/lists.d.ts +55 -0
- package/dist/api/endpoints/lists.d.ts.map +1 -0
- package/dist/api/endpoints/lists.js +125 -0
- package/dist/api/endpoints/lists.js.map +1 -0
- package/dist/api/endpoints/meals.d.ts +154 -0
- package/dist/api/endpoints/meals.d.ts.map +1 -0
- package/dist/api/endpoints/meals.js +194 -0
- package/dist/api/endpoints/meals.js.map +1 -0
- package/dist/api/endpoints/messages.d.ts +98 -0
- package/dist/api/endpoints/messages.d.ts.map +1 -0
- package/dist/api/endpoints/messages.js +116 -0
- package/dist/api/endpoints/messages.js.map +1 -0
- package/dist/api/endpoints/misc.d.ts +27 -0
- package/dist/api/endpoints/misc.d.ts.map +1 -0
- package/dist/api/endpoints/misc.js +19 -0
- package/dist/api/endpoints/misc.js.map +1 -0
- package/dist/api/endpoints/photos.d.ts +13 -0
- package/dist/api/endpoints/photos.d.ts.map +1 -0
- package/dist/api/endpoints/photos.js +10 -0
- package/dist/api/endpoints/photos.js.map +1 -0
- package/dist/api/endpoints/rewards.d.ts +49 -0
- package/dist/api/endpoints/rewards.d.ts.map +1 -0
- package/dist/api/endpoints/rewards.js +106 -0
- package/dist/api/endpoints/rewards.js.map +1 -0
- package/dist/api/endpoints/shape.d.ts +11 -0
- package/dist/api/endpoints/shape.d.ts.map +1 -0
- package/dist/api/endpoints/shape.js +34 -0
- package/dist/api/endpoints/shape.js.map +1 -0
- package/dist/api/endpoints/taskbox.d.ts +13 -0
- package/dist/api/endpoints/taskbox.d.ts.map +1 -0
- package/dist/api/endpoints/taskbox.js +22 -0
- package/dist/api/endpoints/taskbox.js.map +1 -0
- package/dist/api/oauth.d.ts +62 -0
- package/dist/api/oauth.d.ts.map +1 -0
- package/dist/api/oauth.js +206 -0
- package/dist/api/oauth.js.map +1 -0
- package/dist/api/types.d.ts +277 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +5 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +105 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +27 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +17 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +109 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +29 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/calendar.d.ts +3 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +298 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/chores.d.ts +3 -0
- package/dist/tools/chores.d.ts.map +1 -0
- package/dist/tools/chores.js +349 -0
- package/dist/tools/chores.js.map +1 -0
- package/dist/tools/family.d.ts +3 -0
- package/dist/tools/family.d.ts.map +1 -0
- package/dist/tools/family.js +182 -0
- package/dist/tools/family.js.map +1 -0
- package/dist/tools/lists.d.ts +3 -0
- package/dist/tools/lists.d.ts.map +1 -0
- package/dist/tools/lists.js +481 -0
- package/dist/tools/lists.js.map +1 -0
- package/dist/tools/meals.d.ts +3 -0
- package/dist/tools/meals.d.ts.map +1 -0
- package/dist/tools/meals.js +491 -0
- package/dist/tools/meals.js.map +1 -0
- package/dist/tools/messages.d.ts +3 -0
- package/dist/tools/messages.d.ts.map +1 -0
- package/dist/tools/messages.js +195 -0
- package/dist/tools/messages.js.map +1 -0
- package/dist/tools/misc.d.ts +3 -0
- package/dist/tools/misc.d.ts.map +1 -0
- package/dist/tools/misc.js +102 -0
- package/dist/tools/misc.js.map +1 -0
- package/dist/tools/photos.d.ts +3 -0
- package/dist/tools/photos.d.ts.map +1 -0
- package/dist/tools/photos.js +42 -0
- package/dist/tools/photos.js.map +1 -0
- package/dist/tools/planning.d.ts +15 -0
- package/dist/tools/planning.d.ts.map +1 -0
- package/dist/tools/planning.js +303 -0
- package/dist/tools/planning.js.map +1 -0
- package/dist/tools/registry.d.ts +39 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +142 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/rewards.d.ts +3 -0
- package/dist/tools/rewards.d.ts.map +1 -0
- package/dist/tools/rewards.js +339 -0
- package/dist/tools/rewards.js.map +1 -0
- package/dist/tools/tasks.d.ts +3 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +68 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/utils/dates.d.ts +26 -0
- package/dist/utils/dates.d.ts.map +1 -0
- package/dist/utils/dates.js +109 -0
- package/dist/utils/dates.js.map +1 -0
- package/dist/utils/errors.d.ts +45 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +102 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/schedule.d.ts +86 -0
- package/dist/utils/schedule.d.ts.map +1 -0
- package/dist/utils/schedule.js +189 -0
- package/dist/utils/schedule.js.map +1 -0
- package/package.json +76 -4
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for Skylight API errors
|
|
3
|
+
*/
|
|
4
|
+
export class SkylightError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
statusCode;
|
|
7
|
+
recoverable;
|
|
8
|
+
constructor(message, code, statusCode, recoverable = false) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
this.recoverable = recoverable;
|
|
13
|
+
this.name = "SkylightError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Authentication failed - token may be expired or invalid
|
|
18
|
+
*/
|
|
19
|
+
export class AuthenticationError extends SkylightError {
|
|
20
|
+
constructor(message = "Authentication failed. Your token may be expired or invalid.") {
|
|
21
|
+
super(message, "AUTH_FAILED", 401, true);
|
|
22
|
+
this.name = "AuthenticationError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Configuration error - missing or invalid settings
|
|
27
|
+
*/
|
|
28
|
+
export class ConfigurationError extends SkylightError {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message, "CONFIG_ERROR", undefined, true);
|
|
31
|
+
this.name = "ConfigurationError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resource not found
|
|
36
|
+
*/
|
|
37
|
+
export class NotFoundError extends SkylightError {
|
|
38
|
+
constructor(resource) {
|
|
39
|
+
super(`${resource} not found`, "NOT_FOUND", 404, false);
|
|
40
|
+
this.name = "NotFoundError";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Rate limited by the API
|
|
45
|
+
*/
|
|
46
|
+
export class RateLimitError extends SkylightError {
|
|
47
|
+
constructor(retryAfter) {
|
|
48
|
+
super(`Rate limited by Skylight API. ${retryAfter ? `Retry after ${retryAfter}s` : "Please wait and try again."}`, "RATE_LIMITED", 429, true);
|
|
49
|
+
this.name = "RateLimitError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* API returned an unexpected response format
|
|
54
|
+
*/
|
|
55
|
+
export class ParseError extends SkylightError {
|
|
56
|
+
constructor(message = "Unexpected API response format") {
|
|
57
|
+
super(message, "PARSE_ERROR", undefined, false);
|
|
58
|
+
this.name = "ParseError";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Format an error for MCP tool response
|
|
63
|
+
* Accepts unknown to handle any value from catch blocks safely
|
|
64
|
+
*/
|
|
65
|
+
export function formatErrorForMcp(error) {
|
|
66
|
+
if (error instanceof AuthenticationError) {
|
|
67
|
+
return `Authentication Error: ${error.message}
|
|
68
|
+
|
|
69
|
+
Your Skylight token may have expired. To fix this:
|
|
70
|
+
1. If using email/password auth, retry with valid SKYLIGHT_EMAIL and SKYLIGHT_PASSWORD
|
|
71
|
+
2. If using a manual token, capture fresh API traffic using a proxy tool
|
|
72
|
+
3. Update your SKYLIGHT_TOKEN environment variable if you are using manual token auth
|
|
73
|
+
|
|
74
|
+
See the auth documentation for detailed steps.`;
|
|
75
|
+
}
|
|
76
|
+
if (error instanceof NotFoundError) {
|
|
77
|
+
return `Not Found: ${error.message}
|
|
78
|
+
|
|
79
|
+
This could mean:
|
|
80
|
+
- The requested item doesn't exist
|
|
81
|
+
- Your frame ID is incorrect
|
|
82
|
+
- The item was deleted from Skylight`;
|
|
83
|
+
}
|
|
84
|
+
if (error instanceof RateLimitError) {
|
|
85
|
+
return `Rate Limited: ${error.message}
|
|
86
|
+
|
|
87
|
+
The Skylight API is temporarily limiting requests. Please wait a moment and try again.`;
|
|
88
|
+
}
|
|
89
|
+
if (error instanceof ConfigurationError) {
|
|
90
|
+
return `Configuration Error: ${error.message}
|
|
91
|
+
|
|
92
|
+
Please check your environment variables are set correctly.`;
|
|
93
|
+
}
|
|
94
|
+
if (error instanceof SkylightError) {
|
|
95
|
+
return `Skylight Error: ${error.message}`;
|
|
96
|
+
}
|
|
97
|
+
if (error instanceof Error) {
|
|
98
|
+
return `Error: ${error.message}`;
|
|
99
|
+
}
|
|
100
|
+
return `Error: ${String(error)}`;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAG7B;IACA;IACA;IAJT,YACE,OAAe,EACR,IAAY,EACZ,UAAmB,EACnB,cAAuB,KAAK;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAS;QACnB,gBAAW,GAAX,WAAW,CAAiB;QAGnC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IACpD,YAAY,UAAkB,8DAA8D;QAC1F,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,aAAa;IAC9C,YAAY,QAAgB;QAC1B,KAAK,CAAC,GAAG,QAAQ,YAAY,EAAE,WAAW,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,aAAa;IAC/C,YAAY,UAAmB;QAC7B,KAAK,CACH,iCAAiC,UAAU,CAAC,CAAC,CAAC,eAAe,UAAU,GAAG,CAAC,CAAC,CAAC,4BAA4B,EAAE,EAC3G,cAAc,EACd,GAAG,EACH,IAAI,CACL,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,aAAa;IAC3C,YAAY,UAAkB,gCAAgC;QAC5D,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;QACzC,OAAO,yBAAyB,KAAK,CAAC,OAAO;;;;;;;+CAOF,CAAC;IAC9C,CAAC;IAED,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;QACnC,OAAO,cAAc,KAAK,CAAC,OAAO;;;;;qCAKD,CAAC;IACpC,CAAC;IAED,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACpC,OAAO,iBAAiB,KAAK,CAAC,OAAO;;uFAE8C,CAAC;IACtF,CAAC;IAED,IAAI,KAAK,YAAY,kBAAkB,EAAE,CAAC;QACxC,OAAO,wBAAwB,KAAK,CAAC,OAAO;;2DAEW,CAAC;IAC1D,CAAC;IAED,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;QACnC,OAAO,mBAAmB,KAAK,CAAC,OAAO,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC;IAED,OAAO,UAAU,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure schedule math: time zones, intervals, conflicts and free slots.
|
|
3
|
+
*
|
|
4
|
+
* Everything here works in epoch milliseconds plus an IANA time zone, using
|
|
5
|
+
* Intl for the zone rules. No library. Written so that DST transitions and
|
|
6
|
+
* all-day events (which Skylight gives as midnight-to-midnight local ranges)
|
|
7
|
+
* are handled explicitly rather than by accident.
|
|
8
|
+
*/
|
|
9
|
+
export interface Interval {
|
|
10
|
+
/** Epoch ms, inclusive. */
|
|
11
|
+
start: number;
|
|
12
|
+
/** Epoch ms, exclusive. */
|
|
13
|
+
end: number;
|
|
14
|
+
allDay: boolean;
|
|
15
|
+
summary: string;
|
|
16
|
+
/** Free-form origin, e.g. "calendar", "chore". */
|
|
17
|
+
kind: string;
|
|
18
|
+
id?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Conflict {
|
|
21
|
+
a: Interval;
|
|
22
|
+
b: Interval;
|
|
23
|
+
/** Overlap window, epoch ms. */
|
|
24
|
+
overlapStart: number;
|
|
25
|
+
overlapEnd: number;
|
|
26
|
+
}
|
|
27
|
+
export interface FreeSlot {
|
|
28
|
+
/** YYYY-MM-DD in the zone. */
|
|
29
|
+
date: string;
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
minutes: number;
|
|
33
|
+
}
|
|
34
|
+
export interface LocalParts {
|
|
35
|
+
year: number;
|
|
36
|
+
month: number;
|
|
37
|
+
day: number;
|
|
38
|
+
hour: number;
|
|
39
|
+
minute: number;
|
|
40
|
+
second: number;
|
|
41
|
+
}
|
|
42
|
+
/** Wall-clock parts of an instant in a zone. */
|
|
43
|
+
export declare function toLocalParts(epochMs: number, timeZone: string): LocalParts;
|
|
44
|
+
/** Zone offset in ms at an instant (UTC = local + offset... i.e. local - utc). */
|
|
45
|
+
export declare function offsetAt(epochMs: number, timeZone: string): number;
|
|
46
|
+
/**
|
|
47
|
+
* Epoch ms for a wall-clock time in a zone. Handles DST: a nonexistent time
|
|
48
|
+
* (spring-forward gap) resolves to the instant after the gap; an ambiguous
|
|
49
|
+
* time (fall-back) resolves to the earlier instant.
|
|
50
|
+
*/
|
|
51
|
+
export declare function zonedToEpoch(date: string, time: string, timeZone: string): number;
|
|
52
|
+
/** YYYY-MM-DD of an instant in a zone. */
|
|
53
|
+
export declare function dateInZone(epochMs: number, timeZone: string): string;
|
|
54
|
+
/** Add days to a YYYY-MM-DD string (calendar days, no zone involved). */
|
|
55
|
+
export declare function addDays(date: string, days: number): string;
|
|
56
|
+
/** Inclusive list of YYYY-MM-DD from start to end. */
|
|
57
|
+
export declare function eachDay(start: string, end: string): string[];
|
|
58
|
+
/** "9:00 AM" style, in zone. */
|
|
59
|
+
export declare function formatTime(epochMs: number, timeZone: string): string;
|
|
60
|
+
export declare function formatRange(start: number, end: number, timeZone: string): string;
|
|
61
|
+
/** "Thu, Oct 29" for a YYYY-MM-DD. */
|
|
62
|
+
export declare function formatDay(date: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Build an interval from a Skylight calendar event. `starts_at`/`ends_at`
|
|
65
|
+
* are ISO strings with offsets; all-day events are local midnight ranges
|
|
66
|
+
* whose end is the following midnight (exclusive).
|
|
67
|
+
*/
|
|
68
|
+
export declare function eventToInterval(event: {
|
|
69
|
+
id: string;
|
|
70
|
+
attributes: Record<string, unknown>;
|
|
71
|
+
}, timeZone: string): Interval | null;
|
|
72
|
+
/** Timed intervals that overlap. All-day items never conflict. */
|
|
73
|
+
export declare function findConflicts(intervals: Interval[]): Conflict[];
|
|
74
|
+
export interface FreeSlotOptions {
|
|
75
|
+
/** HH:MM local, inclusive window start. */
|
|
76
|
+
earliest: string;
|
|
77
|
+
/** HH:MM local, window end. */
|
|
78
|
+
latest: string;
|
|
79
|
+
minMinutes: number;
|
|
80
|
+
timeZone: string;
|
|
81
|
+
}
|
|
82
|
+
/** Gaps of at least `minMinutes` within each day's window, around timed intervals. */
|
|
83
|
+
export declare function findFreeSlots(intervals: Interval[], days: string[], options: FreeSlotOptions): FreeSlot[];
|
|
84
|
+
/** Group intervals by the local date they start on (multi-day all-day events appear on each day). */
|
|
85
|
+
export declare function groupByDay(intervals: Interval[], days: string[], timeZone: string): Map<string, Interval[]>;
|
|
86
|
+
//# sourceMappingURL=schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../src/utils/schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure schedule math: time zones, intervals, conflicts and free slots.
|
|
3
|
+
*
|
|
4
|
+
* Everything here works in epoch milliseconds plus an IANA time zone, using
|
|
5
|
+
* Intl for the zone rules. No library. Written so that DST transitions and
|
|
6
|
+
* all-day events (which Skylight gives as midnight-to-midnight local ranges)
|
|
7
|
+
* are handled explicitly rather than by accident.
|
|
8
|
+
*/
|
|
9
|
+
const partsCache = new Map();
|
|
10
|
+
function formatter(timeZone) {
|
|
11
|
+
let f = partsCache.get(timeZone);
|
|
12
|
+
if (!f) {
|
|
13
|
+
f = new Intl.DateTimeFormat("en-US", {
|
|
14
|
+
timeZone,
|
|
15
|
+
hourCycle: "h23",
|
|
16
|
+
year: "numeric",
|
|
17
|
+
month: "2-digit",
|
|
18
|
+
day: "2-digit",
|
|
19
|
+
hour: "2-digit",
|
|
20
|
+
minute: "2-digit",
|
|
21
|
+
second: "2-digit",
|
|
22
|
+
});
|
|
23
|
+
partsCache.set(timeZone, f);
|
|
24
|
+
}
|
|
25
|
+
return f;
|
|
26
|
+
}
|
|
27
|
+
/** Wall-clock parts of an instant in a zone. */
|
|
28
|
+
export function toLocalParts(epochMs, timeZone) {
|
|
29
|
+
const parts = formatter(timeZone).formatToParts(new Date(epochMs));
|
|
30
|
+
const get = (type) => Number(parts.find((p) => p.type === type)?.value ?? "0");
|
|
31
|
+
return { year: get("year"), month: get("month"), day: get("day"), hour: get("hour") % 24, minute: get("minute"), second: get("second") };
|
|
32
|
+
}
|
|
33
|
+
/** Zone offset in ms at an instant (UTC = local + offset... i.e. local - utc). */
|
|
34
|
+
export function offsetAt(epochMs, timeZone) {
|
|
35
|
+
const p = toLocalParts(epochMs, timeZone);
|
|
36
|
+
const asUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
|
|
37
|
+
return asUtc - Math.floor(epochMs / 1000) * 1000;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Epoch ms for a wall-clock time in a zone. Handles DST: a nonexistent time
|
|
41
|
+
* (spring-forward gap) resolves to the instant after the gap; an ambiguous
|
|
42
|
+
* time (fall-back) resolves to the earlier instant.
|
|
43
|
+
*/
|
|
44
|
+
export function zonedToEpoch(date, time, timeZone) {
|
|
45
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
46
|
+
const [hh, mm] = time.split(":").map(Number);
|
|
47
|
+
const wall = Date.UTC(y, m - 1, d, hh, mm, 0);
|
|
48
|
+
// First guess using the offset at the wall time interpreted as UTC, then refine.
|
|
49
|
+
let guess = wall - offsetAt(wall, timeZone);
|
|
50
|
+
const refined = wall - offsetAt(guess, timeZone);
|
|
51
|
+
if (refined !== guess) {
|
|
52
|
+
// Two candidate offsets around a transition. Pick the one that round-trips.
|
|
53
|
+
const candidates = [guess, refined];
|
|
54
|
+
const ok = candidates.filter((c) => {
|
|
55
|
+
const p = toLocalParts(c, timeZone);
|
|
56
|
+
return p.hour === hh && p.minute === mm && p.day === d;
|
|
57
|
+
});
|
|
58
|
+
guess = ok.length ? Math.min(...ok) : Math.max(guess, refined);
|
|
59
|
+
}
|
|
60
|
+
return guess;
|
|
61
|
+
}
|
|
62
|
+
/** YYYY-MM-DD of an instant in a zone. */
|
|
63
|
+
export function dateInZone(epochMs, timeZone) {
|
|
64
|
+
const p = toLocalParts(epochMs, timeZone);
|
|
65
|
+
return `${p.year}-${String(p.month).padStart(2, "0")}-${String(p.day).padStart(2, "0")}`;
|
|
66
|
+
}
|
|
67
|
+
/** Add days to a YYYY-MM-DD string (calendar days, no zone involved). */
|
|
68
|
+
export function addDays(date, days) {
|
|
69
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
70
|
+
const t = Date.UTC(y, m - 1, d + days);
|
|
71
|
+
return new Date(t).toISOString().slice(0, 10);
|
|
72
|
+
}
|
|
73
|
+
/** Inclusive list of YYYY-MM-DD from start to end. */
|
|
74
|
+
export function eachDay(start, end) {
|
|
75
|
+
const out = [];
|
|
76
|
+
for (let d = start; d <= end; d = addDays(d, 1))
|
|
77
|
+
out.push(d);
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** "9:00 AM" style, in zone. */
|
|
81
|
+
export function formatTime(epochMs, timeZone) {
|
|
82
|
+
return new Date(epochMs).toLocaleTimeString("en-US", { timeZone, hour: "numeric", minute: "2-digit" });
|
|
83
|
+
}
|
|
84
|
+
export function formatRange(start, end, timeZone) {
|
|
85
|
+
return `${formatTime(start, timeZone)}–${formatTime(end, timeZone)}`;
|
|
86
|
+
}
|
|
87
|
+
/** "Thu, Oct 29" for a YYYY-MM-DD. */
|
|
88
|
+
export function formatDay(date) {
|
|
89
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
90
|
+
return new Date(Date.UTC(y, m - 1, d)).toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", timeZone: "UTC" });
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build an interval from a Skylight calendar event. `starts_at`/`ends_at`
|
|
94
|
+
* are ISO strings with offsets; all-day events are local midnight ranges
|
|
95
|
+
* whose end is the following midnight (exclusive).
|
|
96
|
+
*/
|
|
97
|
+
export function eventToInterval(event, timeZone) {
|
|
98
|
+
const a = event.attributes;
|
|
99
|
+
const summary = typeof a.summary === "string" ? a.summary : "(untitled)";
|
|
100
|
+
const allDay = a.all_day === true;
|
|
101
|
+
const startRaw = typeof a.starts_at === "string" ? a.starts_at : null;
|
|
102
|
+
const endRaw = typeof a.ends_at === "string" ? a.ends_at : null;
|
|
103
|
+
if (!startRaw)
|
|
104
|
+
return null;
|
|
105
|
+
if (allDay) {
|
|
106
|
+
// Use the local date of the start, and the local date of the end (exclusive).
|
|
107
|
+
const startDate = startRaw.slice(0, 10);
|
|
108
|
+
const endDate = endRaw ? endRaw.slice(0, 10) : addDays(startDate, 1);
|
|
109
|
+
return {
|
|
110
|
+
start: zonedToEpoch(startDate, "00:00", timeZone),
|
|
111
|
+
end: zonedToEpoch(endDate > startDate ? endDate : addDays(startDate, 1), "00:00", timeZone),
|
|
112
|
+
allDay: true,
|
|
113
|
+
summary,
|
|
114
|
+
kind: "calendar",
|
|
115
|
+
id: event.id,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const start = Date.parse(startRaw);
|
|
119
|
+
const end = endRaw ? Date.parse(endRaw) : start + 60 * 60 * 1000;
|
|
120
|
+
if (Number.isNaN(start) || Number.isNaN(end))
|
|
121
|
+
return null;
|
|
122
|
+
return { start, end: Math.max(end, start), allDay: false, summary, kind: "calendar", id: event.id };
|
|
123
|
+
}
|
|
124
|
+
/** Timed intervals that overlap. All-day items never conflict. */
|
|
125
|
+
export function findConflicts(intervals) {
|
|
126
|
+
const timed = intervals.filter((i) => !i.allDay && i.end > i.start).sort((x, y) => x.start - y.start);
|
|
127
|
+
const out = [];
|
|
128
|
+
for (let i = 0; i < timed.length; i++) {
|
|
129
|
+
for (let j = i + 1; j < timed.length; j++) {
|
|
130
|
+
const a = timed[i];
|
|
131
|
+
const b = timed[j];
|
|
132
|
+
if (b.start >= a.end)
|
|
133
|
+
break; // sorted by start; nothing later can overlap a
|
|
134
|
+
const overlapStart = Math.max(a.start, b.start);
|
|
135
|
+
const overlapEnd = Math.min(a.end, b.end);
|
|
136
|
+
if (overlapEnd > overlapStart)
|
|
137
|
+
out.push({ a, b, overlapStart, overlapEnd });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
/** Gaps of at least `minMinutes` within each day's window, around timed intervals. */
|
|
143
|
+
export function findFreeSlots(intervals, days, options) {
|
|
144
|
+
const timed = intervals.filter((i) => !i.allDay && i.end > i.start).sort((x, y) => x.start - y.start);
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const date of days) {
|
|
147
|
+
const windowStart = zonedToEpoch(date, options.earliest, options.timeZone);
|
|
148
|
+
const windowEnd = zonedToEpoch(date, options.latest, options.timeZone);
|
|
149
|
+
if (windowEnd <= windowStart)
|
|
150
|
+
continue;
|
|
151
|
+
let cursor = windowStart;
|
|
152
|
+
for (const t of timed) {
|
|
153
|
+
if (t.end <= cursor || t.start >= windowEnd)
|
|
154
|
+
continue;
|
|
155
|
+
if (t.start > cursor)
|
|
156
|
+
push(date, cursor, Math.min(t.start, windowEnd));
|
|
157
|
+
cursor = Math.max(cursor, t.end);
|
|
158
|
+
if (cursor >= windowEnd)
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
if (cursor < windowEnd)
|
|
162
|
+
push(date, cursor, windowEnd);
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
function push(date, start, end) {
|
|
166
|
+
const minutes = Math.floor((end - start) / 60_000);
|
|
167
|
+
if (minutes >= options.minMinutes)
|
|
168
|
+
out.push({ date, start, end, minutes });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** Group intervals by the local date they start on (multi-day all-day events appear on each day). */
|
|
172
|
+
export function groupByDay(intervals, days, timeZone) {
|
|
173
|
+
const map = new Map(days.map((d) => [d, []]));
|
|
174
|
+
for (const i of intervals) {
|
|
175
|
+
if (i.allDay) {
|
|
176
|
+
const first = dateInZone(i.start, timeZone);
|
|
177
|
+
const last = dateInZone(i.end - 1, timeZone); // end is exclusive midnight
|
|
178
|
+
for (const d of eachDay(first, last))
|
|
179
|
+
map.get(d)?.push(i);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
map.get(dateInZone(i.start, timeZone))?.push(i);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (const list of map.values())
|
|
186
|
+
list.sort((x, y) => Number(y.allDay) - Number(x.allDay) || x.start - y.start);
|
|
187
|
+
return map;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/utils/schedule.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@davidwoods/skylight-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "Unofficial MCP server for Skylight Calendar: local (stdio) and hosted (Cloudflare Workers), with browser-paste OAuth sign-in and an encrypted credential store",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"skylight-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"THIRD_PARTY_NOTICES.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"dev": "tsx watch src/index.ts",
|
|
20
|
+
"test": "vitest",
|
|
21
|
+
"test:coverage": "vitest --coverage",
|
|
22
|
+
"lint": "eslint src/",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"prepare": "npm run build",
|
|
25
|
+
"generate:types": "openapi-typescript ../skylight-api/docs/openapi/openapi.yaml -o src/api/generated-types.ts",
|
|
26
|
+
"typecheck:worker": "tsc -p tsconfig.worker.json",
|
|
27
|
+
"worker:dev": "wrangler dev",
|
|
28
|
+
"worker:deploy": "wrangler deploy",
|
|
29
|
+
"worker:deploy:local": "wrangler deploy -c wrangler.local.jsonc",
|
|
30
|
+
"worker:setup": "node scripts/setup-worker.mjs",
|
|
31
|
+
"prepublishOnly": "npm run typecheck && npm run lint && vitest run && npm run build",
|
|
32
|
+
"test:live": "vitest run --config vitest.live.config.ts"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"mcp",
|
|
36
|
+
"skylight",
|
|
37
|
+
"calendar",
|
|
38
|
+
"model-context-protocol",
|
|
39
|
+
"claude",
|
|
40
|
+
"ai",
|
|
41
|
+
"family",
|
|
42
|
+
"chores"
|
|
43
|
+
],
|
|
44
|
+
"author": "David Woods",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/dwooods/skylight-mcp.git"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@cloudflare/workers-oauth-provider": "^1.2.4",
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
53
|
+
"zod": "^4.6.7"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@cloudflare/workers-types": "^5.20261029.1",
|
|
57
|
+
"@types/node": "^22.20.5",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
59
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
60
|
+
"eslint": "^8.57.0",
|
|
61
|
+
"openapi-typescript": "^7.0.0",
|
|
62
|
+
"tsx": "^4.7.0",
|
|
63
|
+
"typescript": "^5.4.5",
|
|
64
|
+
"vite": "^8.3.5",
|
|
65
|
+
"vitest": "^5.0.5",
|
|
66
|
+
"wrangler": "^4.156.0"
|
|
67
|
+
},
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public"
|
|
70
|
+
},
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=20.0.0"
|
|
73
|
+
},
|
|
74
|
+
"homepage": "https://github.com/dwooods/skylight-mcp#readme",
|
|
75
|
+
"bugs": {
|
|
76
|
+
"url": "https://github.com/dwooods/skylight-mcp/issues"
|
|
77
|
+
}
|
|
78
|
+
}
|