@shin1ohno/sage 0.7.8 → 0.8.4

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.
Files changed (43) hide show
  1. package/README.md +26 -8
  2. package/dist/config/loader.d.ts.map +1 -1
  3. package/dist/config/loader.js +30 -1
  4. package/dist/config/loader.js.map +1 -1
  5. package/dist/config/validation.d.ts +130 -0
  6. package/dist/config/validation.d.ts.map +1 -0
  7. package/dist/config/validation.js +53 -0
  8. package/dist/config/validation.js.map +1 -0
  9. package/dist/index.js +677 -214
  10. package/dist/index.js.map +1 -1
  11. package/dist/integrations/calendar-service.d.ts +6 -3
  12. package/dist/integrations/calendar-service.d.ts.map +1 -1
  13. package/dist/integrations/calendar-service.js +26 -4
  14. package/dist/integrations/calendar-service.js.map +1 -1
  15. package/dist/integrations/calendar-source-manager.d.ts +302 -0
  16. package/dist/integrations/calendar-source-manager.d.ts.map +1 -0
  17. package/dist/integrations/calendar-source-manager.js +862 -0
  18. package/dist/integrations/calendar-source-manager.js.map +1 -0
  19. package/dist/integrations/google-calendar-service.d.ts +176 -0
  20. package/dist/integrations/google-calendar-service.d.ts.map +1 -0
  21. package/dist/integrations/google-calendar-service.js +745 -0
  22. package/dist/integrations/google-calendar-service.js.map +1 -0
  23. package/dist/oauth/google-oauth-handler.d.ts +149 -0
  24. package/dist/oauth/google-oauth-handler.d.ts.map +1 -0
  25. package/dist/oauth/google-oauth-handler.js +365 -0
  26. package/dist/oauth/google-oauth-handler.js.map +1 -0
  27. package/dist/types/config.d.ts +15 -0
  28. package/dist/types/config.d.ts.map +1 -1
  29. package/dist/types/config.js +21 -0
  30. package/dist/types/config.js.map +1 -1
  31. package/dist/types/google-calendar-types.d.ts +139 -0
  32. package/dist/types/google-calendar-types.d.ts.map +1 -0
  33. package/dist/types/google-calendar-types.js +46 -0
  34. package/dist/types/google-calendar-types.js.map +1 -0
  35. package/dist/types/index.d.ts +1 -0
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/types/index.js +1 -0
  38. package/dist/types/index.js.map +1 -1
  39. package/dist/version.d.ts +2 -2
  40. package/dist/version.d.ts.map +1 -1
  41. package/dist/version.js +22 -4
  42. package/dist/version.js.map +1 -1
  43. package/package.json +4 -3
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Calendar Source Manager
3
+ * Requirements: 9, 11
4
+ * Design: .claude/specs/google-calendar-api/design.md (CalendarSourceManager section)
5
+ *
6
+ * Manages multiple calendar sources (EventKit, Google Calendar) with automatic
7
+ * source selection, fallback handling, and unified MCP tool interface.
8
+ */
9
+ import { CalendarService } from './calendar-service.js';
10
+ import type { CalendarEvent, AvailableSlot } from './calendar-service.js';
11
+ import { GoogleCalendarService } from './google-calendar-service.js';
12
+ import type { CreateEventRequest } from './google-calendar-service.js';
13
+ import type { UserConfig } from '../types/config.js';
14
+ import type { SyncResult, SyncStatus } from '../types/google-calendar-types.js';
15
+ /**
16
+ * Request interface for finding available slots
17
+ * Requirement: 7
18
+ */
19
+ export interface FindSlotsRequest {
20
+ startDate: string;
21
+ endDate: string;
22
+ minDurationMinutes?: number;
23
+ maxDurationMinutes?: number;
24
+ workingHours?: {
25
+ start: string;
26
+ end: string;
27
+ };
28
+ }
29
+ /**
30
+ * Options for CalendarSourceManager constructor
31
+ */
32
+ export interface CalendarSourceManagerOptions {
33
+ calendarService?: CalendarService;
34
+ googleCalendarService?: GoogleCalendarService;
35
+ config?: UserConfig;
36
+ }
37
+ /**
38
+ * Calendar Source Manager
39
+ *
40
+ * Manages multiple calendar sources (EventKit, Google Calendar) with:
41
+ * - Automatic source detection and selection
42
+ * - Unified event operations across sources
43
+ * - Fallback handling for source failures
44
+ * - Event deduplication across sources
45
+ */
46
+ export declare class CalendarSourceManager {
47
+ private calendarService?;
48
+ private googleCalendarService?;
49
+ private config?;
50
+ /**
51
+ * Constructor
52
+ *
53
+ * @param options - Optional services and config
54
+ */
55
+ constructor(options?: CalendarSourceManagerOptions);
56
+ /**
57
+ * Detect available calendar sources
58
+ * Requirement: 9 (Platform detection and source availability)
59
+ *
60
+ * Uses detectPlatform() pattern from CalendarService to determine which
61
+ * calendar sources are available on the current platform.
62
+ *
63
+ * @returns Object indicating which sources are available
64
+ */
65
+ detectAvailableSources(): Promise<{
66
+ eventkit: boolean;
67
+ google: boolean;
68
+ }>;
69
+ /**
70
+ * Enable a calendar source
71
+ * Requirement: 11 (Calendar source management)
72
+ *
73
+ * Updates config to enable the specified source and validates that
74
+ * at least one source remains enabled.
75
+ *
76
+ * @param source - Calendar source to enable ('eventkit' | 'google')
77
+ * @throws Error if config is not available
78
+ */
79
+ enableSource(source: 'eventkit' | 'google'): Promise<void>;
80
+ /**
81
+ * Disable a calendar source
82
+ * Requirement: 11 (Calendar source management)
83
+ *
84
+ * Updates config to disable the specified source and validates that
85
+ * at least one source remains enabled.
86
+ *
87
+ * @param source - Calendar source to disable ('eventkit' | 'google')
88
+ * @throws Error if disabling would leave no sources enabled
89
+ */
90
+ disableSource(source: 'eventkit' | 'google'): Promise<void>;
91
+ /**
92
+ * Get enabled calendar sources
93
+ * Requirement: 9 (Source configuration reading)
94
+ *
95
+ * Reads from config.calendar.sources to determine which sources are enabled.
96
+ *
97
+ * @returns Array of enabled source names
98
+ */
99
+ getEnabledSources(): ('eventkit' | 'google')[];
100
+ /**
101
+ * Get events from enabled calendar sources
102
+ * Requirement: 7, 10, 11 (Multi-source event retrieval with deduplication and fallback)
103
+ *
104
+ * Fetches events from all enabled sources with fallback handling and deduplication.
105
+ * - Task 17a: Basic parallel fetching
106
+ * - Task 17b: Deduplication and fallback logic
107
+ *
108
+ * Fallback behavior: If one source fails, continues with other sources.
109
+ * Only throws if ALL sources fail.
110
+ *
111
+ * @param startDate - Start date (ISO 8601)
112
+ * @param endDate - End date (ISO 8601)
113
+ * @param calendarId - Optional calendar ID filter
114
+ * @returns Array of deduplicated calendar events from all enabled sources
115
+ */
116
+ getEvents(startDate: string, endDate: string, calendarId?: string): Promise<CalendarEvent[]>;
117
+ /**
118
+ * Check if two events are duplicates
119
+ * Requirement: 10 (Event deduplication)
120
+ *
121
+ * Uses two methods to detect duplicates:
122
+ * 1. iCalUID comparison (most reliable, RFC 5545 standard)
123
+ * 2. Title + time matching (fallback for events without iCalUID)
124
+ *
125
+ * Note: iCalUID support will be added in Task 24. Until then, this uses
126
+ * type assertions to access the optional iCalUID property.
127
+ *
128
+ * @param event1 - First event
129
+ * @param event2 - Second event
130
+ * @returns True if events are duplicates
131
+ */
132
+ private areEventsDuplicate;
133
+ /**
134
+ * Deduplicate events array
135
+ * Requirement: 10 (Event deduplication)
136
+ *
137
+ * Removes duplicate events keeping the first occurrence.
138
+ * Uses areEventsDuplicate() for comparison.
139
+ *
140
+ * @param events - Array of events to deduplicate
141
+ * @returns Array of unique events
142
+ */
143
+ private deduplicateEvents;
144
+ /**
145
+ * Create event in preferred calendar source
146
+ * Requirement: 3, 10, 11 (Multi-source event creation with routing and fallback)
147
+ *
148
+ * Creates an event in the specified source with fallback handling:
149
+ * 1. If preferredSource is specified, try that source first
150
+ * 2. If preferred source fails or not specified, try other enabled sources
151
+ * 3. Throws error if all sources fail
152
+ *
153
+ * Note: EventKit does not support event creation in current implementation,
154
+ * so only Google Calendar is supported for event creation.
155
+ *
156
+ * @param request - Event creation request
157
+ * @param preferredSource - Preferred source ('eventkit' | 'google')
158
+ * @returns Created calendar event
159
+ * @throws Error if all sources fail or no sources are enabled
160
+ */
161
+ createEvent(request: CreateEventRequest, preferredSource?: 'eventkit' | 'google'): Promise<CalendarEvent>;
162
+ /**
163
+ * Delete event from calendar source
164
+ * Requirement: 5, 10, 11 (Multi-source event deletion with routing and error handling)
165
+ *
166
+ * Deletes an event from the specified source, or attempts deletion
167
+ * from all sources if source is not specified.
168
+ *
169
+ * If source specified:
170
+ * - Deletes from that source only
171
+ * - Throws error if source is not enabled or service not available
172
+ *
173
+ * If source not specified:
174
+ * - Attempts to delete from ALL enabled sources
175
+ * - Event may exist in both EventKit and Google Calendar (duplicate)
176
+ * - Uses Promise.allSettled() to try all sources
177
+ * - 404 errors (event not found) do not cause failure
178
+ * - Only throws if ALL attempts fail with non-404 errors
179
+ *
180
+ * @param eventId - Event ID to delete
181
+ * @param source - Optional source ('eventkit' | 'google')
182
+ * @throws Error if source specified and not available, or all sources fail with non-404 errors
183
+ */
184
+ deleteEvent(eventId: string, source?: 'eventkit' | 'google'): Promise<void>;
185
+ /**
186
+ * Find available time slots considering all enabled sources
187
+ * Requirement: 7 (Multi-source slot detection)
188
+ * Task 20a: Basic filtering implementation
189
+ * Task 20b: Suitability calculation integration
190
+ *
191
+ * Fetches events from all enabled sources, merges and deduplicates,
192
+ * then calculates available slots based on working hours and preferences.
193
+ * Applies suitability scoring and sorts by suitability.
194
+ *
195
+ * @param request - Slot search request
196
+ * @returns Array of available time slots sorted by suitability
197
+ */
198
+ findAvailableSlots(request: FindSlotsRequest): Promise<AvailableSlot[]>;
199
+ /**
200
+ * Get default working hours
201
+ * Requirement: 7
202
+ *
203
+ * Returns working hours from config or default (09:00 - 18:00)
204
+ *
205
+ * @returns Working hours configuration
206
+ */
207
+ private getDefaultWorkingHours;
208
+ /**
209
+ * Calculate suitability for all slots
210
+ * Requirement: 7 (Task 20b)
211
+ *
212
+ * Applies suitability scoring to slots based on:
213
+ * - Day type (deep work vs meeting heavy) from config
214
+ * - Time of day (morning slots preferred)
215
+ * - Slot duration (longer slots better for deep work)
216
+ *
217
+ * @param slots - Array of slots to score
218
+ * @returns Array of slots with suitability applied
219
+ */
220
+ private calculateSuitabilityForSlots;
221
+ /**
222
+ * Find available slots for a single day
223
+ * Requirement: 7
224
+ *
225
+ * Calculates gaps between events within working hours for a specific day.
226
+ *
227
+ * @param date - Date to find slots for
228
+ * @param events - All events (sorted by start time)
229
+ * @param workingHours - Working hours configuration
230
+ * @param minDuration - Minimum slot duration in minutes
231
+ * @param maxDuration - Maximum slot duration in minutes
232
+ * @returns Array of available slots for this day
233
+ */
234
+ private findDaySlots;
235
+ /**
236
+ * Sync calendars between sources
237
+ * Requirement: 8 (Calendar synchronization)
238
+ *
239
+ * Synchronizes events between EventKit and Google Calendar when both
240
+ * sources are enabled. Handles conflicts and provides sync results.
241
+ *
242
+ * Note: This is a stub implementation. Full sync logic can be added later.
243
+ * Currently, it validates that both sources are enabled and returns empty results.
244
+ *
245
+ * @returns Sync result with statistics and errors
246
+ * @throws Error if both sources are not enabled
247
+ */
248
+ syncCalendars(): Promise<SyncResult>;
249
+ /**
250
+ * Get sync status between calendar sources
251
+ * Requirement: 8 (Calendar synchronization)
252
+ *
253
+ * Returns the current sync status including last sync time,
254
+ * next scheduled sync, and source availability.
255
+ *
256
+ * Note: This is a stub implementation. lastSyncTime tracking will be added
257
+ * when full sync implementation is completed.
258
+ *
259
+ * @returns Sync status information
260
+ */
261
+ getSyncStatus(): Promise<SyncStatus>;
262
+ /**
263
+ * Health check for calendar sources
264
+ * Requirement: 10, 11 (Health check for both sources)
265
+ * Task 22: Implementation
266
+ *
267
+ * Checks availability and health of all calendar sources by calling
268
+ * their respective isAvailable() methods. Returns a status object
269
+ * indicating which sources are currently healthy and available.
270
+ *
271
+ * This method never throws errors - it catches all failures and returns
272
+ * false for sources that are unavailable or unhealthy.
273
+ *
274
+ * @returns Object indicating health status of each source
275
+ */
276
+ healthCheck(): Promise<{
277
+ eventkit: boolean;
278
+ google: boolean;
279
+ }>;
280
+ /**
281
+ * Respond to a calendar event
282
+ * Requirement: 6 (Event response/RSVP)
283
+ *
284
+ * Routes event response to the appropriate calendar source.
285
+ * Supports EventKit (via CalendarEventResponseService) and Google Calendar.
286
+ * If source is not specified, attempts to determine source by fetching
287
+ * the event from all enabled sources.
288
+ *
289
+ * @param eventId - Event ID
290
+ * @param response - Response type: 'accept', 'decline', or 'tentative'
291
+ * @param source - Optional source routing ('eventkit' or 'google')
292
+ * @param calendarId - Optional calendar ID (for Google Calendar)
293
+ * @returns Success status and message
294
+ * @throws Error if event not found or response fails
295
+ */
296
+ respondToEvent(eventId: string, response: 'accept' | 'decline' | 'tentative', source?: 'eventkit' | 'google', calendarId?: string): Promise<{
297
+ success: boolean;
298
+ message: string;
299
+ source?: string;
300
+ }>;
301
+ }
302
+ //# sourceMappingURL=calendar-source-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar-source-manager.d.ts","sourceRoot":"","sources":["../../src/integrations/calendar-source-manager.ts"],"names":[],"mappings":"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"}