@mattheworiordan/remi 0.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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/dist/cli/commands/add.d.ts +7 -0
  4. package/dist/cli/commands/add.js +36 -0
  5. package/dist/cli/commands/add.js.map +1 -0
  6. package/dist/cli/commands/authorize.d.ts +1 -0
  7. package/dist/cli/commands/authorize.js +75 -0
  8. package/dist/cli/commands/authorize.js.map +1 -0
  9. package/dist/cli/commands/complete.d.ts +3 -0
  10. package/dist/cli/commands/complete.js +9 -0
  11. package/dist/cli/commands/complete.js.map +1 -0
  12. package/dist/cli/commands/create-list.d.ts +1 -0
  13. package/dist/cli/commands/create-list.js +7 -0
  14. package/dist/cli/commands/create-list.js.map +1 -0
  15. package/dist/cli/commands/create-section.d.ts +1 -0
  16. package/dist/cli/commands/create-section.js +7 -0
  17. package/dist/cli/commands/create-section.js.map +1 -0
  18. package/dist/cli/commands/delete-list.d.ts +3 -0
  19. package/dist/cli/commands/delete-list.js +11 -0
  20. package/dist/cli/commands/delete-list.js.map +1 -0
  21. package/dist/cli/commands/delete-section.d.ts +1 -0
  22. package/dist/cli/commands/delete-section.js +7 -0
  23. package/dist/cli/commands/delete-section.js.map +1 -0
  24. package/dist/cli/commands/delete.d.ts +4 -0
  25. package/dist/cli/commands/delete.js +14 -0
  26. package/dist/cli/commands/delete.js.map +1 -0
  27. package/dist/cli/commands/doctor.d.ts +4 -0
  28. package/dist/cli/commands/doctor.js +180 -0
  29. package/dist/cli/commands/doctor.js.map +1 -0
  30. package/dist/cli/commands/list.d.ts +4 -0
  31. package/dist/cli/commands/list.js +11 -0
  32. package/dist/cli/commands/list.js.map +1 -0
  33. package/dist/cli/commands/lists.d.ts +1 -0
  34. package/dist/cli/commands/lists.js +7 -0
  35. package/dist/cli/commands/lists.js.map +1 -0
  36. package/dist/cli/commands/move.d.ts +3 -0
  37. package/dist/cli/commands/move.js +11 -0
  38. package/dist/cli/commands/move.js.map +1 -0
  39. package/dist/cli/commands/overdue.d.ts +1 -0
  40. package/dist/cli/commands/overdue.js +11 -0
  41. package/dist/cli/commands/overdue.js.map +1 -0
  42. package/dist/cli/commands/search.d.ts +1 -0
  43. package/dist/cli/commands/search.js +11 -0
  44. package/dist/cli/commands/search.js.map +1 -0
  45. package/dist/cli/commands/sections.d.ts +1 -0
  46. package/dist/cli/commands/sections.js +7 -0
  47. package/dist/cli/commands/sections.js.map +1 -0
  48. package/dist/cli/commands/today.d.ts +1 -0
  49. package/dist/cli/commands/today.js +11 -0
  50. package/dist/cli/commands/today.js.map +1 -0
  51. package/dist/cli/commands/upcoming.d.ts +3 -0
  52. package/dist/cli/commands/upcoming.js +12 -0
  53. package/dist/cli/commands/upcoming.js.map +1 -0
  54. package/dist/cli/commands/update.d.ts +7 -0
  55. package/dist/cli/commands/update.js +17 -0
  56. package/dist/cli/commands/update.js.map +1 -0
  57. package/dist/cli/index.d.ts +2 -0
  58. package/dist/cli/index.js +232 -0
  59. package/dist/cli/index.js.map +1 -0
  60. package/dist/cli/output.d.ts +26 -0
  61. package/dist/cli/output.js +234 -0
  62. package/dist/cli/output.js.map +1 -0
  63. package/dist/core/checksum.d.ts +9 -0
  64. package/dist/core/checksum.js +13 -0
  65. package/dist/core/checksum.js.map +1 -0
  66. package/dist/core/dateparse.d.ts +7 -0
  67. package/dist/core/dateparse.js +27 -0
  68. package/dist/core/dateparse.js.map +1 -0
  69. package/dist/core/errors.d.ts +26 -0
  70. package/dist/core/errors.js +34 -0
  71. package/dist/core/errors.js.map +1 -0
  72. package/dist/core/eventkit.d.ts +38 -0
  73. package/dist/core/eventkit.js +127 -0
  74. package/dist/core/eventkit.js.map +1 -0
  75. package/dist/core/lookup.d.ts +10 -0
  76. package/dist/core/lookup.js +32 -0
  77. package/dist/core/lookup.js.map +1 -0
  78. package/dist/core/membership.d.ts +30 -0
  79. package/dist/core/membership.js +92 -0
  80. package/dist/core/membership.js.map +1 -0
  81. package/dist/core/recurrence.d.ts +14 -0
  82. package/dist/core/recurrence.js +90 -0
  83. package/dist/core/recurrence.js.map +1 -0
  84. package/dist/core/reminderkit.d.ts +33 -0
  85. package/dist/core/reminderkit.js +154 -0
  86. package/dist/core/reminderkit.js.map +1 -0
  87. package/dist/core/sqlite.d.ts +65 -0
  88. package/dist/core/sqlite.js +175 -0
  89. package/dist/core/sqlite.js.map +1 -0
  90. package/dist/core/tokenmap.d.ts +29 -0
  91. package/dist/core/tokenmap.js +52 -0
  92. package/dist/core/tokenmap.js.map +1 -0
  93. package/dist/reminders-helper +0 -0
  94. package/dist/section-helper +0 -0
  95. package/dist/types.d.ts +81 -0
  96. package/dist/types.js +2 -0
  97. package/dist/types.js.map +1 -0
  98. package/package.json +63 -0
  99. package/src/swift/Info.plist +16 -0
  100. package/src/swift/build.sh +47 -0
  101. package/src/swift/reminders-helper.swift +697 -0
  102. package/src/swift/section-helper.swift +794 -0
@@ -0,0 +1,26 @@
1
+ import type { RemiError, Reminder, ReminderList, Section } from "../types.js";
2
+ export declare function setJsonMode(enabled: boolean): void;
3
+ export declare function isJsonMode(): boolean;
4
+ export declare function setVerboseMode(enabled: boolean): void;
5
+ /** Output a successful result */
6
+ export declare function outputSuccess<T>(data: T): void;
7
+ /** Output an error result */
8
+ export declare function outputError(error: RemiError): void;
9
+ /** Format and output a list of reminder lists */
10
+ export declare function outputLists(lists: ReminderList[]): void;
11
+ /** Options for reminder display */
12
+ interface OutputRemindersOpts {
13
+ /** View context — suppresses redundant info */
14
+ context?: "today" | "overdue" | "upcoming" | "search" | "list";
15
+ /** Show which list each reminder belongs to (for cross-list views) */
16
+ showList?: boolean;
17
+ /** Sort by due date */
18
+ sortByDate?: boolean;
19
+ }
20
+ /** Format and output a list of reminders */
21
+ export declare function outputReminders(reminders: Reminder[], listName?: string, opts?: OutputRemindersOpts): void;
22
+ /** Format and output a list of sections with optional reminder counts */
23
+ export declare function outputSections(sections: Section[], listName: string, counts?: Map<string, number>): void;
24
+ /** Output a simple success message */
25
+ export declare function outputMessage(message: string, data?: Record<string, unknown>): void;
26
+ export {};
@@ -0,0 +1,234 @@
1
+ import chalk from "chalk";
2
+ let jsonMode = false;
3
+ let verboseMode = false;
4
+ export function setJsonMode(enabled) {
5
+ jsonMode = enabled;
6
+ }
7
+ export function isJsonMode() {
8
+ return jsonMode;
9
+ }
10
+ export function setVerboseMode(enabled) {
11
+ verboseMode = enabled;
12
+ }
13
+ // -- Date formatting --
14
+ function formatRelativeDate(dateStr) {
15
+ const now = new Date();
16
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
17
+ const due = new Date(`${dateStr}T00:00:00`);
18
+ const diffMs = due.getTime() - today.getTime();
19
+ const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24));
20
+ if (diffDays < 0) {
21
+ const absDays = Math.abs(diffDays);
22
+ const label = absDays === 1 ? "1d overdue" : `${absDays}d overdue`;
23
+ return { text: label, isOverdue: true, isToday: false };
24
+ }
25
+ if (diffDays === 0)
26
+ return { text: "today", isOverdue: false, isToday: true };
27
+ if (diffDays === 1)
28
+ return { text: "tomorrow", isOverdue: false, isToday: false };
29
+ if (diffDays <= 7)
30
+ return { text: `in ${diffDays}d`, isOverdue: false, isToday: false };
31
+ // Format as "Apr 28" for dates within the year, "Apr 28 2027" for other years
32
+ const months = [
33
+ "Jan",
34
+ "Feb",
35
+ "Mar",
36
+ "Apr",
37
+ "May",
38
+ "Jun",
39
+ "Jul",
40
+ "Aug",
41
+ "Sep",
42
+ "Oct",
43
+ "Nov",
44
+ "Dec",
45
+ ];
46
+ const month = months[due.getMonth()];
47
+ const day = due.getDate();
48
+ if (due.getFullYear() === now.getFullYear()) {
49
+ return { text: `${month} ${day}`, isOverdue: false, isToday: false };
50
+ }
51
+ return { text: `${month} ${day} ${due.getFullYear()}`, isOverdue: false, isToday: false };
52
+ }
53
+ function colorDate(dateStr, context) {
54
+ // Skip redundant date display in context-specific views
55
+ if (context === "today")
56
+ return "";
57
+ if (context === "overdue") {
58
+ const { text } = formatRelativeDate(dateStr);
59
+ return chalk.red(text);
60
+ }
61
+ const { text, isOverdue, isToday } = formatRelativeDate(dateStr);
62
+ if (isOverdue)
63
+ return chalk.red(text);
64
+ if (isToday)
65
+ return chalk.yellow(text);
66
+ return chalk.dim(text);
67
+ }
68
+ // -- Core output functions --
69
+ /** Output a successful result */
70
+ export function outputSuccess(data) {
71
+ if (jsonMode) {
72
+ const result = { success: true, data };
73
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
74
+ }
75
+ else {
76
+ process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
77
+ }
78
+ }
79
+ /** Output an error result */
80
+ export function outputError(error) {
81
+ if (jsonMode) {
82
+ const result = { success: false, error };
83
+ process.stderr.write(`${JSON.stringify(result, null, 2)}\n`);
84
+ }
85
+ else {
86
+ process.stderr.write(chalk.red(`Error: ${error.message}\n`));
87
+ if (error.suggestion) {
88
+ process.stderr.write(chalk.yellow(`Suggestion: ${error.suggestion}\n`));
89
+ }
90
+ }
91
+ }
92
+ /** Format and output a list of reminder lists */
93
+ export function outputLists(lists) {
94
+ if (jsonMode) {
95
+ outputSuccess(lists);
96
+ return;
97
+ }
98
+ if (lists.length === 0) {
99
+ process.stdout.write("No reminder lists found.\n");
100
+ return;
101
+ }
102
+ const maxNameLen = Math.max(...lists.map((l) => l.title.length), 4);
103
+ process.stdout.write(`${chalk.bold("Name".padEnd(maxNameLen))} ${chalk.bold("Count")} ${chalk.bold("Overdue")}\n`);
104
+ process.stdout.write(`${"─".repeat(maxNameLen + 16)}\n`);
105
+ for (const list of lists) {
106
+ const count = String(list.reminderCount).padStart(5);
107
+ const overdue = list.overdueCount > 0
108
+ ? chalk.red(String(list.overdueCount).padStart(7))
109
+ : chalk.dim(String(0).padStart(7));
110
+ process.stdout.write(`${list.title.padEnd(maxNameLen)} ${count} ${overdue}\n`);
111
+ }
112
+ }
113
+ /** Format and output a list of reminders */
114
+ export function outputReminders(reminders, listName, opts) {
115
+ if (jsonMode) {
116
+ outputSuccess(reminders);
117
+ return;
118
+ }
119
+ if (reminders.length === 0) {
120
+ const ctx = listName ? ` in "${listName}"` : "";
121
+ process.stdout.write(`No reminders found${ctx}.\n`);
122
+ return;
123
+ }
124
+ // Sort by date if requested
125
+ let sorted = reminders;
126
+ if (opts?.sortByDate) {
127
+ sorted = [...reminders].sort((a, b) => {
128
+ if (!a.dueDate && !b.dueDate)
129
+ return 0;
130
+ if (!a.dueDate)
131
+ return 1;
132
+ if (!b.dueDate)
133
+ return -1;
134
+ return a.dueDate.localeCompare(b.dueDate);
135
+ });
136
+ }
137
+ // Header with summary
138
+ if (listName) {
139
+ const overdueCount = sorted.filter((r) => {
140
+ if (!r.dueDate)
141
+ return false;
142
+ const { isOverdue } = formatRelativeDate(r.dueDate);
143
+ return isOverdue;
144
+ }).length;
145
+ const summary = [`${sorted.length} reminder${sorted.length === 1 ? "" : "s"}`];
146
+ if (overdueCount > 0) {
147
+ summary.push(chalk.red(`${overdueCount} overdue`));
148
+ }
149
+ process.stdout.write(chalk.bold(`\n${listName}`) + chalk.dim(` (${summary.join(", ")})\n`));
150
+ process.stdout.write(`${"─".repeat(listName.length + 2)}\n`);
151
+ }
152
+ for (const r of sorted) {
153
+ process.stdout.write(formatReminderLine(r, opts));
154
+ }
155
+ process.stdout.write("\n");
156
+ }
157
+ function formatReminderLine(r, opts) {
158
+ const checkbox = r.isCompleted ? chalk.green("✓") : chalk.dim("○");
159
+ const title = r.isCompleted ? chalk.strikethrough(chalk.dim(r.title)) : r.title;
160
+ const parts = [` ${checkbox} ${title}`];
161
+ const badges = [];
162
+ // Date
163
+ if (r.dueDate) {
164
+ const dateStr = colorDate(r.dueDate, opts?.context);
165
+ if (dateStr)
166
+ badges.push(dateStr);
167
+ }
168
+ // Recurring — show schedule if available
169
+ if (r.recurrence) {
170
+ badges.push(chalk.blue(`↻ ${r.recurrence}`));
171
+ }
172
+ else if (r.isRecurring) {
173
+ badges.push(chalk.blue("↻"));
174
+ }
175
+ // Priority
176
+ if (r.priority && r.priority !== "none") {
177
+ const colors = { high: chalk.red, medium: chalk.yellow, low: chalk.blue };
178
+ badges.push(colors[r.priority](r.priority === "high" ? "!!!" : r.priority === "medium" ? "!!" : "!"));
179
+ }
180
+ // Flagged
181
+ if (r.flagged) {
182
+ badges.push(chalk.hex("#FF9500")("⚑"));
183
+ }
184
+ // Notes indicator
185
+ if (r.notes) {
186
+ if (verboseMode) {
187
+ const preview = r.notes.length > 60 ? `${r.notes.substring(0, 57)}...` : r.notes;
188
+ badges.push(chalk.dim(`📝 ${preview}`));
189
+ }
190
+ else {
191
+ badges.push(chalk.dim("📝"));
192
+ }
193
+ }
194
+ // Section (only in list context, not cross-list views)
195
+ if (r.section) {
196
+ badges.push(chalk.cyan(`[${r.section}]`));
197
+ }
198
+ // List name (for cross-list views like today, overdue, search)
199
+ if (opts?.showList && r.listName) {
200
+ badges.push(chalk.magenta(`[${r.listName}]`));
201
+ }
202
+ if (badges.length > 0) {
203
+ parts.push(` ${badges.join(" ")}`);
204
+ }
205
+ return `${parts.join("")}\n`;
206
+ }
207
+ /** Format and output a list of sections with optional reminder counts */
208
+ export function outputSections(sections, listName, counts) {
209
+ if (jsonMode) {
210
+ outputSuccess(sections);
211
+ return;
212
+ }
213
+ if (sections.length === 0) {
214
+ process.stdout.write(`No sections found in "${listName}".\n`);
215
+ return;
216
+ }
217
+ process.stdout.write(chalk.bold(`\nSections in "${listName}"\n`));
218
+ process.stdout.write(`${"─".repeat(listName.length + 14)}\n`);
219
+ for (const s of sections) {
220
+ const count = counts?.get(s.displayName);
221
+ const countStr = count !== undefined ? chalk.dim(` (${count})`) : "";
222
+ process.stdout.write(` • ${s.displayName}${countStr}\n`);
223
+ }
224
+ process.stdout.write("\n");
225
+ }
226
+ /** Output a simple success message */
227
+ export function outputMessage(message, data) {
228
+ if (jsonMode) {
229
+ outputSuccess({ message, ...data });
230
+ return;
231
+ }
232
+ process.stdout.write(`${chalk.green("✓")} ${message}\n`);
233
+ }
234
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SHA-512 checksum computation for section membership data.
3
+ *
4
+ * Apple's remindd uses checksums to detect data corruption in the membership field.
5
+ * The checksum is computed on the exact JSON string stored in
6
+ * ZMEMBERSHIPSOFREMINDERSINSECTIONSASDATA — any difference in whitespace or key order
7
+ * produces a different checksum.
8
+ */
9
+ export declare function computeMembershipChecksum(membershipJson: string): string;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * SHA-512 checksum computation for section membership data.
3
+ *
4
+ * Apple's remindd uses checksums to detect data corruption in the membership field.
5
+ * The checksum is computed on the exact JSON string stored in
6
+ * ZMEMBERSHIPSOFREMINDERSINSECTIONSASDATA — any difference in whitespace or key order
7
+ * produces a different checksum.
8
+ */
9
+ import { createHash } from "node:crypto";
10
+ export function computeMembershipChecksum(membershipJson) {
11
+ return createHash("sha512").update(membershipJson, "utf8").digest("hex");
12
+ }
13
+ //# sourceMappingURL=checksum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checksum.js","sourceRoot":"","sources":["../../src/core/checksum.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,yBAAyB,CAAC,cAAsB;IAC/D,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Date parsing — supports both YYYY-MM-DD and natural language ("next tuesday", "in 3 days").
3
+ *
4
+ * Uses chrono-node for natural language, falls back to direct parsing for ISO dates.
5
+ * Returns YYYY-MM-DD format (what the Swift helper expects).
6
+ */
7
+ export declare function parseDate(input: string): string;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Date parsing — supports both YYYY-MM-DD and natural language ("next tuesday", "in 3 days").
3
+ *
4
+ * Uses chrono-node for natural language, falls back to direct parsing for ISO dates.
5
+ * Returns YYYY-MM-DD format (what the Swift helper expects).
6
+ */
7
+ import * as chrono from "chrono-node";
8
+ import { ErrorCode, RemiCommandError } from "./errors.js";
9
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
10
+ export function parseDate(input) {
11
+ const trimmed = input.trim();
12
+ // Already YYYY-MM-DD — pass through
13
+ if (ISO_DATE_RE.test(trimmed)) {
14
+ return trimmed;
15
+ }
16
+ // Try natural language parsing
17
+ const results = chrono.parse(trimmed, new Date(), { forwardDate: true });
18
+ if (results.length > 0) {
19
+ const date = results[0].start.date();
20
+ const y = date.getFullYear();
21
+ const m = String(date.getMonth() + 1).padStart(2, "0");
22
+ const d = String(date.getDate()).padStart(2, "0");
23
+ return `${y}-${m}-${d}`;
24
+ }
25
+ throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, `Cannot parse date "${input}"`, 'Use YYYY-MM-DD or natural language: "tomorrow", "next tuesday", "in 3 days"');
26
+ }
27
+ //# sourceMappingURL=dateparse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dateparse.js","sourceRoot":"","sources":["../../src/core/dateparse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAE1C,MAAM,UAAU,SAAS,CAAC,KAAa;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,oCAAoC;IACpC,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,+BAA+B;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAClD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,sBAAsB,KAAK,GAAG,EAC9B,6EAA6E,CAC7E,CAAC;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { RemiError } from "../types.js";
2
+ /** Error codes for machine-readable error handling */
3
+ export declare const ErrorCode: {
4
+ readonly PERMISSION_DENIED: "PERMISSION_DENIED";
5
+ readonly LIST_NOT_FOUND: "LIST_NOT_FOUND";
6
+ readonly REMINDER_NOT_FOUND: "REMINDER_NOT_FOUND";
7
+ readonly SECTION_NOT_FOUND: "SECTION_NOT_FOUND";
8
+ readonly AMBIGUOUS_REMINDER: "AMBIGUOUS_REMINDER";
9
+ readonly REMINDERKIT_UNAVAILABLE: "REMINDERKIT_UNAVAILABLE";
10
+ readonly DB_NOT_FOUND: "DB_NOT_FOUND";
11
+ readonly SWIFT_NOT_FOUND: "SWIFT_NOT_FOUND";
12
+ readonly SWIFT_EXECUTION_FAILED: "SWIFT_EXECUTION_FAILED";
13
+ readonly SYNC_TRIGGER_FAILED: "SYNC_TRIGGER_FAILED";
14
+ readonly INVALID_ARGUMENT: "INVALID_ARGUMENT";
15
+ readonly UNKNOWN: "UNKNOWN";
16
+ };
17
+ export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
18
+ /** Create a structured RemiError */
19
+ export declare function createError(code: ErrorCode, message: string, suggestion?: string): RemiError;
20
+ /** RemiError as a throwable Error subclass */
21
+ export declare class RemiCommandError extends Error {
22
+ readonly code: ErrorCode;
23
+ readonly suggestion?: string;
24
+ constructor(code: ErrorCode, message: string, suggestion?: string);
25
+ toRemiError(): RemiError;
26
+ }
@@ -0,0 +1,34 @@
1
+ /** Error codes for machine-readable error handling */
2
+ export const ErrorCode = {
3
+ PERMISSION_DENIED: "PERMISSION_DENIED",
4
+ LIST_NOT_FOUND: "LIST_NOT_FOUND",
5
+ REMINDER_NOT_FOUND: "REMINDER_NOT_FOUND",
6
+ SECTION_NOT_FOUND: "SECTION_NOT_FOUND",
7
+ AMBIGUOUS_REMINDER: "AMBIGUOUS_REMINDER",
8
+ REMINDERKIT_UNAVAILABLE: "REMINDERKIT_UNAVAILABLE",
9
+ DB_NOT_FOUND: "DB_NOT_FOUND",
10
+ SWIFT_NOT_FOUND: "SWIFT_NOT_FOUND",
11
+ SWIFT_EXECUTION_FAILED: "SWIFT_EXECUTION_FAILED",
12
+ SYNC_TRIGGER_FAILED: "SYNC_TRIGGER_FAILED",
13
+ INVALID_ARGUMENT: "INVALID_ARGUMENT",
14
+ UNKNOWN: "UNKNOWN",
15
+ };
16
+ /** Create a structured RemiError */
17
+ export function createError(code, message, suggestion) {
18
+ return { code, message, suggestion };
19
+ }
20
+ /** RemiError as a throwable Error subclass */
21
+ export class RemiCommandError extends Error {
22
+ code;
23
+ suggestion;
24
+ constructor(code, message, suggestion) {
25
+ super(message);
26
+ this.name = "RemiCommandError";
27
+ this.code = code;
28
+ this.suggestion = suggestion;
29
+ }
30
+ toRemiError() {
31
+ return { code: this.code, message: this.message, suggestion: this.suggestion };
32
+ }
33
+ }
34
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,MAAM,CAAC,MAAM,SAAS,GAAG;IACxB,iBAAiB,EAAE,mBAAmB;IACtC,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,oBAAoB;IACxC,iBAAiB,EAAE,mBAAmB;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,uBAAuB,EAAE,yBAAyB;IAClD,YAAY,EAAE,cAAc;IAC5B,eAAe,EAAE,iBAAiB;IAClC,sBAAsB,EAAE,wBAAwB;IAChD,mBAAmB,EAAE,qBAAqB;IAC1C,gBAAgB,EAAE,kBAAkB;IACpC,OAAO,EAAE,SAAS;CACT,CAAC;AAIX,oCAAoC;AACpC,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,OAAe,EAAE,UAAmB;IAChF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC;AAED,8CAA8C;AAC9C,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACjC,IAAI,CAAY;IAChB,UAAU,CAAU;IAE7B,YAAY,IAAe,EAAE,OAAe,EAAE,UAAmB;QAChE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC9B,CAAC;IAED,WAAW;QACV,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;IAChF,CAAC;CACD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * EventKit bridge — executes the Swift helper script for Apple Reminders operations.
3
+ *
4
+ * The Swift helper runs interpreted via /usr/bin/swift and communicates via JSON.
5
+ * It handles EventKit permissions, async fetching, and all standard CRUD operations.
6
+ */
7
+ import type { Reminder, ReminderList } from "../types.js";
8
+ export declare function listLists(): Promise<ReminderList[]>;
9
+ export declare function getReminders(opts: {
10
+ list?: string;
11
+ filter?: string;
12
+ days?: number;
13
+ }): Promise<Reminder[]>;
14
+ export declare function searchReminders(query: string): Promise<Reminder[]>;
15
+ export declare function createReminder(opts: {
16
+ title: string;
17
+ listName: string;
18
+ due?: string;
19
+ notes?: string;
20
+ priority?: string;
21
+ rruleFreq?: string;
22
+ rruleInterval?: number;
23
+ rruleDays?: number[];
24
+ rruleEnd?: string;
25
+ }): Promise<string>;
26
+ export declare function editReminder(opts: {
27
+ id: string;
28
+ title?: string;
29
+ listName?: string;
30
+ due?: string;
31
+ clearDue?: boolean;
32
+ notes?: string;
33
+ priority?: string;
34
+ }): Promise<string>;
35
+ export declare function completeReminder(id: string): Promise<string>;
36
+ export declare function deleteReminder(id: string): Promise<string>;
37
+ export declare function createList(name: string): Promise<string>;
38
+ export declare function deleteList(name: string): Promise<string>;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * EventKit bridge — executes the Swift helper script for Apple Reminders operations.
3
+ *
4
+ * The Swift helper runs interpreted via /usr/bin/swift and communicates via JSON.
5
+ * It handles EventKit permissions, async fetching, and all standard CRUD operations.
6
+ */
7
+ import { execFile } from "node:child_process";
8
+ import { existsSync } from "node:fs";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { promisify } from "node:util";
12
+ import { ErrorCode, RemiCommandError } from "./errors.js";
13
+ const execFileAsync = promisify(execFile);
14
+ const TIMEOUT_MS = 30000;
15
+ /**
16
+ * Find the reminders-helper binary (preferred) or fall back to interpreted Swift script.
17
+ *
18
+ * The compiled binary has an embedded Info.plist with NSRemindersUsageDescription,
19
+ * so macOS attributes the Reminders permission to "remi" rather than the terminal app.
20
+ */
21
+ function findHelper() {
22
+ const currentDir = dirname(fileURLToPath(import.meta.url));
23
+ // Prefer compiled binary (has Info.plist for proper permissions)
24
+ const binaryPaths = [
25
+ join(currentDir, "../reminders-helper"), // From dist/core/ -> dist/reminders-helper
26
+ join(currentDir, "../../dist/reminders-helper"), // From src/core/ -> dist/reminders-helper
27
+ ];
28
+ for (const p of binaryPaths) {
29
+ if (existsSync(p))
30
+ return { path: p, isCompiled: true };
31
+ }
32
+ // Fall back to interpreted Swift script
33
+ const scriptPaths = [
34
+ join(currentDir, "../../src/swift/reminders-helper.swift"), // From dist/core/
35
+ join(currentDir, "../swift/reminders-helper.swift"), // From src/core/
36
+ ];
37
+ for (const p of scriptPaths) {
38
+ if (existsSync(p))
39
+ return { path: p, isCompiled: false };
40
+ }
41
+ throw new RemiCommandError(ErrorCode.SWIFT_NOT_FOUND, "reminders-helper not found", "Run: npm run build:swift");
42
+ }
43
+ async function runSwift(command, args) {
44
+ const helper = findHelper();
45
+ let execPath;
46
+ let cmdArgs;
47
+ if (helper.isCompiled) {
48
+ execPath = helper.path;
49
+ cmdArgs = [command];
50
+ }
51
+ else {
52
+ execPath = "/usr/bin/swift";
53
+ cmdArgs = [helper.path, command];
54
+ }
55
+ if (args) {
56
+ cmdArgs.push(JSON.stringify(args));
57
+ }
58
+ try {
59
+ const { stdout } = await execFileAsync(execPath, cmdArgs, {
60
+ timeout: TIMEOUT_MS,
61
+ env: { ...process.env },
62
+ });
63
+ return JSON.parse(stdout.trim());
64
+ }
65
+ catch (error) {
66
+ const err = error;
67
+ if (err.stdout) {
68
+ try {
69
+ const result = JSON.parse(err.stdout.trim());
70
+ if (result.error) {
71
+ throw new RemiCommandError(ErrorCode.SWIFT_EXECUTION_FAILED, result.error);
72
+ }
73
+ }
74
+ catch (parseErr) {
75
+ if (parseErr instanceof RemiCommandError)
76
+ throw parseErr;
77
+ }
78
+ }
79
+ if (err.code === "ENOENT") {
80
+ throw new RemiCommandError(ErrorCode.SWIFT_NOT_FOUND, "Swift not found at /usr/bin/swift", "Install Xcode Command Line Tools: xcode-select --install");
81
+ }
82
+ throw new RemiCommandError(ErrorCode.SWIFT_EXECUTION_FAILED, `Swift helper failed: ${err.stderr || err.message}`);
83
+ }
84
+ }
85
+ async function runSwiftCommand(command, args) {
86
+ const result = await runSwift(command, args);
87
+ if (!result.success) {
88
+ const msg = result.error || "Unknown error from Swift helper";
89
+ if (msg.includes("not found")) {
90
+ throw new RemiCommandError(ErrorCode.LIST_NOT_FOUND, msg);
91
+ }
92
+ if (msg.includes("access denied") || msg.includes("denied")) {
93
+ throw new RemiCommandError(ErrorCode.PERMISSION_DENIED, "Reminders access not granted", "Run: remi authorize (then check System Settings > Privacy & Security > Reminders)");
94
+ }
95
+ throw new RemiCommandError(ErrorCode.SWIFT_EXECUTION_FAILED, msg);
96
+ }
97
+ return result.data;
98
+ }
99
+ // -- Public API --
100
+ export async function listLists() {
101
+ return runSwift("list-lists");
102
+ }
103
+ export async function getReminders(opts) {
104
+ return runSwift("get-reminders", opts);
105
+ }
106
+ export async function searchReminders(query) {
107
+ return runSwift("search", { query });
108
+ }
109
+ export async function createReminder(opts) {
110
+ return runSwiftCommand("create", opts);
111
+ }
112
+ export async function editReminder(opts) {
113
+ return runSwiftCommand("edit", opts);
114
+ }
115
+ export async function completeReminder(id) {
116
+ return runSwiftCommand("complete", { id });
117
+ }
118
+ export async function deleteReminder(id) {
119
+ return runSwiftCommand("delete", { id });
120
+ }
121
+ export async function createList(name) {
122
+ return runSwiftCommand("create-list", { name });
123
+ }
124
+ export async function deleteList(name) {
125
+ return runSwiftCommand("delete-list", { name });
126
+ }
127
+ //# sourceMappingURL=eventkit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventkit.js","sourceRoot":"","sources":["../../src/core/eventkit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Reminder lookup by title within a list.
3
+ *
4
+ * Resolves a human-friendly title to a reminder ID for operations like
5
+ * complete, delete, update, and move.
6
+ */
7
+ import type { Reminder } from "../types.js";
8
+ export declare function findReminderByTitle(listName: string, title: string, opts?: {
9
+ id?: string;
10
+ }): Promise<Reminder>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Reminder lookup by title within a list.
3
+ *
4
+ * Resolves a human-friendly title to a reminder ID for operations like
5
+ * complete, delete, update, and move.
6
+ */
7
+ import { ErrorCode, RemiCommandError } from "./errors.js";
8
+ import { getReminders } from "./eventkit.js";
9
+ export async function findReminderByTitle(listName, title, opts) {
10
+ // If --id flag is provided, use that directly
11
+ if (opts?.id) {
12
+ const idPrefix = opts.id.toUpperCase();
13
+ const reminders = await getReminders({ list: listName, filter: "all" });
14
+ const match = reminders.find((r) => r.id.toUpperCase().startsWith(idPrefix));
15
+ if (!match) {
16
+ throw new RemiCommandError(ErrorCode.REMINDER_NOT_FOUND, `No reminder found with ID starting with "${opts.id}" in "${listName}"`);
17
+ }
18
+ return match;
19
+ }
20
+ // Search by title (case-insensitive exact match)
21
+ const reminders = await getReminders({ list: listName, filter: "all" });
22
+ const matches = reminders.filter((r) => r.title.toLowerCase() === title.toLowerCase());
23
+ if (matches.length === 0) {
24
+ throw new RemiCommandError(ErrorCode.REMINDER_NOT_FOUND, `No reminder titled "${title}" found in "${listName}"`, `Use "remi list '${listName}'" to see available reminders`);
25
+ }
26
+ if (matches.length > 1) {
27
+ const ids = matches.map((r) => ` ${r.id.substring(0, 8)} - "${r.title}"`).join("\n");
28
+ throw new RemiCommandError(ErrorCode.AMBIGUOUS_REMINDER, `Multiple reminders titled "${title}" found in "${listName}":\n${ids}`, "Use --id <prefix> to specify which one");
29
+ }
30
+ return matches[0];
31
+ }
32
+ //# sourceMappingURL=lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../src/core/lookup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACxC,QAAgB,EAChB,KAAa,EACb,IAAsB;IAEtB,8CAA8C;IAC9C,IAAI,IAAI,EAAE,EAAE,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,kBAAkB,EAC5B,4CAA4C,IAAI,CAAC,EAAE,SAAS,QAAQ,GAAG,CACvE,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,iDAAiD;IACjD,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAEvF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,kBAAkB,EAC5B,uBAAuB,KAAK,eAAe,QAAQ,GAAG,EACtD,mBAAmB,QAAQ,+BAA+B,CAC1D,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtF,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,kBAAkB,EAC5B,8BAA8B,KAAK,eAAe,QAAQ,OAAO,GAAG,EAAE,EACtE,wCAAwC,CACxC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC"}