@airscript/ghitgud 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/VERSION +1 -1
- package/dist/index.js +226 -9
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -54,6 +54,15 @@ ghitgud config get repo
|
|
|
54
54
|
## Commands
|
|
55
55
|
|
|
56
56
|
```
|
|
57
|
+
ghitgud gh <args> Pass through to the gh CLI
|
|
58
|
+
ghitgud notifications list List notifications
|
|
59
|
+
ghitgud notifications list -a Include read notifications
|
|
60
|
+
ghitgud notifications list -p Only participating
|
|
61
|
+
ghitgud notifications list -r owner/repo Filter by repository
|
|
62
|
+
ghitgud notifications read <id> Mark a notification as read
|
|
63
|
+
ghitgud notifications done <id> Mark a notification as done
|
|
64
|
+
ghitgud activity Assigned issues, review requests, mentions
|
|
65
|
+
ghitgud mentions Recent @mentions of you
|
|
57
66
|
ghitgud ping Check if the CLI is working
|
|
58
67
|
ghitgud labels list List all labels for a repository
|
|
59
68
|
ghitgud labels pull Pull labels from a repository to local config
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.1.0
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ let commander = require("commander");
|
|
|
39
39
|
let figlet = require("figlet");
|
|
40
40
|
figlet = __toESM(figlet);
|
|
41
41
|
let consola = require("consola");
|
|
42
|
+
let child_process = require("child_process");
|
|
42
43
|
let path = require("path");
|
|
43
44
|
path = __toESM(path);
|
|
44
45
|
let fs = require("fs");
|
|
@@ -57,6 +58,29 @@ var ascii = figlet.default.textSync("Ghitgud", {
|
|
|
57
58
|
//#region src/core/logger.ts
|
|
58
59
|
var logger = (0, consola.createConsola)({ defaults: { tag: "ghitgud" } });
|
|
59
60
|
//#endregion
|
|
61
|
+
//#region src/commands/gh.ts
|
|
62
|
+
var register$6 = (program) => {
|
|
63
|
+
program.command("gh").description("Pass through to the gh CLI. Usage: ghitgud gh <args>").allowUnknownOption().action((_opts, command) => {
|
|
64
|
+
const args = command.args;
|
|
65
|
+
const child = (0, child_process.spawn)("gh", args, {
|
|
66
|
+
stdio: "inherit",
|
|
67
|
+
shell: false
|
|
68
|
+
});
|
|
69
|
+
child.on("error", (error) => {
|
|
70
|
+
if (error.code === "ENOENT") {
|
|
71
|
+
logger.error("gh CLI is not installed. Install it from https://cli.github.com.");
|
|
72
|
+
process$1.default.exit(1);
|
|
73
|
+
}
|
|
74
|
+
logger.error(String(error));
|
|
75
|
+
process$1.default.exit(1);
|
|
76
|
+
});
|
|
77
|
+
child.on("exit", (code) => {
|
|
78
|
+
process$1.default.exitCode = code ?? 0;
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
var gh_default = { register: register$6 };
|
|
83
|
+
//#endregion
|
|
60
84
|
//#region src/core/constants.ts
|
|
61
85
|
var GHITGUD_FOLDER = path.default.join(os.default.homedir(), ".config", "ghitgud");
|
|
62
86
|
var CREDENTIALS_FILE = "credentials.json";
|
|
@@ -76,6 +100,7 @@ var ERROR_NO_REPO = "Repository not configured. Set it with: ghitgud config set
|
|
|
76
100
|
var ERROR_NO_TOKEN = "Token not configured. Set it with: ghitgud config set token <your-token>.";
|
|
77
101
|
var ERROR_UNSUPPORTED_KEY = "Trying to set unsupported key.";
|
|
78
102
|
var ERROR_NO_METADATA = "No metadata file found.";
|
|
103
|
+
var INFO_NO_NOTIFICATIONS = "No notifications found.";
|
|
79
104
|
var PING_RESPONSE = "pong";
|
|
80
105
|
var SUPPORTED_CONFIG_KEYS = ["token", "repo"];
|
|
81
106
|
//#endregion
|
|
@@ -562,6 +587,10 @@ var client = {
|
|
|
562
587
|
method: "PATCH",
|
|
563
588
|
body
|
|
564
589
|
}),
|
|
590
|
+
put: (endpoint, body) => request(endpoint, {
|
|
591
|
+
method: "PUT",
|
|
592
|
+
body
|
|
593
|
+
}),
|
|
565
594
|
getRepo: () => config.getRepo(),
|
|
566
595
|
isOk: (status) => isSuccessful(status),
|
|
567
596
|
isNotFound: (status) => status === 404,
|
|
@@ -624,7 +653,7 @@ var ping = () => {
|
|
|
624
653
|
message: PING_RESPONSE
|
|
625
654
|
};
|
|
626
655
|
};
|
|
627
|
-
var list = async () => {
|
|
656
|
+
var list$1 = async () => {
|
|
628
657
|
logger.info("Fetching labels from repository.");
|
|
629
658
|
const labels$1 = (await (await labels.fetch()).json()).map((label) => normalizeLabel(label));
|
|
630
659
|
formatLabels(labels$1);
|
|
@@ -697,7 +726,7 @@ var prune = async () => {
|
|
|
697
726
|
};
|
|
698
727
|
var labels_default$1 = {
|
|
699
728
|
ping,
|
|
700
|
-
list,
|
|
729
|
+
list: list$1,
|
|
701
730
|
pull,
|
|
702
731
|
pullTemplate,
|
|
703
732
|
push,
|
|
@@ -706,13 +735,13 @@ var labels_default$1 = {
|
|
|
706
735
|
};
|
|
707
736
|
//#endregion
|
|
708
737
|
//#region src/commands/ping.ts
|
|
709
|
-
var register$
|
|
738
|
+
var register$5 = (program) => {
|
|
710
739
|
program.command("ping").description("Check if the CLI is working.").action(() => void labels_default$1.ping());
|
|
711
740
|
};
|
|
712
|
-
var ping_default = { register: register$
|
|
741
|
+
var ping_default = { register: register$5 };
|
|
713
742
|
//#endregion
|
|
714
743
|
//#region src/commands/labels.ts
|
|
715
|
-
var register$
|
|
744
|
+
var register$4 = (program) => {
|
|
716
745
|
const labels = program.command("labels").description("Manage labels for a repository.");
|
|
717
746
|
labels.command("list").description("List all labels for a repository.").action(() => void labels_default$1.list());
|
|
718
747
|
labels.command("pull").description("Pull all related labels for a repository.").option("-t, --template <name>", "Pull from a built-in template instead of the remote repository").action(async (options) => {
|
|
@@ -725,7 +754,7 @@ var register$1 = (program) => {
|
|
|
725
754
|
});
|
|
726
755
|
labels.command("prune").description("Prune all related labels for a repository.").action(() => void labels_default$1.prune());
|
|
727
756
|
};
|
|
728
|
-
var labels_default = { register: register$
|
|
757
|
+
var labels_default = { register: register$4 };
|
|
729
758
|
//#endregion
|
|
730
759
|
//#region src/services/config.ts
|
|
731
760
|
var validateKey = (key) => {
|
|
@@ -755,7 +784,7 @@ var config_default$1 = {
|
|
|
755
784
|
};
|
|
756
785
|
//#endregion
|
|
757
786
|
//#region src/commands/config.ts
|
|
758
|
-
var register = (program) => {
|
|
787
|
+
var register$3 = (program) => {
|
|
759
788
|
const config = program.command("config").description("Set CLI configurations.");
|
|
760
789
|
config.command("set").description("Set configuration.").arguments("<key> <value>").action((key, value) => {
|
|
761
790
|
config_default$1.set(key, value);
|
|
@@ -764,10 +793,198 @@ var register = (program) => {
|
|
|
764
793
|
config_default$1.get(key);
|
|
765
794
|
});
|
|
766
795
|
};
|
|
767
|
-
var config_default = { register };
|
|
796
|
+
var config_default = { register: register$3 };
|
|
797
|
+
//#endregion
|
|
798
|
+
//#region src/api/notifications.ts
|
|
799
|
+
var BASE_PATH = "/notifications";
|
|
800
|
+
var notifications = {
|
|
801
|
+
fetch: (params) => {
|
|
802
|
+
const query = new URLSearchParams();
|
|
803
|
+
if (params?.all) query.set("all", "true");
|
|
804
|
+
if (params?.participating) query.set("participating", "true");
|
|
805
|
+
if (params?.perPage) query.set("per_page", String(params.perPage));
|
|
806
|
+
const qs = query.toString();
|
|
807
|
+
const endpoint = qs ? `${BASE_PATH}?${qs}` : BASE_PATH;
|
|
808
|
+
return client.get(endpoint);
|
|
809
|
+
},
|
|
810
|
+
markRead: (id) => {
|
|
811
|
+
return client.patch(`/notifications/threads/${id}`, {});
|
|
812
|
+
},
|
|
813
|
+
markDone: (id) => {
|
|
814
|
+
return client.put(`/notifications/threads/${id}/subscription`, { ignored: true });
|
|
815
|
+
},
|
|
816
|
+
assignedIssues: () => {
|
|
817
|
+
return client.get("/issues?filter=assigned&state=open");
|
|
818
|
+
},
|
|
819
|
+
reviewRequests: () => {
|
|
820
|
+
return client.get("/search/issues?q=is:pr+is:open+review-requested:@me");
|
|
821
|
+
},
|
|
822
|
+
mentions: (username) => {
|
|
823
|
+
const since = (/* @__PURE__ */ new Date(Date.now() - 10080 * 60 * 1e3)).toISOString().split("T")[0];
|
|
824
|
+
return client.get(`/search/issues?q=mentions:${username}+updated:>${since}`);
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
//#endregion
|
|
828
|
+
//#region src/types/notifications.ts
|
|
829
|
+
var normalizeThread = (item) => {
|
|
830
|
+
const data = item;
|
|
831
|
+
const repo = data.repository ?? {};
|
|
832
|
+
const subject = data.subject ?? {};
|
|
833
|
+
return {
|
|
834
|
+
id: String(data.id),
|
|
835
|
+
repository: String(repo.full_name ?? ""),
|
|
836
|
+
subjectTitle: String(subject.title ?? ""),
|
|
837
|
+
subjectType: String(subject.type ?? ""),
|
|
838
|
+
reason: String(data.reason ?? ""),
|
|
839
|
+
unread: Boolean(data.unread),
|
|
840
|
+
updatedAt: String(data.updated_at ?? "")
|
|
841
|
+
};
|
|
842
|
+
};
|
|
843
|
+
var normalizeIssue = (item) => {
|
|
844
|
+
const data = item;
|
|
845
|
+
const repo = data.repository ?? {};
|
|
846
|
+
return {
|
|
847
|
+
id: String(data.id),
|
|
848
|
+
repository: String(repo.full_name ?? ""),
|
|
849
|
+
subjectTitle: String(data.title ?? ""),
|
|
850
|
+
subjectType: String(data.pull_request ? "PullRequest" : "Issue"),
|
|
851
|
+
reason: "assigned",
|
|
852
|
+
unread: false,
|
|
853
|
+
updatedAt: String(data.updated_at ?? "")
|
|
854
|
+
};
|
|
855
|
+
};
|
|
856
|
+
var normalizeSearchItem = (item) => {
|
|
857
|
+
const data = item;
|
|
858
|
+
return {
|
|
859
|
+
id: String(data.id),
|
|
860
|
+
repository: String(data.repository_url ?? "").replace("https://api.github.com/repos/", ""),
|
|
861
|
+
subjectTitle: String(data.title ?? ""),
|
|
862
|
+
subjectType: String(data.pull_request ? "PullRequest" : "Issue"),
|
|
863
|
+
reason: "mention",
|
|
864
|
+
unread: false,
|
|
865
|
+
updatedAt: String(data.updated_at ?? "")
|
|
866
|
+
};
|
|
867
|
+
};
|
|
868
|
+
//#endregion
|
|
869
|
+
//#region src/services/notifications.ts
|
|
870
|
+
var formatTable = (notifications) => {
|
|
871
|
+
if (notifications.length === 0) {
|
|
872
|
+
logger.info(INFO_NO_NOTIFICATIONS);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
console.log();
|
|
876
|
+
console.table(notifications.map((n) => ({
|
|
877
|
+
repository: n.repository,
|
|
878
|
+
subject: n.subjectTitle,
|
|
879
|
+
type: n.subjectType,
|
|
880
|
+
reason: n.reason
|
|
881
|
+
})));
|
|
882
|
+
};
|
|
883
|
+
var list = async (options = {}) => {
|
|
884
|
+
logger.info("Fetching notifications.");
|
|
885
|
+
let notifications$1 = (await (await notifications.fetch({
|
|
886
|
+
all: options.all,
|
|
887
|
+
participating: options.participating,
|
|
888
|
+
perPage: options.limit
|
|
889
|
+
})).json()).map(normalizeThread);
|
|
890
|
+
if (options.repo) notifications$1 = notifications$1.filter((n) => n.repository === options.repo);
|
|
891
|
+
formatTable(notifications$1);
|
|
892
|
+
return {
|
|
893
|
+
success: true,
|
|
894
|
+
metadata: notifications$1
|
|
895
|
+
};
|
|
896
|
+
};
|
|
897
|
+
var markRead = async (id) => {
|
|
898
|
+
logger.info(`Marking notification ${id} as read.`);
|
|
899
|
+
await notifications.markRead(id);
|
|
900
|
+
logger.success("Notification marked as read.");
|
|
901
|
+
return { success: true };
|
|
902
|
+
};
|
|
903
|
+
var markDone = async (id) => {
|
|
904
|
+
logger.info(`Marking notification ${id} as done.`);
|
|
905
|
+
await notifications.markDone(id);
|
|
906
|
+
logger.success("Notification marked as done.");
|
|
907
|
+
return { success: true };
|
|
908
|
+
};
|
|
909
|
+
var activity = async () => {
|
|
910
|
+
logger.info("Fetching activity.");
|
|
911
|
+
const [issuesRes, reviewsRes, mentionsRes] = await Promise.all([
|
|
912
|
+
notifications.assignedIssues(),
|
|
913
|
+
notifications.reviewRequests(),
|
|
914
|
+
notifications.mentions("@me")
|
|
915
|
+
]);
|
|
916
|
+
const assignedIssues = await issuesRes.json();
|
|
917
|
+
const reviewData = await reviewsRes.json();
|
|
918
|
+
const mentionData = await mentionsRes.json();
|
|
919
|
+
const result = {
|
|
920
|
+
assignedIssues: assignedIssues.map(normalizeIssue),
|
|
921
|
+
reviewRequests: (reviewData.items ?? []).map(normalizeSearchItem),
|
|
922
|
+
recentMentions: (mentionData.items ?? []).map(normalizeSearchItem)
|
|
923
|
+
};
|
|
924
|
+
console.log();
|
|
925
|
+
console.log("Assigned Issues:", result.assignedIssues.length);
|
|
926
|
+
console.log("Review Requests:", result.reviewRequests.length);
|
|
927
|
+
console.log("Recent Mentions:", result.recentMentions.length);
|
|
928
|
+
return {
|
|
929
|
+
success: true,
|
|
930
|
+
metadata: result
|
|
931
|
+
};
|
|
932
|
+
};
|
|
933
|
+
var mentions = async () => {
|
|
934
|
+
logger.info("Fetching mentions.");
|
|
935
|
+
const notifications$2 = ((await (await notifications.mentions("@me")).json()).items ?? []).map(normalizeSearchItem);
|
|
936
|
+
formatTable(notifications$2);
|
|
937
|
+
return {
|
|
938
|
+
success: true,
|
|
939
|
+
metadata: notifications$2
|
|
940
|
+
};
|
|
941
|
+
};
|
|
942
|
+
var notifications_default$1 = {
|
|
943
|
+
list,
|
|
944
|
+
markRead,
|
|
945
|
+
markDone,
|
|
946
|
+
activity,
|
|
947
|
+
mentions
|
|
948
|
+
};
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/commands/mentions.ts
|
|
951
|
+
var register$2 = (program) => {
|
|
952
|
+
program.command("mentions").description("Find recent @mentions of you.").action(() => void notifications_default$1.mentions());
|
|
953
|
+
};
|
|
954
|
+
var mentions_default = { register: register$2 };
|
|
955
|
+
//#endregion
|
|
956
|
+
//#region src/commands/activity.ts
|
|
957
|
+
var register$1 = (program) => {
|
|
958
|
+
program.command("activity").description("Show assigned issues, review requests, and mentions.").action(() => void notifications_default$1.activity());
|
|
959
|
+
};
|
|
960
|
+
var activity_default = { register: register$1 };
|
|
961
|
+
//#endregion
|
|
962
|
+
//#region src/commands/notifications.ts
|
|
963
|
+
var register = (program) => {
|
|
964
|
+
const notifications = program.command("notifications").description("Manage GitHub notifications.");
|
|
965
|
+
notifications.command("list").description("List notifications.").option("-a, --all", "Include read notifications").option("-p, --participating", "Only participating notifications").option("-r, --repo <owner/repo>", "Filter by repository").option("-l, --limit <n>", "Max results").action((options) => {
|
|
966
|
+
notifications_default$1.list({
|
|
967
|
+
all: options.all,
|
|
968
|
+
participating: options.participating,
|
|
969
|
+
repo: options.repo,
|
|
970
|
+
limit: options.limit ? parseInt(options.limit, 10) : void 0
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
notifications.command("read <id>").description("Mark a notification as read.").action((id) => {
|
|
974
|
+
notifications_default$1.markRead(id);
|
|
975
|
+
});
|
|
976
|
+
notifications.command("done <id>").description("Mark a notification as done.").action((id) => {
|
|
977
|
+
notifications_default$1.markDone(id);
|
|
978
|
+
});
|
|
979
|
+
};
|
|
980
|
+
var notifications_default = { register };
|
|
768
981
|
//#endregion
|
|
769
982
|
//#region src/cli/index.ts
|
|
770
|
-
commander.program.name("ghitgud").description("A simple CLI to give superpowers to GitHub.").version("2.
|
|
983
|
+
commander.program.name("ghitgud").description("A simple CLI to give superpowers to GitHub.").version("2.1.0");
|
|
984
|
+
gh_default.register(commander.program);
|
|
985
|
+
notifications_default.register(commander.program);
|
|
986
|
+
activity_default.register(commander.program);
|
|
987
|
+
mentions_default.register(commander.program);
|
|
771
988
|
ping_default.register(commander.program);
|
|
772
989
|
labels_default.register(commander.program);
|
|
773
990
|
config_default.register(commander.program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@airscript/ghitgud",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A simple CLI to give superpowers to GitHub.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"lint": "eslint src/ tests/",
|
|
31
31
|
"format": "prettier --write .",
|
|
32
32
|
"format:check": "prettier --check .",
|
|
33
|
-
"clean": "rm -rf dist coverage"
|
|
33
|
+
"clean": "rm -rf dist coverage",
|
|
34
|
+
"prepare": "husky && pnpm build"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"@vitest/coverage-v8": "^3.2.4",
|
|
50
51
|
"eslint": "10.3.0",
|
|
51
52
|
"eslint-config-prettier": "10.1.8",
|
|
53
|
+
"husky": "9.1.7",
|
|
52
54
|
"prettier": "3.8.3",
|
|
53
55
|
"typescript": "^5.8.3",
|
|
54
56
|
"typescript-eslint": "8.59.2",
|