mcp-macos 2.0.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 (149) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +360 -0
  3. package/bin/dev.cjs +10 -0
  4. package/bin/run.cjs +15 -0
  5. package/dist/config/index.d.ts +36 -0
  6. package/dist/config/index.js +127 -0
  7. package/dist/config/index.js.map +1 -0
  8. package/dist/config/schema.d.ts +161 -0
  9. package/dist/config/schema.js +45 -0
  10. package/dist/config/schema.js.map +1 -0
  11. package/dist/index.d.ts +11 -0
  12. package/dist/index.js +75 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/server/handlers.d.ts +10 -0
  15. package/dist/server/handlers.js +43 -0
  16. package/dist/server/handlers.js.map +1 -0
  17. package/dist/server/promptAbstractions.d.ts +74 -0
  18. package/dist/server/promptAbstractions.js +150 -0
  19. package/dist/server/promptAbstractions.js.map +1 -0
  20. package/dist/server/prompts.d.ts +8 -0
  21. package/dist/server/prompts.js +480 -0
  22. package/dist/server/prompts.js.map +1 -0
  23. package/dist/server/server.d.ts +29 -0
  24. package/dist/server/server.js +52 -0
  25. package/dist/server/server.js.map +1 -0
  26. package/dist/server/transports/http/auth.d.ts +34 -0
  27. package/dist/server/transports/http/auth.js +148 -0
  28. package/dist/server/transports/http/auth.js.map +1 -0
  29. package/dist/server/transports/http/health.d.ts +35 -0
  30. package/dist/server/transports/http/health.js +93 -0
  31. package/dist/server/transports/http/health.js.map +1 -0
  32. package/dist/server/transports/http/index.d.ts +43 -0
  33. package/dist/server/transports/http/index.js +141 -0
  34. package/dist/server/transports/http/index.js.map +1 -0
  35. package/dist/server/transports/http/middleware.d.ts +53 -0
  36. package/dist/server/transports/http/middleware.js +133 -0
  37. package/dist/server/transports/http/middleware.js.map +1 -0
  38. package/dist/tools/definitions.d.ts +10 -0
  39. package/dist/tools/definitions.js +633 -0
  40. package/dist/tools/definitions.js.map +1 -0
  41. package/dist/tools/handlers/calendarHandlers.d.ts +11 -0
  42. package/dist/tools/handlers/calendarHandlers.js +123 -0
  43. package/dist/tools/handlers/calendarHandlers.js.map +1 -0
  44. package/dist/tools/handlers/contactsHandlers.d.ts +17 -0
  45. package/dist/tools/handlers/contactsHandlers.js +397 -0
  46. package/dist/tools/handlers/contactsHandlers.js.map +1 -0
  47. package/dist/tools/handlers/index.d.ts +11 -0
  48. package/dist/tools/handlers/index.js +12 -0
  49. package/dist/tools/handlers/index.js.map +1 -0
  50. package/dist/tools/handlers/listHandlers.d.ts +10 -0
  51. package/dist/tools/handlers/listHandlers.js +40 -0
  52. package/dist/tools/handlers/listHandlers.js.map +1 -0
  53. package/dist/tools/handlers/mailHandlers.d.ts +11 -0
  54. package/dist/tools/handlers/mailHandlers.js +301 -0
  55. package/dist/tools/handlers/mailHandlers.js.map +1 -0
  56. package/dist/tools/handlers/messagesHandlers.d.ts +17 -0
  57. package/dist/tools/handlers/messagesHandlers.js +350 -0
  58. package/dist/tools/handlers/messagesHandlers.js.map +1 -0
  59. package/dist/tools/handlers/notesHandlers.d.ts +12 -0
  60. package/dist/tools/handlers/notesHandlers.js +305 -0
  61. package/dist/tools/handlers/notesHandlers.js.map +1 -0
  62. package/dist/tools/handlers/reminderHandlers.d.ts +10 -0
  63. package/dist/tools/handlers/reminderHandlers.js +96 -0
  64. package/dist/tools/handlers/reminderHandlers.js.map +1 -0
  65. package/dist/tools/handlers/shared.d.ts +51 -0
  66. package/dist/tools/handlers/shared.js +107 -0
  67. package/dist/tools/handlers/shared.js.map +1 -0
  68. package/dist/tools/index.d.ts +10 -0
  69. package/dist/tools/index.js +125 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/types/index.d.ts +265 -0
  72. package/dist/types/index.js +67 -0
  73. package/dist/types/index.js.map +1 -0
  74. package/dist/types/prompts.d.ts +84 -0
  75. package/dist/types/prompts.js +6 -0
  76. package/dist/types/prompts.js.map +1 -0
  77. package/dist/types/repository.d.ts +102 -0
  78. package/dist/types/repository.js +6 -0
  79. package/dist/types/repository.js.map +1 -0
  80. package/dist/utils/binaryValidator.d.ts +52 -0
  81. package/dist/utils/binaryValidator.js +152 -0
  82. package/dist/utils/binaryValidator.js.map +1 -0
  83. package/dist/utils/calendarRepository.d.ts +25 -0
  84. package/dist/utils/calendarRepository.js +100 -0
  85. package/dist/utils/calendarRepository.js.map +1 -0
  86. package/dist/utils/cliExecutor.d.ts +28 -0
  87. package/dist/utils/cliExecutor.js +196 -0
  88. package/dist/utils/cliExecutor.js.map +1 -0
  89. package/dist/utils/constants.d.ts +96 -0
  90. package/dist/utils/constants.js +97 -0
  91. package/dist/utils/constants.js.map +1 -0
  92. package/dist/utils/contactResolver.d.ts +142 -0
  93. package/dist/utils/contactResolver.js +386 -0
  94. package/dist/utils/contactResolver.js.map +1 -0
  95. package/dist/utils/dateFiltering.d.ts +22 -0
  96. package/dist/utils/dateFiltering.js +72 -0
  97. package/dist/utils/dateFiltering.js.map +1 -0
  98. package/dist/utils/dateUtils.d.ts +20 -0
  99. package/dist/utils/dateUtils.js +36 -0
  100. package/dist/utils/dateUtils.js.map +1 -0
  101. package/dist/utils/errorHandling.d.ts +30 -0
  102. package/dist/utils/errorHandling.js +101 -0
  103. package/dist/utils/errorHandling.js.map +1 -0
  104. package/dist/utils/helpers.d.ts +35 -0
  105. package/dist/utils/helpers.js +59 -0
  106. package/dist/utils/helpers.js.map +1 -0
  107. package/dist/utils/jxaExecutor.d.ts +47 -0
  108. package/dist/utils/jxaExecutor.js +194 -0
  109. package/dist/utils/jxaExecutor.js.map +1 -0
  110. package/dist/utils/logging.d.ts +31 -0
  111. package/dist/utils/logging.js +98 -0
  112. package/dist/utils/logging.js.map +1 -0
  113. package/dist/utils/permissionPrompt.d.ts +16 -0
  114. package/dist/utils/permissionPrompt.js +42 -0
  115. package/dist/utils/permissionPrompt.js.map +1 -0
  116. package/dist/utils/preflight.d.ts +30 -0
  117. package/dist/utils/preflight.js +196 -0
  118. package/dist/utils/preflight.js.map +1 -0
  119. package/dist/utils/projectUtils.d.ts +11 -0
  120. package/dist/utils/projectUtils.js +76 -0
  121. package/dist/utils/projectUtils.js.map +1 -0
  122. package/dist/utils/reminderDateParser.d.ts +8 -0
  123. package/dist/utils/reminderDateParser.js +77 -0
  124. package/dist/utils/reminderDateParser.js.map +1 -0
  125. package/dist/utils/reminderRepository.d.ts +23 -0
  126. package/dist/utils/reminderRepository.js +91 -0
  127. package/dist/utils/reminderRepository.js.map +1 -0
  128. package/dist/utils/sqliteContactReader.d.ts +51 -0
  129. package/dist/utils/sqliteContactReader.js +216 -0
  130. package/dist/utils/sqliteContactReader.js.map +1 -0
  131. package/dist/utils/sqliteMailReader.d.ts +97 -0
  132. package/dist/utils/sqliteMailReader.js +310 -0
  133. package/dist/utils/sqliteMailReader.js.map +1 -0
  134. package/dist/utils/sqliteMessageReader.d.ts +71 -0
  135. package/dist/utils/sqliteMessageReader.js +400 -0
  136. package/dist/utils/sqliteMessageReader.js.map +1 -0
  137. package/dist/utils/timeHelpers.d.ts +40 -0
  138. package/dist/utils/timeHelpers.js +136 -0
  139. package/dist/utils/timeHelpers.js.map +1 -0
  140. package/dist/utils/timezone.d.ts +24 -0
  141. package/dist/utils/timezone.js +39 -0
  142. package/dist/utils/timezone.js.map +1 -0
  143. package/dist/validation/schemas.d.ts +610 -0
  144. package/dist/validation/schemas.js +354 -0
  145. package/dist/validation/schemas.js.map +1 -0
  146. package/package.json +97 -0
  147. package/scripts/build-swift.mjs +86 -0
  148. package/src/swift/EventKitCLI.swift +778 -0
  149. package/src/swift/Info.plist +38 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * utils/binaryValidator.ts
3
+ * Secure binary path validation and integrity checking
4
+ */
5
+ /**
6
+ * Security configuration for binary validation
7
+ */
8
+ interface BinarySecurityConfig {
9
+ expectedHash?: string;
10
+ maxFileSize: number;
11
+ allowedPaths: string[];
12
+ requireAbsolutePath: boolean;
13
+ }
14
+ /**
15
+ * Binary validation error
16
+ */
17
+ export declare class BinaryValidationError extends Error {
18
+ code: string;
19
+ constructor(message: string, code: string);
20
+ }
21
+ /**
22
+ * Validates binary path for security
23
+ */
24
+ export declare function validateBinaryPath(binaryPath: string, config?: Partial<BinarySecurityConfig>): void;
25
+ /**
26
+ * Calculates SHA256 hash of binary file
27
+ */
28
+ export declare function calculateBinaryHash(binaryPath: string): string;
29
+ /**
30
+ * Validates binary integrity using hash
31
+ */
32
+ export declare function validateBinaryIntegrity(binaryPath: string, expectedHash: string): boolean;
33
+ /**
34
+ * Comprehensive binary security validation
35
+ */
36
+ export declare function validateBinarySecurity(binaryPath: string, config?: Partial<BinarySecurityConfig>): {
37
+ isValid: boolean;
38
+ hash?: string;
39
+ errors: string[];
40
+ };
41
+ /**
42
+ * Secure binary path finder with validation
43
+ */
44
+ export declare function findSecureBinaryPath(possiblePaths: string[], config?: Partial<BinarySecurityConfig>): {
45
+ path: string | null;
46
+ validationResult?: ReturnType<typeof validateBinarySecurity>;
47
+ };
48
+ /**
49
+ * Environment-specific binary validation
50
+ */
51
+ export declare function getEnvironmentBinaryConfig(): Partial<BinarySecurityConfig>;
52
+ export {};
@@ -0,0 +1,152 @@
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
+ const DEFAULT_CONFIG = {
12
+ maxFileSize: 50 * 1024 * 1024, // 50MB max
13
+ allowedPaths: ['/dist/swift/bin/', '/src/swift/bin/', '/swift/bin/'],
14
+ requireAbsolutePath: true,
15
+ };
16
+ /**
17
+ * Binary validation error
18
+ */
19
+ export class BinaryValidationError extends Error {
20
+ constructor(message, code) {
21
+ super(message);
22
+ this.code = code;
23
+ this.name = 'BinaryValidationError';
24
+ }
25
+ }
26
+ /**
27
+ * Validates binary path for security
28
+ */
29
+ export function validateBinaryPath(binaryPath, config = {}) {
30
+ const fullConfig = { ...DEFAULT_CONFIG, ...config };
31
+ if (fullConfig.requireAbsolutePath && !path.isAbsolute(binaryPath)) {
32
+ throw new BinaryValidationError('Binary path must be absolute', 'INVALID_PATH');
33
+ }
34
+ const normalizedPath = path.normalize(binaryPath);
35
+ if (normalizedPath.includes('..')) {
36
+ throw new BinaryValidationError('Path traversal detected in binary path', 'PATH_TRAVERSAL');
37
+ }
38
+ if (!fullConfig.allowedPaths.some((p) => normalizedPath.includes(p))) {
39
+ throw new BinaryValidationError('Binary path not in allowed directories', 'FORBIDDEN_PATH');
40
+ }
41
+ if (!fs.existsSync(normalizedPath)) {
42
+ throw new BinaryValidationError(`Binary file not found: ${normalizedPath}`, 'FILE_NOT_FOUND');
43
+ }
44
+ const stats = fs.statSync(normalizedPath);
45
+ if (!stats.isFile()) {
46
+ throw new BinaryValidationError('Binary path does not point to a file', 'NOT_A_FILE');
47
+ }
48
+ if (stats.size > fullConfig.maxFileSize) {
49
+ throw new BinaryValidationError(`Binary file too large: ${stats.size} bytes`, 'FILE_TOO_LARGE');
50
+ }
51
+ try {
52
+ fs.accessSync(normalizedPath, fs.constants.X_OK);
53
+ }
54
+ catch (_error) {
55
+ throw new BinaryValidationError('Binary file is not executable', 'NOT_EXECUTABLE');
56
+ }
57
+ }
58
+ /**
59
+ * Calculates SHA256 hash of binary file
60
+ */
61
+ export function calculateBinaryHash(binaryPath) {
62
+ try {
63
+ const fileBuffer = fs.readFileSync(binaryPath);
64
+ return crypto.createHash('sha256').update(fileBuffer).digest('hex');
65
+ }
66
+ catch (error) {
67
+ throw new BinaryValidationError(`Failed to calculate binary hash: ${error.message}`, 'HASH_CALCULATION_FAILED');
68
+ }
69
+ }
70
+ /**
71
+ * Validates binary integrity using hash
72
+ */
73
+ export function validateBinaryIntegrity(binaryPath, expectedHash) {
74
+ try {
75
+ const actualHash = calculateBinaryHash(binaryPath);
76
+ const isValid = actualHash === expectedHash;
77
+ return isValid;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ /**
84
+ * Comprehensive binary security validation
85
+ */
86
+ export function validateBinarySecurity(binaryPath, config = {}) {
87
+ const errors = [];
88
+ let hash;
89
+ try {
90
+ // Path validation
91
+ validateBinaryPath(binaryPath, config);
92
+ // Calculate hash
93
+ hash = calculateBinaryHash(binaryPath);
94
+ // Integrity check if expected hash provided
95
+ if (config.expectedHash) {
96
+ const integrityValid = validateBinaryIntegrity(binaryPath, config.expectedHash);
97
+ if (!integrityValid) {
98
+ errors.push('Binary integrity check failed - hash mismatch');
99
+ }
100
+ }
101
+ }
102
+ catch (error) {
103
+ if (error instanceof BinaryValidationError) {
104
+ errors.push(`${error.code}: ${error.message}`);
105
+ }
106
+ else {
107
+ errors.push(`Unexpected validation error: ${error.message}`);
108
+ }
109
+ }
110
+ return {
111
+ isValid: errors.length === 0,
112
+ hash,
113
+ errors,
114
+ };
115
+ }
116
+ /**
117
+ * Secure binary path finder with validation
118
+ */
119
+ export function findSecureBinaryPath(possiblePaths, config = {}) {
120
+ for (const binaryPath of possiblePaths) {
121
+ const validationResult = validateBinarySecurity(binaryPath, config);
122
+ if (validationResult.isValid) {
123
+ return { path: binaryPath, validationResult };
124
+ }
125
+ }
126
+ return { path: null };
127
+ }
128
+ /**
129
+ * Environment-specific binary validation
130
+ */
131
+ export function getEnvironmentBinaryConfig() {
132
+ if (process.env.NODE_ENV === 'test') {
133
+ // Relaxed validation for testing
134
+ return {
135
+ requireAbsolutePath: false,
136
+ maxFileSize: 100 * 1024 * 1024, // 100MB for test
137
+ };
138
+ }
139
+ if (process.env.NODE_ENV === 'development') {
140
+ // Development mode - log more details
141
+ return {
142
+ maxFileSize: 100 * 1024 * 1024, // 100MB for dev
143
+ };
144
+ }
145
+ // Production mode - strict validation
146
+ return {
147
+ expectedHash: process.env.SWIFT_BINARY_HASH,
148
+ maxFileSize: 50 * 1024 * 1024, // 50MB
149
+ requireAbsolutePath: true,
150
+ };
151
+ }
152
+ //# 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,25 @@
1
+ /**
2
+ * calendarRepository.ts
3
+ * Repository pattern implementation for calendar event data access operations using EventKitCLI.
4
+ */
5
+ import type { Calendar, CalendarEvent } from '../types/index.js';
6
+ import type { CreateEventData, EventJSON, UpdateEventData } from '../types/repository.js';
7
+ declare class CalendarRepository {
8
+ private readEvents;
9
+ private formatDate;
10
+ private defaultStartDate;
11
+ private defaultEndDate;
12
+ findEventById(id: string): Promise<CalendarEvent>;
13
+ findEvents(filters?: {
14
+ startDate?: string;
15
+ endDate?: string;
16
+ calendarName?: string;
17
+ search?: string;
18
+ }): Promise<CalendarEvent[]>;
19
+ findAllCalendars(): Promise<Calendar[]>;
20
+ createEvent(data: CreateEventData): Promise<EventJSON>;
21
+ updateEvent(data: UpdateEventData): Promise<EventJSON>;
22
+ deleteEvent(id: string): Promise<void>;
23
+ }
24
+ export declare const calendarRepository: CalendarRepository;
25
+ export {};
@@ -0,0 +1,100 @@
1
+ /**
2
+ * calendarRepository.ts
3
+ * Repository pattern implementation for calendar event data access operations using EventKitCLI.
4
+ */
5
+ import { executeCli } from './cliExecutor.js';
6
+ import { addOptionalArg, addOptionalBooleanArg, addOptionalNumberArg, nullToUndefined, } from './helpers.js';
7
+ class CalendarRepository {
8
+ async readEvents(startDate, endDate, calendarName, search) {
9
+ const args = ['--action', 'read-events'];
10
+ addOptionalArg(args, '--startDate', startDate);
11
+ addOptionalArg(args, '--endDate', endDate);
12
+ addOptionalArg(args, '--filterCalendar', calendarName);
13
+ addOptionalArg(args, '--search', search);
14
+ return executeCli(args);
15
+ }
16
+ formatDate(d) {
17
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} 00:00:00`;
18
+ }
19
+ defaultStartDate() {
20
+ const now = new Date();
21
+ return this.formatDate(new Date(now.getFullYear() - 2, now.getMonth(), now.getDate()));
22
+ }
23
+ defaultEndDate() {
24
+ const now = new Date();
25
+ return this.formatDate(new Date(now.getFullYear() + 2, now.getMonth(), now.getDate()));
26
+ }
27
+ async findEventById(id) {
28
+ // EventKit requires bounded date range — distantPast/distantFuture returns 0 events
29
+ const { events } = await this.readEvents(this.defaultStartDate(), this.defaultEndDate());
30
+ const event = events.find((e) => e.id === id);
31
+ if (!event) {
32
+ throw new Error(`Event with ID '${id}' not found.`);
33
+ }
34
+ return nullToUndefined(event, [
35
+ 'notes',
36
+ 'location',
37
+ 'url',
38
+ 'attendees',
39
+ ]);
40
+ }
41
+ async findEvents(filters = {}) {
42
+ // EventKit requires bounded date range — distantPast/distantFuture returns 0 events
43
+ const startDate = filters.startDate ?? this.defaultStartDate();
44
+ const endDate = filters.endDate ?? this.defaultEndDate();
45
+ const { events } = await this.readEvents(startDate, endDate, filters.calendarName, filters.search);
46
+ return events.map((e) => nullToUndefined(e, ['notes', 'location', 'url', 'attendees']));
47
+ }
48
+ async findAllCalendars() {
49
+ return executeCli(['--action', 'read-calendars']);
50
+ }
51
+ async createEvent(data) {
52
+ const args = [
53
+ '--action',
54
+ 'create-event',
55
+ '--title',
56
+ data.title,
57
+ '--startDate',
58
+ data.startDate,
59
+ '--endDate',
60
+ data.endDate,
61
+ ];
62
+ addOptionalArg(args, '--targetCalendar', data.calendar);
63
+ addOptionalArg(args, '--note', data.notes);
64
+ addOptionalArg(args, '--location', data.location);
65
+ addOptionalArg(args, '--url', data.url);
66
+ addOptionalBooleanArg(args, '--isAllDay', data.isAllDay);
67
+ // Recurrence parameters
68
+ if (data.recurrence) {
69
+ addOptionalArg(args, '--recurrence', data.recurrence.frequency);
70
+ addOptionalNumberArg(args, '--recurrenceInterval', data.recurrence.interval);
71
+ addOptionalArg(args, '--recurrenceEnd', data.recurrence.endDate);
72
+ addOptionalNumberArg(args, '--recurrenceCount', data.recurrence.occurrenceCount);
73
+ }
74
+ return executeCli(args);
75
+ }
76
+ async updateEvent(data) {
77
+ const args = ['--action', 'update-event', '--id', data.id];
78
+ addOptionalArg(args, '--title', data.title);
79
+ addOptionalArg(args, '--targetCalendar', data.calendar);
80
+ addOptionalArg(args, '--startDate', data.startDate);
81
+ addOptionalArg(args, '--endDate', data.endDate);
82
+ addOptionalArg(args, '--note', data.notes);
83
+ addOptionalArg(args, '--location', data.location);
84
+ addOptionalArg(args, '--url', data.url);
85
+ addOptionalBooleanArg(args, '--isAllDay', data.isAllDay);
86
+ // Recurrence parameters
87
+ if (data.recurrence) {
88
+ addOptionalArg(args, '--recurrence', data.recurrence.frequency);
89
+ addOptionalNumberArg(args, '--recurrenceInterval', data.recurrence.interval);
90
+ addOptionalArg(args, '--recurrenceEnd', data.recurrence.endDate);
91
+ addOptionalNumberArg(args, '--recurrenceCount', data.recurrence.occurrenceCount);
92
+ }
93
+ return executeCli(args);
94
+ }
95
+ async deleteEvent(id) {
96
+ await executeCli(['--action', 'delete-event', '--id', id]);
97
+ }
98
+ }
99
+ export const calendarRepository = new CalendarRepository();
100
+ //# 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,28 @@
1
+ /**
2
+ * @fileoverview Swift CLI execution and JSON response parsing
3
+ * @module utils/cliExecutor
4
+ * @description Executes the EventKitCLI binary for native macOS EventKit operations
5
+ */
6
+ import { type PermissionDomain } from './permissionPrompt.js';
7
+ /**
8
+ * Custom error class for permission-related failures
9
+ */
10
+ export declare class CliPermissionError extends Error {
11
+ readonly domain: PermissionDomain;
12
+ constructor(message: string, domain: PermissionDomain);
13
+ }
14
+ /**
15
+ * Executes the EventKitCLI binary for native macOS EventKit operations
16
+ * @template T - Expected return type from the Swift CLI
17
+ * @param {string[]} args - Array of arguments to pass to the CLI
18
+ * @returns {Promise<T>} Parsed JSON result from the CLI
19
+ * @throws {Error} If binary not found, validation fails, or CLI execution fails
20
+ * @description
21
+ * - Locates binary using secure path validation
22
+ * - Parses JSON response from Swift CLI
23
+ * - Proactively triggers permission prompts via AppleScript on first access
24
+ * - Automatically retries with AppleScript fallback on permission errors
25
+ * @example
26
+ * const result = await executeCli<Reminder[]>(['--action', 'read', '--showCompleted', 'true']);
27
+ */
28
+ export declare function executeCli<T>(args: string[]): Promise<T>;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @fileoverview Swift CLI execution and JSON response parsing
3
+ * @module utils/cliExecutor
4
+ * @description Executes the EventKitCLI binary for native macOS EventKit operations
5
+ */
6
+ import { execFile } from 'node:child_process';
7
+ import path from 'node:path';
8
+ import { findSecureBinaryPath, getEnvironmentBinaryConfig, } from './binaryValidator.js';
9
+ import { FILE_SYSTEM } from './constants.js';
10
+ import { createCliPermissionHint } from './errorHandling.js';
11
+ import { hasBeenPrompted, triggerPermissionPrompt, } from './permissionPrompt.js';
12
+ import { findProjectRoot } from './projectUtils.js';
13
+ const execFilePromise = (cliPath, args) => new Promise((resolve, reject) => {
14
+ execFile(cliPath, args, (error, stdout, stderr) => {
15
+ if (error) {
16
+ const execError = error;
17
+ execError.stdout = stdout;
18
+ execError.stderr = stderr;
19
+ reject(execError);
20
+ return;
21
+ }
22
+ resolve({ stdout, stderr });
23
+ });
24
+ });
25
+ /**
26
+ * Permission error patterns from the Swift CLI
27
+ */
28
+ const PERMISSION_ERROR_PATTERNS = {
29
+ reminders: [
30
+ /reminder permission denied/i,
31
+ /reminders access denied/i,
32
+ /not authorized.*reminders/i,
33
+ ],
34
+ calendars: [
35
+ /calendar permission denied/i,
36
+ /calendar access denied/i,
37
+ /not authorized.*calendar/i,
38
+ ],
39
+ };
40
+ /**
41
+ * Calendar-specific action names used in Swift CLI
42
+ */
43
+ const CALENDAR_ACTIONS = new Set([
44
+ 'read-events',
45
+ 'read-calendars',
46
+ 'create-event',
47
+ 'update-event',
48
+ 'delete-event',
49
+ ]);
50
+ /**
51
+ * Detects which permission domain an action requires
52
+ * @param args - CLI arguments array
53
+ * @returns The permission domain ('reminders' or 'calendars')
54
+ */
55
+ function detectActionDomain(args) {
56
+ const actionIndex = args.indexOf('--action');
57
+ if (actionIndex !== -1 && actionIndex + 1 < args.length) {
58
+ const action = args[actionIndex + 1];
59
+ return CALENDAR_ACTIONS.has(action) ? 'calendars' : 'reminders';
60
+ }
61
+ return 'reminders'; // Default to reminders if action not found
62
+ }
63
+ /**
64
+ * Detects if an error message indicates a permission issue
65
+ * @param message - Error message to check
66
+ * @returns The permission domain if detected, null otherwise
67
+ */
68
+ function detectPermissionError(message) {
69
+ for (const [domain, patterns] of Object.entries(PERMISSION_ERROR_PATTERNS)) {
70
+ if (patterns.some((pattern) => pattern.test(message))) {
71
+ return domain;
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ /**
77
+ * Custom error class for permission-related failures
78
+ */
79
+ export class CliPermissionError extends Error {
80
+ constructor(message, domain) {
81
+ super(message);
82
+ this.domain = domain;
83
+ this.name = 'CliPermissionError';
84
+ }
85
+ }
86
+ /**
87
+ * Calendar action strings used in Swift CLI (different from MCP tool action names)
88
+ */
89
+ const bufferToString = (data) => {
90
+ if (typeof data === 'string')
91
+ return data;
92
+ if (Buffer.isBuffer(data))
93
+ return data.toString('utf8');
94
+ return data == null ? null : String(data);
95
+ };
96
+ /**
97
+ * Parses JSON output from CLI
98
+ */
99
+ const parseCliOutput = (output) => {
100
+ let parsed;
101
+ try {
102
+ parsed = JSON.parse(output);
103
+ }
104
+ catch (_error) {
105
+ throw new Error('EventKitCLI execution failed: Invalid CLI output');
106
+ }
107
+ if (parsed.status === 'success') {
108
+ return parsed.result;
109
+ }
110
+ // Check for permission errors and throw specialized error with actionable hint
111
+ const permissionDomain = detectPermissionError(parsed.message);
112
+ if (permissionDomain) {
113
+ const hint = createCliPermissionHint(permissionDomain);
114
+ throw new CliPermissionError(`${parsed.message} ${hint}`, permissionDomain);
115
+ }
116
+ throw new Error(parsed.message);
117
+ };
118
+ const runCli = async (cliPath, args) => {
119
+ try {
120
+ const { stdout } = await execFilePromise(cliPath, args);
121
+ const normalized = bufferToString(stdout);
122
+ if (!normalized) {
123
+ throw new Error('EventKitCLI execution failed: Empty CLI output');
124
+ }
125
+ return parseCliOutput(normalized);
126
+ }
127
+ catch (error) {
128
+ // Preserve CliPermissionError for retry logic
129
+ if (error instanceof CliPermissionError) {
130
+ throw error;
131
+ }
132
+ const execError = error;
133
+ const normalized = bufferToString(execError?.stdout);
134
+ if (normalized) {
135
+ return parseCliOutput(normalized);
136
+ }
137
+ const errorMessage = error instanceof Error ? error.message : String(error);
138
+ throw new Error(`EventKitCLI execution failed: ${errorMessage}`);
139
+ }
140
+ };
141
+ /**
142
+ * Executes the EventKitCLI binary for native macOS EventKit operations
143
+ * @template T - Expected return type from the Swift CLI
144
+ * @param {string[]} args - Array of arguments to pass to the CLI
145
+ * @returns {Promise<T>} Parsed JSON result from the CLI
146
+ * @throws {Error} If binary not found, validation fails, or CLI execution fails
147
+ * @description
148
+ * - Locates binary using secure path validation
149
+ * - Parses JSON response from Swift CLI
150
+ * - Proactively triggers permission prompts via AppleScript on first access
151
+ * - Automatically retries with AppleScript fallback on permission errors
152
+ * @example
153
+ * const result = await executeCli<Reminder[]>(['--action', 'read', '--showCompleted', 'true']);
154
+ */
155
+ export async function executeCli(args) {
156
+ const projectRoot = findProjectRoot();
157
+ const binaryName = FILE_SYSTEM.SWIFT_BINARY_NAME;
158
+ const possiblePaths = [path.join(projectRoot, 'bin', binaryName)];
159
+ const config = {
160
+ ...getEnvironmentBinaryConfig(),
161
+ allowedPaths: [
162
+ '/bin/',
163
+ '/dist/swift/bin/',
164
+ '/src/swift/bin/',
165
+ '/swift/bin/',
166
+ ],
167
+ };
168
+ const { path: cliPath } = findSecureBinaryPath(possiblePaths, config);
169
+ if (!cliPath) {
170
+ throw new Error(`EventKitCLI binary not found or validation failed. Searched: ${possiblePaths.join(', ')}`);
171
+ }
172
+ // Detect which permission domain this action requires
173
+ const domain = detectActionDomain(args);
174
+ // Proactively trigger AppleScript permission prompt on first access
175
+ // This ensures the permission dialog appears even in non-interactive contexts
176
+ // where the Swift binary's native EventKit permission request may be suppressed
177
+ if (!hasBeenPrompted(domain)) {
178
+ await triggerPermissionPrompt(domain);
179
+ }
180
+ let hasRetried = false;
181
+ while (true) {
182
+ try {
183
+ return await runCli(cliPath, args);
184
+ }
185
+ catch (error) {
186
+ // On permission error, trigger AppleScript prompt and retry once
187
+ if (!hasRetried && error instanceof CliPermissionError) {
188
+ hasRetried = true;
189
+ await triggerPermissionPrompt(error.domain);
190
+ continue;
191
+ }
192
+ throw error;
193
+ }
194
+ }
195
+ }
196
+ //# sourceMappingURL=cliExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliExecutor.js","sourceRoot":"","sources":["../../src/utils/cliExecutor.ts"],"names":[],"mappings":"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"}