@nocoo/zhe 1.18.0 → 1.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/idea/add.d.ts +22 -0
- package/dist/commands/idea/add.d.ts.map +1 -0
- package/dist/commands/idea/add.js +55 -0
- package/dist/commands/idea/add.js.map +1 -0
- package/dist/commands/idea/delete.d.ts +17 -0
- package/dist/commands/idea/delete.d.ts.map +1 -0
- package/dist/commands/idea/delete.js +47 -0
- package/dist/commands/idea/delete.js.map +1 -0
- package/dist/commands/idea/get.d.ts +12 -0
- package/dist/commands/idea/get.d.ts.map +1 -0
- package/dist/commands/idea/get.js +45 -0
- package/dist/commands/idea/get.js.map +1 -0
- package/dist/commands/idea/helpers.d.ts +13 -0
- package/dist/commands/idea/helpers.d.ts.map +1 -0
- package/dist/commands/idea/helpers.js +78 -0
- package/dist/commands/idea/helpers.js.map +1 -0
- package/dist/commands/idea/list.d.ts +22 -0
- package/dist/commands/idea/list.d.ts.map +1 -0
- package/dist/commands/idea/list.js +64 -0
- package/dist/commands/idea/list.js.map +1 -0
- package/dist/commands/idea/update.d.ts +27 -0
- package/dist/commands/idea/update.d.ts.map +1 -0
- package/dist/commands/idea/update.js +78 -0
- package/dist/commands/idea/update.js.map +1 -0
- package/dist/commands/idea.d.ts +6 -2
- package/dist/commands/idea.d.ts.map +1 -1
- package/dist/commands/idea.js +12 -393
- package/dist/commands/idea.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +97 -96
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +56 -59
- package/dist/commands/update.js.map +1 -1
- package/dist/utils/format.d.ts +27 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +157 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/resolve.d.ts +41 -0
- package/dist/utils/resolve.d.ts.map +1 -0
- package/dist/utils/resolve.js +69 -0
- package/dist/utils/resolve.js.map +1 -0
- package/dist/utils.d.ts +17 -90
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +20 -250
- package/dist/utils.js.map +1 -1
- package/package.json +10 -6
package/dist/commands/idea.js
CHANGED
|
@@ -1,398 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* zhe idea — Manage ideas (Markdown notes)
|
|
2
|
+
* zhe idea — Manage ideas (Markdown notes).
|
|
3
|
+
*
|
|
4
|
+
* Subcommand implementations live in ./idea/*.ts to keep this file small.
|
|
5
|
+
* `formatTags` is re-exported here for tests that import from
|
|
6
|
+
* `commands/idea.js`.
|
|
3
7
|
*/
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const apiKey = getApiKey();
|
|
12
|
-
if (!apiKey) {
|
|
13
|
-
console.log(pc.red("Not authenticated. Run `zhe login` first."));
|
|
14
|
-
process.exit(EXIT_AUTH_REQUIRED);
|
|
15
|
-
}
|
|
16
|
-
return apiKey;
|
|
17
|
-
}
|
|
18
|
-
function handleApiError(error) {
|
|
19
|
-
if (error instanceof ApiClientError) {
|
|
20
|
-
if (error.status === 400) {
|
|
21
|
-
console.log(pc.red(`Error: ${error.message}`));
|
|
22
|
-
}
|
|
23
|
-
else if (error.status === 404) {
|
|
24
|
-
console.log(pc.red("Idea not found."));
|
|
25
|
-
process.exit(EXIT_NOT_FOUND);
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
console.log(pc.red(`Error: ${error.message}`));
|
|
29
|
-
}
|
|
30
|
-
if (error.status === 401) {
|
|
31
|
-
process.exit(EXIT_AUTH_REQUIRED);
|
|
32
|
-
}
|
|
33
|
-
if (error.status === 429) {
|
|
34
|
-
process.exit(EXIT_RATE_LIMITED);
|
|
35
|
-
}
|
|
36
|
-
process.exit(EXIT_ERROR);
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
function formatDate(isoDate) {
|
|
41
|
-
const date = new Date(isoDate);
|
|
42
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
43
|
-
month: "short",
|
|
44
|
-
day: "numeric",
|
|
45
|
-
year: "numeric",
|
|
46
|
-
hour: "numeric",
|
|
47
|
-
minute: "2-digit",
|
|
48
|
-
}).format(date);
|
|
49
|
-
}
|
|
50
|
-
export function formatTags(tagIds, tagMap) {
|
|
51
|
-
if (!tagIds || tagIds.length === 0)
|
|
52
|
-
return "";
|
|
53
|
-
return tagIds.map((id) => `[${tagMap?.get(id) ?? id.slice(0, 8)}]`).join(" ");
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Build a tagId→name map by fetching all tags from API.
|
|
57
|
-
* Returns undefined on failure (display degrades to truncated IDs).
|
|
58
|
-
*/
|
|
59
|
-
async function buildTagMap(client, tagIds) {
|
|
60
|
-
if (tagIds.length === 0)
|
|
61
|
-
return undefined;
|
|
62
|
-
try {
|
|
63
|
-
const { tags } = await client.listTags();
|
|
64
|
-
return new Map(tags.map((t) => [t.id, t.name]));
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
async function confirm(message) {
|
|
71
|
-
return new Promise((resolve) => {
|
|
72
|
-
const rl = readline.createInterface({
|
|
73
|
-
input: process.stdin,
|
|
74
|
-
output: process.stdout,
|
|
75
|
-
});
|
|
76
|
-
rl.question(`${message} [y/N] `, (answer) => {
|
|
77
|
-
rl.close();
|
|
78
|
-
resolve(answer.toLowerCase() === "y");
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
// ── Subcommands ──
|
|
83
|
-
const listSubcommand = defineCommand({
|
|
84
|
-
meta: {
|
|
85
|
-
name: "list",
|
|
86
|
-
description: "List all ideas",
|
|
87
|
-
},
|
|
88
|
-
args: {
|
|
89
|
-
limit: {
|
|
90
|
-
type: "string",
|
|
91
|
-
alias: "l",
|
|
92
|
-
description: "Max results (default: 20)",
|
|
93
|
-
},
|
|
94
|
-
tag: {
|
|
95
|
-
type: "string",
|
|
96
|
-
alias: "t",
|
|
97
|
-
description: "Filter by tag name",
|
|
98
|
-
},
|
|
99
|
-
query: {
|
|
100
|
-
type: "string",
|
|
101
|
-
alias: "q",
|
|
102
|
-
description: "Search title and excerpt",
|
|
103
|
-
},
|
|
104
|
-
json: {
|
|
105
|
-
type: "boolean",
|
|
106
|
-
description: "Output as JSON",
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
async run({ args }) {
|
|
110
|
-
const apiKey = requireAuth();
|
|
111
|
-
const client = new ApiClient(apiKey);
|
|
112
|
-
try {
|
|
113
|
-
// Resolve tag name to ID if provided
|
|
114
|
-
let tagId;
|
|
115
|
-
if (args.tag) {
|
|
116
|
-
const resolved = await resolveTagName(client, args.tag);
|
|
117
|
-
if (resolved === null) {
|
|
118
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
119
|
-
}
|
|
120
|
-
tagId = resolved;
|
|
121
|
-
}
|
|
122
|
-
const response = await client.listIdeas({
|
|
123
|
-
limit: args.limit ? Number.parseInt(args.limit, 10) : 20,
|
|
124
|
-
tagId,
|
|
125
|
-
q: args.query,
|
|
126
|
-
});
|
|
127
|
-
if (args.json) {
|
|
128
|
-
console.log(JSON.stringify(response, null, 2));
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (response.ideas.length === 0) {
|
|
132
|
-
console.log(pc.yellow("No ideas found."));
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
// Build tag name map for display (like links' folder prefetch)
|
|
136
|
-
const allTagIds = response.ideas.flatMap((i) => i.tagIds ?? []);
|
|
137
|
-
const tagMap = await buildTagMap(client, allTagIds);
|
|
138
|
-
// Table format
|
|
139
|
-
console.log(pc.dim("ID TIME TITLE TAGS"));
|
|
140
|
-
console.log(pc.dim("─".repeat(56)));
|
|
141
|
-
for (const idea of response.ideas) {
|
|
142
|
-
const time = formatDate(idea.createdAt);
|
|
143
|
-
const title = (idea.title || idea.excerpt || "(no content)").slice(0, 24);
|
|
144
|
-
const tags = formatTags(idea.tagIds, tagMap);
|
|
145
|
-
console.log(`${pc.cyan(String(idea.id).padEnd(6))}${time.padEnd(17)}${title.padEnd(25)}${pc.yellow(tags)}`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
handleApiError(error);
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
});
|
|
153
|
-
const getSubcommand = defineCommand({
|
|
154
|
-
meta: {
|
|
155
|
-
name: "get",
|
|
156
|
-
description: "Get full content of an idea",
|
|
157
|
-
},
|
|
158
|
-
args: {
|
|
159
|
-
id: {
|
|
160
|
-
type: "positional",
|
|
161
|
-
description: "Idea ID",
|
|
162
|
-
required: true,
|
|
163
|
-
},
|
|
164
|
-
json: {
|
|
165
|
-
type: "boolean",
|
|
166
|
-
description: "Output as JSON",
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
async run({ args }) {
|
|
170
|
-
const apiKey = requireAuth();
|
|
171
|
-
const client = new ApiClient(apiKey);
|
|
172
|
-
const id = parsePositiveInt(args.id);
|
|
173
|
-
if (id === null) {
|
|
174
|
-
console.log(pc.red("Invalid idea ID."));
|
|
175
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
const response = await client.getIdea(id);
|
|
179
|
-
if (args.json) {
|
|
180
|
-
console.log(JSON.stringify(response, null, 2));
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const { idea } = response;
|
|
184
|
-
const tagMap = await buildTagMap(client, idea.tagIds ?? []);
|
|
185
|
-
const tags = formatTags(idea.tagIds, tagMap);
|
|
186
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
187
|
-
console.log(pc.dim("─".repeat(40)));
|
|
188
|
-
console.log(`Idea ${pc.cyan(`#${idea.id}`)} — ${pc.bold(title)}`);
|
|
189
|
-
if (tags)
|
|
190
|
-
console.log(`Tags: ${pc.yellow(tags)}`);
|
|
191
|
-
console.log(pc.dim("─".repeat(40)));
|
|
192
|
-
console.log();
|
|
193
|
-
console.log(idea.content);
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
handleApiError(error);
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
const addSubcommand = defineCommand({
|
|
201
|
-
meta: {
|
|
202
|
-
name: "add",
|
|
203
|
-
description: "Create a new idea",
|
|
204
|
-
},
|
|
205
|
-
args: {
|
|
206
|
-
content: {
|
|
207
|
-
type: "positional",
|
|
208
|
-
description: "Idea content (Markdown)",
|
|
209
|
-
required: true,
|
|
210
|
-
},
|
|
211
|
-
title: {
|
|
212
|
-
type: "string",
|
|
213
|
-
alias: "t",
|
|
214
|
-
description: "Optional title",
|
|
215
|
-
},
|
|
216
|
-
tag: {
|
|
217
|
-
type: "string",
|
|
218
|
-
alias: "T",
|
|
219
|
-
description: "Add tag by name",
|
|
220
|
-
},
|
|
221
|
-
json: {
|
|
222
|
-
type: "boolean",
|
|
223
|
-
description: "Output as JSON",
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
async run({ args }) {
|
|
227
|
-
const apiKey = requireAuth();
|
|
228
|
-
const client = new ApiClient(apiKey);
|
|
229
|
-
const content = args.content;
|
|
230
|
-
if (!content.trim()) {
|
|
231
|
-
console.log(pc.red("Content cannot be empty."));
|
|
232
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
233
|
-
}
|
|
234
|
-
try {
|
|
235
|
-
// Resolve tag name to ID if provided
|
|
236
|
-
let tagIds;
|
|
237
|
-
if (args.tag) {
|
|
238
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
239
|
-
if (tagId === null) {
|
|
240
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
241
|
-
}
|
|
242
|
-
tagIds = [tagId];
|
|
243
|
-
}
|
|
244
|
-
const request = {
|
|
245
|
-
content,
|
|
246
|
-
...(args.title && { title: args.title }),
|
|
247
|
-
...(tagIds && { tagIds }),
|
|
248
|
-
};
|
|
249
|
-
const response = await client.createIdea(request);
|
|
250
|
-
if (args.json) {
|
|
251
|
-
console.log(JSON.stringify(response, null, 2));
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
const { idea } = response;
|
|
255
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
256
|
-
console.log(pc.green(`✓ Created idea ${pc.cyan(`#${idea.id}`)} (${title})`));
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
handleApiError(error);
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
const updateSubcommand = defineCommand({
|
|
264
|
-
meta: {
|
|
265
|
-
name: "update",
|
|
266
|
-
description: "Update an existing idea",
|
|
267
|
-
},
|
|
268
|
-
args: {
|
|
269
|
-
id: {
|
|
270
|
-
type: "positional",
|
|
271
|
-
description: "Idea ID",
|
|
272
|
-
required: true,
|
|
273
|
-
},
|
|
274
|
-
content: {
|
|
275
|
-
type: "string",
|
|
276
|
-
alias: "c",
|
|
277
|
-
description: "New content",
|
|
278
|
-
},
|
|
279
|
-
title: {
|
|
280
|
-
type: "string",
|
|
281
|
-
alias: "t",
|
|
282
|
-
description: "New title (use empty string to clear)",
|
|
283
|
-
},
|
|
284
|
-
tag: {
|
|
285
|
-
type: "string",
|
|
286
|
-
alias: "T",
|
|
287
|
-
description: "Set tag by name (replaces all existing tags)",
|
|
288
|
-
},
|
|
289
|
-
json: {
|
|
290
|
-
type: "boolean",
|
|
291
|
-
description: "Output as JSON",
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
async run({ args }) {
|
|
295
|
-
const apiKey = requireAuth();
|
|
296
|
-
const client = new ApiClient(apiKey);
|
|
297
|
-
const id = parsePositiveInt(args.id);
|
|
298
|
-
if (id === null) {
|
|
299
|
-
console.log(pc.red("Invalid idea ID."));
|
|
300
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
301
|
-
}
|
|
302
|
-
// Build update request
|
|
303
|
-
const request = {};
|
|
304
|
-
if (args.content !== undefined)
|
|
305
|
-
request.content = args.content;
|
|
306
|
-
if (args.title !== undefined) {
|
|
307
|
-
request.title = args.title === "" ? null : args.title;
|
|
308
|
-
}
|
|
309
|
-
// Resolve tag name if provided
|
|
310
|
-
if (args.tag !== undefined) {
|
|
311
|
-
if (args.tag === "") {
|
|
312
|
-
// Empty string means clear all tags
|
|
313
|
-
request.tagIds = [];
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
317
|
-
if (tagId === null) {
|
|
318
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
319
|
-
}
|
|
320
|
-
request.tagIds = [tagId];
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (Object.keys(request).length === 0) {
|
|
324
|
-
console.log(pc.yellow("No changes specified."));
|
|
325
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
const response = await client.updateIdea(id, request);
|
|
329
|
-
if (args.json) {
|
|
330
|
-
console.log(JSON.stringify(response, null, 2));
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
const { idea } = response;
|
|
334
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
335
|
-
console.log(pc.green(`✓ Updated idea ${pc.cyan(`#${idea.id}`)} (${title})`));
|
|
336
|
-
}
|
|
337
|
-
catch (error) {
|
|
338
|
-
handleApiError(error);
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
const deleteSubcommand = defineCommand({
|
|
343
|
-
meta: {
|
|
344
|
-
name: "delete",
|
|
345
|
-
description: "Delete an idea",
|
|
346
|
-
},
|
|
347
|
-
args: {
|
|
348
|
-
id: {
|
|
349
|
-
type: "positional",
|
|
350
|
-
description: "Idea ID",
|
|
351
|
-
required: true,
|
|
352
|
-
},
|
|
353
|
-
yes: {
|
|
354
|
-
type: "boolean",
|
|
355
|
-
alias: "y",
|
|
356
|
-
description: "Skip confirmation",
|
|
357
|
-
},
|
|
358
|
-
json: {
|
|
359
|
-
type: "boolean",
|
|
360
|
-
description: "Output as JSON",
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
async run({ args }) {
|
|
364
|
-
const apiKey = requireAuth();
|
|
365
|
-
const client = new ApiClient(apiKey);
|
|
366
|
-
const id = parsePositiveInt(args.id);
|
|
367
|
-
if (id === null) {
|
|
368
|
-
console.log(pc.red("Invalid idea ID."));
|
|
369
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
370
|
-
}
|
|
371
|
-
try {
|
|
372
|
-
// Only fetch idea for confirmation prompt (requires ideas:read)
|
|
373
|
-
// With --yes flag, skip prefetch to allow write-only keys
|
|
374
|
-
if (!args.yes) {
|
|
375
|
-
const { idea } = await client.getIdea(id);
|
|
376
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
377
|
-
const confirmed = await confirm(`Delete idea #${id} (${title})?`);
|
|
378
|
-
if (!confirmed) {
|
|
379
|
-
console.log(pc.dim("Cancelled."));
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
await client.deleteIdea(id);
|
|
384
|
-
if (args.json) {
|
|
385
|
-
console.log(JSON.stringify({ success: true, id }, null, 2));
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
console.log(pc.green(`✓ Deleted idea ${pc.cyan(`#${id}`)}`));
|
|
389
|
-
}
|
|
390
|
-
catch (error) {
|
|
391
|
-
handleApiError(error);
|
|
392
|
-
}
|
|
393
|
-
},
|
|
394
|
-
});
|
|
395
|
-
// ── Main command ──
|
|
8
|
+
import { defineCommand } from "@nocoo/cli-base";
|
|
9
|
+
import { addSubcommand } from "./idea/add.js";
|
|
10
|
+
import { deleteSubcommand } from "./idea/delete.js";
|
|
11
|
+
import { getSubcommand } from "./idea/get.js";
|
|
12
|
+
import { listSubcommand } from "./idea/list.js";
|
|
13
|
+
import { updateSubcommand } from "./idea/update.js";
|
|
14
|
+
export { formatTags } from "./idea/helpers.js";
|
|
396
15
|
export const ideaCommand = defineCommand({
|
|
397
16
|
meta: {
|
|
398
17
|
name: "idea",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idea.js","sourceRoot":"","sources":["../../src/commands/idea.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACN,SAAS,EACT,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,iBAAiB,GACjB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/D,gBAAgB;AAEhB,SAAS,WAAW;IACnB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACrC,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,KAAK,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IAClC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QACvC,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KACjB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,UAAU,CACzB,MAAmC,EACnC,MAA4B;IAE5B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,WAAW,CACzB,MAAiB,EACjB,MAAgB;IAEhB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC;QACJ,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YACnC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACtB,CAAC,CAAC;QAEH,EAAE,CAAC,QAAQ,CAAC,GAAG,OAAO,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YAC3C,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,oBAAoB;AAEpB,MAAM,cAAc,GAAG,aAAa,CAAC;IACpC,IAAI,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,gBAAgB;KAC7B;IACD,IAAI,EAAE;QACL,KAAK,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,2BAA2B;SACxC;QACD,GAAG,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,oBAAoB;SACjC;QACD,KAAK,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,0BAA0B;SACvC;QACD,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gBAAgB;SAC7B;KACD;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,CAAC;YACJ,qCAAqC;YACrC,IAAI,KAAyB,CAAC;YAC9B,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACd,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACxD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBACvB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACjC,CAAC;gBACD,KAAK,GAAG,QAAQ,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC;gBACvC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;gBACxD,KAAK;gBACL,CAAC,EAAE,IAAI,CAAC,KAAK;aACb,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACR,CAAC;YAED,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAC1C,OAAO;YACR,CAAC;YAED,+DAA+D;YAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YAChE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAEpD,eAAe;YACf,OAAO,CAAC,GAAG,CACV,EAAE,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAC9D,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAEpC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACnC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACxC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC,KAAK,CACjE,CAAC,EACD,EAAE,CACF,CAAC;gBACF,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC7C,OAAO,CAAC,GAAG,CACV,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAC9F,CAAC;YACH,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,cAAc,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,aAAa,CAAC;IACnC,IAAI,EAAE;QACL,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,6BAA6B;KAC1C;IACD,IAAI,EAAE;QACL,EAAE,EAAE;YACH,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,SAAS;YACtB,QAAQ,EAAE,IAAI;SACd;QACD,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gBAAgB;SAC7B;KACD;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAErC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC;QAC/C,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAE1C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACR,CAAC;YAED,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;YAC1B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAEvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClE,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,cAAc,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,aAAa,CAAC;IACnC,IAAI,EAAE;QACL,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,mBAAmB;KAChC;IACD,IAAI,EAAE;QACL,OAAO,EAAE;YACR,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,yBAAyB;YACtC,QAAQ,EAAE,IAAI;SACd;QACD,KAAK,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,gBAAgB;SAC7B;QACD,GAAG,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,iBAAiB;SAC9B;QACD,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gBAAgB;SAC7B;KACD;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAiB,CAAC;QACvC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC;YACJ,qCAAqC;YACrC,IAAI,MAA4B,CAAC;YACjC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACd,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACrD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBACpB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACjC,CAAC;gBACD,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,OAAO,GAAsB;gBAClC,OAAO;gBACP,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACxC,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;aACzB,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAElD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACR,CAAC;YAED,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CACV,EAAE,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAC/D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,cAAc,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,aAAa,CAAC;IACtC,IAAI,EAAE;QACL,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,yBAAyB;KACtC;IACD,IAAI,EAAE;QACL,EAAE,EAAE;YACH,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,SAAS;YACtB,QAAQ,EAAE,IAAI;SACd;QACD,OAAO,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,aAAa;SAC1B;QACD,KAAK,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,uCAAuC;SACpD;QACD,GAAG,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,8CAA8C;SAC3D;QACD,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gBAAgB;SAC7B;KACD;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAErC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC;QAC/C,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,uBAAuB;QACvB,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC/D,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACvD,CAAC;QAED,+BAA+B;QAC/B,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC;gBACrB,oCAAoC;gBACpC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACP,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACrD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBACpB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBACjC,CAAC;gBACD,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;YAC1B,CAAC;QACF,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEtD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACR,CAAC;YAED,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CACV,EAAE,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,GAAG,CAAC,CAC/D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,cAAc,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,aAAa,CAAC;IACtC,IAAI,EAAE;QACL,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,gBAAgB;KAC7B;IACD,IAAI,EAAE;QACL,EAAE,EAAE;YACH,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,SAAS;YACtB,QAAQ,EAAE,IAAI;SACd;QACD,GAAG,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,GAAG;YACV,WAAW,EAAE,mBAAmB;SAChC;QACD,IAAI,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,gBAAgB;SAC7B;KACD;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAErC,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC;QAC/C,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC;YACJ,gEAAgE;YAChE,0DAA0D;YAC1D,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACf,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAEvD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,gBAAgB,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;gBAClE,IAAI,CAAC,SAAS,EAAE,CAAC;oBAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;oBAClC,OAAO;gBACR,CAAC;YACF,CAAC;YAED,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAE5B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC5D,OAAO;YACR,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,cAAc,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;CACD,CAAC,CAAC;AAEH,qBAAqB;AAErB,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACxC,IAAI,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,+BAA+B;KAC5C;IACD,WAAW,EAAE;QACZ,IAAI,EAAE,cAAc;QACpB,GAAG,EAAE,aAAa;QAClB,GAAG,EAAE,aAAa;QAClB,MAAM,EAAE,gBAAgB;QACxB,MAAM,EAAE,gBAAgB;KACxB;CACD,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"idea.js","sourceRoot":"","sources":["../../src/commands/idea.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACxC,IAAI,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,+BAA+B;KAC5C;IACD,WAAW,EAAE;QACZ,IAAI,EAAE,cAAc;QACpB,GAAG,EAAE,aAAa;QAClB,GAAG,EAAE,aAAa;QAClB,MAAM,EAAE,gBAAgB;QACxB,MAAM,EAAE,gBAAgB;KACxB;CACD,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkJH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6HtB,CAAC"}
|
package/dist/commands/list.js
CHANGED
|
@@ -5,6 +5,100 @@ import { defineCommand, pc } from "@nocoo/cli-base";
|
|
|
5
5
|
import { ApiClient, ApiClientError, EXIT_AUTH_REQUIRED, EXIT_ERROR, EXIT_INVALID_ARGS, EXIT_RATE_LIMITED, } from "../api/client.js";
|
|
6
6
|
import { getApiKey, getOutputFormat } from "../config.js";
|
|
7
7
|
import { formatLinksMinimal, formatLinksTable, resolveTagName, } from "../utils.js";
|
|
8
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9
|
+
/** Reject mutually-exclusive flags + invalid sort/order. Exits on error. */
|
|
10
|
+
function validateListArgs(args) {
|
|
11
|
+
if (args.inbox && args.folder) {
|
|
12
|
+
console.log(pc.red("Cannot use --inbox and --folder together."));
|
|
13
|
+
process.exit(EXIT_INVALID_ARGS);
|
|
14
|
+
}
|
|
15
|
+
if (args.sort && args.sort !== "created" && args.sort !== "clicks") {
|
|
16
|
+
console.log(pc.red("Invalid --sort value. Use 'created' or 'clicks'."));
|
|
17
|
+
process.exit(EXIT_INVALID_ARGS);
|
|
18
|
+
}
|
|
19
|
+
if (args.order && args.order !== "asc" && args.order !== "desc") {
|
|
20
|
+
console.log(pc.red("Invalid --order value. Use 'asc' or 'desc'."));
|
|
21
|
+
process.exit(EXIT_INVALID_ARGS);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build ListLinksParams from CLI args, resolving folder/tag names where
|
|
26
|
+
* needed. Returns the params plus any folder list already fetched for reuse.
|
|
27
|
+
* Exits on invalid folder/tag.
|
|
28
|
+
*/
|
|
29
|
+
async function buildListParams(client, args) {
|
|
30
|
+
// Pre-fetch folders only when --folder is a non-UUID name that must be
|
|
31
|
+
// resolved (a UUID can be used directly without folders:read scope).
|
|
32
|
+
const folderArg = args.folder;
|
|
33
|
+
const needsFolderResolution = !!folderArg && !UUID_PATTERN.test(folderArg);
|
|
34
|
+
let cachedFolders;
|
|
35
|
+
if (needsFolderResolution) {
|
|
36
|
+
const foldersResponse = await client.listFolders();
|
|
37
|
+
cachedFolders = foldersResponse.folders;
|
|
38
|
+
}
|
|
39
|
+
const params = {};
|
|
40
|
+
if (args.limit)
|
|
41
|
+
params.limit = Number.parseInt(args.limit, 10);
|
|
42
|
+
if (args.offset)
|
|
43
|
+
params.offset = Number.parseInt(args.offset, 10);
|
|
44
|
+
if (args.query)
|
|
45
|
+
params.query = args.query;
|
|
46
|
+
if (args.inbox)
|
|
47
|
+
params.inbox = true;
|
|
48
|
+
if (args.sort)
|
|
49
|
+
params.sort = args.sort;
|
|
50
|
+
if (args.order)
|
|
51
|
+
params.order = args.order;
|
|
52
|
+
if (folderArg) {
|
|
53
|
+
if (UUID_PATTERN.test(folderArg)) {
|
|
54
|
+
params.folderId = folderArg;
|
|
55
|
+
}
|
|
56
|
+
else if (cachedFolders) {
|
|
57
|
+
const folderId = resolveFolderNameFromCache(folderArg, cachedFolders);
|
|
58
|
+
if (folderId === null)
|
|
59
|
+
process.exit(EXIT_INVALID_ARGS);
|
|
60
|
+
params.folderId = folderId;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (args.tag) {
|
|
64
|
+
const tagId = await resolveTagName(client, args.tag);
|
|
65
|
+
if (tagId === null)
|
|
66
|
+
process.exit(EXIT_INVALID_ARGS);
|
|
67
|
+
params.tagId = tagId;
|
|
68
|
+
}
|
|
69
|
+
return cachedFolders ? { params, cachedFolders } : { params };
|
|
70
|
+
}
|
|
71
|
+
/** Build folder + tag name maps for table output, with graceful fallback. */
|
|
72
|
+
async function loadDisplayMaps(client, links, cachedFolders, showTags) {
|
|
73
|
+
const result = {};
|
|
74
|
+
const hasFolders = links.some((l) => l.folderId);
|
|
75
|
+
if (hasFolders) {
|
|
76
|
+
try {
|
|
77
|
+
const folders = cachedFolders ?? (await client.listFolders()).folders;
|
|
78
|
+
result.folderMap = new Map(folders.map((f) => [f.id, f.name]));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// continue without folder names
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Build tag name map only when we will render tags AND the response is
|
|
85
|
+
// missing embedded tag details. The /links endpoint already includes
|
|
86
|
+
// `tags: Tag[]` per link, so a successful response makes listTags()
|
|
87
|
+
// unnecessary; we only fall back when some tagged link is missing its
|
|
88
|
+
// tags array (older server, or partial response).
|
|
89
|
+
const needsTagFallback = showTags &&
|
|
90
|
+
links.some((l) => (l.tagIds ?? []).length > 0 && (!l.tags || l.tags.length === 0));
|
|
91
|
+
if (needsTagFallback) {
|
|
92
|
+
try {
|
|
93
|
+
const tagsResponse = await client.listTags();
|
|
94
|
+
result.tagMap = new Map(tagsResponse.tags.map((t) => [t.id, t.name]));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// continue without tag names
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
8
102
|
export const listCommand = defineCommand({
|
|
9
103
|
meta: {
|
|
10
104
|
name: "list",
|
|
@@ -79,110 +173,17 @@ export const listCommand = defineCommand({
|
|
|
79
173
|
console.log(pc.red("Not authenticated. Run `zhe login` first."));
|
|
80
174
|
process.exit(EXIT_AUTH_REQUIRED);
|
|
81
175
|
}
|
|
82
|
-
|
|
83
|
-
if (args.inbox && args.folder) {
|
|
84
|
-
console.log(pc.red("Cannot use --inbox and --folder together."));
|
|
85
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
86
|
-
}
|
|
87
|
-
// Validate sort option
|
|
88
|
-
if (args.sort && args.sort !== "created" && args.sort !== "clicks") {
|
|
89
|
-
console.log(pc.red("Invalid --sort value. Use 'created' or 'clicks'."));
|
|
90
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
91
|
-
}
|
|
92
|
-
// Validate order option
|
|
93
|
-
if (args.order && args.order !== "asc" && args.order !== "desc") {
|
|
94
|
-
console.log(pc.red("Invalid --order value. Use 'asc' or 'desc'."));
|
|
95
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
96
|
-
}
|
|
176
|
+
validateListArgs(args);
|
|
97
177
|
const client = new ApiClient(apiKey);
|
|
98
178
|
try {
|
|
99
|
-
|
|
100
|
-
// - --folder is a non-UUID name that must be resolved
|
|
101
|
-
// (a UUID can be used directly without folders:read scope)
|
|
102
|
-
let cachedFolders;
|
|
103
|
-
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
104
|
-
const folderArg = args.folder;
|
|
105
|
-
const needsFolderResolution = !!folderArg && !uuidPattern.test(folderArg);
|
|
106
|
-
if (needsFolderResolution) {
|
|
107
|
-
const foldersResponse = await client.listFolders();
|
|
108
|
-
cachedFolders = foldersResponse.folders;
|
|
109
|
-
}
|
|
110
|
-
// Build params object, only including defined fields
|
|
111
|
-
const params = {};
|
|
112
|
-
if (args.limit)
|
|
113
|
-
params.limit = Number.parseInt(args.limit, 10);
|
|
114
|
-
if (args.offset)
|
|
115
|
-
params.offset = Number.parseInt(args.offset, 10);
|
|
116
|
-
if (args.query)
|
|
117
|
-
params.query = args.query;
|
|
118
|
-
if (args.inbox)
|
|
119
|
-
params.inbox = true;
|
|
120
|
-
if (args.sort)
|
|
121
|
-
params.sort = args.sort;
|
|
122
|
-
if (args.order)
|
|
123
|
-
params.order = args.order;
|
|
124
|
-
// Resolve folder argument: UUIDs pass through; names use cache
|
|
125
|
-
if (folderArg) {
|
|
126
|
-
if (uuidPattern.test(folderArg)) {
|
|
127
|
-
params.folderId = folderArg;
|
|
128
|
-
}
|
|
129
|
-
else if (cachedFolders) {
|
|
130
|
-
const folderId = resolveFolderNameFromCache(folderArg, cachedFolders);
|
|
131
|
-
if (folderId === null) {
|
|
132
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
133
|
-
}
|
|
134
|
-
params.folderId = folderId;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// Resolve tag name to ID
|
|
138
|
-
if (args.tag) {
|
|
139
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
140
|
-
if (tagId === null) {
|
|
141
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
142
|
-
}
|
|
143
|
-
params.tagId = tagId;
|
|
144
|
-
}
|
|
179
|
+
const { params, cachedFolders } = await buildListParams(client, args);
|
|
145
180
|
const response = await client.listLinks(params);
|
|
146
|
-
// Count-only mode: use total from API response
|
|
147
181
|
if (args.count) {
|
|
148
182
|
console.log(response.total);
|
|
149
183
|
return;
|
|
150
184
|
}
|
|
151
|
-
// Build folder name map for table output
|
|
152
|
-
let folderMap;
|
|
153
|
-
const hasFolders = response.links.some((l) => l.folderId);
|
|
154
|
-
if (hasFolders) {
|
|
155
|
-
try {
|
|
156
|
-
// Reuse cached folders if available, otherwise fetch
|
|
157
|
-
const folders = cachedFolders ?? (await client.listFolders()).folders;
|
|
158
|
-
folderMap = new Map(folders.map((f) => [f.id, f.name]));
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
// If folder fetch fails, continue without folder names
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// Determine whether to show TAGS column.
|
|
165
|
-
// Auto-enable when filtering by tag, or when --show-tags is set.
|
|
166
185
|
const showTags = !!(args["show-tags"] || args.tag);
|
|
167
|
-
|
|
168
|
-
// the response is missing embedded tag details. The /links
|
|
169
|
-
// endpoint already includes `tags: Tag[]` per link, so a
|
|
170
|
-
// successful response makes listTags() unnecessary; we only
|
|
171
|
-
// fall back when some tagged link is missing its tags array
|
|
172
|
-
// (older server, or partial response).
|
|
173
|
-
let tagMap;
|
|
174
|
-
const needsTagFallback = showTags &&
|
|
175
|
-
response.links.some((l) => (l.tagIds ?? []).length > 0 && (!l.tags || l.tags.length === 0));
|
|
176
|
-
if (needsTagFallback) {
|
|
177
|
-
try {
|
|
178
|
-
const tagsResponse = await client.listTags();
|
|
179
|
-
tagMap = new Map(tagsResponse.tags.map((t) => [t.id, t.name]));
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
// If tag fetch fails, continue without tag names
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
// Determine output format
|
|
186
|
+
const { folderMap, tagMap } = await loadDisplayMaps(client, response.links, cachedFolders, showTags);
|
|
186
187
|
let format = getOutputFormat();
|
|
187
188
|
if (args.json)
|
|
188
189
|
format = "json";
|