@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/go.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type WorktreePromptEntry } from "./worktree-picker.js";
|
|
1
|
+
import { type QueryWorktreePullRequests, type WorktreePromptEntry } from "./worktree-picker.js";
|
|
2
2
|
export interface GoCommandOptions {
|
|
3
3
|
branch?: string;
|
|
4
4
|
cwd: string;
|
|
@@ -8,6 +8,7 @@ export interface GoCommandOptions {
|
|
|
8
8
|
}
|
|
9
9
|
export interface GoCommandDependencies {
|
|
10
10
|
promptForWorktree: (worktrees: WorktreePromptEntry[]) => Promise<string | null>;
|
|
11
|
+
queryPullRequests: QueryWorktreePullRequests;
|
|
11
12
|
}
|
|
12
13
|
export declare function createGoCommand(dependencies?: Partial<GoCommandDependencies>): (options: GoCommandOptions) => Promise<number>;
|
|
13
14
|
export declare const runGoCommand: (options: GoCommandOptions) => Promise<number>;
|
package/dist/go.js
CHANGED
|
@@ -40,12 +40,15 @@ export function createGoCommand(dependencies = {}) {
|
|
|
40
40
|
return 1;
|
|
41
41
|
}
|
|
42
42
|
const promptSources = worktrees.map((worktree) => ({
|
|
43
|
+
repoRoot: repository.repoRoot,
|
|
43
44
|
repoName: repository.repoName,
|
|
44
45
|
worktree,
|
|
45
46
|
}));
|
|
46
47
|
const promptEntries = options.branch
|
|
47
48
|
? []
|
|
48
|
-
: await buildWorktreePromptEntries(promptSources
|
|
49
|
+
: await buildWorktreePromptEntries(promptSources, {
|
|
50
|
+
queryPullRequests: dependencies.queryPullRequests,
|
|
51
|
+
});
|
|
49
52
|
const queried = options.branch
|
|
50
53
|
? resolveWorktreeQuery(promptSources, options.branch)
|
|
51
54
|
: null;
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { runCli } from "./cli.js";
|
|
4
4
|
import { loadGlobalConfig } from "./config.js";
|
|
5
|
+
import { isHeadless } from "./headless.js";
|
|
5
6
|
async function main() {
|
|
6
7
|
try {
|
|
7
8
|
const argv = process.argv.slice(2);
|
|
8
9
|
// Warn once (until fixed) when shell integration hasn't been set up.
|
|
9
|
-
// Only shown in interactive terminals — suppressed in pipes and after gji init
|
|
10
|
+
// Only shown in interactive terminals — suppressed in pipes and after gji init.
|
|
10
11
|
const isMetaArg = argv[0] === "init" ||
|
|
11
12
|
argv[0] === "--version" ||
|
|
12
13
|
argv[0] === "-V" ||
|
|
@@ -31,15 +32,20 @@ async function warnIfMissingShellIntegration() {
|
|
|
31
32
|
try {
|
|
32
33
|
const { config } = await loadGlobalConfig(homedir());
|
|
33
34
|
if (!config.shellIntegration) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
process.stderr.write(`gji: shell integration not set up — run \`gji init${shellArg} --write\` to enable automatic cd.\n`);
|
|
35
|
+
const setupCommand = isHeadless()
|
|
36
|
+
? legacyShellSetupCommand()
|
|
37
|
+
: "gji init";
|
|
38
|
+
process.stderr.write(`gji: shell integration not set up — run \`${setupCommand}\` to enable automatic cd.\n`);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
catch {
|
|
42
42
|
// best-effort; never block the command
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
function legacyShellSetupCommand() {
|
|
46
|
+
const shell = (process.env.SHELL ?? "").split("/").at(-1);
|
|
47
|
+
return shell && ["bash", "fish", "zsh"].includes(shell)
|
|
48
|
+
? `gji init ${shell} --write`
|
|
49
|
+
: "gji init <shell> --write";
|
|
50
|
+
}
|
|
45
51
|
void main();
|
package/dist/init.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SupportedShell } from "./shell.js";
|
|
2
2
|
export type InstallSaveTarget = "local" | "global";
|
|
3
|
+
export type ShellIntegrationChoice = "existing" | "install" | "skip";
|
|
3
4
|
export interface SetupWizardResult {
|
|
4
5
|
branchPrefix?: string;
|
|
5
6
|
hooks?: {
|
|
@@ -10,9 +11,22 @@ export interface SetupWizardResult {
|
|
|
10
11
|
installSaveTarget: InstallSaveTarget;
|
|
11
12
|
worktreePath?: string;
|
|
12
13
|
}
|
|
14
|
+
export interface InitOnboardingResult {
|
|
15
|
+
editor?: string;
|
|
16
|
+
installCompletion: boolean;
|
|
17
|
+
shellIntegration: ShellIntegrationChoice;
|
|
18
|
+
shell: SupportedShell;
|
|
19
|
+
}
|
|
20
|
+
interface InitOnboardingContext {
|
|
21
|
+
detectedShell: SupportedShell | null;
|
|
22
|
+
home: string;
|
|
23
|
+
}
|
|
13
24
|
export interface InitCommandOptions {
|
|
14
25
|
cwd: string;
|
|
15
26
|
home?: string;
|
|
27
|
+
interactive?: boolean;
|
|
28
|
+
json?: boolean;
|
|
29
|
+
promptForOnboarding?: (context: InitOnboardingContext) => Promise<InitOnboardingResult | null>;
|
|
16
30
|
promptForSetup?: () => Promise<SetupWizardResult | null>;
|
|
17
31
|
shell?: string;
|
|
18
32
|
stderr?: (chunk: string) => void;
|
|
@@ -22,3 +36,4 @@ export interface InitCommandOptions {
|
|
|
22
36
|
export declare function runInitCommand(options: InitCommandOptions): Promise<number>;
|
|
23
37
|
export declare function renderShellIntegration(shell: SupportedShell): string;
|
|
24
38
|
export declare function upsertShellIntegration(existingConfig: string, script: string): string;
|
|
39
|
+
export {};
|
package/dist/init.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname
|
|
4
|
-
import { intro, isCancel, outro, select, text } from "@clack/prompts";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { confirm, intro, isCancel, log, outro, select, text, } from "@clack/prompts";
|
|
5
6
|
import { loadConfig, loadGlobalConfig, saveGlobalConfig, saveLocalConfig, updateGlobalConfigKey, } from "./config.js";
|
|
7
|
+
import { EDITORS } from "./editor.js";
|
|
8
|
+
import { isHeadless } from "./headless.js";
|
|
6
9
|
import { resolveSupportedShell } from "./shell.js";
|
|
7
|
-
|
|
8
|
-
|
|
10
|
+
import { renderShellCompletion } from "./shell-completion.js";
|
|
11
|
+
import { SHELL_INTEGRATION_END_MARKER as END_MARKER, executableExists, hasShellIntegration, ONBOARDING_SHELL_INTEGRATION_END_MARKER as ONBOARDING_END_MARKER, ONBOARDING_SHELL_INTEGRATION_START_MARKER as ONBOARDING_START_MARKER, resolveCompletionPath, resolveShellConfigPath, SHELL_INTEGRATION_START_MARKER as START_MARKER, } from "./shell-setup.js";
|
|
12
|
+
const ZSH_COMPLETION_PATH_LINE = "fpath=(~/.zsh/completions $fpath)";
|
|
9
13
|
const SHELL_WRAPPED_COMMANDS = [
|
|
10
14
|
{
|
|
11
15
|
bypassOptions: ["--help"],
|
|
@@ -58,6 +62,228 @@ const SHELL_WRAPPED_COMMANDS = [
|
|
|
58
62
|
},
|
|
59
63
|
];
|
|
60
64
|
export async function runInitCommand(options) {
|
|
65
|
+
if (options.shell === undefined) {
|
|
66
|
+
return runOnboardingInitCommand(options);
|
|
67
|
+
}
|
|
68
|
+
return runLegacyInitCommand(options);
|
|
69
|
+
}
|
|
70
|
+
async function runOnboardingInitCommand(options) {
|
|
71
|
+
if (options.json || isHeadless() || !canRunOnboarding(options)) {
|
|
72
|
+
return writeNonInteractiveInitError(options);
|
|
73
|
+
}
|
|
74
|
+
const home = options.home ?? homedir();
|
|
75
|
+
const context = {
|
|
76
|
+
detectedShell: resolveSupportedShell(undefined, process.env.SHELL),
|
|
77
|
+
home,
|
|
78
|
+
};
|
|
79
|
+
if (options.promptForOnboarding === undefined) {
|
|
80
|
+
return runDefaultOnboarding(context);
|
|
81
|
+
}
|
|
82
|
+
const result = await options.promptForOnboarding(context);
|
|
83
|
+
if (!result) {
|
|
84
|
+
options.stderr?.("Aborted.\n");
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
await applyOnboardingResult(result, home);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
function canRunOnboarding(options) {
|
|
91
|
+
return (options.interactive ??
|
|
92
|
+
(options.promptForOnboarding !== undefined ||
|
|
93
|
+
(process.stdin.isTTY === true && process.stdout.isTTY === true)));
|
|
94
|
+
}
|
|
95
|
+
function writeNonInteractiveInitError(options) {
|
|
96
|
+
const error = "run `gji init <shell> --write` in non-interactive mode";
|
|
97
|
+
options.stderr?.(options.json ? `${JSON.stringify({ error })}\n` : `${error}\n`);
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
async function runDefaultOnboarding(context) {
|
|
101
|
+
intro("gji init");
|
|
102
|
+
const shell = await select({
|
|
103
|
+
message: "Which shell should gji configure?",
|
|
104
|
+
initialValue: context.detectedShell ?? "zsh",
|
|
105
|
+
options: [
|
|
106
|
+
{ value: "zsh", label: "zsh" },
|
|
107
|
+
{ value: "bash", label: "bash" },
|
|
108
|
+
{ value: "fish", label: "fish" },
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
if (isCancel(shell))
|
|
112
|
+
return abortDefaultOnboarding();
|
|
113
|
+
const rcPath = resolveShellConfigPath(shell, context.home);
|
|
114
|
+
const currentConfig = await readExistingConfig(rcPath);
|
|
115
|
+
const shellIntegration = await promptForShellIntegration(currentConfig, rcPath, shell);
|
|
116
|
+
if (shellIntegration === null)
|
|
117
|
+
return abortDefaultOnboarding();
|
|
118
|
+
const completionPath = resolveCompletionPath(shell, context.home);
|
|
119
|
+
const completionAlreadyInstalled = await fileExists(completionPath);
|
|
120
|
+
await applyShellIntegration(shell, shellIntegration, context.home);
|
|
121
|
+
const installCompletion = await promptForCompletion(shell, completionPath);
|
|
122
|
+
if (installCompletion === null)
|
|
123
|
+
return abortDefaultOnboarding();
|
|
124
|
+
if (installCompletion) {
|
|
125
|
+
await mkdir(dirname(completionPath), { recursive: true });
|
|
126
|
+
await writeFile(completionPath, renderShellCompletion(shell), "utf8");
|
|
127
|
+
}
|
|
128
|
+
if (shell === "zsh" && (completionAlreadyInstalled || installCompletion)) {
|
|
129
|
+
await ensureZshCompletionPath(rcPath);
|
|
130
|
+
}
|
|
131
|
+
const editor = await promptForEditor();
|
|
132
|
+
if (editor === null)
|
|
133
|
+
return abortDefaultOnboarding();
|
|
134
|
+
if (editor) {
|
|
135
|
+
await updateGlobalConfigKey("editor", editor, context.home);
|
|
136
|
+
}
|
|
137
|
+
outro(`Setup complete. Restart your shell or run: source ${rcPath}\nVerify with: gji doctor`);
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
async function applyShellIntegration(shell, choice, home) {
|
|
141
|
+
if (choice === "install") {
|
|
142
|
+
await installOnboardingShellIntegration(shell, home);
|
|
143
|
+
}
|
|
144
|
+
if (choice !== "skip") {
|
|
145
|
+
await updateGlobalConfigKey("shellIntegration", true, home);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function abortDefaultOnboarding() {
|
|
149
|
+
outro("Aborted.");
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
async function promptForShellIntegration(currentConfig, rcPath, shell) {
|
|
153
|
+
if (currentConfig.includes(ONBOARDING_START_MARKER) &&
|
|
154
|
+
currentConfig.includes(ONBOARDING_END_MARKER)) {
|
|
155
|
+
log.success(`Shell integration marker found in ${rcPath}; refreshing it.`);
|
|
156
|
+
return "install";
|
|
157
|
+
}
|
|
158
|
+
if (hasShellIntegration(currentConfig, shell)) {
|
|
159
|
+
log.success(`Shell integration already installed in ${rcPath} ✓`);
|
|
160
|
+
return "existing";
|
|
161
|
+
}
|
|
162
|
+
const confirmed = await confirm({
|
|
163
|
+
message: `Install shell integration in ${rcPath}?`,
|
|
164
|
+
initialValue: true,
|
|
165
|
+
});
|
|
166
|
+
if (isCancel(confirmed))
|
|
167
|
+
return null;
|
|
168
|
+
return confirmed ? "install" : "skip";
|
|
169
|
+
}
|
|
170
|
+
async function promptForCompletion(shell, completionPath) {
|
|
171
|
+
if (await fileExists(completionPath)) {
|
|
172
|
+
log.success(`${shell} completion already installed at ${completionPath} ✓`);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const confirmed = await confirm({
|
|
176
|
+
message: `Install ${shell} completion at ${completionPath}?`,
|
|
177
|
+
initialValue: true,
|
|
178
|
+
});
|
|
179
|
+
if (isCancel(confirmed))
|
|
180
|
+
return null;
|
|
181
|
+
return confirmed;
|
|
182
|
+
}
|
|
183
|
+
async function promptForEditor() {
|
|
184
|
+
const availableEditors = await findAvailableEditors();
|
|
185
|
+
if (availableEditors.length === 0) {
|
|
186
|
+
log.info("No supported editor CLIs found on PATH; skipping editor setup.");
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
const skipValue = "__gji_skip_editor__";
|
|
190
|
+
const selected = await select({
|
|
191
|
+
message: "Which editor should gji use?",
|
|
192
|
+
options: [
|
|
193
|
+
...availableEditors.map(({ cli, name }) => ({
|
|
194
|
+
value: cli,
|
|
195
|
+
label: name,
|
|
196
|
+
hint: cli,
|
|
197
|
+
})),
|
|
198
|
+
{ value: skipValue, label: "Skip" },
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
if (isCancel(selected))
|
|
202
|
+
return null;
|
|
203
|
+
return selected === skipValue ? undefined : selected;
|
|
204
|
+
}
|
|
205
|
+
async function findAvailableEditors() {
|
|
206
|
+
const availableEditors = [];
|
|
207
|
+
for (const editor of EDITORS) {
|
|
208
|
+
if (await executableExists(editor.cli)) {
|
|
209
|
+
availableEditors.push(editor);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return availableEditors;
|
|
213
|
+
}
|
|
214
|
+
async function applyOnboardingResult(result, home) {
|
|
215
|
+
const rcPath = resolveShellConfigPath(result.shell, home);
|
|
216
|
+
const completionPath = resolveCompletionPath(result.shell, home);
|
|
217
|
+
const completionAlreadyInstalled = await fileExists(completionPath);
|
|
218
|
+
await applyShellIntegration(result.shell, result.shellIntegration, home);
|
|
219
|
+
if (result.installCompletion) {
|
|
220
|
+
await mkdir(dirname(completionPath), { recursive: true });
|
|
221
|
+
await writeFile(completionPath, renderShellCompletion(result.shell), "utf8");
|
|
222
|
+
}
|
|
223
|
+
if (result.shell === "zsh" &&
|
|
224
|
+
(completionAlreadyInstalled || result.installCompletion)) {
|
|
225
|
+
await ensureZshCompletionPath(rcPath);
|
|
226
|
+
}
|
|
227
|
+
if (result.editor) {
|
|
228
|
+
await updateGlobalConfigKey("editor", result.editor, home);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function installOnboardingShellIntegration(shell, home) {
|
|
232
|
+
const rcPath = resolveShellConfigPath(shell, home);
|
|
233
|
+
await mkdir(dirname(rcPath), { recursive: true });
|
|
234
|
+
const current = await readExistingConfig(rcPath);
|
|
235
|
+
if (shell === "fish") {
|
|
236
|
+
await writeFile(rcPath, upsertShellIntegration(current, renderShellIntegration(shell)), "utf8");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
await writeFile(rcPath, upsertOnboardingShellIntegration(current, shell), "utf8");
|
|
240
|
+
}
|
|
241
|
+
function upsertOnboardingShellIntegration(existingConfig, shell) {
|
|
242
|
+
const script = renderOnboardingShellIntegration(shell).trimEnd();
|
|
243
|
+
const blockPattern = new RegExp(`${escapeForRegExp(ONBOARDING_START_MARKER)}[\\s\\S]*?${escapeForRegExp(ONBOARDING_END_MARKER)}\\n?`, "m");
|
|
244
|
+
if (blockPattern.test(existingConfig)) {
|
|
245
|
+
return ensureTrailingNewline(existingConfig.replace(blockPattern, `${script}\n`));
|
|
246
|
+
}
|
|
247
|
+
const prefix = existingConfig.trimEnd();
|
|
248
|
+
if (prefix.length === 0)
|
|
249
|
+
return ensureTrailingNewline(script);
|
|
250
|
+
return ensureTrailingNewline(`${prefix}\n\n${script}`);
|
|
251
|
+
}
|
|
252
|
+
function renderOnboardingShellIntegration(shell) {
|
|
253
|
+
return `${ONBOARDING_START_MARKER}
|
|
254
|
+
eval "$(gji init ${shell})"
|
|
255
|
+
${ONBOARDING_END_MARKER}
|
|
256
|
+
`;
|
|
257
|
+
}
|
|
258
|
+
async function ensureZshCompletionPath(rcPath) {
|
|
259
|
+
const current = await readExistingConfig(rcPath);
|
|
260
|
+
const next = upsertZshCompletionPath(current);
|
|
261
|
+
if (next !== current) {
|
|
262
|
+
await writeFile(rcPath, next, "utf8");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function upsertZshCompletionPath(existingConfig) {
|
|
266
|
+
const configWithoutCompletionPath = existingConfig
|
|
267
|
+
.replace(/# >>> gji zsh completion path >>>[\s\S]*?# <<< gji zsh completion path <<<\n?/m, "")
|
|
268
|
+
.replace(new RegExp(`^[\\t ]*${escapeForRegExp(ZSH_COMPLETION_PATH_LINE)}[\\t ]*\\n?`, "gm"), "");
|
|
269
|
+
const suffix = configWithoutCompletionPath
|
|
270
|
+
.replace(/^(?:\r?\n)+/, "")
|
|
271
|
+
.trimEnd();
|
|
272
|
+
// Frameworks can invoke compinit from a sourced file, so this must come first.
|
|
273
|
+
return ensureTrailingNewline(suffix.length === 0
|
|
274
|
+
? ZSH_COMPLETION_PATH_LINE
|
|
275
|
+
: `${ZSH_COMPLETION_PATH_LINE}\n\n${suffix}`);
|
|
276
|
+
}
|
|
277
|
+
async function fileExists(path) {
|
|
278
|
+
try {
|
|
279
|
+
await access(path, constants.F_OK);
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async function runLegacyInitCommand(options) {
|
|
61
287
|
const shell = resolveSupportedShell(options.shell, process.env.SHELL);
|
|
62
288
|
const home = options.home ?? homedir();
|
|
63
289
|
if (!shell) {
|
|
@@ -79,7 +305,7 @@ export async function runInitCommand(options) {
|
|
|
79
305
|
const { config: globalConfig } = await loadGlobalConfig(home);
|
|
80
306
|
const alreadyConfigured = "shellIntegration" in globalConfig || "installSaveTarget" in globalConfig;
|
|
81
307
|
const hasCustomPrompt = options.promptForSetup !== undefined;
|
|
82
|
-
const canPrompt = hasCustomPrompt || process.stdout.isTTY === true;
|
|
308
|
+
const canPrompt = !isHeadless() && (hasCustomPrompt || process.stdout.isTTY === true);
|
|
83
309
|
if (!alreadyConfigured && canPrompt) {
|
|
84
310
|
const prompt = options.promptForSetup ?? defaultPromptForSetup;
|
|
85
311
|
const result = await prompt();
|
|
@@ -154,16 +380,6 @@ async function saveWizardConfig(result, cwd, home) {
|
|
|
154
380
|
await saveGlobalConfig({ ...existing, ...values }, home);
|
|
155
381
|
}
|
|
156
382
|
}
|
|
157
|
-
function resolveShellConfigPath(shell, home) {
|
|
158
|
-
switch (shell) {
|
|
159
|
-
case "bash":
|
|
160
|
-
return join(home, ".bashrc");
|
|
161
|
-
case "fish":
|
|
162
|
-
return join(home, ".config", "fish", "config.fish");
|
|
163
|
-
case "zsh":
|
|
164
|
-
return join(home, ".zshrc");
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
383
|
async function readExistingConfig(path) {
|
|
168
384
|
try {
|
|
169
385
|
return await readFile(path, "utf8");
|
package/dist/open.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type EditorDefinition } from "./editor.js";
|
|
2
|
-
import { type WorktreePromptEntry } from "./worktree-picker.js";
|
|
2
|
+
import { type QueryWorktreePullRequests, type WorktreePromptEntry } from "./worktree-picker.js";
|
|
3
3
|
export type { EditorDefinition };
|
|
4
4
|
export interface OpenCommandOptions {
|
|
5
5
|
branch?: string;
|
|
@@ -14,6 +14,7 @@ export interface OpenCommandDependencies {
|
|
|
14
14
|
detectEditors: () => Promise<EditorDefinition[]>;
|
|
15
15
|
promptForEditor: (editors: EditorDefinition[]) => Promise<string | null>;
|
|
16
16
|
promptForWorktree: (worktrees: WorktreePromptEntry[]) => Promise<string | null>;
|
|
17
|
+
queryPullRequests: QueryWorktreePullRequests;
|
|
17
18
|
spawnEditor: (cli: string, args: string[]) => Promise<void>;
|
|
18
19
|
}
|
|
19
20
|
export declare function createOpenCommand(dependencies?: Partial<OpenCommandDependencies>): (options: OpenCommandOptions) => Promise<number>;
|
package/dist/open.js
CHANGED
|
@@ -42,9 +42,10 @@ export function createOpenCommand(dependencies = {}) {
|
|
|
42
42
|
}
|
|
43
43
|
else {
|
|
44
44
|
const entries = await buildWorktreePromptEntries(worktrees.map((worktree) => ({
|
|
45
|
+
repoRoot: repository.repoRoot,
|
|
45
46
|
repoName: repository.repoName,
|
|
46
47
|
worktree,
|
|
47
|
-
})));
|
|
48
|
+
})), { queryPullRequests: dependencies.queryPullRequests });
|
|
48
49
|
const chosen = await promptForWorktree(entries);
|
|
49
50
|
if (!chosen) {
|
|
50
51
|
options.stderr("Aborted\n");
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type PullRequestInfo } from "./pull-requests.js";
|
|
2
|
+
import { type QueryRepositoryPullRequests, type QueryWorktreePullRequests, type WorktreePromptEntry } from "./worktree-picker.js";
|
|
3
|
+
export interface PrOpenCommandOptions {
|
|
4
|
+
cwd: string;
|
|
5
|
+
stderr: (chunk: string) => void;
|
|
6
|
+
stdout: (chunk: string) => void;
|
|
7
|
+
select?: boolean;
|
|
8
|
+
target?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PrOpenCommandDependencies {
|
|
11
|
+
findOpenPullRequest: (repoRoot: string, number: number) => Promise<PullRequestInfo | null>;
|
|
12
|
+
openBrowser: (url: string) => Promise<void>;
|
|
13
|
+
promptForPullRequest: (pullRequests: PullRequestInfo[]) => Promise<PullRequestInfo | null>;
|
|
14
|
+
promptForWorktree: (worktrees: WorktreePromptEntry[]) => Promise<string | null>;
|
|
15
|
+
queryPullRequests: QueryWorktreePullRequests;
|
|
16
|
+
queryRepositoryPullRequests?: QueryRepositoryPullRequests;
|
|
17
|
+
}
|
|
18
|
+
export declare function createPrOpenCommand(dependencies?: Partial<PrOpenCommandDependencies>): (options: PrOpenCommandOptions) => Promise<number>;
|
|
19
|
+
export declare const runPrOpenCommand: (options: PrOpenCommandOptions) => Promise<number>;
|