@shiori-sh/cli 0.4.0 → 0.7.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.
- package/README.md +11 -1
- package/dist/index.js +315 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ You can also set `SHIORI_API_KEY` as an environment variable.
|
|
|
29
29
|
```bash
|
|
30
30
|
shiori list # List recent links
|
|
31
31
|
shiori list --read unread # List unread links
|
|
32
|
+
shiori list --tag "design" # Filter links by tag
|
|
32
33
|
shiori list --since 7d # Links saved in the last 7 days
|
|
33
34
|
shiori list --content --json # Include full markdown content
|
|
34
35
|
|
|
@@ -46,11 +47,20 @@ shiori update <id> --read # Mark as read
|
|
|
46
47
|
shiori update <id> --unread # Mark as unread
|
|
47
48
|
shiori update <id> --title "..." # Update title
|
|
48
49
|
shiori update <id> --restore # Restore from trash
|
|
50
|
+
shiori update --ids <id1,id2,...> --read # Bulk mark as read
|
|
51
|
+
shiori update --ids <id1,id2,...> --unread # Bulk mark as unread
|
|
49
52
|
|
|
50
53
|
shiori delete <id> # Move to trash
|
|
54
|
+
shiori delete --ids <id1,id2,...> # Bulk move to trash
|
|
51
55
|
shiori trash # List trashed links
|
|
52
56
|
shiori trash --empty # Permanently delete all trash
|
|
53
57
|
|
|
58
|
+
shiori tags list # List your tags
|
|
59
|
+
shiori tags create "design" # Create a tag
|
|
60
|
+
shiori tags update <id> --name "dev" # Rename a tag
|
|
61
|
+
shiori tags delete <id> # Delete a tag
|
|
62
|
+
shiori tags set <link-id> design,work # Set tags on a link
|
|
63
|
+
|
|
54
64
|
shiori subscriptions list # List RSS subscriptions
|
|
55
65
|
shiori subscriptions add <url> # Subscribe to an RSS feed
|
|
56
66
|
shiori subscriptions add <url> --sync # Subscribe and sync recent items
|
|
@@ -58,7 +68,7 @@ shiori subscriptions remove <id> # Remove a subscription
|
|
|
58
68
|
shiori subscriptions sync <id> # Sync a subscription now
|
|
59
69
|
shiori subscriptions sync <id> --limit 5 # Sync with item limit
|
|
60
70
|
|
|
61
|
-
shiori
|
|
71
|
+
shiori whoami # Show account info
|
|
62
72
|
shiori auth --status # Check auth status
|
|
63
73
|
shiori auth --logout # Remove stored credentials
|
|
64
74
|
```
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/commands/auth.ts
|
|
4
|
-
import {
|
|
4
|
+
import { execFile } from "child_process";
|
|
5
5
|
import { hostname } from "os";
|
|
6
6
|
import { createInterface } from "readline";
|
|
7
7
|
|
|
@@ -92,7 +92,7 @@ function promptSecret(question) {
|
|
|
92
92
|
function openUrl(url) {
|
|
93
93
|
const platform = process.platform;
|
|
94
94
|
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
95
|
-
|
|
95
|
+
execFile(cmd, [url]);
|
|
96
96
|
}
|
|
97
97
|
function sleep(ms) {
|
|
98
98
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -290,7 +290,10 @@ function getPositional(args) {
|
|
|
290
290
|
"--title",
|
|
291
291
|
"--summary",
|
|
292
292
|
"--since",
|
|
293
|
-
"--format"
|
|
293
|
+
"--format",
|
|
294
|
+
"--ids",
|
|
295
|
+
"--tag",
|
|
296
|
+
"--name"
|
|
294
297
|
].includes(args[i])) {
|
|
295
298
|
i++;
|
|
296
299
|
}
|
|
@@ -361,18 +364,35 @@ Options:
|
|
|
361
364
|
// src/commands/delete.ts
|
|
362
365
|
async function run3(args) {
|
|
363
366
|
if (hasFlag(args, "--help", "-h")) {
|
|
364
|
-
console.log(`shiori delete - Delete
|
|
367
|
+
console.log(`shiori delete - Delete links (move to trash)
|
|
365
368
|
|
|
366
369
|
Usage: shiori delete <id> [options]
|
|
370
|
+
shiori delete --ids <id1,id2,...> [options]
|
|
367
371
|
|
|
368
372
|
Options:
|
|
369
|
-
--
|
|
370
|
-
--
|
|
373
|
+
--ids <ids> Comma-separated list of link IDs for bulk delete
|
|
374
|
+
--json Output raw JSON
|
|
375
|
+
--help, -h Show this help`);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const idsFlag = getFlag(args, "--ids");
|
|
379
|
+
if (idsFlag) {
|
|
380
|
+
const ids = idsFlag.split(",").map((id2) => id2.trim()).filter(Boolean);
|
|
381
|
+
if (ids.length === 0) {
|
|
382
|
+
console.error("No valid IDs provided.");
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
const { data: data2 } = await api("PATCH", "/api/links", { ids, deleted: true });
|
|
386
|
+
if (hasFlag(args, "--json")) {
|
|
387
|
+
console.log(JSON.stringify(data2, null, 2));
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
console.log(`Deleted ${data2.updated} link(s).`);
|
|
371
391
|
return;
|
|
372
392
|
}
|
|
373
393
|
const id = getPositional(args);
|
|
374
394
|
if (!id) {
|
|
375
|
-
console.error("Usage: shiori delete <id>");
|
|
395
|
+
console.error("Usage: shiori delete <id> or shiori delete --ids <id1,id2,...>");
|
|
376
396
|
process.exit(1);
|
|
377
397
|
}
|
|
378
398
|
const { data } = await api("DELETE", `/api/links/${id}`);
|
|
@@ -440,6 +460,7 @@ Options:
|
|
|
440
460
|
--offset <n> Pagination offset (default: 0)
|
|
441
461
|
--sort <newest|oldest> Sort order (default: newest)
|
|
442
462
|
--read <all|read|unread> Filter by read status (default: all)
|
|
463
|
+
--tag <name> Filter by tag name
|
|
443
464
|
--since <duration> Only links saved within this period (e.g. 1h, 7d, 2w, 1m, 1y)
|
|
444
465
|
--content Include extracted markdown content
|
|
445
466
|
--json Output raw JSON
|
|
@@ -451,6 +472,7 @@ Options:
|
|
|
451
472
|
const sort = getFlag(args, "--sort", "newest");
|
|
452
473
|
const read = getFlag(args, "--read", "all");
|
|
453
474
|
const sinceFlag = getFlag(args, "--since");
|
|
475
|
+
const tag = getFlag(args, "--tag");
|
|
454
476
|
const includeContent = hasFlag(args, "--content");
|
|
455
477
|
const params = new URLSearchParams({
|
|
456
478
|
limit,
|
|
@@ -460,6 +482,7 @@ Options:
|
|
|
460
482
|
});
|
|
461
483
|
if (includeContent) params.set("include_content", "true");
|
|
462
484
|
if (sinceFlag) params.set("since", parseDuration(sinceFlag));
|
|
485
|
+
if (tag) params.set("tag", tag);
|
|
463
486
|
const { data } = await api("GET", `/api/links?${params}`);
|
|
464
487
|
if (hasFlag(args, "--json")) {
|
|
465
488
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -475,36 +498,8 @@ Links: ${data.links.length} of ${data.total} total
|
|
|
475
498
|
console.log();
|
|
476
499
|
}
|
|
477
500
|
|
|
478
|
-
// src/commands/me.ts
|
|
479
|
-
async function run6(args) {
|
|
480
|
-
if (hasFlag(args, "--help", "-h")) {
|
|
481
|
-
console.log(`shiori me - Show current user info
|
|
482
|
-
|
|
483
|
-
Usage: shiori me [options]
|
|
484
|
-
|
|
485
|
-
Options:
|
|
486
|
-
--json Output raw JSON
|
|
487
|
-
--help, -h Show this help`);
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
const { data } = await api("GET", "/api/user/me");
|
|
491
|
-
if (hasFlag(args, "--json")) {
|
|
492
|
-
console.log(JSON.stringify(data, null, 2));
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
const user = data.user;
|
|
496
|
-
console.log(`
|
|
497
|
-
Name: ${user.full_name || "--"}`);
|
|
498
|
-
const plan = user.subscription?.plan === "subscription" ? "Pro" : user.subscription?.plan || "Free";
|
|
499
|
-
console.log(` Plan: ${plan}`);
|
|
500
|
-
console.log(
|
|
501
|
-
` Member since: ${new Date(user.created_at).toLocaleDateString("en-US", { month: "long", year: "numeric" })}`
|
|
502
|
-
);
|
|
503
|
-
console.log();
|
|
504
|
-
}
|
|
505
|
-
|
|
506
501
|
// src/commands/save.ts
|
|
507
|
-
async function
|
|
502
|
+
async function run6(args) {
|
|
508
503
|
if (hasFlag(args, "--help", "-h")) {
|
|
509
504
|
console.log(`shiori save - Save a new link
|
|
510
505
|
|
|
@@ -539,7 +534,7 @@ Options:
|
|
|
539
534
|
}
|
|
540
535
|
|
|
541
536
|
// src/commands/search.ts
|
|
542
|
-
async function
|
|
537
|
+
async function run7(args) {
|
|
543
538
|
if (hasFlag(args, "--help", "-h")) {
|
|
544
539
|
console.log(`shiori search - Search saved links
|
|
545
540
|
|
|
@@ -606,7 +601,7 @@ Examples:
|
|
|
606
601
|
shiori subscriptions add https://example.com --sync
|
|
607
602
|
shiori subscriptions remove <id>
|
|
608
603
|
shiori subscriptions sync <id> --limit 5`;
|
|
609
|
-
async function
|
|
604
|
+
async function run8(args) {
|
|
610
605
|
if (hasFlag(args, "--help", "-h") && !args[0]) {
|
|
611
606
|
console.log(HELP);
|
|
612
607
|
return;
|
|
@@ -744,6 +739,224 @@ Options:
|
|
|
744
739
|
console.log(`Synced: ${data.newItems} new, ${data.skipped} skipped, ${data.errors} errors`);
|
|
745
740
|
}
|
|
746
741
|
|
|
742
|
+
// src/commands/tags.ts
|
|
743
|
+
var HELP2 = `shiori tags - Manage tags
|
|
744
|
+
|
|
745
|
+
Usage: shiori tags <subcommand> [options]
|
|
746
|
+
|
|
747
|
+
Subcommands:
|
|
748
|
+
list List your tags
|
|
749
|
+
create <name> Create a tag
|
|
750
|
+
update <id> --name <name> Rename a tag
|
|
751
|
+
delete <id> Delete a tag
|
|
752
|
+
set <link-id> <tag1,tag2,...> Set tags on a link (by name)
|
|
753
|
+
|
|
754
|
+
Options:
|
|
755
|
+
--json Output raw JSON
|
|
756
|
+
--help, -h Show this help
|
|
757
|
+
|
|
758
|
+
Examples:
|
|
759
|
+
shiori tags list
|
|
760
|
+
shiori tags create "design"
|
|
761
|
+
shiori tags update <id> --name "dev"
|
|
762
|
+
shiori tags delete <id>
|
|
763
|
+
shiori tags set <link-id> design,work`;
|
|
764
|
+
async function run9(args) {
|
|
765
|
+
if (hasFlag(args, "--help", "-h") && !args[0]) {
|
|
766
|
+
console.log(HELP2);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const subcommand = args[0];
|
|
770
|
+
const subArgs = args.slice(1);
|
|
771
|
+
switch (subcommand) {
|
|
772
|
+
case "list":
|
|
773
|
+
case "ls":
|
|
774
|
+
return listTags(subArgs);
|
|
775
|
+
case "create":
|
|
776
|
+
return createTag(subArgs);
|
|
777
|
+
case "update":
|
|
778
|
+
return updateTag(subArgs);
|
|
779
|
+
case "delete":
|
|
780
|
+
case "rm":
|
|
781
|
+
return deleteTag(subArgs);
|
|
782
|
+
case "set":
|
|
783
|
+
return setLinkTags(subArgs);
|
|
784
|
+
default:
|
|
785
|
+
if (subcommand) {
|
|
786
|
+
console.error(`Unknown subcommand: ${subcommand}
|
|
787
|
+
`);
|
|
788
|
+
}
|
|
789
|
+
console.log(HELP2);
|
|
790
|
+
if (subcommand) process.exit(1);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
async function listTags(args) {
|
|
794
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
795
|
+
console.log(`shiori tags list - List your tags
|
|
796
|
+
|
|
797
|
+
Usage: shiori tags list [options]
|
|
798
|
+
|
|
799
|
+
Options:
|
|
800
|
+
--json Output raw JSON
|
|
801
|
+
--help, -h Show this help`);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const { data } = await api("GET", "/api/tags/");
|
|
805
|
+
if (hasFlag(args, "--json")) {
|
|
806
|
+
console.log(JSON.stringify(data, null, 2));
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const tags = data.tags;
|
|
810
|
+
if (tags.length === 0) {
|
|
811
|
+
console.log("\n No tags. Create one with: shiori tags create <name>\n");
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
console.log(`
|
|
815
|
+
Tags: ${tags.length}
|
|
816
|
+
`);
|
|
817
|
+
for (const tag of tags) {
|
|
818
|
+
console.log(` ${tag.id} ${tag.name}`);
|
|
819
|
+
}
|
|
820
|
+
console.log();
|
|
821
|
+
}
|
|
822
|
+
async function createTag(args) {
|
|
823
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
824
|
+
console.log(`shiori tags create - Create a tag
|
|
825
|
+
|
|
826
|
+
Usage: shiori tags create <name> [options]
|
|
827
|
+
|
|
828
|
+
Options:
|
|
829
|
+
--json Output raw JSON
|
|
830
|
+
--help, -h Show this help`);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const name = getPositional(args);
|
|
834
|
+
if (!name) {
|
|
835
|
+
console.error("Usage: shiori tags create <name>");
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
const { data } = await api("POST", "/api/tags/", { name });
|
|
839
|
+
if (hasFlag(args, "--json")) {
|
|
840
|
+
console.log(JSON.stringify(data, null, 2));
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
console.log(`Created: ${data.tag.name} (${data.tag.id})`);
|
|
844
|
+
}
|
|
845
|
+
async function updateTag(args) {
|
|
846
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
847
|
+
console.log(`shiori tags update - Update a tag
|
|
848
|
+
|
|
849
|
+
Usage: shiori tags update <id> [options]
|
|
850
|
+
|
|
851
|
+
Options:
|
|
852
|
+
--name <name> New tag name
|
|
853
|
+
--json Output raw JSON
|
|
854
|
+
--help, -h Show this help`);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const id = getPositional(args);
|
|
858
|
+
if (!id) {
|
|
859
|
+
console.error("Usage: shiori tags update <id> --name <name>");
|
|
860
|
+
process.exit(1);
|
|
861
|
+
}
|
|
862
|
+
const name = getFlag(args, "--name");
|
|
863
|
+
if (!name) {
|
|
864
|
+
console.error("Provide --name to update.");
|
|
865
|
+
process.exit(1);
|
|
866
|
+
}
|
|
867
|
+
const { data } = await api("PATCH", `/api/tags/${id}`, { name });
|
|
868
|
+
if (hasFlag(args, "--json")) {
|
|
869
|
+
console.log(JSON.stringify(data, null, 2));
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
console.log(`Updated: ${data.tag.name} (${data.tag.id})`);
|
|
873
|
+
}
|
|
874
|
+
async function deleteTag(args) {
|
|
875
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
876
|
+
console.log(`shiori tags delete - Delete a tag
|
|
877
|
+
|
|
878
|
+
Usage: shiori tags delete <id> [options]
|
|
879
|
+
|
|
880
|
+
Options:
|
|
881
|
+
--json Output raw JSON
|
|
882
|
+
--help, -h Show this help`);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const id = getPositional(args);
|
|
886
|
+
if (!id) {
|
|
887
|
+
console.error("Usage: shiori tags delete <id>");
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
const { data } = await api("DELETE", `/api/tags/${id}`);
|
|
891
|
+
if (hasFlag(args, "--json")) {
|
|
892
|
+
console.log(JSON.stringify(data, null, 2));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
console.log("Tag deleted.");
|
|
896
|
+
}
|
|
897
|
+
async function setLinkTags(args) {
|
|
898
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
899
|
+
console.log(`shiori tags set - Set tags on a link
|
|
900
|
+
|
|
901
|
+
Usage: shiori tags set <link-id> <tag1,tag2,...> [options]
|
|
902
|
+
|
|
903
|
+
Pass a comma-separated list of tag names. Tags are replaced, not appended.
|
|
904
|
+
Pass an empty string "" to remove all tags.
|
|
905
|
+
|
|
906
|
+
Options:
|
|
907
|
+
--json Output raw JSON
|
|
908
|
+
--help, -h Show this help`);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
const positionals = [];
|
|
912
|
+
for (let i = 0; i < args.length; i++) {
|
|
913
|
+
if (args[i].startsWith("--")) {
|
|
914
|
+
i++;
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
positionals.push(args[i]);
|
|
918
|
+
}
|
|
919
|
+
const linkId = positionals[0];
|
|
920
|
+
const tagNamesRaw = positionals[1];
|
|
921
|
+
if (!linkId) {
|
|
922
|
+
console.error("Usage: shiori tags set <link-id> <tag1,tag2,...>");
|
|
923
|
+
process.exit(1);
|
|
924
|
+
}
|
|
925
|
+
const tagNames = tagNamesRaw === void 0 || tagNamesRaw === "" ? [] : tagNamesRaw.split(",").map((t) => t.trim()).filter(Boolean);
|
|
926
|
+
const tagIds = [];
|
|
927
|
+
if (tagNames.length > 0) {
|
|
928
|
+
const { data: tagsData } = await api("GET", "/api/tags/");
|
|
929
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
930
|
+
for (const tag of tagsData.tags) {
|
|
931
|
+
tagMap.set(tag.name.toLowerCase(), tag.id);
|
|
932
|
+
}
|
|
933
|
+
const missing = [];
|
|
934
|
+
for (const name of tagNames) {
|
|
935
|
+
const id = tagMap.get(name.toLowerCase());
|
|
936
|
+
if (id) {
|
|
937
|
+
tagIds.push(id);
|
|
938
|
+
} else {
|
|
939
|
+
missing.push(name);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
if (missing.length > 0) {
|
|
943
|
+
console.error(`Tags not found: ${missing.join(", ")}`);
|
|
944
|
+
console.error("Create them first with: shiori tags create <name>");
|
|
945
|
+
process.exit(1);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
const { data } = await api("PUT", `/api/links/${linkId}/tags`, { tagIds });
|
|
949
|
+
if (hasFlag(args, "--json")) {
|
|
950
|
+
console.log(JSON.stringify(data, null, 2));
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (tagIds.length === 0) {
|
|
954
|
+
console.log("All tags removed from link.");
|
|
955
|
+
} else {
|
|
956
|
+
console.log(`Set ${tagIds.length} tag${tagIds.length === 1 ? "" : "s"} on link.`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
747
960
|
// src/commands/trash.ts
|
|
748
961
|
async function run10(args) {
|
|
749
962
|
if (hasFlag(args, "--help", "-h")) {
|
|
@@ -798,20 +1011,42 @@ Trashed links: ${data.links.length} of ${data.total} total
|
|
|
798
1011
|
// src/commands/update.ts
|
|
799
1012
|
async function run11(args) {
|
|
800
1013
|
if (hasFlag(args, "--help", "-h")) {
|
|
801
|
-
console.log(`shiori update - Update
|
|
1014
|
+
console.log(`shiori update - Update links
|
|
802
1015
|
|
|
803
1016
|
Usage: shiori update <id> [options]
|
|
1017
|
+
shiori update --ids <id1,id2,...> --read|--unread [options]
|
|
804
1018
|
|
|
805
1019
|
Options:
|
|
1020
|
+
--ids <ids> Comma-separated list of link IDs for bulk update
|
|
806
1021
|
--read Mark as read
|
|
807
1022
|
--unread Mark as unread
|
|
808
|
-
--title <title> Update title
|
|
809
|
-
--summary <text> Update summary
|
|
810
|
-
--restore Restore from trash
|
|
1023
|
+
--title <title> Update title (single link only)
|
|
1024
|
+
--summary <text> Update summary (single link only)
|
|
1025
|
+
--restore Restore from trash (single link only)
|
|
811
1026
|
--json Output raw JSON
|
|
812
1027
|
--help, -h Show this help`);
|
|
813
1028
|
return;
|
|
814
1029
|
}
|
|
1030
|
+
const idsFlag = getFlag(args, "--ids");
|
|
1031
|
+
if (idsFlag) {
|
|
1032
|
+
const ids = idsFlag.split(",").map((id2) => id2.trim()).filter(Boolean);
|
|
1033
|
+
if (ids.length === 0) {
|
|
1034
|
+
console.error("No valid IDs provided.");
|
|
1035
|
+
process.exit(1);
|
|
1036
|
+
}
|
|
1037
|
+
if (!hasFlag(args, "--read") && !hasFlag(args, "--unread")) {
|
|
1038
|
+
console.error("Bulk update requires --read or --unread.");
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
}
|
|
1041
|
+
const read = hasFlag(args, "--read");
|
|
1042
|
+
const { data: data2 } = await api("PATCH", "/api/links", { ids, read });
|
|
1043
|
+
if (hasFlag(args, "--json")) {
|
|
1044
|
+
console.log(JSON.stringify(data2, null, 2));
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
console.log(`Updated ${data2.updated} link(s).`);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
815
1050
|
const id = getPositional(args);
|
|
816
1051
|
if (!id) {
|
|
817
1052
|
console.error("Usage: shiori update <id> [--read | --unread | --title <title> | --restore]");
|
|
@@ -845,6 +1080,34 @@ Options:
|
|
|
845
1080
|
console.log(data.message || "Updated.");
|
|
846
1081
|
}
|
|
847
1082
|
|
|
1083
|
+
// src/commands/whoami.ts
|
|
1084
|
+
async function run12(args) {
|
|
1085
|
+
if (hasFlag(args, "--help", "-h")) {
|
|
1086
|
+
console.log(`shiori whoami - Show current user info
|
|
1087
|
+
|
|
1088
|
+
Usage: shiori whoami [options]
|
|
1089
|
+
|
|
1090
|
+
Options:
|
|
1091
|
+
--json Output raw JSON
|
|
1092
|
+
--help, -h Show this help`);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
const { data } = await api("GET", "/api/user/me");
|
|
1096
|
+
if (hasFlag(args, "--json")) {
|
|
1097
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const user = data.user;
|
|
1101
|
+
console.log(`
|
|
1102
|
+
Name: ${user.full_name || "--"}`);
|
|
1103
|
+
const plan = user.subscription?.plan === "subscription" ? "Pro" : user.subscription?.plan || "Free";
|
|
1104
|
+
console.log(` Plan: ${plan}`);
|
|
1105
|
+
console.log(
|
|
1106
|
+
` Member since: ${new Date(user.created_at).toLocaleDateString("en-US", { month: "long", year: "numeric" })}`
|
|
1107
|
+
);
|
|
1108
|
+
console.log();
|
|
1109
|
+
}
|
|
1110
|
+
|
|
848
1111
|
// src/error-report.ts
|
|
849
1112
|
function reportError(command, error) {
|
|
850
1113
|
const raw = error instanceof Error ? error.message : String(error);
|
|
@@ -854,7 +1117,7 @@ function reportError(command, error) {
|
|
|
854
1117
|
method: "POST",
|
|
855
1118
|
headers: { "Content-Type": "application/json" },
|
|
856
1119
|
body: JSON.stringify({
|
|
857
|
-
version: "0.
|
|
1120
|
+
version: "0.7.0",
|
|
858
1121
|
command,
|
|
859
1122
|
error: message,
|
|
860
1123
|
platform: process.platform
|
|
@@ -896,15 +1159,16 @@ async function checkForUpdate(currentVersion, isJson) {
|
|
|
896
1159
|
var COMMANDS = {
|
|
897
1160
|
auth: { run, desc: "Authenticate with Shiori (browser or API key)" },
|
|
898
1161
|
list: { run: run5, desc: "List saved links" },
|
|
899
|
-
search: { run:
|
|
1162
|
+
search: { run: run7, desc: "Search saved links" },
|
|
900
1163
|
get: { run: run4, desc: "Get a link by ID (includes content)" },
|
|
901
1164
|
content: { run: run2, desc: "Print link content as markdown" },
|
|
902
|
-
save: { run:
|
|
1165
|
+
save: { run: run6, desc: "Save a new link" },
|
|
903
1166
|
update: { run: run11, desc: "Update a link" },
|
|
904
1167
|
delete: { run: run3, desc: "Delete a link (move to trash)" },
|
|
905
1168
|
trash: { run: run10, desc: "List or empty the trash" },
|
|
906
|
-
subscriptions: { run:
|
|
907
|
-
|
|
1169
|
+
subscriptions: { run: run8, desc: "Manage RSS subscriptions" },
|
|
1170
|
+
tags: { run: run9, desc: "Manage tags" },
|
|
1171
|
+
whoami: { run: run12, desc: "Show current user info" }
|
|
908
1172
|
};
|
|
909
1173
|
function printHelp() {
|
|
910
1174
|
console.log(`shiori - Manage your Shiori link library from the terminal
|
|
@@ -923,7 +1187,8 @@ Get started:
|
|
|
923
1187
|
shiori list List your recent links
|
|
924
1188
|
shiori save <url> Save a new link
|
|
925
1189
|
shiori search <query> Search your links
|
|
926
|
-
shiori content <id> Print markdown content (pipe to other tools)
|
|
1190
|
+
shiori content <id> Print markdown content (pipe to other tools)
|
|
1191
|
+
shiori whoami Show your account info`);
|
|
927
1192
|
}
|
|
928
1193
|
async function main() {
|
|
929
1194
|
const args = process.argv.slice(2);
|
|
@@ -933,7 +1198,7 @@ async function main() {
|
|
|
933
1198
|
return;
|
|
934
1199
|
}
|
|
935
1200
|
if (command === "--version" || command === "-v") {
|
|
936
|
-
console.log("0.
|
|
1201
|
+
console.log("0.7.0");
|
|
937
1202
|
return;
|
|
938
1203
|
}
|
|
939
1204
|
const cmd = COMMANDS[command];
|
|
@@ -946,7 +1211,7 @@ async function main() {
|
|
|
946
1211
|
const cmdArgs = args.slice(1);
|
|
947
1212
|
const isJson = cmdArgs.includes("--json");
|
|
948
1213
|
await cmd.run(cmdArgs);
|
|
949
|
-
checkForUpdate("0.
|
|
1214
|
+
checkForUpdate("0.7.0", isJson).catch(() => {
|
|
950
1215
|
});
|
|
951
1216
|
}
|
|
952
1217
|
main().catch((err) => {
|