@solaqua/gji 0.8.0 → 0.9.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 +24 -30
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +37 -0
- package/dist/clean.js +34 -19
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +59 -4
- package/dist/doctor.d.ts +28 -0
- package/dist/doctor.js +454 -0
- package/dist/gji-bundle.mjs +2514 -378
- package/dist/go.d.ts +2 -1
- package/dist/go.js +4 -1
- package/dist/index.js +12 -6
- package/dist/init.d.ts +15 -0
- package/dist/init.js +232 -16
- package/dist/open.d.ts +2 -1
- package/dist/open.js +2 -1
- package/dist/pr-open.d.ts +19 -0
- package/dist/pr-open.js +290 -0
- package/dist/pull-requests.d.ts +33 -0
- package/dist/pull-requests.js +384 -0
- package/dist/remove.js +2 -2
- package/dist/repo-registry.d.ts +5 -0
- package/dist/repo-registry.js +87 -14
- package/dist/shell-completion.js +278 -10
- package/dist/shell-setup.d.ts +9 -0
- package/dist/shell-setup.js +56 -0
- package/dist/warp.d.ts +3 -0
- package/dist/warp.js +8 -3
- package/dist/worktree-management.d.ts +2 -1
- package/dist/worktree-management.js +23 -7
- package/dist/worktree-picker.d.ts +12 -1
- package/dist/worktree-picker.js +84 -6
- package/man/man1/gji-back.1 +1 -1
- package/man/man1/gji-clean.1 +1 -1
- package/man/man1/gji-completion.1 +1 -1
- package/man/man1/gji-config.1 +1 -1
- package/man/man1/gji-doctor.1 +19 -0
- package/man/man1/gji-go.1 +1 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +6 -3
- package/man/man1/gji-ls.1 +1 -1
- package/man/man1/gji-new.1 +1 -1
- package/man/man1/gji-open.1 +1 -1
- package/man/man1/gji-pr.1 +5 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-run-hook.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync-files.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +6 -2
- package/package.json +1 -1
package/dist/worktree-picker.js
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { env, platform, stdin, stdout } from "node:process";
|
|
2
2
|
import { isCancel, Prompt } from "@clack/core";
|
|
3
3
|
import { loadHistory } from "./history.js";
|
|
4
|
+
import { createPullRequestQuery, } from "./pull-requests.js";
|
|
4
5
|
import { readWorktreeInfos, } from "./worktree-info.js";
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const MAX_PULL_REQUEST_REPOSITORY_QUERY_CONCURRENCY = 4;
|
|
7
|
+
export async function buildWorktreePromptEntries(sources, dependencies = {}) {
|
|
8
|
+
const pullRequestQuery = createPullRequestQuery();
|
|
9
|
+
const queryPullRequests = dependencies.queryPullRequests ?? pullRequestQuery.listOpenPullRequests;
|
|
10
|
+
const queryRepositoryPullRequests = dependencies.queryRepositoryPullRequests ??
|
|
11
|
+
(dependencies.queryPullRequests === undefined
|
|
12
|
+
? pullRequestQuery.listOpenPullRequestsForRepository
|
|
13
|
+
: undefined);
|
|
14
|
+
const repositoryPullRequests = queryRepositoryPullRequests === undefined
|
|
15
|
+
? Promise.resolve(null)
|
|
16
|
+
: readRepositoryPullRequests(sources, queryRepositoryPullRequests);
|
|
17
|
+
const [history, infos, pullRequestsByRepository] = await Promise.all([
|
|
7
18
|
loadHistory(),
|
|
8
19
|
readWorktreeInfos(sources.map((source) => source.worktree)),
|
|
20
|
+
repositoryPullRequests,
|
|
9
21
|
]);
|
|
22
|
+
const pullRequests = await Promise.all(sources.map((source) => readSourcePullRequests(source, queryPullRequests, pullRequestsByRepository)));
|
|
10
23
|
const historyByPath = new Map(history.map((entry) => [entry.path, entry]));
|
|
11
|
-
const entries = sources.map((source, index) => buildWorktreePromptEntry(source, infos[index], historyByPath.get(source.worktree.path)?.timestamp ?? null, Date.now()));
|
|
24
|
+
const entries = sources.map((source, index) => buildWorktreePromptEntry(source, infos[index], pullRequests[index], historyByPath.get(source.worktree.path)?.timestamp ?? null, Date.now()));
|
|
12
25
|
return entries
|
|
13
26
|
.sort(comparePromptEntries)
|
|
14
27
|
.map(({ lastActivityTimestamp: _lastActivityTimestamp, ...entry }) => entry);
|
|
@@ -110,7 +123,7 @@ function buildSearchableWorktreeEntry(worktree) {
|
|
|
110
123
|
searchText: buildPromptSearchText(worktree),
|
|
111
124
|
value: worktree.path,
|
|
112
125
|
worktree: {
|
|
113
|
-
branch,
|
|
126
|
+
branch: formatWorktreeBranchLabel(worktree.branch, worktree.pullRequestNumbers),
|
|
114
127
|
metadata,
|
|
115
128
|
path: worktree.path,
|
|
116
129
|
repoName: worktree.repoName,
|
|
@@ -715,11 +728,13 @@ function buildPromptSearchText(worktree) {
|
|
|
715
728
|
worktree.path,
|
|
716
729
|
worktree.label,
|
|
717
730
|
`${worktree.repoName}/${worktree.branch ?? "detached"}`,
|
|
731
|
+
...(worktree.pullRequestNumbers ?? []).map((number) => `#${number}`),
|
|
732
|
+
...(worktree.pullRequestUrls ?? []),
|
|
718
733
|
]
|
|
719
734
|
.join(" ")
|
|
720
735
|
.toLowerCase();
|
|
721
736
|
}
|
|
722
|
-
function buildWorktreePromptEntry(source, info, lastUsedTimestamp, now) {
|
|
737
|
+
function buildWorktreePromptEntry(source, info, pullRequests, lastUsedTimestamp, now) {
|
|
723
738
|
const lastWorkedTimestamp = info.lastCommitTimestamp === null ? null : info.lastCommitTimestamp * 1000;
|
|
724
739
|
const lastActivityTimestamp = lastUsedTimestamp ?? lastWorkedTimestamp;
|
|
725
740
|
const lastActivityType = lastUsedTimestamp !== null
|
|
@@ -727,7 +742,7 @@ function buildWorktreePromptEntry(source, info, lastUsedTimestamp, now) {
|
|
|
727
742
|
: lastWorkedTimestamp !== null
|
|
728
743
|
? "worked"
|
|
729
744
|
: null;
|
|
730
|
-
const branch = source.worktree.branch
|
|
745
|
+
const branch = formatWorktreeBranchLabel(source.worktree.branch, pullRequests.map((pullRequest) => pullRequest.number));
|
|
731
746
|
const badges = buildStatusBadges(info);
|
|
732
747
|
const recency = formatPromptRecency(lastActivityTimestamp, lastActivityType, now);
|
|
733
748
|
const status = badges.length > 0 ? badges.map((badge) => `[${badge}]`).join(" ") : null;
|
|
@@ -748,9 +763,72 @@ function buildWorktreePromptEntry(source, info, lastUsedTimestamp, now) {
|
|
|
748
763
|
label,
|
|
749
764
|
lastActivityTimestamp,
|
|
750
765
|
metadata,
|
|
766
|
+
pullRequestNumbers: pullRequests.map((pullRequest) => pullRequest.number),
|
|
767
|
+
pullRequestUrls: pullRequests.map((pullRequest) => pullRequest.url),
|
|
751
768
|
repoName: source.repoName,
|
|
752
769
|
};
|
|
753
770
|
}
|
|
771
|
+
async function readSourcePullRequests(source, queryPullRequests, pullRequestsByRepository) {
|
|
772
|
+
if (source.repoRoot === undefined || source.worktree.branch === null) {
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
if (pullRequestsByRepository !== null) {
|
|
776
|
+
return sortSourcePullRequests(pullRequestsByRepository
|
|
777
|
+
.get(source.repoRoot)
|
|
778
|
+
?.filter((pullRequest) => pullRequest.sourceBranch === source.worktree.branch));
|
|
779
|
+
}
|
|
780
|
+
try {
|
|
781
|
+
const pullRequests = await queryPullRequests(source.repoRoot, source.worktree.branch);
|
|
782
|
+
return sortSourcePullRequests(pullRequests);
|
|
783
|
+
}
|
|
784
|
+
catch {
|
|
785
|
+
// PR metadata is optional selector decoration; preserve the worktree entry on lookup failures.
|
|
786
|
+
return [];
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
async function readRepositoryPullRequests(sources, queryPullRequests) {
|
|
790
|
+
const repoRoots = [
|
|
791
|
+
...new Set(sources.flatMap((source) => source.repoRoot === undefined || source.worktree.branch === null
|
|
792
|
+
? []
|
|
793
|
+
: [source.repoRoot])),
|
|
794
|
+
];
|
|
795
|
+
const results = await mapWithConcurrency(repoRoots, MAX_PULL_REQUEST_REPOSITORY_QUERY_CONCURRENCY, async (repoRoot) => {
|
|
796
|
+
try {
|
|
797
|
+
return [
|
|
798
|
+
repoRoot,
|
|
799
|
+
sortSourcePullRequests(await queryPullRequests(repoRoot)),
|
|
800
|
+
];
|
|
801
|
+
}
|
|
802
|
+
catch {
|
|
803
|
+
return [repoRoot, []];
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
return new Map(results);
|
|
807
|
+
}
|
|
808
|
+
async function mapWithConcurrency(items, limit, mapper) {
|
|
809
|
+
const results = new Array(items.length);
|
|
810
|
+
let nextIndex = 0;
|
|
811
|
+
async function readNext() {
|
|
812
|
+
for (;;) {
|
|
813
|
+
const index = nextIndex;
|
|
814
|
+
nextIndex += 1;
|
|
815
|
+
if (index >= items.length)
|
|
816
|
+
return;
|
|
817
|
+
results[index] = await mapper(items[index]);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => readNext()));
|
|
821
|
+
return results;
|
|
822
|
+
}
|
|
823
|
+
function sortSourcePullRequests(pullRequests) {
|
|
824
|
+
return [...(pullRequests ?? [])].sort((a, b) => a.number - b.number);
|
|
825
|
+
}
|
|
826
|
+
export function formatWorktreeBranchLabel(branch, pullRequestNumbers = []) {
|
|
827
|
+
const branchLabel = branch ?? "(detached)";
|
|
828
|
+
if (pullRequestNumbers.length === 0)
|
|
829
|
+
return branchLabel;
|
|
830
|
+
return `${branchLabel} (${pullRequestNumbers.map((number) => `#${number}`).join(", ")})`;
|
|
831
|
+
}
|
|
754
832
|
function buildStatusBadges(info) {
|
|
755
833
|
const badges = [];
|
|
756
834
|
if (info.isCurrent) {
|
package/man/man1/gji-back.1
CHANGED
package/man/man1/gji-clean.1
CHANGED
package/man/man1/gji-config.1
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.TH GJI\-DOCTOR 1 "July 2026" "gji 0.9.0" "User Commands"
|
|
2
|
+
.SH NAME
|
|
3
|
+
gji\-doctor \- check gji installation and configuration health
|
|
4
|
+
.SH SYNOPSIS
|
|
5
|
+
.B gji doctor [\fIoptions\fR] [options]
|
|
6
|
+
.SH DESCRIPTION
|
|
7
|
+
check gji installation and configuration health
|
|
8
|
+
.SH OPTIONS
|
|
9
|
+
.TP
|
|
10
|
+
.B \-\-fix
|
|
11
|
+
apply safe automatic fixes after showing the plan
|
|
12
|
+
.TP
|
|
13
|
+
.B \-\-yes
|
|
14
|
+
apply \-\-fix without prompting
|
|
15
|
+
.TP
|
|
16
|
+
.B \-\-json
|
|
17
|
+
emit diagnostic checks as JSON
|
|
18
|
+
.SH "SEE ALSO"
|
|
19
|
+
.BR gji (1)
|
package/man/man1/gji-go.1
CHANGED
package/man/man1/gji-history.1
CHANGED
package/man/man1/gji-init.1
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
.TH GJI\-INIT 1 "July 2026" "gji 0.
|
|
1
|
+
.TH GJI\-INIT 1 "July 2026" "gji 0.9.0" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
|
-
gji\-init \-
|
|
3
|
+
gji\-init \- set up shell integration interactively or print a shell wrapper
|
|
4
4
|
.SH SYNOPSIS
|
|
5
5
|
.B gji init [\fIoptions\fR] [options] [shell]
|
|
6
6
|
.SH DESCRIPTION
|
|
7
|
-
|
|
7
|
+
set up shell integration interactively or print a shell wrapper
|
|
8
8
|
.SH OPTIONS
|
|
9
9
|
.TP
|
|
10
10
|
.B \-\-write
|
|
11
11
|
write the integration to the shell config file
|
|
12
|
+
.TP
|
|
13
|
+
.B \-\-json
|
|
14
|
+
emit a JSON error in non\-interactive mode
|
|
12
15
|
.SH "SEE ALSO"
|
|
13
16
|
.BR gji (1)
|
package/man/man1/gji-ls.1
CHANGED
package/man/man1/gji-new.1
CHANGED
package/man/man1/gji-open.1
CHANGED
package/man/man1/gji-pr.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH GJI\-PR 1 "July 2026" "gji 0.
|
|
1
|
+
.TH GJI\-PR 1 "July 2026" "gji 0.9.0" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
3
|
gji\-pr \- fetch a pull request by number, #number, or URL into a linked worktree
|
|
4
4
|
.SH SYNOPSIS
|
|
@@ -12,5 +12,9 @@ show what would be created without executing any git commands or writing files
|
|
|
12
12
|
.TP
|
|
13
13
|
.B \-\-json
|
|
14
14
|
emit JSON on success or error instead of human\-readable output
|
|
15
|
+
.SH SUBCOMMANDS
|
|
16
|
+
.TP
|
|
17
|
+
.B open
|
|
18
|
+
open an existing pull request in the default browser
|
|
15
19
|
.SH "SEE ALSO"
|
|
16
20
|
.BR gji (1)
|
package/man/man1/gji-remove.1
CHANGED
package/man/man1/gji-root.1
CHANGED
package/man/man1/gji-run-hook.1
CHANGED
package/man/man1/gji-status.1
CHANGED
package/man/man1/gji-sync.1
CHANGED
package/man/man1/gji-warp.1
CHANGED
package/man/man1/gji.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH GJI 1 "July 2026" "gji 0.
|
|
1
|
+
.TH GJI 1 "July 2026" "gji 0.9.0" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
3
|
gji \- Context switching without the mess.
|
|
4
4
|
.SH SYNOPSIS
|
|
@@ -15,7 +15,10 @@ eliminating the need for \fBgit stash\fR when switching contexts.
|
|
|
15
15
|
create a new branch or detached linked worktree
|
|
16
16
|
.TP
|
|
17
17
|
.B init [options] [shell]
|
|
18
|
-
|
|
18
|
+
set up shell integration interactively or print a shell wrapper
|
|
19
|
+
.TP
|
|
20
|
+
.B doctor [options]
|
|
21
|
+
check gji installation and configuration health
|
|
19
22
|
.TP
|
|
20
23
|
.B completion [options] [shell]
|
|
21
24
|
print shell completion definitions
|
|
@@ -77,6 +80,7 @@ output the version number
|
|
|
77
80
|
.SH "SEE ALSO"
|
|
78
81
|
.BR gji\-new (1),
|
|
79
82
|
.BR gji\-init (1),
|
|
83
|
+
.BR gji\-doctor (1),
|
|
80
84
|
.BR gji\-completion (1),
|
|
81
85
|
.BR gji\-pr (1),
|
|
82
86
|
.BR gji\-back (1),
|