@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.
- package/CHANGELOG.md +575 -0
- package/LICENSE +21 -0
- package/README.md +304 -0
- package/README.zh-CN.md +270 -0
- package/bin/event +0 -0
- package/bin/event-disclaim +0 -0
- package/dist/bin/apple-calendar.d.ts +6 -0
- package/dist/bin/apple-calendar.js +8 -0
- package/dist/bin/apple-calendar.js.map +1 -0
- package/dist/bin/apple-reminders.d.ts +7 -0
- package/dist/bin/apple-reminders.js +9 -0
- package/dist/bin/apple-reminders.js.map +1 -0
- package/dist/bootstrap.d.ts +11 -0
- package/dist/bootstrap.js +44 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/server/handlers.d.ts +12 -0
- package/dist/server/handlers.js +58 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/mode.d.ts +19 -0
- package/dist/server/mode.js +47 -0
- package/dist/server/mode.js.map +1 -0
- package/dist/server/promptAbstractions.d.ts +61 -0
- package/dist/server/promptAbstractions.js +140 -0
- package/dist/server/promptAbstractions.js.map +1 -0
- package/dist/server/prompts.d.ts +13 -0
- package/dist/server/prompts.js +461 -0
- package/dist/server/prompts.js.map +1 -0
- package/dist/server/server.d.ts +61 -0
- package/dist/server/server.js +112 -0
- package/dist/server/server.js.map +1 -0
- package/dist/tools/definitions.d.ts +9 -0
- package/dist/tools/definitions.js +272 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers/calendarHandlers.d.ts +11 -0
- package/dist/tools/handlers/calendarHandlers.js +151 -0
- package/dist/tools/handlers/calendarHandlers.js.map +1 -0
- package/dist/tools/handlers/formatters.d.ts +24 -0
- package/dist/tools/handlers/formatters.js +105 -0
- package/dist/tools/handlers/formatters.js.map +1 -0
- package/dist/tools/handlers/index.d.ts +8 -0
- package/dist/tools/handlers/index.js +9 -0
- package/dist/tools/handlers/index.js.map +1 -0
- package/dist/tools/handlers/listHandlers.d.ts +10 -0
- package/dist/tools/handlers/listHandlers.js +47 -0
- package/dist/tools/handlers/listHandlers.js.map +1 -0
- package/dist/tools/handlers/reminderHandlers.d.ts +10 -0
- package/dist/tools/handlers/reminderHandlers.js +219 -0
- package/dist/tools/handlers/reminderHandlers.js.map +1 -0
- package/dist/tools/handlers/shared.d.ts +28 -0
- package/dist/tools/handlers/shared.js +57 -0
- package/dist/tools/handlers/shared.js.map +1 -0
- package/dist/tools/handlers/subtaskHandlers.d.ts +12 -0
- package/dist/tools/handlers/subtaskHandlers.js +113 -0
- package/dist/tools/handlers/subtaskHandlers.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +74 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +263 -0
- package/dist/types/index.js +42 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/prompts.d.ts +88 -0
- package/dist/types/prompts.js +6 -0
- package/dist/types/prompts.js.map +1 -0
- package/dist/types/repository.d.ts +197 -0
- package/dist/types/repository.js +14 -0
- package/dist/types/repository.js.map +1 -0
- package/dist/utils/binaryValidator.d.ts +52 -0
- package/dist/utils/binaryValidator.js +185 -0
- package/dist/utils/binaryValidator.js.map +1 -0
- package/dist/utils/calendarRepository.d.ts +49 -0
- package/dist/utils/calendarRepository.js +226 -0
- package/dist/utils/calendarRepository.js.map +1 -0
- package/dist/utils/constants.d.ts +79 -0
- package/dist/utils/constants.js +80 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/dateFiltering.d.ts +41 -0
- package/dist/utils/dateFiltering.js +129 -0
- package/dist/utils/dateFiltering.js.map +1 -0
- package/dist/utils/dateUtils.d.ts +27 -0
- package/dist/utils/dateUtils.js +71 -0
- package/dist/utils/dateUtils.js.map +1 -0
- package/dist/utils/errorHandling.d.ts +27 -0
- package/dist/utils/errorHandling.js +88 -0
- package/dist/utils/errorHandling.js.map +1 -0
- package/dist/utils/eventCli.d.ts +40 -0
- package/dist/utils/eventCli.js +294 -0
- package/dist/utils/eventCli.js.map +1 -0
- package/dist/utils/helpers.d.ts +35 -0
- package/dist/utils/helpers.js +61 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/looseDateParser.d.ts +19 -0
- package/dist/utils/looseDateParser.js +149 -0
- package/dist/utils/looseDateParser.js.map +1 -0
- package/dist/utils/projectUtils.d.ts +13 -0
- package/dist/utils/projectUtils.js +92 -0
- package/dist/utils/projectUtils.js.map +1 -0
- package/dist/utils/reminderDateParser.d.ts +8 -0
- package/dist/utils/reminderDateParser.js +89 -0
- package/dist/utils/reminderDateParser.js.map +1 -0
- package/dist/utils/reminderRepository.d.ts +33 -0
- package/dist/utils/reminderRepository.js +262 -0
- package/dist/utils/reminderRepository.js.map +1 -0
- package/dist/utils/subtaskUtils.d.ts +103 -0
- package/dist/utils/subtaskUtils.js +253 -0
- package/dist/utils/subtaskUtils.js.map +1 -0
- package/dist/utils/tagUtils.d.ts +58 -0
- package/dist/utils/tagUtils.js +177 -0
- package/dist/utils/tagUtils.js.map +1 -0
- package/dist/utils/timeHelpers.d.ts +40 -0
- package/dist/utils/timeHelpers.js +136 -0
- package/dist/utils/timeHelpers.js.map +1 -0
- package/dist/validation/schemas.d.ts +385 -0
- package/dist/validation/schemas.js +579 -0
- package/dist/validation/schemas.js.map +1 -0
- package/package.json +96 -0
- package/scripts/build-event.mjs +513 -0
- package/scripts/disclaim.c +69 -0
- package/scripts/event-Info.plist +29 -0
- package/scripts/event.entitlements +10 -0
- package/scripts/postinstall.mjs +91 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* projectUtils.ts
|
|
3
|
+
* Shared utilities for project-related operations
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { FILE_SYSTEM } from './constants.js';
|
|
9
|
+
// Project root is immutable for the lifetime of the process. Cache the first
|
|
10
|
+
// resolved path so subsequent MCP tool calls skip the up-to-10-level walk +
|
|
11
|
+
// package.json reads. Cleared by tests via `__clearProjectRootCache`.
|
|
12
|
+
let cachedProjectRoot = null;
|
|
13
|
+
/**
|
|
14
|
+
* Finds the project root directory by looking for package.json
|
|
15
|
+
* @param maxDepth - Maximum directory levels to traverse upward
|
|
16
|
+
* @returns Project root directory path
|
|
17
|
+
* @throws Error if project root cannot be found
|
|
18
|
+
*/
|
|
19
|
+
export function findProjectRoot(maxDepth = FILE_SYSTEM.MAX_DIRECTORY_SEARCH_DEPTH) {
|
|
20
|
+
if (cachedProjectRoot) {
|
|
21
|
+
return cachedProjectRoot;
|
|
22
|
+
}
|
|
23
|
+
const currentDir = getCurrentModuleDir();
|
|
24
|
+
const root = locateProjectRoot(currentDir, maxDepth);
|
|
25
|
+
if (root) {
|
|
26
|
+
cachedProjectRoot = root;
|
|
27
|
+
return root;
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Project root not found within ${maxDepth} directory levels`);
|
|
30
|
+
}
|
|
31
|
+
/** Test helper — drops the cached project root so a fresh resolve happens. */
|
|
32
|
+
export function __clearProjectRootCache() {
|
|
33
|
+
cachedProjectRoot = null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Attempts to find the project root starting from the provided directory.
|
|
37
|
+
* @param startDir - Directory to begin the search from
|
|
38
|
+
* @param maxDepth - Maximum directory levels to traverse upward
|
|
39
|
+
* @returns The project root when found, otherwise `undefined`
|
|
40
|
+
*/
|
|
41
|
+
function locateProjectRoot(startDir, maxDepth = FILE_SYSTEM.MAX_DIRECTORY_SEARCH_DEPTH) {
|
|
42
|
+
let currentDir = startDir;
|
|
43
|
+
let depth = 0;
|
|
44
|
+
while (depth < maxDepth) {
|
|
45
|
+
if (isCorrectProjectRoot(currentDir)) {
|
|
46
|
+
return currentDir;
|
|
47
|
+
}
|
|
48
|
+
const parentDir = path.dirname(currentDir);
|
|
49
|
+
if (parentDir === currentDir) {
|
|
50
|
+
break; // Reached filesystem root
|
|
51
|
+
}
|
|
52
|
+
currentDir = parentDir;
|
|
53
|
+
depth++;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a directory contains the correct package.json for this project
|
|
59
|
+
*/
|
|
60
|
+
function isCorrectProjectRoot(dir) {
|
|
61
|
+
const packageJsonPath = path.join(dir, FILE_SYSTEM.PACKAGE_JSON_FILENAME);
|
|
62
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const packageContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
67
|
+
const packageData = JSON.parse(packageContent);
|
|
68
|
+
// Accept both this package name and the upstream name: test fixtures and
|
|
69
|
+
// future upstream merges share the same detection logic.
|
|
70
|
+
return (packageData.name === '@laylzj777/my-apple-apple-eventkit' ||
|
|
71
|
+
packageData.name === 'mcp-server-apple-events');
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Silently return false for any read/parse errors during project root discovery
|
|
75
|
+
// This allows the search to continue up the directory tree
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the current module's directory
|
|
81
|
+
* Handles both production and test environments
|
|
82
|
+
*/
|
|
83
|
+
function getCurrentModuleDir() {
|
|
84
|
+
if (process.env.NODE_ENV === 'test') {
|
|
85
|
+
return path.join(process.cwd(), 'src', 'utils');
|
|
86
|
+
}
|
|
87
|
+
// In production, use import.meta.url
|
|
88
|
+
// This line is excluded from coverage due to Jest ESM limitations
|
|
89
|
+
/* istanbul ignore next */
|
|
90
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=projectUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectUtils.js","sourceRoot":"","sources":["../../src/utils/projectUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,6EAA6E;AAC7E,4EAA4E;AAC5E,sEAAsE;AACtE,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAQ,GAAG,WAAW,CAAC,0BAA0B;IAEjD,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;IACzC,MAAM,IAAI,GAAG,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAErD,IAAI,IAAI,EAAE,CAAC;QACT,iBAAiB,GAAG,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,mBAAmB,CAAC,CAAC;AAChF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB;IACrC,iBAAiB,GAAG,IAAI,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CACxB,QAAgB,EAChB,QAAQ,GAAG,WAAW,CAAC,0BAA0B;IAEjD,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,KAAK,GAAG,QAAQ,EAAE,CAAC;QACxB,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,CAAC,0BAA0B;QACnC,CAAC;QAED,UAAU,GAAG,SAAS,CAAC;QACvB,KAAK,EAAE,CAAC;IACV,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAW;IACvC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,qBAAqB,CAAC,CAAC;IAC1E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QAChE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,yEAAyE;QACzE,yDAAyD;QACzD,OAAO,CACL,WAAW,CAAC,IAAI,KAAK,oCAAoC;YACzD,WAAW,CAAC,IAAI,KAAK,yBAAyB,CAC/C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;QAChF,2DAA2D;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,qCAAqC;IACrC,kEAAkE;IAClE,0BAA0B;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reminderDateParser.ts
|
|
3
|
+
* Helper utilities for parsing reminder dueDate strings safely across timezones.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Parses reminder dueDate strings into Date objects without losing local timezone semantics.
|
|
7
|
+
*/
|
|
8
|
+
export declare const parseReminderDueDate: (dueDate?: string | null) => Date | undefined;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reminderDateParser.ts
|
|
3
|
+
* Helper utilities for parsing reminder dueDate strings safely across timezones.
|
|
4
|
+
*/
|
|
5
|
+
const DATE_ONLY_REGEX = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
6
|
+
const DATE_ONLY_WITH_TZ_REGEX = /^(\d{4}-\d{2}-\d{2})(Z|[+-]\d{2}:?\d{2})$/i;
|
|
7
|
+
const DATE_TIME_NO_TZ_REGEX = /^(\d{4})-(\d{2})-(\d{2})[ T]+(\d{2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?$/;
|
|
8
|
+
const TIMEZONE_SUFFIX_REGEX = /(Z|[+-]\d{2}(?::?\d{2})?)$/i;
|
|
9
|
+
const toNumber = (value) => Number.parseInt(value, 10);
|
|
10
|
+
const createLocalDate = (year, month, day, hour = 0, minute = 0, second = 0) => {
|
|
11
|
+
if ([year, month, day, hour, minute, second].some(Number.isNaN)) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const date = new Date(year, month - 1, day, hour, minute, second, 0);
|
|
15
|
+
// Validate that the date wasn't auto-corrected by JavaScript
|
|
16
|
+
if (date.getFullYear() !== year ||
|
|
17
|
+
date.getMonth() !== month - 1 ||
|
|
18
|
+
date.getDate() !== day ||
|
|
19
|
+
date.getHours() !== hour ||
|
|
20
|
+
date.getMinutes() !== minute ||
|
|
21
|
+
date.getSeconds() !== second) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return date;
|
|
25
|
+
};
|
|
26
|
+
const normalizeTimezoneSegment = (segment) => {
|
|
27
|
+
if (!segment)
|
|
28
|
+
return segment;
|
|
29
|
+
if (segment === 'Z' || segment === 'z')
|
|
30
|
+
return 'Z';
|
|
31
|
+
const clean = segment.replace(':', '').replace(' ', '');
|
|
32
|
+
if (clean.length === 3) {
|
|
33
|
+
return `${clean}:00`;
|
|
34
|
+
}
|
|
35
|
+
if (clean.length === 5) {
|
|
36
|
+
return `${clean.slice(0, 3)}:${clean.slice(3)}`;
|
|
37
|
+
}
|
|
38
|
+
return segment.includes(':')
|
|
39
|
+
? segment
|
|
40
|
+
: `${segment.slice(0, 3)}:${segment.slice(3)}`;
|
|
41
|
+
};
|
|
42
|
+
const normalizeIsoString = (value) => {
|
|
43
|
+
let normalized = value.trim();
|
|
44
|
+
if (normalized.includes(' ') && normalized.indexOf(' ') === 10) {
|
|
45
|
+
normalized = `${normalized.slice(0, 10)}T${normalized.slice(11)}`;
|
|
46
|
+
}
|
|
47
|
+
normalized = normalized.replace(TIMEZONE_SUFFIX_REGEX, (match) => normalizeTimezoneSegment(match));
|
|
48
|
+
return normalized;
|
|
49
|
+
};
|
|
50
|
+
const parseWithNative = (value) => {
|
|
51
|
+
const normalized = normalizeIsoString(value);
|
|
52
|
+
const parsed = new Date(normalized);
|
|
53
|
+
return Number.isNaN(parsed.getTime()) ? undefined : parsed;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Parses reminder dueDate strings into Date objects without losing local timezone semantics.
|
|
57
|
+
*/
|
|
58
|
+
export const parseReminderDueDate = (dueDate) => {
|
|
59
|
+
if (!dueDate)
|
|
60
|
+
return undefined;
|
|
61
|
+
const trimmed = dueDate.trim();
|
|
62
|
+
if (!trimmed)
|
|
63
|
+
return undefined;
|
|
64
|
+
const dateOnlyMatch = trimmed.match(DATE_ONLY_REGEX);
|
|
65
|
+
if (dateOnlyMatch) {
|
|
66
|
+
// Groups 1-3 are mandatory in DATE_ONLY_REGEX, so they are always defined.
|
|
67
|
+
return createLocalDate(toNumber(dateOnlyMatch[1]), toNumber(dateOnlyMatch[2]), toNumber(dateOnlyMatch[3]));
|
|
68
|
+
}
|
|
69
|
+
const dateWithTzMatch = trimmed.match(DATE_ONLY_WITH_TZ_REGEX);
|
|
70
|
+
if (dateWithTzMatch) {
|
|
71
|
+
return parseWithNative(`${dateWithTzMatch[1]}T00:00:00${normalizeTimezoneSegment(dateWithTzMatch[2])}`);
|
|
72
|
+
}
|
|
73
|
+
const localDateTimeMatch = trimmed.match(DATE_TIME_NO_TZ_REGEX);
|
|
74
|
+
if (localDateTimeMatch) {
|
|
75
|
+
// Groups 1-5 are mandatory; group 6 (seconds) is optional.
|
|
76
|
+
const secondStr = localDateTimeMatch[6];
|
|
77
|
+
return createLocalDate(toNumber(localDateTimeMatch[1]), toNumber(localDateTimeMatch[2]), toNumber(localDateTimeMatch[3]), toNumber(localDateTimeMatch[4]), toNumber(localDateTimeMatch[5]), secondStr ? toNumber(secondStr) : 0);
|
|
78
|
+
}
|
|
79
|
+
if (TIMEZONE_SUFFIX_REGEX.test(trimmed)) {
|
|
80
|
+
return parseWithNative(trimmed);
|
|
81
|
+
}
|
|
82
|
+
// Reject strings that don't match expected date format patterns
|
|
83
|
+
// Valid formats should only contain: digits, hyphens, colons, spaces, T, Z, +, -, and dots
|
|
84
|
+
if (!/^[\d\-:T\s.Z+]+$/.test(trimmed)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return parseWithNative(trimmed);
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=reminderDateParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminderDateParser.js","sourceRoot":"","sources":["../../src/utils/reminderDateParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reminderRepository.ts
|
|
3
|
+
* Repository for reminder data access via the vendored `event` CLI.
|
|
4
|
+
*
|
|
5
|
+
* Tags and subtasks are TS-managed in the notes field (`[#tag]` and
|
|
6
|
+
* `---SUBTASKS---` blocks); the `event --tags` / `--parentTitle` flags are
|
|
7
|
+
* not used so the AdvancedReminderEdit Shortcut is not required.
|
|
8
|
+
*/
|
|
9
|
+
import type { Reminder, ReminderList } from '../types/index.js';
|
|
10
|
+
import type { CreateReminderData, IReminderRepository, ReminderJSON, UpdateReminderData } from '../types/repository.js';
|
|
11
|
+
import type { ReminderFilters } from './dateFiltering.js';
|
|
12
|
+
declare class ReminderRepository implements IReminderRepository {
|
|
13
|
+
private mapReminder;
|
|
14
|
+
private mapReminders;
|
|
15
|
+
private readAllRemindersIncludingCompleted;
|
|
16
|
+
findReminderById(id: string): Promise<Reminder>;
|
|
17
|
+
findReminders(filters?: ReminderFilters): Promise<Reminder[]>;
|
|
18
|
+
findAllLists(): Promise<ReminderList[]>;
|
|
19
|
+
createReminder(data: CreateReminderData): Promise<ReminderJSON>;
|
|
20
|
+
updateReminder(data: UpdateReminderData): Promise<ReminderJSON>;
|
|
21
|
+
deleteReminder(id: string): Promise<void>;
|
|
22
|
+
createReminderList(name: string): Promise<ReminderList>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a list name to its EventKit identifier. `event reminders lists
|
|
25
|
+
* update|delete` are keyed by id, not name, so we have to round-trip
|
|
26
|
+
* through `lists list` whenever a caller targets a list by name.
|
|
27
|
+
*/
|
|
28
|
+
private resolveListIdByName;
|
|
29
|
+
updateReminderList(currentName: string, newName: string): Promise<ReminderList>;
|
|
30
|
+
deleteReminderList(name: string): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare const reminderRepository: ReminderRepository;
|
|
33
|
+
export { ReminderRepository };
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reminderRepository.ts
|
|
3
|
+
* Repository for reminder data access via the vendored `event` CLI.
|
|
4
|
+
*
|
|
5
|
+
* Tags and subtasks are TS-managed in the notes field (`[#tag]` and
|
|
6
|
+
* `---SUBTASKS---` blocks); the `event --tags` / `--parentTitle` flags are
|
|
7
|
+
* not used so the AdvancedReminderEdit Shortcut is not required.
|
|
8
|
+
*/
|
|
9
|
+
import { applyReminderFilters, prefilterReminderJsons, } from './dateFiltering.js';
|
|
10
|
+
import { CliUserError } from './errorHandling.js';
|
|
11
|
+
import { executeEventCliJson, executeEventCliPlain } from './eventCli.js';
|
|
12
|
+
import { addOptionalArg, addOptionalNumberArg, nullToUndefined, } from './helpers.js';
|
|
13
|
+
import { getSubtaskProgress, parseSubtasks } from './subtaskUtils.js';
|
|
14
|
+
import { extractTags } from './tagUtils.js';
|
|
15
|
+
const VALID_ALARM_TYPES = ['display', 'audio', 'procedure', 'email'];
|
|
16
|
+
const isValidAlarmType = (value) => VALID_ALARM_TYPES.includes(value);
|
|
17
|
+
const mapAlarmType = (alarmType) => alarmType && isValidAlarmType(alarmType) ? alarmType : undefined;
|
|
18
|
+
/**
|
|
19
|
+
* `event` returns reminders without a top-level `locationTrigger` field —
|
|
20
|
+
* geofence triggers live inside the `alarms[].locationTrigger` shape. The
|
|
21
|
+
* downstream formatter / icon logic still keys off `reminder.locationTrigger`
|
|
22
|
+
* to render 📍, so derive the first alarm's location trigger here to preserve
|
|
23
|
+
* the existing read-side rendering. Alarms whose proximity is `'none'`
|
|
24
|
+
* (`EKAlarmProximityNone` — geofence configured but no fire condition) are
|
|
25
|
+
* skipped so they don't show up as misleading "Arriving at..." entries.
|
|
26
|
+
*/
|
|
27
|
+
const deriveTopLevelLocationTrigger = (alarms) => {
|
|
28
|
+
if (!alarms || alarms.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
for (const alarm of alarms) {
|
|
31
|
+
if (alarm?.locationTrigger && alarm.locationTrigger.proximity !== 'none') {
|
|
32
|
+
return alarm.locationTrigger;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
// Maps the wire-level proximity union (event emits 'enter' / 'leave' / 'none')
|
|
38
|
+
// onto the domain union ('enter' / 'leave'). 'none' returns undefined so the
|
|
39
|
+
// caller can skip surfacing an unconfigured trigger.
|
|
40
|
+
const mapProximity = (proximity) => proximity === 'leave' ? 'leave' : proximity === 'enter' ? 'enter' : undefined;
|
|
41
|
+
const mapList = (list) => ({
|
|
42
|
+
id: list.id,
|
|
43
|
+
title: list.title,
|
|
44
|
+
color: list.color ?? undefined,
|
|
45
|
+
});
|
|
46
|
+
class ReminderRepository {
|
|
47
|
+
mapReminder(reminder) {
|
|
48
|
+
const normalizedReminder = nullToUndefined(reminder, [
|
|
49
|
+
'notes',
|
|
50
|
+
'url',
|
|
51
|
+
'dueDate',
|
|
52
|
+
'startDate',
|
|
53
|
+
'completionDate',
|
|
54
|
+
'location',
|
|
55
|
+
'timeZone',
|
|
56
|
+
'creationDate',
|
|
57
|
+
'lastModifiedDate',
|
|
58
|
+
'externalId',
|
|
59
|
+
]);
|
|
60
|
+
const mapRecurrenceRule = (rule) => ({
|
|
61
|
+
frequency: rule.frequency,
|
|
62
|
+
interval: rule.interval ?? 1,
|
|
63
|
+
endDate: rule.endDate ?? undefined,
|
|
64
|
+
occurrenceCount: rule.occurrenceCount ?? undefined,
|
|
65
|
+
daysOfWeek: rule.daysOfWeek ?? undefined,
|
|
66
|
+
daysOfMonth: rule.daysOfMonth ?? undefined,
|
|
67
|
+
monthsOfYear: rule.monthsOfYear ?? undefined,
|
|
68
|
+
});
|
|
69
|
+
if (reminder.recurrenceRules && reminder.recurrenceRules.length > 0) {
|
|
70
|
+
normalizedReminder.recurrenceRules =
|
|
71
|
+
reminder.recurrenceRules.map(mapRecurrenceRule);
|
|
72
|
+
}
|
|
73
|
+
const derivedLocationTrigger = reminder.locationTrigger ??
|
|
74
|
+
deriveTopLevelLocationTrigger(reminder.alarms);
|
|
75
|
+
if (derivedLocationTrigger) {
|
|
76
|
+
const proximity = mapProximity(derivedLocationTrigger.proximity);
|
|
77
|
+
if (proximity) {
|
|
78
|
+
normalizedReminder.locationTrigger = {
|
|
79
|
+
title: derivedLocationTrigger.title,
|
|
80
|
+
latitude: derivedLocationTrigger.latitude,
|
|
81
|
+
longitude: derivedLocationTrigger.longitude,
|
|
82
|
+
radius: derivedLocationTrigger.radius,
|
|
83
|
+
proximity,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (reminder.alarms && reminder.alarms.length > 0) {
|
|
88
|
+
normalizedReminder.alarms = reminder.alarms
|
|
89
|
+
.filter((alarm) => alarm !== null)
|
|
90
|
+
.map((alarm) => {
|
|
91
|
+
const alarmProximity = alarm.locationTrigger
|
|
92
|
+
? mapProximity(alarm.locationTrigger.proximity)
|
|
93
|
+
: undefined;
|
|
94
|
+
return {
|
|
95
|
+
relativeOffset: alarm.relativeOffset ?? undefined,
|
|
96
|
+
absoluteDate: alarm.absoluteDate ?? undefined,
|
|
97
|
+
alarmType: mapAlarmType(alarm.alarmType),
|
|
98
|
+
locationTrigger: alarm.locationTrigger && alarmProximity
|
|
99
|
+
? {
|
|
100
|
+
title: alarm.locationTrigger.title,
|
|
101
|
+
latitude: alarm.locationTrigger.latitude,
|
|
102
|
+
longitude: alarm.locationTrigger.longitude,
|
|
103
|
+
radius: alarm.locationTrigger.radius,
|
|
104
|
+
proximity: alarmProximity,
|
|
105
|
+
}
|
|
106
|
+
: undefined,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const tags = extractTags(reminder.notes);
|
|
111
|
+
if (tags.length > 0) {
|
|
112
|
+
normalizedReminder.tags = tags;
|
|
113
|
+
}
|
|
114
|
+
const subtasks = parseSubtasks(reminder.notes);
|
|
115
|
+
if (subtasks.length > 0) {
|
|
116
|
+
normalizedReminder.subtasks = subtasks;
|
|
117
|
+
normalizedReminder.subtaskProgress = getSubtaskProgress(subtasks);
|
|
118
|
+
}
|
|
119
|
+
return normalizedReminder;
|
|
120
|
+
}
|
|
121
|
+
mapReminders(reminders) {
|
|
122
|
+
return reminders.map((reminder) => this.mapReminder(reminder));
|
|
123
|
+
}
|
|
124
|
+
// Reads every reminder (including completed) once so we can `.find` by id.
|
|
125
|
+
// `event reminders list` is the only event command that surfaces a reminder
|
|
126
|
+
// by id, since there's no equivalent of the old `read-by-id` action.
|
|
127
|
+
async readAllRemindersIncludingCompleted() {
|
|
128
|
+
return executeEventCliJson([
|
|
129
|
+
'reminders',
|
|
130
|
+
'list',
|
|
131
|
+
'--completed',
|
|
132
|
+
'--json',
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
async findReminderById(id) {
|
|
136
|
+
const all = await this.readAllRemindersIncludingCompleted();
|
|
137
|
+
const match = all.find((r) => r.id === id);
|
|
138
|
+
if (!match) {
|
|
139
|
+
throw new CliUserError(`Reminder with ID '${id}' not found.`);
|
|
140
|
+
}
|
|
141
|
+
return this.mapReminder(match);
|
|
142
|
+
}
|
|
143
|
+
async findReminders(filters = {}) {
|
|
144
|
+
const args = ['reminders', 'list'];
|
|
145
|
+
addOptionalArg(args, '--list', filters.list);
|
|
146
|
+
if (filters.showCompleted) {
|
|
147
|
+
args.push('--completed');
|
|
148
|
+
}
|
|
149
|
+
args.push('--json');
|
|
150
|
+
const reminders = await executeEventCliJson(args);
|
|
151
|
+
// Apply the cheap structural filters on raw JSON before `mapReminder`'s
|
|
152
|
+
// regex scans for tags / subtasks — important when the result set is
|
|
153
|
+
// large and the user wants a narrow slice (e.g. priority='high').
|
|
154
|
+
const preFiltered = prefilterReminderJsons(reminders, filters);
|
|
155
|
+
const normalized = this.mapReminders(preFiltered);
|
|
156
|
+
return applyReminderFilters(normalized, {
|
|
157
|
+
...filters,
|
|
158
|
+
// `event` filters out completed reminders unless `--completed` is set;
|
|
159
|
+
// list filtering is done by event too. Priority/recurring/locationBased
|
|
160
|
+
// were already applied to JSON. Leave only search/dueWithin/tags for
|
|
161
|
+
// the post-map pass.
|
|
162
|
+
showCompleted: undefined,
|
|
163
|
+
list: undefined,
|
|
164
|
+
priority: undefined,
|
|
165
|
+
recurring: undefined,
|
|
166
|
+
locationBased: undefined,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async findAllLists() {
|
|
170
|
+
const lists = await executeEventCliJson([
|
|
171
|
+
'reminders',
|
|
172
|
+
'lists',
|
|
173
|
+
'list',
|
|
174
|
+
'--json',
|
|
175
|
+
]);
|
|
176
|
+
return lists.map(mapList);
|
|
177
|
+
}
|
|
178
|
+
async createReminder(data) {
|
|
179
|
+
const args = ['reminders', 'create', '--title', data.title];
|
|
180
|
+
addOptionalArg(args, '--list', data.list);
|
|
181
|
+
addOptionalArg(args, '--notes', data.notes);
|
|
182
|
+
addOptionalArg(args, '--url', data.url);
|
|
183
|
+
addOptionalArg(args, '--due', data.dueDate);
|
|
184
|
+
addOptionalNumberArg(args, '--priority', data.priority);
|
|
185
|
+
// Skip the AdvancedReminderEdit Shortcut path — tags / subtasks live in
|
|
186
|
+
// the notes field (see tagUtils / subtaskUtils).
|
|
187
|
+
args.push('--no-shortcuts', '--json');
|
|
188
|
+
return executeEventCliJson(args);
|
|
189
|
+
}
|
|
190
|
+
async updateReminder(data) {
|
|
191
|
+
// Cross-list moves and `isCompleted: false` rejected by the handler so
|
|
192
|
+
// we share its `findReminderById` fetch with the notes-rebuild path.
|
|
193
|
+
const args = ['reminders', 'update', '--id', data.id];
|
|
194
|
+
addOptionalArg(args, '--title', data.newTitle);
|
|
195
|
+
addOptionalArg(args, '--notes', data.notes);
|
|
196
|
+
addOptionalArg(args, '--url', data.url);
|
|
197
|
+
addOptionalArg(args, '--due', data.dueDate);
|
|
198
|
+
addOptionalArg(args, '--start', data.startDate);
|
|
199
|
+
addOptionalNumberArg(args, '--priority', data.priority);
|
|
200
|
+
if (data.isCompleted !== undefined) {
|
|
201
|
+
args.push('--completed', data.isCompleted ? 'true' : 'false');
|
|
202
|
+
}
|
|
203
|
+
args.push('--no-shortcuts', '--json');
|
|
204
|
+
return executeEventCliJson(args);
|
|
205
|
+
}
|
|
206
|
+
async deleteReminder(id) {
|
|
207
|
+
// `event reminders delete` prints a status line ("Reminder deleted
|
|
208
|
+
// successfully") instead of JSON. Use the plain-text executor so we don't
|
|
209
|
+
// attempt to JSON.parse the success message.
|
|
210
|
+
await executeEventCliPlain(['reminders', 'delete', '--id', id]);
|
|
211
|
+
}
|
|
212
|
+
async createReminderList(name) {
|
|
213
|
+
const listJson = await executeEventCliJson([
|
|
214
|
+
'reminders',
|
|
215
|
+
'lists',
|
|
216
|
+
'create',
|
|
217
|
+
'--name',
|
|
218
|
+
name,
|
|
219
|
+
'--json',
|
|
220
|
+
]);
|
|
221
|
+
return mapList(listJson);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resolves a list name to its EventKit identifier. `event reminders lists
|
|
225
|
+
* update|delete` are keyed by id, not name, so we have to round-trip
|
|
226
|
+
* through `lists list` whenever a caller targets a list by name.
|
|
227
|
+
*/
|
|
228
|
+
async resolveListIdByName(name) {
|
|
229
|
+
const lists = await executeEventCliJson([
|
|
230
|
+
'reminders',
|
|
231
|
+
'lists',
|
|
232
|
+
'list',
|
|
233
|
+
'--json',
|
|
234
|
+
]);
|
|
235
|
+
const match = lists.find((list) => list.title === name);
|
|
236
|
+
if (!match) {
|
|
237
|
+
throw new CliUserError(`List '${name}' not found.`);
|
|
238
|
+
}
|
|
239
|
+
return match.id;
|
|
240
|
+
}
|
|
241
|
+
async updateReminderList(currentName, newName) {
|
|
242
|
+
const id = await this.resolveListIdByName(currentName);
|
|
243
|
+
const listJson = await executeEventCliJson([
|
|
244
|
+
'reminders',
|
|
245
|
+
'lists',
|
|
246
|
+
'update',
|
|
247
|
+
'--id',
|
|
248
|
+
id,
|
|
249
|
+
'--name',
|
|
250
|
+
newName,
|
|
251
|
+
'--json',
|
|
252
|
+
]);
|
|
253
|
+
return mapList(listJson);
|
|
254
|
+
}
|
|
255
|
+
async deleteReminderList(name) {
|
|
256
|
+
const id = await this.resolveListIdByName(name);
|
|
257
|
+
await executeEventCliPlain(['reminders', 'lists', 'delete', '--id', id]);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
export const reminderRepository = new ReminderRepository();
|
|
261
|
+
export { ReminderRepository };
|
|
262
|
+
//# sourceMappingURL=reminderRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminderRepository.js","sourceRoot":"","sources":["../../src/utils/reminderRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* subtaskUtils.ts
|
|
3
|
+
* Utilities for handling subtasks stored in reminder notes
|
|
4
|
+
*
|
|
5
|
+
* Subtasks are stored in the notes field with a human-readable format:
|
|
6
|
+
* ---SUBTASKS---
|
|
7
|
+
* [ ] {id} Task title
|
|
8
|
+
* [x] {id} Completed task title
|
|
9
|
+
* ---END SUBTASKS---
|
|
10
|
+
*
|
|
11
|
+
* This format:
|
|
12
|
+
* - Is human-readable in the native Reminders app
|
|
13
|
+
* - Allows programmatic parsing and manipulation
|
|
14
|
+
* - Coexists with tags ([#tag] format) and user notes
|
|
15
|
+
*/
|
|
16
|
+
import type { Subtask, SubtaskProgress } from '../types/index.js';
|
|
17
|
+
/**
|
|
18
|
+
* Generates a short unique ID (8 hex characters)
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateSubtaskId(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Parses subtasks from notes content
|
|
23
|
+
* @param notes - The notes string that may contain subtasks
|
|
24
|
+
* @returns Array of subtasks in order
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseSubtasks(notes: string | null | undefined): Subtask[];
|
|
27
|
+
/**
|
|
28
|
+
* Serializes subtasks into the notes format
|
|
29
|
+
* @param subtasks - Array of subtasks to serialize
|
|
30
|
+
* @returns Formatted subtask section string (empty string if no subtasks)
|
|
31
|
+
*/
|
|
32
|
+
export declare function serializeSubtasks(subtasks: Subtask[]): string;
|
|
33
|
+
/**
|
|
34
|
+
* Removes the subtask section from notes, returning clean content
|
|
35
|
+
* @param notes - The notes string with potential subtasks
|
|
36
|
+
* @returns Notes content without subtask section
|
|
37
|
+
*/
|
|
38
|
+
export declare function stripSubtasks(notes: string | null | undefined): string;
|
|
39
|
+
/**
|
|
40
|
+
* Combines subtasks with notes content
|
|
41
|
+
* Tags are preserved and subtasks are appended at the end
|
|
42
|
+
* @param subtasks - Array of subtasks
|
|
43
|
+
* @param notes - Existing notes content (may have tags and/or existing subtasks)
|
|
44
|
+
* @returns Combined notes with subtasks appended
|
|
45
|
+
*/
|
|
46
|
+
export declare function combineSubtasksAndNotes(subtasks: Subtask[], notes: string | undefined): string;
|
|
47
|
+
/**
|
|
48
|
+
* Adds a subtask to existing notes
|
|
49
|
+
* @param title - Title of the new subtask
|
|
50
|
+
* @param notes - Existing notes content
|
|
51
|
+
* @returns Updated notes with new subtask added
|
|
52
|
+
*/
|
|
53
|
+
export declare function addSubtask(title: string, notes: string | undefined): {
|
|
54
|
+
notes: string;
|
|
55
|
+
subtask: Subtask;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Updates a subtask in existing notes
|
|
59
|
+
* @param subtaskId - ID of the subtask to update
|
|
60
|
+
* @param updates - Partial subtask updates
|
|
61
|
+
* @param notes - Existing notes content
|
|
62
|
+
* @returns Updated notes with subtask modified
|
|
63
|
+
*/
|
|
64
|
+
export declare function updateSubtask(subtaskId: string, updates: {
|
|
65
|
+
title?: string;
|
|
66
|
+
isCompleted?: boolean;
|
|
67
|
+
}, notes: string | undefined): string;
|
|
68
|
+
/**
|
|
69
|
+
* Removes a subtask from existing notes
|
|
70
|
+
* @param subtaskId - ID of the subtask to remove
|
|
71
|
+
* @param notes - Existing notes content
|
|
72
|
+
* @returns Updated notes with subtask removed
|
|
73
|
+
*/
|
|
74
|
+
export declare function removeSubtask(subtaskId: string, notes: string | undefined): string;
|
|
75
|
+
/**
|
|
76
|
+
* Toggles a subtask's completion status
|
|
77
|
+
* @param subtaskId - ID of the subtask to toggle
|
|
78
|
+
* @param notes - Existing notes content
|
|
79
|
+
* @returns Updated notes with subtask toggled
|
|
80
|
+
*/
|
|
81
|
+
export declare function toggleSubtask(subtaskId: string, notes: string | undefined): {
|
|
82
|
+
notes: string;
|
|
83
|
+
subtask: Subtask;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Reorders subtasks based on provided ID order
|
|
87
|
+
* @param order - Array of subtask IDs in desired order
|
|
88
|
+
* @param notes - Existing notes content
|
|
89
|
+
* @returns Updated notes with subtasks reordered
|
|
90
|
+
*/
|
|
91
|
+
export declare function reorderSubtasks(order: string[], notes: string | undefined): string;
|
|
92
|
+
/**
|
|
93
|
+
* Creates subtasks from an array of titles
|
|
94
|
+
* @param titles - Array of subtask titles
|
|
95
|
+
* @returns Array of new subtasks
|
|
96
|
+
*/
|
|
97
|
+
export declare function createSubtasksFromTitles(titles: string[]): Subtask[];
|
|
98
|
+
/**
|
|
99
|
+
* Calculates subtask completion progress
|
|
100
|
+
* @param subtasks - Array of subtasks
|
|
101
|
+
* @returns Progress object with completed count, total, and percentage
|
|
102
|
+
*/
|
|
103
|
+
export declare function getSubtaskProgress(subtasks: Subtask[]): SubtaskProgress;
|