@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthew O'Riordan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # remi
2
+
3
+ **The missing CLI for Apple Reminders — with section support and iCloud sync.**
4
+
5
+ remi is the only Apple Reminders CLI that supports **sections** (the organizational unit Apple added in macOS 13) with full **iCloud sync**. Create lists, add reminders, organize them into sections, and have everything sync across all your Apple devices.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ # Homebrew (recommended)
11
+ brew tap mattheworiordan/remi
12
+ brew install remi
13
+
14
+ # npm
15
+ npm install -g @mattheworiordan/remi
16
+
17
+ # Or run without installing
18
+ npx @mattheworiordan/remi lists
19
+ ```
20
+
21
+ ## Quick start
22
+
23
+ ```bash
24
+ # See all your lists
25
+ remi lists
26
+
27
+ # View reminders in a list
28
+ remi list "Groceries"
29
+
30
+ # Add a reminder
31
+ remi add "Groceries" "Buy milk"
32
+
33
+ # Add with section, due date, and priority
34
+ remi add "Groceries" "Fresh basil" --section "Produce" --due "next tuesday" --priority high
35
+
36
+ # Add a recurring reminder
37
+ remi add "Dogs" "Flea treatment" --due 2026-04-28 --repeat monthly
38
+
39
+ # What's due today?
40
+ remi today
41
+
42
+ # What's overdue?
43
+ remi overdue
44
+ ```
45
+
46
+ ## Commands
47
+
48
+ ### Queries — what's due?
49
+
50
+ ```bash
51
+ remi today # Due today
52
+ remi overdue # Past due
53
+ remi upcoming --days 7 # Due in the next 7 days
54
+ ```
55
+
56
+ ### Browse
57
+
58
+ ```bash
59
+ remi list "Groceries" # Show reminders in a list
60
+ remi list "Groceries" --include-completed
61
+ remi lists # List all reminder lists
62
+ remi search "milk" # Search across all lists
63
+ ```
64
+
65
+ ### Task actions
66
+
67
+ ```bash
68
+ remi add "Work" "Review report" --due "next friday" --priority high --notes "Q1 numbers"
69
+ remi add "Work" "Team standup" --due tomorrow --repeat daily
70
+ remi add "Work" "Sprint review" --repeat "every 2 weeks"
71
+ remi complete "Work" "Review report"
72
+ remi update "Work" "Review report" --due "in 3 days"
73
+ remi delete "Work" "Review report" --confirm
74
+ ```
75
+
76
+ Dates accept YYYY-MM-DD or natural language: `tomorrow`, `next tuesday`, `in 3 days`.
77
+
78
+ Recurrence supports: `daily`, `weekly`, `monthly`, `yearly`, `every N days/weeks/months`, `every 2 weeks on monday,friday`.
79
+
80
+ ### Sections
81
+
82
+ This is what makes remi unique. No other CLI supports Apple Reminders sections with iCloud sync.
83
+
84
+ ```bash
85
+ remi sections "Groceries" # List sections
86
+ remi move "Groceries" "Bananas" --to-section "Dairy" # Move between sections
87
+ remi create-section "Groceries" "Produce" # Create a section
88
+ remi add "Groceries" "Bananas" --section "Produce" # Add to a section
89
+ remi delete-section "Groceries" "Produce" # Delete a section
90
+ ```
91
+
92
+ Sections sync to iCloud via resolution token maps (CRDT-style vector clocks). See the [technical design](docs/TECHNICAL_DESIGN.md) for details.
93
+
94
+ ### List management
95
+
96
+ ```bash
97
+ remi create-list "Home Projects"
98
+ remi delete-list "Home Projects" --confirm
99
+ ```
100
+
101
+ ### System
102
+
103
+ ```bash
104
+ remi doctor # Check system health
105
+ remi doctor --db # Show database stats
106
+ ```
107
+
108
+ ### Shell completions
109
+
110
+ Homebrew installs completions automatically. For manual setup:
111
+
112
+ ```bash
113
+ # zsh (uses Homebrew's completions dir if available, otherwise system dir)
114
+ remi completions zsh > $(brew --prefix 2>/dev/null || echo /usr/local)/share/zsh/site-functions/_remi
115
+
116
+ # bash
117
+ remi completions bash > /usr/local/etc/bash_completion.d/remi
118
+
119
+ # fish
120
+ remi completions fish > ~/.config/fish/completions/remi.fish
121
+ ```
122
+
123
+ ## JSON output
124
+
125
+ Every command supports `--json` for machine-readable output:
126
+
127
+ ```bash
128
+ remi lists --json
129
+ remi today --json
130
+ remi add "Work" "Task" --json
131
+ ```
132
+
133
+ Returns `{"success": true, "data": ...}` on success or `{"success": false, "error": {"code": "...", "message": "...", "suggestion": "..."}}` on failure.
134
+
135
+ ## AI agent integration
136
+
137
+ remi is designed for AI agents. Install as a [Claude Code plugin](https://github.com/mattheworiordan/remi):
138
+
139
+ ```bash
140
+ claude plugin marketplace add mattheworiordan/remi
141
+ claude plugin install remi
142
+ ```
143
+
144
+ Or use as a [skill](https://skills.sh):
145
+
146
+ ```bash
147
+ npx skills add mattheworiordan/remi
148
+ ```
149
+
150
+ Then agents can manage reminders via `/remi` or by using the CLI directly with `--json`.
151
+
152
+ ## Permissions
153
+
154
+ macOS grants permissions to your **terminal app** (Terminal, iTerm, Cursor, VS Code, etc.), not to remi directly. You only need to do this once per terminal app.
155
+
156
+ ```bash
157
+ remi authorize # Guides you through granting permissions
158
+ remi doctor # Shows what's granted and what's missing
159
+ ```
160
+
161
+ | Permission | What it enables | How to grant |
162
+ |------------|----------------|--------------|
163
+ | **Reminders access** | All reminder operations | System dialog on first run — click Allow |
164
+ | **Full Disk Access** | Section features (create-section, move, etc.) | System Settings > Privacy & Security > Full Disk Access — add your terminal app |
165
+
166
+ Most developer terminals (iTerm, Ghostty, VS Code) already have Full Disk Access. If you only need basic reminder operations (no sections), Reminders access alone is sufficient.
167
+
168
+ ## How it works
169
+
170
+ remi uses a three-layer architecture to interact with Apple Reminders:
171
+
172
+ | Layer | API | Used for |
173
+ |-------|-----|----------|
174
+ | 1 | **EventKit** (public) | Standard CRUD — lists, reminders, queries |
175
+ | 2 | **ReminderKit** (private framework) | Section CRUD — create, list, delete sections |
176
+ | 3 | **SQLite + Resolution Token Maps** | Section membership sync via CRDT vector clocks |
177
+
178
+ The key innovation is Layer 3: directly writing to the Reminders SQLite database with proper resolution token map updates so that `remindd` (Apple's sync daemon) pushes section membership changes to CloudKit. This is the only known way to assign reminders to sections and have it sync across devices.
179
+
180
+ See [docs/TECHNICAL_DESIGN.md](docs/TECHNICAL_DESIGN.md) for the full reverse-engineering story.
181
+
182
+ ## Requirements
183
+
184
+ - macOS 13+ (Ventura or later)
185
+ - Node.js 18+
186
+ - Xcode Command Line Tools (`xcode-select --install`)
187
+ - Apple Reminders access (granted on first use)
188
+
189
+ ## Development
190
+
191
+ ```bash
192
+ git clone https://github.com/mattheworiordan/remi.git
193
+ cd remi
194
+ npm install
195
+ npm run build:swift # Compile the section-helper binary
196
+ npm run build # Compile TypeScript
197
+ npm run dev -- lists # Run in dev mode
198
+ npm test # Run unit tests
199
+ ```
200
+
201
+ ## License
202
+
203
+ MIT
204
+
205
+ ## Author
206
+
207
+ [Matthew O'Riordan](https://github.com/mattheworiordan)
@@ -0,0 +1,7 @@
1
+ export declare function addCommand(list: string, title: string, opts: {
2
+ section?: string;
3
+ due?: string;
4
+ priority?: string;
5
+ notes?: string;
6
+ repeat?: string;
7
+ }): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { parseDate } from "../../core/dateparse.js";
2
+ import { createReminder } from "../../core/eventkit.js";
3
+ import { assignToSection } from "../../core/membership.js";
4
+ import { parseRepeat } from "../../core/recurrence.js";
5
+ import { outputMessage } from "../output.js";
6
+ export async function addCommand(list, title, opts) {
7
+ const createOpts = {
8
+ title,
9
+ listName: list,
10
+ due: opts.due ? parseDate(opts.due) : undefined,
11
+ priority: opts.priority,
12
+ notes: opts.notes,
13
+ };
14
+ if (opts.repeat) {
15
+ const rec = parseRepeat(opts.repeat);
16
+ createOpts.rruleFreq = rec.rruleFreq;
17
+ createOpts.rruleInterval = rec.rruleInterval;
18
+ if (rec.rruleDays)
19
+ createOpts.rruleDays = rec.rruleDays;
20
+ }
21
+ const id = await createReminder(createOpts);
22
+ let warning;
23
+ if (opts.section) {
24
+ const result = await assignToSection(list, title, opts.section);
25
+ warning = result.warning;
26
+ }
27
+ let msg = `Added "${title}" to "${list}"`;
28
+ if (opts.repeat)
29
+ msg += ` (repeats ${opts.repeat})`;
30
+ if (opts.section)
31
+ msg += ` in section "${opts.section}"`;
32
+ if (warning)
33
+ msg += ` (note: ${warning})`;
34
+ outputMessage(msg, { id });
35
+ }
36
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,IAAY,EACZ,KAAa,EACb,IAMC;IAED,MAAM,UAAU,GAAyC;QACxD,KAAK;QACL,QAAQ,EAAE,IAAI;QACd,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;KACjB,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,UAAU,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QACrC,UAAU,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;QAC7C,IAAI,GAAG,CAAC,SAAS;YAAE,UAAU,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;IACzD,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IAE5C,IAAI,OAA2B,CAAC;IAChC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAChE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC1B,CAAC;IAED,IAAI,GAAG,GAAG,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC;IAC1C,IAAI,IAAI,CAAC,MAAM;QAAE,GAAG,IAAI,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC;IACpD,IAAI,IAAI,CAAC,OAAO;QAAE,GAAG,IAAI,gBAAgB,IAAI,CAAC,OAAO,GAAG,CAAC;IACzD,IAAI,OAAO;QAAE,GAAG,IAAI,WAAW,OAAO,GAAG,CAAC;IAC1C,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function authorizeCommand(): Promise<void>;
@@ -0,0 +1,75 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import chalk from "chalk";
4
+ import { listLists } from "../../core/eventkit.js";
5
+ import { dbFindDb } from "../../core/reminderkit.js";
6
+ import { isJsonMode } from "../output.js";
7
+ const execFileAsync = promisify(execFile);
8
+ function out(text) {
9
+ if (!isJsonMode())
10
+ process.stdout.write(text);
11
+ }
12
+ export async function authorizeCommand() {
13
+ out(chalk.bold("\nremi authorize\n"));
14
+ out(`${"─".repeat(20)}\n\n`);
15
+ out(chalk.dim("macOS grants permissions to your terminal app (Terminal, iTerm, Cursor, etc.),\nnot to remi directly. You only need to do this once per terminal app.\n"));
16
+ // Step 1: Reminders access
17
+ out("\n1. Checking Reminders access...\n");
18
+ out(chalk.dim(" If a system dialog appears, click Allow.\n"));
19
+ let remindersOk = false;
20
+ try {
21
+ const lists = await listLists();
22
+ const count = Array.isArray(lists) ? lists.length : 0;
23
+ if (count > 0) {
24
+ out(` ${chalk.green("✓")} Reminders access granted (${count} list${count === 1 ? "" : "s"} found)\n`);
25
+ remindersOk = true;
26
+ }
27
+ else {
28
+ out(chalk.yellow(" ✗ Reminders access appears denied (0 lists returned)\n"));
29
+ out(" Opening System Settings — enable your terminal app under Reminders.\n");
30
+ try {
31
+ await execFileAsync("open", [
32
+ "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders",
33
+ ]);
34
+ }
35
+ catch {
36
+ out(chalk.dim(" Go to: System Settings > Privacy & Security > Reminders\n"));
37
+ }
38
+ out(chalk.dim(" After enabling, restart your terminal and run remi authorize again.\n"));
39
+ }
40
+ }
41
+ catch {
42
+ out(chalk.yellow(" ✗ Reminders access not granted.\n"));
43
+ out(" Opening System Settings — enable your terminal app under Reminders.\n");
44
+ try {
45
+ await execFileAsync("open", [
46
+ "x-apple.systempreferences:com.apple.preference.security?Privacy_Reminders",
47
+ ]);
48
+ }
49
+ catch {
50
+ out(chalk.dim(" Go to: System Settings > Privacy & Security > Reminders\n"));
51
+ }
52
+ }
53
+ // Step 2: Database access (Full Disk Access)
54
+ out("\n2. Checking database access (for section features)...\n");
55
+ try {
56
+ const dbPath = await dbFindDb();
57
+ out(` ${chalk.green("✓")} Database access granted (${dbPath.split("/").pop()})\n`);
58
+ }
59
+ catch {
60
+ out(chalk.yellow(" ✗ Database access not yet granted.\n"));
61
+ out(" Section features (create-section, move, etc.) need Full Disk Access.\n");
62
+ out(" Opening System Settings — add your terminal app to Full Disk Access.\n");
63
+ try {
64
+ await execFileAsync("open", [
65
+ "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles",
66
+ ]);
67
+ }
68
+ catch {
69
+ out(chalk.dim(" Go to: System Settings > Privacy & Security > Full Disk Access\n"));
70
+ }
71
+ out(chalk.dim(" After enabling, restart your terminal and run remi authorize again.\n"));
72
+ }
73
+ out(chalk.dim("\nRun 'remi doctor' to verify all permissions.\n\n"));
74
+ }
75
+ //# sourceMappingURL=authorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../../src/cli/commands/authorize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function completeCommand(list: string, title: string, opts: {
2
+ id?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,9 @@
1
+ import * as eventkit from "../../core/eventkit.js";
2
+ import { findReminderByTitle } from "../../core/lookup.js";
3
+ import { outputMessage } from "../output.js";
4
+ export async function completeCommand(list, title, opts) {
5
+ const reminder = await findReminderByTitle(list, title, opts);
6
+ await eventkit.completeReminder(reminder.id);
7
+ outputMessage(`Completed "${reminder.title}" in "${list}"`);
8
+ }
9
+ //# sourceMappingURL=complete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../src/cli/commands/complete.ts"],"names":[],"mappings":"AAAA,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,eAAe,CACpC,IAAY,EACZ,KAAa,EACb,IAAqB;IAErB,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7C,aAAa,CAAC,cAAc,QAAQ,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function createListCommand(name: string): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { createList } from "../../core/eventkit.js";
2
+ import { outputMessage } from "../output.js";
3
+ export async function createListCommand(name) {
4
+ const id = await createList(name);
5
+ outputMessage(`Created list "${name}"`, { id });
6
+ }
7
+ //# sourceMappingURL=create-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-list.js","sourceRoot":"","sources":["../../../src/cli/commands/create-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY;IACnD,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,aAAa,CAAC,iBAAiB,IAAI,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function createSectionCommand(list: string, name: string): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { createSection } from "../../core/reminderkit.js";
2
+ import { outputMessage } from "../output.js";
3
+ export async function createSectionCommand(list, name) {
4
+ await createSection(list, name);
5
+ outputMessage(`Created section "${name}" in "${list}"`);
6
+ }
7
+ //# sourceMappingURL=create-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-section.js","sourceRoot":"","sources":["../../../src/cli/commands/create-section.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IACpE,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,aAAa,CAAC,oBAAoB,IAAI,SAAS,IAAI,GAAG,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function deleteListCommand(name: string, opts: {
2
+ confirm?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,11 @@
1
+ import { ErrorCode, RemiCommandError } from "../../core/errors.js";
2
+ import { deleteList } from "../../core/eventkit.js";
3
+ import { isJsonMode, outputMessage } from "../output.js";
4
+ export async function deleteListCommand(name, opts) {
5
+ if (!opts.confirm && !isJsonMode()) {
6
+ throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, "List deletion requires --confirm flag", `Run: remi delete-list "${name}" --confirm`);
7
+ }
8
+ await deleteList(name);
9
+ outputMessage(`Deleted list "${name}"`);
10
+ }
11
+ //# sourceMappingURL=delete-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-list.js","sourceRoot":"","sources":["../../../src/cli/commands/delete-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,IAA2B;IAChF,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,uCAAuC,EACvC,0BAA0B,IAAI,aAAa,CAC3C,CAAC;IACH,CAAC;IAED,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACvB,aAAa,CAAC,iBAAiB,IAAI,GAAG,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function deleteSectionCommand(list: string, name: string): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import { deleteSection } from "../../core/reminderkit.js";
2
+ import { outputMessage } from "../output.js";
3
+ export async function deleteSectionCommand(list, name) {
4
+ await deleteSection(list, name);
5
+ outputMessage(`Deleted section "${name}" from "${list}"`);
6
+ }
7
+ //# sourceMappingURL=delete-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-section.js","sourceRoot":"","sources":["../../../src/cli/commands/delete-section.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IACpE,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,aAAa,CAAC,oBAAoB,IAAI,WAAW,IAAI,GAAG,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function deleteCommand(list: string, title: string, opts: {
2
+ id?: string;
3
+ confirm?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,14 @@
1
+ import { ErrorCode, RemiCommandError } from "../../core/errors.js";
2
+ import * as eventkit from "../../core/eventkit.js";
3
+ import { findReminderByTitle } from "../../core/lookup.js";
4
+ import { isJsonMode, outputMessage } from "../output.js";
5
+ export async function deleteCommand(list, title, opts) {
6
+ // Require --confirm in interactive mode (JSON mode skips confirmation for agents)
7
+ if (!opts.confirm && !isJsonMode()) {
8
+ throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, "Deletion requires --confirm flag", `Run: remi delete "${list}" "${title}" --confirm`);
9
+ }
10
+ const reminder = await findReminderByTitle(list, title, opts);
11
+ await eventkit.deleteReminder(reminder.id);
12
+ outputMessage(`Deleted "${reminder.title}" from "${list}"`);
13
+ }
14
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/cli/commands/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,IAAY,EACZ,KAAa,EACb,IAAwC;IAExC,kFAAkF;IAClF,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,gBAAgB,CACzB,SAAS,CAAC,gBAAgB,EAC1B,kCAAkC,EAClC,qBAAqB,IAAI,MAAM,KAAK,aAAa,CACjD,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,YAAY,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function doctorCommand(opts: {
2
+ sync?: boolean;
3
+ db?: boolean;
4
+ }): Promise<void>;