@laylzj777/my-apple-apple-eventkit 1.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +575 -0
  2. package/LICENSE +21 -0
  3. package/README.md +304 -0
  4. package/README.zh-CN.md +270 -0
  5. package/bin/event +0 -0
  6. package/bin/event-disclaim +0 -0
  7. package/dist/bin/apple-calendar.d.ts +6 -0
  8. package/dist/bin/apple-calendar.js +8 -0
  9. package/dist/bin/apple-calendar.js.map +1 -0
  10. package/dist/bin/apple-reminders.d.ts +7 -0
  11. package/dist/bin/apple-reminders.js +9 -0
  12. package/dist/bin/apple-reminders.js.map +1 -0
  13. package/dist/bootstrap.d.ts +11 -0
  14. package/dist/bootstrap.js +44 -0
  15. package/dist/bootstrap.js.map +1 -0
  16. package/dist/index.d.ts +10 -0
  17. package/dist/index.js +12 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/server/handlers.d.ts +12 -0
  20. package/dist/server/handlers.js +58 -0
  21. package/dist/server/handlers.js.map +1 -0
  22. package/dist/server/mode.d.ts +19 -0
  23. package/dist/server/mode.js +47 -0
  24. package/dist/server/mode.js.map +1 -0
  25. package/dist/server/promptAbstractions.d.ts +61 -0
  26. package/dist/server/promptAbstractions.js +140 -0
  27. package/dist/server/promptAbstractions.js.map +1 -0
  28. package/dist/server/prompts.d.ts +13 -0
  29. package/dist/server/prompts.js +461 -0
  30. package/dist/server/prompts.js.map +1 -0
  31. package/dist/server/server.d.ts +61 -0
  32. package/dist/server/server.js +112 -0
  33. package/dist/server/server.js.map +1 -0
  34. package/dist/tools/definitions.d.ts +9 -0
  35. package/dist/tools/definitions.js +272 -0
  36. package/dist/tools/definitions.js.map +1 -0
  37. package/dist/tools/handlers/calendarHandlers.d.ts +11 -0
  38. package/dist/tools/handlers/calendarHandlers.js +151 -0
  39. package/dist/tools/handlers/calendarHandlers.js.map +1 -0
  40. package/dist/tools/handlers/formatters.d.ts +24 -0
  41. package/dist/tools/handlers/formatters.js +105 -0
  42. package/dist/tools/handlers/formatters.js.map +1 -0
  43. package/dist/tools/handlers/index.d.ts +8 -0
  44. package/dist/tools/handlers/index.js +9 -0
  45. package/dist/tools/handlers/index.js.map +1 -0
  46. package/dist/tools/handlers/listHandlers.d.ts +10 -0
  47. package/dist/tools/handlers/listHandlers.js +47 -0
  48. package/dist/tools/handlers/listHandlers.js.map +1 -0
  49. package/dist/tools/handlers/reminderHandlers.d.ts +10 -0
  50. package/dist/tools/handlers/reminderHandlers.js +219 -0
  51. package/dist/tools/handlers/reminderHandlers.js.map +1 -0
  52. package/dist/tools/handlers/shared.d.ts +28 -0
  53. package/dist/tools/handlers/shared.js +57 -0
  54. package/dist/tools/handlers/shared.js.map +1 -0
  55. package/dist/tools/handlers/subtaskHandlers.d.ts +12 -0
  56. package/dist/tools/handlers/subtaskHandlers.js +113 -0
  57. package/dist/tools/handlers/subtaskHandlers.js.map +1 -0
  58. package/dist/tools/index.d.ts +10 -0
  59. package/dist/tools/index.js +74 -0
  60. package/dist/tools/index.js.map +1 -0
  61. package/dist/types/index.d.ts +263 -0
  62. package/dist/types/index.js +42 -0
  63. package/dist/types/index.js.map +1 -0
  64. package/dist/types/prompts.d.ts +88 -0
  65. package/dist/types/prompts.js +6 -0
  66. package/dist/types/prompts.js.map +1 -0
  67. package/dist/types/repository.d.ts +197 -0
  68. package/dist/types/repository.js +14 -0
  69. package/dist/types/repository.js.map +1 -0
  70. package/dist/utils/binaryValidator.d.ts +52 -0
  71. package/dist/utils/binaryValidator.js +185 -0
  72. package/dist/utils/binaryValidator.js.map +1 -0
  73. package/dist/utils/calendarRepository.d.ts +49 -0
  74. package/dist/utils/calendarRepository.js +226 -0
  75. package/dist/utils/calendarRepository.js.map +1 -0
  76. package/dist/utils/constants.d.ts +79 -0
  77. package/dist/utils/constants.js +80 -0
  78. package/dist/utils/constants.js.map +1 -0
  79. package/dist/utils/dateFiltering.d.ts +41 -0
  80. package/dist/utils/dateFiltering.js +129 -0
  81. package/dist/utils/dateFiltering.js.map +1 -0
  82. package/dist/utils/dateUtils.d.ts +27 -0
  83. package/dist/utils/dateUtils.js +71 -0
  84. package/dist/utils/dateUtils.js.map +1 -0
  85. package/dist/utils/errorHandling.d.ts +27 -0
  86. package/dist/utils/errorHandling.js +88 -0
  87. package/dist/utils/errorHandling.js.map +1 -0
  88. package/dist/utils/eventCli.d.ts +40 -0
  89. package/dist/utils/eventCli.js +294 -0
  90. package/dist/utils/eventCli.js.map +1 -0
  91. package/dist/utils/helpers.d.ts +35 -0
  92. package/dist/utils/helpers.js +61 -0
  93. package/dist/utils/helpers.js.map +1 -0
  94. package/dist/utils/looseDateParser.d.ts +19 -0
  95. package/dist/utils/looseDateParser.js +149 -0
  96. package/dist/utils/looseDateParser.js.map +1 -0
  97. package/dist/utils/projectUtils.d.ts +13 -0
  98. package/dist/utils/projectUtils.js +92 -0
  99. package/dist/utils/projectUtils.js.map +1 -0
  100. package/dist/utils/reminderDateParser.d.ts +8 -0
  101. package/dist/utils/reminderDateParser.js +89 -0
  102. package/dist/utils/reminderDateParser.js.map +1 -0
  103. package/dist/utils/reminderRepository.d.ts +33 -0
  104. package/dist/utils/reminderRepository.js +262 -0
  105. package/dist/utils/reminderRepository.js.map +1 -0
  106. package/dist/utils/subtaskUtils.d.ts +103 -0
  107. package/dist/utils/subtaskUtils.js +253 -0
  108. package/dist/utils/subtaskUtils.js.map +1 -0
  109. package/dist/utils/tagUtils.d.ts +58 -0
  110. package/dist/utils/tagUtils.js +177 -0
  111. package/dist/utils/tagUtils.js.map +1 -0
  112. package/dist/utils/timeHelpers.d.ts +40 -0
  113. package/dist/utils/timeHelpers.js +136 -0
  114. package/dist/utils/timeHelpers.js.map +1 -0
  115. package/dist/validation/schemas.d.ts +385 -0
  116. package/dist/validation/schemas.js +579 -0
  117. package/dist/validation/schemas.js.map +1 -0
  118. package/package.json +96 -0
  119. package/scripts/build-event.mjs +513 -0
  120. package/scripts/disclaim.c +69 -0
  121. package/scripts/event-Info.plist +29 -0
  122. package/scripts/event.entitlements +10 -0
  123. package/scripts/postinstall.mjs +91 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * utils/binaryValidator.ts
3
+ * Secure binary path validation and integrity checking
4
+ */
5
+ import crypto from 'node:crypto';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ /**
9
+ * Default security configuration.
10
+ *
11
+ * Each `allowedPaths` entry is a path suffix that the candidate binary must
12
+ * match against either its full normalized path or its parent directory.
13
+ * Suffix matching is segment-aligned so `foo-bin` doesn't partial-match
14
+ * `bin`. The defaults intentionally do NOT include a bare `bin` entry — that
15
+ * would pass for any `/<anywhere>/bin/<anything>` (e.g. `/usr/local/bin/curl`).
16
+ * Production callers pass an absolute path tied to the project root via
17
+ * configuration (see `src/utils/eventCli.ts`); the defaults below exist for
18
+ * tests that exercise the suffix matcher.
19
+ */
20
+ const DEFAULT_CONFIG = {
21
+ maxFileSize: 50 * 1024 * 1024, // 50MB max
22
+ allowedPaths: ['dist/swift/bin', 'src/swift/bin', 'swift/bin', 'bin/event'],
23
+ requireAbsolutePath: true,
24
+ };
25
+ /**
26
+ * Binary validation error
27
+ */
28
+ export class BinaryValidationError extends Error {
29
+ constructor(message, code) {
30
+ super(message);
31
+ this.code = code;
32
+ this.name = 'BinaryValidationError';
33
+ }
34
+ }
35
+ /**
36
+ * Validates binary path for security
37
+ */
38
+ export function validateBinaryPath(binaryPath, config = {}) {
39
+ const fullConfig = { ...DEFAULT_CONFIG, ...config };
40
+ if (fullConfig.requireAbsolutePath && !path.isAbsolute(binaryPath)) {
41
+ throw new BinaryValidationError('Binary path must be absolute', 'INVALID_PATH');
42
+ }
43
+ const normalizedPath = path.normalize(binaryPath);
44
+ // `path.normalize` resolves any embedded `..`, so a surviving `..` segment
45
+ // would only come from a deliberately malformed input — check segments
46
+ // rather than substring (`..foo` is a legal filename).
47
+ const segments = normalizedPath.split(path.sep);
48
+ if (segments.includes('..')) {
49
+ throw new BinaryValidationError('Path traversal detected in binary path', 'PATH_TRAVERSAL');
50
+ }
51
+ // An entry matches when it is a suffix of either the full binary path
52
+ // (including its filename, e.g. `bin/event`) or the binary's parent
53
+ // directory. Suffix matching is segment-aligned — `endsWith('/bin')` after
54
+ // stripping trailing separators avoids the `foo-bin` partial-match trap
55
+ // while still working for absolute and relative allowed paths.
56
+ const parentDir = path.dirname(normalizedPath);
57
+ const isInAllowedPath = fullConfig.allowedPaths.some((allowedPath) => {
58
+ const allowedNormalized = path
59
+ .normalize(allowedPath)
60
+ .replace(/[\\/]+$/, '');
61
+ if (!allowedNormalized)
62
+ return false;
63
+ const sepSuffix = path.sep + allowedNormalized;
64
+ return (normalizedPath === allowedNormalized ||
65
+ normalizedPath.endsWith(sepSuffix) ||
66
+ parentDir === allowedNormalized ||
67
+ parentDir.endsWith(sepSuffix));
68
+ });
69
+ if (!isInAllowedPath) {
70
+ throw new BinaryValidationError('Binary path not in allowed directories', 'FORBIDDEN_PATH');
71
+ }
72
+ if (!fs.existsSync(normalizedPath)) {
73
+ throw new BinaryValidationError(`Binary file not found: ${normalizedPath}`, 'FILE_NOT_FOUND');
74
+ }
75
+ const stats = fs.statSync(normalizedPath);
76
+ if (!stats.isFile()) {
77
+ throw new BinaryValidationError('Binary path does not point to a file', 'NOT_A_FILE');
78
+ }
79
+ if (stats.size > fullConfig.maxFileSize) {
80
+ throw new BinaryValidationError(`Binary file too large: ${stats.size} bytes`, 'FILE_TOO_LARGE');
81
+ }
82
+ try {
83
+ fs.accessSync(normalizedPath, fs.constants.X_OK);
84
+ }
85
+ catch (_error) {
86
+ throw new BinaryValidationError('Binary file is not executable', 'NOT_EXECUTABLE');
87
+ }
88
+ }
89
+ /**
90
+ * Calculates SHA256 hash of binary file
91
+ */
92
+ export function calculateBinaryHash(binaryPath) {
93
+ try {
94
+ const fileBuffer = fs.readFileSync(binaryPath);
95
+ return crypto.createHash('sha256').update(fileBuffer).digest('hex');
96
+ }
97
+ catch (error) {
98
+ throw new BinaryValidationError(`Failed to calculate binary hash: ${error.message}`, 'HASH_CALCULATION_FAILED');
99
+ }
100
+ }
101
+ /**
102
+ * Validates binary integrity using hash
103
+ */
104
+ export function validateBinaryIntegrity(binaryPath, expectedHash) {
105
+ try {
106
+ const actualHash = calculateBinaryHash(binaryPath);
107
+ const isValid = actualHash === expectedHash;
108
+ return isValid;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
114
+ /**
115
+ * Comprehensive binary security validation
116
+ */
117
+ export function validateBinarySecurity(binaryPath, config = {}) {
118
+ const errors = [];
119
+ let hash;
120
+ try {
121
+ // Path validation
122
+ validateBinaryPath(binaryPath, config);
123
+ // Hashing the multi-MB binary takes 10–30 ms and blocks the event loop;
124
+ // only do it when the caller will actually compare the result.
125
+ if (config.expectedHash) {
126
+ hash = calculateBinaryHash(binaryPath);
127
+ if (hash !== config.expectedHash) {
128
+ errors.push('Binary integrity check failed - hash mismatch');
129
+ }
130
+ }
131
+ }
132
+ catch (error) {
133
+ if (error instanceof BinaryValidationError) {
134
+ errors.push(`${error.code}: ${error.message}`);
135
+ }
136
+ else {
137
+ errors.push(`Unexpected validation error: ${error.message}`);
138
+ }
139
+ }
140
+ return {
141
+ isValid: errors.length === 0,
142
+ hash,
143
+ errors,
144
+ };
145
+ }
146
+ /**
147
+ * Secure binary path finder with validation
148
+ */
149
+ export function findSecureBinaryPath(possiblePaths, config = {}) {
150
+ for (const binaryPath of possiblePaths) {
151
+ const validationResult = validateBinarySecurity(binaryPath, config);
152
+ if (validationResult.isValid) {
153
+ return { path: binaryPath, validationResult };
154
+ }
155
+ }
156
+ return { path: null };
157
+ }
158
+ /**
159
+ * Environment-specific binary validation
160
+ */
161
+ export function getEnvironmentBinaryConfig() {
162
+ if (process.env.NODE_ENV === 'test') {
163
+ // Relaxed validation for testing
164
+ return {
165
+ requireAbsolutePath: false,
166
+ maxFileSize: 100 * 1024 * 1024, // 100MB for test
167
+ };
168
+ }
169
+ if (process.env.NODE_ENV === 'development') {
170
+ // Development mode - log more details
171
+ return {
172
+ maxFileSize: 100 * 1024 * 1024, // 100MB for dev
173
+ };
174
+ }
175
+ // Production mode - strict validation
176
+ return {
177
+ expectedHash: process.env.SWIFT_BINARY_HASH,
178
+ // The universal bin/event sits at ~51.7MB today; 80MB matches the
179
+ // published-tarball size-sanity bound and leaves room for vendor bumps
180
+ // without surfacing as a misleading "binary not found" error.
181
+ maxFileSize: 80 * 1024 * 1024, // 80MB
182
+ requireAbsolutePath: true,
183
+ };
184
+ }
185
+ //# sourceMappingURL=binaryValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaryValidator.js","sourceRoot":"","sources":["../../src/utils/binaryValidator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * calendarRepository.ts
3
+ * Repository for calendar event data access via the vendored `event` CLI.
4
+ *
5
+ * Read-only fields (URL, structured location, all-day toggle, availability,
6
+ * alarms, recurrence rules) are passed through from JSON when present;
7
+ * write paths only cover what `event` exposes today. See
8
+ * `docs/migration-to-event-cli.md` for the full table.
9
+ */
10
+ import type { Calendar, CalendarEvent } from '../types/index.js';
11
+ import type { CreateEventData, EventJSON, ICalendarRepository, UpdateEventData } from '../types/repository.js';
12
+ type EventSpan = 'this-event' | 'future-events';
13
+ declare class CalendarRepository implements ICalendarRepository {
14
+ private listEvents;
15
+ private listEventsWideWindow;
16
+ findEventById(id: string): Promise<CalendarEvent>;
17
+ findEvents(filters?: {
18
+ startDate?: string;
19
+ endDate?: string;
20
+ calendarName?: string;
21
+ search?: string;
22
+ availability?: string;
23
+ }): Promise<CalendarEvent[]>;
24
+ /**
25
+ * `event` has no first-class "list calendars" command — calendar names are
26
+ * surfaced only as the `calendar` field on each event in `calendar list`.
27
+ * Derive a unique-by-name listing from a wide read window so callers of
28
+ * `calendar_calendars` see every calendar that contains an event. Calendars
29
+ * with zero events in the window won't appear; see
30
+ * `docs/migration-to-event-cli.md` for the workaround.
31
+ */
32
+ findAllCalendars(): Promise<Calendar[]>;
33
+ /**
34
+ * When a date range is supplied, scope the listing to that window instead
35
+ * of the default wide window and annotate each calendar with how many
36
+ * events it contributed — this is the only per-calendar signal `event`
37
+ * exposes (it has no EventKit account/identifier info to filter or key
38
+ * on), so counts are grouped by calendar title rather than a stable id.
39
+ */
40
+ findCalendars(filters?: {
41
+ startDate?: string;
42
+ endDate?: string;
43
+ }): Promise<Calendar[]>;
44
+ createEvent(data: CreateEventData): Promise<EventJSON>;
45
+ updateEvent(data: UpdateEventData): Promise<EventJSON>;
46
+ deleteEvent(id: string, span?: EventSpan): Promise<void>;
47
+ }
48
+ export declare const calendarRepository: CalendarRepository;
49
+ export { CalendarRepository };
@@ -0,0 +1,226 @@
1
+ /**
2
+ * calendarRepository.ts
3
+ * Repository for calendar event data access via the vendored `event` CLI.
4
+ *
5
+ * Read-only fields (URL, structured location, all-day toggle, availability,
6
+ * alarms, recurrence rules) are passed through from JSON when present;
7
+ * write paths only cover what `event` exposes today. See
8
+ * `docs/migration-to-event-cli.md` for the full table.
9
+ */
10
+ import { CliUserError } from './errorHandling.js';
11
+ import { executeEventCliJson, executeEventCliPlain } from './eventCli.js';
12
+ import { addOptionalArg, nullToUndefined } from './helpers.js';
13
+ import { parseReminderDueDate } from './reminderDateParser.js';
14
+ const DEFAULT_READ_WINDOW_DAYS = 14;
15
+ /**
16
+ * When looking up a single event by ID, expand the read window aggressively
17
+ * so events scheduled years away (e.g. recurring annual reservations) can
18
+ * still be located without requiring the caller to know the date in advance.
19
+ * EventKit only supports a maximum 4-year predicate window — bound at
20
+ * roughly that to stay within Apple's limits.
21
+ */
22
+ const FIND_BY_ID_WINDOW_DAYS = 365 * 4;
23
+ const formatDateOnly = (date) => {
24
+ const year = date.getFullYear();
25
+ const month = String(date.getMonth() + 1).padStart(2, '0');
26
+ const day = String(date.getDate()).padStart(2, '0');
27
+ return `${year}-${month}-${day}`;
28
+ };
29
+ const shiftDays = (date, days) => {
30
+ const shifted = new Date(date);
31
+ shifted.setDate(shifted.getDate() + days);
32
+ return shifted;
33
+ };
34
+ // `event calendar list --start/--end` expects bare `yyyy-MM-dd`; trim any
35
+ // time component from caller-supplied dates so the predicate succeeds.
36
+ const toDateOnly = (value) => {
37
+ const match = value.match(/^(\d{4}-\d{2}-\d{2})/);
38
+ return match?.[1] ?? value;
39
+ };
40
+ const resolveReadDateRange = (filters) => {
41
+ const today = new Date();
42
+ if (filters.startDate && filters.endDate) {
43
+ return {
44
+ startDate: toDateOnly(filters.startDate),
45
+ endDate: toDateOnly(filters.endDate),
46
+ };
47
+ }
48
+ if (!filters.startDate && !filters.endDate) {
49
+ return {
50
+ startDate: formatDateOnly(today),
51
+ endDate: formatDateOnly(shiftDays(today, DEFAULT_READ_WINDOW_DAYS)),
52
+ };
53
+ }
54
+ if (filters.startDate && !filters.endDate) {
55
+ // `parseReminderDueDate` is the strict parser shared with the reminder
56
+ // pipeline; it rejects auto-corrected dates like `2025-02-30` that the
57
+ // native `Date` constructor silently coerces to March 2.
58
+ const start = parseReminderDueDate(filters.startDate);
59
+ return {
60
+ startDate: toDateOnly(filters.startDate),
61
+ endDate: formatDateOnly(shiftDays(start ?? today, DEFAULT_READ_WINDOW_DAYS)),
62
+ };
63
+ }
64
+ // !filters.startDate && filters.endDate
65
+ const endStr = filters.endDate;
66
+ const end = parseReminderDueDate(endStr);
67
+ return {
68
+ startDate: formatDateOnly(shiftDays(end ?? today, -DEFAULT_READ_WINDOW_DAYS)),
69
+ endDate: toDateOnly(endStr),
70
+ };
71
+ };
72
+ const EVENT_NULLABLE_FIELDS = [
73
+ 'notes',
74
+ 'location',
75
+ 'structuredLocation',
76
+ 'url',
77
+ 'availability',
78
+ 'alarms',
79
+ 'recurrenceRules',
80
+ 'organizer',
81
+ 'attendees',
82
+ 'status',
83
+ 'isDetached',
84
+ 'occurrenceDate',
85
+ 'creationDate',
86
+ 'lastModifiedDate',
87
+ 'externalId',
88
+ ];
89
+ const mapEvent = (event) => nullToUndefined(event, EVENT_NULLABLE_FIELDS);
90
+ /**
91
+ * Maps our schema span values to `event calendar delete --span` strings.
92
+ * `event` understands "this" (default → `.thisEvent`) and "all"
93
+ * (→ `.futureEvents`).
94
+ */
95
+ const mapSpanForEvent = (span) => span === 'this-event' ? 'this' : span === 'future-events' ? 'all' : undefined;
96
+ class CalendarRepository {
97
+ async listEvents(startDate, endDate, calendarName) {
98
+ const args = ['calendar', 'list', '--start', startDate, '--end', endDate];
99
+ addOptionalArg(args, '--calendar', calendarName);
100
+ args.push('--json');
101
+ return executeEventCliJson(args);
102
+ }
103
+ // `findEventById` and `findAllCalendars` both need a wide read window
104
+ // because EventKit can't be queried for a single event by id directly via
105
+ // `event`, and empty calendars don't appear in narrow windows. Centralize
106
+ // the bounds here so both paths stay in sync.
107
+ listEventsWideWindow() {
108
+ const today = new Date();
109
+ return this.listEvents(formatDateOnly(shiftDays(today, -FIND_BY_ID_WINDOW_DAYS)), formatDateOnly(shiftDays(today, FIND_BY_ID_WINDOW_DAYS)));
110
+ }
111
+ async findEventById(id) {
112
+ const events = await this.listEventsWideWindow();
113
+ const event = events.find((e) => e.id === id);
114
+ if (!event) {
115
+ throw new CliUserError(`Event with ID '${id}' not found.`);
116
+ }
117
+ return mapEvent(event);
118
+ }
119
+ async findEvents(filters = {}) {
120
+ const dateRange = resolveReadDateRange({
121
+ startDate: filters.startDate,
122
+ endDate: filters.endDate,
123
+ });
124
+ const events = await this.listEvents(dateRange.startDate, dateRange.endDate, filters.calendarName);
125
+ let normalized = events.map(mapEvent);
126
+ // `event` does not surface `--search`; apply the substring match in TS
127
+ // against title / notes / location.
128
+ if (filters.search) {
129
+ const needle = filters.search.toLowerCase();
130
+ normalized = normalized.filter((event) => {
131
+ const haystack = [event.title, event.notes, event.location]
132
+ .filter((value) => Boolean(value))
133
+ .map((value) => value.toLowerCase());
134
+ return haystack.some((value) => value.includes(needle));
135
+ });
136
+ }
137
+ if (filters.availability) {
138
+ normalized = normalized.filter((event) => event.availability === filters.availability);
139
+ }
140
+ return normalized;
141
+ }
142
+ /**
143
+ * `event` has no first-class "list calendars" command — calendar names are
144
+ * surfaced only as the `calendar` field on each event in `calendar list`.
145
+ * Derive a unique-by-name listing from a wide read window so callers of
146
+ * `calendar_calendars` see every calendar that contains an event. Calendars
147
+ * with zero events in the window won't appear; see
148
+ * `docs/migration-to-event-cli.md` for the workaround.
149
+ */
150
+ async findAllCalendars() {
151
+ const events = await this.listEventsWideWindow();
152
+ const distinct = new Set();
153
+ for (const event of events) {
154
+ if (event.calendar)
155
+ distinct.add(event.calendar);
156
+ }
157
+ return Array.from(distinct)
158
+ .sort((a, b) => a.localeCompare(b))
159
+ .map((name) => ({ id: name, title: name }));
160
+ }
161
+ /**
162
+ * When a date range is supplied, scope the listing to that window instead
163
+ * of the default wide window and annotate each calendar with how many
164
+ * events it contributed — this is the only per-calendar signal `event`
165
+ * exposes (it has no EventKit account/identifier info to filter or key
166
+ * on), so counts are grouped by calendar title rather than a stable id.
167
+ */
168
+ async findCalendars(filters = {}) {
169
+ if (!filters.startDate && !filters.endDate) {
170
+ return this.findAllCalendars();
171
+ }
172
+ const dateRange = resolveReadDateRange({
173
+ startDate: filters.startDate,
174
+ endDate: filters.endDate,
175
+ });
176
+ const events = await this.listEvents(dateRange.startDate, dateRange.endDate);
177
+ const eventCountByTitle = new Map();
178
+ for (const event of events) {
179
+ if (!event.calendar)
180
+ continue;
181
+ eventCountByTitle.set(event.calendar, (eventCountByTitle.get(event.calendar) ?? 0) + 1);
182
+ }
183
+ return Array.from(eventCountByTitle.keys())
184
+ .sort((a, b) => a.localeCompare(b))
185
+ .map((title) => ({
186
+ id: title,
187
+ title,
188
+ eventCount: eventCountByTitle.get(title) ?? 0,
189
+ }));
190
+ }
191
+ async createEvent(data) {
192
+ const args = [
193
+ 'calendar',
194
+ 'create',
195
+ '--title',
196
+ data.title,
197
+ '--start',
198
+ data.startDate,
199
+ '--end',
200
+ data.endDate,
201
+ ];
202
+ addOptionalArg(args, '--calendar', data.calendar);
203
+ addOptionalArg(args, '--notes', data.notes);
204
+ addOptionalArg(args, '--location', data.location);
205
+ args.push('--json');
206
+ return executeEventCliJson(args);
207
+ }
208
+ async updateEvent(data) {
209
+ const args = ['calendar', 'update', '--id', data.id];
210
+ addOptionalArg(args, '--title', data.title);
211
+ addOptionalArg(args, '--start', data.startDate);
212
+ addOptionalArg(args, '--end', data.endDate);
213
+ addOptionalArg(args, '--location', data.location);
214
+ addOptionalArg(args, '--notes', data.notes);
215
+ args.push('--json');
216
+ return executeEventCliJson(args);
217
+ }
218
+ async deleteEvent(id, span) {
219
+ const args = ['calendar', 'delete', '--id', id];
220
+ addOptionalArg(args, '--span', mapSpanForEvent(span));
221
+ await executeEventCliPlain(args);
222
+ }
223
+ }
224
+ export const calendarRepository = new CalendarRepository();
225
+ export { CalendarRepository };
226
+ //# sourceMappingURL=calendarRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendarRepository.js","sourceRoot":"","sources":["../../src/utils/calendarRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * constants.ts
3
+ * Centralized constants and configuration values to eliminate magic numbers
4
+ */
5
+ /**
6
+ * File system and path constants
7
+ */
8
+ export declare const FILE_SYSTEM: {
9
+ /** Maximum directory traversal depth when searching for project root */
10
+ readonly MAX_DIRECTORY_SEARCH_DEPTH: 10;
11
+ /** Package.json filename for project root detection */
12
+ readonly PACKAGE_JSON_FILENAME: "package.json";
13
+ /** Swift binary filename — points at the vendored `event` CLI (FradSer/event). */
14
+ readonly SWIFT_BINARY_NAME: "event";
15
+ /**
16
+ * TCC disclaim shim filename — spawns `event` as its own TCC-responsible
17
+ * process so EventKit permission prompts work from desktop MCP clients
18
+ * that lack usage-description strings (issue #93).
19
+ */
20
+ readonly DISCLAIM_BINARY_NAME: "event-disclaim";
21
+ };
22
+ /**
23
+ * Validation and security constants
24
+ */
25
+ export declare const VALIDATION: {
26
+ /** Maximum lengths for different text fields */
27
+ readonly MAX_TITLE_LENGTH: 200;
28
+ readonly MAX_NOTE_LENGTH: 20000;
29
+ readonly MAX_LIST_NAME_LENGTH: 100;
30
+ readonly MAX_SEARCH_LENGTH: 100;
31
+ readonly MAX_URL_LENGTH: 500;
32
+ readonly MAX_LOCATION_LENGTH: 200;
33
+ };
34
+ /**
35
+ * Tool names for MCP server operations
36
+ */
37
+ export declare const TOOLS: {
38
+ /** Reminder tasks management tool */
39
+ readonly REMINDERS_TASKS: "reminders_tasks";
40
+ /** Reminder lists management tool */
41
+ readonly REMINDERS_LISTS: "reminders_lists";
42
+ /** Reminder subtasks management tool */
43
+ readonly REMINDERS_SUBTASKS: "reminders_subtasks";
44
+ /** Calendar events management tool */
45
+ readonly CALENDAR_EVENTS: "calendar_events";
46
+ /** Calendar collections management tool */
47
+ readonly CALENDAR_CALENDARS: "calendar_calendars";
48
+ };
49
+ /**
50
+ * Time and date constants for consistent time-based logic
51
+ */
52
+ export declare const TIME: {
53
+ /** Working hours boundaries */
54
+ readonly WORKING_HOURS_START: 9;
55
+ readonly WORKING_HOURS_END: 18;
56
+ /** Time of day boundaries for categorization */
57
+ readonly MORNING_START: 5;
58
+ readonly NOON: 12;
59
+ readonly AFTERNOON_END: 17;
60
+ readonly EVENING_START: 17;
61
+ readonly NIGHT_START: 21;
62
+ /** Default time suggestions */
63
+ readonly LATER_TODAY_HOURS: 4;
64
+ readonly END_OF_WEEK_HOUR: 17;
65
+ readonly DEFAULT_MORNING_HOUR: 9;
66
+ /** Day of week constants (0 = Sunday, 6 = Saturday) */
67
+ readonly SUNDAY: 0;
68
+ readonly FRIDAY: 5;
69
+ readonly SATURDAY: 6;
70
+ };
71
+ /**
72
+ * Error message templates
73
+ */
74
+ export declare const MESSAGES: {
75
+ readonly ERROR: {
76
+ readonly UNKNOWN_TOOL: (name: string) => string;
77
+ readonly UNKNOWN_ACTION: (tool: string, action: string) => string;
78
+ };
79
+ };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * constants.ts
3
+ * Centralized constants and configuration values to eliminate magic numbers
4
+ */
5
+ /**
6
+ * File system and path constants
7
+ */
8
+ export const FILE_SYSTEM = {
9
+ /** Maximum directory traversal depth when searching for project root */
10
+ MAX_DIRECTORY_SEARCH_DEPTH: 10,
11
+ /** Package.json filename for project root detection */
12
+ PACKAGE_JSON_FILENAME: 'package.json',
13
+ /** Swift binary filename — points at the vendored `event` CLI (FradSer/event). */
14
+ SWIFT_BINARY_NAME: 'event',
15
+ /**
16
+ * TCC disclaim shim filename — spawns `event` as its own TCC-responsible
17
+ * process so EventKit permission prompts work from desktop MCP clients
18
+ * that lack usage-description strings (issue #93).
19
+ */
20
+ DISCLAIM_BINARY_NAME: 'event-disclaim',
21
+ };
22
+ /**
23
+ * Validation and security constants
24
+ */
25
+ export const VALIDATION = {
26
+ /** Maximum lengths for different text fields */
27
+ MAX_TITLE_LENGTH: 200,
28
+ MAX_NOTE_LENGTH: 20000,
29
+ MAX_LIST_NAME_LENGTH: 100,
30
+ MAX_SEARCH_LENGTH: 100,
31
+ MAX_URL_LENGTH: 500,
32
+ MAX_LOCATION_LENGTH: 200,
33
+ };
34
+ /**
35
+ * Tool names for MCP server operations
36
+ */
37
+ export const TOOLS = {
38
+ /** Reminder tasks management tool */
39
+ REMINDERS_TASKS: 'reminders_tasks',
40
+ /** Reminder lists management tool */
41
+ REMINDERS_LISTS: 'reminders_lists',
42
+ /** Reminder subtasks management tool */
43
+ REMINDERS_SUBTASKS: 'reminders_subtasks',
44
+ /** Calendar events management tool */
45
+ CALENDAR_EVENTS: 'calendar_events',
46
+ /** Calendar collections management tool */
47
+ CALENDAR_CALENDARS: 'calendar_calendars',
48
+ };
49
+ /**
50
+ * Time and date constants for consistent time-based logic
51
+ */
52
+ export const TIME = {
53
+ /** Working hours boundaries */
54
+ WORKING_HOURS_START: 9,
55
+ WORKING_HOURS_END: 18,
56
+ /** Time of day boundaries for categorization */
57
+ MORNING_START: 5,
58
+ NOON: 12,
59
+ AFTERNOON_END: 17,
60
+ EVENING_START: 17,
61
+ NIGHT_START: 21,
62
+ /** Default time suggestions */
63
+ LATER_TODAY_HOURS: 4,
64
+ END_OF_WEEK_HOUR: 17,
65
+ DEFAULT_MORNING_HOUR: 9,
66
+ /** Day of week constants (0 = Sunday, 6 = Saturday) */
67
+ SUNDAY: 0,
68
+ FRIDAY: 5,
69
+ SATURDAY: 6,
70
+ };
71
+ /**
72
+ * Error message templates
73
+ */
74
+ export const MESSAGES = {
75
+ ERROR: {
76
+ UNKNOWN_TOOL: (name) => `Unknown tool: ${name}`,
77
+ UNKNOWN_ACTION: (tool, action) => `Unknown ${tool} action: ${action}`,
78
+ },
79
+ };
80
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,wEAAwE;IACxE,0BAA0B,EAAE,EAAE;IAE9B,uDAAuD;IACvD,qBAAqB,EAAE,cAAc;IAErC,kFAAkF;IAClF,iBAAiB,EAAE,OAAO;IAE1B;;;;OAIG;IACH,oBAAoB,EAAE,gBAAgB;CAC9B,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,gDAAgD;IAChD,gBAAgB,EAAE,GAAG;IACrB,eAAe,EAAE,KAAK;IACtB,oBAAoB,EAAE,GAAG;IACzB,iBAAiB,EAAE,GAAG;IACtB,cAAc,EAAE,GAAG;IACnB,mBAAmB,EAAE,GAAG;CAChB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,qCAAqC;IACrC,eAAe,EAAE,iBAAiB;IAClC,qCAAqC;IACrC,eAAe,EAAE,iBAAiB;IAClC,wCAAwC;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,sCAAsC;IACtC,eAAe,EAAE,iBAAiB;IAClC,2CAA2C;IAC3C,kBAAkB,EAAE,oBAAoB;CAChC,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,+BAA+B;IAC/B,mBAAmB,EAAE,CAAC;IACtB,iBAAiB,EAAE,EAAE;IAErB,gDAAgD;IAChD,aAAa,EAAE,CAAC;IAChB,IAAI,EAAE,EAAE;IACR,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE;IAEf,+BAA+B;IAC/B,iBAAiB,EAAE,CAAC;IACpB,gBAAgB,EAAE,EAAE;IACpB,oBAAoB,EAAE,CAAC;IAEvB,uDAAuD;IACvD,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,CAAC;IACT,QAAQ,EAAE,CAAC;CACH,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,KAAK,EAAE;QACL,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,iBAAiB,IAAI,EAAE;QACvD,cAAc,EAAE,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,CAC/C,WAAW,IAAI,YAAY,MAAM,EAAE;KACtC;CACO,CAAC"}