@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.
- package/LICENSE +21 -0
- package/README.md +207 -0
- package/dist/cli/commands/add.d.ts +7 -0
- package/dist/cli/commands/add.js +36 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/authorize.d.ts +1 -0
- package/dist/cli/commands/authorize.js +75 -0
- package/dist/cli/commands/authorize.js.map +1 -0
- package/dist/cli/commands/complete.d.ts +3 -0
- package/dist/cli/commands/complete.js +9 -0
- package/dist/cli/commands/complete.js.map +1 -0
- package/dist/cli/commands/create-list.d.ts +1 -0
- package/dist/cli/commands/create-list.js +7 -0
- package/dist/cli/commands/create-list.js.map +1 -0
- package/dist/cli/commands/create-section.d.ts +1 -0
- package/dist/cli/commands/create-section.js +7 -0
- package/dist/cli/commands/create-section.js.map +1 -0
- package/dist/cli/commands/delete-list.d.ts +3 -0
- package/dist/cli/commands/delete-list.js +11 -0
- package/dist/cli/commands/delete-list.js.map +1 -0
- package/dist/cli/commands/delete-section.d.ts +1 -0
- package/dist/cli/commands/delete-section.js +7 -0
- package/dist/cli/commands/delete-section.js.map +1 -0
- package/dist/cli/commands/delete.d.ts +4 -0
- package/dist/cli/commands/delete.js +14 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +4 -0
- package/dist/cli/commands/doctor.js +180 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/list.d.ts +4 -0
- package/dist/cli/commands/list.js +11 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/lists.d.ts +1 -0
- package/dist/cli/commands/lists.js +7 -0
- package/dist/cli/commands/lists.js.map +1 -0
- package/dist/cli/commands/move.d.ts +3 -0
- package/dist/cli/commands/move.js +11 -0
- package/dist/cli/commands/move.js.map +1 -0
- package/dist/cli/commands/overdue.d.ts +1 -0
- package/dist/cli/commands/overdue.js +11 -0
- package/dist/cli/commands/overdue.js.map +1 -0
- package/dist/cli/commands/search.d.ts +1 -0
- package/dist/cli/commands/search.js +11 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/sections.d.ts +1 -0
- package/dist/cli/commands/sections.js +7 -0
- package/dist/cli/commands/sections.js.map +1 -0
- package/dist/cli/commands/today.d.ts +1 -0
- package/dist/cli/commands/today.js +11 -0
- package/dist/cli/commands/today.js.map +1 -0
- package/dist/cli/commands/upcoming.d.ts +3 -0
- package/dist/cli/commands/upcoming.js +12 -0
- package/dist/cli/commands/upcoming.js.map +1 -0
- package/dist/cli/commands/update.d.ts +7 -0
- package/dist/cli/commands/update.js +17 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +232 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +26 -0
- package/dist/cli/output.js +234 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/core/checksum.d.ts +9 -0
- package/dist/core/checksum.js +13 -0
- package/dist/core/checksum.js.map +1 -0
- package/dist/core/dateparse.d.ts +7 -0
- package/dist/core/dateparse.js +27 -0
- package/dist/core/dateparse.js.map +1 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.js +34 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/eventkit.d.ts +38 -0
- package/dist/core/eventkit.js +127 -0
- package/dist/core/eventkit.js.map +1 -0
- package/dist/core/lookup.d.ts +10 -0
- package/dist/core/lookup.js +32 -0
- package/dist/core/lookup.js.map +1 -0
- package/dist/core/membership.d.ts +30 -0
- package/dist/core/membership.js +92 -0
- package/dist/core/membership.js.map +1 -0
- package/dist/core/recurrence.d.ts +14 -0
- package/dist/core/recurrence.js +90 -0
- package/dist/core/recurrence.js.map +1 -0
- package/dist/core/reminderkit.d.ts +33 -0
- package/dist/core/reminderkit.js +154 -0
- package/dist/core/reminderkit.js.map +1 -0
- package/dist/core/sqlite.d.ts +65 -0
- package/dist/core/sqlite.js +175 -0
- package/dist/core/sqlite.js.map +1 -0
- package/dist/core/tokenmap.d.ts +29 -0
- package/dist/core/tokenmap.js +52 -0
- package/dist/core/tokenmap.js.map +1 -0
- package/dist/reminders-helper +0 -0
- package/dist/section-helper +0 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
- package/src/swift/Info.plist +16 -0
- package/src/swift/build.sh +47 -0
- package/src/swift/reminders-helper.swift +697 -0
- package/src/swift/section-helper.swift +794 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section membership orchestration.
|
|
3
|
+
*
|
|
4
|
+
* All database operations are routed through the compiled section-helper binary
|
|
5
|
+
* (which has its own Info.plist for macOS permissions). The binary handles the
|
|
6
|
+
* atomic transaction internally: write data + checksum + token map in one go.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. Read current memberships via binary
|
|
10
|
+
* 2. Modify in TypeScript (add/remove entries)
|
|
11
|
+
* 3. Send updated JSON to binary for atomic write + sync trigger
|
|
12
|
+
*/
|
|
13
|
+
import type { MembershipData } from "../types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Assign a reminder to a section within its list, with iCloud sync.
|
|
16
|
+
* Idempotent: assigning to a section it's already in returns success.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assignToSection(listName: string, reminderTitle: string, sectionName: string): Promise<{
|
|
19
|
+
warning?: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Remove a reminder from its current section.
|
|
23
|
+
*/
|
|
24
|
+
export declare function removeFromSection(listName: string, reminderTitle: string): Promise<{
|
|
25
|
+
warning?: string;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Get all membership entries for a list.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getMemberships(listName: string): Promise<MembershipData>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section membership orchestration.
|
|
3
|
+
*
|
|
4
|
+
* All database operations are routed through the compiled section-helper binary
|
|
5
|
+
* (which has its own Info.plist for macOS permissions). The binary handles the
|
|
6
|
+
* atomic transaction internally: write data + checksum + token map in one go.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. Read current memberships via binary
|
|
10
|
+
* 2. Modify in TypeScript (add/remove entries)
|
|
11
|
+
* 3. Send updated JSON to binary for atomic write + sync trigger
|
|
12
|
+
*/
|
|
13
|
+
import { dbFindReminder, dbFindSection, dbReadMemberships, dbWriteMembershipSync, } from "./reminderkit.js";
|
|
14
|
+
/** Convert hex UUID (32 chars) to dashed format (8-4-4-4-12) */
|
|
15
|
+
function hexToUuid(hex) {
|
|
16
|
+
const h = hex.toUpperCase();
|
|
17
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
18
|
+
}
|
|
19
|
+
/** Core Data timestamp: seconds since 2001-01-01 00:00:00 UTC */
|
|
20
|
+
function coreDataTimestamp() {
|
|
21
|
+
return Date.now() / 1000 - 978307200;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Assign a reminder to a section within its list, with iCloud sync.
|
|
25
|
+
* Idempotent: assigning to a section it's already in returns success.
|
|
26
|
+
*/
|
|
27
|
+
export async function assignToSection(listName, reminderTitle, sectionName) {
|
|
28
|
+
const reminder = await dbFindReminder(reminderTitle, listName);
|
|
29
|
+
const section = await dbFindSection(sectionName, listName);
|
|
30
|
+
const memberUuid = hexToUuid(reminder.identifier);
|
|
31
|
+
const sectionUuid = hexToUuid(section.identifier);
|
|
32
|
+
const timestamp = coreDataTimestamp();
|
|
33
|
+
// Read current membership data
|
|
34
|
+
const currentData = await dbReadMemberships(listName);
|
|
35
|
+
let membership;
|
|
36
|
+
if (currentData && currentData.trim() !== "") {
|
|
37
|
+
membership = JSON.parse(currentData);
|
|
38
|
+
// Idempotent: already assigned to this section
|
|
39
|
+
const existing = membership.memberships.find((m) => m.memberID === memberUuid && m.groupID === sectionUuid);
|
|
40
|
+
if (existing)
|
|
41
|
+
return {};
|
|
42
|
+
// Remove any existing assignment (move semantics)
|
|
43
|
+
membership.memberships = membership.memberships.filter((m) => m.memberID !== memberUuid);
|
|
44
|
+
membership.memberships.push({
|
|
45
|
+
memberID: memberUuid,
|
|
46
|
+
groupID: sectionUuid,
|
|
47
|
+
modifiedOn: timestamp,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
membership = {
|
|
52
|
+
minimumSupportedVersion: 20230430,
|
|
53
|
+
memberships: [{ memberID: memberUuid, groupID: sectionUuid, modifiedOn: timestamp }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Atomic write + sync via compiled binary
|
|
57
|
+
const warning = await dbWriteMembershipSync(listName, JSON.stringify(membership));
|
|
58
|
+
return { warning };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Remove a reminder from its current section.
|
|
62
|
+
*/
|
|
63
|
+
export async function removeFromSection(listName, reminderTitle) {
|
|
64
|
+
const reminder = await dbFindReminder(reminderTitle, listName);
|
|
65
|
+
const memberUuid = hexToUuid(reminder.identifier);
|
|
66
|
+
const currentData = await dbReadMemberships(listName);
|
|
67
|
+
if (!currentData || currentData.trim() === "")
|
|
68
|
+
return {};
|
|
69
|
+
const membership = JSON.parse(currentData);
|
|
70
|
+
const originalLength = membership.memberships.length;
|
|
71
|
+
membership.memberships = membership.memberships.filter((m) => m.memberID !== memberUuid);
|
|
72
|
+
if (membership.memberships.length === originalLength)
|
|
73
|
+
return {};
|
|
74
|
+
const warning = await dbWriteMembershipSync(listName, JSON.stringify(membership));
|
|
75
|
+
return { warning };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get all membership entries for a list.
|
|
79
|
+
*/
|
|
80
|
+
export async function getMemberships(listName) {
|
|
81
|
+
const data = await dbReadMemberships(listName);
|
|
82
|
+
if (!data || data.trim() === "")
|
|
83
|
+
return { memberships: [] };
|
|
84
|
+
const blob = JSON.parse(data);
|
|
85
|
+
return {
|
|
86
|
+
memberships: blob.memberships.map((m) => ({
|
|
87
|
+
reminderID: m.memberID,
|
|
88
|
+
sectionID: m.groupID,
|
|
89
|
+
})),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=membership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"membership.js","sourceRoot":"","sources":["../../src/core/membership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse human-friendly --repeat strings into EKRecurrenceRule parameters.
|
|
3
|
+
*
|
|
4
|
+
* Supported formats:
|
|
5
|
+
* "daily", "weekly", "monthly", "yearly"
|
|
6
|
+
* "every 2 weeks", "every 3 months"
|
|
7
|
+
* "every 2 weeks on monday,friday"
|
|
8
|
+
*/
|
|
9
|
+
export interface RecurrenceParams {
|
|
10
|
+
rruleFreq: string;
|
|
11
|
+
rruleInterval: number;
|
|
12
|
+
rruleDays?: number[];
|
|
13
|
+
}
|
|
14
|
+
export declare function parseRepeat(input: string): RecurrenceParams;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse human-friendly --repeat strings into EKRecurrenceRule parameters.
|
|
3
|
+
*
|
|
4
|
+
* Supported formats:
|
|
5
|
+
* "daily", "weekly", "monthly", "yearly"
|
|
6
|
+
* "every 2 weeks", "every 3 months"
|
|
7
|
+
* "every 2 weeks on monday,friday"
|
|
8
|
+
*/
|
|
9
|
+
import { ErrorCode, RemiCommandError } from "./errors.js";
|
|
10
|
+
const DAY_MAP = {
|
|
11
|
+
sunday: 1,
|
|
12
|
+
sun: 1,
|
|
13
|
+
monday: 2,
|
|
14
|
+
mon: 2,
|
|
15
|
+
tuesday: 3,
|
|
16
|
+
tue: 3,
|
|
17
|
+
wednesday: 4,
|
|
18
|
+
wed: 4,
|
|
19
|
+
thursday: 5,
|
|
20
|
+
thu: 5,
|
|
21
|
+
friday: 6,
|
|
22
|
+
fri: 6,
|
|
23
|
+
saturday: 7,
|
|
24
|
+
sat: 7,
|
|
25
|
+
};
|
|
26
|
+
const FREQ_ALIASES = {
|
|
27
|
+
daily: "DAILY",
|
|
28
|
+
weekly: "WEEKLY",
|
|
29
|
+
monthly: "MONTHLY",
|
|
30
|
+
yearly: "YEARLY",
|
|
31
|
+
day: "DAILY",
|
|
32
|
+
days: "DAILY",
|
|
33
|
+
week: "WEEKLY",
|
|
34
|
+
weeks: "WEEKLY",
|
|
35
|
+
month: "MONTHLY",
|
|
36
|
+
months: "MONTHLY",
|
|
37
|
+
year: "YEARLY",
|
|
38
|
+
years: "YEARLY",
|
|
39
|
+
};
|
|
40
|
+
export function parseRepeat(input) {
|
|
41
|
+
const s = input.trim().toLowerCase();
|
|
42
|
+
// Simple: "daily", "weekly", "monthly", "yearly"
|
|
43
|
+
if (FREQ_ALIASES[s]) {
|
|
44
|
+
return { rruleFreq: FREQ_ALIASES[s], rruleInterval: 1 };
|
|
45
|
+
}
|
|
46
|
+
// "every N <unit>" with optional "on <days>"
|
|
47
|
+
const match = s.match(/^every\s+(\d+)\s+(\w+?)(?:\s+on\s+(.+))?$/);
|
|
48
|
+
if (match) {
|
|
49
|
+
const interval = Number.parseInt(match[1], 10);
|
|
50
|
+
const unit = match[2];
|
|
51
|
+
const freq = FREQ_ALIASES[unit];
|
|
52
|
+
if (!freq) {
|
|
53
|
+
throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, `Unknown frequency unit "${unit}"`, "Use: day(s), week(s), month(s), year(s)");
|
|
54
|
+
}
|
|
55
|
+
const result = { rruleFreq: freq, rruleInterval: interval };
|
|
56
|
+
if (match[3]) {
|
|
57
|
+
result.rruleDays = parseDays(match[3]);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
// "every <unit>" (no number = interval 1)
|
|
62
|
+
const simpleEvery = s.match(/^every\s+(\w+?)(?:\s+on\s+(.+))?$/);
|
|
63
|
+
if (simpleEvery) {
|
|
64
|
+
const unit = simpleEvery[1];
|
|
65
|
+
const freq = FREQ_ALIASES[unit];
|
|
66
|
+
if (freq) {
|
|
67
|
+
const result = { rruleFreq: freq, rruleInterval: 1 };
|
|
68
|
+
if (simpleEvery[2]) {
|
|
69
|
+
result.rruleDays = parseDays(simpleEvery[2]);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, `Cannot parse repeat rule "${input}"`, 'Examples: "daily", "weekly", "every 2 weeks", "every 3 months"');
|
|
75
|
+
}
|
|
76
|
+
function parseDays(input) {
|
|
77
|
+
const days = input.split(/[,\s]+/).map((d) => d.trim().toLowerCase());
|
|
78
|
+
const result = [];
|
|
79
|
+
for (const day of days) {
|
|
80
|
+
if (!day)
|
|
81
|
+
continue;
|
|
82
|
+
const num = DAY_MAP[day];
|
|
83
|
+
if (!num) {
|
|
84
|
+
throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, `Unknown day "${day}"`, "Use: monday, tuesday, wednesday, thursday, friday, saturday, sunday (or mon, tue, etc.)");
|
|
85
|
+
}
|
|
86
|
+
result.push(num);
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=recurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.js","sourceRoot":"","sources":["../../src/core/recurrence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQ1D,MAAM,OAAO,GAA2B;IACvC,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,OAAO,EAAE,CAAC;IACV,GAAG,EAAE,CAAC;IACN,SAAS,EAAE,CAAC;IACZ,GAAG,EAAE,CAAC;IACN,QAAQ,EAAE,CAAC;IACX,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,QAAQ,EAAE,CAAC;IACX,GAAG,EAAE,CAAC;CACN,CAAC;AAEF,MAAM,YAAY,GAA2B;IAC5C,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,OAAO;IACZ,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;CACf,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,KAAa;IACxC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,iDAAiD;IACjD,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,6CAA6C;IAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACnE,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,2BAA2B,IAAI,GAAG,EAClC,yCAAyC,CACzC,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAqB,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;QAE9E,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAED,0CAA0C;IAC1C,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACjE,IAAI,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACV,MAAM,MAAM,GAAqB,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;YACvE,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;IACF,CAAC;IAED,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,6BAA6B,KAAK,GAAG,EACrC,gEAAgE,CAChE,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,EAAE,CAAC;YACV,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,gBAAgB,GAAG,GAAG,EACtB,yFAAyF,CACzF,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReminderKit bridge — executes the compiled section-helper binary
|
|
3
|
+
* for section CRUD, sync trigger, and database operations.
|
|
4
|
+
*
|
|
5
|
+
* Permissions note: macOS TCC always attributes permissions to the
|
|
6
|
+
* "responsible process" (the terminal app), not the child binary.
|
|
7
|
+
* The embedded Info.plist provides NSRemindersUsageDescription for
|
|
8
|
+
* the permission dialog text, but the grant goes to the terminal.
|
|
9
|
+
*/
|
|
10
|
+
import type { Section } from "../types.js";
|
|
11
|
+
export declare function listSections(listName: string): Promise<Section[]>;
|
|
12
|
+
export declare function createSection(listName: string, sectionName: string): Promise<string>;
|
|
13
|
+
export declare function deleteSection(listName: string, sectionName: string): Promise<string>;
|
|
14
|
+
export declare function triggerSync(listName: string): Promise<string | undefined>;
|
|
15
|
+
export declare function dbFindDb(): Promise<string>;
|
|
16
|
+
export declare function dbStats(): Promise<{
|
|
17
|
+
dbPath: string;
|
|
18
|
+
lists: number;
|
|
19
|
+
sections: number;
|
|
20
|
+
reminders: number;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function dbFindList(listName: string): Promise<number>;
|
|
23
|
+
export declare function dbFindReminder(title: string, listName: string): Promise<{
|
|
24
|
+
pk: number;
|
|
25
|
+
identifier: string;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function dbFindSection(sectionName: string, listName: string): Promise<{
|
|
28
|
+
pk: number;
|
|
29
|
+
identifier: string;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function dbReadMemberships(listName: string): Promise<string | null>;
|
|
32
|
+
export declare function dbReadTokenMap(listName: string): Promise<string | null>;
|
|
33
|
+
export declare function dbWriteMembershipSync(listName: string, membershipJSON: string): Promise<string | undefined>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReminderKit bridge — executes the compiled section-helper binary
|
|
3
|
+
* for section CRUD, sync trigger, and database operations.
|
|
4
|
+
*
|
|
5
|
+
* Permissions note: macOS TCC always attributes permissions to the
|
|
6
|
+
* "responsible process" (the terminal app), not the child binary.
|
|
7
|
+
* The embedded Info.plist provides NSRemindersUsageDescription for
|
|
8
|
+
* the permission dialog text, but the grant goes to the terminal.
|
|
9
|
+
*/
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { promisify } from "node:util";
|
|
15
|
+
import { ErrorCode, RemiCommandError } from "./errors.js";
|
|
16
|
+
const execFileAsync = promisify(execFile);
|
|
17
|
+
const TIMEOUT_MS = 30000;
|
|
18
|
+
function findSectionHelper() {
|
|
19
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const candidates = [
|
|
21
|
+
join(currentDir, "../section-helper"), // From dist/core/ -> dist/section-helper
|
|
22
|
+
join(currentDir, "../../dist/section-helper"), // From src/core/ -> dist/section-helper
|
|
23
|
+
];
|
|
24
|
+
for (const p of candidates) {
|
|
25
|
+
if (existsSync(p))
|
|
26
|
+
return p;
|
|
27
|
+
}
|
|
28
|
+
throw new RemiCommandError(ErrorCode.REMINDERKIT_UNAVAILABLE, "section-helper binary not found", "Run: npm run build:swift");
|
|
29
|
+
}
|
|
30
|
+
async function runSectionHelper(command, ...args) {
|
|
31
|
+
const binaryPath = findSectionHelper();
|
|
32
|
+
const cmdArgs = [command, ...args];
|
|
33
|
+
try {
|
|
34
|
+
const { stdout } = await execFileAsync(binaryPath, cmdArgs, {
|
|
35
|
+
timeout: TIMEOUT_MS,
|
|
36
|
+
env: { ...process.env },
|
|
37
|
+
});
|
|
38
|
+
return JSON.parse(stdout.trim());
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const err = error;
|
|
42
|
+
if (err.stdout) {
|
|
43
|
+
try {
|
|
44
|
+
const result = JSON.parse(err.stdout.trim());
|
|
45
|
+
if (result.error) {
|
|
46
|
+
throw new RemiCommandError(ErrorCode.REMINDERKIT_UNAVAILABLE, result.error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (parseErr) {
|
|
50
|
+
if (parseErr instanceof RemiCommandError)
|
|
51
|
+
throw parseErr;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw new RemiCommandError(ErrorCode.REMINDERKIT_UNAVAILABLE, `Section helper failed: ${err.stderr || err.message}`, "Ensure macOS 13+ and Xcode Command Line Tools are installed");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function listSections(listName) {
|
|
58
|
+
const result = await runSectionHelper("list-sections", listName);
|
|
59
|
+
if (!result.success) {
|
|
60
|
+
throw new RemiCommandError(ErrorCode.LIST_NOT_FOUND, result.error || `Failed to list sections for "${listName}"`);
|
|
61
|
+
}
|
|
62
|
+
return (result.sections || []).map((s, i) => ({
|
|
63
|
+
id: s.objectID,
|
|
64
|
+
displayName: s.name,
|
|
65
|
+
listName,
|
|
66
|
+
sortOrder: i,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
export async function createSection(listName, sectionName) {
|
|
70
|
+
const result = await runSectionHelper("create-section", listName, sectionName);
|
|
71
|
+
if (!result.success) {
|
|
72
|
+
throw new RemiCommandError(ErrorCode.REMINDERKIT_UNAVAILABLE, result.error || `Failed to create section "${sectionName}"`);
|
|
73
|
+
}
|
|
74
|
+
return result.message || "OK";
|
|
75
|
+
}
|
|
76
|
+
export async function deleteSection(listName, sectionName) {
|
|
77
|
+
const result = await runSectionHelper("delete-section", listName, sectionName);
|
|
78
|
+
if (!result.success) {
|
|
79
|
+
throw new RemiCommandError(ErrorCode.SECTION_NOT_FOUND, result.error || `Failed to delete section "${sectionName}"`);
|
|
80
|
+
}
|
|
81
|
+
return result.message || "OK";
|
|
82
|
+
}
|
|
83
|
+
export async function triggerSync(listName) {
|
|
84
|
+
const result = await runSectionHelper("trigger-sync", listName);
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
return result.error || "Sync trigger failed";
|
|
87
|
+
}
|
|
88
|
+
return result.warning;
|
|
89
|
+
}
|
|
90
|
+
async function runDbCommand(command, ...args) {
|
|
91
|
+
return runSectionHelper(command, ...args);
|
|
92
|
+
}
|
|
93
|
+
export async function dbFindDb() {
|
|
94
|
+
const result = await runDbCommand("db-find-db");
|
|
95
|
+
if (!result.success) {
|
|
96
|
+
throw new RemiCommandError(ErrorCode.DB_NOT_FOUND, result.error || "Database not found");
|
|
97
|
+
}
|
|
98
|
+
return result.dbPath;
|
|
99
|
+
}
|
|
100
|
+
export async function dbStats() {
|
|
101
|
+
const result = await runDbCommand("db-stats");
|
|
102
|
+
if (!result.success) {
|
|
103
|
+
throw new RemiCommandError(ErrorCode.DB_NOT_FOUND, result.error || "Database not found");
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
dbPath: result.dbPath,
|
|
107
|
+
lists: result.lists,
|
|
108
|
+
sections: result.sections,
|
|
109
|
+
reminders: result.reminders,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export async function dbFindList(listName) {
|
|
113
|
+
const result = await runDbCommand("db-find-list", listName);
|
|
114
|
+
if (!result.success) {
|
|
115
|
+
throw new RemiCommandError(ErrorCode.LIST_NOT_FOUND, result.error || `List "${listName}" not found`);
|
|
116
|
+
}
|
|
117
|
+
return result.pk;
|
|
118
|
+
}
|
|
119
|
+
export async function dbFindReminder(title, listName) {
|
|
120
|
+
const result = await runDbCommand("db-find-reminder", title, listName);
|
|
121
|
+
if (!result.success) {
|
|
122
|
+
throw new RemiCommandError(ErrorCode.REMINDER_NOT_FOUND, result.error || `Reminder "${title}" not found`);
|
|
123
|
+
}
|
|
124
|
+
return { pk: result.pk, identifier: result.identifier };
|
|
125
|
+
}
|
|
126
|
+
export async function dbFindSection(sectionName, listName) {
|
|
127
|
+
const result = await runDbCommand("db-find-section", sectionName, listName);
|
|
128
|
+
if (!result.success) {
|
|
129
|
+
throw new RemiCommandError(ErrorCode.SECTION_NOT_FOUND, result.error || `Section "${sectionName}" not found`);
|
|
130
|
+
}
|
|
131
|
+
return { pk: result.pk, identifier: result.identifier };
|
|
132
|
+
}
|
|
133
|
+
export async function dbReadMemberships(listName) {
|
|
134
|
+
const result = await runDbCommand("db-read-memberships", listName);
|
|
135
|
+
if (!result.success) {
|
|
136
|
+
throw new RemiCommandError(ErrorCode.DB_NOT_FOUND, result.error || "Failed to read memberships");
|
|
137
|
+
}
|
|
138
|
+
return result.data ?? null;
|
|
139
|
+
}
|
|
140
|
+
export async function dbReadTokenMap(listName) {
|
|
141
|
+
const result = await runDbCommand("db-read-tokenmap", listName);
|
|
142
|
+
if (!result.success) {
|
|
143
|
+
throw new RemiCommandError(ErrorCode.DB_NOT_FOUND, result.error || "Failed to read token map");
|
|
144
|
+
}
|
|
145
|
+
return result.data ?? null;
|
|
146
|
+
}
|
|
147
|
+
export async function dbWriteMembershipSync(listName, membershipJSON) {
|
|
148
|
+
const result = await runDbCommand("db-write-membership-sync", listName, membershipJSON);
|
|
149
|
+
if (!result.success) {
|
|
150
|
+
throw new RemiCommandError(ErrorCode.SYNC_TRIGGER_FAILED, result.error || "Membership sync failed");
|
|
151
|
+
}
|
|
152
|
+
return result.warning;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=reminderkit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminderkit.js","sourceRoot":"","sources":["../../src/core/reminderkit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite access for Apple Reminders database.
|
|
3
|
+
*
|
|
4
|
+
* Uses better-sqlite3 for proper transactions and prepared statements.
|
|
5
|
+
* This is a key improvement over the predecessor which shelled out to /usr/bin/sqlite3
|
|
6
|
+
* for each statement, making the 3-step membership write non-atomic.
|
|
7
|
+
*/
|
|
8
|
+
import Database from "better-sqlite3";
|
|
9
|
+
/**
|
|
10
|
+
* Find the active Apple Reminders SQLite database.
|
|
11
|
+
* Scans all .sqlite files and returns the one with actual reminder data.
|
|
12
|
+
*/
|
|
13
|
+
export declare function findRemindersDbPath(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get a database connection. Caches the connection for reuse.
|
|
16
|
+
* Uses WAL mode and busy_timeout for safe concurrent access with remindd.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getDb(): Database.Database;
|
|
19
|
+
/**
|
|
20
|
+
* Close the cached database connection.
|
|
21
|
+
*/
|
|
22
|
+
export declare function closeDb(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Find a list's Z_PK by name.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findListPk(listName: string): number;
|
|
27
|
+
/**
|
|
28
|
+
* Find a reminder's identifier (hex UUID) by title and list name.
|
|
29
|
+
*/
|
|
30
|
+
export declare function findReminderIdentifier(title: string, listName: string): {
|
|
31
|
+
pk: number;
|
|
32
|
+
identifier: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Find a section's identifier (hex UUID) by name and list.
|
|
36
|
+
*/
|
|
37
|
+
export declare function findSectionIdentifier(sectionName: string, listName: string): {
|
|
38
|
+
pk: number;
|
|
39
|
+
identifier: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Read the current membership data JSON from a list.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readMembershipData(listPk: number): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Read the resolution token map JSON from a list.
|
|
47
|
+
* The token map may be stored as a BLOB or TEXT — handle both.
|
|
48
|
+
*/
|
|
49
|
+
export declare function readTokenMap(listPk: number): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Write membership data, checksum, and token map in a SINGLE ATOMIC TRANSACTION.
|
|
52
|
+
*
|
|
53
|
+
* This is the key improvement over the predecessor which used separate sqlite3 process
|
|
54
|
+
* calls for each statement. A partial write (data updated but checksum not) would cause
|
|
55
|
+
* remindd to detect data corruption.
|
|
56
|
+
*/
|
|
57
|
+
export declare function writeMembershipSync(listPk: number, membershipJson: string, checksumHex: string, tokenMapJson: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Convert a hex blob string (32 chars, no hyphens) to standard UUID format.
|
|
60
|
+
*/
|
|
61
|
+
export declare function hexToUuid(hex: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Convert a JS Date to Core Data timestamp (seconds since 2001-01-01 00:00:00 UTC).
|
|
64
|
+
*/
|
|
65
|
+
export declare function coreDataTimestamp(date?: Date): number;
|