@nocoo/zhe 1.16.1 → 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/api/client.d.ts +25 -1
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +41 -2
- package/dist/api/client.js.map +1 -1
- package/dist/api/types.d.ts +32 -2
- package/dist/api/types.d.ts.map +1 -1
- package/dist/commands/create.js +1 -18
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/folder.d.ts +7 -0
- package/dist/commands/folder.d.ts.map +1 -0
- package/dist/commands/folder.js +226 -0
- package/dist/commands/folder.js.map +1 -0
- package/dist/commands/get.d.ts.map +1 -1
- package/dist/commands/get.js +12 -1
- package/dist/commands/get.js.map +1 -1
- 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 -1
- package/dist/commands/idea.d.ts.map +1 -1
- package/dist/commands/idea.js +12 -390
- package/dist/commands/idea.js.map +1 -1
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +133 -61
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/open.js +1 -23
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/tag.d.ts +8 -0
- package/dist/commands/tag.d.ts.map +1 -0
- package/dist/commands/tag.js +289 -0
- package/dist/commands/tag.js.map +1 -0
- 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/index.js +4 -0
- package/dist/index.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 +22 -61
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +66 -187
- package/dist/utils.js.map +1 -1
- package/package.json +10 -6
package/dist/commands/idea.js
CHANGED
|
@@ -1,395 +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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!apiKey) {
|
|
12
|
-
console.log(pc.red("Not authenticated. Run `zhe login` first."));
|
|
13
|
-
process.exit(EXIT_AUTH_REQUIRED);
|
|
14
|
-
}
|
|
15
|
-
return apiKey;
|
|
16
|
-
}
|
|
17
|
-
function handleApiError(error) {
|
|
18
|
-
if (error instanceof ApiClientError) {
|
|
19
|
-
if (error.status === 400) {
|
|
20
|
-
console.log(pc.red(`Error: ${error.message}`));
|
|
21
|
-
}
|
|
22
|
-
else if (error.status === 404) {
|
|
23
|
-
console.log(pc.red("Idea not found."));
|
|
24
|
-
process.exit(EXIT_NOT_FOUND);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
console.log(pc.red(`Error: ${error.message}`));
|
|
28
|
-
}
|
|
29
|
-
if (error.status === 401) {
|
|
30
|
-
process.exit(EXIT_AUTH_REQUIRED);
|
|
31
|
-
}
|
|
32
|
-
if (error.status === 429) {
|
|
33
|
-
process.exit(EXIT_RATE_LIMITED);
|
|
34
|
-
}
|
|
35
|
-
process.exit(EXIT_ERROR);
|
|
36
|
-
}
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
function formatDate(isoDate) {
|
|
40
|
-
const date = new Date(isoDate);
|
|
41
|
-
return new Intl.DateTimeFormat("en-US", {
|
|
42
|
-
month: "short",
|
|
43
|
-
day: "numeric",
|
|
44
|
-
year: "numeric",
|
|
45
|
-
hour: "numeric",
|
|
46
|
-
minute: "2-digit",
|
|
47
|
-
}).format(date);
|
|
48
|
-
}
|
|
49
|
-
function formatTags(tags) {
|
|
50
|
-
if (tags.length === 0)
|
|
51
|
-
return "";
|
|
52
|
-
return tags.map((t) => `[${t.name}]`).join(" ");
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Resolve a single tag name to tag ID via API.
|
|
56
|
-
* Returns null if tag is not found or if multiple tags match (with error message printed).
|
|
57
|
-
*/
|
|
58
|
-
async function resolveTagName(client, tagName) {
|
|
59
|
-
const { tags } = await client.listTags();
|
|
60
|
-
const matches = tags.filter((t) => t.name.toLowerCase() === tagName.toLowerCase());
|
|
61
|
-
if (matches.length === 0) {
|
|
62
|
-
console.log(pc.red(`Tag not found: ${tagName}. Create it first.`));
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
if (matches.length > 1) {
|
|
66
|
-
console.log(pc.red(`Multiple tags match "${tagName}". Tag names must be unique. Please rename or delete duplicates via the web UI.`));
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
return matches[0].id;
|
|
70
|
-
}
|
|
71
|
-
async function confirm(message) {
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
const rl = readline.createInterface({
|
|
74
|
-
input: process.stdin,
|
|
75
|
-
output: process.stdout,
|
|
76
|
-
});
|
|
77
|
-
rl.question(`${message} [y/N] `, (answer) => {
|
|
78
|
-
rl.close();
|
|
79
|
-
resolve(answer.toLowerCase() === "y");
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
// ── Subcommands ──
|
|
84
|
-
const listSubcommand = defineCommand({
|
|
85
|
-
meta: {
|
|
86
|
-
name: "list",
|
|
87
|
-
description: "List all ideas",
|
|
88
|
-
},
|
|
89
|
-
args: {
|
|
90
|
-
limit: {
|
|
91
|
-
type: "string",
|
|
92
|
-
alias: "l",
|
|
93
|
-
description: "Max results (default: 20)",
|
|
94
|
-
},
|
|
95
|
-
tag: {
|
|
96
|
-
type: "string",
|
|
97
|
-
alias: "t",
|
|
98
|
-
description: "Filter by tag name",
|
|
99
|
-
},
|
|
100
|
-
query: {
|
|
101
|
-
type: "string",
|
|
102
|
-
alias: "q",
|
|
103
|
-
description: "Search title and excerpt",
|
|
104
|
-
},
|
|
105
|
-
json: {
|
|
106
|
-
type: "boolean",
|
|
107
|
-
description: "Output as JSON",
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
async run({ args }) {
|
|
111
|
-
const apiKey = requireAuth();
|
|
112
|
-
const client = new ApiClient(apiKey);
|
|
113
|
-
try {
|
|
114
|
-
// Resolve tag name to ID if provided
|
|
115
|
-
let tagId;
|
|
116
|
-
if (args.tag) {
|
|
117
|
-
const resolved = await resolveTagName(client, args.tag);
|
|
118
|
-
if (resolved === null) {
|
|
119
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
120
|
-
}
|
|
121
|
-
tagId = resolved;
|
|
122
|
-
}
|
|
123
|
-
const response = await client.listIdeas({
|
|
124
|
-
limit: args.limit ? Number.parseInt(args.limit, 10) : 20,
|
|
125
|
-
tagId,
|
|
126
|
-
q: args.query,
|
|
127
|
-
});
|
|
128
|
-
if (args.json) {
|
|
129
|
-
console.log(JSON.stringify(response, null, 2));
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (response.ideas.length === 0) {
|
|
133
|
-
console.log(pc.yellow("No ideas found."));
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
// Table format
|
|
137
|
-
console.log(pc.dim("ID TIME TITLE TAGS"));
|
|
138
|
-
console.log(pc.dim("─".repeat(56)));
|
|
139
|
-
for (const idea of response.ideas) {
|
|
140
|
-
const time = formatDate(idea.createdAt);
|
|
141
|
-
const title = (idea.title || idea.excerpt || "(no content)").slice(0, 24);
|
|
142
|
-
const tags = formatTags(idea.tags);
|
|
143
|
-
console.log(`${pc.cyan(String(idea.id).padEnd(6))}${time.padEnd(17)}${title.padEnd(25)}${pc.yellow(tags)}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
handleApiError(error);
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
const getSubcommand = defineCommand({
|
|
152
|
-
meta: {
|
|
153
|
-
name: "get",
|
|
154
|
-
description: "Get full content of an idea",
|
|
155
|
-
},
|
|
156
|
-
args: {
|
|
157
|
-
id: {
|
|
158
|
-
type: "positional",
|
|
159
|
-
description: "Idea ID",
|
|
160
|
-
required: true,
|
|
161
|
-
},
|
|
162
|
-
json: {
|
|
163
|
-
type: "boolean",
|
|
164
|
-
description: "Output as JSON",
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
async run({ args }) {
|
|
168
|
-
const apiKey = requireAuth();
|
|
169
|
-
const client = new ApiClient(apiKey);
|
|
170
|
-
const id = Number.parseInt(args.id, 10);
|
|
171
|
-
if (Number.isNaN(id)) {
|
|
172
|
-
console.log(pc.red("Invalid idea ID."));
|
|
173
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
const response = await client.getIdea(id);
|
|
177
|
-
if (args.json) {
|
|
178
|
-
console.log(JSON.stringify(response, null, 2));
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const { idea } = response;
|
|
182
|
-
const tags = formatTags(idea.tags);
|
|
183
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
184
|
-
console.log(pc.dim("─".repeat(40)));
|
|
185
|
-
console.log(`Idea ${pc.cyan(`#${idea.id}`)} — ${pc.bold(title)}`);
|
|
186
|
-
if (tags)
|
|
187
|
-
console.log(`Tags: ${pc.yellow(tags)}`);
|
|
188
|
-
console.log(pc.dim("─".repeat(40)));
|
|
189
|
-
console.log();
|
|
190
|
-
console.log(idea.content);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
handleApiError(error);
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
const addSubcommand = defineCommand({
|
|
198
|
-
meta: {
|
|
199
|
-
name: "add",
|
|
200
|
-
description: "Create a new idea",
|
|
201
|
-
},
|
|
202
|
-
args: {
|
|
203
|
-
content: {
|
|
204
|
-
type: "positional",
|
|
205
|
-
description: "Idea content (Markdown)",
|
|
206
|
-
required: true,
|
|
207
|
-
},
|
|
208
|
-
title: {
|
|
209
|
-
type: "string",
|
|
210
|
-
alias: "t",
|
|
211
|
-
description: "Optional title",
|
|
212
|
-
},
|
|
213
|
-
tag: {
|
|
214
|
-
type: "string",
|
|
215
|
-
alias: "T",
|
|
216
|
-
description: "Add tag by name",
|
|
217
|
-
},
|
|
218
|
-
json: {
|
|
219
|
-
type: "boolean",
|
|
220
|
-
description: "Output as JSON",
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
async run({ args }) {
|
|
224
|
-
const apiKey = requireAuth();
|
|
225
|
-
const client = new ApiClient(apiKey);
|
|
226
|
-
const content = args.content;
|
|
227
|
-
if (!content.trim()) {
|
|
228
|
-
console.log(pc.red("Content cannot be empty."));
|
|
229
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
230
|
-
}
|
|
231
|
-
try {
|
|
232
|
-
// Resolve tag name to ID if provided
|
|
233
|
-
let tagIds;
|
|
234
|
-
if (args.tag) {
|
|
235
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
236
|
-
if (tagId === null) {
|
|
237
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
238
|
-
}
|
|
239
|
-
tagIds = [tagId];
|
|
240
|
-
}
|
|
241
|
-
const request = {
|
|
242
|
-
content,
|
|
243
|
-
...(args.title && { title: args.title }),
|
|
244
|
-
...(tagIds && { tagIds }),
|
|
245
|
-
};
|
|
246
|
-
const response = await client.createIdea(request);
|
|
247
|
-
if (args.json) {
|
|
248
|
-
console.log(JSON.stringify(response, null, 2));
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
const { idea } = response;
|
|
252
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
253
|
-
console.log(pc.green(`✓ Created idea ${pc.cyan(`#${idea.id}`)} (${title})`));
|
|
254
|
-
}
|
|
255
|
-
catch (error) {
|
|
256
|
-
handleApiError(error);
|
|
257
|
-
}
|
|
258
|
-
},
|
|
259
|
-
});
|
|
260
|
-
const updateSubcommand = defineCommand({
|
|
261
|
-
meta: {
|
|
262
|
-
name: "update",
|
|
263
|
-
description: "Update an existing idea",
|
|
264
|
-
},
|
|
265
|
-
args: {
|
|
266
|
-
id: {
|
|
267
|
-
type: "positional",
|
|
268
|
-
description: "Idea ID",
|
|
269
|
-
required: true,
|
|
270
|
-
},
|
|
271
|
-
content: {
|
|
272
|
-
type: "string",
|
|
273
|
-
alias: "c",
|
|
274
|
-
description: "New content",
|
|
275
|
-
},
|
|
276
|
-
title: {
|
|
277
|
-
type: "string",
|
|
278
|
-
alias: "t",
|
|
279
|
-
description: "New title (use empty string to clear)",
|
|
280
|
-
},
|
|
281
|
-
tag: {
|
|
282
|
-
type: "string",
|
|
283
|
-
alias: "T",
|
|
284
|
-
description: "Set tag by name (replaces all existing tags)",
|
|
285
|
-
},
|
|
286
|
-
json: {
|
|
287
|
-
type: "boolean",
|
|
288
|
-
description: "Output as JSON",
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
async run({ args }) {
|
|
292
|
-
const apiKey = requireAuth();
|
|
293
|
-
const client = new ApiClient(apiKey);
|
|
294
|
-
const id = Number.parseInt(args.id, 10);
|
|
295
|
-
if (Number.isNaN(id)) {
|
|
296
|
-
console.log(pc.red("Invalid idea ID."));
|
|
297
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
298
|
-
}
|
|
299
|
-
// Build update request
|
|
300
|
-
const request = {};
|
|
301
|
-
if (args.content !== undefined)
|
|
302
|
-
request.content = args.content;
|
|
303
|
-
if (args.title !== undefined) {
|
|
304
|
-
request.title = args.title === "" ? null : args.title;
|
|
305
|
-
}
|
|
306
|
-
// Resolve tag name if provided
|
|
307
|
-
if (args.tag !== undefined) {
|
|
308
|
-
if (args.tag === "") {
|
|
309
|
-
// Empty string means clear all tags
|
|
310
|
-
request.tagIds = [];
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
314
|
-
if (tagId === null) {
|
|
315
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
316
|
-
}
|
|
317
|
-
request.tagIds = [tagId];
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (Object.keys(request).length === 0) {
|
|
321
|
-
console.log(pc.yellow("No changes specified."));
|
|
322
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
323
|
-
}
|
|
324
|
-
try {
|
|
325
|
-
const response = await client.updateIdea(id, request);
|
|
326
|
-
if (args.json) {
|
|
327
|
-
console.log(JSON.stringify(response, null, 2));
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const { idea } = response;
|
|
331
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
332
|
-
console.log(pc.green(`✓ Updated idea ${pc.cyan(`#${idea.id}`)} (${title})`));
|
|
333
|
-
}
|
|
334
|
-
catch (error) {
|
|
335
|
-
handleApiError(error);
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
});
|
|
339
|
-
const deleteSubcommand = defineCommand({
|
|
340
|
-
meta: {
|
|
341
|
-
name: "delete",
|
|
342
|
-
description: "Delete an idea",
|
|
343
|
-
},
|
|
344
|
-
args: {
|
|
345
|
-
id: {
|
|
346
|
-
type: "positional",
|
|
347
|
-
description: "Idea ID",
|
|
348
|
-
required: true,
|
|
349
|
-
},
|
|
350
|
-
yes: {
|
|
351
|
-
type: "boolean",
|
|
352
|
-
alias: "y",
|
|
353
|
-
description: "Skip confirmation",
|
|
354
|
-
},
|
|
355
|
-
json: {
|
|
356
|
-
type: "boolean",
|
|
357
|
-
description: "Output as JSON",
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
|
-
async run({ args }) {
|
|
361
|
-
const apiKey = requireAuth();
|
|
362
|
-
const client = new ApiClient(apiKey);
|
|
363
|
-
const id = Number.parseInt(args.id, 10);
|
|
364
|
-
if (Number.isNaN(id)) {
|
|
365
|
-
console.log(pc.red("Invalid idea ID."));
|
|
366
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
// Only fetch idea for confirmation prompt (requires ideas:read)
|
|
370
|
-
// With --yes flag, skip prefetch to allow write-only keys
|
|
371
|
-
if (!args.yes) {
|
|
372
|
-
const { idea } = await client.getIdea(id);
|
|
373
|
-
const title = idea.title || formatDate(idea.createdAt);
|
|
374
|
-
const confirmed = await confirm(`Delete idea #${id} (${title})?`);
|
|
375
|
-
if (!confirmed) {
|
|
376
|
-
console.log(pc.dim("Cancelled."));
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
await client.deleteIdea(id);
|
|
381
|
-
if (args.json) {
|
|
382
|
-
console.log(JSON.stringify({ success: true, id }, null, 2));
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
console.log(pc.green(`✓ Deleted idea ${pc.cyan(`#${id}`)}`));
|
|
386
|
-
}
|
|
387
|
-
catch (error) {
|
|
388
|
-
handleApiError(error);
|
|
389
|
-
}
|
|
390
|
-
},
|
|
391
|
-
});
|
|
392
|
-
// ── 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";
|
|
393
15
|
export const ideaCommand = defineCommand({
|
|
394
16
|
meta: {
|
|
395
17
|
name: "idea",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idea.js","sourceRoot":"","sources":["../../src/commands/idea.ts"],"names":[],"mappings":"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"}
|
|
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"}
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -59,5 +59,9 @@ export declare const listCommand: import("citty").CommandDef<{
|
|
|
59
59
|
readonly alias: "c";
|
|
60
60
|
readonly description: "Show only the count of matching links";
|
|
61
61
|
};
|
|
62
|
+
readonly "show-tags": {
|
|
63
|
+
readonly type: "boolean";
|
|
64
|
+
readonly description: "Show TAGS column in table output (auto-enabled with --tag)";
|
|
65
|
+
};
|
|
62
66
|
}>;
|
|
63
67
|
//# sourceMappingURL=list.d.ts.map
|
|
@@ -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
|
@@ -4,7 +4,101 @@
|
|
|
4
4
|
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
|
-
import { formatLinksMinimal, formatLinksTable,
|
|
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",
|
|
@@ -68,6 +162,10 @@ export const listCommand = defineCommand({
|
|
|
68
162
|
alias: "c",
|
|
69
163
|
description: "Show only the count of matching links",
|
|
70
164
|
},
|
|
165
|
+
"show-tags": {
|
|
166
|
+
type: "boolean",
|
|
167
|
+
description: "Show TAGS column in table output (auto-enabled with --tag)",
|
|
168
|
+
},
|
|
71
169
|
},
|
|
72
170
|
async run({ args }) {
|
|
73
171
|
const apiKey = getApiKey();
|
|
@@ -75,72 +173,17 @@ export const listCommand = defineCommand({
|
|
|
75
173
|
console.log(pc.red("Not authenticated. Run `zhe login` first."));
|
|
76
174
|
process.exit(EXIT_AUTH_REQUIRED);
|
|
77
175
|
}
|
|
78
|
-
|
|
79
|
-
if (args.inbox && args.folder) {
|
|
80
|
-
console.log(pc.red("Cannot use --inbox and --folder together."));
|
|
81
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
82
|
-
}
|
|
83
|
-
// Validate sort option
|
|
84
|
-
if (args.sort && args.sort !== "created" && args.sort !== "clicks") {
|
|
85
|
-
console.log(pc.red("Invalid --sort value. Use 'created' or 'clicks'."));
|
|
86
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
87
|
-
}
|
|
88
|
-
// Validate order option
|
|
89
|
-
if (args.order && args.order !== "asc" && args.order !== "desc") {
|
|
90
|
-
console.log(pc.red("Invalid --order value. Use 'asc' or 'desc'."));
|
|
91
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
92
|
-
}
|
|
176
|
+
validateListArgs(args);
|
|
93
177
|
const client = new ApiClient(apiKey);
|
|
94
178
|
try {
|
|
95
|
-
|
|
96
|
-
const params = {};
|
|
97
|
-
if (args.limit)
|
|
98
|
-
params.limit = Number.parseInt(args.limit, 10);
|
|
99
|
-
if (args.offset)
|
|
100
|
-
params.offset = Number.parseInt(args.offset, 10);
|
|
101
|
-
if (args.query)
|
|
102
|
-
params.query = args.query;
|
|
103
|
-
if (args.inbox)
|
|
104
|
-
params.inbox = true;
|
|
105
|
-
if (args.sort)
|
|
106
|
-
params.sort = args.sort;
|
|
107
|
-
if (args.order)
|
|
108
|
-
params.order = args.order;
|
|
109
|
-
// Resolve folder name to ID
|
|
110
|
-
if (args.folder) {
|
|
111
|
-
const folderId = await resolveFolderName(client, args.folder);
|
|
112
|
-
if (folderId === null) {
|
|
113
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
114
|
-
}
|
|
115
|
-
params.folderId = folderId;
|
|
116
|
-
}
|
|
117
|
-
// Resolve tag name to ID
|
|
118
|
-
if (args.tag) {
|
|
119
|
-
const tagId = await resolveTagName(client, args.tag);
|
|
120
|
-
if (tagId === null) {
|
|
121
|
-
process.exit(EXIT_INVALID_ARGS);
|
|
122
|
-
}
|
|
123
|
-
params.tagId = tagId;
|
|
124
|
-
}
|
|
179
|
+
const { params, cachedFolders } = await buildListParams(client, args);
|
|
125
180
|
const response = await client.listLinks(params);
|
|
126
|
-
// Count-only mode: use total from API response
|
|
127
181
|
if (args.count) {
|
|
128
182
|
console.log(response.total);
|
|
129
183
|
return;
|
|
130
184
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const hasFolders = response.links.some((l) => l.folderId);
|
|
134
|
-
if (hasFolders) {
|
|
135
|
-
try {
|
|
136
|
-
const foldersResponse = await client.listFolders();
|
|
137
|
-
folderMap = new Map(foldersResponse.folders.map((f) => [f.id, f.name]));
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
// If folder fetch fails, continue without folder names
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
// Determine output format
|
|
185
|
+
const showTags = !!(args["show-tags"] || args.tag);
|
|
186
|
+
const { folderMap, tagMap } = await loadDisplayMaps(client, response.links, cachedFolders, showTags);
|
|
144
187
|
let format = getOutputFormat();
|
|
145
188
|
if (args.json)
|
|
146
189
|
format = "json";
|
|
@@ -154,7 +197,12 @@ export const listCommand = defineCommand({
|
|
|
154
197
|
console.log(formatLinksMinimal(response.links));
|
|
155
198
|
break;
|
|
156
199
|
default:
|
|
157
|
-
console.log(formatLinksTable(response.links, {
|
|
200
|
+
console.log(formatLinksTable(response.links, {
|
|
201
|
+
wide: args.wide,
|
|
202
|
+
folderMap,
|
|
203
|
+
tagMap,
|
|
204
|
+
showTags,
|
|
205
|
+
}));
|
|
158
206
|
}
|
|
159
207
|
}
|
|
160
208
|
catch (error) {
|
|
@@ -175,4 +223,28 @@ function handleApiError(error) {
|
|
|
175
223
|
}
|
|
176
224
|
throw error;
|
|
177
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Resolve folder name to ID from cached folders list.
|
|
228
|
+
* If input looks like a UUID, use it directly.
|
|
229
|
+
* Returns null if folder is not found (with error message printed).
|
|
230
|
+
*/
|
|
231
|
+
function resolveFolderNameFromCache(input, folders) {
|
|
232
|
+
// Check if input looks like a UUID (36 chars with dashes)
|
|
233
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
234
|
+
if (uuidPattern.test(input)) {
|
|
235
|
+
return input; // Assume it's already an ID
|
|
236
|
+
}
|
|
237
|
+
// Otherwise, resolve by name
|
|
238
|
+
const matches = folders.filter((f) => f.name.toLowerCase() === input.toLowerCase());
|
|
239
|
+
if (matches.length === 0) {
|
|
240
|
+
console.log(pc.red(`Folder not found: ${input}`));
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
if (matches.length > 1) {
|
|
244
|
+
console.log(pc.red(`Multiple folders match "${input}". Please use the folder ID instead.`));
|
|
245
|
+
console.log(pc.dim("Use `zhe folders` to see all folder IDs."));
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return matches[0].id;
|
|
249
|
+
}
|
|
178
250
|
//# sourceMappingURL=list.js.map
|