@ofocus/sdk 0.1.0 → 0.3.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/api-report/ofocus-sdk.api.md +496 -1
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/commands/archive.d.ts +48 -0
  5. package/dist/commands/archive.d.ts.map +1 -0
  6. package/dist/commands/archive.js +132 -0
  7. package/dist/commands/archive.js.map +1 -0
  8. package/dist/commands/attachments.d.ts +67 -0
  9. package/dist/commands/attachments.d.ts.map +1 -0
  10. package/dist/commands/attachments.js +160 -0
  11. package/dist/commands/attachments.js.map +1 -0
  12. package/dist/commands/defer.d.ts +37 -0
  13. package/dist/commands/defer.d.ts.map +1 -0
  14. package/dist/commands/defer.js +198 -0
  15. package/dist/commands/defer.js.map +1 -0
  16. package/dist/commands/deferred.d.ts +18 -0
  17. package/dist/commands/deferred.d.ts.map +1 -0
  18. package/dist/commands/deferred.js +146 -0
  19. package/dist/commands/deferred.js.map +1 -0
  20. package/dist/commands/duplicate.d.ts +15 -0
  21. package/dist/commands/duplicate.d.ts.map +1 -0
  22. package/dist/commands/duplicate.js +49 -0
  23. package/dist/commands/duplicate.js.map +1 -0
  24. package/dist/commands/focus.d.ts +26 -0
  25. package/dist/commands/focus.d.ts.map +1 -0
  26. package/dist/commands/focus.js +182 -0
  27. package/dist/commands/focus.js.map +1 -0
  28. package/dist/commands/folders-crud.d.ts +18 -0
  29. package/dist/commands/folders-crud.d.ts.map +1 -0
  30. package/dist/commands/folders-crud.js +117 -0
  31. package/dist/commands/folders-crud.js.map +1 -0
  32. package/dist/commands/forecast.d.ts +20 -0
  33. package/dist/commands/forecast.d.ts.map +1 -0
  34. package/dist/commands/forecast.js +145 -0
  35. package/dist/commands/forecast.js.map +1 -0
  36. package/dist/commands/open.d.ts +17 -0
  37. package/dist/commands/open.d.ts.map +1 -0
  38. package/dist/commands/open.js +88 -0
  39. package/dist/commands/open.js.map +1 -0
  40. package/dist/commands/projects-crud.d.ts +30 -0
  41. package/dist/commands/projects-crud.d.ts.map +1 -0
  42. package/dist/commands/projects-crud.js +209 -0
  43. package/dist/commands/projects-crud.js.map +1 -0
  44. package/dist/commands/quick.d.ts +41 -0
  45. package/dist/commands/quick.d.ts.map +1 -0
  46. package/dist/commands/quick.js +257 -0
  47. package/dist/commands/quick.js.map +1 -0
  48. package/dist/commands/review.d.ts +18 -0
  49. package/dist/commands/review.d.ts.map +1 -1
  50. package/dist/commands/review.js +87 -1
  51. package/dist/commands/review.js.map +1 -1
  52. package/dist/commands/stats.d.ts +48 -0
  53. package/dist/commands/stats.d.ts.map +1 -0
  54. package/dist/commands/stats.js +212 -0
  55. package/dist/commands/stats.js.map +1 -0
  56. package/dist/commands/sync.d.ts +32 -0
  57. package/dist/commands/sync.d.ts.map +1 -0
  58. package/dist/commands/sync.js +63 -0
  59. package/dist/commands/sync.js.map +1 -0
  60. package/dist/commands/taskpaper.d.ts +46 -0
  61. package/dist/commands/taskpaper.d.ts.map +1 -0
  62. package/dist/commands/taskpaper.js +359 -0
  63. package/dist/commands/taskpaper.js.map +1 -0
  64. package/dist/commands/templates.d.ts +134 -0
  65. package/dist/commands/templates.d.ts.map +1 -0
  66. package/dist/commands/templates.js +252 -0
  67. package/dist/commands/templates.js.map +1 -0
  68. package/dist/commands/url.d.ts +16 -0
  69. package/dist/commands/url.d.ts.map +1 -0
  70. package/dist/commands/url.js +96 -0
  71. package/dist/commands/url.js.map +1 -0
  72. package/dist/index.d.ts +38 -5
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +30 -3
  75. package/dist/index.js.map +1 -1
  76. package/dist/types.d.ts +27 -0
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/validation.d.ts +1 -1
  79. package/dist/validation.d.ts.map +1 -1
  80. package/dist/validation.js +3 -1
  81. package/dist/validation.js.map +1 -1
  82. package/package.json +12 -12
  83. package/dist/ofocus-sdk.d.ts +0 -608
@@ -0,0 +1,160 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { success, failure, failureMessage } from "../result.js";
4
+ import { ErrorCode, createError } from "../errors.js";
5
+ import { validateId } from "../validation.js";
6
+ import { escapeAppleScript } from "../escape.js";
7
+ import { runAppleScript, omniFocusScriptWithHelpers } from "../applescript.js";
8
+ /**
9
+ * Add an attachment to a task.
10
+ * @param taskId - Task ID to add attachment to
11
+ * @param filePath - Path to the file to attach
12
+ */
13
+ export async function addAttachment(taskId, filePath) {
14
+ const idError = validateId(taskId, "task");
15
+ if (idError)
16
+ return failure(idError);
17
+ // Validate file exists
18
+ const absolutePath = path.resolve(filePath);
19
+ if (!fs.existsSync(absolutePath)) {
20
+ return failureMessage(`File not found: ${filePath}`);
21
+ }
22
+ // Get file stats
23
+ const stats = fs.statSync(absolutePath);
24
+ if (!stats.isFile()) {
25
+ return failureMessage(`Not a file: ${filePath}`);
26
+ }
27
+ const fileName = path.basename(absolutePath);
28
+ // OmniFocus AppleScript for adding attachment
29
+ // Note: OmniFocus uses POSIX file paths for attachments
30
+ const script = `
31
+ set theTask to first flattened task whose id is "${escapeAppleScript(taskId)}"
32
+ set taskName to name of theTask
33
+
34
+ -- Add attachment using POSIX file path
35
+ set theFile to POSIX file "${escapeAppleScript(absolutePath)}"
36
+
37
+ tell theTask
38
+ make new attachment with properties {file:theFile}
39
+ end tell
40
+
41
+ return "{" & ¬
42
+ "\\"taskId\\": \\"" & (id of theTask) & "\\"," & ¬
43
+ "\\"taskName\\": \\"" & (my escapeJson(taskName)) & "\\"," & ¬
44
+ "\\"fileName\\": \\"" & "${escapeAppleScript(fileName)}" & "\\"," & ¬
45
+ "\\"attached\\": true" & ¬
46
+ "}"
47
+ `;
48
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
49
+ if (!result.success) {
50
+ return failure(result.error ??
51
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to add attachment"));
52
+ }
53
+ if (result.data === undefined) {
54
+ return failure(createError(ErrorCode.UNKNOWN_ERROR, "No result data returned"));
55
+ }
56
+ return success(result.data);
57
+ }
58
+ /**
59
+ * List attachments of a task.
60
+ * @param taskId - Task ID to list attachments for
61
+ */
62
+ export async function listAttachments(taskId) {
63
+ const idError = validateId(taskId, "task");
64
+ if (idError)
65
+ return failure(idError);
66
+ const script = `
67
+ set theTask to first flattened task whose id is "${escapeAppleScript(taskId)}"
68
+ set taskName to name of theTask
69
+ set taskId to id of theTask
70
+
71
+ set output to "{\\"taskId\\": \\"" & taskId & "\\","
72
+ set output to output & "\\"taskName\\": \\"" & (my escapeJson(taskName)) & "\\","
73
+ set output to output & "\\"attachments\\": ["
74
+
75
+ set isFirst to true
76
+ set taskAttachments to attachments of theTask
77
+
78
+ repeat with att in taskAttachments
79
+ if not isFirst then set output to output & ","
80
+ set isFirst to false
81
+
82
+ set attId to id of att
83
+ set attName to name of att
84
+
85
+ set output to output & "{"
86
+ set output to output & "\\"id\\": \\"" & attId & "\\","
87
+ set output to output & "\\"name\\": \\"" & (my escapeJson(attName)) & "\\","
88
+ set output to output & "\\"size\\": null,"
89
+ set output to output & "\\"type\\": null"
90
+ set output to output & "}"
91
+ end repeat
92
+
93
+ set output to output & "]}"
94
+ return output
95
+ `;
96
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
97
+ if (!result.success) {
98
+ return failure(result.error ??
99
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to list attachments"));
100
+ }
101
+ if (result.data === undefined) {
102
+ return failure(createError(ErrorCode.UNKNOWN_ERROR, "No result data returned"));
103
+ }
104
+ return success(result.data);
105
+ }
106
+ /**
107
+ * Remove an attachment from a task.
108
+ * @param taskId - Task ID to remove attachment from
109
+ * @param attachmentIdOrName - Attachment ID or name to remove
110
+ */
111
+ export async function removeAttachment(taskId, attachmentIdOrName) {
112
+ const idError = validateId(taskId, "task");
113
+ if (idError)
114
+ return failure(idError);
115
+ if (!attachmentIdOrName || attachmentIdOrName.trim() === "") {
116
+ return failureMessage("Attachment ID or name is required");
117
+ }
118
+ const script = `
119
+ set theTask to first flattened task whose id is "${escapeAppleScript(taskId)}"
120
+ set attachmentToRemove to missing value
121
+ set attName to ""
122
+
123
+ -- Try to find attachment by ID first, then by name
124
+ set taskAttachments to attachments of theTask
125
+
126
+ repeat with att in taskAttachments
127
+ if id of att is "${escapeAppleScript(attachmentIdOrName)}" then
128
+ set attachmentToRemove to att
129
+ set attName to name of att
130
+ exit repeat
131
+ else if name of att is "${escapeAppleScript(attachmentIdOrName)}" then
132
+ set attachmentToRemove to att
133
+ set attName to name of att
134
+ exit repeat
135
+ end if
136
+ end repeat
137
+
138
+ if attachmentToRemove is missing value then
139
+ error "Attachment not found: ${escapeAppleScript(attachmentIdOrName)}"
140
+ end if
141
+
142
+ delete attachmentToRemove
143
+
144
+ return "{" & ¬
145
+ "\\"taskId\\": \\"" & (id of theTask) & "\\"," & ¬
146
+ "\\"attachmentName\\": \\"" & (my escapeJson(attName)) & "\\"," & ¬
147
+ "\\"removed\\": true" & ¬
148
+ "}"
149
+ `;
150
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
151
+ if (!result.success) {
152
+ return failure(result.error ??
153
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to remove attachment"));
154
+ }
155
+ if (result.data === undefined) {
156
+ return failure(createError(ErrorCode.UNKNOWN_ERROR, "No result data returned"));
157
+ }
158
+ return success(result.data);
159
+ }
160
+ //# sourceMappingURL=attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/commands/attachments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { CliOutput, BatchResult } from "../types.js";
2
+ /**
3
+ * Options for deferring a task.
4
+ */
5
+ export interface DeferOptions {
6
+ /** Defer for a number of days from today */
7
+ days?: number | undefined;
8
+ /** Defer to a specific date */
9
+ to?: string | undefined;
10
+ }
11
+ /**
12
+ * Result from deferring a task.
13
+ */
14
+ export interface DeferResult {
15
+ taskId: string;
16
+ taskName: string;
17
+ previousDeferDate: string | null;
18
+ newDeferDate: string;
19
+ }
20
+ /**
21
+ * Item in batch defer result.
22
+ */
23
+ export interface BatchDeferItem {
24
+ taskId: string;
25
+ taskName: string;
26
+ previousDeferDate: string | null;
27
+ newDeferDate: string;
28
+ }
29
+ /**
30
+ * Defer a task by a number of days or to a specific date.
31
+ */
32
+ export declare function deferTask(taskId: string, options?: DeferOptions): Promise<CliOutput<DeferResult>>;
33
+ /**
34
+ * Defer multiple tasks by a number of days or to a specific date.
35
+ */
36
+ export declare function deferTasks(taskIds: string[], options?: DeferOptions): Promise<CliOutput<BatchResult<BatchDeferItem>>>;
37
+ //# sourceMappingURL=defer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defer.d.ts","sourceRoot":"","sources":["../../src/commands/defer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,+BAA+B;IAC/B,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAID;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAiFjC;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CA4IjD"}
@@ -0,0 +1,198 @@
1
+ import { success, failure } from "../result.js";
2
+ import { ErrorCode, createError } from "../errors.js";
3
+ import { validateId, validateDateString } from "../validation.js";
4
+ import { escapeAppleScript } from "../escape.js";
5
+ import { runAppleScript, omniFocusScriptWithHelpers } from "../applescript.js";
6
+ const MAX_BATCH_SIZE = 50;
7
+ /**
8
+ * Defer a task by a number of days or to a specific date.
9
+ */
10
+ export async function deferTask(taskId, options = {}) {
11
+ // Validate task ID
12
+ const idError = validateId(taskId, "task");
13
+ if (idError)
14
+ return failure(idError);
15
+ // Validate that at least one option is provided
16
+ if (options.days === undefined && options.to === undefined) {
17
+ return failure(createError(ErrorCode.VALIDATION_ERROR, "Must specify either --days or --to"));
18
+ }
19
+ // Validate days
20
+ if (options.days !== undefined &&
21
+ (options.days < 1 || !Number.isInteger(options.days))) {
22
+ return failure(createError(ErrorCode.VALIDATION_ERROR, "Days must be a positive integer"));
23
+ }
24
+ // Validate date string if provided
25
+ if (options.to !== undefined) {
26
+ const dateError = validateDateString(options.to);
27
+ if (dateError)
28
+ return failure(dateError);
29
+ }
30
+ // Build the defer date logic
31
+ let deferLogic;
32
+ if (options.days !== undefined) {
33
+ deferLogic = `set newDefer to (current date) + (${String(options.days)} * days)`;
34
+ }
35
+ else {
36
+ deferLogic = `set newDefer to date "${escapeAppleScript(options.to ?? "")}"`;
37
+ }
38
+ const script = `
39
+ set theTask to first flattened task whose id is "${escapeAppleScript(taskId)}"
40
+
41
+ -- Get previous defer date
42
+ set prevDefer to ""
43
+ try
44
+ set prevDefer to (defer date of theTask) as string
45
+ end try
46
+
47
+ -- Calculate new defer date
48
+ ${deferLogic}
49
+
50
+ -- Set the defer date
51
+ set defer date of theTask to newDefer
52
+
53
+ -- Get the new defer date as string
54
+ set newDeferStr to (defer date of theTask) as string
55
+
56
+ return "{" & ¬
57
+ "\\"taskId\\": \\"${escapeAppleScript(taskId)}\\"," & ¬
58
+ "\\"taskName\\": \\"" & (my escapeJson(name of theTask)) & "\\"," & ¬
59
+ "\\"previousDeferDate\\": " & (my jsonString(prevDefer)) & "," & ¬
60
+ "\\"newDeferDate\\": \\"" & (my escapeJson(newDeferStr)) & "\\"" & ¬
61
+ "}"
62
+ `;
63
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
64
+ if (!result.success) {
65
+ return failure(result.error ??
66
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to defer task"));
67
+ }
68
+ if (result.data === undefined) {
69
+ return failure(createError(ErrorCode.UNKNOWN_ERROR, "No result returned"));
70
+ }
71
+ return success(result.data);
72
+ }
73
+ /**
74
+ * Defer multiple tasks by a number of days or to a specific date.
75
+ */
76
+ export async function deferTasks(taskIds, options = {}) {
77
+ // Validate all task IDs first
78
+ for (const id of taskIds) {
79
+ const idError = validateId(id, "task");
80
+ if (idError)
81
+ return failure(idError);
82
+ }
83
+ // Validate that at least one option is provided
84
+ if (options.days === undefined && options.to === undefined) {
85
+ return failure(createError(ErrorCode.VALIDATION_ERROR, "Must specify either --days or --to"));
86
+ }
87
+ // Validate days
88
+ if (options.days !== undefined &&
89
+ (options.days < 1 || !Number.isInteger(options.days))) {
90
+ return failure(createError(ErrorCode.VALIDATION_ERROR, "Days must be a positive integer"));
91
+ }
92
+ // Validate date string if provided
93
+ if (options.to !== undefined) {
94
+ const dateError = validateDateString(options.to);
95
+ if (dateError)
96
+ return failure(dateError);
97
+ }
98
+ // Process in chunks
99
+ const chunks = [];
100
+ for (let i = 0; i < taskIds.length; i += MAX_BATCH_SIZE) {
101
+ chunks.push(taskIds.slice(i, i + MAX_BATCH_SIZE));
102
+ }
103
+ const allSucceeded = [];
104
+ const allFailed = [];
105
+ // Build the defer date logic
106
+ let deferLogic;
107
+ if (options.days !== undefined) {
108
+ deferLogic = `set newDefer to rightNow + (${String(options.days)} * days)`;
109
+ }
110
+ else {
111
+ deferLogic = `set newDefer to date "${escapeAppleScript(options.to ?? "")}"`;
112
+ }
113
+ for (const chunk of chunks) {
114
+ const idsJson = JSON.stringify(chunk);
115
+ const script = `
116
+ set taskIdList to ${idsJson}
117
+ set succeededList to {}
118
+ set failedList to {}
119
+ set rightNow to current date
120
+
121
+ ${deferLogic}
122
+
123
+ repeat with taskIdStr in taskIdList
124
+ try
125
+ set theTask to first flattened task whose id is taskIdStr
126
+
127
+ -- Get previous defer date
128
+ set prevDefer to ""
129
+ try
130
+ set prevDefer to (defer date of theTask) as string
131
+ end try
132
+
133
+ -- Set the defer date
134
+ set defer date of theTask to newDefer
135
+
136
+ -- Get the new defer date as string
137
+ set newDeferStr to (defer date of theTask) as string
138
+
139
+ set end of succeededList to "{" & ¬
140
+ "\\"taskId\\": \\"" & taskIdStr & "\\"," & ¬
141
+ "\\"taskName\\": \\"" & (my escapeJson(name of theTask)) & "\\"," & ¬
142
+ "\\"previousDeferDate\\": " & (my jsonString(prevDefer)) & "," & ¬
143
+ "\\"newDeferDate\\": \\"" & (my escapeJson(newDeferStr)) & "\\"" & ¬
144
+ "}"
145
+ on error errMsg
146
+ set end of failedList to "{" & ¬
147
+ "\\"id\\": \\"" & taskIdStr & "\\"," & ¬
148
+ "\\"error\\": \\"" & (my escapeJson(errMsg)) & "\\"" & ¬
149
+ "}"
150
+ end try
151
+ end repeat
152
+
153
+ set successJson to "["
154
+ set isFirst to true
155
+ repeat with item_ in succeededList
156
+ if not isFirst then set successJson to successJson & ","
157
+ set isFirst to false
158
+ set successJson to successJson & item_
159
+ end repeat
160
+ set successJson to successJson & "]"
161
+
162
+ set failJson to "["
163
+ set isFirst to true
164
+ repeat with item_ in failedList
165
+ if not isFirst then set failJson to failJson & ","
166
+ set isFirst to false
167
+ set failJson to failJson & item_
168
+ end repeat
169
+ set failJson to failJson & "]"
170
+
171
+ return "{" & ¬
172
+ "\\"succeeded\\": " & successJson & "," & ¬
173
+ "\\"failed\\": " & failJson & ¬
174
+ "}"
175
+ `;
176
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
177
+ if (result.success && result.data) {
178
+ allSucceeded.push(...result.data.succeeded);
179
+ allFailed.push(...result.data.failed);
180
+ }
181
+ else {
182
+ // If the entire chunk failed, mark all as failed
183
+ for (const id of chunk) {
184
+ allFailed.push({
185
+ id,
186
+ error: result.error?.message ?? "Unknown error",
187
+ });
188
+ }
189
+ }
190
+ }
191
+ return success({
192
+ succeeded: allSucceeded,
193
+ failed: allFailed,
194
+ totalSucceeded: allSucceeded.length,
195
+ totalFailed: allFailed.length,
196
+ });
197
+ }
198
+ //# sourceMappingURL=defer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defer.js","sourceRoot":"","sources":["../../src/commands/defer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAgC/E,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,UAAwB,EAAE;IAE1B,mBAAmB;IACnB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,gDAAgD;IAChD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC3D,OAAO,OAAO,CACZ,WAAW,CACT,SAAS,CAAC,gBAAgB,EAC1B,oCAAoC,CACrC,CACF,CAAC;IACJ,CAAC;IAED,gBAAgB;IAChB,IACE,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EACrD,CAAC;QACD,OAAO,OAAO,CACZ,WAAW,CAAC,SAAS,CAAC,gBAAgB,EAAE,iCAAiC,CAAC,CAC3E,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACjD,IAAI,SAAS;YAAE,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED,6BAA6B;IAC7B,IAAI,UAAkB,CAAC;IACvB,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,UAAU,GAAG,qCAAqC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;IACnF,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,yBAAyB,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;IAC/E,CAAC;IAED,MAAM,MAAM,GAAG;uDACsC,iBAAiB,CAAC,MAAM,CAAC;;;;;;;;;MAS1E,UAAU;;;;;;;;;0BASU,iBAAiB,CAAC,MAAM,CAAC;;;;;GAKhD,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,0BAA0B,CAAC,MAAM,CAAC,CACnC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,OAAO,CACZ,MAAM,CAAC,KAAK;YACV,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAC/D,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAiB,EACjB,UAAwB,EAAE;IAE1B,8BAA8B;IAC9B,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACvC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,gDAAgD;IAChD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC3D,OAAO,OAAO,CACZ,WAAW,CACT,SAAS,CAAC,gBAAgB,EAC1B,oCAAoC,CACrC,CACF,CAAC;IACJ,CAAC;IAED,gBAAgB;IAChB,IACE,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EACrD,CAAC;QACD,OAAO,OAAO,CACZ,WAAW,CAAC,SAAS,CAAC,gBAAgB,EAAE,iCAAiC,CAAC,CAC3E,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACjD,IAAI,SAAS;YAAE,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED,oBAAoB;IACpB,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,cAAc,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,YAAY,GAAqB,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAoC,EAAE,CAAC;IAEtD,6BAA6B;IAC7B,IAAI,UAAkB,CAAC;IACvB,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,UAAU,GAAG,+BAA+B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;IAC7E,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,yBAAyB,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC;IAC/E,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG;0BACO,OAAO;;;;;QAKzB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsDb,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAGhC,0BAA0B,CAAC,MAAM,CAAC,CAAC,CAAC;QAEvC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAClC,YAAY,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC5C,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,iDAAiD;YACjD,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;gBACvB,SAAS,CAAC,IAAI,CAAC;oBACb,EAAE;oBACF,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,eAAe;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;QACb,SAAS,EAAE,YAAY;QACvB,MAAM,EAAE,SAAS;QACjB,cAAc,EAAE,YAAY,CAAC,MAAM;QACnC,WAAW,EAAE,SAAS,CAAC,MAAM;KAC9B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { CliOutput, OFTask } from "../types.js";
2
+ /**
3
+ * Options for querying deferred tasks.
4
+ */
5
+ export interface DeferredQueryOptions {
6
+ /** Include tasks deferred until after this date */
7
+ deferredAfter?: string | undefined;
8
+ /** Include tasks deferred until before this date */
9
+ deferredBefore?: string | undefined;
10
+ /** Only show tasks that are currently blocked by defer date */
11
+ blockedOnly?: boolean | undefined;
12
+ }
13
+ /**
14
+ * Query all deferred tasks from OmniFocus.
15
+ * Returns tasks that have a defer date set.
16
+ */
17
+ export declare function queryDeferred(options?: DeferredQueryOptions): Promise<CliOutput<OFTask[]>>;
18
+ //# sourceMappingURL=deferred.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/commands/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOrD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAsJ9B"}
@@ -0,0 +1,146 @@
1
+ import { success, failure } from "../result.js";
2
+ import { ErrorCode, createError } from "../errors.js";
3
+ import { runAppleScript, omniFocusScriptWithHelpers } from "../applescript.js";
4
+ import { validateDateString } from "../validation.js";
5
+ import { escapeAppleScript } from "../escape.js";
6
+ /**
7
+ * Query all deferred tasks from OmniFocus.
8
+ * Returns tasks that have a defer date set.
9
+ */
10
+ export async function queryDeferred(options = {}) {
11
+ // Validate date inputs
12
+ if (options.deferredAfter) {
13
+ const afterError = validateDateString(options.deferredAfter);
14
+ if (afterError) {
15
+ return failure(afterError);
16
+ }
17
+ }
18
+ if (options.deferredBefore) {
19
+ const beforeError = validateDateString(options.deferredBefore);
20
+ if (beforeError) {
21
+ return failure(beforeError);
22
+ }
23
+ }
24
+ const blockedOnly = options.blockedOnly === true;
25
+ const escapedDeferredAfter = options.deferredAfter
26
+ ? escapeAppleScript(options.deferredAfter)
27
+ : null;
28
+ const escapedDeferredBefore = options.deferredBefore
29
+ ? escapeAppleScript(options.deferredBefore)
30
+ : null;
31
+ const script = `
32
+ set output to "["
33
+ set isFirst to true
34
+ set rightNow to current date
35
+
36
+ set allTasks to flattened tasks where completed is false and effectively dropped is false
37
+
38
+ repeat with t in allTasks
39
+ set shouldInclude to false
40
+
41
+ -- Check if task has defer date
42
+ try
43
+ set taskDefer to defer date of t
44
+ if taskDefer is not missing value then
45
+ set shouldInclude to true
46
+
47
+ ${blockedOnly
48
+ ? `
49
+ -- Only include if defer date is in the future (currently blocked)
50
+ if taskDefer <= rightNow then
51
+ set shouldInclude to false
52
+ end if
53
+ `
54
+ : ""}
55
+
56
+ ${escapedDeferredAfter
57
+ ? `
58
+ -- Filter by deferred after
59
+ if shouldInclude and taskDefer < date "${escapedDeferredAfter}" then
60
+ set shouldInclude to false
61
+ end if
62
+ `
63
+ : ""}
64
+
65
+ ${escapedDeferredBefore
66
+ ? `
67
+ -- Filter by deferred before
68
+ if shouldInclude and taskDefer > date "${escapedDeferredBefore}" then
69
+ set shouldInclude to false
70
+ end if
71
+ `
72
+ : ""}
73
+ end if
74
+ end try
75
+
76
+ if shouldInclude then
77
+ if not isFirst then set output to output & ","
78
+ set isFirst to false
79
+
80
+ set taskId to id of t
81
+ set taskName to name of t
82
+ set taskNote to note of t
83
+ set taskFlagged to flagged of t
84
+ set taskCompleted to completed of t
85
+
86
+ set dueStr to ""
87
+ try
88
+ set dueStr to (due date of t) as string
89
+ end try
90
+
91
+ set deferStr to ""
92
+ try
93
+ set deferStr to (defer date of t) as string
94
+ end try
95
+
96
+ set completionStr to ""
97
+ try
98
+ set completionStr to (completion date of t) as string
99
+ end try
100
+
101
+ set projId to ""
102
+ set projName to ""
103
+ try
104
+ set proj to containing project of t
105
+ set projId to id of proj
106
+ set projName to name of proj
107
+ end try
108
+
109
+ set tagNames to {}
110
+ repeat with tg in tags of t
111
+ set end of tagNames to name of tg
112
+ end repeat
113
+
114
+ set estMinutes to 0
115
+ try
116
+ set estMinutes to estimated minutes of t
117
+ if estMinutes is missing value then set estMinutes to 0
118
+ end try
119
+
120
+ set output to output & "{" & ¬
121
+ "\\"id\\": \\"" & taskId & "\\"," & ¬
122
+ "\\"name\\": \\"" & (my escapeJson(taskName)) & "\\"," & ¬
123
+ "\\"note\\": " & (my jsonString(taskNote)) & "," & ¬
124
+ "\\"flagged\\": " & taskFlagged & "," & ¬
125
+ "\\"completed\\": " & taskCompleted & "," & ¬
126
+ "\\"dueDate\\": " & (my jsonString(dueStr)) & "," & ¬
127
+ "\\"deferDate\\": " & (my jsonString(deferStr)) & "," & ¬
128
+ "\\"completionDate\\": " & (my jsonString(completionStr)) & "," & ¬
129
+ "\\"projectId\\": " & (my jsonString(projId)) & "," & ¬
130
+ "\\"projectName\\": " & (my jsonString(projName)) & "," & ¬
131
+ "\\"tags\\": " & (my jsonArray(tagNames)) & "," & ¬
132
+ "\\"estimatedMinutes\\": " & estMinutes & ¬
133
+ "}"
134
+ end if
135
+ end repeat
136
+
137
+ return output & "]"
138
+ `;
139
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
140
+ if (!result.success) {
141
+ return failure(result.error ??
142
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to query deferred tasks"));
143
+ }
144
+ return success(result.data ?? []);
145
+ }
146
+ //# sourceMappingURL=deferred.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/commands/deferred.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAcjD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAgC,EAAE;IAElC,uBAAuB;IACvB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC7D,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC/D,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,oBAAoB,GAAG,OAAO,CAAC,aAAa;QAChD,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,aAAa,CAAC;QAC1C,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,qBAAqB,GAAG,OAAO,CAAC,cAAc;QAClD,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,cAAc,CAAC;QAC3C,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;YAiBL,WAAW;QACT,CAAC,CAAC;;;;;WAKL;QACG,CAAC,CAAC,EACN;;YAGE,oBAAoB;QAClB,CAAC,CAAC;;mDAEmC,oBAAoB;;;WAG5D;QACG,CAAC,CAAC,EACN;;YAGE,qBAAqB;QACnB,CAAC,CAAC;;mDAEmC,qBAAqB;;;WAG7D;QACG,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEP,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,0BAA0B,CAAC,MAAM,CAAC,CACnC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,OAAO,CACZ,MAAM,CAAC,KAAK;YACV,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,gCAAgC,CAAC,CACzE,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { CliOutput, DuplicateTaskOptions } from "../types.js";
2
+ /**
3
+ * Result from duplicating a task.
4
+ */
5
+ export interface DuplicateTaskResult {
6
+ originalTaskId: string;
7
+ newTaskId: string;
8
+ newTaskName: string;
9
+ }
10
+ /**
11
+ * Duplicate a task in OmniFocus.
12
+ * Creates a copy of the task with all its properties.
13
+ */
14
+ export declare function duplicateTask(taskId: string, options?: DuplicateTaskOptions): Promise<CliOutput<DuplicateTaskResult>>;
15
+ //# sourceMappingURL=duplicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../../src/commands/duplicate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAOnE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAgDzC"}
@@ -0,0 +1,49 @@
1
+ import { success, failure } from "../result.js";
2
+ import { ErrorCode, createError } from "../errors.js";
3
+ import { validateId } from "../validation.js";
4
+ import { escapeAppleScript } from "../escape.js";
5
+ import { runAppleScript, omniFocusScriptWithHelpers } from "../applescript.js";
6
+ /**
7
+ * Duplicate a task in OmniFocus.
8
+ * Creates a copy of the task with all its properties.
9
+ */
10
+ export async function duplicateTask(taskId, options = {}) {
11
+ // Validate task ID
12
+ const idError = validateId(taskId, "task");
13
+ if (idError)
14
+ return failure(idError);
15
+ // Default to including subtasks
16
+ const includeSubtasks = options.includeSubtasks !== false;
17
+ // AppleScript's duplicate command includes subtasks by default
18
+ // We need to handle the case where we don't want subtasks
19
+ const duplicateScript = includeSubtasks
20
+ ? `set newTask to duplicate theTask`
21
+ : `set newTask to duplicate theTask
22
+ -- Remove subtasks if not including them (iterate in reverse to avoid skipping)
23
+ repeat with i from (count of tasks of newTask) to 1 by -1
24
+ delete task i of newTask
25
+ end repeat`;
26
+ const script = `
27
+ set theTask to first flattened task whose id is "${escapeAppleScript(taskId)}"
28
+ ${duplicateScript}
29
+
30
+ set newId to id of newTask
31
+ set newName to name of newTask
32
+
33
+ return "{" & ¬
34
+ "\\"originalTaskId\\": \\"${escapeAppleScript(taskId)}\\"," & ¬
35
+ "\\"newTaskId\\": \\"" & newId & "\\"," & ¬
36
+ "\\"newTaskName\\": \\"" & (my escapeJson(newName)) & "\\"" & ¬
37
+ "}"
38
+ `;
39
+ const result = await runAppleScript(omniFocusScriptWithHelpers(script));
40
+ if (!result.success) {
41
+ return failure(result.error ??
42
+ createError(ErrorCode.UNKNOWN_ERROR, "Failed to duplicate task"));
43
+ }
44
+ if (result.data === undefined) {
45
+ return failure(createError(ErrorCode.UNKNOWN_ERROR, "No result returned"));
46
+ }
47
+ return success(result.data);
48
+ }
49
+ //# sourceMappingURL=duplicate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate.js","sourceRoot":"","sources":["../../src/commands/duplicate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAW/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,UAAgC,EAAE;IAElC,mBAAmB;IACnB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,gCAAgC;IAChC,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,KAAK,KAAK,CAAC;IAE1D,+DAA+D;IAC/D,0DAA0D;IAC1D,MAAM,eAAe,GAAG,eAAe;QACrC,CAAC,CAAC,kCAAkC;QACpC,CAAC,CAAC;;;;kBAIY,CAAC;IAEjB,MAAM,MAAM,GAAG;uDACsC,iBAAiB,CAAC,MAAM,CAAC;MAC1E,eAAe;;;;;;kCAMa,iBAAiB,CAAC,MAAM,CAAC;;;;GAIxD,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,0BAA0B,CAAC,MAAM,CAAC,CACnC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,OAAO,CACZ,MAAM,CAAC,KAAK;YACV,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,0BAA0B,CAAC,CACnE,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}