@todu/cli 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.
Files changed (73) hide show
  1. package/dist/commands/config.js +3 -3
  2. package/dist/commands/config.js.map +1 -1
  3. package/dist/commands/daemon.d.ts +4 -0
  4. package/dist/commands/daemon.d.ts.map +1 -0
  5. package/dist/commands/daemon.js +675 -0
  6. package/dist/commands/daemon.js.map +1 -0
  7. package/dist/commands/habit.d.ts +2 -2
  8. package/dist/commands/habit.d.ts.map +1 -1
  9. package/dist/commands/habit.js +270 -315
  10. package/dist/commands/habit.js.map +1 -1
  11. package/dist/commands/label.d.ts +2 -2
  12. package/dist/commands/label.d.ts.map +1 -1
  13. package/dist/commands/label.js +76 -92
  14. package/dist/commands/label.js.map +1 -1
  15. package/dist/commands/note.d.ts +2 -2
  16. package/dist/commands/note.d.ts.map +1 -1
  17. package/dist/commands/note.js +97 -118
  18. package/dist/commands/note.js.map +1 -1
  19. package/dist/commands/plugin.d.ts +4 -0
  20. package/dist/commands/plugin.d.ts.map +1 -0
  21. package/dist/commands/plugin.js +527 -0
  22. package/dist/commands/plugin.js.map +1 -0
  23. package/dist/commands/project.d.ts +2 -2
  24. package/dist/commands/project.d.ts.map +1 -1
  25. package/dist/commands/project.js +99 -117
  26. package/dist/commands/project.js.map +1 -1
  27. package/dist/commands/recurring.d.ts +2 -2
  28. package/dist/commands/recurring.d.ts.map +1 -1
  29. package/dist/commands/recurring.js +250 -284
  30. package/dist/commands/recurring.js.map +1 -1
  31. package/dist/commands/sync.d.ts +2 -2
  32. package/dist/commands/sync.d.ts.map +1 -1
  33. package/dist/commands/sync.js +123 -12
  34. package/dist/commands/sync.js.map +1 -1
  35. package/dist/commands/task.d.ts +2 -2
  36. package/dist/commands/task.d.ts.map +1 -1
  37. package/dist/commands/task.js +181 -207
  38. package/dist/commands/task.js.map +1 -1
  39. package/dist/daemon-command-client.d.ts +11 -0
  40. package/dist/daemon-command-client.d.ts.map +1 -0
  41. package/dist/daemon-command-client.js +57 -0
  42. package/dist/daemon-command-client.js.map +1 -0
  43. package/dist/daemon-plugin-config.d.ts +8 -0
  44. package/dist/daemon-plugin-config.d.ts.map +1 -0
  45. package/dist/daemon-plugin-config.js +22 -0
  46. package/dist/daemon-plugin-config.js.map +1 -0
  47. package/dist/daemon-plugin-paths.d.ts +8 -0
  48. package/dist/daemon-plugin-paths.d.ts.map +1 -0
  49. package/dist/daemon-plugin-paths.js +28 -0
  50. package/dist/daemon-plugin-paths.js.map +1 -0
  51. package/dist/daemon-transport.d.ts +37 -0
  52. package/dist/daemon-transport.d.ts.map +1 -0
  53. package/dist/daemon-transport.js +422 -0
  54. package/dist/daemon-transport.js.map +1 -0
  55. package/dist/daemon-worker-assignment.d.ts +8 -0
  56. package/dist/daemon-worker-assignment.d.ts.map +1 -0
  57. package/dist/daemon-worker-assignment.js +22 -0
  58. package/dist/daemon-worker-assignment.js.map +1 -0
  59. package/dist/index.js +20 -23
  60. package/dist/index.js.map +1 -1
  61. package/dist/test-helpers/daemon-process.d.ts +5 -0
  62. package/dist/test-helpers/daemon-process.d.ts.map +1 -0
  63. package/dist/test-helpers/daemon-process.js +55 -0
  64. package/dist/test-helpers/daemon-process.js.map +1 -0
  65. package/dist/version.d.ts +2 -0
  66. package/dist/version.d.ts.map +1 -0
  67. package/dist/version.js +3 -0
  68. package/dist/version.js.map +1 -0
  69. package/dist/warnings.d.ts +7 -0
  70. package/dist/warnings.d.ts.map +1 -0
  71. package/dist/warnings.js +21 -0
  72. package/dist/warnings.js.map +1 -0
  73. package/package.json +5 -3
@@ -1,5 +1,6 @@
1
1
  import { describeSchedule } from "@todu/engine";
2
- import { formatError, formatJSON, formatTable } from "../format.js";
2
+ import { formatDaemonCommandError } from "../daemon-command-client.js";
3
+ import { formatJSON, formatTable } from "../format.js";
3
4
  const HABIT_COLUMNS = [
4
5
  { key: "id", label: "ID" },
5
6
  { key: "title", label: "Title" },
@@ -35,24 +36,28 @@ function habitDetail(h) {
35
36
  lines.push(`Updated: ${h.updatedAt}`);
36
37
  return lines.join("\n");
37
38
  }
38
- async function resolveHabit(todu, ref) {
39
- // Try as ID first
40
- const getResult = await todu.habit.get(ref);
41
- if (getResult.ok)
42
- return { ok: true, value: getResult.value };
43
- // Try by name
44
- const listResult = await todu.habit.list();
45
- if (!listResult.ok)
46
- return { ok: false, message: formatError(listResult.error) };
39
+ async function resolveHabit(invokeDaemon, ref) {
40
+ const byId = await invokeDaemon("habit.get", { id: ref });
41
+ if (byId.ok) {
42
+ return { ok: true, value: byId.value };
43
+ }
44
+ if (byId.error.code !== "NOT_FOUND") {
45
+ return { ok: false, message: formatDaemonCommandError(byId.error) };
46
+ }
47
+ const listResult = await invokeDaemon("habit.list", {});
48
+ if (!listResult.ok) {
49
+ return { ok: false, message: formatDaemonCommandError(listResult.error) };
50
+ }
47
51
  const byName = listResult.value.filter((h) => h.title.toLowerCase() === ref.toLowerCase());
48
- if (byName.length === 1)
52
+ if (byName.length === 1) {
49
53
  return { ok: true, value: byName[0] };
54
+ }
50
55
  if (byName.length > 1) {
51
56
  return { ok: false, message: `Multiple habits match "${ref}". Use the habit ID.` };
52
57
  }
53
58
  return { ok: false, message: `Habit not found: ${ref}` };
54
59
  }
55
- export function registerHabitCommands(program, getTodu) {
60
+ export function registerHabitCommands(program, invokeDaemon) {
56
61
  const habit = program.command("habit").description("Manage habits");
57
62
  habit
58
63
  .command("create")
@@ -64,32 +69,28 @@ export function registerHabitCommands(program, getTodu) {
64
69
  .option("--end-date <date>", "end date (YYYY-MM-DD)")
65
70
  .option("--description <text>", "habit description")
66
71
  .action(async (opts) => {
67
- const todu = await getTodu();
68
- try {
69
- const result = await todu.habit.create({
72
+ const result = await invokeDaemon("habit.create", {
73
+ input: {
70
74
  title: opts.title,
71
75
  schedule: opts.schedule,
72
76
  timezone: opts.timezone,
73
77
  startDate: opts.startDate,
74
78
  endDate: opts.endDate,
75
79
  description: opts.description,
76
- });
77
- if (!result.ok) {
78
- console.error(formatError(result.error));
79
- process.exitCode = 1;
80
- return;
81
- }
82
- const format = program.opts().format;
83
- if (format === "json") {
84
- console.log(formatJSON(result.value));
85
- }
86
- else {
87
- console.log(`Created habit: ${result.value.id}`);
88
- console.log(habitDetail(result.value));
89
- }
80
+ },
81
+ });
82
+ if (!result.ok) {
83
+ console.error(formatDaemonCommandError(result.error));
84
+ process.exitCode = 1;
85
+ return;
90
86
  }
91
- finally {
92
- await todu.close();
87
+ const format = program.opts().format;
88
+ if (format === "json") {
89
+ console.log(formatJSON(result.value));
90
+ }
91
+ else {
92
+ console.log(`Created habit: ${result.value.id}`);
93
+ console.log(habitDetail(result.value));
93
94
  }
94
95
  });
95
96
  habit
@@ -98,80 +99,70 @@ export function registerHabitCommands(program, getTodu) {
98
99
  .option("--active", "show only active habits")
99
100
  .option("--paused", "show only paused habits")
100
101
  .action(async (opts) => {
101
- const todu = await getTodu();
102
- try {
103
- const filter = {};
104
- if (opts.active)
105
- filter.paused = false;
106
- if (opts.paused)
107
- filter.paused = true;
108
- const result = await todu.habit.list(filter);
109
- if (!result.ok) {
110
- console.error(formatError(result.error));
111
- process.exitCode = 1;
112
- return;
113
- }
114
- const format = program.opts().format;
115
- if (format === "json") {
116
- console.log(formatJSON(result.value));
117
- return;
118
- }
119
- // Enhance with streak info
120
- const rows = [];
121
- for (const h of result.value) {
122
- const row = habitToRow(h);
123
- const streak = await todu.habit.streak(h.id);
124
- if (streak.ok) {
125
- row.streak = streak.value.current > 0 ? `🔥 ${streak.value.current}` : "0";
126
- row.today = streak.value.completedToday ? "✅" : "—";
127
- }
128
- rows.push(row);
129
- }
130
- const columns = [
131
- ...HABIT_COLUMNS,
132
- { key: "streak", label: "Streak" },
133
- { key: "today", label: "Today" },
134
- ];
135
- console.log(formatTable(rows, columns));
102
+ const filter = {};
103
+ if (opts.active)
104
+ filter.paused = false;
105
+ if (opts.paused)
106
+ filter.paused = true;
107
+ const result = await invokeDaemon("habit.list", { filter });
108
+ if (!result.ok) {
109
+ console.error(formatDaemonCommandError(result.error));
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+ const format = program.opts().format;
114
+ if (format === "json") {
115
+ console.log(formatJSON(result.value));
116
+ return;
136
117
  }
137
- finally {
138
- await todu.close();
118
+ const rows = [];
119
+ for (const h of result.value) {
120
+ const row = habitToRow(h);
121
+ const streak = await invokeDaemon("habit.streak", { id: h.id });
122
+ if (streak.ok) {
123
+ row.streak = streak.value.current > 0 ? `🔥 ${streak.value.current}` : "0";
124
+ row.today = streak.value.completedToday ? "✅" : "—";
125
+ }
126
+ rows.push(row);
139
127
  }
128
+ const columns = [
129
+ ...HABIT_COLUMNS,
130
+ { key: "streak", label: "Streak" },
131
+ { key: "today", label: "Today" },
132
+ ];
133
+ console.log(formatTable(rows, columns));
140
134
  });
141
135
  habit
142
136
  .command("show <id>")
143
137
  .description("Show habit details with streak info")
144
138
  .action(async (ref) => {
145
- const todu = await getTodu();
146
- try {
147
- const resolved = await resolveHabit(todu, ref);
148
- if (!resolved.ok) {
149
- console.error(resolved.message);
150
- process.exitCode = 1;
151
- return;
152
- }
153
- const format = program.opts().format;
154
- if (format === "json") {
155
- // Include streak in JSON output
156
- const streak = await todu.habit.streak(resolved.value.id);
157
- const data = { ...resolved.value };
158
- if (streak.ok)
159
- data.streak = streak.value;
160
- console.log(formatJSON(data));
161
- return;
162
- }
163
- console.log(habitDetail(resolved.value));
164
- const streak = await todu.habit.streak(resolved.value.id);
165
- if (streak.ok) {
166
- console.log("");
167
- console.log(`Streak: ${streak.value.current > 0 ? `🔥 ${streak.value.current} days` : "0 days"}`);
168
- console.log(`Longest: ${streak.value.longest} days`);
169
- console.log(`Today: ${streak.value.completedToday ? "✅ Done" : "— Not done"}`);
170
- console.log(`Total: ${streak.value.totalCheckins} check-ins`);
171
- }
139
+ const resolved = await resolveHabit(invokeDaemon, ref);
140
+ if (!resolved.ok) {
141
+ console.error(resolved.message);
142
+ process.exitCode = 1;
143
+ return;
172
144
  }
173
- finally {
174
- await todu.close();
145
+ const format = program.opts().format;
146
+ if (format === "json") {
147
+ const streak = await invokeDaemon("habit.streak", {
148
+ id: resolved.value.id,
149
+ });
150
+ const data = { ...resolved.value };
151
+ if (streak.ok)
152
+ data.streak = streak.value;
153
+ console.log(formatJSON(data));
154
+ return;
155
+ }
156
+ console.log(habitDetail(resolved.value));
157
+ const streak = await invokeDaemon("habit.streak", {
158
+ id: resolved.value.id,
159
+ });
160
+ if (streak.ok) {
161
+ console.log("");
162
+ console.log(`Streak: ${streak.value.current > 0 ? `🔥 ${streak.value.current} days` : "0 days"}`);
163
+ console.log(`Longest: ${streak.value.longest} days`);
164
+ console.log(`Today: ${streak.value.completedToday ? "✅ Done" : "— Not done"}`);
165
+ console.log(`Total: ${streak.value.totalCheckins} check-ins`);
175
166
  }
176
167
  });
177
168
  habit
@@ -183,229 +174,196 @@ export function registerHabitCommands(program, getTodu) {
183
174
  .option("--description <text>", "update description")
184
175
  .option("--end-date <date>", "update end date")
185
176
  .action(async (ref, opts) => {
186
- const todu = await getTodu();
187
- try {
188
- const resolved = await resolveHabit(todu, ref);
189
- if (!resolved.ok) {
190
- console.error(resolved.message);
191
- process.exitCode = 1;
192
- return;
193
- }
194
- const input = {};
195
- if (opts.title)
196
- input.title = opts.title;
197
- if (opts.schedule)
198
- input.schedule = opts.schedule;
199
- if (opts.timezone)
200
- input.timezone = opts.timezone;
201
- if (opts.description)
202
- input.description = opts.description;
203
- if (opts.endDate)
204
- input.endDate = opts.endDate;
205
- const result = await todu.habit.update(resolved.value.id, input);
206
- if (!result.ok) {
207
- console.error(formatError(result.error));
208
- process.exitCode = 1;
209
- return;
210
- }
211
- const format = program.opts().format;
212
- if (format === "json") {
213
- console.log(formatJSON(result.value));
214
- }
215
- else {
216
- console.log(`Updated habit: ${result.value.id}`);
217
- }
177
+ const resolved = await resolveHabit(invokeDaemon, ref);
178
+ if (!resolved.ok) {
179
+ console.error(resolved.message);
180
+ process.exitCode = 1;
181
+ return;
182
+ }
183
+ const input = {};
184
+ if (opts.title)
185
+ input.title = opts.title;
186
+ if (opts.schedule)
187
+ input.schedule = opts.schedule;
188
+ if (opts.timezone)
189
+ input.timezone = opts.timezone;
190
+ if (opts.description)
191
+ input.description = opts.description;
192
+ if (opts.endDate)
193
+ input.endDate = opts.endDate;
194
+ const result = await invokeDaemon("habit.update", {
195
+ id: resolved.value.id,
196
+ input,
197
+ });
198
+ if (!result.ok) {
199
+ console.error(formatDaemonCommandError(result.error));
200
+ process.exitCode = 1;
201
+ return;
202
+ }
203
+ const format = program.opts().format;
204
+ if (format === "json") {
205
+ console.log(formatJSON(result.value));
218
206
  }
219
- finally {
220
- await todu.close();
207
+ else {
208
+ console.log(`Updated habit: ${result.value.id}`);
221
209
  }
222
210
  });
223
211
  habit
224
212
  .command("delete <id>")
225
213
  .description("Delete a habit")
226
214
  .action(async (ref) => {
227
- const todu = await getTodu();
228
- try {
229
- const resolved = await resolveHabit(todu, ref);
230
- if (!resolved.ok) {
231
- console.error(resolved.message);
232
- process.exitCode = 1;
233
- return;
234
- }
235
- const result = await todu.habit.delete(resolved.value.id);
236
- if (!result.ok) {
237
- console.error(formatError(result.error));
238
- process.exitCode = 1;
239
- return;
240
- }
241
- const format = program.opts().format;
242
- if (format === "json") {
243
- console.log(formatJSON({ deleted: resolved.value.id }));
244
- }
245
- else {
246
- console.log(`Deleted habit: ${resolved.value.id}`);
247
- }
215
+ const resolved = await resolveHabit(invokeDaemon, ref);
216
+ if (!resolved.ok) {
217
+ console.error(resolved.message);
218
+ process.exitCode = 1;
219
+ return;
220
+ }
221
+ const result = await invokeDaemon("habit.delete", { id: resolved.value.id });
222
+ if (!result.ok) {
223
+ console.error(formatDaemonCommandError(result.error));
224
+ process.exitCode = 1;
225
+ return;
248
226
  }
249
- finally {
250
- await todu.close();
227
+ const format = program.opts().format;
228
+ if (format === "json") {
229
+ console.log(formatJSON({ deleted: resolved.value.id }));
230
+ }
231
+ else {
232
+ console.log(`Deleted habit: ${resolved.value.id}`);
251
233
  }
252
234
  });
253
235
  habit
254
236
  .command("pause <id>")
255
237
  .description("Pause a habit")
256
238
  .action(async (ref) => {
257
- const todu = await getTodu();
258
- try {
259
- const resolved = await resolveHabit(todu, ref);
260
- if (!resolved.ok) {
261
- console.error(resolved.message);
262
- process.exitCode = 1;
263
- return;
264
- }
265
- const result = await todu.habit.pause(resolved.value.id);
266
- if (!result.ok) {
267
- console.error(formatError(result.error));
268
- process.exitCode = 1;
269
- return;
270
- }
271
- const format = program.opts().format;
272
- if (format === "json") {
273
- console.log(formatJSON(result.value));
274
- }
275
- else {
276
- console.log(`Paused habit: ${resolved.value.id}`);
277
- }
239
+ const resolved = await resolveHabit(invokeDaemon, ref);
240
+ if (!resolved.ok) {
241
+ console.error(resolved.message);
242
+ process.exitCode = 1;
243
+ return;
244
+ }
245
+ const result = await invokeDaemon("habit.pause", { id: resolved.value.id });
246
+ if (!result.ok) {
247
+ console.error(formatDaemonCommandError(result.error));
248
+ process.exitCode = 1;
249
+ return;
250
+ }
251
+ const format = program.opts().format;
252
+ if (format === "json") {
253
+ console.log(formatJSON(result.value));
278
254
  }
279
- finally {
280
- await todu.close();
255
+ else {
256
+ console.log(`Paused habit: ${resolved.value.id}`);
281
257
  }
282
258
  });
283
259
  habit
284
260
  .command("resume <id>")
285
261
  .description("Resume a habit")
286
262
  .action(async (ref) => {
287
- const todu = await getTodu();
288
- try {
289
- const resolved = await resolveHabit(todu, ref);
290
- if (!resolved.ok) {
291
- console.error(resolved.message);
292
- process.exitCode = 1;
293
- return;
294
- }
295
- const result = await todu.habit.resume(resolved.value.id);
296
- if (!result.ok) {
297
- console.error(formatError(result.error));
298
- process.exitCode = 1;
299
- return;
300
- }
301
- const format = program.opts().format;
302
- if (format === "json") {
303
- console.log(formatJSON(result.value));
304
- }
305
- else {
306
- console.log(`Resumed habit: ${resolved.value.id}`);
307
- }
263
+ const resolved = await resolveHabit(invokeDaemon, ref);
264
+ if (!resolved.ok) {
265
+ console.error(resolved.message);
266
+ process.exitCode = 1;
267
+ return;
268
+ }
269
+ const result = await invokeDaemon("habit.resume", { id: resolved.value.id });
270
+ if (!result.ok) {
271
+ console.error(formatDaemonCommandError(result.error));
272
+ process.exitCode = 1;
273
+ return;
308
274
  }
309
- finally {
310
- await todu.close();
275
+ const format = program.opts().format;
276
+ if (format === "json") {
277
+ console.log(formatJSON(result.value));
278
+ }
279
+ else {
280
+ console.log(`Resumed habit: ${resolved.value.id}`);
311
281
  }
312
282
  });
313
283
  habit
314
284
  .command("check <id>")
315
285
  .description("Check in for today")
316
286
  .action(async (ref) => {
317
- const todu = await getTodu();
318
- try {
319
- const resolved = await resolveHabit(todu, ref);
320
- if (!resolved.ok) {
321
- console.error(resolved.message);
322
- process.exitCode = 1;
323
- return;
324
- }
325
- const result = await todu.habit.check(resolved.value.id);
326
- if (!result.ok) {
327
- console.error(formatError(result.error));
328
- process.exitCode = 1;
329
- return;
330
- }
331
- const format = program.opts().format;
332
- if (format === "json") {
333
- console.log(formatJSON(result.value));
334
- }
335
- else {
336
- console.log(`✅ ${resolved.value.title} — checked in for ${result.value.date}`);
337
- const streak = await todu.habit.streak(resolved.value.id);
338
- if (streak.ok && streak.value.current > 0) {
339
- console.log(`🔥 ${streak.value.current} day streak!`);
340
- }
341
- }
287
+ const resolved = await resolveHabit(invokeDaemon, ref);
288
+ if (!resolved.ok) {
289
+ console.error(resolved.message);
290
+ process.exitCode = 1;
291
+ return;
342
292
  }
343
- finally {
344
- await todu.close();
293
+ const result = await invokeDaemon("habit.check", {
294
+ id: resolved.value.id,
295
+ });
296
+ if (!result.ok) {
297
+ console.error(formatDaemonCommandError(result.error));
298
+ process.exitCode = 1;
299
+ return;
300
+ }
301
+ const format = program.opts().format;
302
+ if (format === "json") {
303
+ console.log(formatJSON(result.value));
304
+ }
305
+ else {
306
+ console.log(`✅ ${resolved.value.title} — checked in for ${result.value.date}`);
307
+ const streak = await invokeDaemon("habit.streak", {
308
+ id: resolved.value.id,
309
+ });
310
+ if (streak.ok && streak.value.current > 0) {
311
+ console.log(`🔥 ${streak.value.current} day streak!`);
312
+ }
345
313
  }
346
314
  });
347
315
  habit
348
316
  .command("uncheck <id>")
349
317
  .description("Remove today's check-in")
350
318
  .action(async (ref) => {
351
- const todu = await getTodu();
352
- try {
353
- const resolved = await resolveHabit(todu, ref);
354
- if (!resolved.ok) {
355
- console.error(resolved.message);
356
- process.exitCode = 1;
357
- return;
358
- }
359
- const result = await todu.habit.uncheck(resolved.value.id);
360
- if (!result.ok) {
361
- console.error(formatError(result.error));
362
- process.exitCode = 1;
363
- return;
364
- }
365
- const format = program.opts().format;
366
- if (format === "json") {
367
- console.log(formatJSON({ unchecked: resolved.value.id }));
368
- }
369
- else {
370
- console.log(`Unchecked: ${resolved.value.title}`);
371
- }
319
+ const resolved = await resolveHabit(invokeDaemon, ref);
320
+ if (!resolved.ok) {
321
+ console.error(resolved.message);
322
+ process.exitCode = 1;
323
+ return;
324
+ }
325
+ const result = await invokeDaemon("habit.uncheck", { id: resolved.value.id });
326
+ if (!result.ok) {
327
+ console.error(formatDaemonCommandError(result.error));
328
+ process.exitCode = 1;
329
+ return;
372
330
  }
373
- finally {
374
- await todu.close();
331
+ const format = program.opts().format;
332
+ if (format === "json") {
333
+ console.log(formatJSON({ unchecked: resolved.value.id }));
334
+ }
335
+ else {
336
+ console.log(`Unchecked: ${resolved.value.title}`);
375
337
  }
376
338
  });
377
339
  habit
378
340
  .command("streak <id>")
379
341
  .description("Show streak info")
380
342
  .action(async (ref) => {
381
- const todu = await getTodu();
382
- try {
383
- const resolved = await resolveHabit(todu, ref);
384
- if (!resolved.ok) {
385
- console.error(resolved.message);
386
- process.exitCode = 1;
387
- return;
388
- }
389
- const result = await todu.habit.streak(resolved.value.id);
390
- if (!result.ok) {
391
- console.error(formatError(result.error));
392
- process.exitCode = 1;
393
- return;
394
- }
395
- const format = program.opts().format;
396
- if (format === "json") {
397
- console.log(formatJSON(result.value));
398
- }
399
- else {
400
- console.log(`${resolved.value.title}`);
401
- console.log(`Current: ${result.value.current > 0 ? `🔥 ${result.value.current} days` : "0 days"}`);
402
- console.log(`Longest: ${result.value.longest} days`);
403
- console.log(`Today: ${result.value.completedToday ? "✅ Done" : "— Not done"}`);
404
- console.log(`Total: ${result.value.totalCheckins} check-ins`);
405
- }
343
+ const resolved = await resolveHabit(invokeDaemon, ref);
344
+ if (!resolved.ok) {
345
+ console.error(resolved.message);
346
+ process.exitCode = 1;
347
+ return;
348
+ }
349
+ const result = await invokeDaemon("habit.streak", {
350
+ id: resolved.value.id,
351
+ });
352
+ if (!result.ok) {
353
+ console.error(formatDaemonCommandError(result.error));
354
+ process.exitCode = 1;
355
+ return;
406
356
  }
407
- finally {
408
- await todu.close();
357
+ const format = program.opts().format;
358
+ if (format === "json") {
359
+ console.log(formatJSON(result.value));
360
+ }
361
+ else {
362
+ console.log(`${resolved.value.title}`);
363
+ console.log(`Current: ${result.value.current > 0 ? `🔥 ${result.value.current} days` : "0 days"}`);
364
+ console.log(`Longest: ${result.value.longest} days`);
365
+ console.log(`Today: ${result.value.completedToday ? "✅ Done" : "— Not done"}`);
366
+ console.log(`Total: ${result.value.totalCheckins} check-ins`);
409
367
  }
410
368
  });
411
369
  habit
@@ -413,45 +371,42 @@ export function registerHabitCommands(program, getTodu) {
413
371
  .description("Show check-in history")
414
372
  .option("--days <days>", "number of days to look back", "30")
415
373
  .action(async (ref, opts) => {
416
- const todu = await getTodu();
417
- try {
418
- const resolved = await resolveHabit(todu, ref);
419
- if (!resolved.ok) {
420
- console.error(resolved.message);
421
- process.exitCode = 1;
422
- return;
423
- }
424
- const days = Number.parseInt(opts.days, 10);
425
- const result = await todu.habit.history(resolved.value.id, days);
426
- if (!result.ok) {
427
- console.error(formatError(result.error));
428
- process.exitCode = 1;
429
- return;
430
- }
431
- const format = program.opts().format;
432
- if (format === "json") {
433
- console.log(formatJSON(result.value));
434
- return;
435
- }
436
- if (result.value.length === 0) {
437
- console.log("No history.");
438
- return;
439
- }
440
- console.log(`${resolved.value.title} — last ${days} days`);
441
- console.log("");
442
- const columns = [
443
- { key: "date", label: "Date" },
444
- { key: "status", label: "Status" },
445
- ];
446
- const rows = result.value.map((entry) => ({
447
- date: entry.date,
448
- status: entry.completed ? "✅" : "—",
449
- }));
450
- console.log(formatTable(rows, columns));
451
- }
452
- finally {
453
- await todu.close();
374
+ const resolved = await resolveHabit(invokeDaemon, ref);
375
+ if (!resolved.ok) {
376
+ console.error(resolved.message);
377
+ process.exitCode = 1;
378
+ return;
379
+ }
380
+ const days = Number.parseInt(opts.days, 10);
381
+ const result = await invokeDaemon("habit.history", {
382
+ id: resolved.value.id,
383
+ days,
384
+ });
385
+ if (!result.ok) {
386
+ console.error(formatDaemonCommandError(result.error));
387
+ process.exitCode = 1;
388
+ return;
389
+ }
390
+ const format = program.opts().format;
391
+ if (format === "json") {
392
+ console.log(formatJSON(result.value));
393
+ return;
394
+ }
395
+ if (result.value.length === 0) {
396
+ console.log("No history.");
397
+ return;
454
398
  }
399
+ console.log(`${resolved.value.title} — last ${days} days`);
400
+ console.log("");
401
+ const columns = [
402
+ { key: "date", label: "Date" },
403
+ { key: "status", label: "Status" },
404
+ ];
405
+ const rows = result.value.map((entry) => ({
406
+ date: entry.date,
407
+ status: entry.completed ? "✅" : "—",
408
+ }));
409
+ console.log(formatTable(rows, columns));
455
410
  });
456
411
  }
457
412
  //# sourceMappingURL=habit.js.map