@mattheworiordan/remi 0.1.0 → 0.2.1

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 (42) hide show
  1. package/README.md +101 -136
  2. package/dist/cli/commands/add.js +9 -6
  3. package/dist/cli/commands/add.js.map +1 -1
  4. package/dist/cli/commands/complete.js +4 -2
  5. package/dist/cli/commands/complete.js.map +1 -1
  6. package/dist/cli/commands/create-section.js +4 -2
  7. package/dist/cli/commands/create-section.js.map +1 -1
  8. package/dist/cli/commands/delete-list.js +4 -2
  9. package/dist/cli/commands/delete-list.js.map +1 -1
  10. package/dist/cli/commands/delete-section.js +5 -2
  11. package/dist/cli/commands/delete-section.js.map +1 -1
  12. package/dist/cli/commands/delete.js +4 -3
  13. package/dist/cli/commands/delete.js.map +1 -1
  14. package/dist/cli/commands/demo.d.ts +3 -0
  15. package/dist/cli/commands/demo.js +134 -0
  16. package/dist/cli/commands/demo.js.map +1 -0
  17. package/dist/cli/commands/list.js +48 -2
  18. package/dist/cli/commands/list.js.map +1 -1
  19. package/dist/cli/commands/move.js +6 -4
  20. package/dist/cli/commands/move.js.map +1 -1
  21. package/dist/cli/commands/sections.js +4 -2
  22. package/dist/cli/commands/sections.js.map +1 -1
  23. package/dist/cli/commands/update.js +4 -2
  24. package/dist/cli/commands/update.js.map +1 -1
  25. package/dist/cli/index.js +234 -215
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/cli/output.d.ts +2 -0
  28. package/dist/cli/output.js +33 -3
  29. package/dist/cli/output.js.map +1 -1
  30. package/dist/core/fuzzy.d.ts +16 -0
  31. package/dist/core/fuzzy.js +39 -0
  32. package/dist/core/fuzzy.js.map +1 -0
  33. package/dist/core/lookup.d.ts +1 -1
  34. package/dist/core/lookup.js +19 -9
  35. package/dist/core/lookup.js.map +1 -1
  36. package/dist/core/resolve.d.ts +13 -0
  37. package/dist/core/resolve.js +25 -0
  38. package/dist/core/resolve.js.map +1 -0
  39. package/dist/mcp/server.d.ts +23 -0
  40. package/dist/mcp/server.js +217 -0
  41. package/dist/mcp/server.js.map +1 -0
  42. package/package.json +5 -3
@@ -1,11 +1,57 @@
1
1
  import { getReminders } from "../../core/eventkit.js";
2
+ import { getMemberships } from "../../core/membership.js";
3
+ import { listSections } from "../../core/reminderkit.js";
4
+ import { resolveListName } from "../../core/resolve.js";
2
5
  import { outputReminders } from "../output.js";
3
6
  export async function listCommand(name, opts) {
7
+ const listName = await resolveListName(name);
4
8
  const filter = opts.includeCompleted ? "all" : "incomplete";
5
- const reminders = await getReminders({ list: name, filter });
6
- outputReminders(reminders, name, {
9
+ const reminders = await getReminders({ list: listName, filter });
10
+ // Try to enrich reminders with section info
11
+ try {
12
+ const [sections, memberships] = await Promise.all([
13
+ listSections(listName),
14
+ getMemberships(listName),
15
+ ]);
16
+ if (sections.length > 0) {
17
+ // Build lookup: memberID (dashed UUID) -> groupID
18
+ const memberToGroup = new Map(memberships.memberships.map((m) => [m.reminderID, m.sectionID]));
19
+ // Build groupID -> sectionName lookup from sections + memberships
20
+ const groupToSection = new Map();
21
+ // We need to map groupIDs to section names. Since we don't have
22
+ // section UUIDs from ReminderKit, use the database to match them.
23
+ // For now, use a simpler approach: query section identifiers via the DB
24
+ const { dbFindSection } = await import("../../core/reminderkit.js");
25
+ // Build the map by looking up each section's identifier
26
+ for (const section of sections) {
27
+ try {
28
+ const dbSection = await dbFindSection(section.displayName, listName);
29
+ // Convert hex identifier to dashed UUID
30
+ const hex = dbSection.identifier;
31
+ const uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
32
+ groupToSection.set(uuid, section.displayName);
33
+ }
34
+ catch {
35
+ // Skip if can't find in DB
36
+ }
37
+ }
38
+ // Assign section names to reminders
39
+ for (const r of reminders) {
40
+ const groupId = memberToGroup.get(r.id);
41
+ if (groupId) {
42
+ r.section = groupToSection.get(groupId);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ catch {
48
+ // Section enrichment failed (no FDA, no section-helper, etc.)
49
+ // Continue without section info — basic list still works
50
+ }
51
+ outputReminders(reminders, listName, {
7
52
  context: "list",
8
53
  sortByDate: true,
54
+ groupBySections: true,
9
55
  });
10
56
  }
11
57
  //# sourceMappingURL=list.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,IAAY,EACZ,IAAsD;IAEtD,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;IAC5D,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE;QAChC,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,IAAI;KAChB,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,13 @@
1
1
  import { assignToSection } from "../../core/membership.js";
2
+ import { resolveListName, resolveSectionName } from "../../core/resolve.js";
2
3
  import { outputMessage } from "../output.js";
3
4
  export async function moveCommand(list, title, opts) {
4
- const { warning } = await assignToSection(list, title, opts.toSection);
5
- let msg = `Moved "${title}" to section "${opts.toSection}" in "${list}"`;
6
- if (warning) {
5
+ const listName = await resolveListName(list);
6
+ const sectionName = await resolveSectionName(listName, opts.toSection);
7
+ const { warning } = await assignToSection(listName, title, sectionName);
8
+ let msg = `Moved "${title}" to section "${sectionName}" in "${listName}"`;
9
+ if (warning)
7
10
  msg += ` (note: ${warning})`;
8
- }
9
11
  outputMessage(msg);
10
12
  }
11
13
  //# sourceMappingURL=move.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"move.js","sourceRoot":"","sources":["../../../src/cli/commands/move.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,IAAY,EACZ,KAAa,EACb,IAA2B;IAE3B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACvE,IAAI,GAAG,GAAG,UAAU,KAAK,iBAAiB,IAAI,CAAC,SAAS,SAAS,IAAI,GAAG,CAAC;IACzE,IAAI,OAAO,EAAE,CAAC;QACb,GAAG,IAAI,WAAW,OAAO,GAAG,CAAC;IAC9B,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC"}
1
+ {"version":3,"file":"move.js","sourceRoot":"","sources":["../../../src/cli/commands/move.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,IAAY,EACZ,KAAa,EACb,IAA2B;IAE3B,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACvE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACxE,IAAI,GAAG,GAAG,UAAU,KAAK,iBAAiB,WAAW,SAAS,QAAQ,GAAG,CAAC;IAC1E,IAAI,OAAO;QAAE,GAAG,IAAI,WAAW,OAAO,GAAG,CAAC;IAC1C,aAAa,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import { listSections } from "../../core/reminderkit.js";
2
+ import { resolveListName } from "../../core/resolve.js";
2
3
  import { outputSections } from "../output.js";
3
4
  export async function sectionsCommand(list) {
4
- const sections = await listSections(list);
5
- outputSections(sections, list);
5
+ const listName = await resolveListName(list);
6
+ const sections = await listSections(listName);
7
+ outputSections(sections, listName);
6
8
  }
7
9
  //# sourceMappingURL=sections.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../src/cli/commands/sections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IACjD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../../src/cli/commands/sections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IACjD,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC9C,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACpC,CAAC"}
@@ -1,9 +1,11 @@
1
1
  import { parseDate } from "../../core/dateparse.js";
2
2
  import * as eventkit from "../../core/eventkit.js";
3
3
  import { findReminderByTitle } from "../../core/lookup.js";
4
+ import { resolveListName } from "../../core/resolve.js";
4
5
  import { outputMessage } from "../output.js";
5
6
  export async function updateCommand(list, title, opts) {
6
- const reminder = await findReminderByTitle(list, title);
7
+ const listName = await resolveListName(list);
8
+ const reminder = await findReminderByTitle(listName, title);
7
9
  await eventkit.editReminder({
8
10
  id: reminder.id,
9
11
  title: opts.title,
@@ -12,6 +14,6 @@ export async function updateCommand(list, title, opts) {
12
14
  notes: opts.notes,
13
15
  priority: opts.priority,
14
16
  });
15
- outputMessage(`Updated "${reminder.title}" in "${list}"`);
17
+ outputMessage(`Updated "${reminder.title}" in "${listName}"`);
16
18
  }
17
19
  //# sourceMappingURL=update.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,IAAY,EACZ,KAAa,EACb,IAA6F;IAE7F,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxD,MAAM,QAAQ,CAAC,YAAY,CAAC;QAC3B,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC/C,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC,CAAC;IACH,aAAa,CAAC,YAAY,QAAQ,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,IAAY,EACZ,KAAa,EACb,IAA6F;IAE7F,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5D,MAAM,QAAQ,CAAC,YAAY,CAAC;QAC3B,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC/C,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC,CAAC;IACH,aAAa,CAAC,YAAY,QAAQ,CAAC,KAAK,SAAS,QAAQ,GAAG,CAAC,CAAC;AAC/D,CAAC"}
package/dist/cli/index.js CHANGED
@@ -1,185 +1,202 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from "commander";
3
- import { RemiCommandError } from "../core/errors.js";
4
- import { outputError, setJsonMode, setVerboseMode } from "./output.js";
5
- const program = new Command();
6
- program
7
- .name("remi")
8
- .description("Fast, reliable CLI for Apple Reminders with section support and iCloud sync")
9
- .version("0.1.0")
10
- .option("--json", "Output in JSON format for machine consumption")
11
- .option("-v, --verbose", "Show additional details (notes preview, full dates)")
12
- .hook("preAction", (thisCommand) => {
13
- const opts = thisCommand.opts();
14
- if (opts.json) {
15
- setJsonMode(true);
16
- }
17
- if (opts.verbose) {
18
- setVerboseMode(true);
19
- }
20
- });
21
- // -- Daily drivers: queries --
22
- program
23
- .command("today")
24
- .description("Show reminders due today")
25
- .action(async () => {
26
- const { todayCommand } = await import("./commands/today.js");
27
- await todayCommand();
28
- });
29
- program
30
- .command("upcoming")
31
- .description("Show upcoming reminders")
32
- .option("--days <n>", "Number of days to look ahead", "7")
33
- .action(async (opts) => {
34
- const { upcomingCommand } = await import("./commands/upcoming.js");
35
- await upcomingCommand(opts);
36
- });
37
- program
38
- .command("overdue")
39
- .description("Show overdue reminders")
40
- .action(async () => {
41
- const { overdueCommand } = await import("./commands/overdue.js");
42
- await overdueCommand();
43
- });
44
- // -- Browse --
45
- program
46
- .command("list <name>")
47
- .description("Show contents of a reminder list")
48
- .option("--section <section>", "Filter by section")
49
- .option("--include-completed", "Include completed reminders")
50
- .action(async (name, opts) => {
51
- const { listCommand } = await import("./commands/list.js");
52
- await listCommand(name, opts);
53
- });
54
- program
55
- .command("lists")
56
- .alias("ls")
57
- .description("List all reminder lists")
58
- .action(async () => {
59
- const { listsCommand } = await import("./commands/lists.js");
60
- await listsCommand();
61
- });
62
- program
63
- .command("search <query>")
64
- .description("Search reminders across all lists")
65
- .action(async (query) => {
66
- const { searchCommand } = await import("./commands/search.js");
67
- await searchCommand(query);
68
- });
69
- // -- Task actions --
70
- program
71
- .command("add <list> <title>")
72
- .description("Add a reminder to a list")
73
- .option("--section <section>", "Add to a specific section")
74
- .option("--due <date>", 'Due date: YYYY-MM-DD or natural language ("tomorrow", "next friday")')
75
- .option("--priority <level>", "Priority: none, low, medium, high", "none")
76
- .option("--notes <text>", "Reminder notes")
77
- .option("--repeat <rule>", 'Recurrence: "daily", "weekly", "every 2 weeks", "every 3 months"')
78
- .action(async (list, title, opts) => {
79
- const { addCommand } = await import("./commands/add.js");
80
- await addCommand(list, title, opts);
81
- });
82
- program
83
- .command("complete <list> <title>")
84
- .alias("done")
85
- .description("Mark a reminder as complete")
86
- .option("--id <id>", "Match by reminder ID instead of title")
87
- .action(async (list, title, opts) => {
88
- const { completeCommand } = await import("./commands/complete.js");
89
- await completeCommand(list, title, opts);
90
- });
91
- program
92
- .command("update <list> <title>")
93
- .description("Update a reminder")
94
- .option("--title <newTitle>", "New title")
95
- .option("--due <date>", "New due date: YYYY-MM-DD or natural language")
96
- .option("--clear-due", "Remove due date")
97
- .option("--priority <level>", "New priority: none, low, medium, high")
98
- .option("--notes <text>", "New notes")
99
- .action(async (list, title, opts) => {
100
- const { updateCommand } = await import("./commands/update.js");
101
- await updateCommand(list, title, opts);
102
- });
103
- program
104
- .command("delete <list> <title>")
105
- .alias("rm")
106
- .description("Delete a reminder")
107
- .option("--id <id>", "Match by reminder ID instead of title")
108
- .option("--confirm", "Confirm deletion (required in interactive mode)")
109
- .action(async (list, title, opts) => {
110
- const { deleteCommand } = await import("./commands/delete.js");
111
- await deleteCommand(list, title, opts);
112
- });
113
- // -- Organization: sections and lists --
114
- program
115
- .command("sections <list>")
116
- .description("List sections in a reminder list")
117
- .action(async (list) => {
118
- const { sectionsCommand } = await import("./commands/sections.js");
119
- await sectionsCommand(list);
120
- });
121
- program
122
- .command("move <list> <title>")
123
- .description("Move a reminder to a different section")
124
- .requiredOption("--to-section <section>", "Target section name")
125
- .action(async (list, title, opts) => {
126
- const { moveCommand } = await import("./commands/move.js");
127
- await moveCommand(list, title, opts);
128
- });
129
- program
130
- .command("create-section <list> <name>")
131
- .description("Create a section in a reminder list")
132
- .action(async (list, name) => {
133
- const { createSectionCommand } = await import("./commands/create-section.js");
134
- await createSectionCommand(list, name);
135
- });
136
- program
137
- .command("delete-section <list> <name>")
138
- .description("Delete a section from a reminder list")
139
- .action(async (list, name) => {
140
- const { deleteSectionCommand } = await import("./commands/delete-section.js");
141
- await deleteSectionCommand(list, name);
142
- });
143
- program
144
- .command("create-list <name>")
145
- .description("Create a new reminder list")
146
- .action(async (name) => {
147
- const { createListCommand } = await import("./commands/create-list.js");
148
- await createListCommand(name);
149
- });
150
- program
151
- .command("delete-list <name>")
152
- .description("Delete a reminder list")
153
- .option("--confirm", "Confirm deletion (required in interactive mode)")
154
- .action(async (name, opts) => {
155
- const { deleteListCommand } = await import("./commands/delete-list.js");
156
- await deleteListCommand(name, opts);
157
- });
158
- // -- System --
159
- program
160
- .command("authorize")
161
- .description("Request Reminders access permission")
162
- .action(async () => {
163
- const { authorizeCommand } = await import("./commands/authorize.js");
164
- await authorizeCommand();
165
- });
166
- program
167
- .command("doctor")
168
- .description("Check system health and diagnostics")
169
- .option("--sync", "Verify sync status")
170
- .option("--db", "Show database location and stats")
171
- .action(async (opts) => {
172
- const { doctorCommand } = await import("./commands/doctor.js");
173
- await doctorCommand(opts);
174
- });
175
- program
176
- .command("completions")
177
- .description("Generate shell completions (bash, zsh, fish)")
178
- .argument("<shell>", "Shell type: bash, zsh, or fish")
179
- .action(async (shell) => {
180
- const commands = program.commands.map((c) => c.name()).filter((n) => n !== "completions");
181
- if (shell === "zsh") {
182
- const completions = `#compdef remi
2
+ // If --mcp flag is present, start the MCP server instead of the CLI
3
+ if (process.argv.includes("--mcp")) {
4
+ await import("../mcp/server.js");
5
+ // MCP server runs until disconnected — don't proceed to CLI
6
+ }
7
+ else {
8
+ await runCli();
9
+ }
10
+ async function runCli() {
11
+ const { Command } = await import("commander");
12
+ const { RemiCommandError } = await import("../core/errors.js");
13
+ const { outputError, setJsonMode, setVerboseMode } = await import("./output.js");
14
+ const program = new Command();
15
+ program
16
+ .name("remi")
17
+ .description("Fast, reliable CLI for Apple Reminders with section support and iCloud sync")
18
+ .version("0.1.0")
19
+ .option("--json", "Output in JSON format for machine consumption")
20
+ .option("-v, --verbose", "Show additional details (notes preview, full dates)")
21
+ .hook("preAction", (thisCommand) => {
22
+ const opts = thisCommand.opts();
23
+ if (opts.json) {
24
+ setJsonMode(true);
25
+ }
26
+ if (opts.verbose) {
27
+ setVerboseMode(true);
28
+ }
29
+ });
30
+ // -- Daily drivers: queries --
31
+ program
32
+ .command("today")
33
+ .description("Show reminders due today")
34
+ .action(async () => {
35
+ const { todayCommand } = await import("./commands/today.js");
36
+ await todayCommand();
37
+ });
38
+ program
39
+ .command("upcoming")
40
+ .description("Show upcoming reminders")
41
+ .option("--days <n>", "Number of days to look ahead", "7")
42
+ .action(async (opts) => {
43
+ const { upcomingCommand } = await import("./commands/upcoming.js");
44
+ await upcomingCommand(opts);
45
+ });
46
+ program
47
+ .command("overdue")
48
+ .description("Show overdue reminders")
49
+ .action(async () => {
50
+ const { overdueCommand } = await import("./commands/overdue.js");
51
+ await overdueCommand();
52
+ });
53
+ // -- Browse --
54
+ program
55
+ .command("list <name>")
56
+ .description("Show contents of a reminder list")
57
+ .option("--section <section>", "Filter by section")
58
+ .option("--include-completed", "Include completed reminders")
59
+ .action(async (name, opts) => {
60
+ const { listCommand } = await import("./commands/list.js");
61
+ await listCommand(name, opts);
62
+ });
63
+ program
64
+ .command("lists")
65
+ .alias("ls")
66
+ .description("List all reminder lists")
67
+ .action(async () => {
68
+ const { listsCommand } = await import("./commands/lists.js");
69
+ await listsCommand();
70
+ });
71
+ program
72
+ .command("search <query>")
73
+ .description("Search reminders across all lists")
74
+ .action(async (query) => {
75
+ const { searchCommand } = await import("./commands/search.js");
76
+ await searchCommand(query);
77
+ });
78
+ // -- Task actions --
79
+ program
80
+ .command("add <list> <title>")
81
+ .description("Add a reminder to a list")
82
+ .option("--section <section>", "Add to a specific section")
83
+ .option("--due <date>", 'Due date: YYYY-MM-DD or natural language ("tomorrow", "next friday")')
84
+ .option("--priority <level>", "Priority: none, low, medium, high", "none")
85
+ .option("--notes <text>", "Reminder notes")
86
+ .option("--repeat <rule>", 'Recurrence: "daily", "weekly", "every 2 weeks", "every 3 months"')
87
+ .action(async (list, title, opts) => {
88
+ const { addCommand } = await import("./commands/add.js");
89
+ await addCommand(list, title, opts);
90
+ });
91
+ program
92
+ .command("complete <list> <title>")
93
+ .alias("done")
94
+ .description("Mark a reminder as complete")
95
+ .option("--id <id>", "Match by reminder ID instead of title")
96
+ .action(async (list, title, opts) => {
97
+ const { completeCommand } = await import("./commands/complete.js");
98
+ await completeCommand(list, title, opts);
99
+ });
100
+ program
101
+ .command("update <list> <title>")
102
+ .description("Update a reminder")
103
+ .option("--title <newTitle>", "New title")
104
+ .option("--due <date>", "New due date: YYYY-MM-DD or natural language")
105
+ .option("--clear-due", "Remove due date")
106
+ .option("--priority <level>", "New priority: none, low, medium, high")
107
+ .option("--notes <text>", "New notes")
108
+ .action(async (list, title, opts) => {
109
+ const { updateCommand } = await import("./commands/update.js");
110
+ await updateCommand(list, title, opts);
111
+ });
112
+ program
113
+ .command("delete <list> <title>")
114
+ .alias("rm")
115
+ .description("Delete a reminder")
116
+ .option("--id <id>", "Match by reminder ID instead of title")
117
+ .option("--confirm", "Confirm deletion (required in interactive mode)")
118
+ .action(async (list, title, opts) => {
119
+ const { deleteCommand } = await import("./commands/delete.js");
120
+ await deleteCommand(list, title, opts);
121
+ });
122
+ // -- Organization: sections and lists --
123
+ program
124
+ .command("sections <list>")
125
+ .description("List sections in a reminder list")
126
+ .action(async (list) => {
127
+ const { sectionsCommand } = await import("./commands/sections.js");
128
+ await sectionsCommand(list);
129
+ });
130
+ program
131
+ .command("move <list> <title>")
132
+ .description("Move a reminder to a different section")
133
+ .requiredOption("--to-section <section>", "Target section name")
134
+ .action(async (list, title, opts) => {
135
+ const { moveCommand } = await import("./commands/move.js");
136
+ await moveCommand(list, title, opts);
137
+ });
138
+ program
139
+ .command("create-section <list> <name>")
140
+ .description("Create a section in a reminder list")
141
+ .action(async (list, name) => {
142
+ const { createSectionCommand } = await import("./commands/create-section.js");
143
+ await createSectionCommand(list, name);
144
+ });
145
+ program
146
+ .command("delete-section <list> <name>")
147
+ .description("Delete a section from a reminder list")
148
+ .action(async (list, name) => {
149
+ const { deleteSectionCommand } = await import("./commands/delete-section.js");
150
+ await deleteSectionCommand(list, name);
151
+ });
152
+ program
153
+ .command("create-list <name>")
154
+ .description("Create a new reminder list")
155
+ .action(async (name) => {
156
+ const { createListCommand } = await import("./commands/create-list.js");
157
+ await createListCommand(name);
158
+ });
159
+ program
160
+ .command("delete-list <name>")
161
+ .description("Delete a reminder list")
162
+ .option("--confirm", "Confirm deletion (required in interactive mode)")
163
+ .action(async (name, opts) => {
164
+ const { deleteListCommand } = await import("./commands/delete-list.js");
165
+ await deleteListCommand(name, opts);
166
+ });
167
+ // -- System --
168
+ program
169
+ .command("demo", { hidden: true })
170
+ .description("Create a demo list to showcase remi features")
171
+ .option("--cleanup", "Remove the demo list")
172
+ .action(async (opts) => {
173
+ const { demoCommand } = await import("./commands/demo.js");
174
+ await demoCommand(opts);
175
+ });
176
+ program
177
+ .command("authorize")
178
+ .description("Request Reminders access permission")
179
+ .action(async () => {
180
+ const { authorizeCommand } = await import("./commands/authorize.js");
181
+ await authorizeCommand();
182
+ });
183
+ program
184
+ .command("doctor")
185
+ .description("Check system health and diagnostics")
186
+ .option("--sync", "Verify sync status")
187
+ .option("--db", "Show database location and stats")
188
+ .action(async (opts) => {
189
+ const { doctorCommand } = await import("./commands/doctor.js");
190
+ await doctorCommand(opts);
191
+ });
192
+ program
193
+ .command("completions")
194
+ .description("Generate shell completions (bash, zsh, fish)")
195
+ .argument("<shell>", "Shell type: bash, zsh, or fish")
196
+ .action(async (shell) => {
197
+ const commands = program.commands.map((c) => c.name()).filter((n) => n !== "completions");
198
+ if (shell === "zsh") {
199
+ const completions = `#compdef remi
183
200
  _remi() {
184
201
  local -a commands
185
202
  commands=(
@@ -188,45 +205,47 @@ ${commands.map((c) => ` '${c}:${program.commands.find((cmd) => cmd.name() ===
188
205
  _describe 'command' commands
189
206
  }
190
207
  compdef _remi remi`;
191
- process.stdout.write(`${completions}\n`);
192
- }
193
- else if (shell === "bash") {
194
- const completions = `_remi() {
208
+ process.stdout.write(`${completions}\n`);
209
+ }
210
+ else if (shell === "bash") {
211
+ const completions = `_remi() {
195
212
  local commands="${commands.join(" ")}"
196
213
  COMPREPLY=($(compgen -W "$commands" -- "\${COMP_WORDS[COMP_CWORD]}"))
197
214
  }
198
215
  complete -F _remi remi`;
199
- process.stdout.write(`${completions}\n`);
200
- }
201
- else if (shell === "fish") {
202
- const lines = commands
203
- .map((c) => {
204
- const desc = program.commands.find((cmd) => cmd.name() === c)?.description() || "";
205
- return `complete -c remi -n '__fish_use_subcommand' -a '${c}' -d '${desc}'`;
206
- })
207
- .join("\n");
208
- process.stdout.write(`${lines}\n`);
209
- }
210
- else {
211
- process.stderr.write(`Unknown shell: ${shell}. Use: bash, zsh, or fish\n`);
212
- process.exit(1);
213
- }
214
- });
215
- // -- Error handling --
216
- async function main() {
217
- try {
218
- await program.parseAsync(process.argv);
219
- }
220
- catch (err) {
221
- if (err instanceof RemiCommandError) {
222
- outputError(err.toRemiError());
216
+ process.stdout.write(`${completions}\n`);
217
+ }
218
+ else if (shell === "fish") {
219
+ const lines = commands
220
+ .map((c) => {
221
+ const desc = program.commands.find((cmd) => cmd.name() === c)?.description() || "";
222
+ return `complete -c remi -n '__fish_use_subcommand' -a '${c}' -d '${desc}'`;
223
+ })
224
+ .join("\n");
225
+ process.stdout.write(`${lines}\n`);
226
+ }
227
+ else {
228
+ process.stderr.write(`Unknown shell: ${shell}. Use: bash, zsh, or fish\n`);
229
+ process.exit(1);
230
+ }
231
+ });
232
+ // -- Error handling --
233
+ async function main() {
234
+ try {
235
+ await program.parseAsync(process.argv);
236
+ }
237
+ catch (err) {
238
+ if (err instanceof RemiCommandError) {
239
+ outputError(err.toRemiError());
240
+ process.exit(1);
241
+ }
242
+ // Unknown error
243
+ const message = err instanceof Error ? err.message : String(err);
244
+ outputError({ code: "UNKNOWN", message });
223
245
  process.exit(1);
224
246
  }
225
- // Unknown error
226
- const message = err instanceof Error ? err.message : String(err);
227
- outputError({ code: "UNKNOWN", message });
228
- process.exit(1);
229
247
  }
230
- }
231
- main();
248
+ main();
249
+ } // end of runCli()
250
+ export {};
232
251
  //# sourceMappingURL=index.js.map