@mattheworiordan/remi 0.1.0 → 0.2.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/README.md +101 -136
- package/dist/cli/commands/add.js +9 -6
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/complete.js +4 -2
- package/dist/cli/commands/complete.js.map +1 -1
- package/dist/cli/commands/create-section.js +4 -2
- package/dist/cli/commands/create-section.js.map +1 -1
- package/dist/cli/commands/delete-list.js +4 -2
- package/dist/cli/commands/delete-list.js.map +1 -1
- package/dist/cli/commands/delete-section.js +5 -2
- package/dist/cli/commands/delete-section.js.map +1 -1
- package/dist/cli/commands/delete.js +4 -3
- package/dist/cli/commands/delete.js.map +1 -1
- package/dist/cli/commands/demo.d.ts +3 -0
- package/dist/cli/commands/demo.js +134 -0
- package/dist/cli/commands/demo.js.map +1 -0
- package/dist/cli/commands/list.js +48 -2
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/move.js +6 -4
- package/dist/cli/commands/move.js.map +1 -1
- package/dist/cli/commands/sections.js +4 -2
- package/dist/cli/commands/sections.js.map +1 -1
- package/dist/cli/commands/update.js +4 -2
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +234 -215
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +2 -0
- package/dist/cli/output.js +33 -3
- package/dist/cli/output.js.map +1 -1
- package/dist/core/fuzzy.d.ts +16 -0
- package/dist/core/fuzzy.js +39 -0
- package/dist/core/fuzzy.js.map +1 -0
- package/dist/core/lookup.d.ts +1 -1
- package/dist/core/lookup.js +19 -9
- package/dist/core/lookup.js.map +1 -1
- package/dist/core/resolve.d.ts +13 -0
- package/dist/core/resolve.js +25 -0
- package/dist/core/resolve.js.map +1 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +217 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,207 +1,172 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/logo.svg" alt="remi" width="80">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">remi</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center"><strong>The CLI that Apple should have built for Reminders.</strong></p>
|
|
6
8
|
|
|
7
|
-
|
|
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"
|
|
9
|
+
Create lists, add reminders, organize them into sections, and have everything sync across all your Apple devices — from the terminal.
|
|
29
10
|
|
|
30
|
-
|
|
31
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="docs/demo.gif" alt="remi demo" width="500">
|
|
13
|
+
</p>
|
|
32
14
|
|
|
33
|
-
|
|
34
|
-
remi add "Groceries" "Fresh basil" --section "Produce" --due "next tuesday" --priority high
|
|
15
|
+
## Why remi?
|
|
35
16
|
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
- **Sections with iCloud sync** — the only CLI that supports Apple Reminders sections. Create them, assign reminders, move between them, and it all syncs.
|
|
18
|
+
- **Natural language** — `--due "next tuesday"`, `--repeat "every 2 weeks on monday,friday"`
|
|
19
|
+
- **Fuzzy matching** — type `remi list shopping` instead of `remi list "Groceries / Shopping List"`
|
|
20
|
+
- **Agent-first** — structured JSON output, Claude Code plugin, skills.sh skill, OpenClaw compatible
|
|
21
|
+
- **Fast** — compiled Swift helpers, no Electron, no GUI
|
|
38
22
|
|
|
39
|
-
|
|
40
|
-
remi today
|
|
23
|
+
### vs other tools
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
25
|
+
| | remi | [remindctl](https://github.com/steipete/remindctl) | [reminders-cli](https://github.com/keith/reminders-cli) |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Sections | **Yes** | No | No |
|
|
28
|
+
| Section sync (iCloud) | **Yes** | N/A | N/A |
|
|
29
|
+
| Recurrence | **Yes** | Yes | No |
|
|
30
|
+
| Natural language dates | **Yes** | Yes | No |
|
|
31
|
+
| JSON output | **Yes** | Yes | No |
|
|
32
|
+
| AI agent integration | **Yes** | Partial | No |
|
|
47
33
|
|
|
48
|
-
|
|
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
|
|
34
|
+
## Install
|
|
57
35
|
|
|
58
36
|
```bash
|
|
59
|
-
|
|
60
|
-
remi list "Groceries" --include-completed
|
|
61
|
-
remi lists # List all reminder lists
|
|
62
|
-
remi search "milk" # Search across all lists
|
|
37
|
+
brew tap mattheworiordan/tap && brew install remi
|
|
63
38
|
```
|
|
64
39
|
|
|
65
|
-
|
|
40
|
+
Or via npm:
|
|
66
41
|
|
|
67
42
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
remi
|
|
71
|
-
remi complete "Work" "Review report"
|
|
72
|
-
remi update "Work" "Review report" --due "in 3 days"
|
|
73
|
-
remi delete "Work" "Review report" --confirm
|
|
43
|
+
npm install -g @mattheworiordan/remi
|
|
44
|
+
# or run without installing
|
|
45
|
+
npx @mattheworiordan/remi lists
|
|
74
46
|
```
|
|
75
47
|
|
|
76
|
-
|
|
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.
|
|
48
|
+
## Quick start
|
|
83
49
|
|
|
84
50
|
```bash
|
|
85
|
-
remi
|
|
86
|
-
remi
|
|
87
|
-
remi
|
|
88
|
-
remi
|
|
89
|
-
remi
|
|
51
|
+
remi lists # See all lists
|
|
52
|
+
remi list "Groceries" # View a list (fuzzy: remi list groceries)
|
|
53
|
+
remi add "Groceries" "Buy milk" --section "Dairy" # Add to a section
|
|
54
|
+
remi today # What's due today?
|
|
55
|
+
remi complete "Groceries" "milk" # Fuzzy complete
|
|
90
56
|
```
|
|
91
57
|
|
|
92
|
-
|
|
58
|
+
## Usage
|
|
93
59
|
|
|
94
|
-
###
|
|
60
|
+
### Check what's due
|
|
95
61
|
|
|
96
62
|
```bash
|
|
97
|
-
remi
|
|
98
|
-
remi
|
|
63
|
+
remi today # Due today
|
|
64
|
+
remi overdue # Past due
|
|
65
|
+
remi upcoming --days 7 # Coming up
|
|
66
|
+
remi search "dentist" # Search across all lists
|
|
99
67
|
```
|
|
100
68
|
|
|
101
|
-
###
|
|
69
|
+
### Manage reminders
|
|
102
70
|
|
|
103
71
|
```bash
|
|
104
|
-
remi
|
|
105
|
-
remi
|
|
72
|
+
remi add "Work" "Review PR" --due "next friday" --priority high
|
|
73
|
+
remi add "Work" "Standup" --due tomorrow --repeat daily
|
|
74
|
+
remi complete "Work" "standup"
|
|
75
|
+
remi update "Work" "Review PR" --due "in 3 days"
|
|
76
|
+
remi delete "Work" "Review PR" --confirm
|
|
106
77
|
```
|
|
107
78
|
|
|
108
|
-
|
|
79
|
+
Dates: `tomorrow`, `next tuesday`, `in 3 days`, or `YYYY-MM-DD`
|
|
80
|
+
Recurrence: `daily`, `weekly`, `monthly`, `every 2 weeks`, `every 3 months on monday,friday`
|
|
109
81
|
|
|
110
|
-
|
|
82
|
+
### Organize with sections
|
|
111
83
|
|
|
112
84
|
```bash
|
|
113
|
-
|
|
114
|
-
remi
|
|
115
|
-
|
|
116
|
-
#
|
|
117
|
-
remi completions bash > /usr/local/etc/bash_completion.d/remi
|
|
118
|
-
|
|
119
|
-
# fish
|
|
120
|
-
remi completions fish > ~/.config/fish/completions/remi.fish
|
|
85
|
+
remi sections "Groceries" # List sections
|
|
86
|
+
remi create-section "Groceries" "Produce" # Create a section
|
|
87
|
+
remi add "Groceries" "Bananas" --section "Produce" # Add to a section
|
|
88
|
+
remi move "Groceries" "Bananas" --to-section "Dairy" # Move between sections
|
|
121
89
|
```
|
|
122
90
|
|
|
123
|
-
|
|
91
|
+
Sections sync to iCloud via CRDT vector clocks. See [how it works](docs/APPLE_REMINDERS_INTERNALS.md).
|
|
92
|
+
|
|
93
|
+
### JSON output
|
|
124
94
|
|
|
125
95
|
Every command supports `--json` for machine-readable output:
|
|
126
96
|
|
|
127
97
|
```bash
|
|
128
|
-
remi lists --json
|
|
129
98
|
remi today --json
|
|
130
|
-
|
|
99
|
+
# {"success": true, "data": [...]}
|
|
131
100
|
```
|
|
132
101
|
|
|
133
|
-
Returns `{"success": true, "data": ...}` on success or `{"success": false, "error": {"code": "...", "message": "...", "suggestion": "..."}}` on failure.
|
|
134
|
-
|
|
135
102
|
## AI agent integration
|
|
136
103
|
|
|
137
|
-
remi is designed for AI agents.
|
|
104
|
+
remi is designed for AI agents. Use it as an MCP server, Claude Code plugin, or skill:
|
|
138
105
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
106
|
+
### MCP server
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"mcpServers": {
|
|
111
|
+
"remi": {
|
|
112
|
+
"command": "remi",
|
|
113
|
+
"args": ["--mcp"]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
142
117
|
```
|
|
143
118
|
|
|
144
|
-
|
|
119
|
+
16 tools: `remi_lists`, `remi_add`, `remi_complete`, `remi_move`, `remi_today`, `remi_search`, and more — all with fuzzy matching and structured responses.
|
|
120
|
+
|
|
121
|
+
### Other integrations
|
|
145
122
|
|
|
146
123
|
```bash
|
|
124
|
+
# Claude Code plugin
|
|
125
|
+
claude plugin marketplace add mattheworiordan/remi
|
|
126
|
+
|
|
127
|
+
# skills.sh
|
|
147
128
|
npx skills add mattheworiordan/remi
|
|
148
|
-
```
|
|
149
129
|
|
|
150
|
-
|
|
130
|
+
# OpenClaw
|
|
131
|
+
clawhub install remi
|
|
132
|
+
```
|
|
151
133
|
|
|
152
134
|
## Permissions
|
|
153
135
|
|
|
154
|
-
|
|
136
|
+
On first run, macOS will ask you to grant Reminders access (click Allow). Section features also need Full Disk Access for your terminal app.
|
|
155
137
|
|
|
156
138
|
```bash
|
|
157
|
-
remi authorize # Guides you through
|
|
158
|
-
remi doctor # Shows what's granted
|
|
139
|
+
remi authorize # Guides you through both
|
|
140
|
+
remi doctor # Shows what's granted
|
|
159
141
|
```
|
|
160
142
|
|
|
161
|
-
|
|
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 |
|
|
143
|
+
## Requirements
|
|
165
144
|
|
|
166
|
-
|
|
145
|
+
- macOS 13+ (Ventura or later)
|
|
146
|
+
- Node.js 18+
|
|
147
|
+
- Xcode Command Line Tools (`xcode-select --install`)
|
|
167
148
|
|
|
168
149
|
## How it works
|
|
169
150
|
|
|
170
|
-
remi uses
|
|
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.
|
|
151
|
+
remi uses three layers because Apple never exposed sections in their public API:
|
|
181
152
|
|
|
182
|
-
|
|
153
|
+
| Layer | What | Why |
|
|
154
|
+
|-------|------|-----|
|
|
155
|
+
| **EventKit** | Reminder CRUD, queries, recurrence | Stable public API |
|
|
156
|
+
| **ReminderKit** | Section CRUD | Private framework — only way to create sections that sync |
|
|
157
|
+
| **SQLite + Token Maps** | Section membership | Direct database writes with CRDT vector clocks for iCloud sync |
|
|
183
158
|
|
|
184
|
-
|
|
185
|
-
- Node.js 18+
|
|
186
|
-
- Xcode Command Line Tools (`xcode-select --install`)
|
|
187
|
-
- Apple Reminders access (granted on first use)
|
|
159
|
+
The [full reverse-engineering story](docs/APPLE_REMINDERS_INTERNALS.md) explains what we discovered about Apple's undocumented sync architecture.
|
|
188
160
|
|
|
189
|
-
##
|
|
161
|
+
## Contributing
|
|
190
162
|
|
|
191
163
|
```bash
|
|
192
|
-
git clone https://github.com/mattheworiordan/remi.git
|
|
193
|
-
|
|
194
|
-
npm
|
|
195
|
-
npm run
|
|
196
|
-
npm run build # Compile TypeScript
|
|
197
|
-
npm run dev -- lists # Run in dev mode
|
|
198
|
-
npm test # Run unit tests
|
|
164
|
+
git clone https://github.com/mattheworiordan/remi.git && cd remi
|
|
165
|
+
npm install && npm run build:swift && npm run build
|
|
166
|
+
npm test # Unit tests
|
|
167
|
+
npm run test:integration # Integration tests (needs Reminders access)
|
|
199
168
|
```
|
|
200
169
|
|
|
201
170
|
## License
|
|
202
171
|
|
|
203
|
-
MIT
|
|
204
|
-
|
|
205
|
-
## Author
|
|
206
|
-
|
|
207
|
-
[Matthew O'Riordan](https://github.com/mattheworiordan)
|
|
172
|
+
MIT — [Matthew O'Riordan](https://github.com/mattheworiordan)
|
package/dist/cli/commands/add.js
CHANGED
|
@@ -2,11 +2,14 @@ import { parseDate } from "../../core/dateparse.js";
|
|
|
2
2
|
import { createReminder } from "../../core/eventkit.js";
|
|
3
3
|
import { assignToSection } from "../../core/membership.js";
|
|
4
4
|
import { parseRepeat } from "../../core/recurrence.js";
|
|
5
|
+
import { resolveListName, resolveSectionName } from "../../core/resolve.js";
|
|
5
6
|
import { outputMessage } from "../output.js";
|
|
6
7
|
export async function addCommand(list, title, opts) {
|
|
8
|
+
const listName = await resolveListName(list);
|
|
9
|
+
const sectionName = opts.section ? await resolveSectionName(listName, opts.section) : undefined;
|
|
7
10
|
const createOpts = {
|
|
8
11
|
title,
|
|
9
|
-
listName
|
|
12
|
+
listName,
|
|
10
13
|
due: opts.due ? parseDate(opts.due) : undefined,
|
|
11
14
|
priority: opts.priority,
|
|
12
15
|
notes: opts.notes,
|
|
@@ -20,15 +23,15 @@ export async function addCommand(list, title, opts) {
|
|
|
20
23
|
}
|
|
21
24
|
const id = await createReminder(createOpts);
|
|
22
25
|
let warning;
|
|
23
|
-
if (
|
|
24
|
-
const result = await assignToSection(
|
|
26
|
+
if (sectionName) {
|
|
27
|
+
const result = await assignToSection(listName, title, sectionName);
|
|
25
28
|
warning = result.warning;
|
|
26
29
|
}
|
|
27
|
-
let msg = `Added "${title}" to "${
|
|
30
|
+
let msg = `Added "${title}" to "${listName}"`;
|
|
28
31
|
if (opts.repeat)
|
|
29
32
|
msg += ` (repeats ${opts.repeat})`;
|
|
30
|
-
if (
|
|
31
|
-
msg += ` in section "${
|
|
33
|
+
if (sectionName)
|
|
34
|
+
msg += ` in section "${sectionName}"`;
|
|
32
35
|
if (warning)
|
|
33
36
|
msg += ` (note: ${warning})`;
|
|
34
37
|
outputMessage(msg, { id });
|
|
@@ -1 +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
|
|
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,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,IAAY,EACZ,KAAa,EACb,IAMC;IAED,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChG,MAAM,UAAU,GAAyC;QACxD,KAAK;QACL,QAAQ;QACR,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,WAAW,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QACnE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC1B,CAAC;IAED,IAAI,GAAG,GAAG,UAAU,KAAK,SAAS,QAAQ,GAAG,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM;QAAE,GAAG,IAAI,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC;IACpD,IAAI,WAAW;QAAE,GAAG,IAAI,gBAAgB,WAAW,GAAG,CAAC;IACvD,IAAI,OAAO;QAAE,GAAG,IAAI,WAAW,OAAO,GAAG,CAAC;IAC1C,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as eventkit from "../../core/eventkit.js";
|
|
2
2
|
import { findReminderByTitle } from "../../core/lookup.js";
|
|
3
|
+
import { resolveListName } from "../../core/resolve.js";
|
|
3
4
|
import { outputMessage } from "../output.js";
|
|
4
5
|
export async function completeCommand(list, title, opts) {
|
|
5
|
-
const
|
|
6
|
+
const listName = await resolveListName(list);
|
|
7
|
+
const reminder = await findReminderByTitle(listName, title, opts);
|
|
6
8
|
await eventkit.completeReminder(reminder.id);
|
|
7
|
-
outputMessage(`Completed "${reminder.title}" in "${
|
|
9
|
+
outputMessage(`Completed "${reminder.title}" in "${listName}"`);
|
|
8
10
|
}
|
|
9
11
|
//# sourceMappingURL=complete.js.map
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,IAAY,EACZ,KAAa,EACb,IAAqB;IAErB,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7C,aAAa,CAAC,cAAc,QAAQ,CAAC,KAAK,SAAS,QAAQ,GAAG,CAAC,CAAC;AACjE,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createSection } from "../../core/reminderkit.js";
|
|
2
|
+
import { resolveListName } from "../../core/resolve.js";
|
|
2
3
|
import { outputMessage } from "../output.js";
|
|
3
4
|
export async function createSectionCommand(list, name) {
|
|
4
|
-
await
|
|
5
|
-
|
|
5
|
+
const listName = await resolveListName(list);
|
|
6
|
+
await createSection(listName, name);
|
|
7
|
+
outputMessage(`Created section "${name}" in "${listName}"`);
|
|
6
8
|
}
|
|
7
9
|
//# sourceMappingURL=create-section.js.map
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IACpE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpC,aAAa,CAAC,oBAAoB,IAAI,SAAS,QAAQ,GAAG,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ErrorCode, RemiCommandError } from "../../core/errors.js";
|
|
2
2
|
import { deleteList } from "../../core/eventkit.js";
|
|
3
|
+
import { resolveListName } from "../../core/resolve.js";
|
|
3
4
|
import { isJsonMode, outputMessage } from "../output.js";
|
|
4
5
|
export async function deleteListCommand(name, opts) {
|
|
5
6
|
if (!opts.confirm && !isJsonMode()) {
|
|
6
7
|
throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, "List deletion requires --confirm flag", `Run: remi delete-list "${name}" --confirm`);
|
|
7
8
|
}
|
|
8
|
-
await
|
|
9
|
-
|
|
9
|
+
const listName = await resolveListName(name);
|
|
10
|
+
await deleteList(listName);
|
|
11
|
+
outputMessage(`Deleted list "${listName}"`);
|
|
10
12
|
}
|
|
11
13
|
//# sourceMappingURL=delete-list.js.map
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,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,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC3B,aAAa,CAAC,iBAAiB,QAAQ,GAAG,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { deleteSection } from "../../core/reminderkit.js";
|
|
2
|
+
import { resolveListName, resolveSectionName } from "../../core/resolve.js";
|
|
2
3
|
import { outputMessage } from "../output.js";
|
|
3
4
|
export async function deleteSectionCommand(list, name) {
|
|
4
|
-
await
|
|
5
|
-
|
|
5
|
+
const listName = await resolveListName(list);
|
|
6
|
+
const sectionName = await resolveSectionName(listName, name);
|
|
7
|
+
await deleteSection(listName, sectionName);
|
|
8
|
+
outputMessage(`Deleted section "${sectionName}" from "${listName}"`);
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=delete-section.js.map
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY,EAAE,IAAY;IACpE,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7D,MAAM,aAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC3C,aAAa,CAAC,oBAAoB,WAAW,WAAW,QAAQ,GAAG,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { ErrorCode, RemiCommandError } from "../../core/errors.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 { isJsonMode, outputMessage } from "../output.js";
|
|
5
6
|
export async function deleteCommand(list, title, opts) {
|
|
6
|
-
// Require --confirm in interactive mode (JSON mode skips confirmation for agents)
|
|
7
7
|
if (!opts.confirm && !isJsonMode()) {
|
|
8
8
|
throw new RemiCommandError(ErrorCode.INVALID_ARGUMENT, "Deletion requires --confirm flag", `Run: remi delete "${list}" "${title}" --confirm`);
|
|
9
9
|
}
|
|
10
|
-
const
|
|
10
|
+
const listName = await resolveListName(list);
|
|
11
|
+
const reminder = await findReminderByTitle(listName, title, opts);
|
|
11
12
|
await eventkit.deleteReminder(reminder.id);
|
|
12
|
-
outputMessage(`Deleted "${reminder.title}" from "${
|
|
13
|
+
outputMessage(`Deleted "${reminder.title}" from "${listName}"`);
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=delete.js.map
|
|
@@ -1 +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,
|
|
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,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,IAAY,EACZ,KAAa,EACb,IAAwC;IAExC,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,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3C,aAAa,CAAC,YAAY,QAAQ,CAAC,KAAK,WAAW,QAAQ,GAAG,CAAC,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { createList, createReminder, deleteList, listLists } from "../../core/eventkit.js";
|
|
3
|
+
import { assignToSection } from "../../core/membership.js";
|
|
4
|
+
import { createSection } from "../../core/reminderkit.js";
|
|
5
|
+
import { isJsonMode, outputMessage } from "../output.js";
|
|
6
|
+
const DEMO_LIST = "remi Demo";
|
|
7
|
+
function daysFromNow(days) {
|
|
8
|
+
const d = new Date();
|
|
9
|
+
d.setDate(d.getDate() + days);
|
|
10
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
11
|
+
}
|
|
12
|
+
export async function demoCommand(opts) {
|
|
13
|
+
if (opts.cleanup) {
|
|
14
|
+
try {
|
|
15
|
+
await deleteList(DEMO_LIST);
|
|
16
|
+
outputMessage(`Deleted "${DEMO_LIST}"`);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
outputMessage(`"${DEMO_LIST}" not found — nothing to clean up`);
|
|
20
|
+
}
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Check if demo list already exists
|
|
24
|
+
const lists = await listLists();
|
|
25
|
+
if (lists.some((l) => l.title === DEMO_LIST)) {
|
|
26
|
+
if (!isJsonMode()) {
|
|
27
|
+
process.stdout.write(chalk.yellow(`"${DEMO_LIST}" already exists. Run ${chalk.bold("remi demo --cleanup")} first.\n`));
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!isJsonMode()) {
|
|
32
|
+
process.stdout.write(chalk.bold(`\nCreating "${DEMO_LIST}"...\n\n`));
|
|
33
|
+
}
|
|
34
|
+
// Create list
|
|
35
|
+
await createList(DEMO_LIST);
|
|
36
|
+
// Create sections
|
|
37
|
+
const sections = ["This Week", "Upcoming", "Ideas"];
|
|
38
|
+
for (const s of sections) {
|
|
39
|
+
await createSection(DEMO_LIST, s);
|
|
40
|
+
}
|
|
41
|
+
// Add reminders with various features
|
|
42
|
+
const items = [
|
|
43
|
+
// This Week
|
|
44
|
+
{
|
|
45
|
+
title: "Review pull requests",
|
|
46
|
+
section: "This Week",
|
|
47
|
+
due: daysFromNow(0), // today
|
|
48
|
+
priority: "high",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: "Book dentist appointment",
|
|
52
|
+
section: "This Week",
|
|
53
|
+
due: daysFromNow(2),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
title: "Team standup",
|
|
57
|
+
section: "This Week",
|
|
58
|
+
due: daysFromNow(0), // today
|
|
59
|
+
repeat: "DAILY",
|
|
60
|
+
notes: "Zoom link in calendar",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: "Weekly grocery run",
|
|
64
|
+
section: "This Week",
|
|
65
|
+
due: daysFromNow(1),
|
|
66
|
+
repeat: "WEEKLY",
|
|
67
|
+
},
|
|
68
|
+
// Upcoming
|
|
69
|
+
{
|
|
70
|
+
title: "Renew passport",
|
|
71
|
+
section: "Upcoming",
|
|
72
|
+
due: daysFromNow(16),
|
|
73
|
+
priority: "high",
|
|
74
|
+
notes: "Check gov.uk for processing times",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: "Plan birthday party",
|
|
78
|
+
section: "Upcoming",
|
|
79
|
+
due: daysFromNow(36),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
title: "Car service",
|
|
83
|
+
section: "Upcoming",
|
|
84
|
+
due: daysFromNow(24),
|
|
85
|
+
repeat: "YEARLY",
|
|
86
|
+
},
|
|
87
|
+
// Ideas
|
|
88
|
+
{
|
|
89
|
+
title: "Learn to make sourdough bread",
|
|
90
|
+
section: "Ideas",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title: "Set up a home weather station",
|
|
94
|
+
section: "Ideas",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
title: "Try the new ramen place on High Street",
|
|
98
|
+
section: "Ideas",
|
|
99
|
+
notes: "Heard it's great from Sarah",
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
for (const item of items) {
|
|
103
|
+
const createOpts = {
|
|
104
|
+
title: item.title,
|
|
105
|
+
listName: DEMO_LIST,
|
|
106
|
+
due: item.due,
|
|
107
|
+
priority: item.priority,
|
|
108
|
+
notes: item.notes,
|
|
109
|
+
};
|
|
110
|
+
if (item.repeat) {
|
|
111
|
+
createOpts.rruleFreq = item.repeat;
|
|
112
|
+
if (item.repeatInterval)
|
|
113
|
+
createOpts.rruleInterval = item.repeatInterval;
|
|
114
|
+
}
|
|
115
|
+
await createReminder(createOpts);
|
|
116
|
+
await assignToSection(DEMO_LIST, item.title, item.section);
|
|
117
|
+
if (!isJsonMode()) {
|
|
118
|
+
process.stdout.write(chalk.dim(` + ${item.title}\n`));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!isJsonMode()) {
|
|
122
|
+
process.stdout.write(`\n${chalk.green("✓")} Demo list created with ${items.length} reminders and ${sections.length} sections.\n`);
|
|
123
|
+
process.stdout.write(chalk.dim(`\nTry these:\n`));
|
|
124
|
+
process.stdout.write(chalk.dim(` remi list demo\n`));
|
|
125
|
+
process.stdout.write(chalk.dim(` remi sections demo\n`));
|
|
126
|
+
process.stdout.write(chalk.dim(` remi complete demo "Book dentist appointment"\n`));
|
|
127
|
+
process.stdout.write(chalk.dim(` remi move demo "Learn to make sourdough bread" --to-section "This Week"\n`));
|
|
128
|
+
process.stdout.write(chalk.dim(` remi demo --cleanup (when done)\n\n`));
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
outputMessage(`Demo list created with ${items.length} reminders and ${sections.length} sections`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../../../src/cli/commands/demo.ts"],"names":[],"mappings":"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"}
|