@todu/pi-extensions 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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -0
  3. package/dist/domain/habit.d.ts +38 -0
  4. package/dist/domain/habit.js +1 -0
  5. package/dist/domain/note.d.ts +21 -0
  6. package/dist/domain/note.js +1 -0
  7. package/dist/domain/recurring.d.ts +29 -0
  8. package/dist/domain/recurring.js +1 -0
  9. package/dist/domain/task-actions.d.ts +24 -0
  10. package/dist/domain/task-actions.js +1 -0
  11. package/dist/domain/task.d.ts +50 -0
  12. package/dist/domain/task.js +1 -0
  13. package/dist/extension/current-task-context.d.ts +26 -0
  14. package/dist/extension/current-task-context.js +140 -0
  15. package/dist/extension/register-commands.d.ts +114 -0
  16. package/dist/extension/register-commands.js +1214 -0
  17. package/dist/extension/register-events.d.ts +3 -0
  18. package/dist/extension/register-events.js +30 -0
  19. package/dist/extension/register-tools.d.ts +17 -0
  20. package/dist/extension/register-tools.js +36 -0
  21. package/dist/extension/register-ui.d.ts +3 -0
  22. package/dist/extension/register-ui.js +7 -0
  23. package/dist/extension/sync-status-context.d.ts +26 -0
  24. package/dist/extension/sync-status-context.js +162 -0
  25. package/dist/extension/task-browse-filter-context.d.ts +16 -0
  26. package/dist/extension/task-browse-filter-context.js +40 -0
  27. package/dist/flows/browse-tasks.d.ts +7 -0
  28. package/dist/flows/browse-tasks.js +2 -0
  29. package/dist/flows/comment-on-task.d.ts +7 -0
  30. package/dist/flows/comment-on-task.js +2 -0
  31. package/dist/flows/create-task.d.ts +7 -0
  32. package/dist/flows/create-task.js +2 -0
  33. package/dist/flows/pick-current-task.d.ts +7 -0
  34. package/dist/flows/pick-current-task.js +4 -0
  35. package/dist/flows/show-task-detail.d.ts +7 -0
  36. package/dist/flows/show-task-detail.js +2 -0
  37. package/dist/flows/update-task.d.ts +7 -0
  38. package/dist/flows/update-task.js +2 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +12 -0
  41. package/dist/services/habit-service.d.ts +38 -0
  42. package/dist/services/habit-service.js +1 -0
  43. package/dist/services/note-service.d.ts +5 -0
  44. package/dist/services/note-service.js +1 -0
  45. package/dist/services/project-integration-service.d.ts +109 -0
  46. package/dist/services/project-integration-service.js +122 -0
  47. package/dist/services/project-service.d.ts +27 -0
  48. package/dist/services/project-service.js +8 -0
  49. package/dist/services/recurring-service.d.ts +37 -0
  50. package/dist/services/recurring-service.js +1 -0
  51. package/dist/services/repo-context.d.ts +55 -0
  52. package/dist/services/repo-context.js +135 -0
  53. package/dist/services/task-browse-filter-store.d.ts +31 -0
  54. package/dist/services/task-browse-filter-store.js +47 -0
  55. package/dist/services/task-service.d.ts +42 -0
  56. package/dist/services/task-service.js +1 -0
  57. package/dist/services/task-session-store.d.ts +30 -0
  58. package/dist/services/task-session-store.js +55 -0
  59. package/dist/services/todu/daemon-client.d.ts +93 -0
  60. package/dist/services/todu/daemon-client.js +660 -0
  61. package/dist/services/todu/daemon-config.d.ts +17 -0
  62. package/dist/services/todu/daemon-config.js +38 -0
  63. package/dist/services/todu/daemon-connection.d.ts +61 -0
  64. package/dist/services/todu/daemon-connection.js +633 -0
  65. package/dist/services/todu/daemon-events.d.ts +11 -0
  66. package/dist/services/todu/daemon-events.js +1 -0
  67. package/dist/services/todu/default-task-service.d.ts +34 -0
  68. package/dist/services/todu/default-task-service.js +109 -0
  69. package/dist/services/todu/todu-habit-service.d.ts +24 -0
  70. package/dist/services/todu/todu-habit-service.js +80 -0
  71. package/dist/services/todu/todu-note-service.d.ts +20 -0
  72. package/dist/services/todu/todu-note-service.js +35 -0
  73. package/dist/services/todu/todu-project-integration-service.d.ts +27 -0
  74. package/dist/services/todu/todu-project-integration-service.js +45 -0
  75. package/dist/services/todu/todu-project-service.d.ts +24 -0
  76. package/dist/services/todu/todu-project-service.js +42 -0
  77. package/dist/services/todu/todu-recurring-service.d.ts +27 -0
  78. package/dist/services/todu/todu-recurring-service.js +72 -0
  79. package/dist/services/todu/todu-task-service.d.ts +23 -0
  80. package/dist/services/todu/todu-task-service.js +80 -0
  81. package/dist/tools/habit-mutation-tools.d.ts +170 -0
  82. package/dist/tools/habit-mutation-tools.js +363 -0
  83. package/dist/tools/habit-read-tools.d.ts +61 -0
  84. package/dist/tools/habit-read-tools.js +152 -0
  85. package/dist/tools/note-read-tools.d.ts +79 -0
  86. package/dist/tools/note-read-tools.js +148 -0
  87. package/dist/tools/project-integration-tools.d.ts +92 -0
  88. package/dist/tools/project-integration-tools.js +344 -0
  89. package/dist/tools/project-mutation-tools.d.ts +100 -0
  90. package/dist/tools/project-mutation-tools.js +205 -0
  91. package/dist/tools/project-read-tools.d.ts +59 -0
  92. package/dist/tools/project-read-tools.js +131 -0
  93. package/dist/tools/recurring-mutation-tools.d.ts +130 -0
  94. package/dist/tools/recurring-mutation-tools.js +317 -0
  95. package/dist/tools/recurring-read-tools.d.ts +31 -0
  96. package/dist/tools/recurring-read-tools.js +57 -0
  97. package/dist/tools/task-mutation-tools.d.ts +159 -0
  98. package/dist/tools/task-mutation-tools.js +340 -0
  99. package/dist/tools/task-read-tools.d.ts +91 -0
  100. package/dist/tools/task-read-tools.js +186 -0
  101. package/dist/ui/components/habit-table.d.ts +5 -0
  102. package/dist/ui/components/habit-table.js +34 -0
  103. package/dist/ui/components/loaders.d.ts +6 -0
  104. package/dist/ui/components/loaders.js +5 -0
  105. package/dist/ui/components/task-detail.d.ts +19 -0
  106. package/dist/ui/components/task-detail.js +74 -0
  107. package/dist/ui/components/task-list.d.ts +8 -0
  108. package/dist/ui/components/task-list.js +7 -0
  109. package/dist/ui/components/task-settings.d.ts +7 -0
  110. package/dist/ui/components/task-settings.js +12 -0
  111. package/dist/ui/renderers/task-tool-renderer.d.ts +4 -0
  112. package/dist/ui/renderers/task-tool-renderer.js +4 -0
  113. package/dist/ui/widgets/current-task-widget.d.ts +7 -0
  114. package/dist/ui/widgets/current-task-widget.js +20 -0
  115. package/dist/ui/widgets/next-actions-widget.d.ts +7 -0
  116. package/dist/ui/widgets/next-actions-widget.js +5 -0
  117. package/dist/utils/key-hints.d.ts +6 -0
  118. package/dist/utils/key-hints.js +2 -0
  119. package/dist/utils/schedule.d.ts +35 -0
  120. package/dist/utils/schedule.js +111 -0
  121. package/dist/utils/task-filters.d.ts +3 -0
  122. package/dist/utils/task-filters.js +7 -0
  123. package/dist/utils/task-format.d.ts +4 -0
  124. package/dist/utils/task-format.js +6 -0
  125. package/dist/utils/timezone.d.ts +2 -0
  126. package/dist/utils/timezone.js +9 -0
  127. package/package.json +79 -0
@@ -0,0 +1,660 @@
1
+ export class ToduDaemonClientError extends Error {
2
+ code;
3
+ method;
4
+ details;
5
+ constructor(options) {
6
+ super(options.message);
7
+ this.name = "ToduDaemonClientError";
8
+ this.code = options.code;
9
+ this.method = options.method;
10
+ this.details = options.details;
11
+ }
12
+ }
13
+ const createToduDaemonClient = ({ connection, }) => ({
14
+ async listTasks(filter = {}) {
15
+ const tasks = await listRawTasks(connection, filter);
16
+ return tasks.map(mapTaskSummary);
17
+ },
18
+ async getTask(taskId) {
19
+ const taskResult = await connection.request("task.get", { id: taskId });
20
+ if (!taskResult.ok) {
21
+ if (taskResult.error.code === "NOT_FOUND") {
22
+ return null;
23
+ }
24
+ throw mapDaemonErrorToClientError("task.get", taskResult.error);
25
+ }
26
+ const comments = await fetchTaskComments(connection, taskId);
27
+ return mapTaskDetail(taskResult.value, comments);
28
+ },
29
+ async createTask(input) {
30
+ const taskResult = await connection.request("task.create", {
31
+ input: mapCreateTaskInput(input),
32
+ });
33
+ if (!taskResult.ok) {
34
+ throw mapDaemonErrorToClientError("task.create", taskResult.error);
35
+ }
36
+ return mapTaskDetail(taskResult.value, []);
37
+ },
38
+ async updateTask(input) {
39
+ const taskResult = await connection.request("task.update", {
40
+ id: input.taskId,
41
+ input: mapUpdateTaskInput(input),
42
+ });
43
+ if (!taskResult.ok) {
44
+ throw mapDaemonErrorToClientError("task.update", taskResult.error);
45
+ }
46
+ const comments = await fetchTaskComments(connection, input.taskId);
47
+ return mapTaskDetail(taskResult.value, comments);
48
+ },
49
+ async addTaskComment(input) {
50
+ const noteResult = await connection.request("note.create", {
51
+ input: {
52
+ content: input.content,
53
+ entityType: "task",
54
+ entityId: input.taskId,
55
+ },
56
+ });
57
+ if (!noteResult.ok) {
58
+ throw mapDaemonErrorToClientError("note.create", noteResult.error);
59
+ }
60
+ return mapTaskComment(noteResult.value);
61
+ },
62
+ async deleteTask(taskId) {
63
+ const result = await connection.request("task.delete", { id: taskId });
64
+ if (!result.ok) {
65
+ throw mapDaemonErrorToClientError("task.delete", result.error);
66
+ }
67
+ return {
68
+ taskId,
69
+ deleted: true,
70
+ };
71
+ },
72
+ async moveTask(input) {
73
+ const result = await connection.request("task.move", {
74
+ id: input.taskId,
75
+ targetProjectId: input.targetProjectId,
76
+ });
77
+ if (!result.ok) {
78
+ throw mapDaemonErrorToClientError("task.move", result.error);
79
+ }
80
+ const comments = await fetchTaskComments(connection, result.value.id);
81
+ return {
82
+ sourceTaskId: input.taskId,
83
+ targetTask: mapTaskDetail(result.value, comments),
84
+ };
85
+ },
86
+ async listProjects() {
87
+ const result = await connection.request("project.list", {});
88
+ if (!result.ok) {
89
+ throw mapDaemonErrorToClientError("project.list", result.error);
90
+ }
91
+ return result.value.map(mapProjectSummary);
92
+ },
93
+ async getProject(projectId) {
94
+ const result = await connection.request("project.get", { id: projectId });
95
+ if (!result.ok) {
96
+ if (result.error.code === "NOT_FOUND") {
97
+ return null;
98
+ }
99
+ throw mapDaemonErrorToClientError("project.get", result.error);
100
+ }
101
+ return mapProjectSummary(result.value);
102
+ },
103
+ async createProject(input) {
104
+ const result = await connection.request("project.create", {
105
+ input: mapCreateProjectInput(input),
106
+ });
107
+ if (!result.ok) {
108
+ throw mapDaemonErrorToClientError("project.create", result.error);
109
+ }
110
+ return mapProjectSummary(result.value);
111
+ },
112
+ async updateProject(input) {
113
+ const result = await connection.request("project.update", {
114
+ id: input.projectId,
115
+ input: mapUpdateProjectInput(input),
116
+ });
117
+ if (!result.ok) {
118
+ throw mapDaemonErrorToClientError("project.update", result.error);
119
+ }
120
+ return mapProjectSummary(result.value);
121
+ },
122
+ async deleteProject(projectId) {
123
+ const result = await connection.request("project.delete", { id: projectId });
124
+ if (!result.ok) {
125
+ throw mapDaemonErrorToClientError("project.delete", result.error);
126
+ }
127
+ return {
128
+ projectId,
129
+ deleted: true,
130
+ };
131
+ },
132
+ async listRecurring(filter = {}) {
133
+ const result = await connection.request("recurring.list", {
134
+ filter: mapRecurringFilter(filter),
135
+ });
136
+ if (!result.ok) {
137
+ throw mapDaemonErrorToClientError("recurring.list", result.error);
138
+ }
139
+ return result.value.map(mapRecurringTemplateSummary);
140
+ },
141
+ async getRecurring(recurringId) {
142
+ const result = await connection.request("recurring.get", {
143
+ id: recurringId,
144
+ });
145
+ if (!result.ok) {
146
+ if (result.error.code === "NOT_FOUND") {
147
+ return null;
148
+ }
149
+ throw mapDaemonErrorToClientError("recurring.get", result.error);
150
+ }
151
+ return mapRecurringTemplateDetail(result.value);
152
+ },
153
+ async createRecurring(input) {
154
+ const result = await connection.request("recurring.create", {
155
+ input: mapCreateRecurringInput(input),
156
+ });
157
+ if (!result.ok) {
158
+ throw mapDaemonErrorToClientError("recurring.create", result.error);
159
+ }
160
+ return mapRecurringTemplateDetail(result.value);
161
+ },
162
+ async updateRecurring(input) {
163
+ const result = await connection.request("recurring.update", {
164
+ id: input.recurringId,
165
+ input: mapUpdateRecurringInput(input),
166
+ });
167
+ if (!result.ok) {
168
+ throw mapDaemonErrorToClientError("recurring.update", result.error);
169
+ }
170
+ return mapRecurringTemplateDetail(result.value);
171
+ },
172
+ async deleteRecurring(recurringId) {
173
+ const result = await connection.request("recurring.delete", { id: recurringId });
174
+ if (!result.ok) {
175
+ throw mapDaemonErrorToClientError("recurring.delete", result.error);
176
+ }
177
+ return {
178
+ recurringId,
179
+ deleted: true,
180
+ };
181
+ },
182
+ async listIntegrationBindings(filter = {}) {
183
+ const result = await connection.request("integration.list", {
184
+ filter: mapIntegrationBindingFilter(filter),
185
+ });
186
+ if (!result.ok) {
187
+ throw mapDaemonErrorToClientError("integration.list", result.error);
188
+ }
189
+ return result.value.map(mapIntegrationBinding);
190
+ },
191
+ async createIntegrationBinding(input) {
192
+ const result = await connection.request("integration.create", {
193
+ input: mapCreateIntegrationBindingInput(input),
194
+ });
195
+ if (!result.ok) {
196
+ throw mapDaemonErrorToClientError("integration.create", result.error);
197
+ }
198
+ return mapIntegrationBinding(result.value);
199
+ },
200
+ async listHabits(filter = {}) {
201
+ const result = await connection.request("habit.list", {
202
+ filter: mapHabitFilter(filter),
203
+ });
204
+ if (!result.ok) {
205
+ throw mapDaemonErrorToClientError("habit.list", result.error);
206
+ }
207
+ return result.value.map(mapHabitSummary);
208
+ },
209
+ async getHabit(habitId) {
210
+ const result = await connection.request("habit.get", { id: habitId });
211
+ if (!result.ok) {
212
+ if (result.error.code === "NOT_FOUND") {
213
+ return null;
214
+ }
215
+ throw mapDaemonErrorToClientError("habit.get", result.error);
216
+ }
217
+ return mapHabitDetail(result.value);
218
+ },
219
+ async createHabit(input) {
220
+ const result = await connection.request("habit.create", {
221
+ input: mapCreateHabitInput(input),
222
+ });
223
+ if (!result.ok) {
224
+ throw mapDaemonErrorToClientError("habit.create", result.error);
225
+ }
226
+ return mapHabitDetail(result.value);
227
+ },
228
+ async updateHabit(input) {
229
+ const result = await connection.request("habit.update", {
230
+ id: input.habitId,
231
+ input: mapUpdateHabitInput(input),
232
+ });
233
+ if (!result.ok) {
234
+ throw mapDaemonErrorToClientError("habit.update", result.error);
235
+ }
236
+ return mapHabitDetail(result.value);
237
+ },
238
+ async checkHabit(habitId) {
239
+ const result = await connection.request("habit.check", {
240
+ id: habitId,
241
+ });
242
+ if (!result.ok) {
243
+ throw mapDaemonErrorToClientError("habit.check", result.error);
244
+ }
245
+ return mapHabitCheckResult(result.value, habitId);
246
+ },
247
+ async getHabitStreak(habitId) {
248
+ const result = await connection.request("habit.streak", {
249
+ id: habitId,
250
+ });
251
+ if (!result.ok) {
252
+ throw mapDaemonErrorToClientError("habit.streak", result.error);
253
+ }
254
+ return {
255
+ current: result.value.current,
256
+ longest: result.value.longest,
257
+ completedToday: result.value.completedToday,
258
+ totalCheckins: result.value.totalCheckins,
259
+ };
260
+ },
261
+ async addHabitNote(input) {
262
+ const noteResult = await connection.request("note.create", {
263
+ input: {
264
+ content: input.content,
265
+ entityType: "habit",
266
+ entityId: input.habitId,
267
+ },
268
+ });
269
+ if (!noteResult.ok) {
270
+ throw mapDaemonErrorToClientError("note.create", noteResult.error);
271
+ }
272
+ return mapNoteSummary(noteResult.value);
273
+ },
274
+ async deleteHabit(habitId) {
275
+ const result = await connection.request("habit.delete", { id: habitId });
276
+ if (!result.ok) {
277
+ throw mapDaemonErrorToClientError("habit.delete", result.error);
278
+ }
279
+ return {
280
+ habitId,
281
+ deleted: true,
282
+ };
283
+ },
284
+ async getNote(noteId) {
285
+ const result = await connection.request("note.get", { id: noteId });
286
+ if (!result.ok) {
287
+ if (result.error.code === "NOT_FOUND") {
288
+ return null;
289
+ }
290
+ throw mapDaemonErrorToClientError("note.get", result.error);
291
+ }
292
+ return mapNoteSummary(result.value);
293
+ },
294
+ async listNotes(filter = {}) {
295
+ const result = await connection.request("note.list", {
296
+ filter: mapNoteFilter(filter),
297
+ });
298
+ if (!result.ok) {
299
+ throw mapDaemonErrorToClientError("note.list", result.error);
300
+ }
301
+ return result.value.map(mapNoteSummary);
302
+ },
303
+ async listTaskComments(taskId) {
304
+ return fetchTaskComments(connection, taskId);
305
+ },
306
+ on(eventName, listener) {
307
+ return connection.subscribeToEvents([eventName], (event) => {
308
+ if (event.name === eventName) {
309
+ listener(event);
310
+ }
311
+ });
312
+ },
313
+ });
314
+ const listRawTasks = async (connection, filter) => {
315
+ let tasks;
316
+ if (filter.query && filter.query.trim().length > 0) {
317
+ const result = await connection.request("task.search", {
318
+ query: filter.query,
319
+ });
320
+ if (!result.ok) {
321
+ throw mapDaemonErrorToClientError("task.search", result.error);
322
+ }
323
+ tasks = result.value.filter((task) => matchesTaskFilter(task, filter));
324
+ }
325
+ else {
326
+ const result = await connection.request("task.list", {
327
+ filter: mapTaskFilter(filter),
328
+ });
329
+ if (!result.ok) {
330
+ throw mapDaemonErrorToClientError("task.list", result.error);
331
+ }
332
+ tasks = result.value.filter((task) => matchesTaskFilter(task, filter));
333
+ }
334
+ if (filter.sort) {
335
+ tasks = sortTasks(tasks, filter.sort, filter.sortDirection ?? "desc");
336
+ }
337
+ return tasks;
338
+ };
339
+ const sortTasks = (tasks, field, direction) => {
340
+ const sorted = [...tasks].sort((a, b) => {
341
+ const aVal = getTaskSortValue(a, field);
342
+ const bVal = getTaskSortValue(b, field);
343
+ if (aVal < bVal)
344
+ return -1;
345
+ if (aVal > bVal)
346
+ return 1;
347
+ return 0;
348
+ });
349
+ return direction === "asc" ? sorted : sorted.reverse();
350
+ };
351
+ const PRIORITY_ORDER = { urgent: 0, high: 1, medium: 2, low: 3, none: 4 };
352
+ const getTaskSortValue = (task, field) => {
353
+ switch (field) {
354
+ case "priority":
355
+ return PRIORITY_ORDER[task.priority] ?? 99;
356
+ case "dueDate":
357
+ return task.dueDate ?? "9999-12-31";
358
+ case "createdAt":
359
+ return task.createdAt;
360
+ case "updatedAt":
361
+ return task.updatedAt;
362
+ case "title":
363
+ return task.title.toLowerCase();
364
+ default:
365
+ return task.createdAt;
366
+ }
367
+ };
368
+ const fetchTaskComments = async (connection, taskId) => {
369
+ const result = await connection.request("note.list", {
370
+ filter: {
371
+ entityType: "task",
372
+ entityId: taskId,
373
+ },
374
+ });
375
+ if (!result.ok) {
376
+ throw mapDaemonErrorToClientError("note.list", result.error);
377
+ }
378
+ return result.value.map(mapTaskComment);
379
+ };
380
+ const mapTaskSummary = (task) => ({
381
+ id: task.id,
382
+ title: task.title,
383
+ status: toLocalTaskStatus(task.status),
384
+ priority: toLocalTaskPriority(task.priority),
385
+ projectId: task.projectId ?? null,
386
+ projectName: null,
387
+ labels: [...task.labels],
388
+ });
389
+ const mapTaskDetail = (task, comments) => ({
390
+ ...mapTaskSummary(task),
391
+ description: task.description ?? null,
392
+ comments,
393
+ });
394
+ const mapTaskComment = (note) => ({
395
+ id: note.id,
396
+ taskId: note.entityId ?? "",
397
+ content: note.content,
398
+ author: note.author,
399
+ createdAt: note.createdAt,
400
+ });
401
+ const mapNoteSummary = (note) => ({
402
+ id: note.id,
403
+ content: note.content,
404
+ author: note.author,
405
+ entityType: note.entityType ?? null,
406
+ entityId: note.entityId ?? null,
407
+ tags: [...note.tags],
408
+ createdAt: note.createdAt,
409
+ });
410
+ const mapNoteFilter = (filter) => ({
411
+ entityType: filter.entityType,
412
+ entityId: filter.entityId,
413
+ tag: filter.tag,
414
+ author: filter.author,
415
+ createdFrom: filter.from,
416
+ createdTo: filter.to,
417
+ journal: filter.journal,
418
+ timezone: filter.timezone,
419
+ });
420
+ const mapProjectSummary = (project) => ({
421
+ id: project.id,
422
+ name: project.name,
423
+ status: toLocalProjectStatus(project.status),
424
+ priority: toLocalTaskPriority(project.priority),
425
+ description: project.description ?? null,
426
+ });
427
+ const mapIntegrationBinding = (binding) => ({
428
+ id: binding.id,
429
+ provider: binding.provider,
430
+ projectId: binding.projectId,
431
+ targetKind: binding.targetKind,
432
+ targetRef: binding.targetRef,
433
+ strategy: binding.strategy,
434
+ enabled: binding.enabled,
435
+ options: binding.options,
436
+ createdAt: binding.createdAt,
437
+ updatedAt: binding.updatedAt,
438
+ });
439
+ const mapRecurringTemplateSummary = (template) => ({
440
+ id: template.id,
441
+ title: template.title,
442
+ projectId: template.projectId,
443
+ projectName: null,
444
+ priority: toLocalTaskPriority(template.priority),
445
+ schedule: template.schedule,
446
+ timezone: template.timezone,
447
+ startDate: template.startDate,
448
+ endDate: template.endDate ?? null,
449
+ nextDue: template.nextDue,
450
+ missPolicy: toLocalRecurringMissPolicy(template.missPolicy),
451
+ paused: template.paused,
452
+ });
453
+ const mapRecurringTemplateDetail = (template) => ({
454
+ ...mapRecurringTemplateSummary(template),
455
+ description: template.description ?? null,
456
+ labels: [...template.labels],
457
+ skippedDates: [...template.skippedDates],
458
+ createdAt: template.createdAt,
459
+ updatedAt: template.updatedAt,
460
+ });
461
+ const mapHabitSummary = (habit) => ({
462
+ id: habit.id,
463
+ title: habit.title,
464
+ projectId: habit.projectId,
465
+ projectName: null,
466
+ schedule: habit.schedule,
467
+ timezone: habit.timezone,
468
+ startDate: habit.startDate,
469
+ endDate: habit.endDate ?? null,
470
+ nextDue: habit.nextDue,
471
+ paused: habit.paused,
472
+ });
473
+ const mapHabitDetail = (habit) => ({
474
+ ...mapHabitSummary(habit),
475
+ description: habit.description ?? null,
476
+ createdAt: habit.createdAt,
477
+ updatedAt: habit.updatedAt,
478
+ });
479
+ const mapHabitCheckResult = (result, habitId) => ({
480
+ habitId,
481
+ date: result.date,
482
+ completed: result.completed,
483
+ streak: result.streak
484
+ ? {
485
+ current: result.streak.current,
486
+ longest: result.streak.longest,
487
+ completedToday: result.streak.completedToday,
488
+ totalCheckins: result.streak.totalCheckins,
489
+ }
490
+ : undefined,
491
+ });
492
+ const mapCreateHabitInput = (input) => ({
493
+ title: input.title,
494
+ projectId: input.projectId,
495
+ schedule: input.schedule,
496
+ timezone: input.timezone,
497
+ startDate: input.startDate,
498
+ description: input.description ?? undefined,
499
+ endDate: input.endDate ?? undefined,
500
+ });
501
+ const mapUpdateHabitInput = (input) => ({
502
+ title: input.title ?? undefined,
503
+ schedule: input.schedule ?? undefined,
504
+ timezone: input.timezone ?? undefined,
505
+ description: input.description ?? undefined,
506
+ endDate: input.endDate ?? undefined,
507
+ });
508
+ const mapHabitFilter = (filter) => ({
509
+ paused: filter.paused,
510
+ projectId: filter.projectId,
511
+ search: filter.query,
512
+ });
513
+ const mapCreateProjectInput = (input) => ({
514
+ name: input.name,
515
+ description: input.description ?? undefined,
516
+ priority: input.priority ?? undefined,
517
+ });
518
+ const mapUpdateProjectInput = (input) => ({
519
+ name: input.name ?? undefined,
520
+ description: input.description ?? undefined,
521
+ status: input.status ? toRemoteProjectStatus(input.status) : undefined,
522
+ priority: input.priority ?? undefined,
523
+ });
524
+ const mapCreateRecurringInput = (input) => ({
525
+ title: input.title,
526
+ projectId: input.projectId,
527
+ schedule: input.schedule,
528
+ timezone: input.timezone,
529
+ startDate: input.startDate,
530
+ description: input.description ?? undefined,
531
+ priority: input.priority ?? undefined,
532
+ endDate: input.endDate ?? undefined,
533
+ missPolicy: input.missPolicy ? toRemoteRecurringMissPolicy(input.missPolicy) : undefined,
534
+ });
535
+ const mapUpdateRecurringInput = (input) => ({
536
+ title: input.title ?? undefined,
537
+ projectId: input.projectId ?? undefined,
538
+ schedule: input.schedule ?? undefined,
539
+ timezone: input.timezone ?? undefined,
540
+ startDate: input.startDate ?? undefined,
541
+ description: input.description ?? undefined,
542
+ priority: input.priority ?? undefined,
543
+ endDate: input.endDate ?? undefined,
544
+ missPolicy: input.missPolicy ? toRemoteRecurringMissPolicy(input.missPolicy) : undefined,
545
+ paused: input.paused ?? undefined,
546
+ });
547
+ const mapIntegrationBindingFilter = (filter) => ({
548
+ provider: filter.provider,
549
+ projectId: filter.projectId,
550
+ enabled: filter.enabled,
551
+ });
552
+ const mapRecurringFilter = (filter) => ({
553
+ paused: filter.paused,
554
+ projectId: filter.projectId,
555
+ search: filter.query,
556
+ });
557
+ const mapCreateIntegrationBindingInput = (input) => ({
558
+ provider: input.provider,
559
+ projectId: input.projectId,
560
+ targetKind: input.targetKind,
561
+ targetRef: input.targetRef,
562
+ strategy: input.strategy,
563
+ enabled: input.enabled,
564
+ options: input.options,
565
+ });
566
+ const mapTaskFilter = (filter) => {
567
+ const status = filter.statuses && filter.statuses.length > 0
568
+ ? filter.statuses.map(toRemoteTaskStatus)
569
+ : undefined;
570
+ const priority = filter.priorities && filter.priorities.length > 0
571
+ ? toRemoteTaskPriority(filter.priorities[0])
572
+ : undefined;
573
+ return {
574
+ projectId: filter.projectId,
575
+ status: status?.length === 1 ? status[0] : status,
576
+ priority,
577
+ label: filter.label,
578
+ overdue: filter.overdue,
579
+ today: filter.today,
580
+ createdFrom: filter.from,
581
+ createdTo: filter.to,
582
+ updatedFrom: filter.updatedFrom,
583
+ updatedTo: filter.updatedTo,
584
+ timezone: filter.timezone,
585
+ };
586
+ };
587
+ const mapCreateTaskInput = (input) => ({
588
+ title: input.title,
589
+ description: input.description ?? undefined,
590
+ projectId: input.projectId ?? undefined,
591
+ labels: input.labels,
592
+ });
593
+ const mapUpdateTaskInput = (input) => ({
594
+ title: input.title ?? undefined,
595
+ status: input.status ? toRemoteTaskStatus(input.status) : undefined,
596
+ priority: input.priority ? toRemoteTaskPriority(input.priority) : undefined,
597
+ description: input.description ?? undefined,
598
+ });
599
+ const matchesTaskFilter = (task, filter) => {
600
+ if (filter.projectId && task.projectId !== filter.projectId) {
601
+ return false;
602
+ }
603
+ if (filter.statuses &&
604
+ filter.statuses.length > 0 &&
605
+ !filter.statuses.includes(toLocalTaskStatus(task.status))) {
606
+ return false;
607
+ }
608
+ if (filter.priorities &&
609
+ filter.priorities.length > 0 &&
610
+ !filter.priorities.includes(toLocalTaskPriority(task.priority))) {
611
+ return false;
612
+ }
613
+ if (filter.query && filter.query.trim().length > 0) {
614
+ const normalizedQuery = filter.query.trim().toLowerCase();
615
+ if (!task.title.toLowerCase().includes(normalizedQuery)) {
616
+ return false;
617
+ }
618
+ }
619
+ if (filter.label && !task.labels.includes(filter.label)) {
620
+ return false;
621
+ }
622
+ return true;
623
+ };
624
+ const mapDaemonErrorToClientError = (method, error) => {
625
+ const code = toClientErrorCode(error.code);
626
+ return new ToduDaemonClientError({
627
+ code,
628
+ method,
629
+ message: `${method} failed (${error.code}): ${error.message}`,
630
+ details: error.details,
631
+ });
632
+ };
633
+ const toClientErrorCode = (code) => {
634
+ switch (code) {
635
+ case "NOT_FOUND":
636
+ return "not-found";
637
+ case "VALIDATION_ERROR":
638
+ case "BAD_REQUEST":
639
+ return "validation";
640
+ case "CONFLICT":
641
+ return "conflict";
642
+ case "PRECONDITION_FAILED":
643
+ return "precondition-failed";
644
+ case "DAEMON_UNAVAILABLE":
645
+ return "unavailable";
646
+ case "TIMEOUT":
647
+ return "timeout";
648
+ default:
649
+ return "internal";
650
+ }
651
+ };
652
+ const toLocalTaskStatus = (status) => status === "canceled" ? "cancelled" : status;
653
+ const toRemoteTaskStatus = (status) => status === "cancelled" ? "canceled" : status;
654
+ const toLocalProjectStatus = (status) => status === "canceled" ? "cancelled" : status === "done" ? "done" : "active";
655
+ const toLocalTaskPriority = (priority) => priority;
656
+ const toRemoteTaskPriority = (priority) => priority;
657
+ const toLocalRecurringMissPolicy = (missPolicy) => missPolicy ?? "accumulate";
658
+ const toRemoteRecurringMissPolicy = (missPolicy) => missPolicy;
659
+ const toRemoteProjectStatus = (status) => status === "cancelled" ? "canceled" : status;
660
+ export { createToduDaemonClient, mapCreateHabitInput, mapCreateIntegrationBindingInput, mapCreateProjectInput, mapCreateRecurringInput, mapDaemonErrorToClientError, mapHabitCheckResult, mapHabitDetail, mapHabitFilter, mapHabitSummary, mapIntegrationBindingFilter, mapRecurringFilter, mapRecurringTemplateDetail, mapRecurringTemplateSummary, mapUpdateHabitInput, mapUpdateProjectInput, mapUpdateRecurringInput, toLocalTaskStatus, toRemoteProjectStatus, toRemoteTaskStatus, };
@@ -0,0 +1,17 @@
1
+ import { type ConfigResolutionOptions, type ToduFileConfig } from "@todu/core";
2
+ declare const TODU_DAEMON_SOCKET_ENV = "TODU_DAEMON_SOCKET";
3
+ declare const TODUAI_DAEMON_SOCKET_ENV = "TODUAI_DAEMON_SOCKET";
4
+ declare const DEFAULT_TODU_DAEMON_SOCKET_FILENAME = "daemon.sock";
5
+ export interface ToduDaemonConfig {
6
+ configPath: string;
7
+ dataDir: string;
8
+ socketPath: string;
9
+ fileConfig: ToduFileConfig;
10
+ }
11
+ export interface ResolveToduDaemonConfigOptions extends ConfigResolutionOptions {
12
+ configPath?: string;
13
+ }
14
+ declare const loadToduFileConfig: (configPath: string) => ToduFileConfig;
15
+ declare const resolveDaemonSocketPath: (dataDir: string, env?: NodeJS.ProcessEnv) => string;
16
+ declare const resolveToduDaemonConfig: (options?: ResolveToduDaemonConfigOptions) => ToduDaemonConfig;
17
+ export { DEFAULT_TODU_DAEMON_SOCKET_FILENAME, TODUAI_DAEMON_SOCKET_ENV, TODU_DAEMON_SOCKET_ENV, loadToduFileConfig, resolveDaemonSocketPath, resolveToduDaemonConfig, };